packages/sql-fixture/tests/Unit/Hydrator/Reflection/ValueConversionTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Hydrator\Reflection;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\DataProvider;
9use PHPUnit\Framework\Attributes\UsesClass;
10use PHPUnit\Framework\TestCase;
11use SqlFixture\Hydrator\Reflection\ConversionTarget;
12use SqlFixture\Hydrator\Reflection\ValueConversion;
13
14#[CoversClass(ValueConversion::class)]
15#[UsesClass(ConversionTarget::class)]
16final class ValueConversionTest extends TestCase
17{
18 /**
19 * @param list<int|string>|int|float|bool|string|null $value
20 * @param list<int|string>|int|float|bool|string|null $expected
21 */
22 #[DataProvider('providerConversions')]
23 public function testCastValuePreservesOrConvertsTheDatabaseValue(
24 array|int|float|bool|string|null $value,
25 ?ConversionTarget $type,
26 array|int|float|bool|string|null $expected,
27 ): void {
28 self::assertSame($expected, (new ValueConversion())->castValue($value, $type));
29 }
30
31 /**
32 * @return iterable<string, array{list<int|string>|int|float|bool|string|null, ?ConversionTarget, list<int|string>|int|float|bool|string|null}>
33 */
34 public static function providerConversions(): iterable
35 {
36 yield 'numeric string to integer' => ['42', ConversionTarget::Integer, 42];
37 yield 'numeric float to integer' => [42.9, ConversionTarget::Integer, 42];
38 yield 'nonnumeric integer input is preserved' => ['pending', ConversionTarget::Integer, 'pending'];
39 yield 'numeric string to float' => ['12.5', ConversionTarget::Float, 12.5];
40 yield 'integer to float' => [12, ConversionTarget::Float, 12.0];
41 yield 'nonnumeric float input is preserved' => ['pending', ConversionTarget::Float, 'pending'];
42 yield 'integer to string' => [42, ConversionTarget::String, '42'];
43 yield 'boolean to string' => [false, ConversionTarget::String, ''];
44 yield 'nonscalar string input is preserved' => [[1, 2], ConversionTarget::String, [1, 2]];
45 yield 'zero to boolean' => [0, ConversionTarget::Boolean, false];
46 yield 'one to boolean' => [1, ConversionTarget::Boolean, true];
47 yield 'null stays null' => [null, ConversionTarget::Boolean, null];
48 yield 'JSON array' => ['[1,2]', ConversionTarget::Array, [1, 2]];
49 yield 'JSON null becomes an element' => ['null', ConversionTarget::Array, ['null']];
50 yield 'plain text becomes an element' => ['plain', ConversionTarget::Array, ['plain']];
51 yield 'scalar becomes an array' => [42, ConversionTarget::Array, [42]];
52 yield 'existing array is preserved' => [[1, 2], ConversionTarget::Array, [1, 2]];
53 yield 'unconverted type preserves numeric strings' => ['42', null, '42'];
54 }
55}
56