Skip to content

Commit

Permalink
Add DataProvider.map()
Browse files Browse the repository at this point in the history
  • Loading branch information
danon committed Aug 14, 2023
1 parent be14000 commit 6de1a31
Show file tree
Hide file tree
Showing 6 changed files with 235 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/DataProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use TRegx\PhpUnit\DataProviders\Internal\Provider\DropProvider;
use TRegx\PhpUnit\DataProviders\Internal\Provider\JoinProvider;
use TRegx\PhpUnit\DataProviders\Internal\Provider\ListProvider;
use TRegx\PhpUnit\DataProviders\Internal\Provider\MapProvider;
use TRegx\PhpUnit\DataProviders\Internal\Provider\PairsProvider;
use TRegx\PhpUnit\DataProviders\Internal\Provider\SliceProvider;
use TRegx\PhpUnit\DataProviders\Internal\Provider\TuplesProvider;
Expand Down Expand Up @@ -61,6 +62,11 @@ public static function distinctPairs($value1, $value2, ...$values): DataProvider
return new DistinctPairsProvider(\array_merge([$value1, $value2], $values));
}

public function map(callable $mapper): DataProvider
{
return new MapProvider($this, $mapper);
}

public function slice(int $start, int $count = null): DataProvider
{
return new SliceProvider($this, $start, $count);
Expand Down
29 changes: 29 additions & 0 deletions src/Internal/Provider/MapProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php
namespace TRegx\PhpUnit\DataProviders\Internal\Provider;

use TRegx\PhpUnit\DataProviders\DataProvider;
use TRegx\PhpUnit\DataProviders\Internal\Frame\DataRow;

class MapProvider extends DataProvider
{
/** @var DataProvider */
private $provider;
/** @var Mapper */
private $mapper;

public function __construct(DataProvider $provider, callable $mapper)
{
$this->provider = $provider;
$this->mapper = new Mapper($mapper);
}

protected function dataset(): array
{
return \array_map([$this, 'mapped'], $this->provider->dataset());
}

private function mapped(DataRow $row): DataRow
{
return $row->set($this->mapper->apply($row->values));
}
}
25 changes: 25 additions & 0 deletions src/Internal/Provider/Mapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php
namespace TRegx\PhpUnit\DataProviders\Internal\Provider;

use TRegx\PhpUnit\DataProviders\Internal\Type;
use UnexpectedValueException;

class Mapper
{
/** @var callable */
private $mapper;

public function __construct(callable $mapper)
{
$this->mapper = $mapper;
}

public function apply(array $arguments): array
{
$mapped = ($this->mapper)(...$arguments);
if (\is_array($mapped)) {
return \array_values($mapped);
}
throw new UnexpectedValueException('Failed to map data row as array, given: ' . new Type($mapped));
}
}
19 changes: 19 additions & 0 deletions test/Fixture/Functions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php
namespace Test\Fixture;

class Functions
{
public static function constant($value): callable
{
return function () use ($value) {
return $value;
};
}

public static function toArray(): callable
{
return function ($argument): array {
return [$argument];
};
}
}
103 changes: 103 additions & 0 deletions test/Unit/entry/MapTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?php
namespace Test\Unit\entry;

use PHPUnit\Framework\TestCase;
use Test\Fixture\Assertion\AssertsIteration;
use Test\Fixture\Executes;
use Test\Fixture\Functions;
use Test\Fixture\TestCase\TestCaseExactMessage;
use TRegx\PhpUnit\DataProviders\DataProvider;

class MapTest extends TestCase
{
use AssertsIteration, TestCaseExactMessage, Executes;

/**
* @test
*/
public function shouldMap()
{
// given
$provider = DataProvider::tuples(
['Joffrey', 'Baratheon'],
['Cersei', 'Lannister'],
['Ilyn', 'Payne'],
['Sandor', 'Clegane']);
// when
$mapped = $provider->map(function (string $name, string $lastName): array {
return [
\strToLower($name),
\strToUpper($lastName)
];
});
// then
$this->assertIteratesValues($mapped, [
['joffrey', 'BARATHEON'],
['cersei', 'LANNISTER'],
['ilyn', 'PAYNE'],
['sandor', 'CLEGANE'],
]);
}

/**
* @test
* @dataProvider invalidValues
*/
public function shouldThrow($value, string $name)
{
// given
$mapped = DataProvider::tuples(['Valar', 'Morghulis'])
->map(Functions::constant($value));
// then
$this->expectException(\UnexpectedValueException::class);
$this->expectExceptionMessage("Failed to map data row as array, given: $name");
// when
$this->execute($mapped);
}

public function invalidValues(): DataProvider
{
return DataProvider::tuples(
['invalid', "(string) 'invalid'"],
[4, '(int) [4]'],
[3.14, '(float) [3.14]'],
[true, '(bool) true'],
[new \stdClass(), '(object) \stdClass']
);
}

/**
* @test
*/
public function shouldAcceptPhpCallable()
{
// given
$tuples = DataProvider::tuples(
['Joffrey'],
['Cersei'],
['Ilyn Payne']);
// when
$mapped = $tuples->map('str_split');
// then
$this->assertIteratesValues($mapped, [
['J', 'o', 'f', 'f', 'r', 'e', 'y'],
['C', 'e', 'r', 's', 'e', 'i'],
['I', 'l', 'y', 'n', ' ', 'P', 'a', 'y', 'n', 'e'],
]);
}

/**
* @test
*/
public function shouldIgnoreKeysInReturnArray()
{
// given
$provider = DataProvider::list('argument');
// when
$mapped = $provider->map(Functions::constant(['key' => 'value']));
// then
$this->assertIteratesValues($mapped, [
['value'],
]);
}
}
53 changes: 53 additions & 0 deletions test/Unit/names/MapTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php
namespace Test\Unit\names;

use PHPUnit\Framework\TestCase;
use Test\Fixture\Assertion\AssertsIteration;
use Test\Fixture\Functions;
use TRegx\PhpUnit\DataProviders\DataProvider;

class MapTest extends TestCase
{
use AssertsIteration;

/**
* @test
*/
public function shouldName()
{
// given
$list = DataProvider::tuples(
['Joffrey', 'Baratheon'],
['Cersei', 'Lannister'],
['Ilyn', 'Payne'],
['Sandor', 'Clegane']);
// when
$mapped = $list->map(Functions::constant([]))->map(Functions::constant([]));
// then
$this->assertIteratesNames($mapped, [
"'Joffrey', 'Baratheon'",
"'Cersei', 'Lannister'",
"'Ilyn', 'Payne'",
"'Sandor', 'Clegane'",
]);
}

/**
* @test
*/
public function shouldNameAssociative()
{
// given
$provider = DataProvider::zip(
DataProvider::of([
'4' => ['Joffrey', 'Baratheon'],
'5' => ['Cersei', 'Lannister']]),
DataProvider::of([
['Ilyn', 'Payne'],
['Sandor', 'Clegane']]));
// when
$mapped = $provider->map(Functions::toArray());
// then
$this->assertIteratesNames($mapped, ['[4], #0', '[5], #1']);
}
}

0 comments on commit 6de1a31

Please sign in to comment.