Skip to content

Commit c9419d9

Browse files
jakubkulhanclaude
andcommitted
Add database flavor filtering to data type tests with separate JSON cases for MySQL and MariaDB
🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 43fd931 commit c9419d9

1 file changed

Lines changed: 69 additions & 64 deletions

File tree

data-access-kit-replication/test/StreamIntegrationTest.php

Lines changed: 69 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -258,88 +258,102 @@ public static function dataTypeProvider(): array
258258
{
259259
return [
260260
// Integer Types
261-
['TINYINT', 127, 127],
262-
['TINYINT UNSIGNED', 255, -1], // MySQL binlog represents max unsigned as -1
263-
['SMALLINT', 32767, 32767],
264-
['SMALLINT UNSIGNED', 65535, -1], // MySQL binlog represents max unsigned as -1
265-
['MEDIUMINT', 8388607, 8388607],
266-
['MEDIUMINT UNSIGNED', 16777215, -1], // MySQL binlog represents max unsigned as -1
267-
['INT', 2147483647, 2147483647],
268-
['INT UNSIGNED', 4294967295, -1], // MySQL binlog represents max unsigned as -1
269-
['BIGINT', '9223372036854775807', '9223372036854775807'],
270-
['BIGINT UNSIGNED', '18446744073709551615', -1], // MySQL binlog represents max unsigned as -1
271-
['BIT(8)', 'b\'11111111\'', 255],
272-
['BIT(1)', 'b\'1\'', 1],
261+
['TINYINT', 127, 127, null],
262+
['TINYINT UNSIGNED', 255, -1, null], // MySQL binlog represents max unsigned as -1
263+
['SMALLINT', 32767, 32767, null],
264+
['SMALLINT UNSIGNED', 65535, -1, null], // MySQL binlog represents max unsigned as -1
265+
['MEDIUMINT', 8388607, 8388607, null],
266+
['MEDIUMINT UNSIGNED', 16777215, -1, null], // MySQL binlog represents max unsigned as -1
267+
['INT', 2147483647, 2147483647, null],
268+
['INT UNSIGNED', 4294967295, -1, null], // MySQL binlog represents max unsigned as -1
269+
['BIGINT', '9223372036854775807', '9223372036854775807', null],
270+
['BIGINT UNSIGNED', '18446744073709551615', -1, null], // MySQL binlog represents max unsigned as -1
271+
['BIT(8)', 'b\'11111111\'', 255, null],
272+
['BIT(1)', 'b\'1\'', 1, null],
273273

274274
// Fixed-Point Types
275-
['DECIMAL(10,2)', '123.45', '123.45'],
276-
['DECIMAL(5,0)', '12345', '12345'],
277-
['NUMERIC(8,3)', '12345.678', '12345.678'],
275+
['DECIMAL(10,2)', '123.45', '123.45', null],
276+
['DECIMAL(5,0)', '12345', '12345', null],
277+
['NUMERIC(8,3)', '12345.678', '12345.678', null],
278278

279279
// Floating-Point Types
280-
['FLOAT', 123.456, 123.456],
281-
['DOUBLE', 123.456789, 123.456789],
280+
['FLOAT', 123.456, 123.456, null],
281+
['DOUBLE', 123.456789, 123.456789, null],
282282

283283
// Character Types
284-
['CHAR(10)', '\'Hello\'', 'Hello'],
285-
['VARCHAR(50)', '\'Variable length\'', 'Variable length'],
286-
['BINARY(5)', 'X\'48656c6c6f\'', 'Hello'], // Use hex notation for binary data
287-
['VARBINARY(10)', 'X\'48656c6c6f\'', 'Hello'], // Use hex notation for binary data
284+
['CHAR(10)', '\'Hello\'', 'Hello', null],
285+
['VARCHAR(50)', '\'Variable length\'', 'Variable length', null],
286+
['BINARY(5)', 'X\'48656c6c6f\'', 'Hello', null], // Use hex notation for binary data
287+
['VARBINARY(10)', 'X\'48656c6c6f\'', 'Hello', null], // Use hex notation for binary data
288288

289289
// Text Types - these are base64 encoded in binlog
290-
['TINYTEXT', '\'Tiny text\'', 'VGlueSB0ZXh0'],
291-
['TEXT', '\'Regular text content\'', 'UmVndWxhciB0ZXh0IGNvbnRlbnQ='],
292-
['MEDIUMTEXT', '\'Medium text content\'', 'TWVkaXVtIHRleHQgY29udGVudA=='],
293-
['LONGTEXT', '\'Long text content\'', 'TG9uZyB0ZXh0IGNvbnRlbnQ='],
290+
['TINYTEXT', '\'Tiny text\'', 'VGlueSB0ZXh0', null],
291+
['TEXT', '\'Regular text content\'', 'UmVndWxhciB0ZXh0IGNvbnRlbnQ=', null],
292+
['MEDIUMTEXT', '\'Medium text content\'', 'TWVkaXVtIHRleHQgY29udGVudA==', null],
293+
['LONGTEXT', '\'Long text content\'', 'TG9uZyB0ZXh0IGNvbnRlbnQ=', null],
294294

295295
// Binary Large Object Types - these are base64 encoded in binlog
296-
['TINYBLOB', 'X\'48656c6c6f\'', 'SGVsbG8='], // "Hello" in base64
297-
['BLOB', 'X\'48656c6c6f20576f726c64\'', 'SGVsbG8gV29ybGQ='], // "Hello World" in base64
298-
['MEDIUMBLOB', 'X\'48656c6c6f204d656469756d\'', 'SGVsbG8gTWVkaXVt'], // "Hello Medium" in base64
299-
['LONGBLOB', 'X\'48656c6c6f204c6f6e67\'', 'SGVsbG8gTG9uZw=='], // "Hello Long" in base64
296+
['TINYBLOB', 'X\'48656c6c6f\'', 'SGVsbG8=', null], // "Hello" in base64
297+
['BLOB', 'X\'48656c6c6f20576f726c64\'', 'SGVsbG8gV29ybGQ=', null], // "Hello World" in base64
298+
['MEDIUMBLOB', 'X\'48656c6c6f204d656469756d\'', 'SGVsbG8gTWVkaXVt', null], // "Hello Medium" in base64
299+
['LONGBLOB', 'X\'48656c6c6f204c6f6e67\'', 'SGVsbG8gTG9uZw==', null], // "Hello Long" in base64
300300

301301
// Special String Types - now return actual string values with fix-enum-set-metadata branch
302-
['ENUM(\'red\',\'green\',\'blue\')', '\'red\'', 'red'], // ENUM returns actual string value
303-
['SET(\'read\',\'write\',\'execute\')', '\'read,write\'', ['read', 'write']], // SET returns array of strings
302+
['ENUM(\'red\',\'green\',\'blue\')', '\'red\'', 'red', null], // ENUM returns actual string value
303+
['SET(\'read\',\'write\',\'execute\')', '\'read,write\'', ['read', 'write'], null], // SET returns array of strings
304304

305305
// Date and Time Data Types
306-
['DATE', '\'2024-01-15\'', '2024-01-15'],
307-
['TIME', '\'14:30:45\'', '14:30:45.000000'], // TIME includes microseconds
308-
['DATETIME', '\'2024-01-15 14:30:45\'', new \DateTimeImmutable('2024-01-15 14:30:45.000000')], // DATETIME as DateTimeImmutable
309-
['TIMESTAMP', '\'2024-01-15 14:30:45\'', new \DateTimeImmutable('2024-01-15 14:30:45')], // TIMESTAMP as DateTimeImmutable
310-
['YEAR', '2024', '2024'],
306+
['DATE', '\'2024-01-15\'', '2024-01-15', null],
307+
['TIME', '\'14:30:45\'', '14:30:45.000000', null], // TIME includes microseconds
308+
['DATETIME', '\'2024-01-15 14:30:45\'', new \DateTimeImmutable('2024-01-15 14:30:45.000000'), null], // DATETIME as DateTimeImmutable
309+
['TIMESTAMP', '\'2024-01-15 14:30:45\'', new \DateTimeImmutable('2024-01-15 14:30:45'), null], // TIMESTAMP as DateTimeImmutable
310+
['YEAR', '2024', '2024', null],
311311

312-
// JSON Data Type - now returns parsed stdClass objects
313-
['JSON', '\'{"key": "value", "number": 42}\'', (object)['key' => 'value', 'number' => 42]],
312+
// JSON Data Type - MySQL returns parsed stdClass objects
313+
['JSON', '\'{"key": "value", "number": 42}\'', (object)['key' => 'value', 'number' => 42], 'mysql'],
314+
// JSON Data Type - MariaDB returns base64 encoded strings
315+
['JSON', '\'{"key": "value", "number": 42}\'', 'eyJrZXkiOiAidmFsdWUiLCAibnVtYmVyIjogNDJ9', 'mariadb'],
314316

315317
// NULL values for various types
316-
['VARCHAR(50)', 'NULL', null],
317-
['INT', 'NULL', null],
318-
['DATE', 'NULL', null],
319-
['JSON', 'NULL', null],
318+
['VARCHAR(50)', 'NULL', null, null],
319+
['INT', 'NULL', null, null],
320+
['DATE', 'NULL', null, null],
321+
['JSON', 'NULL', null, null],
320322

321323
// Zero and empty values
322-
['INT', '0', 0],
323-
['VARCHAR(50)', '\'\'', ''],
324-
['TEXT', '\'\'', ''],
324+
['INT', '0', 0, null],
325+
['VARCHAR(50)', '\'\'', '', null],
326+
['TEXT', '\'\'', '', null],
325327

326328
// Negative numbers
327-
['TINYINT', '-128', -128],
328-
['SMALLINT', '-32768', -32768],
329-
['MEDIUMINT', '-8388608', -8388608],
330-
['INT', '-2147483648', -2147483648],
331-
['BIGINT', '-9223372036854775808', '-9223372036854775808'],
332-
['DECIMAL(10,2)', '-123.45', '-123.45'],
333-
['FLOAT', '-123.456', -123.456],
334-
['DOUBLE', '-123.456789', -123.456789],
329+
['TINYINT', '-128', -128, null],
330+
['SMALLINT', '-32768', -32768, null],
331+
['MEDIUMINT', '-8388608', -8388608, null],
332+
['INT', '-2147483648', -2147483648, null],
333+
['BIGINT', '-9223372036854775808', '-9223372036854775808', null],
334+
['DECIMAL(10,2)', '-123.45', '-123.45', null],
335+
['FLOAT', '-123.456', -123.456, null],
336+
['DOUBLE', '-123.456789', -123.456789, null],
335337
];
336338
}
337339

