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\MySql80Container;
8use Container\MySql84Container;
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(getenv('MYSQL_VERSION') === '8.4.7' ? MySql84Container::class : MySql80Container::class);
24        try {
25            $connection = new mysqli(str_replace('localhost', '127.0.0.1', $container->getHost()), 'root', 'root', 'test', $container->getMappedPort(3306));
26            $connection->set_charset('utf8mb4');
27            $statement = $connection->prepare('SELECT ? AS value UNION ALL SELECT ?');
28            self::assertInstanceOf(mysqli_stmt::class, $statement);
29            $reader = new MysqliStatementPropertyReader();
30            self::assertSame(2, $reader->read($statement, 'param_count'));
31            self::assertSame(1, $reader->read($statement, 'field_count'));
32            self::assertSame($statement->id, $reader->read($statement, 'id'));
33            self::assertTrue($statement->execute([7, 8]));
34            self::assertTrue($statement->store_result());
35            self::assertSame(2, $reader->read($statement, 'num_rows'));
36            self::assertSame(2, $reader->read($statement, 'affected_rows'));
37            self::assertSame(0, $reader->read($statement, 'errno'));
38            self::assertSame('', $reader->read($statement, 'error'));
39            self::assertSame([], $reader->read($statement, 'error_list'));
40            self::assertSame('00000', $reader->read($statement, 'sqlstate'));
41            self::assertNull($reader->read($statement, 'unsupported'));
42            $statement->close();
43            $connection->close();
44        } finally {
45            $container->stop();
46        }
47    }
48
49    public function testReadPreservesGeneratedIdsAndWriteCounts(): void
50    {
51        $container = Testcontainers::run(getenv('MYSQL_VERSION') === '8.4.7' ? MySql84Container::class : MySql80Container::class);
52        try {
53            $connection = new mysqli(str_replace('localhost', '127.0.0.1', $container->getHost()), 'root', 'root', 'test', $container->getMappedPort(3306));
54            $connection->set_charset('utf8mb4');
55            $connection->query('CREATE TABLE generated_rows (id INT AUTO_INCREMENT PRIMARY KEY, value INT)');
56            $statement = $connection->prepare('INSERT INTO generated_rows (value) VALUES (?), (?)');
57            self::assertInstanceOf(mysqli_stmt::class, $statement);
58            self::assertTrue($statement->execute([7, 8]));
59            $reader = new MysqliStatementPropertyReader();
60            self::assertSame(1, $reader->read($statement, 'insert_id'));
61            self::assertSame(2, $reader->read($statement, 'affected_rows'));
62            self::assertSame(0, $reader->read($statement, 'field_count'));
63            self::assertSame(0, $reader->read($statement, 'num_rows'));
64            $statement->close();
65            $connection->close();
66        } finally {
67            $container->stop();
68        }
69    }
70
71    public function testReadPreservesNativeFailureDetails(): void
72    {
73        $container = Testcontainers::run(getenv('MYSQL_VERSION') === '8.4.7' ? MySql84Container::class : MySql80Container::class);
74        try {
75            $connection = new mysqli(str_replace('localhost', '127.0.0.1', $container->getHost()), 'root', 'root', 'test', $container->getMappedPort(3306));
76            $connection->set_charset('utf8mb4');
77            $connection->query('CREATE TABLE unique_rows (id INT PRIMARY KEY)');
78            $statement = $connection->prepare('INSERT INTO unique_rows VALUES (?)');
79            self::assertInstanceOf(mysqli_stmt::class, $statement);
80            self::assertTrue($statement->execute([1]));
81            mysqli_report(MYSQLI_REPORT_OFF);
82            try {
83                self::assertFalse($statement->execute([1]));
84                $reader = new MysqliStatementPropertyReader();
85                self::assertSame(1062, $reader->read($statement, 'errno'));
86                self::assertSame('23000', $reader->read($statement, 'sqlstate'));
87                self::assertStringContainsString('Duplicate entry', $statement->error);
88                self::assertSame($statement->error, $reader->read($statement, 'error'));
89                self::assertSame([['errno' => 1062, 'sqlstate' => '23000', 'error' => $statement->error]], $reader->read($statement, 'error_list'));
90            } finally {
91                mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
92                $statement->close();
93                $connection->close();
94            }
95        } finally {
96            $container->stop();
97        }
98    }
99}
100