Skip to content

Commit

Permalink
Fix #19 - Print all error messages (#20)
Browse files Browse the repository at this point in the history
* Tested that duplicate warnings are reported once.

* Fixed reporting of warning/notice/deprecation so all unique issues are printed.

* Fixed carriage return generation when printing issues.

* Simplified issue hash.

* Removed unnecessary variable.

* Fixed carriage return generation when printing issues.

* Removed redundant silenced warning from capabilities test.

* Documented direct addition of Risky event trace to unique traces array.

* Separated test to test the interaction between silenced and non-silenced traces.

* Refactored test to reuse private method.

* Replaced inline warning in test with helper method.
  • Loading branch information
kAlvaro authored Nov 4, 2024
1 parent 3111fb5 commit 2d4895f
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 18 deletions.
24 changes: 17 additions & 7 deletions src/Printer.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,22 @@ final class Printer implements Tracer

private ?Throwable $throwable = null;

private ?Trace $trace = null;
/**
* @var array<string, Trace>
*/
private array $uniqueTraces = [];

private bool $flawless = true;

public function __construct(private readonly PipConfig $config)
{
}

private function addUniqueTrace(Trace $trace): void
{
$this->uniqueTraces[$trace->getIssueId()] = $trace;
}

public function trace(Event $event): void
{
if ($event instanceof ExecutionStarted) {
Expand Down Expand Up @@ -77,28 +85,29 @@ public function trace(Event $event): void
$this->status = TestStatus::Risky;
}

$this->trace = new Trace($event->message(), $event->test()->file(), $event->test()->line());
// No duplicate handling needed. Risky is a test status (rather than issue status) and it's final.
$this->uniqueTraces[] = new Trace(TestStatus::Risky, $event->message(), $event->test()->file(), $event->test()->line());
}
if ($event instanceof PhpNoticeTriggered) {
if (!$event->wasSuppressed()) {
$this->status ??= TestStatus::Notice;
}

$this->trace = Trace::fromEvent($event);
$this->addUniqueTrace(Trace::fromEvent($event));
}
if ($event instanceof PhpWarningTriggered) {
if (!$event->wasSuppressed()) {
$this->status ??= TestStatus::Warning;
}

$this->trace = Trace::fromEvent($event);
$this->addUniqueTrace(Trace::fromEvent($event));
}
if ($event instanceof PhpDeprecationTriggered) {
if (!$event->wasSuppressed()) {
$this->status ??= TestStatus::Deprecated;
}

$this->trace = Trace::fromEvent($event);
$this->addUniqueTrace(Trace::fromEvent($event));
}

if ($event instanceof Finished) {
Expand Down Expand Up @@ -135,10 +144,11 @@ public function trace(Event $event): void
$ms,
$performance,
$this->throwable,
$this->trace,
$this->uniqueTraces
));

$this->trace = $this->throwable = $this->status = null;
$this->uniqueTraces = [];
$this->throwable = $this->status = null;
}

