From d977207933e5cf2a6b2f565f061b9ce76d3eb5d8 Mon Sep 17 00:00:00 2001 From: tristan Date: Tue, 21 Apr 2026 16:49:28 +0200 Subject: [PATCH] test : pin des helpers scalaires de BovinNodeMappingTrait --- .../Mapper/BovinNodeMappingTraitTest.php | 190 ++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 tests/Unit/Bovin/Mapper/BovinNodeMappingTraitTest.php diff --git a/tests/Unit/Bovin/Mapper/BovinNodeMappingTraitTest.php b/tests/Unit/Bovin/Mapper/BovinNodeMappingTraitTest.php new file mode 100644 index 0000000..842c668 --- /dev/null +++ b/tests/Unit/Bovin/Mapper/BovinNodeMappingTraitTest.php @@ -0,0 +1,190 @@ +normalizeToList(null)); + } + + public function testNormalizeToListWithScalarWrapsIntoList(): void + { + self::assertSame(['foo'], self::adapter()->normalizeToList('foo')); + self::assertSame([42], self::adapter()->normalizeToList(42)); + } + + public function testNormalizeToListWithObjectWrapsIntoList(): void + { + $obj = new stdClass(); + $result = self::adapter()->normalizeToList($obj); + + self::assertCount(1, $result); + self::assertSame($obj, $result[0]); + } + + public function testNormalizeToListWithListReturnsListUnchanged(): void + { + $input = ['a', 'b', 'c']; + self::assertSame($input, self::adapter()->normalizeToList($input)); + } + + public function testNormalizeToListWithAssociativeArrayDiscardsKeys(): void + { + $input = ['x' => 'a', 'y' => 'b']; + $result = self::adapter()->normalizeToList($input); + + self::assertSame(['a', 'b'], $result); + } + + #[DataProvider('toNullableStringProvider')] + public function testToNullableString(mixed $input, ?string $expected): void + { + self::assertSame($expected, self::adapter()->toNullableString($input)); + } + + // ---------- toNullableString ---------- + + /** @return iterable */ + public static function toNullableStringProvider(): iterable + { + yield 'null' => [null, null]; + + yield 'empty string' => ['', null]; + + yield 'whitespace only' => [' ', null]; + + yield 'plain' => ['abc', 'abc']; + + yield 'trimmed' => [' abc ', 'abc']; + + yield 'int coerced to string' => [42, '42']; + + yield 'zero preserved' => ['0', '0']; + } + + #[DataProvider('toNullableIntProvider')] + public function testToNullableInt(mixed $input, ?int $expected): void + { + self::assertSame($expected, self::adapter()->toNullableInt($input)); + } + + // ---------- toNullableInt ---------- + + /** @return iterable */ + public static function toNullableIntProvider(): iterable + { + yield 'null' => [null, null]; + + yield 'int passthrough' => [42, 42]; + + yield 'zero int' => [0, 0]; + + yield 'numeric string' => ['42', 42]; + + yield 'negative string' => ['-7', -7]; + + yield 'float-like string' => ['3.14', 3]; + + yield 'non-numeric' => ['abc', null]; + + yield 'empty string' => ['', null]; + } + + #[DataProvider('toNullableBoolProvider')] + public function testToNullableBool(mixed $input, ?bool $expected): void + { + self::assertSame($expected, self::adapter()->toNullableBool($input)); + } + + // ---------- toNullableBool ---------- + + /** @return iterable */ + public static function toNullableBoolProvider(): iterable + { + yield 'null' => [null, null]; + + yield 'true' => [true, true]; + + yield 'false' => [false, false]; + + yield 'string 1' => ['1', true]; + + yield 'string 0' => ['0', false]; + + yield 'empty string' => ['', false]; + + yield 'int 1' => [1, true]; + + yield 'int 0' => [0, false]; + } + + // ---------- toNullableDate ---------- + + public function testToNullableDateFromIsoString(): void + { + $result = self::adapter()->toNullableDate('2026-04-21'); + self::assertEquals(new DateTimeImmutable('2026-04-21'), $result); + } + + public function testToNullableDateFromDateTimeString(): void + { + $result = self::adapter()->toNullableDate('2026-04-21T10:30:00+02:00'); + self::assertEquals(new DateTimeImmutable('2026-04-21T10:30:00+02:00'), $result); + } + + #[DataProvider('toNullableDateFallbackProvider')] + public function testToNullableDateReturnsNullOnInvalidInput(mixed $input): void + { + self::assertNull(self::adapter()->toNullableDate($input)); + } + + /** @return iterable */ + public static function toNullableDateFallbackProvider(): iterable + { + yield 'null' => [null]; + + yield 'empty string' => ['']; + + yield 'whitespace' => [' ']; + + yield 'non-string int' => [42]; + + yield 'non-string array' => [[]]; + + yield 'invalid date string' => ['not-a-date']; + } + + /** + * Adapter anonyme : re-expose chaque helper protected en public pour le test, + * sans jamais instancier un vrai mapper (ceux-ci ont des dépendances DI). + */ + private static function adapter(): object + { + return new class { + use BovinNodeMappingTrait { + normalizeToList as public; + toNullableString as public; + toNullableInt as public; + toNullableBool as public; + toNullableDate as public; + } + }; + } +}