packages/deriver/tests/Unit/Deriver/Evaluator/Call/PrecedenceTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Deriver\Evaluator\Call;
6
7use Deriver\Deriver\Evaluator\Call\CallDescriptor;
8use Deriver\Deriver\Evaluator\Call\Precedence;
9use Deriver\Exception\InvalidInputException;
10use PHPUnit\Framework\Attributes\CoversClass;
11use PHPUnit\Framework\Attributes\Small;
12use PHPUnit\Framework\Attributes\UsesClass;
13use PHPUnit\Framework\TestCase;
14
15/**
16 * @covers \Deriver\Deriver\Evaluator\Call\Precedence
17 */
18#[CoversClass(Precedence::class)]
19#[UsesClass(InvalidInputException::class)]
20#[UsesClass(CallDescriptor::class)]
21#[UsesClass(\Deriver\Deriver\Evaluator\Declaration\Signature::class)]
22#[Small]
23final class PrecedenceTest extends TestCase
24{
25 public function testSelectUsesTransitiveReplacementIndependentlyOfOrder(): void
26 {
27 $a = new CallDescriptor('a', '1', 'target');
28 $b = new CallDescriptor('b', '1', 'target', replaces: ['a']);
29 $c = new CallDescriptor('c', '1', 'target', replaces: ['b']);
30 $precedence = new Precedence();
31 self::assertSame('c', $precedence->select(['a' => $a, 'c' => $c, 'b' => $b]));
32 self::assertSame('c', $precedence->select(['b' => $b, 'c' => $c, 'a' => $a]));
33 }
34 public function testSelectRejectsEqualMaxima(): void
35 {
36 $this->expectException(InvalidInputException::class);
37 (new Precedence())->select(['a' => new CallDescriptor('a', '1', 'target'), 'b' => new CallDescriptor('b', '1', 'target')]);
38 }
39 public function testSelectAllowsOneHigherPriorityOverAnEqualLowerTier(): void
40 {
41 $a = new CallDescriptor('a', '1', 'target');
42 $b = new CallDescriptor('b', '1', 'target');
43 $c = new CallDescriptor('c', '1', 'target', priority: 1);
44 self::assertSame('c', (new Precedence())->select(['b' => $b, 'a' => $a, 'c' => $c]));
45 }
46 public function testAcyclicRejectsThreeNodeCycles(): void
47 {
48 $this->expectException(InvalidInputException::class);
49 (new Precedence())->acyclic(['a' => ['b' => true], 'b' => ['c' => true], 'c' => ['a' => true]]);
50 }
51 public function testAcyclicAcceptsSharedDependencies(): void
52 {
53 (new Precedence())->acyclic(['a' => ['c' => true], 'b' => ['c' => true], 'c' => []]);
54 self::assertSame('a', (new Precedence())->select(['a' => new CallDescriptor('a', '1', 'target')]));
55 }
56}
57