Skip to content

Commit 5b2ff31

Browse files
smuufdg
andcommitted
Implemented console-lines mode which prints each test on separate line. (#443)
This is handy for environments with non-standard (buffered) handling of standard output, for example Github Actions (where a progress of tests cannot be seen until until end-of-line appears, which in standard `console` mode happens only when all tests finish) or Docker Compose logging output, where in standard `console` mode each finished test's dot is printed alone on separate line. Or the console-lines mode can be handy just to see a more detailed progress of tests in all environments, because it outputs something like this: ``` · 1/85 Framework/Assert.contains.phpt OK in 0.14 s · 2/85 CodeCoverage/PhpParser.parse.edge.phpt OK in 0.17 s · 3/85 CodeCoverage/PhpParser.parse.lines-of-code.phpt SKIPPED in 0.18 s · 4/85 CodeCoverage/PhpParser.parse.lines.phpt FAILED in 0.19 s ... ``` Also, "cider mode" now shows a lemon emoji for skipped tests. Co-authored-by: David Grudl <[email protected]>
1 parent 1271f4c commit 5b2ff31

File tree

5 files changed

+136
-10
lines changed

5 files changed

+136
-10
lines changed

readme.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,8 @@ Options:
223223
-s Show information about skipped tests.
224224
--stop-on-fail Stop execution upon the first failure.
225225
-j <num> Run <num> jobs in parallel (default: 8).
226-
-o <console|tap|junit|none> Specify output format.
226+
-o <console|console-lines|tap|junit|none>
227+
Specify output format.
227228
-w | --watch <path> Watch directory.
228229
-i | --info Show tests environment info and exit.
229230
--setup <path> Script for runner setup.

src/Runner/CliTester.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ private function loadOptions(): CommandLine
112112
-s Show information about skipped tests.
113113
--stop-on-fail Stop execution upon the first failure.
114114
-j <num> Run <num> jobs in parallel (default: 8).
115-
-o <console|tap|junit|log|none> (e.g. -o junit:output.xml)
115+
-o <console|console-lines|tap|junit|log|none> (e.g. -o junit:output.xml)
116116
Specify one or more output formats with optional file name.
117117
-w | --watch <path> Watch directory.
118118
-i | --info Show tests environment info and exit.
@@ -230,7 +230,13 @@ private function createRunner(): Runner
230230
foreach ($this->options['-o'] as $output) {
231231
[$format, $file] = $output;
232232
match ($format) {
233-
'console' => $runner->outputHandlers[] = new Output\ConsolePrinter($runner, (bool) $this->options['-s'], $file, (bool) $this->options['--cider']),
233+
'console', 'console-lines' => $runner->outputHandlers[] = new Output\ConsolePrinter(
234+
$runner,
235+
(bool) $this->options['-s'],
236+
$file,
237+
(bool) $this->options['--cider'],
238+
$format === 'console-lines',
239+
),
234240
'tap' => $runner->outputHandlers[] = new Output\TapPrinter($file),
235241
'junit' => $runner->outputHandlers[] = new Output\JUnitPrinter($file),
236242
'log' => $runner->outputHandlers[] = new Output\Logger($runner, $file),

src/Runner/Output/ConsolePrinter.php

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,16 @@ public function __construct(
3838
bool $displaySkipped = false,
3939
?string $file = null,
4040
bool $ciderMode = false,
41+
private bool $lineMode = false,
4142
) {
4243
$this->runner = $runner;
4344
$this->displaySkipped = $displaySkipped;
4445
$this->file = fopen($file ?: 'php://output', 'w');
45-
$this->symbols = [
46-
Test::Passed => $ciderMode ? Dumper::color('green', '🍎') : '.',
47-
Test::Skipped => 's',
48-
Test::Failed => $ciderMode ? Dumper::color('red', '🍎') : Dumper::color('white/red', 'F'),
49-
];
46+
$this->symbols = match (true) {
47+
$ciderMode => [Test::Passed => '🍏', Test::Skipped => 's', Test::Failed => '🍎'],
48+
$lineMode => [Test::Passed => Dumper::color('lime', 'OK'), Test::Skipped => Dumper::color('yellow', 'SKIP'), Test::Failed => Dumper::color('white/red', 'FAIL')],
49+
default => [Test::Passed => '.', Test::Skipped => 's', Test::Failed => Dumper::color('white/red', 'F')],
50+
};
5051
}
5152

5253

@@ -94,7 +95,12 @@ public function prepare(Test $test): void
9495
public function finish(Test $test): void
9596
{
9697
$this->results[$test->getResult()]++;
97-
fwrite($this->file, $this->symbols[$test->getResult()]);
98+
fwrite(
99+
$this->file,
100+
$this->lineMode
101+
? $this->generateFinishLine($test)
102+
: $this->symbols[$test->getResult()],
103+
);
98104

99105
$title = ($test->title ? "$test->title | " : '') . substr($test->getSignature(), strlen($this->baseDir));
100106
$message = ' ' . str_replace("\n", "\n ", trim((string) $test->message)) . "\n\n";
@@ -121,4 +127,43 @@ public function end(): void
121127

122128
$this->buffer = '';
123129
}
130+
131+
132+
private function generateFinishLine(Test $test): string
133+
{
134+
$result = $test->getResult();
135+
136+
$shortFilePath = str_replace($this->baseDir, '', $test->getFile());
137+
$shortDirPath = dirname($shortFilePath) . DIRECTORY_SEPARATOR;
138+
$basename = basename($shortFilePath);
139+
$fileText = $result === Test::Failed
140+
? Dumper::color('red', $shortDirPath) . Dumper::color('white/red', $basename)
141+
: Dumper::color('gray', $shortDirPath) . Dumper::color('silver', $basename);
142+
143+
$header = '· ';
144+
$titleText = $test->title
145+
? Dumper::color('fuchsia', " [$test->title]")
146+
: '';
147+
148+
// failed tests messages will be printed after all tests are finished
149+
$message = '';
150+
if ($result !== Test::Failed && $test->message) {
151+
$indent = str_repeat(' ', mb_strlen($header));
152+
$message = preg_match('#\n#', $test->message)
153+
? "\n$indent" . preg_replace('#\r?\n#', '\0' . $indent, $test->message)
154+
: Dumper::color('olive', "[$test->message]");
155+
}
156+
157+
return sprintf(
158+
"%s%s/%s %s%s %s %s %s\n",
159+
$header,
160+
array_sum($this->results),
161+
$this->count,
162+
$fileText,
163+
$titleText,
164+
$this->symbols[$result],
165+
Dumper::color('gray', sprintf('in %.2f s', $test->getDuration())),
166+
$message,
167+
);
168+
}
124169
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
%a% | %a% | 1 thread
2+
3+
· 1/11 .%ds%01-basic.fail.phptx FAIL in %f% s
4+
· 2/11 .%ds%01-basic.pass.phptx OK in %f% s
5+
· 3/11 .%ds%01-basic.skip.phptx SKIP in %f% s
6+
· 4/11 .%ds%02-title.fail.phptx [Title for output handlers] FAIL in %f% s
7+
· 5/11 .%ds%02-title.pass.phptx [Title for output handlers] OK in %f% s
8+
· 6/11 .%ds%02-title.skip.phptx [Title for output handlers] SKIP in %f% s
9+
· 7/11 .%ds%03-message.fail.phptx FAIL in %f% s
10+
· 8/11 .%ds%03-message.skip.phptx SKIP in %f% s
11+
Multi
12+
line
13+
message.
14+
· 9/11 .%ds%04-args.fail.phptx FAIL in %f% s
15+
· 10/11 .%ds%04-args.pass.phptx OK in %f% s
16+
· 11/11 .%ds%04-args.skip.phptx SKIP in %f% s
17+
Multi
18+
line
19+
message.
20+
21+
22+
-- FAILED: 01-basic.fail.phptx
23+
Multi
24+
line
25+
stdout.Failed:
26+
27+
in %a%01-basic.fail.phptx(%d%) Tester\Assert::fail('');
28+
29+
STDERR:
30+
Multi
31+
line
32+
stderr.
33+
34+
-- FAILED: Title for output handlers | 02-title.fail.phptx
35+
Multi
36+
line
37+
stdout.Failed:
38+
39+
in %a%02-title.fail.phptx(%d%) Tester\Assert::fail('');
40+
41+
STDERR:
42+
Multi
43+
line
44+
stderr.
45+
46+
-- FAILED: 03-message.fail.phptx
47+
Multi
48+
line
49+
stdout.Failed: Multi
50+
line
51+
message.
52+
53+
in %a%03-message.fail.phptx(%d%) Tester\Assert::fail("Multi\nline\nmessage.");
54+
55+
STDERR:
56+
Multi
57+
line
58+
stderr.
59+
60+
-- FAILED: 04-args.fail.phptx dataprovider=thisIsAVeryVeryVeryLongArgumentNameToTestHowOutputHandlersDealWithItsLengthInTheirOutputFormatting|%a%provider.ini
61+
Multi
62+
line
63+
stdout.Failed:
64+
65+
in %a%04-args.fail.phptx(%d%) Tester\Assert::fail('');
66+
67+
STDERR:
68+
Multi
69+
line
70+
stderr.
71+
72+
73+
FAILURES! (11 tests, 4 failures, 4 skipped, %a% seconds)

tests/RunnerOutput/OutputHandlers.phpt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,15 @@ $runner->setEnvironmentVariable(Tester\Environment::VariableColors, '0');
3232
$runner->paths[] = __DIR__ . '/cases/*.phptx';
3333
$runner->outputHandlers[] = new Output\ConsolePrinter($runner, false, $console = FileMock::create(''));
3434
$runner->outputHandlers[] = new Output\ConsolePrinter($runner, true, $consoleWithSkipped = FileMock::create(''));
35+
$runner->outputHandlers[] = new Output\ConsolePrinter($runner, false, $consoleLines = FileMock::create(''), false, true);
3536
$runner->outputHandlers[] = new Output\JUnitPrinter($jUnit = FileMock::create(''));
3637
$runner->outputHandlers[] = new Output\Logger($runner, $logger = FileMock::create(''));
3738
$runner->outputHandlers[] = new Output\TapPrinter($tap = FileMock::create(''));
3839
$runner->run();
3940

40-
4141
Assert::matchFile(__DIR__ . '/OutputHandlers.expect.console.txt', Dumper::removeColors(file_get_contents($console)));
4242
Assert::matchFile(__DIR__ . '/OutputHandlers.expect.consoleWithSkip.txt', Dumper::removeColors(file_get_contents($consoleWithSkipped)));
43+
Assert::matchFile(__DIR__ . '/OutputHandlers.expect.consoleLines.txt', Dumper::removeColors(file_get_contents($consoleLines)));
4344
Assert::matchFile(__DIR__ . '/OutputHandlers.expect.jUnit.xml', file_get_contents($jUnit));
4445
Assert::matchFile(__DIR__ . '/OutputHandlers.expect.logger.txt', file_get_contents($logger));
4546
Assert::matchFile(__DIR__ . '/OutputHandlers.expect.tap.txt', file_get_contents($tap));

0 commit comments

Comments
 (0)