if ($event instanceof \PHPUnit\Event\TestRunner\Finished) {
Expand Down
3 changes: 2 additions & 1 deletion src/TestResult.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ public function __construct(
public readonly int $testDurationMs,
public readonly TestPerformance $testPerformance,
public readonly ?Throwable $throwable,
public readonly ?Trace $trace,
/** @var array<string, Trace> */
public readonly array $uniqueTraces,
) {
}

Expand Down
25 changes: 16 additions & 9 deletions src/Theme/ClassicTheme.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use ScriptFUSION\Pip\TestPerformance;
use ScriptFUSION\Pip\TestResult;
use ScriptFUSION\Pip\TestStatus;
use ScriptFUSION\Pip\Trace;

final class ClassicTheme implements Theme
{
Expand Down Expand Up @@ -46,15 +47,21 @@ public function onTestFinished(TestResult $result): void
$throwable = $throwable->previous();
}

if ($result->trace && !$result->trace->suppressed) {
printf(
Color::colorize("fg-$statusColour", '%s%s: %s in %s on line %s%1$s%1$s'),
PHP_EOL,
$result->status->name,
$result->trace->message,
$result->trace->file,
$result->trace->line,
);
$firstIssue = true;
foreach ($result->uniqueTraces as $trace) {
if (!$trace->suppressed) {
$issueStatusColour = self::getColour($trace->issueStatus);
printf(
Color::colorize("fg-$issueStatusColour", '%s%s: %s in %s on line %d%s'),
$firstIssue ? PHP_EOL : '',
$trace->issueStatus->name,
$trace->message,
$trace->file,
$trace->line,
PHP_EOL . PHP_EOL,
);
$firstIssue = false;
}
}
}

Expand Down
28 changes: 27 additions & 1 deletion src/Trace.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
final class Trace
{
public function __construct(
public readonly TestStatus $issueStatus,
public readonly string $message,
public readonly string $file,
public readonly int $line,
Expand All @@ -18,6 +19,31 @@ public function __construct(

public static function fromEvent(PhpWarningTriggered|PhpNoticeTriggered|PhpDeprecationTriggered $event): self
{
return new self($event->message(), $event->file(), $event->line(), $event->wasSuppressed());
return new self(
match (true) {
$event instanceof PhpWarningTriggered => TestStatus::Warning,
$event instanceof PhpNoticeTriggered => TestStatus::Notice,
$event instanceof PhpDeprecationTriggered => TestStatus::Deprecated,
},
$event->message(),
$event->file(),
$event->line(),
$event->wasSuppressed(),
);
}

/**
* Key to identify identical issues, using the same rules as PHPUnit.
*
* @see \PHPUnit\TestRunner\TestResult\Collector::issueId
*/
public function getIssueId(): string
{
return sprintf(
'%s:%s:%s',
$this->file,
$this->line,
$this->message,
);
}
}
49 changes: 49 additions & 0 deletions test/CapabilitiesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,55 @@ public function testSilencedDeprecation(): void
self::assertTrue(true);
}

private function triggerWarning(): void
{
foreach (1 as $n) {}
}

public function testDuplicateWarningsA(): void
{
$this->triggerWarning();

self::assertTrue(true);
}

public function testDuplicateWarningsB(): void
{
$this->triggerWarning();
$this->triggerWarning();
$this->triggerWarning();

foreach (1 as $n) {}

self::assertTrue(true);
}

public function testDuplicateWarningsC(): void
{
self::assertTrue(true);
}

public function testMixedSeverities(): void
{
// Notice.
$foo = &self::provideData();
$this->triggerWarning();
// Deprecated.
trim(null);

self::assertTrue(true);
}

public function testSilencedWarningNotAffectsStatus(): void
{
@$this->triggerWarning();

// Notice.
$foo = &self::provideData();

self::assertTrue(true);
}

#[DataProvider('provideData')]

public function testDataProvider(): void
Expand Down
32 changes: 32 additions & 0 deletions test/functional/duplicate warnings.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
--TEST--
PHPUnit only reports warnings with globally unique locations within executed tests.

--ARGS--
-c test --colors=always test/CapabilitiesTest.php --filter ::testDuplicateWarnings

--FILE_EXTERNAL--
../PHPUnit runner.php

--EXPECTF--
PHPUnit %s

Runtime: %s
Configuration: %s

33% W ScriptFUSIONTest\Pip\CapabilitiesTest::testDuplicateWarningsA (%d ms)

Warning: foreach() argument must be of type array|object, int given in %s%eCapabilitiesTest.php on line %d

 66% W ScriptFUSIONTest\Pip\CapabilitiesTest::testDuplicateWarningsB (%d ms)

Warning: foreach() argument must be of type array|object, int given in %s%eCapabilitiesTest.php on line %d

Warning: foreach() argument must be of type array|object, int given in %s%eCapabilitiesTest.php on line %d

100% . ScriptFUSIONTest\Pip\CapabilitiesTest::testDuplicateWarningsC (%d ms)


Time: %s
%A
OK, but %s!
Tests: 3, Assertions: 3, Warnings: 2.
30 changes: 30 additions & 0 deletions test/functional/mixed severities.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
--TEST--
When a test generates errors with different severities and silences some of them, first non-silenced error determines
overall test status and all non-silenced messages are shown.

--ARGS--
-c test --colors=always test/CapabilitiesTest.php --filter ::testMixedSeverities$

--FILE_EXTERNAL--
../PHPUnit runner.php

--EXPECTF--
PHPUnit %s

Runtime: %s
Configuration: %s

100% N ScriptFUSIONTest\Pip\CapabilitiesTest::testMixedSeverities (%d ms)

Notice: Only variables should be assigned by reference in %s%eCapabilitiesTest.php on line %d

Warning: foreach() argument must be of type array|object, int given in %s%eCapabilitiesTest.php on line %d

Deprecated: trim(): Passing null to parameter #1 ($string) of type string is deprecated in %s%eCapabilitiesTest.php on line %d



Time: %s
%A
OK, but %s!
Tests: 1, Assertions: 1, Warnings: 1, Deprecations: 1, Notices: 1.
25 changes: 25 additions & 0 deletions test/functional/status notice warning silenced.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
--TEST--
Test that first notice determines test status and prior silenced warning does not.

--ARGS--
-c test --colors=always test/CapabilitiesTest.php --filter ::testSilencedWarningNotAffectsStatus$

--FILE_EXTERNAL--
../PHPUnit runner.php

--EXPECTF--
PHPUnit %s

Runtime: %s
Configuration: %s

100% N ScriptFUSIONTest\Pip\CapabilitiesTest::testSilencedWarningNotAffectsStatus (%d ms)

Notice: Only variables should be assigned by reference in %s%eCapabilitiesTest.php on line %d



Time: %s
%A
OK, but %s!
Tests: 1, Assertions: 1, Notices: 1.

0 comments on commit 2d4895f

Please sign in to comment.