2424use PHPUnit \Event \InvalidArgumentException ;
2525use PHPUnit \Event \Telemetry \HRTime ;
2626use PHPUnit \Event \Test \BeforeFirstTestMethodErrored ;
27+ use PHPUnit \Event \Test \BeforeFirstTestMethodFailed ;
2728use PHPUnit \Event \Test \ConsideredRisky ;
2829use PHPUnit \Event \Test \Errored ;
2930use PHPUnit \Event \Test \Failed ;
3031use PHPUnit \Event \Test \Finished ;
3132use PHPUnit \Event \Test \MarkedIncomplete ;
32- use PHPUnit \Event \Test \Prepared ;
33+ use PHPUnit \Event \Test \PreparationStarted ;
3334use PHPUnit \Event \Test \Skipped ;
3435use PHPUnit \Event \TestSuite \Finished as TestSuiteFinished ;
3536use PHPUnit \Event \TestSuite \Skipped as TestSuiteSkipped ;
@@ -50,6 +51,9 @@ final class TeamCityLogger
5051 private bool $ isSummaryTestCountPrinted = false ;
5152 private ?HRTime $ time = null ;
5253 private ?int $ flowId = null ;
54+ private bool $ testStartedEmitted = false ;
55+ private bool $ prepared = false ;
56+ private bool $ preparationFailed = false ;
5357
5458 public function __construct (Printer $ printer , Facade $ facade )
5559 {
@@ -112,7 +116,7 @@ public function testSuiteFinished(TestSuiteFinished $event): void
112116 $ this ->writeMessage ('testSuiteFinished ' , $ parameters );
113117 }
114118
115- public function testPrepared ( Prepared $ event ): void
119+ public function testPreparationStarted ( PreparationStarted $ event ): void
116120 {
117121 $ test = $ event ->test ();
118122
@@ -133,7 +137,25 @@ public function testPrepared(Prepared $event): void
133137
134138 $ this ->writeMessage ('testStarted ' , $ parameters );
135139
136- $ this ->time = $ event ->telemetryInfo ()->time ();
140+ $ this ->time = $ event ->telemetryInfo ()->time ();
141+ $ this ->testStartedEmitted = true ;
142+ $ this ->prepared = false ;
143+ $ this ->preparationFailed = false ;
144+ }
145+
146+ public function testPreparationErrored (): void
147+ {
148+ $ this ->preparationFailed = true ;
149+ }
150+
151+ public function testPreparationFailed (): void
152+ {
153+ $ this ->preparationFailed = true ;
154+ }
155+
156+ public function testPrepared (): void
157+ {
158+ $ this ->prepared = true ;
137159 }
138160
139161 /**
@@ -156,6 +178,8 @@ public function testMarkedIncomplete(MarkedIncomplete $event): void
156178 'duration ' => $ this ->duration ($ event ),
157179 ],
158180 );
181+
182+ $ this ->writeTestFinishedIfPreparationDidNotComplete ($ event );
159183 }
160184
161185 /**
@@ -175,6 +199,8 @@ public function testSkipped(Skipped $event): void
175199 $ parameters ['duration ' ] = $ this ->duration ($ event );
176200
177201 $ this ->writeMessage ('testIgnored ' , $ parameters );
202+
203+ $ this ->writeTestFinishedIfPreparationDidNotComplete ($ event );
178204 }
179205
180206 /**
@@ -202,19 +228,23 @@ public function testSuiteSkipped(TestSuiteSkipped $event): void
202228 */
203229 public function beforeFirstTestMethodErrored (BeforeFirstTestMethodErrored $ event ): void
204230 {
205- if ($ this ->time === null ) {
206- $ this ->time = $ event ->telemetryInfo ()->time ();
207- }
208-
209- $ parameters = [
210- 'name ' => $ event ->testClassName (),
211- 'message ' => $ this ->message ($ event ->throwable ()),
212- 'details ' => $ this ->details ($ event ->throwable ()),
213- 'duration ' => $ this ->duration ($ event ),
214- ];
231+ $ this ->writeBeforeFirstTestMethodHookFailure (
232+ $ event ,
233+ $ event ->testClassName (),
234+ $ event ->throwable (),
235+ );
236+ }
215237
216- $ this ->writeMessage ('testFailed ' , $ parameters );
217- $ this ->writeMessage ('testSuiteFinished ' , $ parameters );
238+ /**
239+ * @throws InvalidArgumentException
240+ */
241+ public function beforeFirstTestMethodFailed (BeforeFirstTestMethodFailed $ event ): void
242+ {
243+ $ this ->writeBeforeFirstTestMethodHookFailure (
244+ $ event ,
245+ $ event ->testClassName (),
246+ $ event ->throwable (),
247+ );
218248 }
219249
220250 /**
@@ -235,6 +265,8 @@ public function testErrored(Errored $event): void
235265 'duration ' => $ this ->duration ($ event ),
236266 ],
237267 );
268+
269+ $ this ->writeTestFinishedIfPreparationDidNotComplete ($ event );
238270 }
239271
240272 /**
@@ -262,6 +294,8 @@ public function testFailed(Failed $event): void
262294 }
263295
264296 $ this ->writeMessage ('testFailed ' , $ parameters );
297+
298+ $ this ->writeTestFinishedIfPreparationDidNotComplete ($ event );
265299 }
266300
267301 /**
@@ -291,6 +325,10 @@ public function testConsideredRisky(ConsideredRisky $event): void
291325 */
292326 public function testFinished (Finished $ event ): void
293327 {
328+ if (!$ this ->testStartedEmitted ) {
329+ return ;
330+ }
331+
294332 $ this ->writeMessage (
295333 'testFinished ' ,
296334 [
@@ -299,7 +337,10 @@ public function testFinished(Finished $event): void
299337 ],
300338 );
301339
302- $ this ->time = null ;
340+ $ this ->time = null ;
341+ $ this ->testStartedEmitted = false ;
342+ $ this ->prepared = false ;
343+ $ this ->preparationFailed = false ;
303344 }
304345
305346 public function flush (): void
@@ -312,6 +353,9 @@ private function registerSubscribers(Facade $facade): void
312353 $ facade ->registerSubscribers (
313354 new TestSuiteStartedSubscriber ($ this ),
314355 new TestSuiteFinishedSubscriber ($ this ),
356+ new TestPreparationStartedSubscriber ($ this ),
357+ new TestPreparationErroredSubscriber ($ this ),
358+ new TestPreparationFailedSubscriber ($ this ),
315359 new TestPreparedSubscriber ($ this ),
316360 new TestFinishedSubscriber ($ this ),
317361 new TestErroredSubscriber ($ this ),
@@ -322,7 +366,78 @@ private function registerSubscribers(Facade $facade): void
322366 new TestConsideredRiskySubscriber ($ this ),
323367 new TestRunnerExecutionFinishedSubscriber ($ this ),
324368 new TestSuiteBeforeFirstTestMethodErroredSubscriber ($ this ),
369+ new TestSuiteBeforeFirstTestMethodFailedSubscriber ($ this ),
370+ );
371+ }
372+
373+ /**
374+ * @throws InvalidArgumentException
375+ */
376+ private function writeBeforeFirstTestMethodHookFailure (Event $ event , string $ name , Throwable $ throwable ): void
377+ {
378+ if ($ this ->time === null ) {
379+ $ this ->time = $ event ->telemetryInfo ()->time ();
380+ }
381+
382+ $ this ->writeMessage (
383+ 'testStarted ' ,
384+ [
385+ 'name ' => $ name ,
386+ ],
387+ );
388+
389+ $ parameters = [
390+ 'name ' => $ name ,
391+ 'message ' => $ this ->message ($ throwable ),
392+ 'details ' => $ this ->details ($ throwable ),
393+ 'duration ' => $ this ->duration ($ event ),
394+ ];
395+
396+ $ this ->writeMessage ('testFailed ' , $ parameters );
397+
398+ $ this ->writeMessage (
399+ 'testFinished ' ,
400+ [
401+ 'name ' => $ name ,
402+ 'duration ' => $ this ->duration ($ event ),
403+ ],
325404 );
405+
406+ $ this ->writeMessage (
407+ 'testSuiteFinished ' ,
408+ [
409+ 'name ' => $ name ,
410+ ],
411+ );
412+
413+ $ this ->time = null ;
414+ }
415+
416+ /**
417+ * @throws InvalidArgumentException
418+ */
419+ private function writeTestFinishedIfPreparationDidNotComplete (Errored |Failed |MarkedIncomplete |Skipped $ event ): void
420+ {
421+ if (!$ this ->testStartedEmitted ) {
422+ return ;
423+ }
424+
425+ if ($ this ->prepared && !$ this ->preparationFailed ) {
426+ return ;
427+ }
428+
429+ $ this ->writeMessage (
430+ 'testFinished ' ,
431+ [
432+ 'name ' => $ event ->test ()->name (),
433+ 'duration ' => $ this ->duration ($ event ),
434+ ],
435+ );
436+
437+ $ this ->time = null ;
438+ $ this ->testStartedEmitted = false ;
439+ $ this ->prepared = false ;
440+ $ this ->preparationFailed = false ;
326441 }
327442
328443 private function setFlowId (): void
0 commit comments