packages/deriver/tests/Unit/Deriver/Evaluator/Predicate/TruthTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Deriver\Evaluator\Predicate;
6
7use Deriver\Deriver\Evaluator\Call\Evaluators;
8use Deriver\Deriver\Evaluator\Enumeration\Choices;
9use Deriver\Deriver\Evaluator\Evaluator;
10use Deriver\Deriver\Evaluator\EvaluatorConfig;
11use Deriver\Deriver\Evaluator\Index\DefinitionIndex;
12use Deriver\Deriver\Evaluator\Micro\Request;
13use Deriver\Deriver\Evaluator\Predicate\Truth;
14use Deriver\Deriver\Evaluator\Request\Budget;
15use Deriver\Deriver\Evaluator\Scope\Context;
16use Deriver\Deriver\Evaluator\Scope\Frame;
17use Deriver\Deriver\Lowerer\Declaration\Index;
18use Deriver\Deriver\Parser\Parser;
19use Deriver\Deriver\Parser\ParserConfig;
20use Deriver\Deriver\Resolver\Resolver;
21use Deriver\Deriver\Sources\Source;
22use PHPUnit\Framework\Attributes\CoversNothing;
23use PHPUnit\Framework\TestCase;
24
25#[CoversNothing]
26final class TruthTest extends TestCase
27{
28 public function testValueKeepsTheBooleanCacheSeparateFromFullValueCandidates(): void
29 {
30 $source = 'function subject($x){return $x?1:2;}';
31 $tree = (new Resolver())->resolve((new Parser(new ParserConfig('8.3')))->parse(new Source('a.php', '<?php ' . $source)));
32 $index = new DefinitionIndex(new Index('s', [$tree]));
33 $config = new EvaluatorConfig();
34 $engine = new Evaluator(new Context($index, $config, new Evaluators($config->target), new Budget()));
35 $graph = $index->graph('subject');
36 self::assertNotNull($graph);
37 $frame = new Frame($graph, 'source:subject');
38 $register = $graph->returns()[0][1];
39 self::assertSame(true, (new Truth($engine))->value($frame, $register, 32)->native());
40 $values = array_map(static fn (array $row) => $row[0]->native(), iterator_to_array((new Choices())->alternatives($engine->value($frame, $register, 32))));
41 self::assertSame([1,2], $values);
42 }
43
44 public function testEvaluatePropagatesNegationToTheBooleanDemand(): void
45 {
46 $source = 'function subject(){return !0;}';
47 $tree = (new Resolver())->resolve((new Parser(new ParserConfig('8.3')))->parse(new Source('a.php', '<?php ' . $source)));
48 $index = new DefinitionIndex(new Index('s', [$tree]));
49 $config = new EvaluatorConfig();
50 $engine = new Evaluator(new Context($index, $config, new Evaluators($config->target), new Budget()));
51 $graph = $index->graph('subject');
52 self::assertNotNull($graph);
53 $frame = new Frame($graph, 'source:subject');
54 $instruction = $graph->definitions[$graph->returns()[0][1]];
55 self::assertSame(true, (new Truth($engine))->evaluate(new Request($engine, $frame, $instruction, 32))->native());
56 }
57 public function testDefinitionRetainsUnknownPredicates(): void
58 {
59 $source = 'function subject($x){return $x;}';
60 $tree = (new Resolver())->resolve((new Parser(new ParserConfig('8.3')))->parse(new Source('a.php', '<?php ' . $source)));
61 $index = new DefinitionIndex(new Index('s', [$tree]));
62 $config = new EvaluatorConfig();
63 $engine = new Evaluator(new Context($index, $config, new Evaluators($config->target), new Budget()));
64 $graph = $index->graph('subject');
65 self::assertNotNull($graph);
66 $frame = new Frame($graph, 'source:subject');
67 $value = (new Truth($engine))->definition($frame, $graph->returns()[0][1], 32);
68 self::assertFalse($value->isConcrete());
69 self::assertNotEmpty($value->operands);
70 }
71
72 public function testIterationExcludesTheBodyOfAKnownEmptyIterable(): void
73 {
74 $source = 'function subject(){foreach([] as $v){}return 42;}';
75 $tree = (new Resolver())->resolve((new Parser(new ParserConfig('8.3')))->parse(new Source('a.php', '<?php ' . $source)));
76 $index = new DefinitionIndex(new Index('s', [$tree]));
77 $config = new EvaluatorConfig();
78 $engine = new Evaluator(new Context($index, $config, new Evaluators($config->target), new Budget()));
79 $graph = $index->graph('subject');
80 self::assertNotNull($graph);
81 $frame = new Frame($graph, 'source:subject');
82 $instruction = array_values(array_filter($graph->definitions, static fn ($definition): bool => $definition->operation === 'iterate'))[0];
83 self::assertSame(false, (new Truth($engine))->iteration(new Request($engine, $frame, $instruction, 32))->native());
84 }
85
86}
87