Skip to content

Keep information which data provider provided current data set #5992

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/Framework/Exception/Exception.php
Original file line number Diff line number Diff line change
@@ -42,12 +42,14 @@
*/
class Exception extends RuntimeException implements \PHPUnit\Exception
{
public ?string $method;

/**
* @var list<array{file: string, line: int, function: string}>
*/
protected array $serializableTrace;

public function __construct(string $message = '', int|string $code = 0, ?Throwable $previous = null)
public function __construct(string $message = '', int|string $code = 0, ?Throwable $previous = null, ?string $method = null)
{
/**
* @see https://github.com/sebastianbergmann/phpunit/issues/5965
@@ -68,6 +70,7 @@ public function __construct(string $message = '', int|string $code = 0, ?Throwab
foreach (array_keys($this->serializableTrace) as $key) {
unset($this->serializableTrace[$key]['args']);
}
$this->method = $method;
}

public function __sleep(): array
28 changes: 16 additions & 12 deletions src/Framework/TestBuilder.php
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@

use function array_merge;
use function assert;
use function reset;
use PHPUnit\Metadata\Api\DataProvider;
use PHPUnit\Metadata\Api\Groups;
use PHPUnit\Metadata\Api\Requirements;
@@ -47,7 +48,7 @@ public function build(ReflectionClass $theClass, string $methodName, array $grou
$data = (new DataProvider)->providedData($className, $methodName);
}

if ($data !== null) {
if ($data !== null && reset($data) !== null) {
return $this->buildDataProviderTestSuite(
$methodName,
$className,
@@ -91,20 +92,23 @@ private function buildDataProviderTestSuite(string $methodName, string $classNam
(new Groups)->groups($className, $methodName),
);

foreach ($data as $_dataName => $_data) {
$_test = new $className($methodName);
foreach ($data as $providerName => $providedData) {
foreach ($providedData as $_dataName => $_data) {
$_test = new $className($methodName);

$_test->setData($_dataName, $_data);
$_test->setData($_dataName, $_data);

$this->configureTestCase(
$_test,
$runTestInSeparateProcess,
$preserveGlobalState,
$runClassInSeparateProcess,
$backupSettings,
);
$this->configureTestCase(
$_test,
$runTestInSeparateProcess,
$preserveGlobalState,
$runClassInSeparateProcess,
$backupSettings,
);

$dataProviderTestSuite->addTest($_test, $groups);
$_test->setProviderName($providerName);
$dataProviderTestSuite->addTest($_test, $groups);
}
}

return $dataProviderTestSuite;
19 changes: 19 additions & 0 deletions src/Framework/TestCase.php
Original file line number Diff line number Diff line change
@@ -107,6 +107,10 @@
*/
abstract class TestCase extends Assert implements Reorderable, SelfDescribing, Test
{
/**
* @var non-empty-string
*/
protected string $providerName;
private ?bool $backupGlobals = null;

/**
@@ -375,6 +379,21 @@ final public function setGroups(array $groups): void
$this->groups = $groups;
}

public function getProviderName(): string
{
return $this->providerName;
}

/**
* @return $this
*/
public function setProviderName(string $providerName): self
{
$this->providerName = $providerName;

return $this;
}

/**
* @internal This method is not covered by the backward compatibility promise for PHPUnit
*/
3 changes: 2 additions & 1 deletion src/Framework/TestSuite.php
Original file line number Diff line number Diff line change
@@ -528,7 +528,8 @@ protected function addTestMethod(ReflectionClass $class, ReflectionMethod $metho
Event\TestData\TestDataCollection::fromArray([]),
),
sprintf(
"The data provider specified for %s::%s is invalid\n%s",
"The data provider %s specified for %s::%s is invalid\n%s",
$e->method,
$className,
$methodName,
$this->exceptionToString($e),
162 changes: 87 additions & 75 deletions src/Metadata/Api/DataProvider.php
Original file line number Diff line number Diff line change
@@ -15,9 +15,13 @@
use function get_debug_type;
use function is_array;
use function is_int;
use function is_iterable;
use function is_string;
use function key;
use function reset;
use function sprintf;
use PHPUnit\Event;
use PHPUnit\Event\Code\ClassMethod;
use PHPUnit\Event\Code\TestMethod;
use PHPUnit\Framework\InvalidDataProviderException;
use PHPUnit\Metadata\DataProvider as DataProviderMetadata;
@@ -54,75 +58,82 @@ public function providedData(string $className, string $methodName): ?array
if ($dataProvider->isNotEmpty()) {
$data = $this->dataProvidedByMethods($className, $methodName, $dataProvider);
} else {
$data = $this->dataProvidedByMetadata($testWith);
$data = ['testWith' => $this->dataProvidedByMetadata($testWith)];
}

if ($data === []) {
if ($data === [] || reset($data) === []) {
throw new InvalidDataProviderException(
'Empty data set provided by data provider',
method: key($data),
);
}

$method = new ReflectionMethod($className, $methodName);
$testMethodNumberOfParameters = $method->getNumberOfParameters();
$testMethodIsNonVariadic = !$method->isVariadic();

foreach ($data as $key => $value) {
if (!is_array($value)) {
throw new InvalidDataProviderException(
sprintf(
'Data set %s is invalid, expected array but got %s',
$this->formatKey($key),
get_debug_type($value),
),
);
}
foreach ($data as $providerMethodName => $providedData) {
foreach ($providedData as $key => $value) {
if (!is_array($value)) {
throw new InvalidDataProviderException(
sprintf(
'Data set %s is invalid, expected array but got %s',
$this->formatKey($key),
get_debug_type($value),
),
method: $providerMethodName,
);
}

if ($testMethodIsNonVariadic && $testMethodNumberOfParameters < count($value)) {
Event\Facade::emitter()->testTriggeredPhpunitWarning(
new TestMethod(
$className,
$methodName,
$method->getFileName(),
$method->getStartLine(),
Event\Code\TestDoxBuilder::fromClassNameAndMethodName(
if ($testMethodIsNonVariadic && $testMethodNumberOfParameters < count($value)) {
Event\Facade::emitter()->testTriggeredPhpunitWarning(
new TestMethod(
$className,
$methodName,
$method->getFileName(),
$method->getStartLine(),
Event\Code\TestDoxBuilder::fromClassNameAndMethodName(
$className,
$methodName,
),
MetadataCollection::fromArray([]),
Event\TestData\TestDataCollection::fromArray([]),
),
MetadataCollection::fromArray([]),
Event\TestData\TestDataCollection::fromArray([]),
),
sprintf(
'Data set %s has more arguments (%d) than the test method accepts (%d)',
$this->formatKey($key),
count($value),
$testMethodNumberOfParameters,
),
);
sprintf(
'Data set %s has more arguments (%d) than the test method accepts (%d)',
$this->formatKey($key),
count($value),
$testMethodNumberOfParameters,
),
);
}
}
}

return $data;
}

/**
* @param class-string $className
* @param non-empty-string $methodName
* @param class-string $testClassName Name of class with test
* @param non-empty-string $testMethodName Name of method containing test
*
* @throws InvalidDataProviderException
*
* @return array<array<mixed>>
*/
private function dataProvidedByMethods(string $className, string $methodName, MetadataCollection $dataProvider): array
private function dataProvidedByMethods(string $testClassName, string $testMethodName, MetadataCollection $dataProvider): array
{
$testMethod = new Event\Code\ClassMethod($className, $methodName);
$testMethod = new ClassMethod($testClassName, $testMethodName);
$methodsCalled = [];
$result = [];
$return = [];
$caseNames = [];

foreach ($dataProvider as $_dataProvider) {
assert($_dataProvider instanceof DataProviderMetadata);

$dataProviderMethod = new Event\Code\ClassMethod($_dataProvider->className(), $_dataProvider->methodName());
$providerClassName = $_dataProvider->className();
$providerMethodName = $_dataProvider->methodName();
$dataProviderMethod = new ClassMethod($providerClassName, $providerMethodName);

Event\Facade::emitter()->dataProviderMethodCalled(
$testMethod,
@@ -135,91 +146,92 @@ private function dataProvidedByMethods(string $className, string $methodName, Me
$method = new ReflectionMethod($_dataProvider->className(), $_dataProvider->methodName());

if (!$method->isPublic()) {
throw new InvalidDataProviderException(
sprintf(
'Data Provider method %s::%s() is not public',
$_dataProvider->className(),
$_dataProvider->methodName(),
),
);
$this->throwInvalid('is not public', $_dataProvider);
}

if (!$method->isStatic()) {
throw new InvalidDataProviderException(
sprintf(
'Data Provider method %s::%s() is not static',
$_dataProvider->className(),
$_dataProvider->methodName(),
),
);
$this->throwInvalid('is not static', $_dataProvider);
}

if ($method->getNumberOfParameters() > 0) {
throw new InvalidDataProviderException(
sprintf(
'Data Provider method %s::%s() expects an argument',
$_dataProvider->className(),
$_dataProvider->methodName(),
),
);
$this->throwInvalid('expects an argument', $_dataProvider);
}

$className = $_dataProvider->className();
$methodName = $_dataProvider->methodName();

/** @phpstan-ignore staticMethod.dynamicName */
$data = $className::$methodName();
$data = $providerClassName::$providerMethodName();

if (!is_iterable($data)) {
$this->throwInvalid('does not provide iterable type', $_dataProvider);
}
} catch (Throwable $e) {
Event\Facade::emitter()->dataProviderMethodFinished(
$testMethod,
...$methodsCalled,
);
$this->finishMethods($testMethod, $methodsCalled);

throw new InvalidDataProviderException(
$e->getMessage(),
$e->getCode(),
$e,
$providerMethodName,
);
}

$result = [];

foreach ($data as $key => $value) {
if (is_int($key)) {
$result[] = $value;
} elseif (is_string($key)) {
if (array_key_exists($key, $result)) {
Event\Facade::emitter()->dataProviderMethodFinished(
$testMethod,
...$methodsCalled,
);
if (isset($caseNames[$key])) {
$this->finishMethods($testMethod, $methodsCalled);

throw new InvalidDataProviderException(
sprintf(
'The key "%s" has already been defined by a previous data provider',
$key,
),
method: $providerMethodName,
);
}

$result[$key] = $value;
$caseNames[$key] = 1;
$result[$key] = $value;
} else {
// @codeCoverageIgnoreStart
throw new InvalidDataProviderException(
sprintf(
'The key must be an integer or a string, %s given',
get_debug_type($key),
),
method: $providerMethodName,
);
// @codeCoverageIgnoreEnd
}
}
$return[$providerMethodName] = $result;
}
$this->finishMethods($testMethod, $methodsCalled);

return $return;
}

private function throwInvalid(string $message, DataProviderMetadata $dataProvider): never
{
throw new InvalidDataProviderException(
sprintf(
'Data Provider method %s::%s() ',
$dataProvider->className(),
$dataProvider->methodName(),
) . $message,
);
}

/**
* @param ClassMethod[] $methodsCalled
*/
private function finishMethods(ClassMethod $method, array $methodsCalled): void
{
Event\Facade::emitter()->dataProviderMethodFinished(
$testMethod,
$method,
...$methodsCalled,
);

return $result;
}

/**
7 changes: 4 additions & 3 deletions tests/_files/AbstractVariousIterableDataProviderTest.php
Original file line number Diff line number Diff line change
@@ -9,11 +9,12 @@
*/
namespace PHPUnit\TestFixture;

use Generator;
use PHPUnit\Framework\Attributes\DataProvider;

abstract class AbstractVariousIterableDataProviderTest
{
public static function asArrayProviderInParent()
public static function asArrayProviderInParent(): array
{
return [
['J'],
@@ -22,7 +23,7 @@ public static function asArrayProviderInParent()
];
}

public static function asIteratorProviderInParent()
public static function asIteratorProviderInParent(): Generator
{
yield ['M'];

@@ -31,7 +32,7 @@ public static function asIteratorProviderInParent()
yield ['O'];
}

public static function asTraversableProviderInParent()
public static function asTraversableProviderInParent(): WrapperIteratorAggregate
{
return new WrapperIteratorAggregate([
['P'],
2 changes: 1 addition & 1 deletion tests/_files/DuplicateKeyDataProviderTest.php
Original file line number Diff line number Diff line change
@@ -23,7 +23,7 @@ public static function dataProvider(): Generator
}

#[DataProvider('dataProvider')]
public function test($arg): void
public function test(string $arg): void
{
}
}
2 changes: 1 addition & 1 deletion tests/_files/DuplicateKeyDataProvidersTest.php
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ public static function dataProvider2(): iterable

#[DataProvider('dataProvider1')]
#[DataProvider('dataProvider2')]
public function test($value): void
public function test(int $value): void
{
$this->assertSame(2, $value);
}
29 changes: 29 additions & 0 deletions tests/_files/InvalidKeyDataProviderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\TestFixture;

use Generator;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;

final class InvalidKeyDataProviderTest extends TestCase
{
public static function dataProvider(): Generator
{
yield true => [true];

yield false => [false];
}

#[DataProvider('dataProvider')]
public function test(bool $arg): void
{
}
}
2 changes: 1 addition & 1 deletion tests/end-to-end/event/data-provider-duplicate-key.phpt
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ Data Provider Method Called (PHPUnit\TestFixture\Event\DataProviderDuplicateKeyT
Data Provider Method Finished for PHPUnit\TestFixture\Event\DataProviderDuplicateKeyTest::testSomething:
- PHPUnit\TestFixture\Event\DataProviderDuplicateKeyTest::provider
Test Triggered PHPUnit Error (PHPUnit\TestFixture\Event\DataProviderDuplicateKeyTest::testSomething)
The data provider specified for PHPUnit\TestFixture\Event\DataProviderDuplicateKeyTest::testSomething is invalid
The data provider provider specified for PHPUnit\TestFixture\Event\DataProviderDuplicateKeyTest::testSomething is invalid
The key "key" has already been defined by a previous data provider
Test Runner Triggered Warning (No tests found in class "PHPUnit\TestFixture\Event\DataProviderDuplicateKeyTest".)
Test Suite Loaded (0 tests)
2 changes: 1 addition & 1 deletion tests/end-to-end/event/data-provider-empty.phpt
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ Data Provider Method Called (PHPUnit\TestFixture\Event\EmptyDataProviderTest::pr
Data Provider Method Finished for PHPUnit\TestFixture\Event\EmptyDataProviderTest::testCase:
- PHPUnit\TestFixture\Event\EmptyDataProviderTest::providerMethod
Test Triggered PHPUnit Error (PHPUnit\TestFixture\Event\EmptyDataProviderTest::testCase)
The data provider specified for PHPUnit\TestFixture\Event\EmptyDataProviderTest::testCase is invalid
The data provider providerMethod specified for PHPUnit\TestFixture\Event\EmptyDataProviderTest::testCase is invalid
Empty data set provided by data provider
Test Runner Triggered Warning (No tests found in class "PHPUnit\TestFixture\Event\EmptyDataProviderTest".)
Test Suite Loaded (0 tests)
2 changes: 1 addition & 1 deletion tests/end-to-end/event/data-provider-exception.phpt
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ Data Provider Method Called (PHPUnit\TestFixture\Event\ExceptionInDataProviderTe
Data Provider Method Finished for PHPUnit\TestFixture\Event\ExceptionInDataProviderTest::testOne:
- PHPUnit\TestFixture\Event\ExceptionInDataProviderTest::provider
Test Triggered PHPUnit Error (PHPUnit\TestFixture\Event\ExceptionInDataProviderTest::testOne)
The data provider specified for PHPUnit\TestFixture\Event\ExceptionInDataProviderTest::testOne is invalid
The data provider provider specified for PHPUnit\TestFixture\Event\ExceptionInDataProviderTest::testOne is invalid
message
Test Runner Triggered Warning (No tests found in class "PHPUnit\TestFixture\Event\ExceptionInDataProviderTest".)
Test Suite Loaded (0 tests)
2 changes: 1 addition & 1 deletion tests/end-to-end/event/data-provider-expects-argument.phpt
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ Data Provider Method Called (PHPUnit\TestFixture\Event\ArgumentDataProviderTest:
Data Provider Method Finished for PHPUnit\TestFixture\Event\ArgumentDataProviderTest::testSuccess:
- PHPUnit\TestFixture\Event\ArgumentDataProviderTest::values
Test Triggered PHPUnit Error (PHPUnit\TestFixture\Event\ArgumentDataProviderTest::testSuccess)
The data provider specified for PHPUnit\TestFixture\Event\ArgumentDataProviderTest::testSuccess is invalid
The data provider values specified for PHPUnit\TestFixture\Event\ArgumentDataProviderTest::testSuccess is invalid
Data Provider method PHPUnit\TestFixture\Event\ArgumentDataProviderTest::values() expects an argument
Test Runner Triggered Warning (No tests found in class "PHPUnit\TestFixture\Event\ArgumentDataProviderTest".)
Test Suite Loaded (0 tests)
2 changes: 1 addition & 1 deletion tests/end-to-end/event/data-provider-not-public.phpt
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ Data Provider Method Called (PHPUnit\TestFixture\Event\PrivateDataProviderTest::
Data Provider Method Finished for PHPUnit\TestFixture\Event\PrivateDataProviderTest::testSuccess:
- PHPUnit\TestFixture\Event\PrivateDataProviderTest::values
Test Triggered PHPUnit Error (PHPUnit\TestFixture\Event\PrivateDataProviderTest::testSuccess)
The data provider specified for PHPUnit\TestFixture\Event\PrivateDataProviderTest::testSuccess is invalid
The data provider values specified for PHPUnit\TestFixture\Event\PrivateDataProviderTest::testSuccess is invalid
Data Provider method PHPUnit\TestFixture\Event\PrivateDataProviderTest::values() is not public
Test Runner Triggered Warning (No tests found in class "PHPUnit\TestFixture\Event\PrivateDataProviderTest".)
Test Suite Loaded (0 tests)
2 changes: 1 addition & 1 deletion tests/end-to-end/event/data-provider-not-static.phpt
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ Data Provider Method Called (PHPUnit\TestFixture\Event\DynamicDataProviderTest::
Data Provider Method Finished for PHPUnit\TestFixture\Event\DynamicDataProviderTest::testSuccess:
- PHPUnit\TestFixture\Event\DynamicDataProviderTest::values
Test Triggered PHPUnit Error (PHPUnit\TestFixture\Event\DynamicDataProviderTest::testSuccess)
The data provider specified for PHPUnit\TestFixture\Event\DynamicDataProviderTest::testSuccess is invalid
The data provider values specified for PHPUnit\TestFixture\Event\DynamicDataProviderTest::testSuccess is invalid
Data Provider method PHPUnit\TestFixture\Event\DynamicDataProviderTest::values() is not static
Test Runner Triggered Warning (No tests found in class "PHPUnit\TestFixture\Event\DynamicDataProviderTest".)
Test Suite Loaded (0 tests)
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ Data Provider Method Called (PHPUnit\TestFixture\Event\InvalidDataProviderWithOn
Data Provider Method Finished for PHPUnit\TestFixture\Event\InvalidDataProviderWithOneTestPassingTest::testOne:
- PHPUnit\TestFixture\Event\InvalidDataProviderWithOneTestPassingTest::provider
Test Triggered PHPUnit Error (PHPUnit\TestFixture\Event\InvalidDataProviderWithOneTestPassingTest::testOne)
The data provider specified for PHPUnit\TestFixture\Event\InvalidDataProviderWithOneTestPassingTest::testOne is invalid
The data provider provider specified for PHPUnit\TestFixture\Event\InvalidDataProviderWithOneTestPassingTest::testOne is invalid
Data set #0 is invalid, expected array but got int
Test Suite Loaded (1 test)
Test Runner Started
2 changes: 1 addition & 1 deletion tests/end-to-end/event/invalid-data-provider.phpt
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ Data Provider Method Called (PHPUnit\TestFixture\Event\InvalidDataProviderTest::
Data Provider Method Finished for PHPUnit\TestFixture\Event\InvalidDataProviderTest::testOne:
- PHPUnit\TestFixture\Event\InvalidDataProviderTest::provider
Test Triggered PHPUnit Error (PHPUnit\TestFixture\Event\InvalidDataProviderTest::testOne)
The data provider specified for PHPUnit\TestFixture\Event\InvalidDataProviderTest::testOne is invalid
The data provider provider specified for PHPUnit\TestFixture\Event\InvalidDataProviderTest::testOne is invalid
Data set #0 is invalid, expected array but got int
Test Runner Triggered Warning (No tests found in class "PHPUnit\TestFixture\Event\InvalidDataProviderTest".)
Test Suite Loaded (0 tests)
4 changes: 2 additions & 2 deletions tests/end-to-end/regression/2137-filter.phpt
Original file line number Diff line number Diff line change
@@ -18,13 +18,13 @@ Runtime: %s
There were 2 PHPUnit errors:

1) PHPUnit\TestFixture\Issue2137Test::testBrandService
The data provider specified for PHPUnit\TestFixture\Issue2137Test::testBrandService is invalid
The data provider provideBrandService specified for PHPUnit\TestFixture\Issue2137Test::testBrandService is invalid
Data set #0 is invalid, expected array but got stdClass

%s:%d

2) PHPUnit\TestFixture\Issue2137Test::testSomethingElseInvalid
The data provider specified for PHPUnit\TestFixture\Issue2137Test::testSomethingElseInvalid is invalid
The data provider provideBrandService specified for PHPUnit\TestFixture\Issue2137Test::testSomethingElseInvalid is invalid
Data set #0 is invalid, expected array but got stdClass

%s:%d
4 changes: 2 additions & 2 deletions tests/end-to-end/regression/2137-no_filter.phpt
Original file line number Diff line number Diff line change
@@ -16,13 +16,13 @@ Runtime: %s
There were 2 PHPUnit errors:

1) PHPUnit\TestFixture\Issue2137Test::testBrandService
The data provider specified for PHPUnit\TestFixture\Issue2137Test::testBrandService is invalid
The data provider provideBrandService specified for PHPUnit\TestFixture\Issue2137Test::testBrandService is invalid
Data set #0 is invalid, expected array but got stdClass

%s:%d

2) PHPUnit\TestFixture\Issue2137Test::testSomethingElseInvalid
The data provider specified for PHPUnit\TestFixture\Issue2137Test::testSomethingElseInvalid is invalid
The data provider provideBrandService specified for PHPUnit\TestFixture\Issue2137Test::testSomethingElseInvalid is invalid
Data set #0 is invalid, expected array but got stdClass

%s:%d
2 changes: 1 addition & 1 deletion tests/end-to-end/regression/498.phpt
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ Runtime: %s
There was 1 PHPUnit error:

1) PHPUnit\TestFixture\Issue498Test::shouldBeFalse
The data provider specified for PHPUnit\TestFixture\Issue498Test::shouldBeFalse is invalid
The data provider shouldBeFalseDataProvider specified for PHPUnit\TestFixture\Issue498Test::shouldBeFalse is invalid
Can't create the data

%s:%d
2 changes: 1 addition & 1 deletion tests/end-to-end/regression/5138.phpt
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ Configuration: %s
There was 1 PHPUnit error:

1) PHPUnit\TestFixture\Issue5138Test::testOne
The data provider specified for PHPUnit\TestFixture\Issue5138Test::testOne is invalid
The data provider provideData specified for PHPUnit\TestFixture\Issue5138Test::testOne is invalid
message

%s:%d
2 changes: 1 addition & 1 deletion tests/end-to-end/regression/5451.phpt
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ Time: %s, Memory: %s
There was 1 PHPUnit error:

1) PHPUnit\TestFixture\Issue5451\Issue5451Test::testWithErrorInDataProvider
The data provider specified for PHPUnit\TestFixture\Issue5451\Issue5451Test::testWithErrorInDataProvider is invalid
The data provider dataProviderThatTriggersPhpError specified for PHPUnit\TestFixture\Issue5451\Issue5451Test::testWithErrorInDataProvider is invalid
Call to a member function bar() on array

%s%eIssue5451Test.php:26
2 changes: 1 addition & 1 deletion tests/end-to-end/regression/5908-list-tests-xml.phpt
Original file line number Diff line number Diff line change
@@ -20,5 +20,5 @@ PHPUnit %s by Sebastian Bergmann and contributors.

There were errors:

The data provider specified for PHPUnit\TestFixture\Issue5908\Issue5908Test::testOne is invalid
The data provider provider specified for PHPUnit\TestFixture\Issue5908\Issue5908Test::testOne is invalid
message
2 changes: 1 addition & 1 deletion tests/end-to-end/regression/5908-list-tests.phpt
Original file line number Diff line number Diff line change
@@ -15,5 +15,5 @@ PHPUnit %s by Sebastian Bergmann and contributors.

There were errors:

The data provider specified for PHPUnit\TestFixture\Issue5908\Issue5908Test::testOne is invalid
The data provider provider specified for PHPUnit\TestFixture\Issue5908\Issue5908Test::testOne is invalid
message
2 changes: 1 addition & 1 deletion tests/end-to-end/regression/765.phpt
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ Time: %s, Memory: %s
There was 1 PHPUnit error:

1) PHPUnit\TestFixture\Issue765Test::testDependent
The data provider specified for PHPUnit\TestFixture\Issue765Test::testDependent is invalid
The data provider dependentProvider specified for PHPUnit\TestFixture\Issue765Test::testDependent is invalid
<no message>

%s:%d
3 changes: 2 additions & 1 deletion tests/unit/Framework/Exception/ExceptionTest.php
Original file line number Diff line number Diff line change
@@ -20,11 +20,12 @@ public function testExceptionSleep(): void
{
$actual = (new Exception)->__sleep();

$this->assertCount(5, $actual);
$this->assertCount(6, $actual);
$this->assertContains('serializableTrace', $actual);
$this->assertContains('message', $actual);
$this->assertContains('code', $actual);
$this->assertContains('file', $actual);
$this->assertContains('line', $actual);
$this->assertContains('method', $actual);
}
}
8 changes: 8 additions & 0 deletions tests/unit/Framework/TestCaseTest.php
Original file line number Diff line number Diff line change
@@ -11,7 +11,9 @@

use function sprintf;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProviderExternal;
use PHPUnit\Framework\Attributes\ExcludeGlobalVariableFromBackup;
use PHPUnit\TestFixture\TestBuilder\TestWithDataProvider;
use PHPUnit\TestFixture\TestWithDifferentNames;

#[CoversClass(TestCase::class)]
@@ -83,4 +85,10 @@ public function testGetNameReturnsMethodName(): void

$this->assertSame($methodName, $testCase->nameWithDataSet());
}

#[DataProviderExternal(TestWithDataProvider::class, 'provider')]
public function testKnowProviderName(): void
{
$this->assertEquals('provider', $this->getProviderName());
}
}
133 changes: 52 additions & 81 deletions tests/unit/Metadata/Api/DataProviderTest.php
Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@
use PHPUnit\Framework\TestCase;
use PHPUnit\TestFixture\DuplicateKeyDataProvidersTest;
use PHPUnit\TestFixture\DuplicateKeyDataProviderTest;
use PHPUnit\TestFixture\InvalidKeyDataProviderTest;
use PHPUnit\TestFixture\MultipleDataProviderTest;
use PHPUnit\TestFixture\TestWithAttributeDataProviderTest;
use PHPUnit\TestFixture\VariousIterableDataProviderTest;
@@ -30,60 +31,22 @@ final class DataProviderTest extends TestCase
*/
public function testMultipleDataProviders(): void
{
$dataSets = (new DataProvider)->providedData(MultipleDataProviderTest::class, 'testOne');

$this->assertCount(9, $dataSets);

$aCount = 0;
$bCount = 0;
$cCount = 0;

for ($i = 0; $i < 9; $i++) {
$aCount += $dataSets[$i][0] != null ? 1 : 0;
$bCount += $dataSets[$i][1] != null ? 1 : 0;
$cCount += $dataSets[$i][2] != null ? 1 : 0;
}

$this->assertEquals(3, $aCount);
$this->assertEquals(3, $bCount);
$this->assertEquals(3, $cCount);
$this->checkMultipleProviders('testOne');
}

public function testMultipleYieldIteratorDataProviders(): void
{
$dataSets = (new DataProvider)->providedData(MultipleDataProviderTest::class, 'testTwo');

$this->assertCount(9, $dataSets);

$aCount = 0;
$bCount = 0;
$cCount = 0;

for ($i = 0; $i < 9; $i++) {
$aCount += $dataSets[$i][0] != null ? 1 : 0;
$bCount += $dataSets[$i][1] != null ? 1 : 0;
$cCount += $dataSets[$i][2] != null ? 1 : 0;
}

$this->assertEquals(3, $aCount);
$this->assertEquals(3, $bCount);
$this->assertEquals(3, $cCount);
$this->checkMultipleProviders('testTwo');
}

public function testWithVariousIterableDataProvidersFromParent(): void
{
$dataSets = (new DataProvider)->providedData(VariousIterableDataProviderTest::class, 'testFromParent');

$this->assertEquals([
['J'],
['K'],
['L'],
['M'],
['N'],
['O'],
['P'],
['Q'],
['R'],
'asArrayProviderInParent' => [['J'], ['K'], ['L']],
'asIteratorProviderInParent' => [['M'], ['N'], ['O']],
'asTraversableProviderInParent' => [['P'], ['Q'], ['R']],
], $dataSets);
}

@@ -92,15 +55,9 @@ public function testWithVariousIterableDataProvidersInParent(): void
$dataSets = (new DataProvider)->providedData(VariousIterableDataProviderTest::class, 'testInParent');

$this->assertEquals([
['J'],
['K'],
['L'],
['M'],
['N'],
['O'],
['P'],
['Q'],
['R'],
'asArrayProviderInParent' => [['J'], ['K'], ['L']],
'asIteratorProviderInParent' => [['M'], ['N'], ['O']],
'asTraversableProviderInParent' => [['P'], ['Q'], ['R']],
], $dataSets);
}

@@ -109,15 +66,9 @@ public function testWithVariousIterableAbstractDataProviders(): void
$dataSets = (new DataProvider)->providedData(VariousIterableDataProviderTest::class, 'testAbstract');

$this->assertEquals([
['S'],
['T'],
['U'],
['V'],
['W'],
['X'],
['Y'],
['Z'],
['P'],
'asArrayProvider' => [['S'], ['T'], ['U']],
'asIteratorProvider' => [['V'], ['W'], ['X']],
'asTraversableProvider' => [['Y'], ['Z'], ['P']],
], $dataSets);
}

@@ -126,15 +77,9 @@ public function testWithVariousIterableStaticDataProviders(): void
$dataSets = (new DataProvider)->providedData(VariousIterableDataProviderTest::class, 'testStatic');

$this->assertEquals([
['A'],
['B'],
['C'],
['D'],
['E'],
['F'],
['G'],
['H'],
['I'],
'asArrayStaticProvider' => [['A'], ['B'], ['C']],
'asIteratorStaticProvider' => [['D'], ['E'], ['F']],
'asTraversableStaticProvider' => [['G'], ['H'], ['I']],
], $dataSets);
}

@@ -143,18 +88,21 @@ public function testWithVariousIterableNonStaticDataProviders(): void
$dataSets = (new DataProvider)->providedData(VariousIterableDataProviderTest::class, 'testNonStatic');

$this->assertEquals([
['S'],
['T'],
['U'],
['V'],
['W'],
['X'],
['Y'],
['Z'],
['P'],
'asArrayProvider' => [['S'], ['T'], ['U']],
'asIteratorProvider' => [['V'], ['W'], ['X']],
'asTraversableProvider' => [['Y'], ['Z'], ['P']],
], $dataSets);
}

public function testWithInvalidKeyDataProvider(): void
{
$this->expectException(InvalidDataProviderException::class);
$this->expectExceptionMessage('The key must be an integer or a string, bool given');

/* @noinspection UnusedFunctionResultInspection */
(new DataProvider)->providedData(InvalidKeyDataProviderTest::class, 'test');
}

public function testWithDuplicateKeyDataProvider(): void
{
$this->expectException(InvalidDataProviderException::class);
@@ -168,12 +116,12 @@ public function testTestWithAttribute(): void
{
$dataSets = (new DataProvider)->providedData(TestWithAttributeDataProviderTest::class, 'testWithAttribute');

$this->assertSame([
$this->assertSame(['testWith' => [
'foo' => ['a', 'b'],
'bar' => ['c', 'd'],
0 => ['e', 'f'],
1 => ['g', 'h'],
], $dataSets);
]], $dataSets);
}

public function testTestWithAttributeWithDuplicateKey(): void
@@ -193,4 +141,27 @@ public function testWithDuplicateKeyDataProviders(): void
/* @noinspection UnusedFunctionResultInspection */
(new DataProvider)->providedData(DuplicateKeyDataProvidersTest::class, 'test');
}

private function checkMultipleProviders(string $testMethodName): void
{
$dataSetsByProvider = (new DataProvider)->providedData(MultipleDataProviderTest::class, $testMethodName);
$this->assertCount(3, $dataSetsByProvider);

$counts = ['a' => 0, 'b' => 0, 'c' => 0];
$pos = ['a' => 0, 'b' => 1, 'c' => 2];

foreach ($dataSetsByProvider as $dataSet) {
for ($i = 0; $i < 3; $i++) {
foreach ($pos as $which => $where) {
if ($dataSet[$i][$where] !== null) {
$counts[$which]++;
}
}
}
}

$this->assertEquals(3, $counts['a']);
$this->assertEquals(3, $counts['b']);
$this->assertEquals(3, $counts['c']);
}
}