From f3f35a2ed119f63eefd323a8c66d3387e908df3f Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Sun, 30 Jul 2023 23:49:20 +0100 Subject: [PATCH] feat: adds `repeat` --- src/Concerns/Testable.php | 25 +++++- src/Exceptions/InvalidArgumentException.php | 24 ++++++ src/Factories/TestCaseMethodFactory.php | 15 +++- src/PendingCalls/TestCall.php | 16 +++- tests/.snapshots/success.txt | 91 ++++++++++++++++++++- tests/Features/Repeat.php | 18 ++++ tests/Visual/Parallel.php | 2 +- 7 files changed, 185 insertions(+), 6 deletions(-) create mode 100644 src/Exceptions/InvalidArgumentException.php create mode 100644 tests/Features/Repeat.php diff --git a/src/Concerns/Testable.php b/src/Concerns/Testable.php index a962edf3..3268f2ae 100644 --- a/src/Concerns/Testable.php +++ b/src/Concerns/Testable.php @@ -187,7 +187,24 @@ trait Testable $method = TestSuite::getInstance()->tests->get(self::$__filename)->getMethod($this->name()); - $this->__description = self::$__latestDescription = $this->dataName() ? $method->description.' with '.$this->dataName() : $method->description; + $description = $this->dataName() ? $method->description.' with '.$this->dataName() : $method->description; + + if ($method->repetitions > 1) { + $matches = []; + preg_match('/\((.*?)\)/', $description, $matches); + + if (count($matches) > 1) { + if (str_contains($description, 'with '.$matches[0].' /')) { + $description = str_replace('with '.$matches[0].' /', '', $description); + } else { + $description = str_replace('with '.$matches[0], '', $description); + } + } + + $description .= ' @ repetition '.($matches[1].' of '.$method->repetitions); + } + + $this->__description = self::$__latestDescription = $description; parent::setUp(); @@ -238,6 +255,12 @@ trait Testable */ private function __resolveTestArguments(array $arguments): array { + $method = TestSuite::getInstance()->tests->get(self::$__filename)->getMethod($this->name()); + + if ($method->repetitions > 1) { + array_shift($arguments); + } + $underlyingTest = Reflection::getFunctionVariable($this->__test, 'closure'); $testParameterTypes = array_values(Reflection::getFunctionArguments($underlyingTest)); diff --git a/src/Exceptions/InvalidArgumentException.php b/src/Exceptions/InvalidArgumentException.php new file mode 100644 index 00000000..6ba8ffa2 --- /dev/null +++ b/src/Exceptions/InvalidArgumentException.php @@ -0,0 +1,24 @@ +__invoke($this, $attributes); } - if ($this->datasets !== []) { + if ($this->datasets !== [] || $this->repetitions > 1) { $dataProviderName = $methodName.'_dataset'; $annotations[] = "@dataProvider $dataProviderName"; $datasetsCode = $this->buildDatasetForEvaluation($methodName, $dataProviderName); @@ -177,7 +182,13 @@ final class TestCaseMethodFactory */ private function buildDatasetForEvaluation(string $methodName, string $dataProviderName): string { - DatasetsRepository::with($this->filename, $methodName, $this->datasets); + $datasets = $this->datasets; + + if ($this->repetitions > 1) { + $datasets = [range(1, $this->repetitions), ...$datasets]; + } + + DatasetsRepository::with($this->filename, $methodName, $datasets); return <<testCaseMethod->repetitions = $times; + + return $this; + } + /** * Sets the test as "todo". */ diff --git a/tests/.snapshots/success.txt b/tests/.snapshots/success.txt index 9dc4510d..909ae0e6 100644 --- a/tests/.snapshots/success.txt +++ b/tests/.snapshots/success.txt @@ -762,6 +762,95 @@ ! notice → This is a notice description // tests/Features/Notices.php:4 ! a "describe" group of tests → notice → This is a notice description // tests/Features/Notices.php:11 + PASS Tests\Features\Repeat + ✓ once + ✓ multiple times @ repetition 1 of 5 + ✓ multiple times @ repetition 2 of 5 + ✓ multiple times @ repetition 3 of 5 + ✓ multiple times @ repetition 4 of 5 + ✓ multiple times @ repetition 5 of 5 + ✓ multiple times with single dataset dataset "a" @ repetition 1 of 6 + ✓ multiple times with single dataset dataset "b" @ repetition 1 of 6 + ✓ multiple times with single dataset dataset "c" @ repetition 1 of 6 + ✓ multiple times with single dataset dataset "a" @ repetition 2 of 6 + ✓ multiple times with single dataset dataset "b" @ repetition 2 of 6 + ✓ multiple times with single dataset dataset "c" @ repetition 2 of 6 + ✓ multiple times with single dataset dataset "a" @ repetition 3 of 6 + ✓ multiple times with single dataset dataset "b" @ repetition 3 of 6 + ✓ multiple times with single dataset dataset "c" @ repetition 3 of 6 + ✓ multiple times with single dataset dataset "a" @ repetition 4 of 6 + ✓ multiple times with single dataset dataset "b" @ repetition 4 of 6 + ✓ multiple times with single dataset dataset "c" @ repetition 4 of 6 + ✓ multiple times with single dataset dataset "a" @ repetition 5 of 6 + ✓ multiple times with single dataset dataset "b" @ repetition 5 of 6 + ✓ multiple times with single dataset dataset "c" @ repetition 5 of 6 + ✓ multiple times with single dataset dataset "a" @ repetition 6 of 6 + ✓ multiple times with single dataset dataset "b" @ repetition 6 of 6 + ✓ multiple times with single dataset dataset "c" @ repetition 6 of 6 + ✓ multiple times with multiple dataset dataset "a" / (4) @ repetition 1 of 7 + ✓ multiple times with multiple dataset dataset "a" / (5) @ repetition 1 of 7 + ✓ multiple times with multiple dataset dataset "a" / (6) @ repetition 1 of 7 + ✓ multiple times with multiple dataset dataset "b" / (4) @ repetition 1 of 7 + ✓ multiple times with multiple dataset dataset "b" / (5) @ repetition 1 of 7 + ✓ multiple times with multiple dataset dataset "b" / (6) @ repetition 1 of 7 + ✓ multiple times with multiple dataset dataset "c" / (4) @ repetition 1 of 7 + ✓ multiple times with multiple dataset dataset "c" / (5) @ repetition 1 of 7 + ✓ multiple times with multiple dataset dataset "c" / (6) @ repetition 1 of 7 + ✓ multiple times with multiple dataset dataset "a" / (4) @ repetition 2 of 7 + ✓ multiple times with multiple dataset dataset "a" / (5) @ repetition 2 of 7 + ✓ multiple times with multiple dataset dataset "a" / (6) @ repetition 2 of 7 + ✓ multiple times with multiple dataset dataset "b" / (4) @ repetition 2 of 7 + ✓ multiple times with multiple dataset dataset "b" / (5) @ repetition 2 of 7 + ✓ multiple times with multiple dataset dataset "b" / (6) @ repetition 2 of 7 + ✓ multiple times with multiple dataset dataset "c" / (4) @ repetition 2 of 7 + ✓ multiple times with multiple dataset dataset "c" / (5) @ repetition 2 of 7 + ✓ multiple times with multiple dataset dataset "c" / (6) @ repetition 2 of 7 + ✓ multiple times with multiple dataset dataset "a" / (4) @ repetition 3 of 7 + ✓ multiple times with multiple dataset dataset "a" / (5) @ repetition 3 of 7 + ✓ multiple times with multiple dataset dataset "a" / (6) @ repetition 3 of 7 + ✓ multiple times with multiple dataset dataset "b" / (4) @ repetition 3 of 7 + ✓ multiple times with multiple dataset dataset "b" / (5) @ repetition 3 of 7 + ✓ multiple times with multiple dataset dataset "b" / (6) @ repetition 3 of 7 + ✓ multiple times with multiple dataset dataset "c" / (4) @ repetition 3 of 7 + ✓ multiple times with multiple dataset dataset "c" / (5) @ repetition 3 of 7 + ✓ multiple times with multiple dataset dataset "c" / (6) @ repetition 3 of 7 + ✓ multiple times with multiple dataset dataset "a" / (4) @ repetition 4 of 7 + ✓ multiple times with multiple dataset dataset "a" / (5) @ repetition 4 of 7 + ✓ multiple times with multiple dataset dataset "a" / (6) @ repetition 4 of 7 + ✓ multiple times with multiple dataset dataset "b" / (4) @ repetition 4 of 7 + ✓ multiple times with multiple dataset dataset "b" / (5) @ repetition 4 of 7 + ✓ multiple times with multiple dataset dataset "b" / (6) @ repetition 4 of 7 + ✓ multiple times with multiple dataset dataset "c" / (4) @ repetition 4 of 7 + ✓ multiple times with multiple dataset dataset "c" / (5) @ repetition 4 of 7 + ✓ multiple times with multiple dataset dataset "c" / (6) @ repetition 4 of 7 + ✓ multiple times with multiple dataset dataset "a" / (4) @ repetition 5 of 7 + ✓ multiple times with multiple dataset dataset "a" / (5) @ repetition 5 of 7 + ✓ multiple times with multiple dataset dataset "a" / (6) @ repetition 5 of 7 + ✓ multiple times with multiple dataset dataset "b" / (4) @ repetition 5 of 7 + ✓ multiple times with multiple dataset dataset "b" / (5) @ repetition 5 of 7 + ✓ multiple times with multiple dataset dataset "b" / (6) @ repetition 5 of 7 + ✓ multiple times with multiple dataset dataset "c" / (4) @ repetition 5 of 7 + ✓ multiple times with multiple dataset dataset "c" / (5) @ repetition 5 of 7 + ✓ multiple times with multiple dataset dataset "c" / (6) @ repetition 5 of 7 + ✓ multiple times with multiple dataset dataset "a" / (4) @ repetition 6 of 7 + ✓ multiple times with multiple dataset dataset "a" / (5) @ repetition 6 of 7 + ✓ multiple times with multiple dataset dataset "a" / (6) @ repetition 6 of 7 + ✓ multiple times with multiple dataset dataset "b" / (4) @ repetition 6 of 7 + ✓ multiple times with multiple dataset dataset "b" / (5) @ repetition 6 of 7 + ✓ multiple times with multiple dataset dataset "b" / (6) @ repetition 6 of 7 + ✓ multiple times with multiple dataset dataset "c" / (4) @ repetition 6 of 7 + ✓ multiple times with multiple dataset dataset "c" / (5) @ repetition 6 of 7 + ✓ multiple times with multiple dataset dataset "c" / (6) @ repetition 6 of 7 + ✓ multiple times with multiple dataset dataset "a" / (4) @ repetition 7 of 7 + ✓ multiple times with multiple dataset dataset "a" / (5) @ repetition 7 of 7 + ✓ multiple times with multiple dataset dataset "a" / (6) @ repetition 7 of 7 + ✓ multiple times with multiple dataset dataset "b" / (4) @ repetition 7 of 7 + ✓ multiple times with multiple dataset dataset "b" / (5) @ repetition 7 of 7 + ✓ multiple times with multiple dataset dataset "b" / (6) @ repetition 7 of 7 + ✓ multiple times with multiple dataset dataset "c" / (4) @ repetition 7 of 7 + ✓ multiple times with multiple dataset dataset "c" / (5) @ repetition 7 of 7 + ✓ multiple times with multiple dataset dataset "c" / (6) @ repetition 7 of 7 + PASS Tests\Features\ScopedDatasets\Directory\NestedDirectory1\TestFileInNestedDirectoryWithDatasetsFile ✓ uses dataset with (1) ✓ uses dataset with (2) @@ -1085,4 +1174,4 @@ WARN Tests\Visual\Version - visual snapshot of help command output - Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 13 todos, 19 skipped, 743 passed (1777 assertions) \ No newline at end of file + Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 13 todos, 19 skipped, 830 passed (1927 assertions) \ No newline at end of file diff --git a/tests/Features/Repeat.php b/tests/Features/Repeat.php new file mode 100644 index 00000000..e0651d33 --- /dev/null +++ b/tests/Features/Repeat.php @@ -0,0 +1,18 @@ +toBeTrue(); +})->repeat(times: 1); + +test('multiple times', function () { + expect(true)->toBeTrue(); +})->repeat(times: 5); + +test('multiple times with single dataset', function (int $number) { + expect([1, 2, 3])->toContain($number); +})->repeat(times: 6)->with(['a' => 1, 'b' => 2, 'c' => 3]); + +test('multiple times with multiple dataset', function (int $numberA, int $numberB) { + expect([1, 2, 3])->toContain($numberA) + ->and([4, 5, 6])->toContain($numberB); +})->repeat(times: 7)->with(['a' => 1, 'b' => 2, 'c' => 3], [4, 5, 6]); diff --git a/tests/Visual/Parallel.php b/tests/Visual/Parallel.php index d87d551d..a8a69a34 100644 --- a/tests/Visual/Parallel.php +++ b/tests/Visual/Parallel.php @@ -16,7 +16,7 @@ $run = function () { test('parallel', function () use ($run) { expect($run('--exclude-group=integration')) - ->toContain('Tests: 1 deprecated, 4 warnings, 5 incomplete, 2 notices, 13 todos, 15 skipped, 732 passed (1762 assertions)') + ->toContain('Tests: 1 deprecated, 4 warnings, 5 incomplete, 2 notices, 13 todos, 15 skipped, 819 passed (1912 assertions)') ->toContain('Parallel: 3 processes'); })->skipOnWindows();