packages/sql-fixture/tests/Integration/PostgreSql/PostgreSqlReleaseRoundTripTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Integration\PostgreSql;
6
7use Container\Endpoint;
8use Container\PostgreSql16Container;
9use Container\PostgreSql17Container;
10use Container\PostgreSqlContainer;
11use Faker\Factory;
12use PDO;
13use PHPUnit\Framework\Attributes\CoversNothing;
14use PHPUnit\Framework\Attributes\DataProvider;
15use PHPUnit\Framework\Attributes\Large;
16use PHPUnit\Framework\TestCase;
17use SqlFixture\Provider\DatabaseFixtureProvider;
18use Testcontainers\Testcontainers;
19
20#[CoversNothing]
21#[Large]
22final class PostgreSqlReleaseRoundTripTest extends TestCase
23{
24    /**
25     * @return iterable<string, array{class-string<PostgreSqlContainer>, int}>
26     */
27    public static function providerReleases(): iterable
28    {
29        $selected = getenv('SQL_FIXTURE_PGSQL_VERSION');
30        $containers = [
31            PostgreSql16Container::class,
32            PostgreSql17Container::class,
33        ];
34        foreach ($containers as $container) {
35            $tag = $container::getGrammarVersion();
36            if ($selected !== false && $selected !== '' && $tag !== 'pg-' . $selected) {
37                continue;
38            }
39            foreach ([1, 2, 3] as $seed) {
40                yield $tag . ' seed ' . $seed => [$container, $seed];
41            }
42        }
43    }
44
45    /**
46     * @param class-string<PostgreSqlContainer> $container
47     */
48    #[DataProvider('providerReleases')]
49    public function testRowGeneratedFromTheReportedSchemaIsAccepted(string $container, int $seed): void
50    {
51        $endpoint = Testcontainers::run($container)->getData(Endpoint::class);
52        $pdo = new PDO($endpoint->dsn(), $endpoint->username, $endpoint->password, [
53            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
54            PDO::ATTR_EMULATE_PREPARES => false,
55        ]);
56        $faker = Factory::create();
57        $faker->seed($seed);
58        $provider = new DatabaseFixtureProvider($faker, $pdo);
59        self::assertSame($container::getGrammarVersion(), $provider->getVersion());
60
61        $table = 'fixture_' . bin2hex(random_bytes(4));
62        $pdo->exec(<<<SQL
63            CREATE TABLE {$table} (
64                id SERIAL PRIMARY KEY,
65                col_smallint SMALLINT NOT NULL,
66                col_integer INTEGER NOT NULL,
67                col_bigint BIGINT NOT NULL,
68                col_numeric NUMERIC(10, 2) NOT NULL,
69                col_real REAL NOT NULL,
70                col_double DOUBLE PRECISION NOT NULL,
71                col_boolean BOOLEAN NOT NULL,
72                col_char CHAR(10) NOT NULL,
73                col_varchar VARCHAR(100) NOT NULL,
74                col_text TEXT NOT NULL,
75                col_bytea BYTEA NOT NULL,
76                col_date DATE NOT NULL,
77                col_time TIME NOT NULL,
78                col_timetz TIMETZ NOT NULL,
79                col_timestamp TIMESTAMP NOT NULL,
80                col_timestamptz TIMESTAMPTZ NOT NULL,
81                col_interval INTERVAL NOT NULL,
82                col_uuid UUID NOT NULL,
83                col_json JSON NOT NULL,
84                col_jsonb JSONB NOT NULL,
85                col_inet INET NOT NULL,
86                col_cidr CIDR NOT NULL,
87                col_macaddr MACADDR NOT NULL,
88                col_money MONEY NOT NULL,
89                col_xml XML NOT NULL,
90                col_text_array TEXT[] NOT NULL,
91                col_int_array INTEGER[] NOT NULL,
92                col_nullable VARCHAR(20) DEFAULT 'none'
93            )
94            SQL);
95        try {
96            $row = $provider->fixture($table);
97            $statement = $pdo->prepare(sprintf(
98                'INSERT INTO %s (%s) VALUES (%s)',
99                $table,
100                implode(', ', array_keys($row)),
101                implode(', ', array_fill(0, count($row), '?')),
102            ));
103            self::assertTrue($statement->execute(array_values(array_replace($row, array_map('intval', array_filter($row, 'is_bool'))))));
104            $count = $pdo->query(sprintf('SELECT COUNT(*) FROM %s', $table));
105            self::assertNotFalse($count);
106            self::assertSame(1, (int) $count->fetchColumn());
107        } finally {
108            $pdo->exec(sprintf('DROP TABLE IF EXISTS %s', $table));
109        }
110    }
111}
112