templatesDir = __DIR__ . '/fixtures'; } public function testRenderSignature(): void { $engine = new Engine(); $this->assertTrue(method_exists($engine, 'render')); } public function testThrowsTemplateNotFoundExceptionInDebug(): void { $this->expectException(TemplateNotFoundException::class); $engine = new Engine(['mode' => 'debug']); $engine->render('missing.template'); } public function testRendersPlaceholderInProduction(): void { $engine = new Engine(['mode' => 'production']); $output = $engine->render('missing.template'); $this->assertEquals("", $output); } public function testRenders404Fallback(): void { file_put_contents($this->templatesDir . '/404.scape.php', 'Custom 404: {{ missing_template }}'); $engine = new Engine(['templates_dir' => $this->templatesDir, 'mode' => 'production']); $output = $engine->render('missing.template'); $this->assertEquals('Custom 404: missing.template', $output); unlink($this->templatesDir . '/404.scape.php'); } public function testRendersSimpleTemplate(): void { $engine = new Engine([ 'templates_dir' => $this->templatesDir, 'mode' => 'production' ]); $output = $engine->render('tests.simple', [ 'name' => 'Funky', 'items' => ['Apple', 'Banana'] ]); $expected = "Hello Funky!\n - Apple\n - Banana\n"; $this->assertEquals($expected, $output); } public function testRendersTemplateWithInheritance(): void { $engine = new Engine([ 'templates_dir' => $this->templatesDir, 'layouts_dir' => $this->templatesDir . '/layouts', 'mode' => 'production' ]); $output = $engine->render('tests.child', [ 'name' => 'Funky' ]); $this->assertStringContainsString('Child Page - Funky', $output); $this->assertStringContainsString('

Site Header

', $output); $this->assertStringContainsString('

Welcome

', $output); $this->assertStringContainsString('Nested default', $output); $this->assertStringContainsString('© 2026 - Custom Footer', $output); } public function testRendersIncludeWithContext(): void { $engine = new Engine([ 'templates_dir' => $this->templatesDir, 'partials_dir' => $this->templatesDir . '/partials', 'mode' => 'production' ]); $output = $engine->render('tests.include', [ 'name' => 'Funky', 'id' => 123, 'person' => ['name' => 'John', 'id' => 456] ]); $this->assertStringContainsString('Hello Funky!', $output); $this->assertStringContainsString('Name: Funky', $output); $this->assertStringContainsString('ID: 123', $output); $this->assertStringContainsString('Name: John', $output); $this->assertStringContainsString('ID: 456', $output); } public function testRecursionLimit(): void { $this->expectException(RecursionLimitException::class); $engine = new Engine([ 'templates_dir' => $this->templatesDir, 'partials_dir' => $this->templatesDir . '/partials', 'mode' => 'production' ]); $engine->render('partials.recursive'); } }