From 2bffd6a51e616efe443bf1786b19ea2deb7b1ad2 Mon Sep 17 00:00:00 2001 From: Andrea Marco Sartori Date: Tue, 17 Jan 2023 21:02:47 +1000 Subject: [PATCH] feat: compact dataset descriptions --- src/Exporters/Exporter.php | 76 +++++++++++++++++++++++++ src/Repositories/DatasetsRepository.php | 2 +- tests/.snapshots/success.txt | 70 ++++++++++++----------- tests/Unit/DatasetsTests.php | 32 +++++++++-- 4 files changed, 139 insertions(+), 41 deletions(-) create mode 100644 src/Exporters/Exporter.php diff --git a/src/Exporters/Exporter.php b/src/Exporters/Exporter.php new file mode 100644 index 00000000..25c685b9 --- /dev/null +++ b/src/Exporters/Exporter.php @@ -0,0 +1,76 @@ +exporter = new BaseExporter(); + } + + /** + * Exports a value into a single-line string recursively. + * + * @param array $data + */ + public function shortenedRecursiveExport(array &$data, Context $context = null): string + { + $result = []; + $array = $data; + $itemsCount = 0; + $exporter = new self(); + $context ??= new Context(); + + $context->add($data); + + foreach ($array as $key => $value) { + if (++$itemsCount > self::MAX_ARRAY_ITEMS) { + $result[] = '…'; + + break; + } + + if (! is_array($value)) { + $result[] = $exporter->shortenedExport($value); + + continue; + } + + $result[] = $context->contains($data[$key]) !== false + ? '*RECURSION*' + : sprintf('[%s]', $this->shortenedRecursiveExport($data[$key], $context)); + } + + return implode(', ', $result); + } + + /** + * Exports a value into a single-line string. + */ + public function shortenedExport(mixed $value): string + { + return (string) preg_replace(['#\.{3}#', '#\\\n\s*#'], ['…'], $this->exporter->shortenedExport($value)); + } +} diff --git a/src/Repositories/DatasetsRepository.php b/src/Repositories/DatasetsRepository.php index 3b00b7b4..df7c71da 100644 --- a/src/Repositories/DatasetsRepository.php +++ b/src/Repositories/DatasetsRepository.php @@ -9,7 +9,7 @@ use Generator; use Pest\Exceptions\DatasetAlreadyExists; use Pest\Exceptions\DatasetDoesNotExist; use Pest\Exceptions\ShouldNotHappen; -use SebastianBergmann\Exporter\Exporter; +use Pest\Exporters\Exporter; use function sprintf; use Traversable; diff --git a/tests/.snapshots/success.txt b/tests/.snapshots/success.txt index e80dff6b..5fa5e48c 100644 --- a/tests/.snapshots/success.txt +++ b/tests/.snapshots/success.txt @@ -36,7 +36,7 @@ ✓ it sets arrays ✓ it gets bound to test case object with ('a') ✓ it gets bound to test case object with ('b') - ✓ it truncates the description with ('FoooFoooFoooFoooFoooFoooFoooF...ooFooo') + ✓ it truncates the description with ('FoooFoooFoooFoooFoooFoooFoooF…ooFooo') ✓ lazy datasets with (1) ✓ lazy datasets with (2) ✓ lazy datasets did the job right @@ -55,7 +55,7 @@ ✓ named datasets with data set "one" ✓ named datasets with data set "two" ✓ named datasets did the job right - ✓ lazy named datasets with (Bar Object (...)) + ✓ lazy named datasets with (Bar Object (…)) ✓ it creates unique test case names with ('Name 1', Pest\Plugin Object (), true) #1 ✓ it creates unique test case names with ('Name 1', Pest\Plugin Object (), true) #2 ✓ it creates unique test case names with ('Name 1', Pest\Plugin Object (), false) @@ -109,20 +109,20 @@ ✓ eager registered wrapped datasets with Generator functions did the job right ✓ eager registered wrapped datasets with Generator functions display description with data set "taylor" ✓ eager registered wrapped datasets with Generator functions display description with data set "james" - ✓ it can resolve a dataset after the test case is available with (Closure Object (...)) #1 - ✓ it can resolve a dataset after the test case is available with (Closure Object (...)) #2 - ✓ it can resolve a dataset after the test case is available with shared yield sets with (Closure Object (...)) #1 - ✓ it can resolve a dataset after the test case is available with shared yield sets with (Closure Object (...)) #2 - ✓ it can resolve a dataset after the test case is available with shared array sets with (Closure Object (...)) #1 - ✓ it can resolve a dataset after the test case is available with shared array sets with (Closure Object (...)) #2 - ✓ it resolves a potential bound dataset logically with ('foo', Closure Object (...)) - ✓ it resolves a potential bound dataset logically even when the closure comes first with (Closure Object (...), 'bar') - ✓ it will not resolve a closure if it is type hinted as a closure with (Closure Object (...)) #1 - ✓ it will not resolve a closure if it is type hinted as a closure with (Closure Object (...)) #2 - ✓ it will not resolve a closure if it is type hinted as a callable with (Closure Object (...)) #1 - ✓ it will not resolve a closure if it is type hinted as a callable with (Closure Object (...)) #2 - ✓ it can correctly resolve a bound dataset that returns an array with (Closure Object (...)) - ✓ it can correctly resolve a bound dataset that returns an array but wants to be spread with (Closure Object (...)) + ✓ it can resolve a dataset after the test case is available with (Closure Object (…)) #1 + ✓ it can resolve a dataset after the test case is available with (Closure Object (…)) #2 + ✓ it can resolve a dataset after the test case is available with shared yield sets with (Closure Object (…)) #1 + ✓ it can resolve a dataset after the test case is available with shared yield sets with (Closure Object (…)) #2 + ✓ it can resolve a dataset after the test case is available with shared array sets with (Closure Object (…)) #1 + ✓ it can resolve a dataset after the test case is available with shared array sets with (Closure Object (…)) #2 + ✓ it resolves a potential bound dataset logically with ('foo', Closure Object (…)) + ✓ it resolves a potential bound dataset logically even when the closure comes first with (Closure Object (…), 'bar') + ✓ it will not resolve a closure if it is type hinted as a closure with (Closure Object (…)) #1 + ✓ it will not resolve a closure if it is type hinted as a closure with (Closure Object (…)) #2 + ✓ it will not resolve a closure if it is type hinted as a callable with (Closure Object (…)) #1 + ✓ it will not resolve a closure if it is type hinted as a callable with (Closure Object (…)) #2 + ✓ it can correctly resolve a bound dataset that returns an array with (Closure Object (…)) + ✓ it can correctly resolve a bound dataset that returns an array but wants to be spread with (Closure Object (…)) ↓ forbids to define tests in Datasets dirs and Datasets.php files PASS Tests\Features\Depends @@ -549,7 +549,7 @@ ✓ it passes with ('Fortaleza') ✓ it passes with ('Sollefteå') ✓ it passes with ('Ιεράπετρα') - ✓ it passes with (stdClass Object (...)) + ✓ it passes with (stdClass Object (…)) ✓ it passes with array ✓ it passes with *not* ✓ it properly fails with *not* @@ -677,7 +677,7 @@ ✓ uses dataset with (3) ✓ uses dataset with (4) ✓ uses dataset with (5) - ✓ uses dataset with ('ScopedDatasets/NestedDirector...ts.php') + ✓ uses dataset with ('ScopedDatasets/NestedDirector…ts.php') ✓ the right dataset is taken PASS Tests\Features\ScopedDatasets\Directory\NestedDirectory2\TestFileInNestedDirectory @@ -821,6 +821,8 @@ ✓ 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 + ✓ it shows the correct description for long texts with newlines + ✓ it shows the correct description for arrays with many elements PASS Tests\Unit\Expectations\OppositeExpectation ✓ it throw expectation failed exception with string argument @@ -846,24 +848,24 @@ ✓ it cannot resolve a parameter without type PASS Tests\Unit\Support\DatasetInfo - ✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Datase...rs.php', true) + ✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Datase…rs.php', true) ✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Datasets.php', false) - ✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Featur...rs.php', true) - ✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Featur...rs.php', false) - ✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Featur...ts.php', false) - ✓ it can check if dataset is defined inside a Datasets.php file with ('/var/www/project/tests/Datase...rs.php', false) + ✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Featur…rs.php', true) + ✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Featur…rs.php', false) + ✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Featur…ts.php', false) + ✓ it can check if dataset is defined inside a Datasets.php file with ('/var/www/project/tests/Datase…rs.php', false) ✓ it can check if dataset is defined inside a Datasets.php file with ('/var/www/project/tests/Datasets.php', true) - ✓ it can check if dataset is defined inside a Datasets.php file with ('/var/www/project/tests/Featur...rs.php', false) #1 - ✓ it can check if dataset is defined inside a Datasets.php file with ('/var/www/project/tests/Featur...rs.php', false) #2 - ✓ it can check if dataset is defined inside a Datasets.php file with ('/var/www/project/tests/Featur...ts.php', true) - ✓ it computes the dataset scope with ('/var/www/project/tests/Datase...rs.php', '/var/www/project/tests') + ✓ it can check if dataset is defined inside a Datasets.php file with ('/var/www/project/tests/Featur…rs.php', false) #1 + ✓ it can check if dataset is defined inside a Datasets.php file with ('/var/www/project/tests/Featur…rs.php', false) #2 + ✓ it can check if dataset is defined inside a Datasets.php file with ('/var/www/project/tests/Featur…ts.php', true) + ✓ it computes the dataset scope with ('/var/www/project/tests/Datase…rs.php', '/var/www/project/tests') ✓ it computes the dataset scope with ('/var/www/project/tests/Datasets.php', '/var/www/project/tests') - ✓ it computes the dataset scope with ('/var/www/project/tests/Featur...rs.php', '/var/www/project/tests/Features') - ✓ it computes the dataset scope with ('/var/www/project/tests/Featur...rs.php', '/var/www/project/tests/Featur...rs.php') #1 - ✓ it computes the dataset scope with ('/var/www/project/tests/Featur...ts.php', '/var/www/project/tests/Features') - ✓ it computes the dataset scope with ('/var/www/project/tests/Featur...rs.php', '/var/www/project/tests/Featur...ollers') - ✓ it computes the dataset scope with ('/var/www/project/tests/Featur...rs.php', '/var/www/project/tests/Featur...rs.php') #2 - ✓ it computes the dataset scope with ('/var/www/project/tests/Featur...ts.php', '/var/www/project/tests/Featur...ollers') + ✓ it computes the dataset scope with ('/var/www/project/tests/Featur…rs.php', '/var/www/project/tests/Features') + ✓ it computes the dataset scope with ('/var/www/project/tests/Featur…rs.php', '/var/www/project/tests/Featur…rs.php') #1 + ✓ it computes the dataset scope with ('/var/www/project/tests/Featur…ts.php', '/var/www/project/tests/Features') + ✓ it computes the dataset scope with ('/var/www/project/tests/Featur…rs.php', '/var/www/project/tests/Featur…ollers') + ✓ it computes the dataset scope with ('/var/www/project/tests/Featur…rs.php', '/var/www/project/tests/Featur…rs.php') #2 + ✓ it computes the dataset scope with ('/var/www/project/tests/Featur…ts.php', '/var/www/project/tests/Featur…ollers') PASS Tests\Unit\Support\Reflection ✓ it gets file name from closure @@ -902,4 +904,4 @@ PASS Tests\Visual\Version ✓ visual snapshot of help command output - Tests: 4 incomplete, 4 todos, 18 skipped, 625 passed (1512 assertions) \ No newline at end of file + Tests: 4 incomplete, 4 todos, 18 skipped, 627 passed (1514 assertions) \ No newline at end of file diff --git a/tests/Unit/DatasetsTests.php b/tests/Unit/DatasetsTests.php index a1914f82..63653f5b 100644 --- a/tests/Unit/DatasetsTests.php +++ b/tests/Unit/DatasetsTests.php @@ -23,7 +23,7 @@ it('show the actual dataset of non-named datasets in their description', functio ], __FILE__)); expect($descriptions[0])->toBe('(1)'); - expect($descriptions[1])->toBe('(array(2))'); + expect($descriptions[1])->toBe('([2])'); }); it('show only the names of multiple named datasets in their description', function () { @@ -57,9 +57,9 @@ it('show the actual dataset of multiple non-named datasets in their description' ], __FILE__)); expect($descriptions[0])->toBe('(1) / (3)'); - expect($descriptions[1])->toBe('(1) / (array(4))'); - expect($descriptions[2])->toBe('(array(2)) / (3)'); - expect($descriptions[3])->toBe('(array(2)) / (array(4))'); + expect($descriptions[1])->toBe('(1) / ([4])'); + expect($descriptions[2])->toBe('([2]) / (3)'); + expect($descriptions[3])->toBe('([2]) / ([4])'); }); it('show the correct description for mixed named and not-named datasets', function () { @@ -76,6 +76,26 @@ it('show the correct description for mixed named and not-named datasets', functi expect($descriptions[0])->toBe('data set "one" / (3)'); expect($descriptions[1])->toBe('data set "one" / data set "four"'); - expect($descriptions[2])->toBe('(array(2)) / (3)'); - expect($descriptions[3])->toBe('(array(2)) / data set "four"'); + expect($descriptions[2])->toBe('([2]) / (3)'); + expect($descriptions[3])->toBe('([2]) / data set "four"'); +}); + +it('shows the correct description for long texts with newlines', function () { + $descriptions = array_keys(DatasetsRepository::resolve([ + [ + ['some very \nlong text with \n newlines'], + ], + ], __FILE__)); + + expect($descriptions[0])->toBe('(\'some very long text with …wlines\')'); +}); + +it('shows the correct description for arrays with many elements', function () { + $descriptions = array_keys(DatasetsRepository::resolve([ + [ + [[1, 2, 3, 4, 5]], + ], + ], __FILE__)); + + expect($descriptions[0])->toBe('([1, 2, 3, …])'); });