Skip to content

Commit 807fa5e

Browse files
authored
Merge branch 'main' into main
2 parents bbd5491 + 675f9d8 commit 807fa5e

File tree

53 files changed

+1237
-105
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1237
-105
lines changed

ChangeLog-13.1.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,18 @@ All notable changes of the PHPUnit 13.1 release series are documented in this fi
1111
* [#6523](https://github.com/sebastianbergmann/phpunit/issues/6523): Include `#[Group]` information in Open Test Reporting (OTR) XML logfile
1212
* [#6524](https://github.com/sebastianbergmann/phpunit/pull/6524): Report issues in Open Test Reporting (OTR) XML logfile
1313
* [#6526](https://github.com/sebastianbergmann/phpunit/pull/6526): Introduce `#[DataProviderClosure]` for static closures
14+
* Support for configuring HTML code coverage report options (colors, thresholds, custom CSS) in XML configuration file without requiring an `outputDirectory` attribute, allowing the output directory to be specified later with the `--coverage-html` CLI option
15+
* [#6530](https://github.com/sebastianbergmann/phpunit/issues/6530): Support for custom issue trigger resolvers that can be configured using `<issueTriggerResolvers>` in the XML configuration file
16+
* Support for configuring dark mode colors, progress bar colors, and breadcrumb colors for HTML code coverage reports in the XML configuration file
1417

1518
### Changed
1619

1720
* Improved failure message for mock object expectations
21+
* The HTML code coverage report now uses a more colorblind-friendly blue/amber/orange palette by default
1822

1923
### Deprecated
2024

2125
* [#6515](https://github.com/sebastianbergmann/phpunit/issues/6515): Deprecate the `--log-events-verbose-text <file>` CLI option
26+
* [#6537](https://github.com/sebastianbergmann/phpunit/issues/6537): Soft-deprecate `id()` and `after()` for mock object expectations
2227

2328
[13.1.0]: https://github.com/sebastianbergmann/phpunit/compare/13.0...main

DEPRECATIONS.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Deprecations
22

3+
## Soft Deprecations
4+
5+
This functionality is currently [soft-deprecated](https://phpunit.de/backward-compatibility.html#soft-deprecation):
6+
7+
### Writing Tests
8+
9+
#### Assertions, Constraints, and Expectations
10+
11+
| Issue | Description | Since | Replacement |
12+
|-------------------------------------------------------------------|---------------------------------------------------|--------|-------------|
13+
| [#6537](https://github.com/sebastianbergmann/phpunit/issues/6537) | `id()` and `after()` for mock object expectations | 13.1.0 | |
14+
315
## Hard Deprecations
416

517
This functionality is currently [hard-deprecated](https://phpunit.de/backward-compatibility.html#hard-deprecation):

composer.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

phpunit.xsd

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
</xs:complexType>
2525
</xs:element>
2626
<xs:element name="deprecationTrigger" type="deprecationTriggerType" minOccurs="0"/>
27+
<xs:element name="issueTriggerResolvers" type="issueTriggerResolversType" minOccurs="0"/>
2728
</xs:all>
2829
<xs:attribute name="baseline" type="xs:anyURI"/>
2930
<xs:attribute name="restrictNotices" type="xs:boolean" default="false"/>
@@ -332,14 +333,27 @@
332333
<xs:attribute name="threshold" type="xs:integer"/>
333334
</xs:complexType>
334335
<xs:complexType name="coverageReportHtmlType">
335-
<xs:attribute name="outputDirectory" type="xs:anyURI" use="required"/>
336+
<xs:attribute name="outputDirectory" type="xs:anyURI"/>
336337
<xs:attribute name="lowUpperBound" type="xs:integer" default="50"/>
337338
<xs:attribute name="highLowerBound" type="xs:integer" default="90"/>
338-
<xs:attribute name="colorSuccessLow" type="xs:string" default="#dff0d8"/>
339-
<xs:attribute name="colorSuccessMedium" type="xs:string" default="#c3e3b5"/>
340-
<xs:attribute name="colorSuccessHigh" type="xs:string" default="#99cb84"/>
341-
<xs:attribute name="colorWarning" type="xs:string" default="#fcf8e3"/>
342-
<xs:attribute name="colorDanger" type="xs:string" default="#f2dede"/>
339+
<xs:attribute name="colorSuccessLow" type="xs:string" default="#d6e6f2"/>
340+
<xs:attribute name="colorSuccessMedium" type="xs:string" default="#b3d1e8"/>
341+
<xs:attribute name="colorSuccessHigh" type="xs:string" default="#8cb4d5"/>
342+
<xs:attribute name="colorSuccessBar" type="xs:string" default="#1a73b4"/>
343+
<xs:attribute name="colorWarning" type="xs:string" default="#fdf0d5"/>
344+
<xs:attribute name="colorWarningBar" type="xs:string" default="#e5a100"/>
345+
<xs:attribute name="colorDanger" type="xs:string" default="#fad4c0"/>
346+
<xs:attribute name="colorDangerBar" type="xs:string" default="#d45500"/>
347+
<xs:attribute name="colorBreadcrumbs" type="xs:string" default="var(--bs-gray-200)"/>
348+
<xs:attribute name="colorSuccessLowDark" type="xs:string" default="#1e3550"/>
349+
<xs:attribute name="colorSuccessMediumDark" type="xs:string" default="#2d4f6e"/>
350+
<xs:attribute name="colorSuccessHighDark" type="xs:string" default="#2a4a6b"/>
351+
<xs:attribute name="colorSuccessBarDark" type="xs:string" default="#1560a0"/>
352+
<xs:attribute name="colorWarningDark" type="xs:string" default="#3d3010"/>
353+
<xs:attribute name="colorWarningBarDark" type="xs:string" default="#b88a00"/>
354+
<xs:attribute name="colorDangerDark" type="xs:string" default="#4a2a10"/>
355+
<xs:attribute name="colorDangerBarDark" type="xs:string" default="#b54400"/>
356+
<xs:attribute name="colorBreadcrumbsDark" type="xs:string" default="var(--bs-gray-800)"/>
343357
<xs:attribute name="customCssFile" type="xs:string"/>
344358
</xs:complexType>
345359
<xs:complexType name="coverageReportTextType">
@@ -359,4 +373,12 @@
359373
</xs:choice>
360374
</xs:sequence>
361375
</xs:complexType>
376+
<xs:complexType name="issueTriggerResolversType">
377+
<xs:sequence>
378+
<xs:element name="issueTriggerResolver" type="issueTriggerResolverType" minOccurs="0" maxOccurs="unbounded"/>
379+
</xs:sequence>
380+
</xs:complexType>
381+
<xs:complexType name="issueTriggerResolverType">
382+
<xs:attribute name="className" type="xs:string" use="required"/>
383+
</xs:complexType>
362384
</xs:schema>

src/Framework/MockObject/Runtime/Interface/InvocationMocker.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ public function withAnyParameters(): self;
3939
* @param non-empty-string $id
4040
*
4141
* @return $this
42+
*
43+
* @deprecated https://github.com/sebastianbergmann/phpunit/issues/6537
4244
*/
4345
public function id(string $id): self;
4446

@@ -48,6 +50,8 @@ public function id(string $id): self;
4850
* @param non-empty-string $id
4951
*
5052
* @return $this
53+
*
54+
* @deprecated https://github.com/sebastianbergmann/phpunit/issues/6537
5155
*/
5256
public function after(string $id): self;
5357
}

src/Framework/MockObject/Runtime/InvocationMockerImplementation.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ public function withAnyParameters(): InvocationMocker
7878
* @throws MatcherAlreadyRegisteredException
7979
*
8080
* @return $this
81+
*
82+
* @deprecated https://github.com/sebastianbergmann/phpunit/issues/6537
8183
*/
8284
public function id(string $id): InvocationMocker
8385
{
@@ -90,6 +92,8 @@ public function id(string $id): InvocationMocker
9092
* @param non-empty-string $id
9193
*
9294
* @return $this
95+
*
96+
* @deprecated https://github.com/sebastianbergmann/phpunit/issues/6537
9397
*/
9498
public function after(string $id): InvocationMocker
9599
{

src/Framework/TestRunner/templates/method.tpl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?php declare(strict_types=1);
22
use PHPUnit\Event\Facade;
3+
use PHPUnit\Runner\IssueTriggerResolver;
34
use PHPUnit\Runner\CodeCoverage;
45
use PHPUnit\Runner\ErrorHandler;
56
use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry;
@@ -69,6 +70,10 @@ function __phpunit_run_isolated_test()
6970

7071
ErrorHandler::instance()->useDeprecationTriggers($deprecationTriggers);
7172

73+
foreach (array_reverse($configuration->source()->issueTriggerResolvers()) as $className) {
74+
ErrorHandler::instance()->addIssueTriggerResolver(new $className);
75+
}
76+
7277
$test = new {className}('{methodName}');
7378

7479
$test->setData('{dataName}', unserialize('{data}'));

src/Runner/CodeCoverage.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,10 +349,23 @@ public function generateReports(Printer $printer, Configuration $configuration):
349349
),
350350
Colors::from(
351351
$configuration->coverageHtmlColorSuccessLow(),
352+
$configuration->coverageHtmlColorSuccessLowDark(),
352353
$configuration->coverageHtmlColorSuccessMedium(),
354+
$configuration->coverageHtmlColorSuccessMediumDark(),
353355
$configuration->coverageHtmlColorSuccessHigh(),
356+
$configuration->coverageHtmlColorSuccessHighDark(),
357+
$configuration->coverageHtmlColorSuccessBar(),
358+
$configuration->coverageHtmlColorSuccessBarDark(),
354359
$configuration->coverageHtmlColorWarning(),
360+
$configuration->coverageHtmlColorWarningDark(),
361+
$configuration->coverageHtmlColorWarningBar(),
362+
$configuration->coverageHtmlColorWarningBarDark(),
355363
$configuration->coverageHtmlColorDanger(),
364+
$configuration->coverageHtmlColorDangerDark(),
365+
$configuration->coverageHtmlColorDangerBar(),
366+
$configuration->coverageHtmlColorDangerBarDark(),
367+
$configuration->coverageHtmlColorBreadcrumbs(),
368+
$configuration->coverageHtmlColorBreadcrumbsDark(),
356369
),
357370
Thresholds::from(
358371
$configuration->coverageHtmlLowUpperBound(),

src/Runner/ErrorHandler.php

Lines changed: 55 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@
2525
use const E_USER_WARNING;
2626
use const E_WARNING;
2727
use function array_keys;
28+
use function array_unshift;
2829
use function array_values;
2930
use function assert;
31+
use function count;
3032
use function debug_backtrace;
3133
use function defined;
3234
use function error_reporting;
@@ -44,6 +46,8 @@
4446
use PHPUnit\Metadata\Parser\Registry as MetadataParserRegistry;
4547
use PHPUnit\Runner\Baseline\Baseline;
4648
use PHPUnit\Runner\Baseline\Issue;
49+
use PHPUnit\Runner\IssueTriggerResolver\DefaultResolver as DefaultIssueTriggerResolver;
50+
use PHPUnit\Runner\IssueTriggerResolver\Resolver as IssueTriggerResolver;
4751
use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry;
4852
use PHPUnit\TextUI\Configuration\SourceFilter;
4953
use PHPUnit\Util\ExcludeList;
@@ -80,6 +84,11 @@ final class ErrorHandler
8084
*/
8185
private ?array $deprecationTriggers = null;
8286

87+
/**
88+
* @var non-empty-list<IssueTriggerResolver>
89+
*/
90+
private array $issueTriggerResolvers;
91+
8392
public static function instance(): self
8493
{
8594
$source = ConfigurationRegistry::get()->source();
@@ -99,8 +108,9 @@ public static function instance(): self
99108

100109
private function __construct(bool $identifyIssueTrigger)
101110
{
102-
$this->excludeList = new ExcludeList;
103-
$this->identifyIssueTrigger = $identifyIssueTrigger;
111+
$this->excludeList = new ExcludeList;
112+
$this->identifyIssueTrigger = $identifyIssueTrigger;
113+
$this->issueTriggerResolvers = [new DefaultIssueTriggerResolver];
104114
}
105115

106116
/**
@@ -196,7 +206,7 @@ public function __invoke(int $errorNumber, string $errorString, string $errorFil
196206
$suppressed,
197207
$ignoredByBaseline,
198208
$ignoredByTest,
199-
$this->trigger($test, false, $errorFile),
209+
$this->trigger($test, false, $errorString, $errorFile),
200210
);
201211

202212
break;
@@ -210,7 +220,7 @@ public function __invoke(int $errorNumber, string $errorString, string $errorFil
210220
$suppressed,
211221
$ignoredByBaseline,
212222
$ignoredByTest,
213-
$this->trigger($test, true),
223+
$this->trigger($test, true, $errorString),
214224
$this->stackTrace(),
215225
);
216226

@@ -302,6 +312,11 @@ public function useDeprecationTriggers(array $deprecationTriggers): void
302312
$this->deprecationTriggers = $deprecationTriggers;
303313
}
304314

315+
public function addIssueTriggerResolver(IssueTriggerResolver $resolver): void
316+
{
317+
array_unshift($this->issueTriggerResolvers, $resolver);
318+
}
319+
305320
public function enterTestCaseContext(string $className, string $methodName): void
306321
{
307322
$this->testCaseContext = $this->testCaseContext($className, $methodName);
@@ -329,7 +344,7 @@ private function ignoredByBaseline(string $file, int $line, string $description)
329344
/**
330345
* @param null|non-empty-string $errorFile
331346
*/
332-
private function trigger(TestMethod $test, bool $isUserland, ?string $errorFile = null): IssueTrigger
347+
private function trigger(TestMethod $test, bool $isUserland, string $errorString, ?string $errorFile = null): IssueTrigger
333348
{
334349
if (!$this->identifyIssueTrigger) {
335350
return IssueTrigger::from(null, null);
@@ -343,26 +358,39 @@ private function trigger(TestMethod $test, bool $isUserland, ?string $errorFile
343358

344359
$trace = $this->filteredStackTrace();
345360

346-
return $this->triggerForUserlandDeprecation($test, $trace);
361+
return $this->triggerForUserlandDeprecation($test, $errorString, $trace);
347362
}
348363

349364
/**
350-
* @param list<array{file: string, line: int, class?: string, function?: string, type: string}> $trace
365+
* @param list<array{file?: string, line?: int, class?: class-string, function?: string, type?: string, args?: list<mixed>}> $trace
351366
*/
352-
private function triggerForUserlandDeprecation(TestMethod $test, array $trace): IssueTrigger
367+
private function triggerForUserlandDeprecation(TestMethod $test, string $message, array $trace): IssueTrigger
353368
{
354-
$callee = null;
355-
$caller = null;
369+
foreach ($this->issueTriggerResolvers as $resolver) {
370+
$result = $resolver->resolve($trace, $message);
356371

357-
if (isset($trace[0]['file'])) {
358-
$callee = $this->categorizeFile($trace[0]['file'], $test);
359-
}
372+
if ($result === null) {
373+
continue;
374+
}
375+
376+
$callee = null;
360377

361-
if (isset($trace[1]['file'])) {
362-
$caller = $this->categorizeFile($trace[1]['file'], $test);
378+
if ($result->hasCallee()) {
379+
$callee = $this->categorizeFile($result->callee(), $test);
380+
}
381+
382+
$caller = null;
383+
384+
if ($result->hasCaller()) {
385+
$caller = $this->categorizeFile($result->caller(), $test);
386+
}
387+
388+
return IssueTrigger::from($callee, $caller);
363389
}
364390

365-
return IssueTrigger::from($callee, $caller);
391+
// @codeCoverageIgnoreStart
392+
return IssueTrigger::from(null, null);
393+
// @codeCoverageIgnoreEnd
366394
}
367395

368396
/**
@@ -386,11 +414,13 @@ private function categorizeFile(string $file, TestMethod $test): Code
386414
}
387415

388416
/**
389-
* @return list<array{file: string, line: int, class?: string, function?: string, type: string}>
417+
* @return list<array{file: string, line: int, class?: string, function?: string, type: string, args?: list<mixed>}>
390418
*/
391419
private function filteredStackTrace(): array
392420
{
393-
$trace = $this->errorStackTrace();
421+
$ignoreArguments = count($this->issueTriggerResolvers) === 1;
422+
423+
$trace = $this->errorStackTrace($ignoreArguments);
394424

395425
if ($this->deprecationTriggers === null) {
396426
return array_values($trace);
@@ -446,11 +476,15 @@ private function guessDeprecationFrame(): ?array
446476
}
447477

448478
/**
449-
* @return list<array{file: string, line: ?int, class?: class-string, function?: string, type: string}>
479+
* @return list<array{file: string, line: ?int, class?: class-string, function?: string, type: string, args?: list<mixed>}>
450480
*/
451-
private function errorStackTrace(): array
481+
private function errorStackTrace(bool $ignoreArgs = true): array
452482
{
453-
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
483+
if ($ignoreArgs) {
484+
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
485+
} else {
486+
$trace = debug_backtrace();
487+
}
454488

455489
$i = 0;
456490

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 <sebastian@phpunit.de>
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\Runner\IssueTriggerResolver;
11+
12+
/**
13+
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
14+
*
15+
* @internal This class is not covered by the backward compatibility promise for PHPUnit
16+
*/
17+
final class DefaultResolver implements Resolver
18+
{
19+
/**
20+
* @param list<array{file?: string, line?: int, class?: class-string, function?: string, type?: string, args?: list<mixed>}> $trace
21+
*/
22+
public function resolve(array $trace, string $message): Resolution
23+
{
24+
return new Resolution(
25+
$trace[0]['file'] ?? null,
26+
$trace[1]['file'] ?? null,
27+
);
28+
}
29+
}

0 commit comments

Comments
 (0)