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 ;
11+ import io .cucumber .query .Repository ;
912
1013import java .io .File ;
1114import java .io .OutputStream ;
15+ import java .io .OutputStreamWriter ;
16+ import java .io .PrintWriter ;
1217import java .net .URI ;
1318import java .net .URISyntaxException ;
14- import java .util . ArrayList ;
15- import java .util .Collection ;
19+ import java .nio . charset . StandardCharsets ;
20+ import java .util .HashSet ;
1621import java .util .LinkedHashMap ;
1722import java .util .Map ;
23+ import java .util .Set ;
1824
1925import static io .cucumber .core .feature .FeatureWithLines .create ;
26+ import static io .cucumber .query .Repository .RepositoryFeature .INCLUDE_GHERKIN_DOCUMENT ;
27+ import static java .util .Objects .requireNonNull ;
2028
2129/**
2230 * Formatter for reporting all failed test cases and print their locations
2331 * Failed means: results that make the exit code non-zero.
2432 */
2533public final class RerunFormatter implements ConcurrentEventListener {
2634
27- private final UTF8PrintWriter out ;
28- private final Map <URI , Collection <Integer >> featureAndFailedLinesMapping = new LinkedHashMap <>();
35+ private final PrintWriter writer ;
36+ private final Map <String , Set <Integer >> featureAndFailedLinesMapping = new LinkedHashMap <>();
37+ private final Repository repository = Repository .builder ()
38+ .feature (INCLUDE_GHERKIN_DOCUMENT , true )
39+ .build ();
40+ private final Query query = new Query (repository );
2941
3042 public RerunFormatter (OutputStream out ) {
31- this .out = new UTF8PrintWriter (out );
43+ this .writer = createPrintWriter (out );
3244 }
3345
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 <>());
46+ private static PrintWriter createPrintWriter (OutputStream out ) {
47+ return new PrintWriter (
48+ new OutputStreamWriter (
49+ requireNonNull (out ),
50+ StandardCharsets .UTF_8 ));
6351 }
6452
6553 static URI relativize (URI uri ) {
@@ -79,4 +67,46 @@ static URI relativize(URI uri) {
7967 throw new IllegalArgumentException (e .getMessage (), e );
8068 }
8169 }
70+
71+ @ Override
72+ public void setEventPublisher (EventPublisher publisher ) {
73+ publisher .registerHandlerFor (Envelope .class , event -> {
74+ repository .update (event );
75+ event .getTestCaseFinished ().ifPresent (this ::handleTestCaseFinished );
76+ event .getTestRunFinished ().ifPresent (testRunFinished -> finishReport ());
77+ });
78+ }
79+
80+ private void handleTestCaseFinished (TestCaseFinished event ) {
81+ TestStepResultStatus testStepResultStatus = query .findMostSevereTestStepResultBy (event )
82+ .map (TestStepResult ::getStatus )
83+ // By definition
84+ .orElse (TestStepResultStatus .PASSED );
85+
86+ if (testStepResultStatus == TestStepResultStatus .PASSED
87+ || testStepResultStatus == TestStepResultStatus .SKIPPED ) {
88+ return ;
89+ }
90+
91+ query .findPickleBy (event ).ifPresent (pickle -> {
92+ Set <Integer > lines = featureAndFailedLinesMapping
93+ .computeIfAbsent (pickle .getUri (), s -> new HashSet <>());
94+ query .findLocationOf (pickle ).ifPresent (location -> {
95+ // TODO: Messages are silly
96+ lines .add ((int ) (long ) location .getLine ());
97+ });
98+ });
99+ }
100+
101+ private void finishReport () {
102+ for (Map .Entry <String , Set <Integer >> entry : featureAndFailedLinesMapping .entrySet ()) {
103+ String key = entry .getKey ();
104+ // TODO: Should these be relative?
105+ FeatureWithLines featureWithLines = create (relativize (URI .create (key )), entry .getValue ());
106+ writer .println (featureWithLines );
107+ }
108+
109+ writer .close ();
110+ }
111+
82112}
0 commit comments