packages/ztd-query-mysqli-adapter/tests/Unit/Native/MysqliStatementPropertyReaderTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Native;
6
7use Container\Endpoint;
8use Container\MySqlRelease;
9use mysqli;
10use mysqli_stmt;
11use PHPUnit\Framework\Attributes\CoversClass;
12use PHPUnit\Framework\Attributes\Large;
13use PHPUnit\Framework\TestCase;
14use Testcontainers\Testcontainers;
15use ZtdQuery\Adapter\Mysqli\Native\MysqliStatementPropertyReader;
16
17#[CoversClass(MysqliStatementPropertyReader::class)]
18#[Large]
19final class MysqliStatementPropertyReaderTest extends TestCase
20{
21    public function testReadPreservesPreparedMetadataAndBufferedRowCounts(): void
22    {
23        $container = Testcontainers::run(MySqlRelease::fromEnvironment());
24        $endpoint = $container->getData(Endpoint::class);
25        try {
26            $connection = new mysqli($endpoint->host, $endpoint->username, $endpoint->password, $endpoint->database, $endpoint->port);
27            $connection->set_charset('utf8mb4');
28            $statement = $connection->prepare('SELECT ? AS value UNION ALL SELECT ?');
29            self::assertInstanceOf(mysqli_stmt::class, $statement);
30            $reader = new MysqliStatementPropertyReader();
31            self::assertSame(2, $reader->read($statement, 'param_count'));
32            self::assertSame(1, $reader->read($statement, 'field_count'));
33            self::assertSame($statement->id, $reader->read($statement, 'id'));
34            self::assertTrue($statement->execute([7, 8]));
35            self::assertTrue($statement->store_result());
36            self::assertSame(2, $reader->read($statement, 'num_rows'));
37            self::assertSame(2, $reader->read($statement, 'affected_rows'));
38            self::assertSame(0, $reader->read($statement, 'errno'));
39            self::assertSame('', $reader->read($statement, 'error'));
40            self::assertSame([], $reader->read($statement, 'error_list'));
41            self::assertSame('00000', $reader->read($statement, 'sqlstate'));
42            self::assertNull($reader->read($statement, 'unsupported'));
43            $statement->close();
44            $connection->close();
45        } finally {
46            $container->stop();
47        }
48    }
49
50    public function testReadPreservesGeneratedIdsAndWriteCounts(): void
51    {
52        $container = Testcontainers::run(MySqlRelease::fromEnvironment());
53        $endpoint = $container->getData(Endpoint::class);
54        try {
55            $connection = new mysqli($endpoint->host, $endpoint->username, $endpoint->password, $endpoint->database, $endpoint->port);
56            $connection->set_charset('utf8mb4');
57            $connection->query('CREATE TABLE generated_rows (id INT AUTO_INCREMENT PRIMARY KEY, value INT)');
58            $statement = $connection->prepare('INSERT INTO generated_rows (value) VALUES (?), (?)');
59            self::assertInstanceOf(mysqli_stmt::class, $statement);
60            self::assertTrue($statement->execute([7, 8]));
61            $reader = new MysqliStatementPropertyReader();
62            self::assertSame(1, $reader->read($statement, 'insert_id'));
63            self::assertSame(2, $reader->read($statement, 'affected_rows'));
64            self::assertSame(0, $reader->read($statement, 'field_count'));
65            self::assertSame(0, $reader->read($statement, 'num_rows'));
66            $statement->close();
67            $connection->close();
68        } finally {
69            $container->stop();
70        }
71    }
72
73    public function testReadPreservesNativeFailureDetails(): void
74    {
75        $container = Testcontainers::run(MySqlRelease::fromEnvironment());
76        $endpoint = $container->getData(Endpoint::class);
77        try {
78            $connection = new mysqli($endpoint->host, $endpoint->username, $endpoint->password, $endpoint->database, $endpoint->port);
79            $connection->set_charset('utf8mb4');
80            $connection->query('CREATE TABLE unique_rows (id INT PRIMARY KEY)');
81            $statement = $connection->prepare('INSERT INTO unique_rows VALUES (?)');
82            self::assertInstanceOf(mysqli_stmt::class, $statement);
83            self::assertTrue($statement->execute([1]));
84            mysqli_report(MYSQLI_REPORT_OFF);
85            try {
86                self::assertFalse($statement->execute([1]));
87                $reader = new MysqliStatementPropertyReader();
88                self::assertSame(1062, $reader->read($statement, 'errno'));
89                self::assertSame('23000', $reader->read($statement, 'sqlstate'));
90                self::assertStringContainsString('Duplicate entry', $statement->error);
91                self::assertSame($statement->error, $reader->read($statement, 'error'));
92                self::assertSame([['errno' => 1062, 'sqlstate' => '23000', 'error' => $statement->error]], $reader->read($statement, 'error_list'));
93            } finally {
94                mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
95                $statement->close();
96                $connection->close();
97            }
98        } finally {
99            $container->stop();
100        }
101    }
102}
103