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