1<?php declare(strict_types=1);
2
3namespace App\Tests\Unit\Template;
4
5use PHPUnit\Framework\TestCase;
6use App\Template\Context;
7
8class ContextTest extends TestCase
9{
10    /** @var Context */
11    private $context;
12
13    public function setUp(): void
14    {
15        $this->context = new Context(TEST_FIXTURES_DIRECTORY . '/templates');
16    }
17
18    public function testBlock(): void
19    {
20        $this->context->start('foo');
21        echo 'bar';
22        $this->context->end('foo');
23
24        $this->assertEquals($this->context->block('foo'), 'bar');
25
26        $this->context->append('foo');
27        echo 'baz';
28        $this->context->end('foo');
29
30        $this->assertEquals($this->context->block('foo'), 'barbaz');
31
32        $this->context->start('foo');
33        echo 'overridden';
34        $this->context->end('foo');
35
36        $this->assertEquals($this->context->block('foo'), 'overridden');
37    }
38
39    public function testInclude(): void
40    {
41        ob_start();
42        $this->context->include('includes/banner.php');
43        $content = ob_get_clean();
44
45        $this->assertEquals(file_get_contents(TEST_FIXTURES_DIRECTORY . '/templates/includes/banner.php'), $content);
46    }
47
48    public function testIncludeReturn(): void
49    {
50        $variable = $this->context->include('includes/variable.php');
51
52        $this->assertEquals(include TEST_FIXTURES_DIRECTORY . '/templates/includes/variable.php', $variable);
53    }
54
55    public function testIncludeOnInvalidVariableCounts(): void
56    {
57        $this->expectException(\Exception::class);
58        $this->expectExceptionMessage('Variables with numeric names $0, $1... cannot be imported to scope includes/variable.php');
59
60        $this->context->include('includes/variable.php', ['var1', 'var2', 'var3']);
61    }
62
63    /**
64     * @dataProvider attacksProvider
65     */
66    public function testEscaping(string $malicious, string $escaped, string $noHtml): void
67    {
68        $this->assertEquals($escaped, $this->context->e($malicious));
69    }
70
71    /**
72     * @dataProvider attacksProvider
73     */
74    public function testNoHtml(string $malicious, string $escaped, string $noHtml): void
75    {
76        $this->assertEquals($noHtml, $this->context->noHtml($malicious));
77    }
78
79    public function attacksProvider(): array
80    {
81        return [
82            [
83                '<iframe src="javascript:alert(\'Xss\')";></iframe>',
84                '&lt;iframe src=&quot;javascript:alert(&#039;Xss&#039;)&quot;;&gt;&lt;/iframe&gt;',
85                '&lt;iframe src&equals;&quot;javascript&colon;alert&lpar;&apos;Xss&apos;&rpar;&quot;&semi;&gt;&lt;&sol;iframe&gt;'
86            ]
87        ];
88    }
89}
90