Valinor/tests/Unit/Mapper/Source/Modifier/PathMappingTest.php
Nathan Boiron b7a7d22993
feat: introduce a path-mapping source modifier
This modifier can be used to change paths in the source data using a dot
notation.

The mapping is done using an associative array of path mappings. This
array must have the source path as key and the target path as value.

The source path uses the dot notation (eg `A.B.C`) and can contain one
`*` for array paths (eg `A.B.*.C`).

```php
final class Country
{
    /** @var City[] */
    public readonly array $cities;
}

final class City
{
    public readonly string $name;
}

$source = new \CuyZ\Valinor\Mapper\Source\Modifier\PathMapping([
    'towns' => [
        ['label' => 'Ankh Morpork'],
        ['label' => 'Minas Tirith'],
    ],
], [
    'towns' => 'cities',
    'towns.*.label' => 'name',
]);

// After modification this is what the source will look like:
[
    'cities' => [
        ['name' => 'Ankh Morpork'],
        ['name' => 'Minas Tirith'],
    ],
];

(new \CuyZ\Valinor\MapperBuilder())
    ->mapper()
    ->map(Country::class, $source);
```
2022-02-26 11:33:50 +01:00

205 lines
4.7 KiB
PHP

<?php
declare(strict_types=1);
namespace CuyZ\Valinor\Tests\Unit\Mapper\Source\Modifier;
use CuyZ\Valinor\Mapper\Source\Modifier\PathMapping;
use PHPUnit\Framework\TestCase;
final class PathMappingTest extends TestCase
{
public function test_root_path_is_mapped(): void
{
$source = new PathMapping(
['A' => 'bar'],
['A' => 'new_A']
);
self::assertSame(['new_A' => 'bar'], iterator_to_array($source));
}
public function test_sub_path_is_mapped(): void
{
$source = new PathMapping(
[
'A' => [
'B' => 'foo',
],
],
['A.B' => 'new_B']
);
self::assertSame([
'A' => [
'new_B' => 'foo',
],
], iterator_to_array($source));
}
public function test_root_iterable_path_is_mapped(): void
{
$source = new PathMapping(
[
['A' => 'bar'],
['A' => 'buz'],
],
['*.A' => 'new_A']
);
self::assertSame([
['new_A' => 'bar'],
['new_A' => 'buz'],
], iterator_to_array($source));
}
public function test_sub_iterable_numeric_path_is_mapped(): void
{
$source = new PathMapping(
[
'A' => [
['C' => 'bar'],
['C' => 'buz'],
],
],
['A.*.C' => 'new_C']
);
self::assertSame([
'A' => [
['new_C' => 'bar'],
['new_C' => 'buz'],
],
], iterator_to_array($source));
}
public function test_sub_iterable_string_path_is_mapped(): void
{
$source = new PathMapping(
[
'A' => [
'B1' => ['C' => 'bar'],
'B2' => ['C' => 'buz'],
],
],
['A.*.C' => 'new_C'],
);
self::assertSame([
'A' => [
'B1' => ['new_C' => 'bar'],
'B2' => ['new_C' => 'buz'],
],
], iterator_to_array($source));
}
public function test_path_with_sub_paths_are_mapped(): void
{
$source = new PathMapping(
[
'A' => [
['B' => 'bar'],
['B' => 'buz'],
],
],
[
'A' => 'new_A',
'A.*.B' => 'new_B',
]
);
self::assertSame([
'new_A' => [
['new_B' => 'bar'],
['new_B' => 'buz'],
],
], iterator_to_array($source));
}
public function test_conflicting_paths_are_mapped(): void
{
$source = new PathMapping(
[
'A1' => [
'B' => 'foo',
],
'A2' => [
'B' => 'bar',
],
],
[
'A1.B' => 'new_B1',
]
);
self::assertSame([
'A1' => [
'new_B1' => 'foo',
],
'A2' => [
'B' => 'bar',
],
], iterator_to_array($source));
}
public function test_sub_iterable_numeric_path_with_sub_key_is_mapped(): void
{
$source = new PathMapping(
[
'A' => [
[
'B' => ['C' => 'bar'],
],
[
'B' => ['C' => 'buz'],
],
],
],
[
'A.*.B.C' => 'new_C',
]
);
self::assertSame([
'A' => [
[
'B' => ['new_C' => 'bar'],
],
[
'B' => ['new_C' => 'buz'],
],
],
], iterator_to_array($source));
}
public function test_sub_iterable_string_path_with_sub_key_is_mapped(): void
{
$source = new PathMapping(
[
'A' => [
'B1' => [
'C' => ['D' => 'bar'],
],
'B2' => [
'C' => ['D' => 'buz'],
],
],
],
[
'A.*.C.D' => 'new_D',
]
);
self::assertSame([
'A' => [
'B1' => [
'C' => ['new_D' => 'bar'],
],
'B2' => [
'C' => ['new_D' => 'buz'],
],
],
], iterator_to_array($source));
}
}