Skip to content

Commit

Permalink
TypesNode validates mapping
Browse files Browse the repository at this point in the history
Keys must be NameExpressions, values must be string constants.
  • Loading branch information
drjayvee committed Aug 23, 2024
1 parent ed00857 commit e06d15b
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 4 deletions.
28 changes: 27 additions & 1 deletion src/Node/TypesNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,46 @@

use Twig\Compiler;
use Twig\Node\Expression\ArrayExpression;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Expression\NameExpression;

/**
* Represents a types node.
*
* @author Jeroen Versteeg <[email protected]>
* @see https://github.com/twigphp/Twig/issues/4165
* @see https://github.com/twigphp/Twig/issues/4165
*/
class TypesNode extends Node implements NodeCaptureInterface
{
public function __construct(ArrayExpression $typesNode, int $lineno, ?string $tag = null)
{
$this->validateMapping($typesNode);

parent::__construct(['mapping' => $typesNode], [], $lineno, $tag);
}

protected function validateMapping(ArrayExpression $typesNode): void
{
foreach ($typesNode->getKeyValuePairs() as $i => $pair) {
$keyExpression = $pair['key'];
$valueExpression = $pair['value'];

if (!$keyExpression instanceof NameExpression) {
throw new \InvalidArgumentException("Key at index $i is not a NameExpression");
}
$name = $keyExpression->getAttribute('name');

if (!$valueExpression instanceof ConstantExpression) {
throw new \InvalidArgumentException("Value for key \"$name\" is not a ConstantExpression");
}
$value = $valueExpression->getAttribute('value');

if (!is_string($value)) {
throw new \InvalidArgumentException("Value for key \"$name\" is not a string");
}
}
}

public function compile(Compiler $compiler)
{
// Don't compile anything.
Expand Down
75 changes: 72 additions & 3 deletions tests/Node/TypesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
class TypesTest extends NodeTestCase
{
/** @return ArrayExpression */
private function createArrayExpression()
private function getValidMapping()
{
// {foo: 'string', bar: 'int'}
return new ArrayExpression([
Expand All @@ -25,18 +25,87 @@ private function createArrayExpression()

public function testConstructor()
{
$types = $this->createArrayExpression();
$types = $this->getValidMapping();
$node = new TypesNode($types, 1);

$this->assertEquals($types, $node->getNode('mapping'));
}

/** @return array<array<ArrayExpression>> */
public function getInvalidMappings()
{
return [
// {'foo': string}
[
new ArrayExpression([
new ConstantExpression('foo', 1),
new ConstantExpression('string', 1),
], 1),
'Key at index 0 is not a NameExpression'
],

// [13, 37]
[
new ArrayExpression([
new ConstantExpression(13, 1),
new ConstantExpression(37, 1),
], 1),
'Key at index 0 is not a NameExpression'
],

// {foo: bar}
[
new ArrayExpression([
new NameExpression('foo', 1),
new NameExpression('bar', 1),
], 1),
'Value for key "foo" is not a ConstantExpression'
],

// {foo: true}
[
new ArrayExpression([
new NameExpression('foo', 1),
new ConstantExpression(true, 1),
], 1),
'Value for key "foo" is not a string'
],

// {foo: 123}
[
new ArrayExpression([
new NameExpression('foo', 1),
new ConstantExpression(123, 1),
], 1),
'Value for key "foo" is not a string'
],

// {foo: {}}}
[
new ArrayExpression([
new NameExpression('foo', 1),
new ConstantExpression(new ArrayExpression([], 1), 1),
], 1),
'Value for key "foo" is not a string'
],
];
}

/** @dataProvider getInvalidMappings */
public function testConstructorThrowsOnInvalidMapping(ArrayExpression $mapping, string $message)
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage($message);

new TypesNode($mapping, 1);
}

public function getTests()
{
return [
// 1st test: Node shouldn't compile at all
[
new TypesNode($this->createArrayExpression(), 1),
new TypesNode($this->getValidMapping(), 1),
''
]
];
Expand Down

0 comments on commit e06d15b

Please sign in to comment.