packages/sql-fixture/tests/Unit/Version/ServerVersionTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Version;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\DataProvider;
9use PHPUnit\Framework\Attributes\UsesClass;
10use PHPUnit\Framework\TestCase;
11use SqlFixture\Version\ReleaseNumber;
12use SqlFixture\Version\Releases;
13use SqlFixture\Version\ServerVersion as Subject;
14use SqlFixture\Version\UnsupportedVersionException;
15
16#[CoversClass(Subject::class)]
17#[UsesClass(Releases::class)]
18#[UsesClass(ReleaseNumber::class)]
19#[UsesClass(UnsupportedVersionException::class)]
20final class ServerVersionTest extends TestCase
21{
22    public function testResolveNamesTheDefaultOfEachDialect(): void
23    {
24        self::assertSame('mysql-8.4.7', Subject::resolve('mysql')->tag);
25        self::assertSame('pg-17.2', Subject::resolve('pgsql')->tag);
26        self::assertSame('sqlite-3.47.2', Subject::resolve('sqlite')->tag);
27    }
28
29    public function testResolveReadsTheNumberOfATag(): void
30    {
31        $release = Subject::resolve('mysql', 'mysql-5.7.44');
32        self::assertSame('mysql', $release->dialect);
33        self::assertSame('mysql-5.7.44', $release->tag);
34        self::assertSame('5.7.44', $release->number);
35    }
36
37    public function testResolveRejectsATagOfAnotherDialect(): void
38    {
39        $this->expectException(UnsupportedVersionException::class);
40        $this->expectExceptionMessage('Unsupported mysql version: pg-17.2');
41        Subject::resolve('mysql', 'pg-17.2');
42    }
43
44    public function testResolveRejectsAnUnknownDialect(): void
45    {
46        $this->expectException(UnsupportedVersionException::class);
47        $this->expectExceptionMessage('No supported versions are registered for the oracle driver');
48        Subject::resolve('oracle');
49    }
50
51    /**
52     * @return iterable<string, array{string, string, string}>
53     */
54    public static function providerServerVersions(): iterable
55    {
56        yield 'same series with a build suffix' => ['mysql', '8.0.36-0ubuntu0.22.04.1', 'mysql-8.0.44'];
57        yield 'same series with a log suffix' => ['mysql', '5.7.44-log', 'mysql-5.7.44'];
58        yield 'exact release' => ['mysql', '9.1.0', 'mysql-9.1.0'];
59        yield 'newer than every release' => ['mysql', '9.4.0', 'mysql-9.1.0'];
60        yield 'older than every release' => ['mysql', '5.5.62', 'mysql-5.6.51'];
61        yield 'postgres with a distribution note' => ['pgsql', '17.2 (Debian 17.2-1.pgdg120+1)', 'pg-17.2'];
62        yield 'postgres of an older series' => ['pgsql', '16.6', 'pg-16.6'];
63        yield 'postgres older than every release' => ['pgsql', '15.8', 'pg-16.6'];
64        yield 'sqlite newer than the release' => ['sqlite', '3.53.3', 'sqlite-3.47.2'];
65        yield 'sqlite older than the release' => ['sqlite', '3.45.1', 'sqlite-3.47.2'];
66    }
67
68    #[DataProvider('providerServerVersions')]
69    public function testFromServerMatchesTheClosestRelease(string $dialect, string $reported, string $expected): void
70    {
71        self::assertSame($expected, Subject::fromServer($dialect, $reported)->tag);
72    }
73
74    public function testFromServerRejectsAStringWithoutANumber(): void
75    {
76        $this->expectException(UnsupportedVersionException::class);
77        $this->expectExceptionMessage('Unsupported mysql version: unknown');
78        Subject::fromServer('mysql', 'unknown');
79    }
80
81    public function testAllListsTheReleasesOldestFirst(): void
82    {
83        $numbers = array_map(static fn (Subject $release): string => $release->number, Subject::all('mysql'));
84        self::assertSame(['5.6.51', '5.7.44', '8.0.44', '8.1.0', '8.2.0', '8.3.0', '8.4.7', '9.0.1', '9.1.0'], $numbers);
85    }
86
87    public function testTagsMatchTheOtherSqlPackages(): void
88    {
89        self::assertSame([
90            'mysql-5.6.51',
91            'mysql-5.7.44',
92            'mysql-8.0.44',
93            'mysql-8.1.0',
94            'mysql-8.2.0',
95            'mysql-8.3.0',
96            'mysql-8.4.7',
97            'mysql-9.0.1',
98            'mysql-9.1.0',
99        ], Subject::tags('mysql'));
100        self::assertSame(['pg-16.6', 'pg-17.2'], Subject::tags('pgsql'));
101        self::assertSame(['sqlite-3.47.2'], Subject::tags('sqlite'));
102    }
103
104    public function testIsDefaultMarksOneReleasePerDialect(): void
105    {
106        $defaults = array_values(array_filter(Subject::all('mysql'), static fn (Subject $release): bool => $release->isDefault()));
107        self::assertCount(1, $defaults);
108        self::assertSame('mysql-8.4.7', $defaults[0]->tag);
109    }
110
111    public function testIdNumbersTheReleaseLikeMysql(): void
112    {
113        self::assertSame(80044, Subject::resolve('mysql', 'mysql-8.0.44')->id());
114        self::assertSame(170200, Subject::resolve('pgsql', 'pg-17.2')->id());
115    }
116
117    public function testSeriesDropsTheLastNumber(): void
118    {
119        self::assertSame('8.0', Subject::resolve('mysql', 'mysql-8.0.44')->series());
120        self::assertSame('17', Subject::resolve('pgsql', 'pg-17.2')->series());
121    }
122
123    public function testIsAtLeastComparesNumbers(): void
124    {
125        $release = Subject::resolve('mysql', 'mysql-5.7.44');
126        self::assertTrue($release->isAtLeast('5.7.8'));
127        self::assertTrue($release->isAtLeast('5.7.44'));
128        self::assertFalse($release->isAtLeast('8.0'));
129    }
130}
131