11package io .cucumber .core .plugin ;
22
33import io .cucumber .core .feature .FeatureWithLines ;
4+ import io .cucumber .messages .types .Envelope ;
5+ import io .cucumber .messages .types .TestCaseFinished ;
6+ import io .cucumber .messages .types .TestStepResult ;
7+ import io .cucumber .messages .types .TestStepResultStatus ;
48import io .cucumber .plugin .ConcurrentEventListener ;
59import io .cucumber .plugin .event .EventPublisher ;
6- import io .cucumber .plugin .event .TestCase ;
7- import io .cucumber .plugin .event .TestCaseFinished ;
8- import io .cucumber .plugin .event .TestRunFinished ;
10+ import io .cucumber .query .Query ;
911
1012import java .io .File ;
1113import java .io .OutputStream ;
14+ import java .io .OutputStreamWriter ;
15+ import java .io .PrintWriter ;
1216import java .net .URI ;
1317import java .net .URISyntaxException ;
14- import java .util . ArrayList ;
15- import java .util .Collection ;
18+ import java .nio . charset . StandardCharsets ;
19+ import java .util .HashSet ;
1620import java .util .LinkedHashMap ;
1721import java .util .Map ;
22+ import java .util .Set ;
1823
1924import static io .cucumber .core .feature .FeatureWithLines .create ;
25+ import static java .util .Objects .requireNonNull ;
2026
2127/**
2228 * Formatter for reporting all failed test cases and print their locations
2329 * Failed means: results that make the exit code non-zero.
2430 */
2531public final class RerunFormatter implements ConcurrentEventListener {
2632
27- private final UTF8PrintWriter out ;
28- private final Map <URI , Collection <Integer >> featureAndFailedLinesMapping = new LinkedHashMap <>();
33+ private final PrintWriter writer ;
34+ private final Map <String , Set <Integer >> featureAndFailedLinesMapping = new LinkedHashMap <>();
35+ private final Query query = new Query ();
2936
3037 public RerunFormatter (OutputStream out ) {
31- this .out = new UTF8PrintWriter (out );
38+ this .writer = createPrintWriter (out );
3239 }
3340
34- @ Override
35- public void setEventPublisher (EventPublisher publisher ) {
36- publisher .registerHandlerFor (TestCaseFinished .class , this ::handleTestCaseFinished );
37- publisher .registerHandlerFor (TestRunFinished .class , event -> finishReport ());
38- }
39-
40- private void handleTestCaseFinished (TestCaseFinished event ) {
41- if (!event .getResult ().getStatus ().isOk ()) {
42- recordTestFailed (event .getTestCase ());
43- }
44- }
45-
46- private void finishReport () {
47- for (Map .Entry <URI , Collection <Integer >> entry : featureAndFailedLinesMapping .entrySet ()) {
48- FeatureWithLines featureWithLines = create (relativize (entry .getKey ()), entry .getValue ());
49- out .println (featureWithLines .toString ());
50- }
51-
52- out .close ();
53- }
54-
55- private void recordTestFailed (TestCase testCase ) {
56- URI uri = testCase .getUri ();
57- Collection <Integer > failedTestCaseLines = getFailedTestCaseLines (uri );
58- failedTestCaseLines .add (testCase .getLocation ().getLine ());
59- }
60-
61- private Collection <Integer > getFailedTestCaseLines (URI uri ) {
62- return featureAndFailedLinesMapping .computeIfAbsent (uri , k -> new ArrayList <>());
41+ private static PrintWriter createPrintWriter (OutputStream out ) {
42+ return new PrintWriter (
43+ new OutputStreamWriter (
44+ requireNonNull (out ),
45+ StandardCharsets .UTF_8 ));
6346 }
6447
6548 static URI relativize (URI uri ) {
@@ -79,4 +62,46 @@ static URI relativize(URI uri) {
7962 throw new IllegalArgumentException (e .getMessage (), e );
8063 }
8164 }
65+
66+ @ Override
67+ public void setEventPublisher (EventPublisher publisher ) {
68+ publisher .registerHandlerFor (Envelope .class , event -> {
69+ query .update (event );
70+ event .getTestCaseFinished ().ifPresent (this ::handleTestCaseFinished );
71+ event .getTestRunFinished ().ifPresent (testRunFinished -> finishReport ());
72+ });
73+ }
74+
75+ private void handleTestCaseFinished (TestCaseFinished event ) {
76+ TestStepResultStatus testStepResultStatus = query .findMostSevereTestStepResultBy (event )
77+ .map (TestStepResult ::getStatus )
78+ // By definition
79+ .orElse (TestStepResultStatus .PASSED );
80+
81+ if (testStepResultStatus == TestStepResultStatus .PASSED
82+ || testStepResultStatus == TestStepResultStatus .SKIPPED ) {
83+ return ;
84+ }
85+
86+ query .findPickleBy (event ).ifPresent (pickle -> {
87+ Set <Integer > lines = featureAndFailedLinesMapping
88+ .computeIfAbsent (pickle .getUri (), s -> new HashSet <>());
89+ query .findLocationOf (pickle ).ifPresent (location -> {
90+ // TODO: Messages are silly
91+ lines .add ((int ) (long ) location .getLine ());
92+ });
93+ });
94+ }
95+
96+ private void finishReport () {
97+ for (Map .Entry <String , Set <Integer >> entry : featureAndFailedLinesMapping .entrySet ()) {
98+ String key = entry .getKey ();
99+ // TODO: Should these be relative?
100+ FeatureWithLines featureWithLines = create (relativize (URI .create (key )), entry .getValue ());
101+ writer .println (featureWithLines );
102+ }
103+
104+ writer .close ();
105+ }
106+
82107}
0 commit comments