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