diff --git a/tests/unit/Compiler/AccessTest.php b/tests/unit/Compiler/AccessTest.php new file mode 100644 index 0000000..d2b7bfb --- /dev/null +++ b/tests/unit/Compiler/AccessTest.php @@ -0,0 +1,223 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class AccessTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprDot(): void + { + $source = '{{ user.name }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 46, + 'left' => [ + 'type' => 265, + 'value' => 'user', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'name', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprDotNested(): void + { + $source = '{{ user.address.city }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 46, + 'left' => [ + 'type' => 46, + 'left' => [ + 'type' => 265, + 'value' => 'user', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'address', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'city', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprArrayAccess(): void + { + $source = '{{ items[0] }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 361, + 'left' => [ + 'type' => 265, + 'value' => 'items', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 258, + 'value' => '0', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprArrayAccessKey(): void + { + $source = '{{ map[\'key\'] }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 361, + 'left' => [ + 'type' => 265, + 'value' => 'map', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 260, + 'value' => 'key', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprArrayAccessVar(): void + { + $source = '{{ items[index] }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 361, + 'left' => [ + 'type' => 265, + 'value' => 'items', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'index', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/ArithmeticTest.php b/tests/unit/Compiler/ArithmeticTest.php new file mode 100644 index 0000000..95f6491 --- /dev/null +++ b/tests/unit/Compiler/ArithmeticTest.php @@ -0,0 +1,410 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class ArithmeticTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprAdd(): void + { + $source = '{{ 1 + 2 }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 43, + 'left' => [ + 'type' => 258, + 'value' => '1', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 258, + 'value' => '2', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprSub(): void + { + $source = '{{ 5 - 3 }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 45, + 'left' => [ + 'type' => 258, + 'value' => '5', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 258, + 'value' => '3', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprMul(): void + { + $source = '{{ 4 * 3 }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 42, + 'left' => [ + 'type' => 258, + 'value' => '4', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 258, + 'value' => '3', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprDiv(): void + { + $source = '{{ 10 / 2 }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 47, + 'left' => [ + 'type' => 258, + 'value' => '10', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 258, + 'value' => '2', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprMod(): void + { + $source = '{{ 10 % 3 }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 37, + 'left' => [ + 'type' => 258, + 'value' => '10', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 258, + 'value' => '3', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprPow(): void + { + $source = '{{ 2 * * 8 }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 278, + 'left' => [ + 'type' => 258, + 'value' => '2', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 258, + 'value' => '8', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprIntDiv(): void + { + $source = '{{ 10 / / 3 }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 37, + 'left' => [ + 'type' => 258, + 'value' => '10', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 258, + 'value' => '3', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprUnaryMinus(): void + { + $source = '{{ -value }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 368, + 'right' => [ + 'type' => 265, + 'value' => 'value', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprUnaryPlus(): void + { + $source = '{{ +value }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 369, + 'right' => [ + 'type' => 265, + 'value' => 'value', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprIncr(): void + { + $source = '{{ value++ }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 279, + 'left' => [ + 'type' => 265, + 'value' => 'value', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprDecr(): void + { + $source = '{{ value-- }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 280, + 'left' => [ + 'type' => 265, + 'value' => 'value', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/ArrayTest.php b/tests/unit/Compiler/ArrayTest.php new file mode 100644 index 0000000..d2eead1 --- /dev/null +++ b/tests/unit/Compiler/ArrayTest.php @@ -0,0 +1,240 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class ArrayTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprArrayEmpty(): void + { + $source = '{{ [] }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 360, + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprArrayLiteral(): void + { + $source = '{{ [1, 2, 3] }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 360, + 'left' => [ + [ + 'expr' => [ + 'type' => 258, + 'value' => '1', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'expr' => [ + 'type' => 258, + 'value' => '2', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'expr' => [ + 'type' => 258, + 'value' => '3', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprArrayMixed(): void + { + $source = '{{ [\'a\', \'b\', \'c\'] }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 360, + 'left' => [ + [ + 'expr' => [ + 'type' => 260, + 'value' => 'a', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'expr' => [ + 'type' => 260, + 'value' => 'b', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'expr' => [ + 'type' => 260, + 'value' => 'c', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprHashEmpty(): void + { + $source = '{{ {} }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 360, + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprHashLiteral(): void + { + $source = '{{ {\'key\': \'value\', \'num\': 42} }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 360, + 'left' => [ + [ + 'expr' => [ + 'type' => 260, + 'value' => 'value', + 'file' => 'eval code', + 'line' => 1, + ], + 'name' => 'key', + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'expr' => [ + 'type' => 258, + 'value' => '42', + 'file' => 'eval code', + 'line' => 1, + ], + 'name' => 'num', + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/AutoescapeTest.php b/tests/unit/Compiler/AutoescapeTest.php new file mode 100644 index 0000000..287d0c5 --- /dev/null +++ b/tests/unit/Compiler/AutoescapeTest.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class AutoescapeTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserAutoescapeTrue(): void + { + $source = '{% autoescape true %}{{ name }}{% endautoescape %}'; + $expected = [ + [ + 'type' => 317, + 'enable' => 1, + 'block_statements' => [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 265, + 'value' => 'name', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserAutoescapeFalse(): void + { + $source = '{% autoescape false %}{{ html }}{% endautoescape %}'; + $expected = [ + [ + 'type' => 317, + 'enable' => 0, + 'block_statements' => [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 265, + 'value' => 'html', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/BlockTest.php b/tests/unit/Compiler/BlockTest.php new file mode 100644 index 0000000..53770b7 --- /dev/null +++ b/tests/unit/Compiler/BlockTest.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class BlockTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserBlockWithContent(): void + { + $source = '{% block content %}Default content{% endblock %}'; + $expected = [ + [ + 'type' => 307, + 'name' => 'content', + 'block_statements' => [ + [ + 'type' => 357, + 'value' => 'Default content', + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserBlockEmpty(): void + { + $source = '{% block sidebar %}{% endblock %}'; + $expected = [ + [ + 'type' => 307, + 'name' => 'sidebar', + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/CacheTest.php b/tests/unit/Compiler/CacheTest.php new file mode 100644 index 0000000..35d8ca2 --- /dev/null +++ b/tests/unit/Compiler/CacheTest.php @@ -0,0 +1,156 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class CacheTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserCacheSimple(): void + { + $source = '{% cache \'sidebar\' %}{{ content }}{% endcache %}'; + $expected = [ + [ + 'type' => 314, + 'expr' => [ + 'type' => 260, + 'value' => 'sidebar', + 'file' => 'eval code', + 'line' => 1, + ], + 'block_statements' => [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 265, + 'value' => 'content', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserCacheLifetimeInt(): void + { + $source = '{% cache \'sidebar\' 3600 %}{{ content }}{% endcache %}'; + $expected = [ + [ + 'type' => 314, + 'expr' => [ + 'type' => 260, + 'value' => 'sidebar', + 'file' => 'eval code', + 'line' => 1, + ], + 'lifetime' => [ + 'type' => 258, + 'value' => '3600', + 'file' => 'eval code', + 'line' => 1, + ], + 'block_statements' => [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 265, + 'value' => 'content', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserCacheLifetimeVar(): void + { + $source = '{% cache cacheKey lifetime %}{{ content }}{% endcache %}'; + $expected = [ + [ + 'type' => 314, + 'expr' => [ + 'type' => 265, + 'value' => 'cacheKey', + 'file' => 'eval code', + 'line' => 1, + ], + 'lifetime' => [ + 'type' => 265, + 'value' => 'lifetime', + 'file' => 'eval code', + 'line' => 1, + ], + 'block_statements' => [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 265, + 'value' => 'content', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/CallTest.php b/tests/unit/Compiler/CallTest.php new file mode 100644 index 0000000..55c5663 --- /dev/null +++ b/tests/unit/Compiler/CallTest.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class CallTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserCallNoArgs(): void + { + $source = '{% call myMacro() %}{% endcall %}'; + $expected = [ + [ + 'type' => 325, + 'name' => [ + 'type' => 265, + 'value' => 'myMacro', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserCallWithArgs(): void + { + $source = '{% call render(item) %}block content{% endcall %}'; + $expected = [ + [ + 'type' => 325, + 'name' => [ + 'type' => 265, + 'value' => 'render', + 'file' => 'eval code', + 'line' => 1, + ], + 'arguments' => [ + [ + 'expr' => [ + 'type' => 265, + 'value' => 'item', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'caller' => [ + [ + 'type' => 357, + 'value' => 'block content', + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/CommentTest.php b/tests/unit/Compiler/CommentTest.php new file mode 100644 index 0000000..eef535b --- /dev/null +++ b/tests/unit/Compiler/CommentTest.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class CommentTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserComment(): void + { + $source = '{# This is a comment #}'; + $expected = []; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserCommentInline(): void + { + $source = 'Hello {# greeting comment #} World'; + $expected = [ + [ + 'type' => 357, + 'value' => 'Hello World', + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/ComparisonTest.php b/tests/unit/Compiler/ComparisonTest.php new file mode 100644 index 0000000..e33f038 --- /dev/null +++ b/tests/unit/Compiler/ComparisonTest.php @@ -0,0 +1,360 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class ComparisonTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprEq(): void + { + $source = '{{ a == b }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 272, + 'left' => [ + 'type' => 265, + 'value' => 'a', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'b', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprNeq(): void + { + $source = '{{ a != b }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 273, + 'left' => [ + 'type' => 265, + 'value' => 'a', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'b', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprNeqAlt(): void + { + $source = '{{ a <> b }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 273, + 'left' => [ + 'type' => 265, + 'value' => 'a', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'b', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprIdentical(): void + { + $source = '{{ a === b }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 274, + 'left' => [ + 'type' => 265, + 'value' => 'a', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'b', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprNotidentical(): void + { + $source = '{{ a !== b }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 275, + 'left' => [ + 'type' => 265, + 'value' => 'a', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'b', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprLt(): void + { + $source = '{{ a < b }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 60, + 'left' => [ + 'type' => 265, + 'value' => 'a', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'b', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprGt(): void + { + $source = '{{ a > b }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 62, + 'left' => [ + 'type' => 265, + 'value' => 'a', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'b', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprLte(): void + { + $source = '{{ a <= b }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 270, + 'left' => [ + 'type' => 265, + 'value' => 'a', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'b', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprGte(): void + { + $source = '{{ a >= b }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 271, + 'left' => [ + 'type' => 265, + 'value' => 'a', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'b', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/ConcatenationTest.php b/tests/unit/Compiler/ConcatenationTest.php new file mode 100644 index 0000000..2c2ca61 --- /dev/null +++ b/tests/unit/Compiler/ConcatenationTest.php @@ -0,0 +1,123 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class ConcatenationTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprConcat(): void + { + $source = '{{ \'Hello\' ~ \' \' ~ \'World\' }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 126, + 'left' => [ + 'type' => 126, + 'left' => [ + 'type' => 260, + 'value' => 'Hello', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 260, + 'value' => ' ', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 260, + 'value' => 'World', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprConcatVar(): void + { + $source = '{{ firstName ~ \' \' ~ lastName }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 126, + 'left' => [ + 'type' => 126, + 'left' => [ + 'type' => 265, + 'value' => 'firstName', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 260, + 'value' => ' ', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'lastName', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/DoTest.php b/tests/unit/Compiler/DoTest.php new file mode 100644 index 0000000..4ea2591 --- /dev/null +++ b/tests/unit/Compiler/DoTest.php @@ -0,0 +1,112 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class DoTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserDo(): void + { + $source = '{% do myFunction() %}'; + $expected = [ + [ + 'type' => 316, + 'expr' => [ + 'type' => 350, + 'name' => [ + 'type' => 265, + 'value' => 'myFunction', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserDoMethod(): void + { + $source = '{% do object.method(arg) %}'; + $expected = [ + [ + 'type' => 316, + 'expr' => [ + 'type' => 350, + 'name' => [ + 'type' => 46, + 'left' => [ + 'type' => 265, + 'value' => 'object', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'method', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'arguments' => [ + [ + 'expr' => [ + 'type' => 265, + 'value' => 'arg', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/EchoTest.php b/tests/unit/Compiler/EchoTest.php new file mode 100644 index 0000000..c23395e --- /dev/null +++ b/tests/unit/Compiler/EchoTest.php @@ -0,0 +1,310 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class EchoTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserEchoVar(): void + { + $source = '{{ name }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 265, + 'value' => 'name', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserEchoInteger(): void + { + $source = '{{ 42 }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 258, + 'value' => '42', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserEchoDouble(): void + { + $source = '{{ 3.14 }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 259, + 'value' => '3.14', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserEchoStringSingle(): void + { + $source = '{{ \'Hello\' }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 260, + 'value' => 'Hello', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserEchoStringDouble(): void + { + $source = '{{ "Hello" }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 260, + 'value' => 'Hello', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserEchoNull(): void + { + $source = '{{ null }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 261, + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserEchoTrue(): void + { + $source = '{{ true }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 263, + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserEchoFalse(): void + { + $source = '{{ false }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 262, + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserEchoTrimLeft(): void + { + $source = '{{- name }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 265, + 'value' => 'name', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserEchoTrimRight(): void + { + $source = '{{ name -}}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 265, + 'value' => 'name', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserEchoTrimBoth(): void + { + $source = '{{- name -}}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 265, + 'value' => 'name', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/ExtendsTest.php b/tests/unit/Compiler/ExtendsTest.php new file mode 100644 index 0000000..ffd4238 --- /dev/null +++ b/tests/unit/Compiler/ExtendsTest.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class ExtendsTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExtends(): void + { + $source = '{% extends \'base.volt\' %}'; + $expected = [ + [ + 'type' => 310, + 'path' => [ + 'type' => 260, + 'value' => 'base.volt', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExtendsVar(): void + { + $source = '{% extends layout %}'; + $expected = [ + [ + 'type' => 310, + 'path' => [ + 'type' => 265, + 'value' => 'layout', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/FilterTest.php b/tests/unit/Compiler/FilterTest.php new file mode 100644 index 0000000..63e6346 --- /dev/null +++ b/tests/unit/Compiler/FilterTest.php @@ -0,0 +1,112 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class FilterTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprPipe(): void + { + $source = '{{ name | upper }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 124, + 'left' => [ + 'type' => 265, + 'value' => 'name', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'upper', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprPipeChain(): void + { + $source = '{{ name | upper | trim }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 124, + 'left' => [ + 'type' => 124, + 'left' => [ + 'type' => 265, + 'value' => 'name', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'upper', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'trim', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/ForTest.php b/tests/unit/Compiler/ForTest.php new file mode 100644 index 0000000..7a89131 --- /dev/null +++ b/tests/unit/Compiler/ForTest.php @@ -0,0 +1,302 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class ForTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserForSimple(): void + { + $source = '{% for item in items %}{{ item }}{% endfor %}'; + $expected = [ + [ + 'type' => 304, + 'variable' => 'item', + 'expr' => [ + 'type' => 265, + 'value' => 'items', + 'file' => 'eval code', + 'line' => 1, + ], + 'block_statements' => [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 265, + 'value' => 'item', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserForIf(): void + { + $source = '{% for item in items if item.active %}{{ item.name }}{% endfor %}'; + $expected = [ + [ + 'type' => 304, + 'variable' => 'item', + 'expr' => [ + 'type' => 265, + 'value' => 'items', + 'file' => 'eval code', + 'line' => 1, + ], + 'if_expr' => [ + 'type' => 46, + 'left' => [ + 'type' => 265, + 'value' => 'item', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'active', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'block_statements' => [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 46, + 'left' => [ + 'type' => 265, + 'value' => 'item', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'name', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserForKeyValue(): void + { + $source = '{% for key, value in map %}{{ key }}: {{ value }}{% endfor %}'; + $expected = [ + [ + 'type' => 304, + 'variable' => 'value', + 'key' => 'key', + 'expr' => [ + 'type' => 265, + 'value' => 'map', + 'file' => 'eval code', + 'line' => 1, + ], + 'block_statements' => [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 265, + 'value' => 'key', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'type' => 357, + 'value' => ': ', + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'type' => 359, + 'expr' => [ + 'type' => 265, + 'value' => 'value', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserForKeyValueIf(): void + { + $source = '{% for key, value in map if value > 0 %}{{ key }}{% endfor %}'; + $expected = [ + [ + 'type' => 304, + 'variable' => 'value', + 'key' => 'key', + 'expr' => [ + 'type' => 265, + 'value' => 'map', + 'file' => 'eval code', + 'line' => 1, + ], + 'if_expr' => [ + 'type' => 62, + 'left' => [ + 'type' => 265, + 'value' => 'value', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 258, + 'value' => '0', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'block_statements' => [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 265, + 'value' => 'key', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserForElsefor(): void + { + $source = '{% for item in items %}{{ item }}{% elsefor %}No items{% endfor %}'; + $expected = [ + [ + 'type' => 304, + 'variable' => 'item', + 'expr' => [ + 'type' => 265, + 'value' => 'items', + 'file' => 'eval code', + 'line' => 1, + ], + 'block_statements' => [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 265, + 'value' => 'item', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'type' => 321, + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'type' => 357, + 'value' => 'No items', + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/FunctionCallTest.php b/tests/unit/Compiler/FunctionCallTest.php new file mode 100644 index 0000000..43c868e --- /dev/null +++ b/tests/unit/Compiler/FunctionCallTest.php @@ -0,0 +1,261 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class FunctionCallTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprFuncNoArgs(): void + { + $source = '{{ myFunc() }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 350, + 'name' => [ + 'type' => 265, + 'value' => 'myFunc', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprFuncOneArg(): void + { + $source = '{{ upper(name) }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 350, + 'name' => [ + 'type' => 265, + 'value' => 'upper', + 'file' => 'eval code', + 'line' => 1, + ], + 'arguments' => [ + [ + 'expr' => [ + 'type' => 265, + 'value' => 'name', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprFuncMultiArgs(): void + { + $source = '{{ slice(text, 0, 50) }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 350, + 'name' => [ + 'type' => 265, + 'value' => 'slice', + 'file' => 'eval code', + 'line' => 1, + ], + 'arguments' => [ + [ + 'expr' => [ + 'type' => 265, + 'value' => 'text', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'expr' => [ + 'type' => 258, + 'value' => '0', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'expr' => [ + 'type' => 258, + 'value' => '50', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprFuncNamedArgs(): void + { + $source = '{{ myFunc(\'key\': value) }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 350, + 'name' => [ + 'type' => 265, + 'value' => 'myFunc', + 'file' => 'eval code', + 'line' => 1, + ], + 'arguments' => [ + [ + 'expr' => [ + 'type' => 265, + 'value' => 'value', + 'file' => 'eval code', + 'line' => 1, + ], + 'name' => 'key', + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprParentheses(): void + { + $source = '{{ (1 + 2) * 3 }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 42, + 'left' => [ + 'type' => 356, + 'left' => [ + 'type' => 43, + 'left' => [ + 'type' => 258, + 'value' => '1', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 258, + 'value' => '2', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 258, + 'value' => '3', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/IfTest.php b/tests/unit/Compiler/IfTest.php new file mode 100644 index 0000000..2c3ab5f --- /dev/null +++ b/tests/unit/Compiler/IfTest.php @@ -0,0 +1,283 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class IfTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserIfSimple(): void + { + $source = '{% if active %}Yes{% endif %}'; + $expected = [ + [ + 'type' => 300, + 'expr' => [ + 'type' => 265, + 'value' => 'active', + 'file' => 'eval code', + 'line' => 1, + ], + 'true_statements' => [ + [ + 'type' => 357, + 'value' => 'Yes', + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserIfElse(): void + { + $source = '{% if active %}Yes{% else %}No{% endif %}'; + $expected = [ + [ + 'type' => 300, + 'expr' => [ + 'type' => 265, + 'value' => 'active', + 'file' => 'eval code', + 'line' => 1, + ], + 'true_statements' => [ + [ + 'type' => 357, + 'value' => 'Yes', + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'false_statements' => [ + [ + 'type' => 357, + 'value' => 'No', + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserIfElseif(): void + { + $source = '{% if status == 1 %}Active{% elseif status == 0 %}Inactive{% endif %}'; + $expected = [ + [ + 'type' => 300, + 'expr' => [ + 'type' => 272, + 'left' => [ + 'type' => 265, + 'value' => 'status', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 258, + 'value' => '1', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'true_statements' => [ + [ + 'type' => 357, + 'value' => 'Active', + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'type' => 302, + 'expr' => [ + 'type' => 272, + 'left' => [ + 'type' => 265, + 'value' => 'status', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 258, + 'value' => '0', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'type' => 357, + 'value' => 'Inactive', + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserIfElseifElse(): void + { + $source = '{% if status == 1 %}Active{% elseif status == 2 %}Pending{% else %}Unknown{% endif %}'; + $expected = [ + [ + 'type' => 300, + 'expr' => [ + 'type' => 272, + 'left' => [ + 'type' => 265, + 'value' => 'status', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 258, + 'value' => '1', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'true_statements' => [ + [ + 'type' => 357, + 'value' => 'Active', + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'type' => 302, + 'expr' => [ + 'type' => 272, + 'left' => [ + 'type' => 265, + 'value' => 'status', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 258, + 'value' => '2', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'type' => 357, + 'value' => 'Pending', + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'false_statements' => [ + [ + 'type' => 357, + 'value' => 'Unknown', + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserIfEmptyBody(): void + { + $source = '{% if condition %}{% endif %}'; + $expected = [ + [ + 'type' => 300, + 'expr' => [ + 'type' => 265, + 'value' => 'condition', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/InTest.php b/tests/unit/Compiler/InTest.php new file mode 100644 index 0000000..1f08e05 --- /dev/null +++ b/tests/unit/Compiler/InTest.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class InTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprIn(): void + { + $source = '{{ item in collection }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 309, + 'left' => [ + 'type' => 265, + 'value' => 'item', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'collection', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprNotIn(): void + { + $source = '{{ item not in collection }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 367, + 'left' => [ + 'type' => 265, + 'value' => 'item', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'collection', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/IncludeTest.php b/tests/unit/Compiler/IncludeTest.php new file mode 100644 index 0000000..d3508c2 --- /dev/null +++ b/tests/unit/Compiler/IncludeTest.php @@ -0,0 +1,129 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class IncludeTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserInclude(): void + { + $source = '{% include \'partial.volt\' %}'; + $expected = [ + [ + 'type' => 313, + 'path' => [ + 'type' => 260, + 'value' => 'partial.volt', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserIncludeWith(): void + { + $source = '{% include \'partial.volt\' with vars %}'; + $expected = [ + [ + 'type' => 313, + 'path' => [ + 'type' => 260, + 'value' => 'partial.volt', + 'file' => 'eval code', + 'line' => 1, + ], + 'params' => [ + 'type' => 265, + 'value' => 'vars', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserIncludeWithHash(): void + { + $source = '{% include \'partial.volt\' with {\'key\': \'value\'} %}'; + $expected = [ + [ + 'type' => 313, + 'path' => [ + 'type' => 260, + 'value' => 'partial.volt', + 'file' => 'eval code', + 'line' => 1, + ], + 'params' => [ + 'type' => 360, + 'left' => [ + [ + 'expr' => [ + 'type' => 260, + 'value' => 'value', + 'file' => 'eval code', + 'line' => 1, + ], + 'name' => 'key', + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/IsTest.php b/tests/unit/Compiler/IsTest.php new file mode 100644 index 0000000..97e17c8 --- /dev/null +++ b/tests/unit/Compiler/IsTest.php @@ -0,0 +1,461 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class IsTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprIsDefined(): void + { + $source = '{{ var is defined }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 363, + 'left' => [ + 'type' => 265, + 'value' => 'var', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprIsNotDefined(): void + { + $source = '{{ var is not defined }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 362, + 'left' => [ + 'type' => 265, + 'value' => 'var', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprIsEmpty(): void + { + $source = '{{ var is empty }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 386, + 'left' => [ + 'type' => 265, + 'value' => 'var', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprIsNotEmpty(): void + { + $source = '{{ var is not empty }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 392, + 'left' => [ + 'type' => 265, + 'value' => 'var', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprIsEven(): void + { + $source = '{{ number is even }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 387, + 'left' => [ + 'type' => 265, + 'value' => 'number', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprIsNotEven(): void + { + $source = '{{ number is not even }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 393, + 'left' => [ + 'type' => 265, + 'value' => 'number', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprIsOdd(): void + { + $source = '{{ number is odd }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 388, + 'left' => [ + 'type' => 265, + 'value' => 'number', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprIsNotOdd(): void + { + $source = '{{ number is not odd }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 394, + 'left' => [ + 'type' => 265, + 'value' => 'number', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprIsNumeric(): void + { + $source = '{{ var is numeric }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 389, + 'left' => [ + 'type' => 265, + 'value' => 'var', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprIsNotNumeric(): void + { + $source = '{{ var is not numeric }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 395, + 'left' => [ + 'type' => 265, + 'value' => 'var', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprIsScalar(): void + { + $source = '{{ var is scalar }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 390, + 'left' => [ + 'type' => 265, + 'value' => 'var', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprIsNotScalar(): void + { + $source = '{{ var is not scalar }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 396, + 'left' => [ + 'type' => 265, + 'value' => 'var', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprIsIterable(): void + { + $source = '{{ var is iterable }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 391, + 'left' => [ + 'type' => 265, + 'value' => 'var', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprIsNotIterable(): void + { + $source = '{{ var is not iterable }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 397, + 'left' => [ + 'type' => 265, + 'value' => 'var', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/LogicalTest.php b/tests/unit/Compiler/LogicalTest.php new file mode 100644 index 0000000..fef11a0 --- /dev/null +++ b/tests/unit/Compiler/LogicalTest.php @@ -0,0 +1,163 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class LogicalTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprAnd(): void + { + $source = '{{ a and b }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 266, + 'left' => [ + 'type' => 265, + 'value' => 'a', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'b', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprOr(): void + { + $source = '{{ a or b }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 267, + 'left' => [ + 'type' => 265, + 'value' => 'a', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'b', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprNot(): void + { + $source = '{{ not a }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 33, + 'right' => [ + 'type' => 265, + 'value' => 'a', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprNotBang(): void + { + $source = '{{ !a }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 33, + 'right' => [ + 'type' => 265, + 'value' => 'a', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/LoopControlTest.php b/tests/unit/Compiler/LoopControlTest.php new file mode 100644 index 0000000..b732236 --- /dev/null +++ b/tests/unit/Compiler/LoopControlTest.php @@ -0,0 +1,165 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class LoopControlTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserBreak(): void + { + $source = '{% for item in items %}{% if item.skip %}{% break %}{% endif %}{{ item }}{% endfor %}'; + $expected = [ + [ + 'type' => 304, + 'variable' => 'item', + 'expr' => [ + 'type' => 265, + 'value' => 'items', + 'file' => 'eval code', + 'line' => 1, + ], + 'block_statements' => [ + [ + 'type' => 300, + 'expr' => [ + 'type' => 46, + 'left' => [ + 'type' => 265, + 'value' => 'item', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'skip', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'true_statements' => [ + [ + 'type' => 320, + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'type' => 359, + 'expr' => [ + 'type' => 265, + 'value' => 'item', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserContinue(): void + { + $source = '{% for item in items %}{% if item.skip %}{% continue %}{% endif %}{{ item }}{% endfor %}'; + $expected = [ + [ + 'type' => 304, + 'variable' => 'item', + 'expr' => [ + 'type' => 265, + 'value' => 'items', + 'file' => 'eval code', + 'line' => 1, + ], + 'block_statements' => [ + [ + 'type' => 300, + 'expr' => [ + 'type' => 46, + 'left' => [ + 'type' => 265, + 'value' => 'item', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'skip', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'true_statements' => [ + [ + 'type' => 319, + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'type' => 359, + 'expr' => [ + 'type' => 265, + 'value' => 'item', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/MacroTest.php b/tests/unit/Compiler/MacroTest.php new file mode 100644 index 0000000..8798691 --- /dev/null +++ b/tests/unit/Compiler/MacroTest.php @@ -0,0 +1,416 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class MacroTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserMacroNoParams(): void + { + $source = '{% macro myMacro() %}content{% endmacro %}'; + $expected = [ + [ + 'type' => 322, + 'name' => 'myMacro', + 'block_statements' => [ + [ + 'type' => 357, + 'value' => 'content', + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserMacroOneParam(): void + { + $source = '{% macro greet(name) %}Hello {{ name }}{% endmacro %}'; + $expected = [ + [ + 'type' => 322, + 'name' => 'greet', + 'parameters' => [ + [ + 'variable' => 'name', + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'block_statements' => [ + [ + 'type' => 357, + 'value' => 'Hello ', + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'type' => 359, + 'expr' => [ + 'type' => 265, + 'value' => 'name', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserMacroMultiParams(): void + { + $source = '{% macro input(name, value) %}{% endmacro %}'; + $expected = [ + [ + 'type' => 322, + 'name' => 'input', + 'parameters' => [ + [ + 'variable' => 'name', + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'variable' => 'value', + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'block_statements' => [ + [ + 'type' => 357, + 'value' => '', + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserMacroDefaultInt(): void + { + $source = '{% macro repeat(times = 1) %}{{ times }}{% endmacro %}'; + $expected = [ + [ + 'type' => 322, + 'name' => 'repeat', + 'parameters' => [ + [ + 'variable' => 'times', + 'default' => [ + 'type' => 258, + 'value' => '1', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'block_statements' => [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 265, + 'value' => 'times', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserMacroDefaultString(): void + { + $source = '{% macro greet(name = \'World\') %}Hello {{ name }}{% endmacro %}'; + $expected = [ + [ + 'type' => 322, + 'name' => 'greet', + 'parameters' => [ + [ + 'variable' => 'name', + 'default' => [ + 'type' => 260, + 'value' => 'World', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'block_statements' => [ + [ + 'type' => 357, + 'value' => 'Hello ', + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'type' => 359, + 'expr' => [ + 'type' => 265, + 'value' => 'name', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserMacroDefaultNull(): void + { + $source = '{% macro render(item = null) %}{{ item }}{% endmacro %}'; + $expected = [ + [ + 'type' => 322, + 'name' => 'render', + 'parameters' => [ + [ + 'variable' => 'item', + 'default' => [ + 'type' => 261, + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'block_statements' => [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 265, + 'value' => 'item', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserMacroDefaultTrue(): void + { + $source = '{% macro show(visible = true) %}{{ visible }}{% endmacro %}'; + $expected = [ + [ + 'type' => 322, + 'name' => 'show', + 'parameters' => [ + [ + 'variable' => 'visible', + 'default' => [ + 'type' => 263, + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'block_statements' => [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 265, + 'value' => 'visible', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserMacroDefaultFalse(): void + { + $source = '{% macro show(visible = false) %}{{ visible }}{% endmacro %}'; + $expected = [ + [ + 'type' => 322, + 'name' => 'show', + 'parameters' => [ + [ + 'variable' => 'visible', + 'default' => [ + 'type' => 262, + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'block_statements' => [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 265, + 'value' => 'visible', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/RangeTest.php b/tests/unit/Compiler/RangeTest.php new file mode 100644 index 0000000..d05fdd3 --- /dev/null +++ b/tests/unit/Compiler/RangeTest.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class RangeTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprRange(): void + { + $source = '{{ 1..10 }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 276, + 'left' => [ + 'type' => 258, + 'value' => '1', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 258, + 'value' => '10', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprRangeVar(): void + { + $source = '{{ start..end }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 276, + 'left' => [ + 'type' => 265, + 'value' => 'start', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'end', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/RawFragmentTest.php b/tests/unit/Compiler/RawFragmentTest.php new file mode 100644 index 0000000..b34eb50 --- /dev/null +++ b/tests/unit/Compiler/RawFragmentTest.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class RawFragmentTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserRawText(): void + { + $source = 'Hello World'; + $expected = [ + [ + 'type' => 357, + 'value' => 'Hello World', + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserRawTextMultiline(): void + { + $source = "Line one +Line two"; + $expected = [ + [ + 'type' => 357, + 'value' => "Line one +Line two", + 'file' => 'eval code', + 'line' => 2, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/RawStatementTest.php b/tests/unit/Compiler/RawStatementTest.php new file mode 100644 index 0000000..663c208 --- /dev/null +++ b/tests/unit/Compiler/RawStatementTest.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class RawStatementTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserRawStatement(): void + { + $source = '{% raw %}{{ this is not parsed }}{% endraw %}'; + $expected = [ + [ + 'type' => 400, + 'content' => [ + 'type' => 359, + 'expr' => [ + 'type' => 273, + 'left' => [ + 'type' => 265, + 'value' => 'this', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'parsed', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/ReturnTest.php b/tests/unit/Compiler/ReturnTest.php new file mode 100644 index 0000000..bdf856f --- /dev/null +++ b/tests/unit/Compiler/ReturnTest.php @@ -0,0 +1,90 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class ReturnTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserReturn(): void + { + $source = '{% return value %}'; + $expected = [ + [ + 'type' => 327, + 'expr' => [ + 'type' => 265, + 'value' => 'value', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserReturnExpr(): void + { + $source = '{% return a + b %}'; + $expected = [ + [ + 'type' => 327, + 'expr' => [ + 'type' => 43, + 'left' => [ + 'type' => 265, + 'value' => 'a', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'b', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/SetTest.php b/tests/unit/Compiler/SetTest.php new file mode 100644 index 0000000..543b7ba --- /dev/null +++ b/tests/unit/Compiler/SetTest.php @@ -0,0 +1,427 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class SetTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserSetAssign(): void + { + $source = '{% set name = \'John\' %}'; + $expected = [ + [ + 'type' => 306, + 'assignments' => [ + [ + 'variable' => [ + 'type' => 265, + 'value' => 'name', + 'file' => 'eval code', + 'line' => 1, + ], + 'op' => 61, + 'expr' => [ + 'type' => 260, + 'value' => 'John', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserSetAssignExpr(): void + { + $source = '{% set total = price * qty %}'; + $expected = [ + [ + 'type' => 306, + 'assignments' => [ + [ + 'variable' => [ + 'type' => 265, + 'value' => 'total', + 'file' => 'eval code', + 'line' => 1, + ], + 'op' => 61, + 'expr' => [ + 'type' => 42, + 'left' => [ + 'type' => 265, + 'value' => 'price', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'qty', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserSetAddAssign(): void + { + $source = '{% set counter += 1 %}'; + $expected = [ + [ + 'type' => 306, + 'assignments' => [ + [ + 'variable' => [ + 'type' => 265, + 'value' => 'counter', + 'file' => 'eval code', + 'line' => 1, + ], + 'op' => 281, + 'expr' => [ + 'type' => 258, + 'value' => '1', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserSetSubAssign(): void + { + $source = '{% set counter -= 1 %}'; + $expected = [ + [ + 'type' => 306, + 'assignments' => [ + [ + 'variable' => [ + 'type' => 265, + 'value' => 'counter', + 'file' => 'eval code', + 'line' => 1, + ], + 'op' => 282, + 'expr' => [ + 'type' => 258, + 'value' => '1', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserSetMulAssign(): void + { + $source = '{% set value *= 2 %}'; + $expected = [ + [ + 'type' => 306, + 'assignments' => [ + [ + 'variable' => [ + 'type' => 265, + 'value' => 'value', + 'file' => 'eval code', + 'line' => 1, + ], + 'op' => 283, + 'expr' => [ + 'type' => 258, + 'value' => '2', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserSetDivAssign(): void + { + $source = '{% set value /= 2 %}'; + $expected = [ + [ + 'type' => 306, + 'assignments' => [ + [ + 'variable' => [ + 'type' => 265, + 'value' => 'value', + 'file' => 'eval code', + 'line' => 1, + ], + 'op' => 284, + 'expr' => [ + 'type' => 258, + 'value' => '2', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserSetMulti(): void + { + $source = '{% set a = 1, b = 2, c = 3 %}'; + $expected = [ + [ + 'type' => 306, + 'assignments' => [ + [ + 'variable' => [ + 'type' => 265, + 'value' => 'a', + 'file' => 'eval code', + 'line' => 1, + ], + 'op' => 61, + 'expr' => [ + 'type' => 258, + 'value' => '1', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'variable' => [ + 'type' => 265, + 'value' => 'b', + 'file' => 'eval code', + 'line' => 1, + ], + 'op' => 61, + 'expr' => [ + 'type' => 258, + 'value' => '2', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'variable' => [ + 'type' => 265, + 'value' => 'c', + 'file' => 'eval code', + 'line' => 1, + ], + 'op' => 61, + 'expr' => [ + 'type' => 258, + 'value' => '3', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserSetArrayAccess(): void + { + $source = '{% set items[0] = \'first\' %}'; + $expected = [ + [ + 'type' => 306, + 'assignments' => [ + [ + 'variable' => [ + 'type' => 361, + 'left' => [ + 'type' => 265, + 'value' => 'items', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 258, + 'value' => '0', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'op' => 61, + 'expr' => [ + 'type' => 260, + 'value' => 'first', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserSetDotAccess(): void + { + $source = '{% set user.name = \'John\' %}'; + $expected = [ + [ + 'type' => 306, + 'assignments' => [ + [ + 'variable' => [ + 'type' => 46, + 'left' => [ + 'type' => 265, + 'value' => 'user', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'name', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'op' => 61, + 'expr' => [ + 'type' => 260, + 'value' => 'John', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ], + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/SliceTest.php b/tests/unit/Compiler/SliceTest.php new file mode 100644 index 0000000..f068323 --- /dev/null +++ b/tests/unit/Compiler/SliceTest.php @@ -0,0 +1,144 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class SliceTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprSliceBoth(): void + { + $source = '{{ items[1:3] }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 365, + 'left' => [ + 'type' => 265, + 'value' => 'items', + 'file' => 'eval code', + 'line' => 1, + ], + 'start' => [ + 'type' => 258, + 'value' => '1', + 'file' => 'eval code', + 'line' => 1, + ], + 'end' => [ + 'type' => 258, + 'value' => '3', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprSliceFrom(): void + { + $source = '{{ items[2:] }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 365, + 'left' => [ + 'type' => 265, + 'value' => 'items', + 'file' => 'eval code', + 'line' => 1, + ], + 'start' => [ + 'type' => 258, + 'value' => '2', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprSliceTo(): void + { + $source = '{{ items[:4] }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 365, + 'left' => [ + 'type' => 265, + 'value' => 'items', + 'file' => 'eval code', + 'line' => 1, + ], + 'end' => [ + 'type' => 258, + 'value' => '4', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/SwitchTest.php b/tests/unit/Compiler/SwitchTest.php new file mode 100644 index 0000000..f283a9b --- /dev/null +++ b/tests/unit/Compiler/SwitchTest.php @@ -0,0 +1,126 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class SwitchTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserSwitchCase(): void + { + $source = '{% switch status %}{% case 1 %}Active{% case 2 %}Pending{% default %}Unknown{% endswitch %}'; + $expected = [ + [ + 'type' => 411, + 'expr' => [ + 'type' => 265, + 'value' => 'status', + 'file' => 'eval code', + 'line' => 1, + ], + 'case_clauses' => [ + [ + 'type' => 412, + 'expr' => [ + 'type' => 258, + 'value' => '1', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'type' => 357, + 'value' => 'Active', + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'type' => 412, + 'expr' => [ + 'type' => 258, + 'value' => '2', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'type' => 357, + 'value' => 'Pending', + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'type' => 413, + 'file' => 'eval code', + 'line' => 1, + ], + [ + 'type' => 357, + 'value' => 'Unknown', + 'file' => 'eval code', + 'line' => 1, + ], + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserSwitchEmpty(): void + { + $source = '{% switch status %}{% endswitch %}'; + $expected = [ + [ + 'type' => 411, + 'expr' => [ + 'type' => 265, + 'value' => 'status', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Compiler/TernaryTest.php b/tests/unit/Compiler/TernaryTest.php new file mode 100644 index 0000000..83095c7 --- /dev/null +++ b/tests/unit/Compiler/TernaryTest.php @@ -0,0 +1,113 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Tests\Unit\Compiler; + +use Phalcon\Volt\Compiler; +use PHPUnit\Framework\TestCase; + +final class TernaryTest extends TestCase +{ + private Compiler $compiler; + + public function setUp(): void + { + $this->compiler = new Compiler(); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprTernary(): void + { + $source = '{{ condition ? \'yes\' : \'no\' }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 366, + 'ternary' => [ + 'type' => 265, + 'value' => 'condition', + 'file' => 'eval code', + 'line' => 1, + ], + 'left' => [ + 'type' => 260, + 'value' => 'yes', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 260, + 'value' => 'no', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } + + /** + * @return void + * + * @author Phalcon Team + * @since 2026-04-10 + */ + public function testMvcViewEngineVoltParserExprTernaryVar(): void + { + $source = '{{ active ? activeLabel : inactiveLabel }}'; + $expected = [ + [ + 'type' => 359, + 'expr' => [ + 'type' => 366, + 'ternary' => [ + 'type' => 265, + 'value' => 'active', + 'file' => 'eval code', + 'line' => 1, + ], + 'left' => [ + 'type' => 265, + 'value' => 'activeLabel', + 'file' => 'eval code', + 'line' => 1, + ], + 'right' => [ + 'type' => 265, + 'value' => 'inactiveLabel', + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + 'file' => 'eval code', + 'line' => 1, + ], + ]; + $actual = $this->compiler->parse($source); + $this->assertSame($expected, $actual); + } +}