packages/deriver/tests/Unit/Deriver/Sources/SourceRefTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Deriver\Sources;
6
7use Deriver\Deriver\Sources\SourceRef;
8use Deriver\Exception\InvalidInputException;
9use PHPUnit\Framework\Attributes\CoversClass;
10use PHPUnit\Framework\Attributes\DataProvider;
11use PHPUnit\Framework\Attributes\Small;
12use PHPUnit\Framework\TestCase;
13
14#[CoversClass(SourceRef::class)]
15#[Small]
16final class SourceRefTest extends TestCase
17{
18    public function testIdPreservesTheSemanticContract(): void
19    {
20        $this->expectException(InvalidInputException::class);
21        $this->expectExceptionMessage('half-open');
22        new SourceRef('s', 'a.php', 4, 3);
23    }
24
25    #[DataProvider('providerInvalidCoordinates')]
26    public function testRejectsCoordinatesOutsideHalfOpenSourceRanges(int $start, int $end, int $line, int $column): void
27    {
28        $this->expectException(InvalidInputException::class);
29        $this->expectExceptionMessage('Source ranges must be half-open and coordinates positive.');
30        new SourceRef('snapshot', 'file.php', $start, $end, $line, $column);
31    }
32
33    /**
34     * @return iterable<string,array{int,int,int,int}>
35     */
36    public static function providerInvalidCoordinates(): iterable
37    {
38        yield 'negative start' => [-1,0,1,1];
39        yield 'end before start' => [2,1,1,1];
40        yield 'zero line' => [0,0,0,1];
41        yield 'negative line' => [0,0,-1,1];
42        yield 'zero column' => [0,0,1,0];
43        yield 'negative column' => [0,0,1,-1];
44    }
45
46    public function testIdIncludesSnapshotPathAndBothByteEndpoints(): void
47    {
48        $source = new SourceRef('snapshot', 'src/file.php', 7, 29, 3, 5);
49        self::assertSame('snapshot:src/file.php:7:29', $source->id());
50        self::assertSame('snapshot', $source->snapshotId);
51        self::assertSame('src/file.php', $source->path);
52        self::assertSame(7, $source->start);
53        self::assertSame(29, $source->end);
54        self::assertSame(3, $source->line);
55        self::assertSame(5, $source->column);
56        self::assertSame('empty:file.php:0:0', (new SourceRef('empty', 'file.php', 0, 0))->id());
57    }
58}
59