Skip to content

Commit b301867

Browse files
staabmsebastianbergmann
authored andcommitted
Reference dataprovider label in error messages
1 parent a73ec49 commit b301867

21 files changed

+163
-53
lines changed

src/Framework/Exception/InvalidDataProviderException.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,39 @@
99
*/
1010
namespace PHPUnit\Framework;
1111

12+
use Throwable;
13+
1214
/**
1315
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
1416
*
1517
* @internal This class is not covered by the backward compatibility promise for PHPUnit
1618
*/
1719
final class InvalidDataProviderException extends Exception
1820
{
21+
private ?string $providerLabel = null;
22+
23+
public static function forException(Throwable $e, string $providerLabel): self
24+
{
25+
$exception = new self(
26+
$e->getMessage(),
27+
$e->getCode(),
28+
$e,
29+
);
30+
$exception->providerLabel = $providerLabel;
31+
32+
return $exception;
33+
}
34+
35+
public static function forProvider(string $message, string $providerLabel): self
36+
{
37+
$exception = new self($message);
38+
$exception->providerLabel = $providerLabel;
39+
40+
return $exception;
41+
}
42+
43+
public function getProviderLabel(): ?string
44+
{
45+
return $this->providerLabel;
46+
}
1947
}

src/Framework/TestBuilder.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use function assert;
1414
use PHPUnit\Metadata\Api\DataProvider;
1515
use PHPUnit\Metadata\Api\Groups;
16+
use PHPUnit\Metadata\Api\ProvidedData;
1617
use PHPUnit\Metadata\Api\Requirements;
1718
use PHPUnit\Metadata\BackupGlobals;
1819
use PHPUnit\Metadata\BackupStaticProperties;
@@ -76,7 +77,7 @@ public function build(ReflectionClass $theClass, string $methodName, array $grou
7677
/**
7778
* @param non-empty-string $methodName
7879
* @param class-string<TestCase> $className
79-
* @param array<array<mixed>> $data
80+
* @param array<ProvidedData> $data
8081
* @param array{backupGlobals: ?bool, backupGlobalsExcludeList: list<string>, backupStaticProperties: ?bool, backupStaticPropertiesExcludeList: array<string,list<string>>} $backupSettings
8182
* @param list<non-empty-string> $groups
8283
*/
@@ -94,7 +95,7 @@ private function buildDataProviderTestSuite(string $methodName, string $classNam
9495
foreach ($data as $_dataName => $_data) {
9596
$_test = new $className($methodName);
9697

97-
$_test->setData($_dataName, $_data);
98+
$_test->setData($_dataName, $_data->getData());
9899

99100
$this->configureTestCase(
100101
$_test,

src/Framework/TestSuite.php

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,23 @@ protected function addTestMethod(ReflectionClass $class, ReflectionMethod $metho
514514
try {
515515
$test = (new TestBuilder)->build($class, $methodName, $groups);
516516
} catch (InvalidDataProviderException $e) {
517+
if ($e->getProviderLabel() === null) {
518+
$message = sprintf(
519+
"The data provider specified for %s::%s is invalid\n%s",
520+
$className,
521+
$methodName,
522+
$this->exceptionToString($e),
523+
);
524+
} else {
525+
$message = sprintf(
526+
"The data provider %s specified for %s::%s is invalid\n%s",
527+
$e->getProviderLabel(),
528+
$className,
529+
$methodName,
530+
$this->exceptionToString($e),
531+
);
532+
}
533+
517534
Event\Facade::emitter()->testTriggeredPhpunitError(
518535
new TestMethod(
519536
$className,
@@ -527,12 +544,7 @@ protected function addTestMethod(ReflectionClass $class, ReflectionMethod $metho
527544
MetadataCollection::fromArray([]),
528545
Event\TestData\TestDataCollection::fromArray([]),
529546
),
530-
sprintf(
531-
"The data provider specified for %s::%s is invalid\n%s",
532-
$className,
533-
$methodName,
534-
$this->exceptionToString($e),
535-
),
547+
$message,
536548
);
537549

538550
return;

src/Metadata/Api/DataProvider.php

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
*
4141
* @throws InvalidDataProviderException
4242
*
43-
* @return ?array<array<mixed>>
43+
* @return ?array<ProvidedData>
4444
*/
4545
public function providedData(string $className, string $methodName): ?array
4646
{
@@ -67,14 +67,17 @@ public function providedData(string $className, string $methodName): ?array
6767
$testMethodNumberOfParameters = $method->getNumberOfParameters();
6868
$testMethodIsNonVariadic = !$method->isVariadic();
6969

70-
foreach ($data as $key => $value) {
70+
foreach ($data as $key => $providedData) {
71+
$value = $providedData->getData();
72+
7173
if (!is_array($value)) {
72-
throw new InvalidDataProviderException(
74+
throw InvalidDataProviderException::forProvider(
7375
sprintf(
7476
'Data set %s is invalid, expected array but got %s',
7577
$this->formatKey($key),
7678
get_debug_type($value),
7779
),
80+
$providedData->getProviderLabel(),
7881
);
7982
}
8083

@@ -111,7 +114,7 @@ public function providedData(string $className, string $methodName): ?array
111114
*
112115
* @throws InvalidDataProviderException
113116
*
114-
* @return array<array<mixed>>
117+
* @return array<ProvidedData>
115118
*/
116119
private function dataProvidedByMethods(string $className, string $methodName, MetadataCollection $dataProvider): array
117120
{
@@ -122,6 +125,7 @@ private function dataProvidedByMethods(string $className, string $methodName, Me
122125
foreach ($dataProvider as $_dataProvider) {
123126
assert($_dataProvider instanceof DataProviderMetadata);
124127

128+
$providerLabel = $_dataProvider->className() . '::' . $_dataProvider->methodName();
125129
$dataProviderMethod = new Event\Code\ClassMethod($_dataProvider->className(), $_dataProvider->methodName());
126130

127131
Event\Facade::emitter()->dataProviderMethodCalled(
@@ -135,32 +139,35 @@ private function dataProvidedByMethods(string $className, string $methodName, Me
135139
$method = new ReflectionMethod($_dataProvider->className(), $_dataProvider->methodName());
136140

137141
if (!$method->isPublic()) {
138-
throw new InvalidDataProviderException(
142+
throw InvalidDataProviderException::forProvider(
139143
sprintf(
140144
'Data Provider method %s::%s() is not public',
141145
$_dataProvider->className(),
142146
$_dataProvider->methodName(),
143147
),
148+
$providerLabel,
144149
);
145150
}
146151

147152
if (!$method->isStatic()) {
148-
throw new InvalidDataProviderException(
153+
throw InvalidDataProviderException::forProvider(
149154
sprintf(
150155
'Data Provider method %s::%s() is not static',
151156
$_dataProvider->className(),
152157
$_dataProvider->methodName(),
153158
),
159+
$providerLabel,
154160
);
155161
}
156162

157163
if ($method->getNumberOfParameters() > 0) {
158-
throw new InvalidDataProviderException(
164+
throw InvalidDataProviderException::forProvider(
159165
sprintf(
160166
'Data Provider method %s::%s() expects an argument',
161167
$_dataProvider->className(),
162168
$_dataProvider->methodName(),
163169
),
170+
$providerLabel,
164171
);
165172
}
166173

@@ -175,39 +182,37 @@ private function dataProvidedByMethods(string $className, string $methodName, Me
175182
...$methodsCalled,
176183
);
177184

178-
throw new InvalidDataProviderException(
179-
$e->getMessage(),
180-
$e->getCode(),
181-
$e,
182-
);
185+
throw InvalidDataProviderException::forException($e, $providerLabel);
183186
}
184187

185188
foreach ($data as $key => $value) {
186189
if (is_int($key)) {
187-
$result[] = $value;
190+
$result[] = new ProvidedData($providerLabel, $value);
188191
} elseif (is_string($key)) {
189192
if (array_key_exists($key, $result)) {
190193
Event\Facade::emitter()->dataProviderMethodFinished(
191194
$testMethod,
192195
...$methodsCalled,
193196
);
194197

195-
throw new InvalidDataProviderException(
198+
throw InvalidDataProviderException::forProvider(
196199
sprintf(
197200
'The key "%s" has already been defined by a previous data provider',
198201
$key,
199202
),
203+
$providerLabel,
200204
);
201205
}
202206

203-
$result[$key] = $value;
207+
$result[$key] = new ProvidedData($providerLabel, $value);
204208
} else {
205209
// @codeCoverageIgnoreStart
206-
throw new InvalidDataProviderException(
210+
throw InvalidDataProviderException::forProvider(
207211
sprintf(
208212
'The key must be an integer or a string, %s given',
209213
get_debug_type($key),
210214
),
215+
$providerLabel,
211216
);
212217
// @codeCoverageIgnoreEnd
213218
}
@@ -223,30 +228,33 @@ private function dataProvidedByMethods(string $className, string $methodName, Me
223228
}
224229

225230
/**
226-
* @return array<array<mixed>>
231+
* @return array<ProvidedData>
227232
*/
228233
private function dataProvidedByMetadata(MetadataCollection $testWith): array
229234
{
230235
$result = [];
231236

237+
$providerLabel = 'TestWith attribute';
238+
232239
foreach ($testWith as $_testWith) {
233240
assert($_testWith instanceof TestWith);
234241

235242
if ($_testWith->hasName()) {
236243
$key = $_testWith->name();
237244

238245
if (array_key_exists($key, $result)) {
239-
throw new InvalidDataProviderException(
246+
throw InvalidDataProviderException::forProvider(
240247
sprintf(
241248
'The key "%s" has already been defined by a previous TestWith attribute',
242249
$key,
243250
),
251+
$providerLabel,
244252
);
245253
}
246254

247-
$result[$key] = $_testWith->data();
255+
$result[$key] = new ProvidedData($providerLabel, $_testWith->data());
248256
} else {
249-
$result[] = $_testWith->data();
257+
$result[] = new ProvidedData($providerLabel, $_testWith->data());
250258
}
251259
}
252260

src/Metadata/Api/ProvidedData.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php declare(strict_types=1);
2+
/*
3+
* This file is part of PHPUnit.
4+
*
5+
* (c) Sebastian Bergmann <[email protected]>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
namespace PHPUnit\Metadata\Api;
11+
12+
final readonly class ProvidedData
13+
{
14+
public function __construct(
15+
private string $providerLabel,
16+
private mixed $data
17+
) {
18+
}
19+
20+
public function getData(): mixed
21+
{
22+
return $this->data;
23+
}
24+
25+
public function getProviderLabel(): string
26+
{
27+
return $this->providerLabel;
28+
}
29+
}

tests/end-to-end/event/data-provider-duplicate-key.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Data Provider Method Called (PHPUnit\TestFixture\Event\DataProviderDuplicateKeyT
1818
Data Provider Method Finished for PHPUnit\TestFixture\Event\DataProviderDuplicateKeyTest::testSomething:
1919
- PHPUnit\TestFixture\Event\DataProviderDuplicateKeyTest::provider
2020
Test Triggered PHPUnit Error (PHPUnit\TestFixture\Event\DataProviderDuplicateKeyTest::testSomething)
21-
The data provider specified for PHPUnit\TestFixture\Event\DataProviderDuplicateKeyTest::testSomething is invalid
21+
The data provider PHPUnit\TestFixture\Event\DataProviderDuplicateKeyTest::provider specified for PHPUnit\TestFixture\Event\DataProviderDuplicateKeyTest::testSomething is invalid
2222
The key "key" has already been defined by a previous data provider
2323
Test Runner Triggered Warning (No tests found in class "PHPUnit\TestFixture\Event\DataProviderDuplicateKeyTest".)
2424
Test Suite Loaded (0 tests)

tests/end-to-end/event/data-provider-exception.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Data Provider Method Called (PHPUnit\TestFixture\Event\ExceptionInDataProviderTe
1818
Data Provider Method Finished for PHPUnit\TestFixture\Event\ExceptionInDataProviderTest::testOne:
1919
- PHPUnit\TestFixture\Event\ExceptionInDataProviderTest::provider
2020
Test Triggered PHPUnit Error (PHPUnit\TestFixture\Event\ExceptionInDataProviderTest::testOne)
21-
The data provider specified for PHPUnit\TestFixture\Event\ExceptionInDataProviderTest::testOne is invalid
21+
The data provider PHPUnit\TestFixture\Event\ExceptionInDataProviderTest::provider specified for PHPUnit\TestFixture\Event\ExceptionInDataProviderTest::testOne is invalid
2222
message
2323
Test Runner Triggered Warning (No tests found in class "PHPUnit\TestFixture\Event\ExceptionInDataProviderTest".)
2424
Test Suite Loaded (0 tests)

tests/end-to-end/event/data-provider-expects-argument.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Data Provider Method Called (PHPUnit\TestFixture\Event\ArgumentDataProviderTest:
1818
Data Provider Method Finished for PHPUnit\TestFixture\Event\ArgumentDataProviderTest::testSuccess:
1919
- PHPUnit\TestFixture\Event\ArgumentDataProviderTest::values
2020
Test Triggered PHPUnit Error (PHPUnit\TestFixture\Event\ArgumentDataProviderTest::testSuccess)
21-
The data provider specified for PHPUnit\TestFixture\Event\ArgumentDataProviderTest::testSuccess is invalid
21+
The data provider PHPUnit\TestFixture\Event\ArgumentDataProviderTest::values specified for PHPUnit\TestFixture\Event\ArgumentDataProviderTest::testSuccess is invalid
2222
Data Provider method PHPUnit\TestFixture\Event\ArgumentDataProviderTest::values() expects an argument
2323
Test Runner Triggered Warning (No tests found in class "PHPUnit\TestFixture\Event\ArgumentDataProviderTest".)
2424
Test Suite Loaded (0 tests)

tests/end-to-end/event/data-provider-not-public.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Data Provider Method Called (PHPUnit\TestFixture\Event\PrivateDataProviderTest::
1818
Data Provider Method Finished for PHPUnit\TestFixture\Event\PrivateDataProviderTest::testSuccess:
1919
- PHPUnit\TestFixture\Event\PrivateDataProviderTest::values
2020
Test Triggered PHPUnit Error (PHPUnit\TestFixture\Event\PrivateDataProviderTest::testSuccess)
21-
The data provider specified for PHPUnit\TestFixture\Event\PrivateDataProviderTest::testSuccess is invalid
21+
The data provider PHPUnit\TestFixture\Event\PrivateDataProviderTest::values specified for PHPUnit\TestFixture\Event\PrivateDataProviderTest::testSuccess is invalid
2222
Data Provider method PHPUnit\TestFixture\Event\PrivateDataProviderTest::values() is not public
2323
Test Runner Triggered Warning (No tests found in class "PHPUnit\TestFixture\Event\PrivateDataProviderTest".)
2424
Test Suite Loaded (0 tests)

tests/end-to-end/event/data-provider-not-static.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Data Provider Method Called (PHPUnit\TestFixture\Event\DynamicDataProviderTest::
1818
Data Provider Method Finished for PHPUnit\TestFixture\Event\DynamicDataProviderTest::testSuccess:
1919
- PHPUnit\TestFixture\Event\DynamicDataProviderTest::values
2020
Test Triggered PHPUnit Error (PHPUnit\TestFixture\Event\DynamicDataProviderTest::testSuccess)
21-
The data provider specified for PHPUnit\TestFixture\Event\DynamicDataProviderTest::testSuccess is invalid
21+
The data provider PHPUnit\TestFixture\Event\DynamicDataProviderTest::values specified for PHPUnit\TestFixture\Event\DynamicDataProviderTest::testSuccess is invalid
2222
Data Provider method PHPUnit\TestFixture\Event\DynamicDataProviderTest::values() is not static
2323
Test Runner Triggered Warning (No tests found in class "PHPUnit\TestFixture\Event\DynamicDataProviderTest".)
2424
Test Suite Loaded (0 tests)

0 commit comments

Comments
 (0)