diff --git a/src/Datasets.php b/src/Datasets.php index 8eff980c..89725107 100644 --- a/src/Datasets.php +++ b/src/Datasets.php @@ -51,36 +51,34 @@ final class Datasets /** * Resolves the current dataset to an array value. * - * @param Traversable|Closure|iterable|string|null $data + * @param array|string> $datasets * * @return array */ - public static function resolve(string $description, $data): array + public static function resolve(string $description, array $datasets): array { /* @phpstan-ignore-next-line */ - if (is_null($data) || empty($data)) { + if (empty($datasets)) { return [$description => []]; } - if (is_string($data)) { - $data = self::get($data); - } + $datasets = self::processDatasets($datasets); - if (is_callable($data)) { - $data = call_user_func($data); - } - - if ($data instanceof Traversable) { - $data = iterator_to_array($data); - } + $datasetCombinations = self::getDataSetsCombinations($datasets); $dataSetDescriptions = []; $dataSetValues = []; - foreach ($data as $key => $values) { - $values = is_array($values) ? $values : [$values]; + foreach ($datasetCombinations as $datasetCombination) { + $partialDescriptions = []; + $values = []; - $dataSetDescriptions[] = $description . self::getDataSetDescription($key, $values); + foreach ($datasetCombination as $dataset_data) { + $partialDescriptions[] = $dataset_data['label']; + $values = array_merge($values, $dataset_data['values']); + } + + $dataSetDescriptions[] = $description . ' with ' . implode(' / ', $partialDescriptions); $dataSetValues[] = $values; } @@ -103,6 +101,65 @@ final class Datasets return $namedData; } + /** + * @param array|string> $datasets + * + * @return array + */ + private static function processDatasets(array $datasets): array + { + $processedDatasets = []; + + foreach ($datasets as $index => $data) { + $processedDataset = []; + + if (is_string($data)) { + $datasets[$index] = self::get($data); + } + + if (is_callable($datasets[$index])) { + $datasets[$index] = call_user_func($datasets[$index]); + } + + if ($datasets[$index] instanceof Traversable) { + $datasets[$index] = iterator_to_array($datasets[$index]); + } + + foreach ($datasets[$index] as $key => $values) { + $values = is_array($values) ? $values : [$values]; + $processedDataset[] = [ + 'label' => self::getDataSetDescription($key, $values), + 'values' => $values, + ]; + } + + $processedDatasets[] = $processedDataset; + } + + return $processedDatasets; + } + + /** + * @param array $combinations + * + * @return array + */ + private static function getDataSetsCombinations(array $combinations): array + { + $result = [[]]; + foreach ($combinations as $index => $values) { + $tmp = []; + foreach ($result as $resultItem) { + foreach ($values as $value) { + $tmp[] = array_merge($resultItem, [$index => $value]); + } + } + $result = $tmp; + } + + return $result; + } + /** * @param int|string $key * @param array $data @@ -112,9 +169,9 @@ final class Datasets $exporter = new Exporter(); if (is_int($key)) { - return \sprintf(' with (%s)', $exporter->shortenedRecursiveExport($data)); + return \sprintf('(%s)', $exporter->shortenedRecursiveExport($data)); } - return \sprintf(' with data set "%s"', $key); + return \sprintf('data set "%s"', $key); } } diff --git a/src/Factories/TestCaseFactory.php b/src/Factories/TestCaseFactory.php index ddba1083..5285fc9e 100644 --- a/src/Factories/TestCaseFactory.php +++ b/src/Factories/TestCaseFactory.php @@ -62,9 +62,9 @@ final class TestCaseFactory /** * Holds the dataset, if any. * - * @var Closure|iterable|string|null + * @var array|string> */ - public $dataset; + public $datasets = []; /** * The FQN of the test case class. @@ -155,7 +155,7 @@ final class TestCaseFactory return $testCase; }; - $datasets = Datasets::resolve($this->description, $this->dataset); + $datasets = Datasets::resolve($this->description, $this->datasets); return array_map($createTest, array_keys($datasets), $datasets); } diff --git a/src/PendingObjects/TestCall.php b/src/PendingObjects/TestCall.php index cd65ae76..39486565 100644 --- a/src/PendingObjects/TestCall.php +++ b/src/PendingObjects/TestCall.php @@ -77,11 +77,13 @@ final class TestCall * Runs the current test multiple times with * each item of the given `iterable`. * - * @param \Closure|iterable|string $data + * @param array<\Closure|iterable|string> $data */ - public function with($data): TestCall + public function with(...$data): TestCall { - $this->testCaseFactory->dataset = $data; + foreach ($data as $dataset) { + $this->testCaseFactory->datasets[] = $dataset; + } return $this; } diff --git a/tests/.snapshots/success.txt b/tests/.snapshots/success.txt index d392dedc..eb3a3532 100644 --- a/tests/.snapshots/success.txt +++ b/tests/.snapshots/success.txt @@ -51,6 +51,45 @@ ✓ it creates unique test case names with ('Name 2', Pest\Plugin Object (), true) ✓ it creates unique test case names with ('Name 1', Pest\Plugin Object (), true) #3 ✓ it creates unique test case names - count + ✓ lazy multiple datasets with (1) / (3) + ✓ lazy multiple datasets with (1) / (4) + ✓ lazy multiple datasets with (2) / (3) + ✓ lazy multiple datasets with (2) / (4) + ✓ lazy multiple datasets did the job right + ✓ eager multiple datasets with (1) / (3) + ✓ eager multiple datasets with (1) / (4) + ✓ eager multiple datasets with (2) / (3) + ✓ eager multiple datasets with (2) / (4) + ✓ eager multiple datasets did the job right + ✓ lazy registered multiple datasets with (1) / (1) + ✓ lazy registered multiple datasets with (1) / (2) + ✓ lazy registered multiple datasets with (2) / (1) + ✓ lazy registered multiple datasets with (2) / (2) + ✓ lazy registered multiple datasets did the job right + ✓ eager registered multiple datasets with (1) / (1) + ✓ eager registered multiple datasets with (1) / (2) + ✓ eager registered multiple datasets with (2) / (1) + ✓ eager registered multiple datasets with (2) / (2) + ✓ eager registered multiple datasets did the job right + ✓ eager wrapped registered multiple datasets with (1) / (1) + ✓ eager wrapped registered multiple datasets with (1) / (2) + ✓ eager wrapped registered multiple datasets with (2) / (1) + ✓ eager wrapped registered multiple datasets with (2) / (2) + ✓ eager wrapped registered multiple datasets did the job right + ✓ named multiple datasets with data set "one" / data set "three" + ✓ named multiple datasets with data set "one" / data set "four" + ✓ named multiple datasets with data set "two" / data set "three" + ✓ named multiple datasets with data set "two" / data set "four" + ✓ named multiple datasets did the job right + ✓ more than two datasets with (1) / (3) / (5) + ✓ more than two datasets with (1) / (3) / (6) + ✓ more than two datasets with (1) / (4) / (5) + ✓ more than two datasets with (1) / (4) / (6) + ✓ more than two datasets with (2) / (3) / (5) + ✓ more than two datasets with (2) / (3) / (6) + ✓ more than two datasets with (2) / (4) / (5) + ✓ more than two datasets with (2) / (4) / (6) + ✓ more than two datasets did the job right PASS Tests\Features\Exceptions ✓ it gives access the the underlying expectException @@ -174,6 +213,9 @@ PASS Tests\Unit\Datasets ✓ it show only the names of named datasets in their description ✓ it show the actual dataset of non-named datasets in their description + ✓ it show only the names of multiple named datasets in their description + ✓ it show the actual dataset of multiple non-named datasets in their description + ✓ it show the correct description for mixed named and not-named datasets PASS Tests\Unit\Plugins\Version ✓ it outputs the version when --version is used @@ -224,5 +266,5 @@ ✓ it is a test ✓ it uses correct parent class - Tests: 7 skipped, 122 passed + Tests: 7 skipped, 164 passed \ No newline at end of file diff --git a/tests/Features/Datasets.php b/tests/Features/Datasets.php index dabda849..b7aeb478 100644 --- a/tests/Features/Datasets.php +++ b/tests/Features/Datasets.php @@ -137,3 +137,89 @@ it('creates unique test case names', function (string $name, Plugin $plugin, boo it('creates unique test case names - count', function () use (&$counter) { expect($counter)->toBe(6); }); + +$datasets_a = [[1], [2]]; +$datasets_b = [[3], [4]]; + +test('lazy multiple datasets', function ($text_a, $text_b) use ($state, $datasets_a, $datasets_b) { + $state->text .= $text_a . $text_b; + expect($datasets_a)->toContain([$text_a]); + expect($datasets_b)->toContain([$text_b]); +})->with($datasets_a, $datasets_b); + +test('lazy multiple datasets did the job right', function () use ($state) { + expect($state->text)->toBe('12121212121213142324'); +}); + +$state->text = ''; + +test('eager multiple datasets', function ($text_a, $text_b) use ($state, $datasets_a, $datasets_b) { + $state->text .= $text_a . $text_b; + expect($datasets_a)->toContain([$text_a]); + expect($datasets_b)->toContain([$text_b]); +})->with(function () use ($datasets_a) { + return $datasets_a; +})->with(function () use ($datasets_b) { + return $datasets_b; +}); + +test('eager multiple datasets did the job right', function () use ($state) { + expect($state->text)->toBe('1212121212121314232413142324'); +}); + +test('lazy registered multiple datasets', function ($text_a, $text_b) use ($state, $datasets) { + $state->text .= $text_a . $text_b; + expect($datasets)->toContain([$text_a]); + expect($datasets)->toContain([$text_b]); +})->with('numbers.array')->with('numbers.array'); + +test('lazy registered multiple datasets did the job right', function () use ($state) { + expect($state->text)->toBe('121212121212131423241314232411122122'); +}); + +test('eager registered multiple datasets', function ($text_a, $text_b) use ($state, $datasets) { + $state->text .= $text_a . $text_b; + expect($datasets)->toContain([$text_a]); + expect($datasets)->toContain([$text_b]); +})->with('numbers.array')->with('numbers.closure'); + +test('eager registered multiple datasets did the job right', function () use ($state) { + expect($state->text)->toBe('12121212121213142324131423241112212211122122'); +}); + +test('eager wrapped registered multiple datasets', function ($text_a, $text_b) use ($state, $datasets) { + $state->text .= $text_a . $text_b; + expect($datasets)->toContain([$text_a]); + expect($datasets)->toContain([$text_b]); +})->with('numbers.closure.wrapped')->with('numbers.closure'); + +test('eager wrapped registered multiple datasets did the job right', function () use ($state) { + expect($state->text)->toBe('1212121212121314232413142324111221221112212211122122'); +}); + +test('named multiple datasets', function ($text_a, $text_b) use ($state, $datasets_a, $datasets_b) { + $state->text .= $text_a . $text_b; + expect($datasets_a)->toContain([$text_a]); + expect($datasets_b)->toContain([$text_b]); +})->with([ + 'one' => [1], + 'two' => [2], +])->with([ + 'three' => [3], + 'four' => [4], +]); + +test('named multiple datasets did the job right', function () use ($state) { + expect($state->text)->toBe('121212121212131423241314232411122122111221221112212213142324'); +}); + +test('more than two datasets', function ($text_a, $text_b, $text_c) use ($state, $datasets_a, $datasets_b) { + $state->text .= $text_a . $text_b . $text_c; + expect($datasets_a)->toContain([$text_a]); + expect($datasets_b)->toContain([$text_b]); + expect([5, 6])->toContain($text_c); +})->with($datasets_a, $datasets_b)->with([5, 6]); + +test('more than two datasets did the job right', function () use ($state) { + expect($state->text)->toBe('121212121212131423241314232411122122111221221112212213142324135136145146235236245246'); +}); diff --git a/tests/Unit/Datasets.php b/tests/Unit/Datasets.php index 39070038..08f82352 100644 --- a/tests/Unit/Datasets.php +++ b/tests/Unit/Datasets.php @@ -4,8 +4,10 @@ use Pest\Datasets; it('show only the names of named datasets in their description', function () { $descriptions = array_keys(Datasets::resolve('test description', [ - 'one' => [1], - 'two' => [[2]], + [ + 'one' => [1], + 'two' => [[2]], + ], ])); expect($descriptions[0])->toBe('test description with data set "one"'); @@ -14,10 +16,66 @@ it('show only the names of named datasets in their description', function () { it('show the actual dataset of non-named datasets in their description', function () { $descriptions = array_keys(Datasets::resolve('test description', [ - [1], - [[2]], + [ + [1], + [[2]], + ], ])); expect($descriptions[0])->toBe('test description with (1)'); expect($descriptions[1])->toBe('test description with (array(2))'); }); + +it('show only the names of multiple named datasets in their description', function () { + $descriptions = array_keys(Datasets::resolve('test description', [ + [ + 'one' => [1], + 'two' => [[2]], + ], + [ + 'three' => [3], + 'four' => [[4]], + ], + ])); + + expect($descriptions[0])->toBe('test description with data set "one" / data set "three"'); + expect($descriptions[1])->toBe('test description with data set "one" / data set "four"'); + expect($descriptions[2])->toBe('test description with data set "two" / data set "three"'); + expect($descriptions[3])->toBe('test description with data set "two" / data set "four"'); +}); + +it('show the actual dataset of multiple non-named datasets in their description', function () { + $descriptions = array_keys(Datasets::resolve('test description', [ + [ + [1], + [[2]], + ], + [ + [3], + [[4]], + ], + ])); + + expect($descriptions[0])->toBe('test description with (1) / (3)'); + expect($descriptions[1])->toBe('test description with (1) / (array(4))'); + expect($descriptions[2])->toBe('test description with (array(2)) / (3)'); + expect($descriptions[3])->toBe('test description with (array(2)) / (array(4))'); +}); + +it('show the correct description for mixed named and not-named datasets', function () { + $descriptions = array_keys(Datasets::resolve('test description', [ + [ + 'one' => [1], + [[2]], + ], + [ + [3], + 'four' => [[4]], + ], + ])); + + expect($descriptions[0])->toBe('test description with data set "one" / (3)'); + expect($descriptions[1])->toBe('test description with data set "one" / data set "four"'); + expect($descriptions[2])->toBe('test description with (array(2)) / (3)'); + expect($descriptions[3])->toBe('test description with (array(2)) / data set "four"'); +});