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