2020 */
2121class ConsolePrinter implements Tester \Runner \OutputHandler
2222{
23- private Runner $ runner ;
24-
2523 /** @var resource */
2624 private $ file ;
27- private bool $ displaySkipped = false ;
28- private string $ buffer ;
25+
26+ /** @var list<string> */
27+ private array $ buffer ;
28+
29+ /**
30+ * @phpstan-var array<Alias_TestResultState, string>
31+ * @var array<int, string>
32+ */
33+ private array $ symbols ;
34+
35+ /**
36+ * @phpstan-var array<Alias_TestResultState, int>
37+ * @var array<int, string>
38+ */
39+ private array $ results = [
40+ Test::Passed => 0 ,
41+ Test::Skipped => 0 ,
42+ Test::Failed => 0 ,
43+ ];
44+
2945 private float $ time ;
3046 private int $ count ;
31- private array $ results ;
3247 private ?string $ baseDir ;
33- private array $ symbols ;
34-
48+ private int $ resultsCount = 0 ;
3549
50+ /**
51+ * @param bool $lineMode If `true`, reports each finished test on separate line.
52+ */
3653 public function __construct (
37- Runner $ runner ,
38- bool $ displaySkipped = false ,
54+ private Runner $ runner ,
55+ private bool $ displaySkipped = false ,
3956 ?string $ file = null ,
4057 bool $ ciderMode = false ,
58+ private bool $ lineMode = false ,
4159 ) {
4260 $ this ->runner = $ runner ;
4361 $ this ->displaySkipped = $ displaySkipped ;
4462 $ this ->file = fopen ($ file ?: 'php://output ' , 'w ' );
63+
4564 $ 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 ' ),
65+ Test::Passed => $ this -> lineMode ? Dumper::color ('lime ' , 'OK ' ) : '. ' ,
66+ Test::Skipped => $ this -> lineMode ? Dumper:: color ( ' yellow ' , ' SKIP ' ) : 's ' ,
67+ Test::Failed => $ this -> lineMode ? Dumper::color ('white/ red ' , 'FAIL ' ) : Dumper::color ('white/red ' , 'F ' ),
4968 ];
69+
70+ if ($ ciderMode ) {
71+ $ this ->symbols [Test::Passed] = '🍏 ' ;
72+ $ this ->symbols [Test::Skipped] = '🍋 ' ;
73+ $ this ->symbols [Test::Failed] = '🍎 ' ;
74+ }
5075 }
5176
5277
5378 public function begin (): void
5479 {
5580 $ this ->count = 0 ;
56- $ this ->buffer = '' ;
81+ $ this ->buffer = [] ;
5782 $ this ->baseDir = null ;
58- $ this ->results = [
59- Test::Passed => 0 ,
60- Test::Skipped => 0 ,
61- Test::Failed => 0 ,
62- ];
6383 $ this ->time = -microtime (true );
6484 fwrite ($ this ->file , $ this ->runner ->getInterpreter ()->getShortInfo ()
6585 . ' | ' . $ this ->runner ->getInterpreter ()->getCommandLine ()
@@ -94,15 +114,17 @@ public function prepare(Test $test): void
94114 public function finish (Test $ test ): void
95115 {
96116 $ this ->results [$ test ->getResult ()]++;
97- fwrite ($ this ->file , $ this ->symbols [$ test ->getResult ()]);
117+ $ this ->lineMode
118+ ? $ this ->printFinishedTestLine ($ test )
119+ : $ this ->printFinishedTestDot ($ test );
98120
99121 $ title = ($ test ->title ? "$ test ->title | " : '' ) . substr ($ test ->getSignature (), strlen ($ this ->baseDir ));
100122 $ message = ' ' . str_replace ("\n" , "\n " , trim ((string ) $ test ->message )) . "\n\n" ;
101123 $ message = preg_replace ('/^ $/m ' , '' , $ message );
102124 if ($ test ->getResult () === Test::Failed) {
103- $ this ->buffer . = Dumper::color ('red ' , "-- FAILED: $ title " ) . "\n$ message " ;
125+ $ this ->buffer [] = Dumper::color ('red ' , "-- FAILED: $ title " ) . "\n$ message " ;
104126 } elseif ($ test ->getResult () === Test::Skipped && $ this ->displaySkipped ) {
105- $ this ->buffer . = "-- Skipped: $ title \n$ message " ;
127+ $ this ->buffer [] = "-- Skipped: $ title \n$ message " ;
106128 }
107129 }
108130
@@ -111,14 +133,73 @@ public function end(): void
111133 {
112134 $ run = array_sum ($ this ->results );
113135 fwrite ($ this ->file , !$ this ->count ? "No tests found \n" :
114- "\n\n" . $ this ->buffer . "\n"
136+ "\n\n" . implode ( '' , $ this ->buffer ) . "\n"
115137 . ($ this ->results [Test::Failed] ? Dumper::color ('white/red ' ) . 'FAILURES! ' : Dumper::color ('white/green ' ) . 'OK ' )
116138 . " ( $ this ->count test " . ($ this ->count > 1 ? 's ' : '' ) . ', '
117139 . ($ this ->results [Test::Failed] ? $ this ->results [Test::Failed] . ' failure ' . ($ this ->results [Test::Failed] > 1 ? 's ' : '' ) . ', ' : '' )
118140 . ($ this ->results [Test::Skipped] ? $ this ->results [Test::Skipped] . ' skipped, ' : '' )
119141 . ($ this ->count !== $ run ? ($ this ->count - $ run ) . ' not run, ' : '' )
120142 . sprintf ('%0.1f ' , $ this ->time + microtime (true )) . ' seconds) ' . Dumper::color () . "\n" );
121143
122- $ this ->buffer = '' ;
144+ $ this ->buffer = [];
145+ $ this ->resultsCount = 0 ;
146+ }
147+
148+
149+ private function printFinishedTestDot (Test $ test ): void
150+ {
151+ fwrite ($ this ->file , $ this ->symbols [$ test ->getResult ()]);
152+ }
153+
154+
155+ private function printFinishedTestLine (Test $ test ): void
156+ {
157+ $ this ->resultsCount ++;
158+ $ result = $ test ->getResult ();
159+
160+ $ shortFilePath = str_replace ($ this ->baseDir , '' , $ test ->getFile ());
161+ $ shortDirPath = dirname ($ shortFilePath ) . DIRECTORY_SEPARATOR ;
162+ $ basename = basename ($ shortFilePath );
163+
164+ // Filename.
165+ if ($ result === Test::Failed) {
166+ $ fileText = Dumper::color ('red ' , $ shortDirPath ) . Dumper::color ('white/red ' , $ basename );
167+ } else {
168+ $ fileText = Dumper::color ('gray ' , $ shortDirPath ) . Dumper::color ('silver ' , $ basename );
169+ }
170+
171+ // Line header.
172+ $ header = "· " ;
173+ // Test's title.
174+ $ titleText = $ test ->title
175+ ? Dumper::color ('fuchsia ' , " [ $ test ->title ] " )
176+ : '' ;
177+
178+ // Print test's message only if it's not failed (those will be printed
179+ // after all tests are finished and will contain detailed info about the
180+ // failed test).
181+ $ message = '' ;
182+ if ($ result !== Test::Failed && $ test ->message ) {
183+ $ message = $ test ->message ;
184+ $ indent = str_repeat (' ' , mb_strlen ($ header ));
185+
186+ if (preg_match ('#\n# ' , $ message )) {
187+ $ message = "\n$ indent " . preg_replace ('#\r?\n# ' , '\0 ' . $ indent , $ message );
188+ } else {
189+ $ message = Dumper::color ('olive ' , "[ $ message] " );
190+ }
191+ }
192+
193+ $ output = sprintf (
194+ "%s%s %s %s %s %s \n" ,
195+ $ header ,
196+ "{$ this ->resultsCount }/ {$ this ->count }" ,
197+ "$ fileText {$ titleText }" ,
198+ $ this ->symbols [$ result ],
199+ Dumper::color ('gray ' , sprintf ("in %.2f s " , $ test ->getDuration ())),
200+ $ message ,
201+ );
202+
203+ fwrite ($ this ->file , $ output );
123204 }
124205}
0 commit comments