packages/deriver/tests/Unit/Deriver/Evaluator/Execution/Call/Contract/InputsTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Deriver\Evaluator\Execution\Call\Contract;
6
7use Deriver\Deriver\Evaluator\Call\CallDescriptor;
8use Deriver\Deriver\Evaluator\Declaration\Signature;
9use Deriver\Deriver\Evaluator\Execution\Call\Contract\Inputs;
10use Deriver\Deriver\Evaluator\Execution\Call\PassedArgument;
11use Deriver\Deriver\Evaluator\Execution\State;
12use Deriver\Deriver\Evaluator\Term;
13use Deriver\Deriver\Lowerer\Graph\Instruction;
14use Deriver\Deriver\Sources\SourceRef;
15use PHPUnit\Framework\Attributes\CoversClass;
16use PHPUnit\Framework\Attributes\Small;
17use PHPUnit\Framework\Attributes\UsesClass;
18use PHPUnit\Framework\TestCase;
19
20/**
21 * @covers \Deriver\Deriver\Evaluator\Execution\Call\Contract\Inputs
22 */
23#[CoversClass(Inputs::class)]
24#[UsesClass(\Deriver\Deriver\Lowerer\Graph\BasicBlock::class)]
25#[UsesClass(\Deriver\Deriver\Lowerer\Graph\CallableGraph::class)]
26#[UsesClass(Instruction::class)]
27#[UsesClass(\Deriver\Deriver\Lowerer\Graph\Parameter::class)]
28#[UsesClass(\Deriver\Deriver\Lowerer\Graph\Terminator::class)]
29#[UsesClass(\Deriver\Deriver\Evaluator\Execution\Call\ArgumentOrder::class)]
30#[UsesClass(PassedArgument::class)]
31#[UsesClass(\Deriver\Deriver\Evaluator\Execution\Completion\Completion::class)]
32#[UsesClass(State::class)]
33#[UsesClass(\Deriver\Deriver\Evaluator\Execution\Memory\Location::class)]
34#[UsesClass(\Deriver\Deriver\Evaluator\Execution\Memory\Materialization::class)]
35#[UsesClass(\Deriver\Deriver\Evaluator\Execution\Memory\Memory::class)]
36#[UsesClass(\Deriver\Deriver\Evaluator\Call\ArgumentBindings::class)]
37#[UsesClass(\Deriver\Deriver\Evaluator\Call\BoundArgument::class)]
38#[UsesClass(\Deriver\Deriver\Evaluator\Call\Plan\Location\LocationRef::class)]
39#[UsesClass(\Deriver\Deriver\Evaluator\Call\Plan\PlanCompiler::class)]
40#[UsesClass(CallDescriptor::class)]
41#[UsesClass(\Deriver\Deriver\Evaluator\Call\Plan\SemanticPlan::class)]
42#[UsesClass(\Deriver\Deriver\Evaluator\Declaration\Parameter::class)]
43#[UsesClass(Signature::class)]
44#[UsesClass(SourceRef::class)]
45#[UsesClass(Term::class)]
46#[Small]
47final class InputsTest extends TestCase
48{
49 public function testBindingsNormalizesNamedDefaultsAndVariadicKeys(): void
50 {
51 $descriptor = new CallDescriptor('sample', '1', 'sample', new Signature([new \Deriver\Deriver\Evaluator\Declaration\Parameter('id', default: Term::constant(3)), new \Deriver\Deriver\Evaluator\Declaration\Parameter('rest', variadic: true)]));
52 $instruction = new \Deriver\Deriver\Evaluator\Call\BoundInstruction('call', 'invoke', new SourceRef('test', 'fixture.php', 0, 1));
53 $bindings = (new Inputs())->bindings($descriptor, $instruction, [new PassedArgument(Term::constant(2), 'named')], new State());
54 self::assertTrue($bindings->evaluated);
55 self::assertFalse($bindings->arguments['id']->supplied);
56 self::assertSame(3, $bindings->arguments['id']->value->native());
57 self::assertSame(['named' => 2], $bindings->arguments['rest']->value->native());
58 }
59 public function testBindingsReadsCurrentReferenceCellWithoutExposingItsIdentity(): void
60 {
61 $descriptor = new CallDescriptor('sample', '1', 'sample', new Signature([new \Deriver\Deriver\Evaluator\Declaration\Parameter('id', byReference: true)]));
62 $instruction = new \Deriver\Deriver\Evaluator\Call\BoundInstruction('call', 'invoke', new SourceRef('test', 'fixture.php', 0, 1));
63 $state = new State();
64 $address = $state->local('source');
65 $state->memory->write($address, Term::constant(4));
66 $bindings = (new Inputs())->bindings($descriptor, $instruction, [new PassedArgument(Term::constant(1), location: $address)], $state);
67 self::assertSame(4, $bindings->arguments['id']->value->native());
68 self::assertSame('id', $bindings->arguments['id']->location?->name);
69 }
70 public function testBindingsRetainsInvalidArgumentOrder(): void
71 {
72 $descriptor = new CallDescriptor('sample', '1', 'sample');
73 $instruction = new \Deriver\Deriver\Evaluator\Call\BoundInstruction('call', 'invoke', new SourceRef('test', 'fixture.php', 0, 1));
74 $bindings = (new Inputs())->bindings($descriptor, $instruction, [new PassedArgument(Term::constant(1), 'absent')], new State());
75 self::assertSame('Error', $bindings->error);
76 }
77 public function testValueReadsCurrentVariadicReferenceCells(): void
78 {
79 $state = new State();
80 $location = $state->local('source');
81 $state->memory->write($location, Term::constant(4));
82 $actual = new PassedArgument(Term::fromNative(['key' => 1]), elements: ['key' => new PassedArgument(Term::constant(1), location: $location)]);
83 $value = (new Inputs())->value(new \Deriver\Deriver\Evaluator\Declaration\Parameter('items', byReference: true, variadic: true), $actual, $state);
84 self::assertSame(['key' => 4], $value->native());
85 }
86}
87