packages/deriver/tests/Unit/Deriver/Evaluator/Recurrence/ObservationTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Deriver\Evaluator\Recurrence;
6
7use Deriver\Deriver\BranchEvaluators;
8use Deriver\Deriver\Evaluator\Call\Evaluators;
9use Deriver\Deriver\Evaluator\Evaluator;
10use Deriver\Deriver\Evaluator\EvaluatorConfig;
11use Deriver\Deriver\Evaluator\Index\DefinitionIndex;
12use Deriver\Deriver\Evaluator\Recurrence\Observation;
13use Deriver\Deriver\Evaluator\Request\Budget;
14use Deriver\Deriver\Evaluator\Scope\Context;
15use Deriver\Deriver\Evaluator\Scope\Frame;
16use Deriver\Deriver\Lowerer\Declaration\Index;
17use Deriver\Deriver\MicroEvaluatorConversion;
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 ObservationTest extends TestCase
27{
28    public function testFrameUsesEntryBindingsOnlyInsideOnePassBodies(): void
29    {
30        $tree = (new Resolver())->resolve((new Parser(new ParserConfig('8.3')))->parse(new Source('a.php', '<?php function subject(){for($i=0;$i<1;$i++){$v=$i;}return $v;}')));
31        $index = new DefinitionIndex(new Index('s', [$tree]));
32        $config = new EvaluatorConfig(evaluators: array_map((new MicroEvaluatorConversion())->convert(...), BranchEvaluators::truth()));
33        $engine = new Evaluator(new Context($index, $config, new Evaluators($config->target), new Budget()));
34        $graph = $index->graph('subject');
35        self::assertNotNull($graph);
36        $frame = new Frame($graph, 'source:subject');
37        $header = array_values(array_filter($graph->body->blocks, static fn ($block): bool => $block->loopHeader))[0];
38        $observation = new Observation($engine);
39        self::assertSame([$header->id => 0], $observation->frame($frame, $header->terminator->targets[0], 32)->iterations);
40        self::assertSame($frame, $observation->frame($frame, $header->terminator->targets[1], 32));
41    }
42
43    public function testConditionSeparatesEntryAndExitObservations(): void
44    {
45        $tree = (new Resolver())->resolve((new Parser(new ParserConfig('8.3')))->parse(new Source('a.php', '<?php function subject(){for($i=0;$i<1;$i++){$v=$i;}return $v;}')));
46        $index = new DefinitionIndex(new Index('s', [$tree]));
47        $config = new EvaluatorConfig(evaluators: array_map((new MicroEvaluatorConversion())->convert(...), BranchEvaluators::truth()));
48        $engine = new Evaluator(new Context($index, $config, new Evaluators($config->target), new Budget()));
49        $graph = $index->graph('subject');
50        self::assertNotNull($graph);
51        $frame = new Frame($graph, 'source:subject');
52        $header = array_values(array_filter($graph->body->blocks, static fn ($block): bool => $block->loopHeader))[0];
53        $observation = new Observation($engine);
54        self::assertSame([$header->id => 0], $observation->condition($frame, $header->id, true, 32)->iterations);
55        self::assertSame([$header->id => 1], $observation->condition($frame, $header->id, false, 32)->iterations);
56    }
57
58    public function testBodiesSharesStructuralMembershipAcrossObservations(): void
59    {
60        $tree = (new Resolver())->resolve((new Parser(new ParserConfig('8.3')))->parse(new Source('a.php', '<?php function subject(){for($i=0;$i<10000;$i++){$v=$i;}return $v;}')));
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        $header = array_values(array_filter($graph->body->blocks, static fn ($block): bool => $block->loopHeader))[0];
68        $observation = new Observation($engine);
69        $bodies = $observation->bodies($frame);
70        self::assertArrayHasKey($header->terminator->targets[0], $bodies[$header->id]);
71        self::assertArrayNotHasKey($header->terminator->targets[1], $bodies[$header->id]);
72        self::assertSame($bodies, $graph->loopBodies);
73        self::assertSame($bodies, $observation->bodies($frame));
74        self::assertSame($frame, $observation->frame($frame, $header->terminator->targets[0], 32));
75    }
76}
77