338340
#[DataProvider('dataTypeProvider')]
339-
public function testDataTypeConversion(string $columnType, $insertValue, $expectedPhpValue): void
341+
public function testDataTypeConversion(string $columnType, $insertValue, $expectedPhpValue, ?string $databaseFlavor): void
340342
{
341343
$this->requireDatabase();
342344

345+
// Skip test if database flavor doesn't match
346+
if ($databaseFlavor !== null) {
347+
$stmt = $this->pdo->query("SELECT VERSION()");
348+
$version = $stmt->fetchColumn();
349+
$isMariaDB = stripos($version, 'mariadb') !== false;
350+
351+
if (($databaseFlavor === 'mariadb' && !$isMariaDB) ||
352+
($databaseFlavor === 'mysql' && $isMariaDB)) {
353+
$this->markTestSkipped("Test only runs on {$databaseFlavor}");
354+
}
355+
}
356+
343357
$stream = null;
344358
$testTableName = 'test_data_types_' . md5($columnType . serialize($insertValue));
345359

@@ -353,11 +367,6 @@ public function testDataTypeConversion(string $columnType, $insertValue, $expect
353367
$this->dbConfig['password']
354368
);
355369

356-
// Detect database type
357-
$stmt = $testPdo->query("SELECT VERSION()");
358-
$version = $stmt->fetchColumn();
359-
$isMariaDB = stripos($version, 'mariadb') !== false;
360-
361370
$createTableSql = "CREATE TABLE IF NOT EXISTS `{$testTableName}` (
362371
id INT AUTO_INCREMENT PRIMARY KEY,
363372
test_column {$columnType}
@@ -383,12 +392,8 @@ public function testDataTypeConversion(string $columnType, $insertValue, $expect
383392
$this->assertEquals($testTableName, $insertEvent->table);
384393
$this->assertIsObject($insertEvent->after);
385394

386-
// Adjust expectations for MariaDB JSON handling
395+
// Use expected value as-is since database flavor filtering handles different expectations
387396
$actualExpectedValue = $expectedPhpValue;
388-
if ($isMariaDB && strpos($columnType, 'JSON') === 0 && is_object($expectedPhpValue) && get_class($expectedPhpValue) === 'stdClass') {
389-
// MariaDB returns JSON as base64 encoded string, not parsed object
390-
$actualExpectedValue = 'eyJrZXkiOiAidmFsdWUiLCAibnVtYmVyIjogNDJ9'; // Base64 encoded
391-
}
392397

393398
if ($actualExpectedValue === null) {
394399
$this->assertNull($insertEvent->after->test_column);

0 commit comments

Comments
 (0)