diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php
index 7dace6b1df8..02c2f6282da 100644
--- a/.php-cs-fixer.dist.php
+++ b/.php-cs-fixer.dist.php
@@ -24,6 +24,9 @@
->notName('TestAttributeOnHookMethodsTest.php')
// InvokableConstraintAndPipeOperatorTest.php uses PHP 8.5 syntax
->notName('InvokableConstraintAndPipeOperatorTest.php')
+ // NoReturnTypeTest.php and RepeatAttributeWithoutReturnTypeTest.php must have a method without a return type declaration
+ ->notPath('repeat/_files/NoReturnTypeTest.php')
+ ->notPath('repeat/_files/RepeatAttributeWithoutReturnTypeTest.php')
// FirstPartyClass.php and PhpDeprecationTest.php must not use declare(strict_types=1);
->notPath('error-handler/_files/php-deprecation/src/FirstPartyClass.php')
->notPath('error-handler/_files/php-deprecation/tests/PhpDeprecationTest.php')
diff --git a/phpunit.xml b/phpunit.xml
index aa383a74a29..c13a944af95 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -37,6 +37,7 @@
tests/end-to-end/migration
tests/end-to-end/phpt
tests/end-to-end/regression
+ tests/end-to-end/repeat
tests/end-to-end/test-doubles/generator
tests/end-to-end/test-doubles/runtime
tests/end-to-end/testdox
@@ -46,6 +47,7 @@
tests/end-to-end/groups-from-configuration/_files
tests/end-to-end/logging/_files
tests/end-to-end/migration/_files
+ tests/end-to-end/repeat/_files
tests/end-to-end/self-direct-indirect/_files
tests/end-to-end/testdox/_files
diff --git a/src/Event/Events/TestSuite/Finished.php b/src/Event/Events/TestSuite/Finished.php
index 378768de01c..305809548a2 100644
--- a/src/Event/Events/TestSuite/Finished.php
+++ b/src/Event/Events/TestSuite/Finished.php
@@ -47,11 +47,31 @@ public function testSuite(): TestSuite
*/
public function asString(): string
{
+ $prefix = 'Test Suite Finished';
+ $unit = 'test';
+
+ if ($this->testSuite->isForTestMethodWithDataProvider()) {
+ $prefix = 'Test Suite for Test Method with Data Provider Finished';
+ $unit = 'data set';
+ } elseif ($this->testSuite->isForRepeatedTestMethod()) {
+ $prefix = 'Test Suite for Repeated Test Method Finished';
+ $unit = 'repetition';
+ }
+
+ $count = $this->testSuite->count();
+ $plural = '';
+
+ if ($count !== 1) {
+ $plural = 's';
+ }
+
return sprintf(
- 'Test Suite Finished (%s, %d test%s)',
+ '%s (%s, %d %s%s)',
+ $prefix,
$this->testSuite->name(),
- $this->testSuite->count(),
- $this->testSuite->count() !== 1 ? 's' : '',
+ $count,
+ $unit,
+ $plural,
);
}
}
diff --git a/src/Event/Events/TestSuite/Started.php b/src/Event/Events/TestSuite/Started.php
index c558d7679b0..54e7b1ff676 100644
--- a/src/Event/Events/TestSuite/Started.php
+++ b/src/Event/Events/TestSuite/Started.php
@@ -47,11 +47,31 @@ public function testSuite(): TestSuite
*/
public function asString(): string
{
+ $prefix = 'Test Suite Started';
+ $unit = 'test';
+
+ if ($this->testSuite->isForTestMethodWithDataProvider()) {
+ $prefix = 'Test Suite for Test Method with Data Provider Started';
+ $unit = 'data set';
+ } elseif ($this->testSuite->isForRepeatedTestMethod()) {
+ $prefix = 'Test Suite for Repeated Test Method Started';
+ $unit = 'repetition';
+ }
+
+ $count = $this->testSuite->count();
+ $plural = '';
+
+ if ($count !== 1) {
+ $plural = 's';
+ }
+
return sprintf(
- 'Test Suite Started (%s, %d test%s)',
+ '%s (%s, %d %s%s)',
+ $prefix,
$this->testSuite->name(),
- $this->testSuite->count(),
- $this->testSuite->count() !== 1 ? 's' : '',
+ $count,
+ $unit,
+ $plural,
);
}
}
diff --git a/src/Event/Value/Test/TestMethod.php b/src/Event/Value/Test/TestMethod.php
index 3cc2590833a..ed142125bf3 100644
--- a/src/Event/Value/Test/TestMethod.php
+++ b/src/Event/Value/Test/TestMethod.php
@@ -39,24 +39,38 @@
private MetadataCollection $metadata;
private TestDataCollection $testData;
+ /**
+ * @var positive-int
+ */
+ private int $repetition;
+
+ /**
+ * @var positive-int
+ */
+ private int $totalRepetitions;
+
/**
* @param class-string $className
* @param non-empty-string $methodName
* @param non-empty-string $file
* @param non-negative-int $line
+ * @param positive-int $repetition
+ * @param positive-int $totalRepetitions
*
* @internal This method is not covered by the backward compatibility promise for PHPUnit
*/
- public function __construct(string $className, string $methodName, string $file, int $line, TestDox $testDox, MetadataCollection $metadata, TestDataCollection $testData)
+ public function __construct(string $className, string $methodName, string $file, int $line, TestDox $testDox, MetadataCollection $metadata, TestDataCollection $testData, int $repetition = 1, int $totalRepetitions = 1)
{
parent::__construct($file);
- $this->className = $className;
- $this->methodName = $methodName;
- $this->line = $line;
- $this->testDox = $testDox;
- $this->metadata = $metadata;
- $this->testData = $testData;
+ $this->className = $className;
+ $this->methodName = $methodName;
+ $this->line = $line;
+ $this->testDox = $testDox;
+ $this->metadata = $metadata;
+ $this->testData = $testData;
+ $this->repetition = $repetition;
+ $this->totalRepetitions = $totalRepetitions;
}
/**
@@ -98,6 +112,27 @@ public function testData(): TestDataCollection
return $this->testData;
}
+ /**
+ * @return positive-int
+ */
+ public function repetition(): int
+ {
+ return $this->repetition;
+ }
+
+ /**
+ * @return positive-int
+ */
+ public function totalRepetitions(): int
+ {
+ return $this->totalRepetitions;
+ }
+
+ public function isRepeated(): bool
+ {
+ return $this->totalRepetitions > 1;
+ }
+
public function isTestMethod(): true
{
return true;
@@ -114,6 +149,14 @@ public function id(): string
$buffer .= '#' . $this->testData->dataFromDataProvider()->dataSetName();
}
+ if ($this->totalRepetitions > 1) {
+ $buffer .= sprintf(
+ ' (repetition %d of %d)',
+ $this->repetition,
+ $this->totalRepetitions,
+ );
+ }
+
return $buffer;
}
@@ -130,24 +173,32 @@ public function nameWithClass(): string
*/
public function name(): string
{
- if (!$this->testData->hasDataFromDataProvider()) {
- return $this->methodName;
+ $name = $this->methodName;
+
+ if ($this->testData->hasDataFromDataProvider()) {
+ $dataSetName = $this->testData->dataFromDataProvider()->dataSetName();
+
+ if (is_int($dataSetName)) {
+ $name .= sprintf(
+ ' with data set #%d',
+ $dataSetName,
+ );
+ } else {
+ $name .= sprintf(
+ ' with data set "%s"',
+ $dataSetName,
+ );
+ }
}
- $dataSetName = $this->testData->dataFromDataProvider()->dataSetName();
-
- if (is_int($dataSetName)) {
- $dataSetName = sprintf(
- ' with data set #%d',
- $dataSetName,
- );
- } else {
- $dataSetName = sprintf(
- ' with data set "%s"',
- $dataSetName,
+ if ($this->totalRepetitions > 1) {
+ $name .= sprintf(
+ ' (repetition %d of %d)',
+ $this->repetition,
+ $this->totalRepetitions,
);
}
- return $this->methodName . $dataSetName;
+ return $name;
}
}
diff --git a/src/Event/Value/Test/TestMethodBuilder.php b/src/Event/Value/Test/TestMethodBuilder.php
index dc1a32ef8ab..6e69e869a7d 100644
--- a/src/Event/Value/Test/TestMethodBuilder.php
+++ b/src/Event/Value/Test/TestMethodBuilder.php
@@ -45,6 +45,8 @@ public static function fromTestCase(TestCase $testCase, bool $useTestCaseForTest
$testDox,
MetadataRegistry::parser()->forClassAndMethod($testCase::class, $methodName),
self::dataFor($testCase),
+ $testCase->repetition(),
+ $testCase->totalRepetitions(),
);
}
diff --git a/src/Event/Value/TestSuite/TestSuite.php b/src/Event/Value/TestSuite/TestSuite.php
index 73672ae00ff..35b38c6a786 100644
--- a/src/Event/Value/TestSuite/TestSuite.php
+++ b/src/Event/Value/TestSuite/TestSuite.php
@@ -78,4 +78,12 @@ public function isForTestMethodWithDataProvider(): bool
{
return false;
}
+
+ /**
+ * @phpstan-assert-if-true TestSuiteForRepeatedTestMethod $this
+ */
+ public function isForRepeatedTestMethod(): bool
+ {
+ return false;
+ }
}
diff --git a/src/Event/Value/TestSuite/TestSuiteBuilder.php b/src/Event/Value/TestSuite/TestSuiteBuilder.php
index 3192636baa9..b064e308928 100644
--- a/src/Event/Value/TestSuite/TestSuiteBuilder.php
+++ b/src/Event/Value/TestSuite/TestSuiteBuilder.php
@@ -14,10 +14,13 @@
use function count;
use function explode;
use function method_exists;
+use function strpos;
+use function substr;
use PHPUnit\Event\Code\Test;
use PHPUnit\Event\Code\TestCollection;
use PHPUnit\Event\RuntimeException;
use PHPUnit\Framework\DataProviderTestSuite;
+use PHPUnit\Framework\RepeatTestSuite;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestSuite as FrameworkTestSuite;
use PHPUnit\Runner\Phpt\TestCase as PhptTestCase;
@@ -66,6 +69,44 @@ public static function from(FrameworkTestSuite $testSuite): TestSuite
);
}
+ if ($testSuite instanceof RepeatTestSuite) {
+ $name = $testSuite->name();
+
+ $separatorPosition = strpos($name, '::');
+
+ assert($separatorPosition !== false);
+
+ $className = substr($name, 0, $separatorPosition);
+ $methodName = substr($name, $separatorPosition + 2);
+
+ $hashPosition = strpos($methodName, '#');
+
+ if ($hashPosition !== false) {
+ $methodName = substr($methodName, 0, $hashPosition);
+ }
+
+ assert($className !== '' && class_exists($className));
+ assert($methodName !== '' && method_exists($className, $methodName));
+
+ $reflector = new ReflectionMethod($className, $methodName);
+
+ $file = $reflector->getFileName();
+ $line = $reflector->getStartLine();
+
+ assert($file !== false);
+ assert($line !== false);
+
+ return new TestSuiteForRepeatedTestMethod(
+ $name,
+ $testSuite->count(),
+ TestCollection::fromArray($tests),
+ $className,
+ $methodName,
+ $file,
+ $line,
+ );
+ }
+
if ($testSuite->isForTestClass()) {
$testClassName = $testSuite->name();
diff --git a/src/Event/Value/TestSuite/TestSuiteForRepeatedTestMethod.php b/src/Event/Value/TestSuite/TestSuiteForRepeatedTestMethod.php
new file mode 100644
index 00000000000..e9679aeac16
--- /dev/null
+++ b/src/Event/Value/TestSuite/TestSuiteForRepeatedTestMethod.php
@@ -0,0 +1,78 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Event\TestSuite;
+
+use PHPUnit\Event\Code\TestCollection;
+
+/**
+ * @immutable
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final readonly class TestSuiteForRepeatedTestMethod extends TestSuite
+{
+ /**
+ * @var class-string
+ */
+ private string $className;
+
+ /**
+ * @var non-empty-string
+ */
+ private string $methodName;
+ private string $file;
+ private int $line;
+
+ /**
+ * @param non-empty-string $name
+ * @param class-string $className
+ * @param non-empty-string $methodName
+ */
+ public function __construct(string $name, int $size, TestCollection $tests, string $className, string $methodName, string $file, int $line)
+ {
+ parent::__construct($name, $size, $tests);
+
+ $this->className = $className;
+ $this->methodName = $methodName;
+ $this->file = $file;
+ $this->line = $line;
+ }
+
+ /**
+ * @return class-string
+ */
+ public function className(): string
+ {
+ return $this->className;
+ }
+
+ /**
+ * @return non-empty-string
+ */
+ public function methodName(): string
+ {
+ return $this->methodName;
+ }
+
+ public function file(): string
+ {
+ return $this->file;
+ }
+
+ public function line(): int
+ {
+ return $this->line;
+ }
+
+ public function isForRepeatedTestMethod(): true
+ {
+ return true;
+ }
+}
diff --git a/src/Framework/Attributes/Repeat.php b/src/Framework/Attributes/Repeat.php
new file mode 100644
index 00000000000..4932df7af9e
--- /dev/null
+++ b/src/Framework/Attributes/Repeat.php
@@ -0,0 +1,57 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Attributes;
+
+use Attribute;
+
+/**
+ * @immutable
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+#[Attribute(Attribute::TARGET_METHOD)]
+final readonly class Repeat
+{
+ /**
+ * @var positive-int
+ */
+ private int $times;
+
+ /**
+ * @var positive-int
+ */
+ private int $failureThreshold;
+
+ /**
+ * @param positive-int $times
+ * @param positive-int $failureThreshold
+ */
+ public function __construct(int $times, int $failureThreshold = 1)
+ {
+ $this->times = $times;
+ $this->failureThreshold = $failureThreshold;
+ }
+
+ /**
+ * @return positive-int
+ */
+ public function times(): int
+ {
+ return $this->times;
+ }
+
+ /**
+ * @return positive-int
+ */
+ public function failureThreshold(): int
+ {
+ return $this->failureThreshold;
+ }
+}
diff --git a/src/Framework/RepeatTestSuite.php b/src/Framework/RepeatTestSuite.php
new file mode 100644
index 00000000000..251c2af7214
--- /dev/null
+++ b/src/Framework/RepeatTestSuite.php
@@ -0,0 +1,149 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+use function assert;
+use PHPUnit\Event;
+use PHPUnit\Event\NoPreviousThrowableException;
+use PHPUnit\TestRunner\TestResult\Facade as TestResultFacade;
+use SebastianBergmann\CodeCoverage\InvalidArgumentException;
+use SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class RepeatTestSuite extends TestSuite
+{
+ /**
+ * @var positive-int
+ */
+ private int $failureThreshold = 1;
+
+ /**
+ * @param non-empty-string $name
+ * @param non-empty-list $tests
+ * @param positive-int $failureThreshold
+ */
+ public static function fromTests(string $name, array $tests, int $failureThreshold): self
+ {
+ $suite = self::empty($name);
+
+ $suite->failureThreshold = $failureThreshold;
+
+ foreach ($tests as $test) {
+ $suite->addTest($test);
+ }
+
+ return $suite;
+ }
+
+ /**
+ * @throws Event\RuntimeException
+ * @throws Exception
+ * @throws InvalidArgumentException
+ * @throws NoPreviousThrowableException
+ * @throws UnintentionallyCoveredCodeException
+ */
+ public function run(): void
+ {
+ if ($this->isEmpty()) {
+ return;
+ }
+
+ $emitter = Event\Facade::emitter();
+ $testSuiteValueObjectForEvents = Event\TestSuite\TestSuiteBuilder::from($this);
+
+ $emitter->testSuiteStarted($testSuiteValueObjectForEvents);
+
+ $failureCount = 0;
+ $lastFailedRepetition = 0;
+
+ foreach ($this as $test) {
+ assert($test instanceof TestCase);
+
+ if (TestResultFacade::shouldStop()) {
+ $emitter->testRunnerExecutionAborted();
+
+ break;
+ }
+
+ if ($failureCount >= $this->failureThreshold) {
+ $test->markSkippedForRepeatAbort($lastFailedRepetition);
+
+ continue;
+ }
+
+ $test->run();
+
+ if ($test->status()->isFailure() || $test->status()->isError()) {
+ $failureCount++;
+ $lastFailedRepetition = $test->repetition();
+ }
+ }
+
+ $emitter->testSuiteFinished($testSuiteValueObjectForEvents);
+ }
+
+ /**
+ * @param list $dependencies
+ */
+ public function setDependencies(array $dependencies): void
+ {
+ foreach ($this->tests() as $test) {
+ assert($test instanceof TestCase);
+
+ $test->setDependencies($dependencies);
+ }
+ }
+
+ /**
+ * @return list
+ */
+ public function provides(): array
+ {
+ $tests = $this->tests();
+
+ if ($tests === []) {
+ return [];
+ }
+
+ assert($tests[0] instanceof TestCase);
+
+ return $tests[0]->provides();
+ }
+
+ /**
+ * @return list
+ */
+ public function requires(): array
+ {
+ $tests = $this->tests();
+
+ if ($tests === []) {
+ return [];
+ }
+
+ assert($tests[0] instanceof TestCase);
+
+ return $tests[0]->requires();
+ }
+
+ public function sortId(): string
+ {
+ $tests = $this->tests();
+
+ assert($tests !== []);
+ assert($tests[0] instanceof TestCase);
+
+ return $tests[0]->sortId();
+ }
+}
diff --git a/src/Framework/TestBuilder.php b/src/Framework/TestBuilder.php
index e51427e13b8..b3e636a8ab6 100644
--- a/src/Framework/TestBuilder.php
+++ b/src/Framework/TestBuilder.php
@@ -13,6 +13,9 @@
use function assert;
use function get_parent_class;
use function preg_match;
+use function range;
+use function sprintf;
+use PHPUnit\Event\Facade as EventFacade;
use PHPUnit\Metadata\Api\DataProvider;
use PHPUnit\Metadata\Api\Groups;
use PHPUnit\Metadata\Api\ProvidedData;
@@ -23,10 +26,13 @@
use PHPUnit\Metadata\ExcludeStaticPropertyFromBackup;
use PHPUnit\Metadata\Parser\Registry as MetadataRegistry;
use PHPUnit\Metadata\PreserveGlobalState;
+use PHPUnit\Metadata\Repeat as RepeatMetadata;
use PHPUnit\Runner\ErrorHandler;
use PHPUnit\Runner\Filter\MethodNameFilterCompiler;
use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry;
use ReflectionClass;
+use ReflectionMethod;
+use ReflectionNamedType;
/**
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -41,12 +47,52 @@
* @param ReflectionClass $theClass
* @param non-empty-string $methodName
* @param list $groups
+ * @param positive-int $numberOfRuns
+ * @param positive-int $failureThreshold
*
* @throws InvalidDataProviderException
*/
- public function build(ReflectionClass $theClass, string $methodName, array $groups = []): Test
+ public function build(ReflectionClass $theClass, string $methodName, array $groups = [], int $numberOfRuns = 1, int $failureThreshold = 1): Test
{
- $className = $theClass->getName();
+ $className = $theClass->getName();
+ $runTestInSeparateProcess = $this->shouldTestMethodBeRunInSeparateProcess($className, $methodName);
+ $preserveGlobalState = $this->shouldGlobalStateBePreserved($className, $methodName);
+ $backupSettings = $this->backupSettings($className, $methodName);
+
+ $repeatMetadata = MetadataRegistry::parser()->forMethod($className, $methodName)->isRepeat();
+
+ if ($repeatMetadata->isNotEmpty()) {
+ $metadata = $repeatMetadata->asArray()[0];
+
+ assert($metadata instanceof RepeatMetadata);
+
+ $numberOfRuns = $metadata->times();
+ $failureThreshold = $metadata->failureThreshold();
+
+ if (!$this->hasVoidReturnType($theClass->getMethod($methodName))) {
+ EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(
+ sprintf(
+ 'Method %s::%s is annotated with #[Repeat] but does not have a void return type declaration and will not be repeated',
+ $className,
+ $methodName,
+ ),
+ );
+ }
+
+ if (!$this->doesNotDependOnAnotherTest($className, $methodName)) {
+ EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(
+ sprintf(
+ 'Method %s::%s is annotated with #[Repeat] but depends on another test and will not be repeated',
+ $className,
+ $methodName,
+ ),
+ );
+ }
+ }
+
+ $repeat = $numberOfRuns > 1 &&
+ $this->hasVoidReturnType($theClass->getMethod($methodName)) &&
+ $this->doesNotDependOnAnotherTest($className, $methodName);
$data = null;
@@ -66,10 +112,24 @@ public function build(ReflectionClass $theClass, string $methodName, array $grou
$methodName,
$className,
$data,
- $this->shouldTestMethodBeRunInSeparateProcess($className, $methodName),
- $this->shouldGlobalStateBePreserved($className, $methodName),
- $this->backupSettings($className, $methodName),
+ $runTestInSeparateProcess,
+ $preserveGlobalState,
+ $backupSettings,
$groups,
+ $repeat ? $numberOfRuns : 1,
+ $failureThreshold,
+ );
+ }
+
+ if ($repeat) {
+ return $this->buildRepeatTestSuite(
+ $className,
+ $methodName,
+ $numberOfRuns,
+ $failureThreshold,
+ $runTestInSeparateProcess,
+ $preserveGlobalState,
+ $backupSettings,
);
}
@@ -83,9 +143,9 @@ public function build(ReflectionClass $theClass, string $methodName, array $grou
$this->configureTestCase(
$test,
- $this->shouldTestMethodBeRunInSeparateProcess($className, $methodName),
- $this->shouldGlobalStateBePreserved($className, $methodName),
- $this->backupSettings($className, $methodName),
+ $runTestInSeparateProcess,
+ $preserveGlobalState,
+ $backupSettings,
);
return $test;
@@ -97,8 +157,10 @@ public function build(ReflectionClass $theClass, string $methodName, array $grou
* @param array $data
* @param BackupSettings $backupSettings
* @param list $groups
+ * @param positive-int $numberOfRuns
+ * @param positive-int $failureThreshold
*/
- private function buildDataProviderTestSuite(string $methodName, string $className, array $data, bool $runTestInSeparateProcess, ?bool $preserveGlobalState, array $backupSettings, array $groups): DataProviderTestSuite
+ private function buildDataProviderTestSuite(string $methodName, string $className, array $data, bool $runTestInSeparateProcess, ?bool $preserveGlobalState, array $backupSettings, array $groups, int $numberOfRuns = 1, int $failureThreshold = 1): DataProviderTestSuite
{
$dataProviderTestSuite = DataProviderTestSuite::empty(
$className . '::' . $methodName,
@@ -110,21 +172,83 @@ private function buildDataProviderTestSuite(string $methodName, string $classNam
);
foreach ($data as $_dataName => $_data) {
- $_test = new $className($methodName);
+ if ($numberOfRuns > 1) {
+ $tests = [];
+
+ foreach (range(1, $numberOfRuns) as $i) {
+ $_test = new $className($methodName);
+
+ $_test->setData($_dataName, $_data->value());
+ $_test->setRepetition($i, $numberOfRuns);
+
+ $this->configureTestCase(
+ $_test,
+ $runTestInSeparateProcess,
+ $preserveGlobalState,
+ $backupSettings,
+ );
+
+ $tests[] = $_test;
+ }
+
+ $dataProviderTestSuite->addTest(
+ RepeatTestSuite::fromTests(
+ $className . '::' . $methodName . '#' . $_dataName,
+ $tests,
+ $failureThreshold,
+ ),
+ $groups,
+ );
+ } else {
+ $_test = new $className($methodName);
+
+ $_test->setData($_dataName, $_data->value());
+
+ $this->configureTestCase(
+ $_test,
+ $runTestInSeparateProcess,
+ $preserveGlobalState,
+ $backupSettings,
+ );
+
+ $dataProviderTestSuite->addTest($_test, $groups);
+ }
+ }
+
+ return $dataProviderTestSuite;
+ }
- $_test->setData($_dataName, $_data->value());
+ /**
+ * @param class-string $className
+ * @param non-empty-string $methodName
+ * @param positive-int $numberOfRuns
+ * @param positive-int $failureThreshold
+ * @param array{backupGlobals: ?true, backupGlobalsExcludeList: list, backupStaticProperties: ?true, backupStaticPropertiesExcludeList: array>} $backupSettings
+ */
+ private function buildRepeatTestSuite(string $className, string $methodName, int $numberOfRuns, int $failureThreshold, bool $runTestInSeparateProcess, ?bool $preserveGlobalState, array $backupSettings): RepeatTestSuite
+ {
+ $tests = [];
+
+ foreach (range(1, $numberOfRuns) as $i) {
+ $test = new $className($methodName);
+
+ $test->setRepetition($i, $numberOfRuns);
$this->configureTestCase(
- $_test,
+ $test,
$runTestInSeparateProcess,
$preserveGlobalState,
$backupSettings,
);
- $dataProviderTestSuite->addTest($_test, $groups);
+ $tests[] = $test;
}
- return $dataProviderTestSuite;
+ return RepeatTestSuite::fromTests(
+ $className . '::' . $methodName,
+ $tests,
+ $failureThreshold,
+ );
}
/**
@@ -323,4 +447,30 @@ private function filterExcludesMethod(string $className, string $methodName): bo
return $result === 0;
}
+
+ private function hasVoidReturnType(ReflectionMethod $method): bool
+ {
+ if (!$method->hasReturnType()) {
+ return false;
+ }
+
+ $returnType = $method->getReturnType();
+
+ if (!$returnType instanceof ReflectionNamedType) {
+ return false;
+ }
+
+ return $returnType->getName() === 'void';
+ }
+
+ /**
+ * @param class-string $className
+ * @param non-empty-string $methodName
+ */
+ private function doesNotDependOnAnotherTest(string $className, string $methodName): bool
+ {
+ $metadata = MetadataRegistry::parser()->forClassAndMethod($className, $methodName);
+
+ return $metadata->isDepends()->isEmpty();
+ }
}
diff --git a/src/Framework/TestCase.php b/src/Framework/TestCase.php
index 71108967cfd..8aba5681cca 100644
--- a/src/Framework/TestCase.php
+++ b/src/Framework/TestCase.php
@@ -233,6 +233,16 @@ abstract class TestCase extends Assert implements Reorderable, SelfDescribing, T
private false|string $previousErrorLogTarget = false;
private ?string $emptyDataProviderSkipMessage = null;
+ /**
+ * @var positive-int
+ */
+ private int $repetition = 1;
+
+ /**
+ * @var positive-int
+ */
+ private int $totalRepetitions = 1;
+
/**
* @param non-empty-string $name
*
@@ -1003,6 +1013,56 @@ final public function wasPrepared(): bool
return $this->wasPrepared;
}
+ /**
+ * @return positive-int
+ *
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ final public function repetition(): int
+ {
+ return $this->repetition;
+ }
+
+ /**
+ * @return positive-int
+ *
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ final public function totalRepetitions(): int
+ {
+ return $this->totalRepetitions;
+ }
+
+ /**
+ * @param positive-int $repetition
+ * @param positive-int $totalRepetitions
+ *
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ final public function setRepetition(int $repetition, int $totalRepetitions): void
+ {
+ $this->repetition = $repetition;
+ $this->totalRepetitions = $totalRepetitions;
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ final public function markSkippedForRepeatAbort(int $failedRepetition): void
+ {
+ $message = sprintf(
+ 'Remaining repetition skipped after failure in repetition %d',
+ $failedRepetition,
+ );
+
+ Event\Facade::emitter()->testSkipped(
+ $this->valueObjectForEvents(),
+ $message,
+ );
+
+ $this->status = TestStatus::skipped($message);
+ }
+
/**
* Returns a matcher that matches when the method is executed
* zero or more times.
diff --git a/src/Framework/TestSuite.php b/src/Framework/TestSuite.php
index 6490b22301c..d749deb4837 100644
--- a/src/Framework/TestSuite.php
+++ b/src/Framework/TestSuite.php
@@ -97,8 +97,9 @@ public static function empty(string $name): static
/**
* @param ReflectionClass $class
* @param list $groups
+ * @param positive-int $numberOfRuns
*/
- public static function fromClassReflector(ReflectionClass $class, array $groups = []): static
+ public static function fromClassReflector(ReflectionClass $class, array $groups = [], int $numberOfRuns = 1): static
{
$testSuite = new static($class->getName());
@@ -119,7 +120,7 @@ public static function fromClassReflector(ReflectionClass $class, array $groups
continue;
}
- $testSuite->addTestMethod($class, $method, $groups);
+ $testSuite->addTestMethod($class, $method, $groups, $numberOfRuns);
}
if ($testSuite->isEmpty()) {
@@ -189,10 +190,11 @@ public function addTest(Test $test, array $groups = []): void
*
* @param ReflectionClass $testClass
* @param list $groups
+ * @param positive-int $numberOfRuns
*
* @throws Exception
*/
- public function addTestSuite(ReflectionClass $testClass, array $groups = []): void
+ public function addTestSuite(ReflectionClass $testClass, array $groups = [], int $numberOfRuns = 1): void
{
$className = $testClass->getName();
@@ -215,7 +217,7 @@ public function addTestSuite(ReflectionClass $testClass, array $groups = []): vo
);
}
- $this->addTest(self::fromClassReflector($testClass, $groups), $groups);
+ $this->addTest(self::fromClassReflector($testClass, $groups, $numberOfRuns), $groups);
}
/**
@@ -227,10 +229,11 @@ public function addTestSuite(ReflectionClass $testClass, array $groups = []): vo
* leaving the current test run untouched.
*
* @param list $groups
+ * @param positive-int $numberOfRuns
*
* @throws Exception
*/
- public function addTestFile(string $filename, array $groups = []): void
+ public function addTestFile(string $filename, array $groups = [], int $numberOfRuns = 1): void
{
try {
if (str_ends_with($filename, '.phpt') && is_file($filename)) {
@@ -239,6 +242,7 @@ public function addTestFile(string $filename, array $groups = []): void
$this->addTestSuite(
(new TestSuiteLoader)->load($filename),
$groups,
+ $numberOfRuns,
);
}
} catch (RunnerException $e) {
@@ -256,13 +260,14 @@ public function addTestFile(string $filename, array $groups = []): void
* Wrapper for addTestFile() that adds multiple test files.
*
* @param iterable $fileNames
+ * @param positive-int $numberOfRuns
*
* @throws Exception
*/
- public function addTestFiles(iterable $fileNames): void
+ public function addTestFiles(iterable $fileNames, int $numberOfRuns = 1): void
{
foreach ($fileNames as $filename) {
- $this->addTestFile((string) $filename);
+ $this->addTestFile((string) $filename, [], $numberOfRuns);
}
}
@@ -511,16 +516,17 @@ public function isForTestClass(): bool
/**
* @param ReflectionClass $class
* @param list $groups
+ * @param positive-int $numberOfRuns
*
* @throws Exception
*/
- protected function addTestMethod(ReflectionClass $class, ReflectionMethod $method, array $groups): void
+ protected function addTestMethod(ReflectionClass $class, ReflectionMethod $method, array $groups, int $numberOfRuns = 1): void
{
$className = $class->getName();
$methodName = $method->getName();
try {
- $test = (new TestBuilder)->build($class, $methodName, $groups);
+ $test = (new TestBuilder)->build($class, $methodName, $groups, $numberOfRuns);
} catch (InvalidDataProviderException $e) {
if ($e->getProviderLabel() === null) {
$message = sprintf(
@@ -564,7 +570,7 @@ protected function addTestMethod(ReflectionClass $class, ReflectionMethod $metho
return;
}
- if ($test instanceof TestCase || $test instanceof DataProviderTestSuite) {
+ if ($test instanceof TestCase || $test instanceof DataProviderTestSuite || $test instanceof RepeatTestSuite) {
$test->setDependencies(
Dependencies::dependencies($class->getName(), $methodName),
);
diff --git a/src/Logging/JUnit/JunitXmlLogger.php b/src/Logging/JUnit/JunitXmlLogger.php
index f0bdeb5366d..93b9e7b247f 100644
--- a/src/Logging/JUnit/JunitXmlLogger.php
+++ b/src/Logging/JUnit/JunitXmlLogger.php
@@ -12,7 +12,6 @@
use const PHP_EOL;
use function assert;
use function basename;
-use function is_int;
use function sprintf;
use function str_replace;
use function trim;
@@ -448,25 +447,7 @@ private function name(Test $test): string
assert($test instanceof TestMethod);
- if (!$test->testData()->hasDataFromDataProvider()) {
- return $test->methodName();
- }
-
- $dataSetName = $test->testData()->dataFromDataProvider()->dataSetName();
-
- if (is_int($dataSetName)) {
- return sprintf(
- '%s with data set #%d',
- $test->methodName(),
- $dataSetName,
- );
- }
-
- return sprintf(
- '%s with data set "%s"',
- $test->methodName(),
- $dataSetName,
- );
+ return $test->name();
}
/**
diff --git a/src/Metadata/Metadata.php b/src/Metadata/Metadata.php
index 3a3f2de34b3..09f47141b32 100644
--- a/src/Metadata/Metadata.php
+++ b/src/Metadata/Metadata.php
@@ -482,6 +482,15 @@ public static function runTestsInSeparateProcesses(): RunTestsInSeparateProcesse
return new RunTestsInSeparateProcesses(Level::CLASS_LEVEL);
}
+ /**
+ * @param positive-int $times
+ * @param positive-int $failureThreshold
+ */
+ public static function repeat(int $times, int $failureThreshold): Repeat
+ {
+ return new Repeat(Level::METHOD_LEVEL, $times, $failureThreshold);
+ }
+
public static function runInSeparateProcess(): RunInSeparateProcess
{
return new RunInSeparateProcess(Level::METHOD_LEVEL);
@@ -820,6 +829,14 @@ public function isIgnorePhpunitDeprecations(): bool
return false;
}
+ /**
+ * @phpstan-assert-if-true Repeat $this
+ */
+ public function isRepeat(): bool
+ {
+ return false;
+ }
+
/**
* @phpstan-assert-if-true RunInSeparateProcess $this
*/
diff --git a/src/Metadata/MetadataCollection.php b/src/Metadata/MetadataCollection.php
index 975d5af6b74..2f6e43f459e 100644
--- a/src/Metadata/MetadataCollection.php
+++ b/src/Metadata/MetadataCollection.php
@@ -391,6 +391,16 @@ public function isIgnorePhpunitWarnings(): self
);
}
+ public function isRepeat(): self
+ {
+ return new self(
+ ...array_filter(
+ $this->metadata,
+ static fn (Metadata $metadata): bool => $metadata->isRepeat(),
+ ),
+ );
+ }
+
public function isRunInSeparateProcess(): self
{
return new self(
diff --git a/src/Metadata/Parser/AttributeParser.php b/src/Metadata/Parser/AttributeParser.php
index a475c35636b..ef5ce175cd6 100644
--- a/src/Metadata/Parser/AttributeParser.php
+++ b/src/Metadata/Parser/AttributeParser.php
@@ -61,6 +61,7 @@
use PHPUnit\Framework\Attributes\PostCondition;
use PHPUnit\Framework\Attributes\PreCondition;
use PHPUnit\Framework\Attributes\PreserveGlobalState;
+use PHPUnit\Framework\Attributes\Repeat;
use PHPUnit\Framework\Attributes\RequiresEnvironmentVariable;
use PHPUnit\Framework\Attributes\RequiresFunction;
use PHPUnit\Framework\Attributes\RequiresMethod;
@@ -894,6 +895,16 @@ public function forMethod(string $className, string $methodName): MetadataCollec
break;
+ case Repeat::class:
+ assert($attributeInstance instanceof Repeat);
+
+ $result[] = Metadata::repeat(
+ $attributeInstance->times(),
+ $attributeInstance->failureThreshold(),
+ );
+
+ break;
+
case RunInSeparateProcess::class:
$result[] = Metadata::runInSeparateProcess();
diff --git a/src/Metadata/Repeat.php b/src/Metadata/Repeat.php
new file mode 100644
index 00000000000..b84ccc1c8b7
--- /dev/null
+++ b/src/Metadata/Repeat.php
@@ -0,0 +1,61 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Metadata;
+
+/**
+ * @immutable
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final readonly class Repeat extends Metadata
+{
+ /**
+ * @var positive-int
+ */
+ private int $times;
+
+ /**
+ * @var positive-int
+ */
+ private int $failureThreshold;
+
+ /**
+ * @param positive-int $times
+ * @param positive-int $failureThreshold
+ */
+ protected function __construct(Level $level, int $times, int $failureThreshold)
+ {
+ parent::__construct($level);
+
+ $this->times = $times;
+ $this->failureThreshold = $failureThreshold;
+ }
+
+ public function isRepeat(): true
+ {
+ return true;
+ }
+
+ /**
+ * @return positive-int
+ */
+ public function times(): int
+ {
+ return $this->times;
+ }
+
+ /**
+ * @return positive-int
+ */
+ public function failureThreshold(): int
+ {
+ return $this->failureThreshold;
+ }
+}
diff --git a/src/Runner/TestResult/Collector.php b/src/Runner/TestResult/Collector.php
index 3c1fef008bb..19e8093ff82 100644
--- a/src/Runner/TestResult/Collector.php
+++ b/src/Runner/TestResult/Collector.php
@@ -51,6 +51,7 @@
use PHPUnit\Event\TestSuite\Finished as TestSuiteFinished;
use PHPUnit\Event\TestSuite\Skipped as TestSuiteSkipped;
use PHPUnit\Event\TestSuite\Started as TestSuiteStarted;
+use PHPUnit\Event\TestSuite\TestSuiteForRepeatedTestMethod;
use PHPUnit\Event\TestSuite\TestSuiteForTestClass;
use PHPUnit\Event\TestSuite\TestSuiteForTestMethodWithDataProvider;
use PHPUnit\TestRunner\IssueFilter;
@@ -350,6 +351,29 @@ public function testSuiteFinished(TestSuiteFinished $event): void
return;
}
+ if ($testSuite->isForRepeatedTestMethod()) {
+ assert($testSuite instanceof TestSuiteForRepeatedTestMethod);
+ assert(count($testSuite->tests()->asArray()) > 0);
+
+ $test = $testSuite->tests()->asArray()[0];
+
+ assert($test instanceof TestMethod);
+
+ foreach ($this->testFailedEvents as $testFailedEvent) {
+ if ($testFailedEvent instanceof AfterLastTestMethodFailed || $testFailedEvent instanceof BeforeFirstTestMethodFailed) {
+ continue;
+ }
+
+ if ($testFailedEvent->test()->isTestMethod() && $testFailedEvent->test()->methodName() === $test->methodName()) {
+ return;
+ }
+ }
+
+ PassedTests::instance()->testMethodPassed($test, null);
+
+ return;
+ }
+
assert($testSuite instanceof TestSuiteForTestClass);
PassedTests::instance()->testClassPassed($testSuite->className());
diff --git a/src/TextUI/Configuration/Cli/Builder.php b/src/TextUI/Configuration/Cli/Builder.php
index 782cbd6129f..e7461717dc1 100644
--- a/src/TextUI/Configuration/Cli/Builder.php
+++ b/src/TextUI/Configuration/Cli/Builder.php
@@ -116,6 +116,7 @@ final class Builder
'do-not-report-useless-tests',
'random-order',
'random-order-seed=',
+ 'repeat=',
'reverse-order',
'reverse-list',
'static-backup',
@@ -363,6 +364,7 @@ public function fromParameters(array $parameters): Configuration
$noLogging = null;
$processIsolation = null;
$randomOrderSeed = null;
+ $repeat = null;
$reportUselessTests = null;
$resolveDependencies = null;
$reverseList = null;
@@ -1209,6 +1211,25 @@ public function fromParameters(array $parameters): Configuration
break;
+ case '--repeat':
+ if (!is_numeric($option[1]) ||
+ (string) (int) $option[1] !== $option[1] ||
+ (int) $option[1] < 1) {
+ EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(
+ sprintf(
+ 'Option "--repeat %s" ignored because "%s" is not a positive integer',
+ $option[1],
+ $option[1],
+ ),
+ );
+
+ break;
+ }
+
+ $repeat = (int) $option[1];
+
+ break;
+
case '--resolve-dependencies':
$resolveDependencies = true;
@@ -1409,6 +1430,7 @@ public function fromParameters(array $parameters): Configuration
$noLogging,
$processIsolation,
$randomOrderSeed,
+ $repeat,
$reportUselessTests,
$resolveDependencies,
$reverseList,
diff --git a/src/TextUI/Configuration/Cli/Configuration.php b/src/TextUI/Configuration/Cli/Configuration.php
index 545682e2ace..da4dec277c1 100644
--- a/src/TextUI/Configuration/Cli/Configuration.php
+++ b/src/TextUI/Configuration/Cli/Configuration.php
@@ -157,6 +157,11 @@
private ?bool $noLogging;
private ?bool $processIsolation;
private ?int $randomOrderSeed;
+
+ /**
+ * @var ?positive-int
+ */
+ private ?int $repeat;
private ?bool $reportUselessTests;
private ?bool $resolveDependencies;
private ?bool $reverseList;
@@ -207,11 +212,12 @@
* @param ?non-empty-list $testsUsing
* @param ?non-empty-list $testsRequiringPhpExtension
* @param ?non-empty-array $iniSettings
+ * @param ?positive-int $repeat
* @param ?non-empty-list $testSuffixes
* @param ?non-empty-list $coverageFilter
* @param ?non-empty-list $extensions
*/
- public function __construct(array $arguments, ?string $testFilesFile, ?string $testIdFile, ?string $testIdFilter, ?bool $all, ?string $atLeastVersion, ?bool $backupGlobals, ?bool $backupStaticProperties, ?bool $beStrictAboutChangesToGlobalState, ?string $bootstrap, ?string $cacheDirectory, ?bool $cacheResult, bool $checkPhpConfiguration, bool $checkVersion, ?string $colors, null|int|string $columns, ?string $configurationFile, ?string $coverageClover, ?string $coverageCobertura, ?string $coverageCrap4J, ?string $coverageHtml, ?string $coverageOpenClover, ?string $coveragePhp, ?string $coverageText, ?bool $coverageTextShowUncoveredFiles, ?bool $coverageTextShowOnlySummary, ?string $coverageXml, ?bool $coverageXmlIncludeSource, ?bool $pathCoverage, ?bool $branchCoverage, bool $warmCoverageCache, ?int $defaultTimeLimit, ?int $diffContext, ?bool $disableCodeCoverageIgnore, ?bool $disableCoverageTargeting, ?bool $disallowTestOutput, ?bool $enforceTimeLimit, ?array $excludeGroups, ?int $executionOrder, ?int $executionOrderDefects, ?bool $failOnAllIssues, ?bool $failOnDeprecation, ?bool $failOnPhpunitDeprecation, ?bool $failOnPhpunitNotice, ?bool $failOnPhpunitWarning, ?bool $failOnEmptyTestSuite, ?bool $failOnIncomplete, ?bool $failOnNotice, ?bool $failOnRisky, ?bool $failOnSkipped, ?bool $failOnWarning, ?bool $doNotFailOnDeprecation, ?bool $doNotFailOnPhpunitDeprecation, ?bool $doNotFailOnPhpunitNotice, ?bool $doNotFailOnPhpunitWarning, ?bool $doNotFailOnEmptyTestSuite, ?bool $doNotFailOnIncomplete, ?bool $doNotFailOnNotice, ?bool $doNotFailOnRisky, ?bool $doNotFailOnSkipped, ?bool $doNotFailOnWarning, ?int $stopOnDefect, ?int $stopOnDeprecation, ?string $specificDeprecationToStopOn, ?int $stopOnError, ?int $stopOnFailure, ?int $stopOnIncomplete, ?int $stopOnNotice, ?int $stopOnRisky, ?int $stopOnSkipped, ?int $stopOnWarning, ?string $filter, ?string $excludeFilter, ?string $generateBaseline, ?string $useBaseline, bool $ignoreBaseline, bool $generateConfiguration, bool $migrateConfiguration, bool $validateConfiguration, ?array $groups, ?array $testsCovering, ?array $testsUsing, ?array $testsRequiringPhpExtension, bool $help, ?string $includePath, ?array $iniSettings, ?string $junitLogfile, ?string $otrLogfile, ?bool $includeGitInformation, bool $listGroups, bool $listSuites, bool $listTestFiles, bool $listTestIds, bool $listTests, ?string $listTestsXml, ?bool $noCoverage, ?bool $noExtensions, ?bool $noOutput, ?bool $noProgress, ?bool $noResults, ?bool $noLogging, ?bool $processIsolation, ?int $randomOrderSeed, ?bool $reportUselessTests, ?bool $resolveDependencies, ?bool $reverseList, ?bool $stderr, ?bool $strictCoverage, ?bool $requireCoverageContribution, ?string $teamcityLogfile, ?string $testdoxHtmlFile, ?string $testdoxTextFile, ?array $testSuffixes, ?string $testSuite, ?string $excludeTestSuite, bool $useDefaultConfiguration, ?bool $displayDetailsOnAllIssues, ?bool $displayDetailsOnIncompleteTests, ?bool $displayDetailsOnSkippedTests, ?bool $displayDetailsOnTestsThatTriggerDeprecations, ?bool $displayDetailsOnPhpunitDeprecations, ?bool $displayDetailsOnPhpunitNotices, ?bool $displayDetailsOnTestsThatTriggerErrors, ?bool $displayDetailsOnTestsThatTriggerNotices, ?bool $displayDetailsOnTestsThatTriggerWarnings, bool $version, ?array $coverageFilter, ?string $logEventsText, ?string $logEventsVerboseText, ?bool $printerCompact, ?bool $printerTeamCity, ?bool $testdoxPrinter, ?bool $testdoxPrinterSummary, bool $debug, bool $withTelemetry, ?array $extensions)
+ public function __construct(array $arguments, ?string $testFilesFile, ?string $testIdFile, ?string $testIdFilter, ?bool $all, ?string $atLeastVersion, ?bool $backupGlobals, ?bool $backupStaticProperties, ?bool $beStrictAboutChangesToGlobalState, ?string $bootstrap, ?string $cacheDirectory, ?bool $cacheResult, bool $checkPhpConfiguration, bool $checkVersion, ?string $colors, null|int|string $columns, ?string $configurationFile, ?string $coverageClover, ?string $coverageCobertura, ?string $coverageCrap4J, ?string $coverageHtml, ?string $coverageOpenClover, ?string $coveragePhp, ?string $coverageText, ?bool $coverageTextShowUncoveredFiles, ?bool $coverageTextShowOnlySummary, ?string $coverageXml, ?bool $coverageXmlIncludeSource, ?bool $pathCoverage, ?bool $branchCoverage, bool $warmCoverageCache, ?int $defaultTimeLimit, ?int $diffContext, ?bool $disableCodeCoverageIgnore, ?bool $disableCoverageTargeting, ?bool $disallowTestOutput, ?bool $enforceTimeLimit, ?array $excludeGroups, ?int $executionOrder, ?int $executionOrderDefects, ?bool $failOnAllIssues, ?bool $failOnDeprecation, ?bool $failOnPhpunitDeprecation, ?bool $failOnPhpunitNotice, ?bool $failOnPhpunitWarning, ?bool $failOnEmptyTestSuite, ?bool $failOnIncomplete, ?bool $failOnNotice, ?bool $failOnRisky, ?bool $failOnSkipped, ?bool $failOnWarning, ?bool $doNotFailOnDeprecation, ?bool $doNotFailOnPhpunitDeprecation, ?bool $doNotFailOnPhpunitNotice, ?bool $doNotFailOnPhpunitWarning, ?bool $doNotFailOnEmptyTestSuite, ?bool $doNotFailOnIncomplete, ?bool $doNotFailOnNotice, ?bool $doNotFailOnRisky, ?bool $doNotFailOnSkipped, ?bool $doNotFailOnWarning, ?int $stopOnDefect, ?int $stopOnDeprecation, ?string $specificDeprecationToStopOn, ?int $stopOnError, ?int $stopOnFailure, ?int $stopOnIncomplete, ?int $stopOnNotice, ?int $stopOnRisky, ?int $stopOnSkipped, ?int $stopOnWarning, ?string $filter, ?string $excludeFilter, ?string $generateBaseline, ?string $useBaseline, bool $ignoreBaseline, bool $generateConfiguration, bool $migrateConfiguration, bool $validateConfiguration, ?array $groups, ?array $testsCovering, ?array $testsUsing, ?array $testsRequiringPhpExtension, bool $help, ?string $includePath, ?array $iniSettings, ?string $junitLogfile, ?string $otrLogfile, ?bool $includeGitInformation, bool $listGroups, bool $listSuites, bool $listTestFiles, bool $listTestIds, bool $listTests, ?string $listTestsXml, ?bool $noCoverage, ?bool $noExtensions, ?bool $noOutput, ?bool $noProgress, ?bool $noResults, ?bool $noLogging, ?bool $processIsolation, ?int $randomOrderSeed, ?int $repeat, ?bool $reportUselessTests, ?bool $resolveDependencies, ?bool $reverseList, ?bool $stderr, ?bool $strictCoverage, ?bool $requireCoverageContribution, ?string $teamcityLogfile, ?string $testdoxHtmlFile, ?string $testdoxTextFile, ?array $testSuffixes, ?string $testSuite, ?string $excludeTestSuite, bool $useDefaultConfiguration, ?bool $displayDetailsOnAllIssues, ?bool $displayDetailsOnIncompleteTests, ?bool $displayDetailsOnSkippedTests, ?bool $displayDetailsOnTestsThatTriggerDeprecations, ?bool $displayDetailsOnPhpunitDeprecations, ?bool $displayDetailsOnPhpunitNotices, ?bool $displayDetailsOnTestsThatTriggerErrors, ?bool $displayDetailsOnTestsThatTriggerNotices, ?bool $displayDetailsOnTestsThatTriggerWarnings, bool $version, ?array $coverageFilter, ?string $logEventsText, ?string $logEventsVerboseText, ?bool $printerCompact, ?bool $printerTeamCity, ?bool $testdoxPrinter, ?bool $testdoxPrinterSummary, bool $debug, bool $withTelemetry, ?array $extensions)
{
$this->arguments = $arguments;
$this->testFilesFile = $testFilesFile;
@@ -317,6 +323,7 @@ public function __construct(array $arguments, ?string $testFilesFile, ?string $t
$this->noLogging = $noLogging;
$this->processIsolation = $processIsolation;
$this->randomOrderSeed = $randomOrderSeed;
+ $this->repeat = $repeat;
$this->reportUselessTests = $reportUselessTests;
$this->resolveDependencies = $resolveDependencies;
$this->reverseList = $reverseList;
@@ -2240,6 +2247,28 @@ public function randomOrderSeed(): int
return $this->randomOrderSeed;
}
+ /**
+ * @phpstan-assert-if-true !null $this->repeat
+ */
+ public function hasRepeat(): bool
+ {
+ return $this->repeat !== null;
+ }
+
+ /**
+ * @throws Exception
+ *
+ * @return positive-int
+ */
+ public function repeat(): int
+ {
+ if (!$this->hasRepeat()) {
+ throw new Exception;
+ }
+
+ return $this->repeat;
+ }
+
/**
* @phpstan-assert-if-true !null $this->reportUselessTests
*/
diff --git a/src/TextUI/Configuration/Configuration.php b/src/TextUI/Configuration/Configuration.php
index 4ddb4809ca4..1ef00ad615f 100644
--- a/src/TextUI/Configuration/Configuration.php
+++ b/src/TextUI/Configuration/Configuration.php
@@ -432,6 +432,11 @@
* @var positive-int
*/
private int $randomOrderSeed;
+
+ /**
+ * @var positive-int
+ */
+ private int $repeat;
private bool $includeUncoveredFiles;
private TestSuiteCollection $testSuite;
private string $includeTestSuite;
@@ -535,13 +540,14 @@
* @param list $groups
* @param list $excludeGroups
* @param positive-int $randomOrderSeed
+ * @param positive-int $repeat
* @param ?non-empty-string $defaultTestSuite
* @param non-empty-list $testSuffixes
* @param positive-int $numberOfTestsBeforeGarbageCollection
* @param null|non-empty-string $generateBaseline
* @param non-negative-int $shortenArraysForExportThreshold
*/
- public function __construct(array $cliArguments, ?string $testFilesFile, ?string $configurationFile, ?string $bootstrap, array $bootstrapForTestSuite, bool $cacheResult, ?string $cacheDirectory, ?string $coverageCacheDirectory, Source $source, string $testResultCacheFile, ?string $coverageClover, ?string $coverageCobertura, ?string $coverageCrap4j, int $coverageCrap4jThreshold, ?string $coverageHtml, int $coverageHtmlLowUpperBound, int $coverageHtmlHighLowerBound, string $coverageHtmlColorSuccessLow, string $coverageHtmlColorSuccessLowDark, string $coverageHtmlColorSuccessMedium, string $coverageHtmlColorSuccessMediumDark, string $coverageHtmlColorSuccessHigh, string $coverageHtmlColorSuccessHighDark, string $coverageHtmlColorSuccessBar, string $coverageHtmlColorSuccessBarDark, string $coverageHtmlColorWarning, string $coverageHtmlColorWarningDark, string $coverageHtmlColorWarningBar, string $coverageHtmlColorWarningBarDark, string $coverageHtmlColorDanger, string $coverageHtmlColorDangerDark, string $coverageHtmlColorDangerBar, string $coverageHtmlColorDangerBarDark, string $coverageHtmlColorBreadcrumbs, string $coverageHtmlColorBreadcrumbsDark, ?string $coverageHtmlCustomCssFile, ?string $coverageOpenClover, ?string $coveragePhp, ?string $coverageText, bool $coverageTextShowUncoveredFiles, bool $coverageTextShowOnlySummary, ?string $coverageXml, bool $coverageXmlIncludeSource, bool $pathCoverage, bool $branchCoverage, bool $ignoreDeprecatedCodeUnitsFromCodeCoverage, bool $disableCodeCoverageIgnore, bool $disableCoverageTargeting, bool $failOnAllIssues, bool $failOnDeprecation, bool $failOnPhpunitDeprecation, bool $failOnPhpunitNotice, bool $failOnPhpunitWarning, bool $failOnEmptyTestSuite, bool $failOnIncomplete, bool $failOnNotice, bool $failOnRisky, bool $failOnSkipped, bool $failOnWarning, bool $doNotFailOnDeprecation, bool $doNotFailOnPhpunitDeprecation, bool $doNotFailOnPhpunitNotice, bool $doNotFailOnPhpunitWarning, bool $doNotFailOnEmptyTestSuite, bool $doNotFailOnIncomplete, bool $doNotFailOnNotice, bool $doNotFailOnRisky, bool $doNotFailOnSkipped, bool $doNotFailOnWarning, int $stopOnDefect, int $stopOnDeprecation, ?string $specificDeprecationToStopOn, int $stopOnError, int $stopOnFailure, int $stopOnIncomplete, int $stopOnNotice, int $stopOnRisky, int $stopOnSkipped, int $stopOnWarning, bool $outputToStandardErrorStream, int $columns, bool $noExtensions, ?string $pharExtensionDirectory, array $extensionBootstrappers, bool $backupGlobals, bool $backupStaticProperties, bool $beStrictAboutChangesToGlobalState, bool $colors, bool $processIsolation, bool $enforceTimeLimit, int $defaultTimeLimit, int $diffContext, int $timeoutForSmallTests, int $timeoutForMediumTests, int $timeoutForLargeTests, bool $reportUselessTests, bool $strictCoverage, bool $requireCoverageContribution, bool $disallowTestOutput, bool $displayDetailsOnAllIssues, bool $displayDetailsOnIncompleteTests, bool $displayDetailsOnSkippedTests, bool $displayDetailsOnTestsThatTriggerDeprecations, bool $displayDetailsOnPhpunitDeprecations, bool $displayDetailsOnPhpunitNotices, bool $displayDetailsOnTestsThatTriggerErrors, bool $displayDetailsOnTestsThatTriggerNotices, bool $displayDetailsOnTestsThatTriggerWarnings, bool $reverseDefectList, bool $requireCoverageMetadata, bool $requireSealedMockObjects, bool $noProgress, bool $noResults, bool $noOutput, int $executionOrder, int $executionOrderDefects, bool $resolveDependencies, ?string $logfileTeamcity, ?string $logfileJunit, ?string $logfileOtr, bool $includeGitInformation, bool $includeGitInformationInOtrLogfile, ?string $logfileTestdoxHtml, ?string $logfileTestdoxText, ?string $logEventsText, ?string $logEventsVerboseText, bool $compactOutput, bool $teamCityOutput, bool $testDoxOutput, bool $testDoxOutputSummary, ?array $testsCovering, ?array $testsUsing, ?array $testsRequiringPhpExtension, ?string $filter, ?string $excludeFilter, ?string $testIdFilterFile, ?string $testIdFilter, array $groups, array $excludeGroups, int $randomOrderSeed, bool $includeUncoveredFiles, TestSuiteCollection $testSuite, string $includeTestSuite, string $excludeTestSuite, ?string $defaultTestSuite, bool $ignoreTestSelectionInXmlConfiguration, array $testSuffixes, Php $php, bool $controlGarbageCollector, int $numberOfTestsBeforeGarbageCollection, ?string $generateBaseline, bool $debug, bool $withTelemetry, int $shortenArraysForExportThreshold)
+ public function __construct(array $cliArguments, ?string $testFilesFile, ?string $configurationFile, ?string $bootstrap, array $bootstrapForTestSuite, bool $cacheResult, ?string $cacheDirectory, ?string $coverageCacheDirectory, Source $source, string $testResultCacheFile, ?string $coverageClover, ?string $coverageCobertura, ?string $coverageCrap4j, int $coverageCrap4jThreshold, ?string $coverageHtml, int $coverageHtmlLowUpperBound, int $coverageHtmlHighLowerBound, string $coverageHtmlColorSuccessLow, string $coverageHtmlColorSuccessLowDark, string $coverageHtmlColorSuccessMedium, string $coverageHtmlColorSuccessMediumDark, string $coverageHtmlColorSuccessHigh, string $coverageHtmlColorSuccessHighDark, string $coverageHtmlColorSuccessBar, string $coverageHtmlColorSuccessBarDark, string $coverageHtmlColorWarning, string $coverageHtmlColorWarningDark, string $coverageHtmlColorWarningBar, string $coverageHtmlColorWarningBarDark, string $coverageHtmlColorDanger, string $coverageHtmlColorDangerDark, string $coverageHtmlColorDangerBar, string $coverageHtmlColorDangerBarDark, string $coverageHtmlColorBreadcrumbs, string $coverageHtmlColorBreadcrumbsDark, ?string $coverageHtmlCustomCssFile, ?string $coverageOpenClover, ?string $coveragePhp, ?string $coverageText, bool $coverageTextShowUncoveredFiles, bool $coverageTextShowOnlySummary, ?string $coverageXml, bool $coverageXmlIncludeSource, bool $pathCoverage, bool $branchCoverage, bool $ignoreDeprecatedCodeUnitsFromCodeCoverage, bool $disableCodeCoverageIgnore, bool $disableCoverageTargeting, bool $failOnAllIssues, bool $failOnDeprecation, bool $failOnPhpunitDeprecation, bool $failOnPhpunitNotice, bool $failOnPhpunitWarning, bool $failOnEmptyTestSuite, bool $failOnIncomplete, bool $failOnNotice, bool $failOnRisky, bool $failOnSkipped, bool $failOnWarning, bool $doNotFailOnDeprecation, bool $doNotFailOnPhpunitDeprecation, bool $doNotFailOnPhpunitNotice, bool $doNotFailOnPhpunitWarning, bool $doNotFailOnEmptyTestSuite, bool $doNotFailOnIncomplete, bool $doNotFailOnNotice, bool $doNotFailOnRisky, bool $doNotFailOnSkipped, bool $doNotFailOnWarning, int $stopOnDefect, int $stopOnDeprecation, ?string $specificDeprecationToStopOn, int $stopOnError, int $stopOnFailure, int $stopOnIncomplete, int $stopOnNotice, int $stopOnRisky, int $stopOnSkipped, int $stopOnWarning, bool $outputToStandardErrorStream, int $columns, bool $noExtensions, ?string $pharExtensionDirectory, array $extensionBootstrappers, bool $backupGlobals, bool $backupStaticProperties, bool $beStrictAboutChangesToGlobalState, bool $colors, bool $processIsolation, bool $enforceTimeLimit, int $defaultTimeLimit, int $diffContext, int $timeoutForSmallTests, int $timeoutForMediumTests, int $timeoutForLargeTests, bool $reportUselessTests, bool $strictCoverage, bool $requireCoverageContribution, bool $disallowTestOutput, bool $displayDetailsOnAllIssues, bool $displayDetailsOnIncompleteTests, bool $displayDetailsOnSkippedTests, bool $displayDetailsOnTestsThatTriggerDeprecations, bool $displayDetailsOnPhpunitDeprecations, bool $displayDetailsOnPhpunitNotices, bool $displayDetailsOnTestsThatTriggerErrors, bool $displayDetailsOnTestsThatTriggerNotices, bool $displayDetailsOnTestsThatTriggerWarnings, bool $reverseDefectList, bool $requireCoverageMetadata, bool $requireSealedMockObjects, bool $noProgress, bool $noResults, bool $noOutput, int $executionOrder, int $executionOrderDefects, bool $resolveDependencies, ?string $logfileTeamcity, ?string $logfileJunit, ?string $logfileOtr, bool $includeGitInformation, bool $includeGitInformationInOtrLogfile, ?string $logfileTestdoxHtml, ?string $logfileTestdoxText, ?string $logEventsText, ?string $logEventsVerboseText, bool $compactOutput, bool $teamCityOutput, bool $testDoxOutput, bool $testDoxOutputSummary, ?array $testsCovering, ?array $testsUsing, ?array $testsRequiringPhpExtension, ?string $filter, ?string $excludeFilter, ?string $testIdFilterFile, ?string $testIdFilter, array $groups, array $excludeGroups, int $randomOrderSeed, int $repeat, bool $includeUncoveredFiles, TestSuiteCollection $testSuite, string $includeTestSuite, string $excludeTestSuite, ?string $defaultTestSuite, bool $ignoreTestSelectionInXmlConfiguration, array $testSuffixes, Php $php, bool $controlGarbageCollector, int $numberOfTestsBeforeGarbageCollection, ?string $generateBaseline, bool $debug, bool $withTelemetry, int $shortenArraysForExportThreshold)
{
$this->cliArguments = $cliArguments;
$this->testFilesFile = $testFilesFile;
@@ -683,6 +689,7 @@ public function __construct(array $cliArguments, ?string $testFilesFile, ?string
$this->groups = $groups;
$this->excludeGroups = $excludeGroups;
$this->randomOrderSeed = $randomOrderSeed;
+ $this->repeat = $repeat;
$this->includeUncoveredFiles = $includeUncoveredFiles;
$this->testSuite = $testSuite;
$this->includeTestSuite = $includeTestSuite;
@@ -2164,6 +2171,14 @@ public function randomOrderSeed(): int
return $this->randomOrderSeed;
}
+ /**
+ * @return positive-int
+ */
+ public function repeat(): int
+ {
+ return $this->repeat;
+ }
+
public function includeUncoveredFiles(): bool
{
return $this->includeUncoveredFiles;
diff --git a/src/TextUI/Configuration/Merger.php b/src/TextUI/Configuration/Merger.php
index b87dd0ff612..ec70c7996a9 100644
--- a/src/TextUI/Configuration/Merger.php
+++ b/src/TextUI/Configuration/Merger.php
@@ -912,6 +912,12 @@ public function merge(CliConfiguration $cliConfiguration, XmlConfiguration $xmlC
$randomOrderSeed = time();
}
+ $repeat = 1;
+
+ if ($cliConfiguration->hasRepeat()) {
+ $repeat = $cliConfiguration->repeat();
+ }
+
if ($xmlConfiguration->wasLoadedFromFile() && $xmlConfiguration->hasValidationErrors()) {
if ((new SchemaDetector)->detect($xmlConfiguration->filename())->detected()) {
EventFacade::emitter()->testRunnerTriggeredPhpunitDeprecation(
@@ -1282,6 +1288,7 @@ public function merge(CliConfiguration $cliConfiguration, XmlConfiguration $xmlC
$groups,
$excludeGroups,
$randomOrderSeed,
+ $repeat,
$includeUncoveredFiles,
$xmlConfiguration->testSuite(),
$includeTestSuite,
diff --git a/src/TextUI/Configuration/TestSuiteBuilder.php b/src/TextUI/Configuration/TestSuiteBuilder.php
index 44cc0b71212..039be174b3f 100644
--- a/src/TextUI/Configuration/TestSuiteBuilder.php
+++ b/src/TextUI/Configuration/TestSuiteBuilder.php
@@ -45,6 +45,8 @@
*/
public function build(Configuration $configuration): TestSuite
{
+ $numberOfRuns = $configuration->repeat();
+
if ($configuration->hasCliArguments() || $configuration->hasTestFilesFile()) {
$arguments = [];
@@ -95,11 +97,13 @@ public function build(Configuration $configuration): TestSuite
$testSuite = $this->testSuiteFromPath(
$arguments[0],
$configuration->testSuffixes(),
+ $numberOfRuns,
);
} else {
$testSuite = $this->testSuiteFromPathList(
$arguments,
$configuration->testSuffixes(),
+ $numberOfRuns,
);
}
}
@@ -114,6 +118,7 @@ public function build(Configuration $configuration): TestSuite
$configuration->testSuite(),
$configuration->ignoreTestSelectionInXmlConfiguration() ? [] : $configuration->includeTestSuites(),
$configuration->ignoreTestSelectionInXmlConfiguration() ? [] : $configuration->excludeTestSuites(),
+ $numberOfRuns,
);
}
@@ -125,17 +130,18 @@ public function build(Configuration $configuration): TestSuite
/**
* @param non-empty-string $path
* @param list $suffixes
+ * @param positive-int $numberOfRuns
*
* @throws \PHPUnit\Framework\Exception
*/
- private function testSuiteFromPath(string $path, array $suffixes, ?TestSuite $suite = null): TestSuite
+ private function testSuiteFromPath(string $path, array $suffixes, int $numberOfRuns, ?TestSuite $suite = null): TestSuite
{
if (str_ends_with($path, '.phpt') && is_file($path)) {
if ($suite === null) {
$suite = TestSuite::empty($path);
}
- $suite->addTestFile($path);
+ $suite->addTestFile($path, [], $numberOfRuns);
return $suite;
}
@@ -147,7 +153,7 @@ private function testSuiteFromPath(string $path, array $suffixes, ?TestSuite $su
$suite = TestSuite::empty('CLI Arguments');
}
- $suite->addTestFiles($files);
+ $suite->addTestFiles($files, $numberOfRuns);
return $suite;
}
@@ -161,10 +167,10 @@ private function testSuiteFromPath(string $path, array $suffixes, ?TestSuite $su
}
if ($suite === null) {
- return TestSuite::fromClassReflector($testClass);
+ return TestSuite::fromClassReflector($testClass, [], $numberOfRuns);
}
- $suite->addTestSuite($testClass);
+ $suite->addTestSuite($testClass, [], $numberOfRuns);
return $suite;
}
@@ -172,15 +178,16 @@ private function testSuiteFromPath(string $path, array $suffixes, ?TestSuite $su
/**
* @param list $paths
* @param list $suffixes
+ * @param positive-int $numberOfRuns
*
* @throws \PHPUnit\Framework\Exception
*/
- private function testSuiteFromPathList(array $paths, array $suffixes): TestSuite
+ private function testSuiteFromPathList(array $paths, array $suffixes, int $numberOfRuns): TestSuite
{
$suite = TestSuite::empty('CLI Arguments');
foreach ($paths as $path) {
- $this->testSuiteFromPath($path, $suffixes, $suite);
+ $this->testSuiteFromPath($path, $suffixes, $numberOfRuns, $suite);
}
return $suite;
diff --git a/src/TextUI/Configuration/Xml/TestSuiteMapper.php b/src/TextUI/Configuration/Xml/TestSuiteMapper.php
index 66bd611c1c6..61c99d62590 100644
--- a/src/TextUI/Configuration/Xml/TestSuiteMapper.php
+++ b/src/TextUI/Configuration/Xml/TestSuiteMapper.php
@@ -36,12 +36,13 @@
* @param non-empty-string $xmlConfigurationFile
* @param list $includeTestSuites
* @param list $excludeTestSuites
+ * @param positive-int $numberOfRuns
*
* @throws RuntimeException
* @throws TestDirectoryNotFoundException
* @throws TestFileNotFoundException
*/
- public function map(string $xmlConfigurationFile, TestSuiteCollection $configuredTestSuites, array $includeTestSuites, array $excludeTestSuites): TestSuiteObject
+ public function map(string $xmlConfigurationFile, TestSuiteCollection $configuredTestSuites, array $includeTestSuites, array $excludeTestSuites, int $numberOfRuns = 1): TestSuiteObject
{
try {
$result = TestSuiteObject::empty($xmlConfigurationFile);
@@ -101,7 +102,7 @@ public function map(string $xmlConfigurationFile, TestSuiteCollection $configure
$processed[$file] = $testSuiteName;
$empty = false;
- $testSuite->addTestFile($file, $groups);
+ $testSuite->addTestFile($file, $groups, $numberOfRuns);
}
}
@@ -130,7 +131,7 @@ public function map(string $xmlConfigurationFile, TestSuiteCollection $configure
$processed[$file->path()] = $testSuiteName;
$empty = false;
- $testSuite->addTestFile($file->path(), $file->groups());
+ $testSuite->addTestFile($file->path(), $file->groups(), $numberOfRuns);
}
if (!$empty) {
diff --git a/src/TextUI/Help.php b/src/TextUI/Help.php
index 3bda4b78ebd..1ae49d06513 100644
--- a/src/TextUI/Help.php
+++ b/src/TextUI/Help.php
@@ -272,6 +272,7 @@ private function elements(): array
['arg' => '--ignore-dependencies', 'desc' => 'Alias for "--order-by no-depends"'],
['arg' => '--random-order', 'desc' => 'Alias for "--order-by random"'],
['arg' => '--random-order-seed ', 'desc' => 'Use the specified random seed when running tests in random order'],
+ ['arg' => '--repeat ', 'desc' => 'Run each test N times, stopping at the first failure'],
['arg' => '--reverse-order', 'desc' => 'Alias for "--order-by reverse"'],
],
diff --git a/tests/_files/Metadata/Attribute/tests/RepeatTest.php b/tests/_files/Metadata/Attribute/tests/RepeatTest.php
new file mode 100644
index 00000000000..1cc98494545
--- /dev/null
+++ b/tests/_files/Metadata/Attribute/tests/RepeatTest.php
@@ -0,0 +1,21 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TestFixture\Metadata\Attribute;
+
+use PHPUnit\Framework\Attributes\Repeat;
+use PHPUnit\Framework\TestCase;
+
+final class RepeatTest extends TestCase
+{
+ #[Repeat(5, failureThreshold: 2)]
+ public function testOne(): void
+ {
+ }
+}
diff --git a/tests/end-to-end/_files/output-cli-help-color.txt b/tests/end-to-end/_files/output-cli-help-color.txt
index 4389f4f4ec6..2e9c7f3e452 100644
--- a/tests/end-to-end/_files/output-cli-help-color.txt
+++ b/tests/end-to-end/_files/output-cli-help-color.txt
@@ -149,6 +149,8 @@
[32m--random-order [0m Alias for "--order-by random"
[32m--random-order-seed [36m[0m [0m Use the specified random seed when
running tests in random order
+ [32m--repeat [36m[0m [0m Run each test N times, stopping at the
+ first failure
[32m--reverse-order [0m Alias for "--order-by reverse"
[33mReporting:[0m
diff --git a/tests/end-to-end/_files/output-cli-usage.txt b/tests/end-to-end/_files/output-cli-usage.txt
index f390f71b4b8..9b7e12b9305 100644
--- a/tests/end-to-end/_files/output-cli-usage.txt
+++ b/tests/end-to-end/_files/output-cli-usage.txt
@@ -98,6 +98,7 @@ Execution:
--ignore-dependencies Alias for "--order-by no-depends"
--random-order Alias for "--order-by random"
--random-order-seed Use the specified random seed when running tests in random order
+ --repeat Run each test N times, stopping at the first failure
--reverse-order Alias for "--order-by reverse"
Reporting:
diff --git a/tests/end-to-end/cli/filter/filter-empty-method-portion-keeps-all-providers.phpt b/tests/end-to-end/cli/filter/filter-empty-method-portion-keeps-all-providers.phpt
index 2854419366f..001daaa59ff 100644
--- a/tests/end-to-end/cli/filter/filter-empty-method-portion-keeps-all-providers.phpt
+++ b/tests/end-to-end/cli/filter/filter-empty-method-portion-keeps-all-providers.phpt
@@ -28,18 +28,18 @@ Test Suite Sorted
Test Suite Filtered (2 tests)
Test Runner Execution Started (2 tests)
Test Suite Started (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest, 2 tests)
-Test Suite Started (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA, 1 test)
+Test Suite for Test Method with Data Provider Started (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA, 1 data set)
Test Preparation Started (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA#1)
Test Prepared (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA#1)
Test Passed (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA#1)
Test Finished (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA#1)
-Test Suite Finished (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA, 1 test)
-Test Suite Started (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testB, 1 test)
+Test Suite for Test Method with Data Provider Finished (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA, 1 data set)
+Test Suite for Test Method with Data Provider Started (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testB, 1 data set)
Test Preparation Started (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testB#1)
Test Prepared (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testB#1)
Test Passed (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testB#1)
Test Finished (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testB#1)
-Test Suite Finished (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testB, 1 test)
+Test Suite for Test Method with Data Provider Finished (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testB, 1 data set)
Test Suite Finished (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest, 2 tests)
Test Runner Execution Finished
Test Runner Finished
diff --git a/tests/end-to-end/cli/filter/filter-explicit-regex-keeps-all-providers.phpt b/tests/end-to-end/cli/filter/filter-explicit-regex-keeps-all-providers.phpt
index 0ad3c6529c0..cebb887dcaf 100644
--- a/tests/end-to-end/cli/filter/filter-explicit-regex-keeps-all-providers.phpt
+++ b/tests/end-to-end/cli/filter/filter-explicit-regex-keeps-all-providers.phpt
@@ -28,7 +28,7 @@ Test Suite Sorted
Test Suite Filtered (2 tests)
Test Runner Execution Started (2 tests)
Test Suite Started (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest, 2 tests)
-Test Suite Started (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA, 2 tests)
+Test Suite for Test Method with Data Provider Started (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA, 2 data sets)
Test Preparation Started (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA#0)
Test Prepared (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA#0)
Test Passed (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA#0)
@@ -37,7 +37,7 @@ Test Preparation Started (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::
Test Prepared (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA#1)
Test Passed (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA#1)
Test Finished (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA#1)
-Test Suite Finished (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA, 2 tests)
+Test Suite for Test Method with Data Provider Finished (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA, 2 data sets)
Test Suite Finished (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest, 2 tests)
Test Runner Execution Finished
Test Runner Finished
diff --git a/tests/end-to-end/cli/filter/filter-skips-data-provider-for-non-matching-method.phpt b/tests/end-to-end/cli/filter/filter-skips-data-provider-for-non-matching-method.phpt
index 317561f796d..271956a32a2 100644
--- a/tests/end-to-end/cli/filter/filter-skips-data-provider-for-non-matching-method.phpt
+++ b/tests/end-to-end/cli/filter/filter-skips-data-provider-for-non-matching-method.phpt
@@ -25,7 +25,7 @@ Test Suite Sorted
Test Suite Filtered (2 tests)
Test Runner Execution Started (2 tests)
Test Suite Started (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest, 2 tests)
-Test Suite Started (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA, 2 tests)
+Test Suite for Test Method with Data Provider Started (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA, 2 data sets)
Test Preparation Started (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA#0)
Test Prepared (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA#0)
Test Passed (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA#0)
@@ -34,7 +34,7 @@ Test Preparation Started (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::
Test Prepared (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA#1)
Test Passed (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA#1)
Test Finished (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA#1)
-Test Suite Finished (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA, 2 tests)
+Test Suite for Test Method with Data Provider Finished (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest::testA, 2 data sets)
Test Suite Finished (PHPUnit\TestFixture\DataProviderSkipWhenFilteredTest, 2 tests)
Test Runner Execution Finished
Test Runner Finished
diff --git a/tests/end-to-end/cli/test-id-filter/test-id-filter-by-id-with-special-characters.phpt b/tests/end-to-end/cli/test-id-filter/test-id-filter-by-id-with-special-characters.phpt
index dcf79b8ad7e..31025272477 100644
--- a/tests/end-to-end/cli/test-id-filter/test-id-filter-by-id-with-special-characters.phpt
+++ b/tests/end-to-end/cli/test-id-filter/test-id-filter-by-id-with-special-characters.phpt
@@ -25,12 +25,12 @@ Test Suite Sorted
Test Suite Filtered (1 test)
Test Runner Execution Started (1 test)
Test Suite Started (PHPUnit\TestFixture\TestIdFilter\BarTest, 1 test)
-Test Suite Started (PHPUnit\TestFixture\TestIdFilter\BarTest::testWithSpecialCharacters, 1 test)
+Test Suite for Test Method with Data Provider Started (PHPUnit\TestFixture\TestIdFilter\BarTest::testWithSpecialCharacters, 1 data set)
Test Preparation Started (PHPUnit\TestFixture\TestIdFilter\BarTest::testWithSpecialCharacters#total ($100))
Test Prepared (PHPUnit\TestFixture\TestIdFilter\BarTest::testWithSpecialCharacters#total ($100))
Test Passed (PHPUnit\TestFixture\TestIdFilter\BarTest::testWithSpecialCharacters#total ($100))
Test Finished (PHPUnit\TestFixture\TestIdFilter\BarTest::testWithSpecialCharacters#total ($100))
-Test Suite Finished (PHPUnit\TestFixture\TestIdFilter\BarTest::testWithSpecialCharacters, 1 test)
+Test Suite for Test Method with Data Provider Finished (PHPUnit\TestFixture\TestIdFilter\BarTest::testWithSpecialCharacters, 1 data set)
Test Suite Finished (PHPUnit\TestFixture\TestIdFilter\BarTest, 1 test)
Test Runner Execution Finished
Test Runner Finished
diff --git a/tests/end-to-end/event/data-provider-external.phpt b/tests/end-to-end/event/data-provider-external.phpt
index 03ff9791292..9aa408e6538 100644
--- a/tests/end-to-end/event/data-provider-external.phpt
+++ b/tests/end-to-end/event/data-provider-external.phpt
@@ -25,7 +25,7 @@ Test Runner Started
Test Suite Sorted
Test Runner Execution Started (2 tests)
Test Suite Started (PHPUnit\TestFixture\Event\DataProviderExternalTest, 2 tests)
-Test Suite Started (PHPUnit\TestFixture\Event\DataProviderExternalTest::testSuccess, 2 tests)
+Test Suite for Test Method with Data Provider Started (PHPUnit\TestFixture\Event\DataProviderExternalTest::testSuccess, 2 data sets)
Test Preparation Started (PHPUnit\TestFixture\Event\DataProviderExternalTest::testSuccess#0)
Test Prepared (PHPUnit\TestFixture\Event\DataProviderExternalTest::testSuccess#0)
Test Passed (PHPUnit\TestFixture\Event\DataProviderExternalTest::testSuccess#0)
@@ -34,7 +34,7 @@ Test Preparation Started (PHPUnit\TestFixture\Event\DataProviderExternalTest::te
Test Prepared (PHPUnit\TestFixture\Event\DataProviderExternalTest::testSuccess#1)
Test Passed (PHPUnit\TestFixture\Event\DataProviderExternalTest::testSuccess#1)
Test Finished (PHPUnit\TestFixture\Event\DataProviderExternalTest::testSuccess#1)
-Test Suite Finished (PHPUnit\TestFixture\Event\DataProviderExternalTest::testSuccess, 2 tests)
+Test Suite for Test Method with Data Provider Finished (PHPUnit\TestFixture\Event\DataProviderExternalTest::testSuccess, 2 data sets)
Test Suite Finished (PHPUnit\TestFixture\Event\DataProviderExternalTest, 2 tests)
Test Runner Execution Finished
Test Runner Finished
diff --git a/tests/end-to-end/event/data-provider-in-parent-class.phpt b/tests/end-to-end/event/data-provider-in-parent-class.phpt
index 9a96a36329c..b03a20e5bc3 100644
--- a/tests/end-to-end/event/data-provider-in-parent-class.phpt
+++ b/tests/end-to-end/event/data-provider-in-parent-class.phpt
@@ -22,12 +22,12 @@ Test Runner Started
Test Suite Sorted
Test Runner Execution Started (1 test)
Test Suite Started (PHPUnit\TestFixture\Event\DataProviderInParentTest, 1 test)
-Test Suite Started (PHPUnit\TestFixture\Event\DataProviderInParentTest::testSomething, 1 test)
+Test Suite for Test Method with Data Provider Started (PHPUnit\TestFixture\Event\DataProviderInParentTest::testSomething, 1 data set)
Test Preparation Started (PHPUnit\TestFixture\Event\DataProviderInParentTest::testSomething#0)
Test Prepared (PHPUnit\TestFixture\Event\DataProviderInParentTest::testSomething#0)
Test Passed (PHPUnit\TestFixture\Event\DataProviderInParentTest::testSomething#0)
Test Finished (PHPUnit\TestFixture\Event\DataProviderInParentTest::testSomething#0)
-Test Suite Finished (PHPUnit\TestFixture\Event\DataProviderInParentTest::testSomething, 1 test)
+Test Suite for Test Method with Data Provider Finished (PHPUnit\TestFixture\Event\DataProviderInParentTest::testSomething, 1 data set)
Test Suite Finished (PHPUnit\TestFixture\Event\DataProviderInParentTest, 1 test)
Test Runner Execution Finished
Test Runner Finished
diff --git a/tests/end-to-end/event/data-provider-invalid-argument-name.phpt b/tests/end-to-end/event/data-provider-invalid-argument-name.phpt
index d5b8b946f5b..1d61749ae98 100644
--- a/tests/end-to-end/event/data-provider-invalid-argument-name.phpt
+++ b/tests/end-to-end/event/data-provider-invalid-argument-name.phpt
@@ -22,7 +22,7 @@ Test Runner Started
Test Suite Sorted
Test Runner Execution Started (2 tests)
Test Suite Started (PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest, 2 tests)
-Test Suite Started (PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest::testSuccess, 2 tests)
+Test Suite for Test Method with Data Provider Started (PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest::testSuccess, 2 data sets)
Test Preparation Started (PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest::testSuccess#0)
Test Prepared (PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest::testSuccess#0)
Test Passed (PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest::testSuccess#0)
@@ -32,7 +32,7 @@ Test Prepared (PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest::t
Test Errored (PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest::testSuccess#1)
Unknown named parameter $value3
Test Finished (PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest::testSuccess#1)
-Test Suite Finished (PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest::testSuccess, 2 tests)
+Test Suite for Test Method with Data Provider Finished (PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest::testSuccess, 2 data sets)
Test Suite Finished (PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest, 2 tests)
Test Runner Execution Finished
Test Runner Finished
diff --git a/tests/end-to-end/event/data-provider.phpt b/tests/end-to-end/event/data-provider.phpt
index f50444ec77a..3188caf5abe 100644
--- a/tests/end-to-end/event/data-provider.phpt
+++ b/tests/end-to-end/event/data-provider.phpt
@@ -22,7 +22,7 @@ Test Runner Started
Test Suite Sorted
Test Runner Execution Started (2 tests)
Test Suite Started (PHPUnit\TestFixture\Event\DataProviderTest, 2 tests)
-Test Suite Started (PHPUnit\TestFixture\Event\DataProviderTest::testSuccess, 2 tests)
+Test Suite for Test Method with Data Provider Started (PHPUnit\TestFixture\Event\DataProviderTest::testSuccess, 2 data sets)
Test Preparation Started (PHPUnit\TestFixture\Event\DataProviderTest::testSuccess#0)
Test Prepared (PHPUnit\TestFixture\Event\DataProviderTest::testSuccess#0)
Test Passed (PHPUnit\TestFixture\Event\DataProviderTest::testSuccess#0)
@@ -31,7 +31,7 @@ Test Preparation Started (PHPUnit\TestFixture\Event\DataProviderTest::testSucces
Test Prepared (PHPUnit\TestFixture\Event\DataProviderTest::testSuccess#1)
Test Passed (PHPUnit\TestFixture\Event\DataProviderTest::testSuccess#1)
Test Finished (PHPUnit\TestFixture\Event\DataProviderTest::testSuccess#1)
-Test Suite Finished (PHPUnit\TestFixture\Event\DataProviderTest::testSuccess, 2 tests)
+Test Suite for Test Method with Data Provider Finished (PHPUnit\TestFixture\Event\DataProviderTest::testSuccess, 2 data sets)
Test Suite Finished (PHPUnit\TestFixture\Event\DataProviderTest, 2 tests)
Test Runner Execution Finished
Test Runner Finished
diff --git a/tests/end-to-end/event/testwith-attribute-too-many-values.phpt b/tests/end-to-end/event/testwith-attribute-too-many-values.phpt
index 6255dd60b25..2917bc2d930 100644
--- a/tests/end-to-end/event/testwith-attribute-too-many-values.phpt
+++ b/tests/end-to-end/event/testwith-attribute-too-many-values.phpt
@@ -21,12 +21,12 @@ Test Runner Started
Test Suite Sorted
Test Runner Execution Started (1 test)
Test Suite Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTooManyValuesTest, 1 test)
-Test Suite Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTooManyValuesTest::testOne, 1 test)
+Test Suite for Test Method with Data Provider Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTooManyValuesTest::testOne, 1 data set)
Test Preparation Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTooManyValuesTest::testOne#0)
Test Prepared (PHPUnit\TestFixture\Metadata\Attribute\TestWithTooManyValuesTest::testOne#0)
Test Passed (PHPUnit\TestFixture\Metadata\Attribute\TestWithTooManyValuesTest::testOne#0)
Test Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTooManyValuesTest::testOne#0)
-Test Suite Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTooManyValuesTest::testOne, 1 test)
+Test Suite for Test Method with Data Provider Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTooManyValuesTest::testOne, 1 data set)
Test Suite Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTooManyValuesTest, 1 test)
Test Runner Execution Finished
Test Runner Finished
diff --git a/tests/end-to-end/event/testwith-attribute.phpt b/tests/end-to-end/event/testwith-attribute.phpt
index d5761afdc7c..ee394d93446 100644
--- a/tests/end-to-end/event/testwith-attribute.phpt
+++ b/tests/end-to-end/event/testwith-attribute.phpt
@@ -19,30 +19,30 @@ Test Runner Started
Test Suite Sorted
Test Runner Execution Started (4 tests)
Test Suite Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest, 4 tests)
-Test Suite Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOne, 1 test)
+Test Suite for Test Method with Data Provider Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOne, 1 data set)
Test Preparation Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOne#0)
Test Prepared (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOne#0)
Test Passed (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOne#0)
Test Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOne#0)
-Test Suite Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOne, 1 test)
-Test Suite Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOneWithName, 1 test)
+Test Suite for Test Method with Data Provider Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOne, 1 data set)
+Test Suite for Test Method with Data Provider Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOneWithName, 1 data set)
Test Preparation Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOneWithName#Name1)
Test Prepared (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOneWithName#Name1)
Test Passed (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOneWithName#Name1)
Test Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOneWithName#Name1)
-Test Suite Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOneWithName, 1 test)
-Test Suite Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwo, 1 test)
+Test Suite for Test Method with Data Provider Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOneWithName, 1 data set)
+Test Suite for Test Method with Data Provider Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwo, 1 data set)
Test Preparation Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwo#0)
Test Prepared (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwo#0)
Test Passed (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwo#0)
Test Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwo#0)
-Test Suite Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwo, 1 test)
-Test Suite Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwoWithName, 1 test)
+Test Suite for Test Method with Data Provider Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwo, 1 data set)
+Test Suite for Test Method with Data Provider Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwoWithName, 1 data set)
Test Preparation Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwoWithName#Name2)
Test Prepared (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwoWithName#Name2)
Test Passed (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwoWithName#Name2)
Test Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwoWithName#Name2)
-Test Suite Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwoWithName, 1 test)
+Test Suite for Test Method with Data Provider Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwoWithName, 1 data set)
Test Suite Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest, 4 tests)
Test Runner Execution Finished
Test Runner Finished
diff --git a/tests/end-to-end/regression/4975.phpt b/tests/end-to-end/regression/4975.phpt
index aa898dd2499..1cc05f6444a 100644
--- a/tests/end-to-end/regression/4975.phpt
+++ b/tests/end-to-end/regression/4975.phpt
@@ -24,12 +24,12 @@ Test Suite Sorted
Test Suite Filtered (1 test)
Test Runner Execution Started (1 test)
Test Suite Started (PHPUnit\TestFixture\Issue4975Test, 1 test)
-Test Suite Started (PHPUnit\TestFixture\Issue4975Test::testSomething, 1 test)
+Test Suite for Test Method with Data Provider Started (PHPUnit\TestFixture\Issue4975Test::testSomething, 1 data set)
Test Preparation Started (PHPUnit\TestFixture\Issue4975Test::testSomething##2 second)
Test Prepared (PHPUnit\TestFixture\Issue4975Test::testSomething##2 second)
Test Passed (PHPUnit\TestFixture\Issue4975Test::testSomething##2 second)
Test Finished (PHPUnit\TestFixture\Issue4975Test::testSomething##2 second)
-Test Suite Finished (PHPUnit\TestFixture\Issue4975Test::testSomething, 1 test)
+Test Suite for Test Method with Data Provider Finished (PHPUnit\TestFixture\Issue4975Test::testSomething, 1 data set)
Test Suite Finished (PHPUnit\TestFixture\Issue4975Test, 1 test)
Test Runner Execution Finished
Test Runner Finished
diff --git a/tests/end-to-end/regression/5287.phpt b/tests/end-to-end/regression/5287.phpt
index db0517cd433..8c9acdfbd12 100644
--- a/tests/end-to-end/regression/5287.phpt
+++ b/tests/end-to-end/regression/5287.phpt
@@ -26,12 +26,12 @@ Test Suite Sorted
Test Runner Execution Started (3 tests)
Test Suite Started (CLI Arguments, 3 tests)
Test Suite Started (PHPUnit\TestFixture\Issue5278\A\AnotherClassTest, 1 test)
-Test Suite Started (PHPUnit\TestFixture\Issue5278\A\AnotherClassTest::test, 1 test)
+Test Suite for Test Method with Data Provider Started (PHPUnit\TestFixture\Issue5278\A\AnotherClassTest::test, 1 data set)
Test Preparation Started (PHPUnit\TestFixture\Issue5278\A\AnotherClassTest::test#0)
Test Prepared (PHPUnit\TestFixture\Issue5278\A\AnotherClassTest::test#0)
Test Passed (PHPUnit\TestFixture\Issue5278\A\AnotherClassTest::test#0)
Test Finished (PHPUnit\TestFixture\Issue5278\A\AnotherClassTest::test#0)
-Test Suite Finished (PHPUnit\TestFixture\Issue5278\A\AnotherClassTest::test, 1 test)
+Test Suite for Test Method with Data Provider Finished (PHPUnit\TestFixture\Issue5278\A\AnotherClassTest::test, 1 data set)
Test Suite Finished (PHPUnit\TestFixture\Issue5278\A\AnotherClassTest, 1 test)
Test Suite Started (PHPUnit\TestFixture\Issue5278\B\MyClassTest, 1 test)
Test Preparation Started (PHPUnit\TestFixture\Issue5278\B\MyClassTest::test)
diff --git a/tests/end-to-end/repeat/_files/DataProviderTest.php b/tests/end-to-end/repeat/_files/DataProviderTest.php
new file mode 100644
index 00000000000..39d0b696320
--- /dev/null
+++ b/tests/end-to-end/repeat/_files/DataProviderTest.php
@@ -0,0 +1,30 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TestFixture\Repeat;
+
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\TestCase;
+
+final class DataProviderTest extends TestCase
+{
+ public static function provider(): array
+ {
+ return [
+ 'one' => [1],
+ 'two' => [2],
+ ];
+ }
+
+ #[DataProvider('provider')]
+ public function testWithDataProvider(int $value): void
+ {
+ $this->assertGreaterThan(0, $value);
+ }
+}
diff --git a/tests/end-to-end/repeat/_files/DependsTest.php b/tests/end-to-end/repeat/_files/DependsTest.php
new file mode 100644
index 00000000000..1ac752726ce
--- /dev/null
+++ b/tests/end-to-end/repeat/_files/DependsTest.php
@@ -0,0 +1,27 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TestFixture\Repeat;
+
+use PHPUnit\Framework\Attributes\Depends;
+use PHPUnit\Framework\TestCase;
+
+final class DependsTest extends TestCase
+{
+ public function testOne(): void
+ {
+ $this->assertTrue(true);
+ }
+
+ #[Depends('testOne')]
+ public function testTwo(): void
+ {
+ $this->assertTrue(true);
+ }
+}
diff --git a/tests/end-to-end/repeat/_files/FailureOnSecondRepetitionTest.php b/tests/end-to-end/repeat/_files/FailureOnSecondRepetitionTest.php
new file mode 100644
index 00000000000..a842627a970
--- /dev/null
+++ b/tests/end-to-end/repeat/_files/FailureOnSecondRepetitionTest.php
@@ -0,0 +1,28 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TestFixture\Repeat;
+
+use PHPUnit\Framework\TestCase;
+
+final class FailureOnSecondRepetitionTest extends TestCase
+{
+ private static int $count = 0;
+
+ public function testOne(): void
+ {
+ self::$count++;
+
+ if (self::$count === 2) {
+ $this->fail('Failure on second repetition');
+ }
+
+ $this->assertTrue(true);
+ }
+}
diff --git a/tests/end-to-end/repeat/_files/NoReturnTypeTest.php b/tests/end-to-end/repeat/_files/NoReturnTypeTest.php
new file mode 100644
index 00000000000..ec589dbb619
--- /dev/null
+++ b/tests/end-to-end/repeat/_files/NoReturnTypeTest.php
@@ -0,0 +1,26 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TestFixture\Repeat;
+
+use PHPUnit\Framework\TestCase;
+
+final class NoReturnTypeTest extends TestCase
+{
+ /** @phpstan-ignore missingType.return */
+ public function testWithoutReturnType()
+ {
+ $this->assertTrue(true);
+ }
+
+ public function testWithVoidReturn(): void
+ {
+ $this->assertTrue(true);
+ }
+}
diff --git a/tests/end-to-end/repeat/_files/NonVoidReturnTest.php b/tests/end-to-end/repeat/_files/NonVoidReturnTest.php
new file mode 100644
index 00000000000..7568bbcdf7b
--- /dev/null
+++ b/tests/end-to-end/repeat/_files/NonVoidReturnTest.php
@@ -0,0 +1,27 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TestFixture\Repeat;
+
+use PHPUnit\Framework\TestCase;
+
+final class NonVoidReturnTest extends TestCase
+{
+ public function testWithReturnValue(): int
+ {
+ $this->assertTrue(true);
+
+ return 1;
+ }
+
+ public function testWithVoidReturn(): void
+ {
+ $this->assertTrue(true);
+ }
+}
diff --git a/tests/end-to-end/repeat/_files/RepeatAttributeOnDependentTest.php b/tests/end-to-end/repeat/_files/RepeatAttributeOnDependentTest.php
new file mode 100644
index 00000000000..1cbf1fbbb31
--- /dev/null
+++ b/tests/end-to-end/repeat/_files/RepeatAttributeOnDependentTest.php
@@ -0,0 +1,29 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TestFixture\Repeat;
+
+use PHPUnit\Framework\Attributes\Depends;
+use PHPUnit\Framework\Attributes\Repeat;
+use PHPUnit\Framework\TestCase;
+
+final class RepeatAttributeOnDependentTest extends TestCase
+{
+ public function testOne(): void
+ {
+ $this->assertTrue(true);
+ }
+
+ #[Depends('testOne')]
+ #[Repeat(3)]
+ public function testTwo(): void
+ {
+ $this->assertTrue(true);
+ }
+}
diff --git a/tests/end-to-end/repeat/_files/RepeatAttributeOnNonVoidReturnTest.php b/tests/end-to-end/repeat/_files/RepeatAttributeOnNonVoidReturnTest.php
new file mode 100644
index 00000000000..d5b307e4f83
--- /dev/null
+++ b/tests/end-to-end/repeat/_files/RepeatAttributeOnNonVoidReturnTest.php
@@ -0,0 +1,24 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TestFixture\Repeat;
+
+use PHPUnit\Framework\Attributes\Repeat;
+use PHPUnit\Framework\TestCase;
+
+final class RepeatAttributeOnNonVoidReturnTest extends TestCase
+{
+ #[Repeat(3)]
+ public function testWithReturnValue(): int
+ {
+ $this->assertTrue(true);
+
+ return 1;
+ }
+}
diff --git a/tests/end-to-end/repeat/_files/RepeatAttributeOverrideTest.php b/tests/end-to-end/repeat/_files/RepeatAttributeOverrideTest.php
new file mode 100644
index 00000000000..167d1d88d47
--- /dev/null
+++ b/tests/end-to-end/repeat/_files/RepeatAttributeOverrideTest.php
@@ -0,0 +1,22 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TestFixture\Repeat;
+
+use PHPUnit\Framework\Attributes\Repeat;
+use PHPUnit\Framework\TestCase;
+
+final class RepeatAttributeOverrideTest extends TestCase
+{
+ #[Repeat(2)]
+ public function testAttributeOverridesCliRepeat(): void
+ {
+ $this->assertTrue(true);
+ }
+}
diff --git a/tests/end-to-end/repeat/_files/RepeatAttributeTest.php b/tests/end-to-end/repeat/_files/RepeatAttributeTest.php
new file mode 100644
index 00000000000..d4243286330
--- /dev/null
+++ b/tests/end-to-end/repeat/_files/RepeatAttributeTest.php
@@ -0,0 +1,27 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TestFixture\Repeat;
+
+use PHPUnit\Framework\Attributes\Repeat;
+use PHPUnit\Framework\TestCase;
+
+final class RepeatAttributeTest extends TestCase
+{
+ #[Repeat(3)]
+ public function testRepeatedThreeTimes(): void
+ {
+ $this->assertTrue(true);
+ }
+
+ public function testNotRepeated(): void
+ {
+ $this->assertTrue(true);
+ }
+}
diff --git a/tests/end-to-end/repeat/_files/RepeatAttributeWithoutReturnTypeTest.php b/tests/end-to-end/repeat/_files/RepeatAttributeWithoutReturnTypeTest.php
new file mode 100644
index 00000000000..e2b425dde2a
--- /dev/null
+++ b/tests/end-to-end/repeat/_files/RepeatAttributeWithoutReturnTypeTest.php
@@ -0,0 +1,22 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TestFixture\Repeat;
+
+use PHPUnit\Framework\Attributes\Repeat;
+use PHPUnit\Framework\TestCase;
+
+final class RepeatAttributeWithoutReturnTypeTest extends TestCase
+{
+ #[Repeat(3)]
+ public function testWithoutReturnType()
+ {
+ $this->assertTrue(true);
+ }
+}
diff --git a/tests/end-to-end/repeat/_files/SuccessTest.php b/tests/end-to-end/repeat/_files/SuccessTest.php
new file mode 100644
index 00000000000..413c3acd975
--- /dev/null
+++ b/tests/end-to-end/repeat/_files/SuccessTest.php
@@ -0,0 +1,25 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TestFixture\Repeat;
+
+use PHPUnit\Framework\TestCase;
+
+final class SuccessTest extends TestCase
+{
+ public function testOne(): void
+ {
+ $this->assertTrue(true);
+ }
+
+ public function testTwo(): void
+ {
+ $this->assertTrue(true);
+ }
+}
diff --git a/tests/end-to-end/repeat/_files/UnionReturnTypeTest.php b/tests/end-to-end/repeat/_files/UnionReturnTypeTest.php
new file mode 100644
index 00000000000..864f4d6890d
--- /dev/null
+++ b/tests/end-to-end/repeat/_files/UnionReturnTypeTest.php
@@ -0,0 +1,27 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TestFixture\Repeat;
+
+use PHPUnit\Framework\TestCase;
+
+final class UnionReturnTypeTest extends TestCase
+{
+ public function testWithUnionReturnType(): int|string
+ {
+ $this->assertTrue(true);
+
+ return 1;
+ }
+
+ public function testWithVoidReturn(): void
+ {
+ $this->assertTrue(true);
+ }
+}
diff --git a/tests/end-to-end/repeat/repeat-attribute-overrides-cli.phpt b/tests/end-to-end/repeat/repeat-attribute-overrides-cli.phpt
new file mode 100644
index 00000000000..d68dc0ea77b
--- /dev/null
+++ b/tests/end-to-end/repeat/repeat-attribute-overrides-cli.phpt
@@ -0,0 +1,37 @@
+--TEST--
+#[Repeat] attribute takes precedence over --repeat CLI option
+--FILE--
+run($_SERVER['argv']);
+--EXPECTF--
+PHPUnit Started (PHPUnit %s using %s)
+Test Runner Configured
+Event Facade Sealed
+Test Suite Loaded (2 tests)
+Test Runner Started
+Test Suite Sorted
+Test Runner Execution Started (2 tests)
+Test Suite Started (PHPUnit\TestFixture\Repeat\RepeatAttributeOverrideTest, 2 tests)
+Test Suite for Repeated Test Method Started (PHPUnit\TestFixture\Repeat\RepeatAttributeOverrideTest::testAttributeOverridesCliRepeat, 2 repetitions)
+Test Preparation Started (PHPUnit\TestFixture\Repeat\RepeatAttributeOverrideTest::testAttributeOverridesCliRepeat (repetition 1 of 2))
+Test Prepared (PHPUnit\TestFixture\Repeat\RepeatAttributeOverrideTest::testAttributeOverridesCliRepeat (repetition 1 of 2))
+Test Passed (PHPUnit\TestFixture\Repeat\RepeatAttributeOverrideTest::testAttributeOverridesCliRepeat (repetition 1 of 2))
+Test Finished (PHPUnit\TestFixture\Repeat\RepeatAttributeOverrideTest::testAttributeOverridesCliRepeat (repetition 1 of 2))
+Test Preparation Started (PHPUnit\TestFixture\Repeat\RepeatAttributeOverrideTest::testAttributeOverridesCliRepeat (repetition 2 of 2))
+Test Prepared (PHPUnit\TestFixture\Repeat\RepeatAttributeOverrideTest::testAttributeOverridesCliRepeat (repetition 2 of 2))
+Test Passed (PHPUnit\TestFixture\Repeat\RepeatAttributeOverrideTest::testAttributeOverridesCliRepeat (repetition 2 of 2))
+Test Finished (PHPUnit\TestFixture\Repeat\RepeatAttributeOverrideTest::testAttributeOverridesCliRepeat (repetition 2 of 2))
+Test Suite for Repeated Test Method Finished (PHPUnit\TestFixture\Repeat\RepeatAttributeOverrideTest::testAttributeOverridesCliRepeat, 2 repetitions)
+Test Suite Finished (PHPUnit\TestFixture\Repeat\RepeatAttributeOverrideTest, 2 tests)
+Test Runner Execution Finished
+Test Runner Finished
+PHPUnit Finished (Shell Exit Code: 0)
diff --git a/tests/end-to-end/repeat/repeat-attribute-warning-depends.phpt b/tests/end-to-end/repeat/repeat-attribute-warning-depends.phpt
new file mode 100644
index 00000000000..c9421bd013e
--- /dev/null
+++ b/tests/end-to-end/repeat/repeat-attribute-warning-depends.phpt
@@ -0,0 +1,34 @@
+--TEST--
+#[Repeat] on method that depends on another test triggers a test runner warning
+--FILE--
+run($_SERVER['argv']);
+--EXPECTF--
+PHPUnit Started (PHPUnit %s using %s)
+Test Runner Configured
+Event Facade Sealed
+Test Runner Triggered PHPUnit Warning (Method PHPUnit\TestFixture\Repeat\RepeatAttributeOnDependentTest::testTwo is annotated with #[Repeat] but depends on another test and will not be repeated)
+Test Suite Loaded (2 tests)
+Test Runner Started
+Test Suite Sorted
+Test Runner Execution Started (2 tests)
+Test Suite Started (PHPUnit\TestFixture\Repeat\RepeatAttributeOnDependentTest, 2 tests)
+Test Preparation Started (PHPUnit\TestFixture\Repeat\RepeatAttributeOnDependentTest::testOne)
+Test Prepared (PHPUnit\TestFixture\Repeat\RepeatAttributeOnDependentTest::testOne)
+Test Passed (PHPUnit\TestFixture\Repeat\RepeatAttributeOnDependentTest::testOne)
+Test Finished (PHPUnit\TestFixture\Repeat\RepeatAttributeOnDependentTest::testOne)
+Test Preparation Started (PHPUnit\TestFixture\Repeat\RepeatAttributeOnDependentTest::testTwo)
+Test Prepared (PHPUnit\TestFixture\Repeat\RepeatAttributeOnDependentTest::testTwo)
+Test Passed (PHPUnit\TestFixture\Repeat\RepeatAttributeOnDependentTest::testTwo)
+Test Finished (PHPUnit\TestFixture\Repeat\RepeatAttributeOnDependentTest::testTwo)
+Test Suite Finished (PHPUnit\TestFixture\Repeat\RepeatAttributeOnDependentTest, 2 tests)
+Test Runner Execution Finished
+Test Runner Finished
+PHPUnit Finished (Shell Exit Code: 1)
diff --git a/tests/end-to-end/repeat/repeat-attribute-warning-no-return-type.phpt b/tests/end-to-end/repeat/repeat-attribute-warning-no-return-type.phpt
new file mode 100644
index 00000000000..850bd50cc3c
--- /dev/null
+++ b/tests/end-to-end/repeat/repeat-attribute-warning-no-return-type.phpt
@@ -0,0 +1,30 @@
+--TEST--
+#[Repeat] on method without return type declaration triggers a test runner warning
+--FILE--
+run($_SERVER['argv']);
+--EXPECTF--
+PHPUnit Started (PHPUnit %s using %s)
+Test Runner Configured
+Event Facade Sealed
+Test Runner Triggered PHPUnit Warning (Method PHPUnit\TestFixture\Repeat\RepeatAttributeWithoutReturnTypeTest::testWithoutReturnType is annotated with #[Repeat] but does not have a void return type declaration and will not be repeated)
+Test Suite Loaded (1 test)
+Test Runner Started
+Test Suite Sorted
+Test Runner Execution Started (1 test)
+Test Suite Started (PHPUnit\TestFixture\Repeat\RepeatAttributeWithoutReturnTypeTest, 1 test)
+Test Preparation Started (PHPUnit\TestFixture\Repeat\RepeatAttributeWithoutReturnTypeTest::testWithoutReturnType)
+Test Prepared (PHPUnit\TestFixture\Repeat\RepeatAttributeWithoutReturnTypeTest::testWithoutReturnType)
+Test Passed (PHPUnit\TestFixture\Repeat\RepeatAttributeWithoutReturnTypeTest::testWithoutReturnType)
+Test Finished (PHPUnit\TestFixture\Repeat\RepeatAttributeWithoutReturnTypeTest::testWithoutReturnType)
+Test Suite Finished (PHPUnit\TestFixture\Repeat\RepeatAttributeWithoutReturnTypeTest, 1 test)
+Test Runner Execution Finished
+Test Runner Finished
+PHPUnit Finished (Shell Exit Code: 1)
diff --git a/tests/end-to-end/repeat/repeat-attribute-warning-non-void-return.phpt b/tests/end-to-end/repeat/repeat-attribute-warning-non-void-return.phpt
new file mode 100644
index 00000000000..704fb754a0b
--- /dev/null
+++ b/tests/end-to-end/repeat/repeat-attribute-warning-non-void-return.phpt
@@ -0,0 +1,30 @@
+--TEST--
+#[Repeat] on method with non-void return type triggers a test runner warning
+--FILE--
+run($_SERVER['argv']);
+--EXPECTF--
+PHPUnit Started (PHPUnit %s using %s)
+Test Runner Configured
+Event Facade Sealed
+Test Runner Triggered PHPUnit Warning (Method PHPUnit\TestFixture\Repeat\RepeatAttributeOnNonVoidReturnTest::testWithReturnValue is annotated with #[Repeat] but does not have a void return type declaration and will not be repeated)
+Test Suite Loaded (1 test)
+Test Runner Started
+Test Suite Sorted
+Test Runner Execution Started (1 test)
+Test Suite Started (PHPUnit\TestFixture\Repeat\RepeatAttributeOnNonVoidReturnTest, 1 test)
+Test Preparation Started (PHPUnit\TestFixture\Repeat\RepeatAttributeOnNonVoidReturnTest::testWithReturnValue)
+Test Prepared (PHPUnit\TestFixture\Repeat\RepeatAttributeOnNonVoidReturnTest::testWithReturnValue)
+Test Passed (PHPUnit\TestFixture\Repeat\RepeatAttributeOnNonVoidReturnTest::testWithReturnValue)
+Test Finished (PHPUnit\TestFixture\Repeat\RepeatAttributeOnNonVoidReturnTest::testWithReturnValue)
+Test Suite Finished (PHPUnit\TestFixture\Repeat\RepeatAttributeOnNonVoidReturnTest, 1 test)
+Test Runner Execution Finished
+Test Runner Finished
+PHPUnit Finished (Shell Exit Code: 1)
diff --git a/tests/end-to-end/repeat/repeat-attribute.phpt b/tests/end-to-end/repeat/repeat-attribute.phpt
new file mode 100644
index 00000000000..fe75c4472a0
--- /dev/null
+++ b/tests/end-to-end/repeat/repeat-attribute.phpt
@@ -0,0 +1,43 @@
+--TEST--
+#[Repeat] attribute repeats individual test method
+--FILE--
+run($_SERVER['argv']);
+--EXPECTF--
+PHPUnit Started (PHPUnit %s using %s)
+Test Runner Configured
+Event Facade Sealed
+Test Suite Loaded (4 tests)
+Test Runner Started
+Test Suite Sorted
+Test Runner Execution Started (4 tests)
+Test Suite Started (PHPUnit\TestFixture\Repeat\RepeatAttributeTest, 4 tests)
+Test Suite for Repeated Test Method Started (PHPUnit\TestFixture\Repeat\RepeatAttributeTest::testRepeatedThreeTimes, 3 repetitions)
+Test Preparation Started (PHPUnit\TestFixture\Repeat\RepeatAttributeTest::testRepeatedThreeTimes (repetition 1 of 3))
+Test Prepared (PHPUnit\TestFixture\Repeat\RepeatAttributeTest::testRepeatedThreeTimes (repetition 1 of 3))
+Test Passed (PHPUnit\TestFixture\Repeat\RepeatAttributeTest::testRepeatedThreeTimes (repetition 1 of 3))
+Test Finished (PHPUnit\TestFixture\Repeat\RepeatAttributeTest::testRepeatedThreeTimes (repetition 1 of 3))
+Test Preparation Started (PHPUnit\TestFixture\Repeat\RepeatAttributeTest::testRepeatedThreeTimes (repetition 2 of 3))
+Test Prepared (PHPUnit\TestFixture\Repeat\RepeatAttributeTest::testRepeatedThreeTimes (repetition 2 of 3))
+Test Passed (PHPUnit\TestFixture\Repeat\RepeatAttributeTest::testRepeatedThreeTimes (repetition 2 of 3))
+Test Finished (PHPUnit\TestFixture\Repeat\RepeatAttributeTest::testRepeatedThreeTimes (repetition 2 of 3))
+Test Preparation Started (PHPUnit\TestFixture\Repeat\RepeatAttributeTest::testRepeatedThreeTimes (repetition 3 of 3))
+Test Prepared (PHPUnit\TestFixture\Repeat\RepeatAttributeTest::testRepeatedThreeTimes (repetition 3 of 3))
+Test Passed (PHPUnit\TestFixture\Repeat\RepeatAttributeTest::testRepeatedThreeTimes (repetition 3 of 3))
+Test Finished (PHPUnit\TestFixture\Repeat\RepeatAttributeTest::testRepeatedThreeTimes (repetition 3 of 3))
+Test Suite for Repeated Test Method Finished (PHPUnit\TestFixture\Repeat\RepeatAttributeTest::testRepeatedThreeTimes, 3 repetitions)
+Test Preparation Started (PHPUnit\TestFixture\Repeat\RepeatAttributeTest::testNotRepeated)
+Test Prepared (PHPUnit\TestFixture\Repeat\RepeatAttributeTest::testNotRepeated)
+Test Passed (PHPUnit\TestFixture\Repeat\RepeatAttributeTest::testNotRepeated)
+Test Finished (PHPUnit\TestFixture\Repeat\RepeatAttributeTest::testNotRepeated)
+Test Suite Finished (PHPUnit\TestFixture\Repeat\RepeatAttributeTest, 4 tests)
+Test Runner Execution Finished
+Test Runner Finished
+PHPUnit Finished (Shell Exit Code: 0)
diff --git a/tests/end-to-end/repeat/repeat-failure-stops-repetitions.phpt b/tests/end-to-end/repeat/repeat-failure-stops-repetitions.phpt
new file mode 100644
index 00000000000..2ea390050af
--- /dev/null
+++ b/tests/end-to-end/repeat/repeat-failure-stops-repetitions.phpt
@@ -0,0 +1,40 @@
+--TEST--
+--repeat stops remaining repetitions after failure
+--FILE--
+run($_SERVER['argv']);
+--EXPECTF--
+PHPUnit Started (PHPUnit %s using %s)
+Test Runner Configured
+Event Facade Sealed
+Test Suite Loaded (3 tests)
+Test Runner Started
+Test Suite Sorted
+Test Runner Execution Started (3 tests)
+Test Suite Started (PHPUnit\TestFixture\Repeat\FailureOnSecondRepetitionTest, 3 tests)
+Test Suite for Repeated Test Method Started (PHPUnit\TestFixture\Repeat\FailureOnSecondRepetitionTest::testOne, 3 repetitions)
+Test Preparation Started (PHPUnit\TestFixture\Repeat\FailureOnSecondRepetitionTest::testOne (repetition 1 of 3))
+Test Prepared (PHPUnit\TestFixture\Repeat\FailureOnSecondRepetitionTest::testOne (repetition 1 of 3))
+Test Passed (PHPUnit\TestFixture\Repeat\FailureOnSecondRepetitionTest::testOne (repetition 1 of 3))
+Test Finished (PHPUnit\TestFixture\Repeat\FailureOnSecondRepetitionTest::testOne (repetition 1 of 3))
+Test Preparation Started (PHPUnit\TestFixture\Repeat\FailureOnSecondRepetitionTest::testOne (repetition 2 of 3))
+Test Prepared (PHPUnit\TestFixture\Repeat\FailureOnSecondRepetitionTest::testOne (repetition 2 of 3))
+Test Failed (PHPUnit\TestFixture\Repeat\FailureOnSecondRepetitionTest::testOne (repetition 2 of 3))
+Failure on second repetition
+Test Finished (PHPUnit\TestFixture\Repeat\FailureOnSecondRepetitionTest::testOne (repetition 2 of 3))
+Test Skipped (PHPUnit\TestFixture\Repeat\FailureOnSecondRepetitionTest::testOne (repetition 3 of 3))
+Remaining repetition skipped after failure in repetition 2
+Test Suite for Repeated Test Method Finished (PHPUnit\TestFixture\Repeat\FailureOnSecondRepetitionTest::testOne, 3 repetitions)
+Test Suite Finished (PHPUnit\TestFixture\Repeat\FailureOnSecondRepetitionTest, 3 tests)
+Test Runner Execution Finished
+Test Runner Finished
+PHPUnit Finished (Shell Exit Code: 1)
diff --git a/tests/end-to-end/repeat/repeat-invalid-value.phpt b/tests/end-to-end/repeat/repeat-invalid-value.phpt
new file mode 100644
index 00000000000..903aae72385
--- /dev/null
+++ b/tests/end-to-end/repeat/repeat-invalid-value.phpt
@@ -0,0 +1,36 @@
+--TEST--
+--repeat with invalid value triggers warning
+--FILE--
+run($_SERVER['argv']);
+--EXPECTF--
+PHPUnit Started (PHPUnit %s using %s)
+Test Runner Triggered PHPUnit Warning (Option "--repeat 0" ignored because "0" is not a positive integer)
+Test Runner Configured
+Event Facade Sealed
+Test Suite Loaded (2 tests)
+Test Runner Started
+Test Suite Sorted
+Test Runner Execution Started (2 tests)
+Test Suite Started (PHPUnit\TestFixture\Repeat\SuccessTest, 2 tests)
+Test Preparation Started (PHPUnit\TestFixture\Repeat\SuccessTest::testOne)
+Test Prepared (PHPUnit\TestFixture\Repeat\SuccessTest::testOne)
+Test Passed (PHPUnit\TestFixture\Repeat\SuccessTest::testOne)
+Test Finished (PHPUnit\TestFixture\Repeat\SuccessTest::testOne)
+Test Preparation Started (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo)
+Test Prepared (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo)
+Test Passed (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo)
+Test Finished (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo)
+Test Suite Finished (PHPUnit\TestFixture\Repeat\SuccessTest, 2 tests)
+Test Runner Execution Finished
+Test Runner Finished
+PHPUnit Finished (Shell Exit Code: 1)
diff --git a/tests/end-to-end/repeat/repeat-junit-xml-logging.phpt b/tests/end-to-end/repeat/repeat-junit-xml-logging.phpt
new file mode 100644
index 00000000000..450a0d10499
--- /dev/null
+++ b/tests/end-to-end/repeat/repeat-junit-xml-logging.phpt
@@ -0,0 +1,44 @@
+--TEST--
+--repeat with JUnit XML logging includes repetition info in test names
+--FILE--
+run($_SERVER['argv']);
+
+print file_get_contents($junitFile);
+
+unlink($junitFile);
+--EXPECTF--
+PHPUnit %s by Sebastian Bergmann and contributors.
+
+Runtime: %s
+
+.... 4 / 4 (100%)
+
+Time: %s, Memory: %s
+
+OK (4 tests, 4 assertions)
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/end-to-end/repeat/repeat-skips-dependent-test.phpt b/tests/end-to-end/repeat/repeat-skips-dependent-test.phpt
new file mode 100644
index 00000000000..7f10476e489
--- /dev/null
+++ b/tests/end-to-end/repeat/repeat-skips-dependent-test.phpt
@@ -0,0 +1,41 @@
+--TEST--
+--repeat does not repeat test that depends on another test
+--FILE--
+run($_SERVER['argv']);
+--EXPECTF--
+PHPUnit Started (PHPUnit %s using %s)
+Test Runner Configured
+Event Facade Sealed
+Test Suite Loaded (3 tests)
+Test Runner Started
+Test Suite Sorted
+Test Runner Execution Started (3 tests)
+Test Suite Started (PHPUnit\TestFixture\Repeat\DependsTest, 3 tests)
+Test Suite for Repeated Test Method Started (PHPUnit\TestFixture\Repeat\DependsTest::testOne, 2 repetitions)
+Test Preparation Started (PHPUnit\TestFixture\Repeat\DependsTest::testOne (repetition 1 of 2))
+Test Prepared (PHPUnit\TestFixture\Repeat\DependsTest::testOne (repetition 1 of 2))
+Test Passed (PHPUnit\TestFixture\Repeat\DependsTest::testOne (repetition 1 of 2))
+Test Finished (PHPUnit\TestFixture\Repeat\DependsTest::testOne (repetition 1 of 2))
+Test Preparation Started (PHPUnit\TestFixture\Repeat\DependsTest::testOne (repetition 2 of 2))
+Test Prepared (PHPUnit\TestFixture\Repeat\DependsTest::testOne (repetition 2 of 2))
+Test Passed (PHPUnit\TestFixture\Repeat\DependsTest::testOne (repetition 2 of 2))
+Test Finished (PHPUnit\TestFixture\Repeat\DependsTest::testOne (repetition 2 of 2))
+Test Suite for Repeated Test Method Finished (PHPUnit\TestFixture\Repeat\DependsTest::testOne, 2 repetitions)
+Test Preparation Started (PHPUnit\TestFixture\Repeat\DependsTest::testTwo)
+Test Prepared (PHPUnit\TestFixture\Repeat\DependsTest::testTwo)
+Test Passed (PHPUnit\TestFixture\Repeat\DependsTest::testTwo)
+Test Finished (PHPUnit\TestFixture\Repeat\DependsTest::testTwo)
+Test Suite Finished (PHPUnit\TestFixture\Repeat\DependsTest, 3 tests)
+Test Runner Execution Finished
+Test Runner Finished
+PHPUnit Finished (Shell Exit Code: 0)
diff --git a/tests/end-to-end/repeat/repeat-skips-no-return-type.phpt b/tests/end-to-end/repeat/repeat-skips-no-return-type.phpt
new file mode 100644
index 00000000000..8676fc50ce5
--- /dev/null
+++ b/tests/end-to-end/repeat/repeat-skips-no-return-type.phpt
@@ -0,0 +1,41 @@
+--TEST--
+--repeat skips test without return type declaration
+--FILE--
+run($_SERVER['argv']);
+--EXPECTF--
+PHPUnit Started (PHPUnit %s using %s)
+Test Runner Configured
+Event Facade Sealed
+Test Suite Loaded (3 tests)
+Test Runner Started
+Test Suite Sorted
+Test Runner Execution Started (3 tests)
+Test Suite Started (PHPUnit\TestFixture\Repeat\NoReturnTypeTest, 3 tests)
+Test Preparation Started (PHPUnit\TestFixture\Repeat\NoReturnTypeTest::testWithoutReturnType)
+Test Prepared (PHPUnit\TestFixture\Repeat\NoReturnTypeTest::testWithoutReturnType)
+Test Passed (PHPUnit\TestFixture\Repeat\NoReturnTypeTest::testWithoutReturnType)
+Test Finished (PHPUnit\TestFixture\Repeat\NoReturnTypeTest::testWithoutReturnType)
+Test Suite for Repeated Test Method Started (PHPUnit\TestFixture\Repeat\NoReturnTypeTest::testWithVoidReturn, 2 repetitions)
+Test Preparation Started (PHPUnit\TestFixture\Repeat\NoReturnTypeTest::testWithVoidReturn (repetition 1 of 2))
+Test Prepared (PHPUnit\TestFixture\Repeat\NoReturnTypeTest::testWithVoidReturn (repetition 1 of 2))
+Test Passed (PHPUnit\TestFixture\Repeat\NoReturnTypeTest::testWithVoidReturn (repetition 1 of 2))
+Test Finished (PHPUnit\TestFixture\Repeat\NoReturnTypeTest::testWithVoidReturn (repetition 1 of 2))
+Test Preparation Started (PHPUnit\TestFixture\Repeat\NoReturnTypeTest::testWithVoidReturn (repetition 2 of 2))
+Test Prepared (PHPUnit\TestFixture\Repeat\NoReturnTypeTest::testWithVoidReturn (repetition 2 of 2))
+Test Passed (PHPUnit\TestFixture\Repeat\NoReturnTypeTest::testWithVoidReturn (repetition 2 of 2))
+Test Finished (PHPUnit\TestFixture\Repeat\NoReturnTypeTest::testWithVoidReturn (repetition 2 of 2))
+Test Suite for Repeated Test Method Finished (PHPUnit\TestFixture\Repeat\NoReturnTypeTest::testWithVoidReturn, 2 repetitions)
+Test Suite Finished (PHPUnit\TestFixture\Repeat\NoReturnTypeTest, 3 tests)
+Test Runner Execution Finished
+Test Runner Finished
+PHPUnit Finished (Shell Exit Code: 0)
diff --git a/tests/end-to-end/repeat/repeat-skips-non-void-return.phpt b/tests/end-to-end/repeat/repeat-skips-non-void-return.phpt
new file mode 100644
index 00000000000..33f0968191c
--- /dev/null
+++ b/tests/end-to-end/repeat/repeat-skips-non-void-return.phpt
@@ -0,0 +1,41 @@
+--TEST--
+--repeat does not repeat test with non-void return type
+--FILE--
+run($_SERVER['argv']);
+--EXPECTF--
+PHPUnit Started (PHPUnit %s using %s)
+Test Runner Configured
+Event Facade Sealed
+Test Suite Loaded (3 tests)
+Test Runner Started
+Test Suite Sorted
+Test Runner Execution Started (3 tests)
+Test Suite Started (PHPUnit\TestFixture\Repeat\NonVoidReturnTest, 3 tests)
+Test Preparation Started (PHPUnit\TestFixture\Repeat\NonVoidReturnTest::testWithReturnValue)
+Test Prepared (PHPUnit\TestFixture\Repeat\NonVoidReturnTest::testWithReturnValue)
+Test Passed (PHPUnit\TestFixture\Repeat\NonVoidReturnTest::testWithReturnValue)
+Test Finished (PHPUnit\TestFixture\Repeat\NonVoidReturnTest::testWithReturnValue)
+Test Suite for Repeated Test Method Started (PHPUnit\TestFixture\Repeat\NonVoidReturnTest::testWithVoidReturn, 2 repetitions)
+Test Preparation Started (PHPUnit\TestFixture\Repeat\NonVoidReturnTest::testWithVoidReturn (repetition 1 of 2))
+Test Prepared (PHPUnit\TestFixture\Repeat\NonVoidReturnTest::testWithVoidReturn (repetition 1 of 2))
+Test Passed (PHPUnit\TestFixture\Repeat\NonVoidReturnTest::testWithVoidReturn (repetition 1 of 2))
+Test Finished (PHPUnit\TestFixture\Repeat\NonVoidReturnTest::testWithVoidReturn (repetition 1 of 2))
+Test Preparation Started (PHPUnit\TestFixture\Repeat\NonVoidReturnTest::testWithVoidReturn (repetition 2 of 2))
+Test Prepared (PHPUnit\TestFixture\Repeat\NonVoidReturnTest::testWithVoidReturn (repetition 2 of 2))
+Test Passed (PHPUnit\TestFixture\Repeat\NonVoidReturnTest::testWithVoidReturn (repetition 2 of 2))
+Test Finished (PHPUnit\TestFixture\Repeat\NonVoidReturnTest::testWithVoidReturn (repetition 2 of 2))
+Test Suite for Repeated Test Method Finished (PHPUnit\TestFixture\Repeat\NonVoidReturnTest::testWithVoidReturn, 2 repetitions)
+Test Suite Finished (PHPUnit\TestFixture\Repeat\NonVoidReturnTest, 3 tests)
+Test Runner Execution Finished
+Test Runner Finished
+PHPUnit Finished (Shell Exit Code: 0)
diff --git a/tests/end-to-end/repeat/repeat-skips-union-return-type.phpt b/tests/end-to-end/repeat/repeat-skips-union-return-type.phpt
new file mode 100644
index 00000000000..ce25ac45039
--- /dev/null
+++ b/tests/end-to-end/repeat/repeat-skips-union-return-type.phpt
@@ -0,0 +1,41 @@
+--TEST--
+--repeat does not repeat test with union return type
+--FILE--
+run($_SERVER['argv']);
+--EXPECTF--
+PHPUnit Started (PHPUnit %s using %s)
+Test Runner Configured
+Event Facade Sealed
+Test Suite Loaded (3 tests)
+Test Runner Started
+Test Suite Sorted
+Test Runner Execution Started (3 tests)
+Test Suite Started (PHPUnit\TestFixture\Repeat\UnionReturnTypeTest, 3 tests)
+Test Preparation Started (PHPUnit\TestFixture\Repeat\UnionReturnTypeTest::testWithUnionReturnType)
+Test Prepared (PHPUnit\TestFixture\Repeat\UnionReturnTypeTest::testWithUnionReturnType)
+Test Passed (PHPUnit\TestFixture\Repeat\UnionReturnTypeTest::testWithUnionReturnType)
+Test Finished (PHPUnit\TestFixture\Repeat\UnionReturnTypeTest::testWithUnionReturnType)
+Test Suite for Repeated Test Method Started (PHPUnit\TestFixture\Repeat\UnionReturnTypeTest::testWithVoidReturn, 2 repetitions)
+Test Preparation Started (PHPUnit\TestFixture\Repeat\UnionReturnTypeTest::testWithVoidReturn (repetition 1 of 2))
+Test Prepared (PHPUnit\TestFixture\Repeat\UnionReturnTypeTest::testWithVoidReturn (repetition 1 of 2))
+Test Passed (PHPUnit\TestFixture\Repeat\UnionReturnTypeTest::testWithVoidReturn (repetition 1 of 2))
+Test Finished (PHPUnit\TestFixture\Repeat\UnionReturnTypeTest::testWithVoidReturn (repetition 1 of 2))
+Test Preparation Started (PHPUnit\TestFixture\Repeat\UnionReturnTypeTest::testWithVoidReturn (repetition 2 of 2))
+Test Prepared (PHPUnit\TestFixture\Repeat\UnionReturnTypeTest::testWithVoidReturn (repetition 2 of 2))
+Test Passed (PHPUnit\TestFixture\Repeat\UnionReturnTypeTest::testWithVoidReturn (repetition 2 of 2))
+Test Finished (PHPUnit\TestFixture\Repeat\UnionReturnTypeTest::testWithVoidReturn (repetition 2 of 2))
+Test Suite for Repeated Test Method Finished (PHPUnit\TestFixture\Repeat\UnionReturnTypeTest::testWithVoidReturn, 2 repetitions)
+Test Suite Finished (PHPUnit\TestFixture\Repeat\UnionReturnTypeTest, 3 tests)
+Test Runner Execution Finished
+Test Runner Finished
+PHPUnit Finished (Shell Exit Code: 0)
diff --git a/tests/end-to-end/repeat/repeat-success.phpt b/tests/end-to-end/repeat/repeat-success.phpt
new file mode 100644
index 00000000000..848bc11beea
--- /dev/null
+++ b/tests/end-to-end/repeat/repeat-success.phpt
@@ -0,0 +1,55 @@
+--TEST--
+--repeat with all tests passing
+--FILE--
+run($_SERVER['argv']);
+--EXPECTF--
+PHPUnit Started (PHPUnit %s using %s)
+Test Runner Configured
+Event Facade Sealed
+Test Suite Loaded (6 tests)
+Test Runner Started
+Test Suite Sorted
+Test Runner Execution Started (6 tests)
+Test Suite Started (PHPUnit\TestFixture\Repeat\SuccessTest, 6 tests)
+Test Suite for Repeated Test Method Started (PHPUnit\TestFixture\Repeat\SuccessTest::testOne, 3 repetitions)
+Test Preparation Started (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 1 of 3))
+Test Prepared (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 1 of 3))
+Test Passed (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 1 of 3))
+Test Finished (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 1 of 3))
+Test Preparation Started (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 2 of 3))
+Test Prepared (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 2 of 3))
+Test Passed (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 2 of 3))
+Test Finished (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 2 of 3))
+Test Preparation Started (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 3 of 3))
+Test Prepared (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 3 of 3))
+Test Passed (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 3 of 3))
+Test Finished (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 3 of 3))
+Test Suite for Repeated Test Method Finished (PHPUnit\TestFixture\Repeat\SuccessTest::testOne, 3 repetitions)
+Test Suite for Repeated Test Method Started (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo, 3 repetitions)
+Test Preparation Started (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo (repetition 1 of 3))
+Test Prepared (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo (repetition 1 of 3))
+Test Passed (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo (repetition 1 of 3))
+Test Finished (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo (repetition 1 of 3))
+Test Preparation Started (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo (repetition 2 of 3))
+Test Prepared (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo (repetition 2 of 3))
+Test Passed (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo (repetition 2 of 3))
+Test Finished (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo (repetition 2 of 3))
+Test Preparation Started (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo (repetition 3 of 3))
+Test Prepared (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo (repetition 3 of 3))
+Test Passed (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo (repetition 3 of 3))
+Test Finished (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo (repetition 3 of 3))
+Test Suite for Repeated Test Method Finished (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo, 3 repetitions)
+Test Suite Finished (PHPUnit\TestFixture\Repeat\SuccessTest, 6 tests)
+Test Runner Execution Finished
+Test Runner Finished
+PHPUnit Finished (Shell Exit Code: 0)
diff --git a/tests/end-to-end/repeat/repeat-with-data-provider.phpt b/tests/end-to-end/repeat/repeat-with-data-provider.phpt
new file mode 100644
index 00000000000..2700a3e558a
--- /dev/null
+++ b/tests/end-to-end/repeat/repeat-with-data-provider.phpt
@@ -0,0 +1,52 @@
+--TEST--
+--repeat with data provider repeats each data set independently
+--FILE--
+run($_SERVER['argv']);
+--EXPECTF--
+PHPUnit Started (PHPUnit %s using %s)
+Test Runner Configured
+Event Facade Sealed
+Data Provider Method Called (PHPUnit\TestFixture\Repeat\DataProviderTest::provider for test method PHPUnit\TestFixture\Repeat\DataProviderTest::testWithDataProvider)
+Data Provider Method Finished for PHPUnit\TestFixture\Repeat\DataProviderTest::testWithDataProvider:
+- PHPUnit\TestFixture\Repeat\DataProviderTest::provider
+Test Suite Loaded (4 tests)
+Test Runner Started
+Test Suite Sorted
+Test Runner Execution Started (4 tests)
+Test Suite Started (PHPUnit\TestFixture\Repeat\DataProviderTest, 4 tests)
+Test Suite for Test Method with Data Provider Started (PHPUnit\TestFixture\Repeat\DataProviderTest::testWithDataProvider, 4 data sets)
+Test Suite for Repeated Test Method Started (PHPUnit\TestFixture\Repeat\DataProviderTest::testWithDataProvider#one, 2 repetitions)
+Test Preparation Started (PHPUnit\TestFixture\Repeat\DataProviderTest::testWithDataProvider#one (repetition 1 of 2))
+Test Prepared (PHPUnit\TestFixture\Repeat\DataProviderTest::testWithDataProvider#one (repetition 1 of 2))
+Test Passed (PHPUnit\TestFixture\Repeat\DataProviderTest::testWithDataProvider#one (repetition 1 of 2))
+Test Finished (PHPUnit\TestFixture\Repeat\DataProviderTest::testWithDataProvider#one (repetition 1 of 2))
+Test Preparation Started (PHPUnit\TestFixture\Repeat\DataProviderTest::testWithDataProvider#one (repetition 2 of 2))
+Test Prepared (PHPUnit\TestFixture\Repeat\DataProviderTest::testWithDataProvider#one (repetition 2 of 2))
+Test Passed (PHPUnit\TestFixture\Repeat\DataProviderTest::testWithDataProvider#one (repetition 2 of 2))
+Test Finished (PHPUnit\TestFixture\Repeat\DataProviderTest::testWithDataProvider#one (repetition 2 of 2))
+Test Suite for Repeated Test Method Finished (PHPUnit\TestFixture\Repeat\DataProviderTest::testWithDataProvider#one, 2 repetitions)
+Test Suite for Repeated Test Method Started (PHPUnit\TestFixture\Repeat\DataProviderTest::testWithDataProvider#two, 2 repetitions)
+Test Preparation Started (PHPUnit\TestFixture\Repeat\DataProviderTest::testWithDataProvider#two (repetition 1 of 2))
+Test Prepared (PHPUnit\TestFixture\Repeat\DataProviderTest::testWithDataProvider#two (repetition 1 of 2))
+Test Passed (PHPUnit\TestFixture\Repeat\DataProviderTest::testWithDataProvider#two (repetition 1 of 2))
+Test Finished (PHPUnit\TestFixture\Repeat\DataProviderTest::testWithDataProvider#two (repetition 1 of 2))
+Test Preparation Started (PHPUnit\TestFixture\Repeat\DataProviderTest::testWithDataProvider#two (repetition 2 of 2))
+Test Prepared (PHPUnit\TestFixture\Repeat\DataProviderTest::testWithDataProvider#two (repetition 2 of 2))
+Test Passed (PHPUnit\TestFixture\Repeat\DataProviderTest::testWithDataProvider#two (repetition 2 of 2))
+Test Finished (PHPUnit\TestFixture\Repeat\DataProviderTest::testWithDataProvider#two (repetition 2 of 2))
+Test Suite for Repeated Test Method Finished (PHPUnit\TestFixture\Repeat\DataProviderTest::testWithDataProvider#two, 2 repetitions)
+Test Suite for Test Method with Data Provider Finished (PHPUnit\TestFixture\Repeat\DataProviderTest::testWithDataProvider, 4 data sets)
+Test Suite Finished (PHPUnit\TestFixture\Repeat\DataProviderTest, 4 tests)
+Test Runner Execution Finished
+Test Runner Finished
+PHPUnit Finished (Shell Exit Code: 0)
diff --git a/tests/end-to-end/repeat/repeat-with-filter.phpt b/tests/end-to-end/repeat/repeat-with-filter.phpt
new file mode 100644
index 00000000000..0c0d768457d
--- /dev/null
+++ b/tests/end-to-end/repeat/repeat-with-filter.phpt
@@ -0,0 +1,40 @@
+--TEST--
+--repeat works with --filter to select specific tests
+--FILE--
+run($_SERVER['argv']);
+--EXPECTF--
+PHPUnit Started (PHPUnit %s using %s)
+Test Runner Configured
+Event Facade Sealed
+Test Suite Loaded (4 tests)
+Test Runner Started
+Test Suite Sorted
+Test Suite Filtered (2 tests)
+Test Runner Execution Started (2 tests)
+Test Suite Started (PHPUnit\TestFixture\Repeat\SuccessTest, 2 tests)
+Test Suite for Repeated Test Method Started (PHPUnit\TestFixture\Repeat\SuccessTest::testOne, 2 repetitions)
+Test Preparation Started (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 1 of 2))
+Test Prepared (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 1 of 2))
+Test Passed (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 1 of 2))
+Test Finished (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 1 of 2))
+Test Preparation Started (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 2 of 2))
+Test Prepared (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 2 of 2))
+Test Passed (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 2 of 2))
+Test Finished (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 2 of 2))
+Test Suite for Repeated Test Method Finished (PHPUnit\TestFixture\Repeat\SuccessTest::testOne, 2 repetitions)
+Test Suite Finished (PHPUnit\TestFixture\Repeat\SuccessTest, 2 tests)
+Test Runner Execution Finished
+Test Runner Finished
+PHPUnit Finished (Shell Exit Code: 0)
diff --git a/tests/end-to-end/repeat/repeat-with-order-by-defects.phpt b/tests/end-to-end/repeat/repeat-with-order-by-defects.phpt
new file mode 100644
index 00000000000..6367e8b0594
--- /dev/null
+++ b/tests/end-to-end/repeat/repeat-with-order-by-defects.phpt
@@ -0,0 +1,48 @@
+--TEST--
+--repeat works with --order-by=defects
+--FILE--
+run($_SERVER['argv']);
+--EXPECTF--
+PHPUnit Started (PHPUnit %s using %s)
+Test Runner Configured
+Event Facade Sealed
+Test Suite Loaded (4 tests)
+Test Runner Started
+Test Suite Sorted
+Test Runner Execution Started (4 tests)
+Test Suite Started (PHPUnit\TestFixture\Repeat\SuccessTest, 4 tests)
+Test Suite for Repeated Test Method Started (PHPUnit\TestFixture\Repeat\SuccessTest::testOne, 2 repetitions)
+Test Preparation Started (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 1 of 2))
+Test Prepared (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 1 of 2))
+Test Passed (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 1 of 2))
+Test Finished (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 1 of 2))
+Test Preparation Started (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 2 of 2))
+Test Prepared (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 2 of 2))
+Test Passed (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 2 of 2))
+Test Finished (PHPUnit\TestFixture\Repeat\SuccessTest::testOne (repetition 2 of 2))
+Test Suite for Repeated Test Method Finished (PHPUnit\TestFixture\Repeat\SuccessTest::testOne, 2 repetitions)
+Test Suite for Repeated Test Method Started (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo, 2 repetitions)
+Test Preparation Started (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo (repetition 1 of 2))
+Test Prepared (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo (repetition 1 of 2))
+Test Passed (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo (repetition 1 of 2))
+Test Finished (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo (repetition 1 of 2))
+Test Preparation Started (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo (repetition 2 of 2))
+Test Prepared (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo (repetition 2 of 2))
+Test Passed (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo (repetition 2 of 2))
+Test Finished (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo (repetition 2 of 2))
+Test Suite for Repeated Test Method Finished (PHPUnit\TestFixture\Repeat\SuccessTest::testTwo, 2 repetitions)
+Test Suite Finished (PHPUnit\TestFixture\Repeat\SuccessTest, 4 tests)
+Test Runner Execution Finished
+Test Runner Finished
+PHPUnit Finished (Shell Exit Code: 0)
diff --git a/tests/unit/Event/Events/TestSuite/FinishedTest.php b/tests/unit/Event/Events/TestSuite/FinishedTest.php
index 53366571943..1a42331bf87 100644
--- a/tests/unit/Event/Events/TestSuite/FinishedTest.php
+++ b/tests/unit/Event/Events/TestSuite/FinishedTest.php
@@ -10,6 +10,7 @@
namespace PHPUnit\Event\TestSuite;
use PHPUnit\Event\AbstractEventTestCase;
+use PHPUnit\Event\Code\TestCollection;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\Attributes\Small;
@@ -43,4 +44,46 @@ public function testCanBeRepresentedAsString(): void
$this->assertSame('Test Suite Finished (foo, 9001 tests)', $event->asString());
}
+
+ public function testCanBeRepresentedAsStringForTestSuiteForTestMethodWithDataProvider(): void
+ {
+ $event = new Finished(
+ $this->telemetryInfo(),
+ new TestSuiteForTestMethodWithDataProvider(
+ 'PHPUnit\TestFixture\ExampleTest::testSomething',
+ 2,
+ TestCollection::fromArray([]),
+ 'PHPUnit\TestFixture\ExampleTest',
+ 'testSomething',
+ 'ExampleTest.php',
+ 10,
+ ),
+ );
+
+ $this->assertSame(
+ 'Test Suite for Test Method with Data Provider Finished (PHPUnit\TestFixture\ExampleTest::testSomething, 2 data sets)',
+ $event->asString(),
+ );
+ }
+
+ public function testCanBeRepresentedAsStringForTestSuiteForRepeatedTestMethod(): void
+ {
+ $event = new Finished(
+ $this->telemetryInfo(),
+ new TestSuiteForRepeatedTestMethod(
+ 'PHPUnit\TestFixture\ExampleTest::testSomething',
+ 3,
+ TestCollection::fromArray([]),
+ 'PHPUnit\TestFixture\ExampleTest',
+ 'testSomething',
+ 'ExampleTest.php',
+ 10,
+ ),
+ );
+
+ $this->assertSame(
+ 'Test Suite for Repeated Test Method Finished (PHPUnit\TestFixture\ExampleTest::testSomething, 3 repetitions)',
+ $event->asString(),
+ );
+ }
}
diff --git a/tests/unit/Event/Events/TestSuite/StartedTest.php b/tests/unit/Event/Events/TestSuite/StartedTest.php
index afb771f989f..c5b368b602c 100644
--- a/tests/unit/Event/Events/TestSuite/StartedTest.php
+++ b/tests/unit/Event/Events/TestSuite/StartedTest.php
@@ -10,6 +10,7 @@
namespace PHPUnit\Event\TestSuite;
use PHPUnit\Event\AbstractEventTestCase;
+use PHPUnit\Event\Code\TestCollection;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\Attributes\Small;
@@ -40,4 +41,46 @@ public function testCanBeRepresentedAsString(): void
$this->assertSame('Test Suite Started (foo, 9001 tests)', $event->asString());
}
+
+ public function testCanBeRepresentedAsStringForTestSuiteForTestMethodWithDataProvider(): void
+ {
+ $event = new Started(
+ $this->telemetryInfo(),
+ new TestSuiteForTestMethodWithDataProvider(
+ 'PHPUnit\TestFixture\ExampleTest::testSomething',
+ 2,
+ TestCollection::fromArray([]),
+ 'PHPUnit\TestFixture\ExampleTest',
+ 'testSomething',
+ 'ExampleTest.php',
+ 10,
+ ),
+ );
+
+ $this->assertSame(
+ 'Test Suite for Test Method with Data Provider Started (PHPUnit\TestFixture\ExampleTest::testSomething, 2 data sets)',
+ $event->asString(),
+ );
+ }
+
+ public function testCanBeRepresentedAsStringForTestSuiteForRepeatedTestMethod(): void
+ {
+ $event = new Started(
+ $this->telemetryInfo(),
+ new TestSuiteForRepeatedTestMethod(
+ 'PHPUnit\TestFixture\ExampleTest::testSomething',
+ 3,
+ TestCollection::fromArray([]),
+ 'PHPUnit\TestFixture\ExampleTest',
+ 'testSomething',
+ 'ExampleTest.php',
+ 10,
+ ),
+ );
+
+ $this->assertSame(
+ 'Test Suite for Repeated Test Method Started (PHPUnit\TestFixture\ExampleTest::testSomething, 3 repetitions)',
+ $event->asString(),
+ );
+ }
}
diff --git a/tests/unit/Event/Value/Test/TestMethodTest.php b/tests/unit/Event/Value/Test/TestMethodTest.php
index 0b035299a0d..a546beeea5a 100644
--- a/tests/unit/Event/Value/Test/TestMethodTest.php
+++ b/tests/unit/Event/Value/Test/TestMethodTest.php
@@ -56,6 +56,73 @@ public function testConstructorSetsValues(): void
$this->assertSame($testData, $test->testData());
$this->assertTrue($test->isTestMethod());
$this->assertFalse($test->isPhpt());
+ $this->assertSame(1, $test->repetition());
+ $this->assertSame(1, $test->totalRepetitions());
+ $this->assertFalse($test->isRepeated());
+ }
+
+ public function testRepetitionValues(): void
+ {
+ $test = new TestMethod(
+ 'FooTest',
+ 'testBar',
+ 'FooTest.php',
+ 1,
+ TestDoxBuilder::fromClassNameAndMethodName('Foo', 'bar'),
+ MetadataCollection::fromArray([]),
+ TestDataCollection::fromArray([]),
+ 2,
+ 3,
+ );
+
+ $this->assertSame(2, $test->repetition());
+ $this->assertSame(3, $test->totalRepetitions());
+ $this->assertTrue($test->isRepeated());
+ }
+
+ public function testNameIncludesRepetitionWhenRepeated(): void
+ {
+ $test = new TestMethod(
+ 'FooTest',
+ 'testBar',
+ 'FooTest.php',
+ 1,
+ TestDoxBuilder::fromClassNameAndMethodName('Foo', 'bar'),
+ MetadataCollection::fromArray([]),
+ TestDataCollection::fromArray([]),
+ 2,
+ 3,
+ );
+
+ $this->assertSame('testBar (repetition 2 of 3)', $test->name());
+ $this->assertSame('FooTest::testBar (repetition 2 of 3)', $test->nameWithClass());
+ $this->assertSame('FooTest::testBar (repetition 2 of 3)', $test->id());
+ }
+
+ public function testNameIncludesDataProviderAndRepetition(): void
+ {
+ $test = new TestMethod(
+ 'FooTest',
+ 'testBar',
+ 'FooTest.php',
+ 1,
+ TestDoxBuilder::fromClassNameAndMethodName('Foo', 'bar'),
+ MetadataCollection::fromArray([]),
+ TestDataCollection::fromArray(
+ [
+ DataFromDataProvider::from(
+ 0,
+ 'data',
+ 'data as string for result output',
+ ),
+ ],
+ ),
+ 2,
+ 3,
+ );
+
+ $this->assertSame('testBar with data set #0 (repetition 2 of 3)', $test->name());
+ $this->assertSame('FooTest::testBar#0 (repetition 2 of 3)', $test->id());
}
public function testNameReturnsNameWhenTestDoesNotHaveDataFromDataProvider(): void
diff --git a/tests/unit/Event/Value/TestSuite/TestSuiteTest.php b/tests/unit/Event/Value/TestSuite/TestSuiteTest.php
index 25ddc3b4532..12aa1e7ffc3 100644
--- a/tests/unit/Event/Value/TestSuite/TestSuiteTest.php
+++ b/tests/unit/Event/Value/TestSuite/TestSuiteTest.php
@@ -59,6 +59,33 @@ public function testCanBeTestSuiteForTestMethodWithDataProvider(): void
$this->assertFalse($testSuite->isForTestClass());
$this->assertTrue($testSuite->isForTestMethodWithDataProvider());
+ $this->assertFalse($testSuite->isForRepeatedTestMethod());
+ $this->assertFalse($testSuite->isWithName());
+
+ $this->assertSame($name, $testSuite->name());
+ $this->assertSame($className, $testSuite->className());
+ $this->assertSame($methodName, $testSuite->methodName());
+ $this->assertSame($size, $testSuite->count());
+ $this->assertSame($tests, $testSuite->tests());
+ $this->assertSame($file, $testSuite->file());
+ $this->assertSame($line, $testSuite->line());
+ }
+
+ public function testCanBeTestSuiteForRepeatedTestMethod(): void
+ {
+ $name = 'ExampleTest::testOne';
+ $className = 'ExampleTest';
+ $methodName = 'testOne';
+ $size = 0;
+ $tests = TestCollection::fromArray([]);
+ $file = 'ExampleTest.php';
+ $line = 1;
+
+ $testSuite = new TestSuiteForRepeatedTestMethod($name, $size, $tests, $className, $methodName, $file, $line);
+
+ $this->assertFalse($testSuite->isForTestClass());
+ $this->assertFalse($testSuite->isForTestMethodWithDataProvider());
+ $this->assertTrue($testSuite->isForRepeatedTestMethod());
$this->assertFalse($testSuite->isWithName());
$this->assertSame($name, $testSuite->name());
diff --git a/tests/unit/Framework/RepeatTestSuiteTest.php b/tests/unit/Framework/RepeatTestSuiteTest.php
new file mode 100644
index 00000000000..54ab87c002f
--- /dev/null
+++ b/tests/unit/Framework/RepeatTestSuiteTest.php
@@ -0,0 +1,56 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\Small;
+use PHPUnit\TestFixture\Success;
+
+#[CoversClass(RepeatTestSuite::class)]
+#[Small]
+final class RepeatTestSuiteTest extends TestCase
+{
+ public function testCountReturnsNumberOfRepetitions(): void
+ {
+ $tests = [
+ new Success('testOne'),
+ new Success('testOne'),
+ new Success('testOne'),
+ ];
+
+ $suite = RepeatTestSuite::fromTests('PHPUnit\TestFixture\Success::testOne', $tests, 1);
+
+ $this->assertCount(3, $suite);
+ }
+
+ public function testNameReturnsValueProvidedToFactory(): void
+ {
+ $suite = RepeatTestSuite::fromTests(
+ 'PHPUnit\TestFixture\Success::testOne',
+ [new Success('testOne')],
+ 1,
+ );
+
+ $this->assertSame('PHPUnit\TestFixture\Success::testOne', $suite->name());
+ }
+
+ public function testSortIdDelegatesToFirstChild(): void
+ {
+ $test = new Success('testOne');
+
+ $suite = RepeatTestSuite::fromTests(
+ 'PHPUnit\TestFixture\Success::testOne',
+ [$test],
+ 1,
+ );
+
+ $this->assertSame($test->sortId(), $suite->sortId());
+ }
+}
diff --git a/tests/unit/Metadata/MetadataCollectionTest.php b/tests/unit/Metadata/MetadataCollectionTest.php
index 540cbeb33a9..9376e951e55 100644
--- a/tests/unit/Metadata/MetadataCollectionTest.php
+++ b/tests/unit/Metadata/MetadataCollectionTest.php
@@ -41,6 +41,7 @@
#[UsesClass(PostCondition::class)]
#[UsesClass(PreCondition::class)]
#[UsesClass(PreserveGlobalState::class)]
+#[UsesClass(Repeat::class)]
#[UsesClass(RequiresFunction::class)]
#[UsesClass(RequiresMethod::class)]
#[UsesClass(RequiresOperatingSystem::class)]
@@ -571,6 +572,14 @@ public function test_Can_be_filtered_for_UsesMethod(): void
$this->assertTrue($collection->asArray()[0]->isUsesMethod());
}
+ public function test_Can_be_filtered_for_Repeat(): void
+ {
+ $collection = $this->collectionWithOneOfEach()->isRepeat();
+
+ $this->assertCount(1, $collection);
+ $this->assertTrue($collection->asArray()[0]->isRepeat());
+ }
+
public function test_Can_be_filtered_for_WithoutErrorHandler(): void
{
$collection = $this->collectionWithOneOfEach()->isWithoutErrorHandler();
@@ -650,6 +659,7 @@ private function collectionWithOneOfEach(): MetadataCollection
Metadata::usesTrait(''),
Metadata::usesFunction(''),
Metadata::usesMethod('', ''),
+ Metadata::repeat(3, 1),
Metadata::withEnvironmentVariableOnClass('foo', 'bar'),
Metadata::withoutErrorHandler(),
],
diff --git a/tests/unit/Metadata/MetadataTest.php b/tests/unit/Metadata/MetadataTest.php
index b39471dc2df..42d1c8aee0e 100644
--- a/tests/unit/Metadata/MetadataTest.php
+++ b/tests/unit/Metadata/MetadataTest.php
@@ -57,6 +57,7 @@ public function testCanBeAfter(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -124,6 +125,7 @@ public function testCanBeAfterClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -189,6 +191,7 @@ public function testCanBeAllowMockObjectsWithoutExpectations(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -253,6 +256,7 @@ public function testCanBeBackupGlobalsOnClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -318,6 +322,7 @@ public function testCanBeBackupGlobalsOnMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -383,6 +388,7 @@ public function testCanBeBackupStaticPropertiesOnClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -448,6 +454,7 @@ public function testCanBeBackupStaticPropertiesOnMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -515,6 +522,7 @@ public function testCanBeBeforeClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -581,6 +589,7 @@ public function testCanBeBefore(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -646,6 +655,7 @@ public function testCanBeCoversClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -714,6 +724,7 @@ public function testCanBeCoversNamespace(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -780,6 +791,7 @@ public function testCanBeCoversClassesThatExtendClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -846,6 +858,7 @@ public function testCanBeCoversClassesThatImplementInterface(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -912,6 +925,7 @@ public function testCanBeCoversFunction(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -978,6 +992,7 @@ public function testCanBeCoversMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -1045,6 +1060,7 @@ public function testCanBeCoversNothingOnMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -1109,6 +1125,7 @@ public function testCanBeCoversNothingOnClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -1173,6 +1190,7 @@ public function testCanBeCoversTrait(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -1239,6 +1257,7 @@ public function testCanBeDataProvider(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -1311,6 +1330,7 @@ public function testCanBeDataProviderClosure(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -1378,6 +1398,7 @@ public function testCanBeDependsOnClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -1446,6 +1467,7 @@ public function testCanBeDependsOnMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -1515,6 +1537,7 @@ public function testCanBeDisableReturnValueGenerationForTestDoubles(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -1579,6 +1602,7 @@ public function testCanBeDoesNotPerformAssertionsOnClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -1643,6 +1667,7 @@ public function testCanBeDoesNotPerformAssertionsOnMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -1707,6 +1732,7 @@ public function testCanBeExcludeGlobalVariableFromBackupOnClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -1772,6 +1798,7 @@ public function testCanBeExcludeGlobalVariableFromBackupOnMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -1837,6 +1864,7 @@ public function testCanBeExcludeStaticPropertyFromBackupOnClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -1904,6 +1932,7 @@ public function testCanBeExcludeStaticPropertyFromBackupOnMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -1971,6 +2000,7 @@ public function testCanBeGroupOnClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -2039,6 +2069,7 @@ public function testCanBeIgnoreDeprecationsOnClass(): void
$this->assertTrue($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -2104,6 +2135,7 @@ public function testCanBeIgnoreDeprecationsOnMethod(): void
$this->assertTrue($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -2168,6 +2200,7 @@ public function testCanBeIgnorePhpunitDeprecationsOnClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertTrue($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -2232,6 +2265,7 @@ public function testCanBeIgnorePhpunitDeprecationsOnMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertTrue($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -2363,6 +2397,7 @@ public function testCanBeGroupOnMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -2429,6 +2464,7 @@ public function testCanBeRunTestsInSeparateProcesses(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertTrue($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -2557,6 +2593,7 @@ public function testCanBeTest(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertTrue($metadata->isTest());
@@ -2623,6 +2660,7 @@ public function testCanBePreCondition(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -2690,6 +2728,7 @@ public function testCanBePostCondition(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -2751,6 +2790,7 @@ public function testCanBePreserveGlobalStateOnClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -2813,6 +2853,7 @@ public function testCanBePreserveGlobalStateOnMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -2879,6 +2920,7 @@ public function testCanBeRequiresMethodOnClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -2946,6 +2988,7 @@ public function testCanBeRequiresMethodOnMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -3013,6 +3056,7 @@ public function testCanBeRequiresFunctionOnClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -3079,6 +3123,7 @@ public function testCanBeRequiresFunctionOnMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -3145,6 +3190,7 @@ public function testCanBeRequiresOperatingSystemOnClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -3211,6 +3257,7 @@ public function testCanBeRequiresOperatingSystemOnMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -3277,6 +3324,7 @@ public function testCanBeRequiresOperatingSystemFamilyOnClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -3343,6 +3391,7 @@ public function testCanBeRequiresOperatingSystemFamilyOnMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -3414,6 +3463,7 @@ public function testCanBeRequiresPhpOnClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -3485,6 +3535,7 @@ public function testCanBeRequiresPhpOnMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -3551,6 +3602,7 @@ public function testCanBeRequiresPhpExtensionOnClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -3627,6 +3679,7 @@ public function testCanBeRequiresPhpExtensionWithVersionOnClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -3695,6 +3748,7 @@ public function testCanBeRequiresPhpExtensionOnMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -3771,6 +3825,7 @@ public function testCanBeRequiresPhpExtensionWithVersionOnMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -3844,6 +3899,7 @@ public function testCanBeRequiresPhpunitOnClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -3910,6 +3966,7 @@ public function testCanBeRequiresPhpunitExtensionOnClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -3981,6 +4038,7 @@ public function testCanBeRequiresPhpunitOnMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -4047,6 +4105,7 @@ public function testCanBeRequiresPhpunitExtensionOnMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -4113,6 +4172,7 @@ public function testCanBeRequiresEnvironmentVariableOnMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -4180,6 +4240,7 @@ public function testCanBeRequiresEnvironmentVariableOnClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -4247,6 +4308,7 @@ public function testCanBeWithEnvironmentVariableOnMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -4314,6 +4376,7 @@ public function testCanBeWithEnvironmentVariableOnClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -4381,6 +4444,7 @@ public function testCanBeRequiresSettingOnClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -4448,6 +4512,7 @@ public function testCanBeRequiresSettingOnMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -4515,6 +4580,7 @@ public function testCanBeTestDoxOnClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -4581,6 +4647,7 @@ public function testCanBeTestDoxOnMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -4647,6 +4714,7 @@ public function testCanBeTestDoxFormatterOnMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -4714,6 +4782,7 @@ public function testCanBeTestWith(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -4783,6 +4852,7 @@ public function testCanBeUsesNamespace(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -4849,6 +4919,7 @@ public function testCanBeUsesClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -4915,6 +4986,7 @@ public function testCanBeUsesClassesThatExtendClass(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -4981,6 +5053,7 @@ public function testCanBeUsesClassesThatImplementInterface(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -5047,6 +5120,7 @@ public function testCanBeUsesFunction(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -5112,6 +5186,7 @@ public function testCanBeUsesMethod(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -5179,6 +5254,7 @@ public function testCanBeUsesTrait(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -5245,6 +5321,7 @@ public function testCanBeWithoutErrorHandler(): void
$this->assertFalse($metadata->isIgnoreDeprecations());
$this->assertFalse($metadata->isIgnorePhpunitDeprecations());
$this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertFalse($metadata->isRepeat());
$this->assertFalse($metadata->isRunInSeparateProcess());
$this->assertFalse($metadata->isRunTestsInSeparateProcesses());
$this->assertFalse($metadata->isTest());
@@ -5277,4 +5354,72 @@ public function testCanBeWithoutErrorHandler(): void
$this->assertTrue($metadata->isMethodLevel());
$this->assertFalse($metadata->isClassLevel());
}
+
+ public function testCanBeRepeat(): void
+ {
+ $metadata = Metadata::repeat(3, 2);
+
+ $this->assertFalse($metadata->isAfter());
+ $this->assertFalse($metadata->isAfterClass());
+ $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations());
+ $this->assertFalse($metadata->isBackupGlobals());
+ $this->assertFalse($metadata->isBackupStaticProperties());
+ $this->assertFalse($metadata->isBeforeClass());
+ $this->assertFalse($metadata->isBefore());
+ $this->assertFalse($metadata->isCoversNamespace());
+ $this->assertFalse($metadata->isCoversClass());
+ $this->assertFalse($metadata->isCoversClassesThatExtendClass());
+ $this->assertFalse($metadata->isCoversClassesThatImplementInterface());
+ $this->assertFalse($metadata->isCoversFunction());
+ $this->assertFalse($metadata->isCoversMethod());
+ $this->assertFalse($metadata->isCoversNothing());
+ $this->assertFalse($metadata->isCoversTrait());
+ $this->assertFalse($metadata->isDataProvider());
+ $this->assertFalse($metadata->isDataProviderClosure());
+ $this->assertFalse($metadata->isDependsOnClass());
+ $this->assertFalse($metadata->isDependsOnMethod());
+ $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles());
+ $this->assertFalse($metadata->isDoesNotPerformAssertions());
+ $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup());
+ $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup());
+ $this->assertFalse($metadata->isGroup());
+ $this->assertFalse($metadata->isIgnoreDeprecations());
+ $this->assertFalse($metadata->isIgnorePhpunitDeprecations());
+ $this->assertFalse($metadata->isIgnorePHPUnitWarnings());
+ $this->assertTrue($metadata->isRepeat());
+ $this->assertFalse($metadata->isRunInSeparateProcess());
+ $this->assertFalse($metadata->isRunTestsInSeparateProcesses());
+ $this->assertFalse($metadata->isTest());
+ $this->assertFalse($metadata->isPreCondition());
+ $this->assertFalse($metadata->isPostCondition());
+ $this->assertFalse($metadata->isPreserveGlobalState());
+ $this->assertFalse($metadata->isRequiresMethod());
+ $this->assertFalse($metadata->isRequiresFunction());
+ $this->assertFalse($metadata->isRequiresOperatingSystem());
+ $this->assertFalse($metadata->isRequiresOperatingSystemFamily());
+ $this->assertFalse($metadata->isRequiresPhp());
+ $this->assertFalse($metadata->isRequiresPhpExtension());
+ $this->assertFalse($metadata->isRequiresPhpunit());
+ $this->assertFalse($metadata->isRequiresPhpunitExtension());
+ $this->assertFalse($metadata->isRequiresEnvironmentVariable());
+ $this->assertFalse($metadata->isWithEnvironmentVariable());
+ $this->assertFalse($metadata->isRequiresSetting());
+ $this->assertFalse($metadata->isTestDox());
+ $this->assertFalse($metadata->isTestDoxFormatter());
+ $this->assertFalse($metadata->isTestWith());
+ $this->assertFalse($metadata->isUsesNamespace());
+ $this->assertFalse($metadata->isUsesClass());
+ $this->assertFalse($metadata->isUsesClassesThatExtendClass());
+ $this->assertFalse($metadata->isUsesClassesThatImplementInterface());
+ $this->assertFalse($metadata->isUsesFunction());
+ $this->assertFalse($metadata->isUsesMethod());
+ $this->assertFalse($metadata->isUsesTrait());
+ $this->assertFalse($metadata->isWithoutErrorHandler());
+
+ $this->assertSame(3, $metadata->times());
+ $this->assertSame(2, $metadata->failureThreshold());
+
+ $this->assertTrue($metadata->isMethodLevel());
+ $this->assertFalse($metadata->isClassLevel());
+ }
}
diff --git a/tests/unit/Metadata/Parser/AttributeParserTestCase.php b/tests/unit/Metadata/Parser/AttributeParserTestCase.php
index 236b287e065..09e7875ad8b 100644
--- a/tests/unit/Metadata/Parser/AttributeParserTestCase.php
+++ b/tests/unit/Metadata/Parser/AttributeParserTestCase.php
@@ -15,6 +15,7 @@
use PHPUnit\Metadata\DependsOnClass;
use PHPUnit\Metadata\DependsOnMethod;
use PHPUnit\Metadata\InvalidAttributeException;
+use PHPUnit\Metadata\Repeat;
use PHPUnit\Metadata\RequiresEnvironmentVariable;
use PHPUnit\Metadata\RequiresPhp;
use PHPUnit\Metadata\RequiresPhpExtension;
@@ -52,6 +53,7 @@
use PHPUnit\TestFixture\Metadata\Attribute\PhpunitAttributeThatDoesNotExistTest;
use PHPUnit\TestFixture\Metadata\Attribute\PreserveGlobalStateTest;
use PHPUnit\TestFixture\Metadata\Attribute\ProcessIsolationTest;
+use PHPUnit\TestFixture\Metadata\Attribute\RepeatTest;
use PHPUnit\TestFixture\Metadata\Attribute\RequiresEnvironmentVariableTest;
use PHPUnit\TestFixture\Metadata\Attribute\RequiresFunctionTest;
use PHPUnit\TestFixture\Metadata\Attribute\RequiresMethodTest;
@@ -1213,6 +1215,22 @@ public function test_parses_Ticket_attribute_on_method(): void
$this->assertSame('another-ticket', $metadata->asArray()[1]->groupName());
}
+ #[TestDox('Parses #[Repeat] attribute on method')]
+ public function test_parses_Repeat_attribute_on_method(): void
+ {
+ $metadata = $this->parser()->forMethod(RepeatTest::class, 'testOne')->isRepeat();
+
+ $this->assertCount(1, $metadata);
+ $this->assertTrue($metadata->asArray()[0]->isRepeat());
+
+ $repeat = $metadata->asArray()[0];
+
+ assert($repeat instanceof Repeat);
+
+ $this->assertSame(5, $repeat->times());
+ $this->assertSame(2, $repeat->failureThreshold());
+ }
+
#[TestDox('Parses #[WithoutErrorHandler] attribute on method')]
public function test_parses_WithoutErrorHandler_attribute_on_method(): void
{
diff --git a/tests/unit/TextUI/Configuration/Cli/BuilderTest.php b/tests/unit/TextUI/Configuration/Cli/BuilderTest.php
index cb41c882f18..ea912761166 100644
--- a/tests/unit/TextUI/Configuration/Cli/BuilderTest.php
+++ b/tests/unit/TextUI/Configuration/Cli/BuilderTest.php
@@ -2952,6 +2952,26 @@ public function testExtensionMayNotBeConfigured(): void
$configuration->extensions();
}
+ #[TestDox('--repeat')]
+ public function testRepeat(): void
+ {
+ $configuration = (new Builder)->fromParameters(['--repeat', '3']);
+
+ $this->assertTrue($configuration->hasRepeat());
+ $this->assertSame(3, $configuration->repeat());
+ }
+
+ public function testRepeatMayNotBeConfigured(): void
+ {
+ $configuration = (new Builder)->fromParameters([]);
+
+ $this->assertFalse($configuration->hasRepeat());
+
+ $this->expectException(Exception::class);
+
+ $configuration->repeat();
+ }
+
public function testInvalidOption(): void
{
$this->expectException(Exception::class);