11package io .cucumber .core .plugin ;
22
3+ import io .cucumber .messages .types .Location ;
4+ import io .cucumber .messages .types .TestStepFinished ;
5+ import io .cucumber .messages .types .TestStepResult ;
6+ import io .cucumber .messages .types .TestStepResultStatus ;
37import io .cucumber .plugin .ColorAware ;
4- import io .cucumber .plugin .ConcurrentEventListener ;
5- import io .cucumber .plugin .event .EventPublisher ;
6- import io .cucumber .plugin .event .PickleStepTestStep ;
7- import io .cucumber .plugin .event .Result ;
8- import io .cucumber .plugin .event .Status ;
9- import io .cucumber .plugin .event .TestCase ;
10- import io .cucumber .plugin .event .TestCaseFinished ;
11- import io .cucumber .plugin .event .TestRunFinished ;
12- import io .cucumber .plugin .event .TestRunStarted ;
13- import io .cucumber .plugin .event .TestStepFinished ;
8+ import io .cucumber .query .Query ;
149
1510import java .io .PrintStream ;
1611import java .text .DecimalFormat ;
1712import java .text .DecimalFormatSymbols ;
18- import java .time .Duration ;
19- import java .time .Instant ;
2013import java .util .ArrayList ;
14+ import java .util .Collections ;
2115import java .util .List ;
2216import java .util .Locale ;
17+ import java .util .Map ;
18+ import java .util .Optional ;
19+ import java .util .function .Function ;
20+ import java .util .stream .Collectors ;
2321
2422import static io .cucumber .core .plugin .Formats .ansi ;
2523import static io .cucumber .core .plugin .Formats .monochrome ;
2624import static java .util .Locale .ROOT ;
2725import static java .util .concurrent .TimeUnit .SECONDS ;
2826
29- class Stats implements ConcurrentEventListener , ColorAware {
27+ class Stats implements ColorAware {
3028
3129 private static final long ONE_SECOND = SECONDS .toNanos (1 );
3230 private static final long ONE_MINUTE = 60 * ONE_SECOND ;
33- private final SubCounts scenarioSubCounts = new SubCounts ();
34- private final SubCounts stepSubCounts = new SubCounts ();
31+ private final Query query ;
3532 private final Locale locale ;
36- private final List <TestCase > failedScenarios = new ArrayList <>();
37- private final List <TestCase > ambiguousScenarios = new ArrayList <>();
38- private final List <TestCase > pendingScenarios = new ArrayList <>();
39- private final List <TestCase > undefinedScenarios = new ArrayList <>();
4033 private final List <Throwable > errors = new ArrayList <>();
41- private Instant startTime = Instant .EPOCH ;
42- private Duration totalDuration = Duration .ZERO ;
4334 private Formats formats = ansi ();
4435
45- Stats (Locale locale ) {
36+ Stats (Query query , Locale locale ) {
37+ this .query = query ;
4638 this .locale = locale ;
4739 }
4840
@@ -51,102 +43,14 @@ public void setMonochrome(boolean monochrome) {
5143 formats = monochrome ? monochrome () : ansi ();
5244 }
5345
54- @ Override
55- public void setEventPublisher (EventPublisher publisher ) {
56- publisher .registerHandlerFor (TestRunStarted .class , this ::setStartTime );
57- publisher .registerHandlerFor (TestStepFinished .class , this ::addStepResult );
58- publisher .registerHandlerFor (TestCaseFinished .class , this ::addScenario );
59- publisher .registerHandlerFor (TestRunFinished .class , this ::setFinishTime );
60- }
61-
62- private void setStartTime (TestRunStarted event ) {
63- setStartTime (event .getInstant ());
64- }
65-
66- private void addStepResult (TestStepFinished event ) {
67- Result result = event .getResult ();
68- if (result .getError () != null ) {
69- addError (result .getError ());
70- }
71- if (event .getTestStep () instanceof PickleStepTestStep ) {
72- addStep (result .getStatus ());
73- }
74- }
75-
76- private void addScenario (TestCaseFinished event ) {
77- TestCase testCase = event .getTestCase ();
78- addScenario (event .getResult ().getStatus (), testCase );
79- }
80-
81- private void setFinishTime (TestRunFinished event ) {
82- setFinishTime (event .getInstant ());
83- }
84-
85- void setStartTime (Instant startTime ) {
86- this .startTime = startTime ;
87- }
88-
89- private void addError (Throwable error ) {
90- errors .add (error );
91- }
92-
93- void addStep (Status resultStatus ) {
94- addResultToSubCount (stepSubCounts , resultStatus );
95- }
96-
97- void addScenario (Status resultStatus , TestCase testCase ) {
98- addResultToSubCount (scenarioSubCounts , resultStatus );
99- switch (resultStatus ) {
100- case FAILED :
101- failedScenarios .add (testCase );
102- break ;
103- case AMBIGUOUS :
104- ambiguousScenarios .add (testCase );
105- break ;
106- case PENDING :
107- pendingScenarios .add (testCase );
108- break ;
109- case UNDEFINED :
110- undefinedScenarios .add (testCase );
111- break ;
112- default :
113- // intentionally left blank
114- }
115- }
116-
117- void setFinishTime (Instant finishTime ) {
118- this .totalDuration = Duration .between (startTime , finishTime );
119- }
120-
121- private void addResultToSubCount (SubCounts subCounts , Status resultStatus ) {
122- switch (resultStatus ) {
123- case FAILED :
124- subCounts .failed ++;
125- break ;
126- case AMBIGUOUS :
127- subCounts .ambiguous ++;
128- break ;
129- case PENDING :
130- subCounts .pending ++;
131- break ;
132- case UNDEFINED :
133- subCounts .undefined ++;
134- break ;
135- case SKIPPED :
136- subCounts .skipped ++;
137- break ;
138- default :
139- subCounts .passed ++;
140- }
141- }
142-
14346 public List <Throwable > getErrors () {
14447 return errors ;
14548 }
14649
14750 void printStats (PrintStream out ) {
14851 printNonZeroResultScenarios (out );
149- if (stepSubCounts .getTotal () == 0 ) {
52+ List <TestStepFinished > testStepFinished = query .findAllTestStepFinished ();
53+ if (testStepFinished .isEmpty ()) {
15054 out .println ("0 Scenarios" );
15155 out .println ("0 Steps" );
15256 } else {
@@ -157,30 +61,42 @@ void printStats(PrintStream out) {
15761 }
15862
15963 private void printStepCounts (PrintStream out ) {
160- out .print (stepSubCounts .getTotal ());
64+ List <io .cucumber .messages .types .TestStepFinished > testStepsFinished = query .findAllTestStepFinished ();
65+ Map <TestStepResultStatus , Long > testStepResultStatus = query .countMostSevereTestStepResultStatus ();
66+
67+ out .print (testStepsFinished .size ());
16168 out .print (" Steps (" );
162- printSubCounts (out , stepSubCounts );
69+ printSubCounts (out , testStepResultStatus );
16370 out .println (")" );
16471 }
16572
16673 private void printScenarioCounts (PrintStream out ) {
167- out .print (scenarioSubCounts .getTotal ());
74+ Map <TestStepResultStatus , Long > scenarioSubCounts = query .findAllTestCaseFinished ()
75+ .stream ()
76+ .map (query ::findMostSevereTestStepResultBy )
77+ .filter (Optional ::isPresent )
78+ .map (Optional ::get )
79+ .map (TestStepResult ::getStatus )
80+ .collect (Collectors .groupingBy (Function .identity (), Collectors .counting ()));
81+
82+ out .print (query .findAllTestCaseFinished ().size ());
16883 out .print (" Scenarios (" );
16984 printSubCounts (out , scenarioSubCounts );
17085 out .println (")" );
17186 }
17287
173- private void printSubCounts (PrintStream out , SubCounts subCounts ) {
88+ private void printSubCounts (PrintStream out , Map < TestStepResultStatus , Long > subCounts ) {
17489 boolean addComma = false ;
175- addComma = printSubCount (out , subCounts . failed , Status .FAILED , addComma );
176- addComma = printSubCount (out , subCounts . ambiguous , Status .AMBIGUOUS , addComma );
177- addComma = printSubCount (out , subCounts . skipped , Status .SKIPPED , addComma );
178- addComma = printSubCount (out , subCounts . pending , Status .PENDING , addComma );
179- addComma = printSubCount (out , subCounts . undefined , Status .UNDEFINED , addComma );
180- addComma = printSubCount (out , subCounts . passed , Status .PASSED , addComma );
90+ addComma = printSubCount (out , subCounts , TestStepResultStatus .FAILED , addComma );
91+ addComma = printSubCount (out , subCounts , TestStepResultStatus .AMBIGUOUS , addComma );
92+ addComma = printSubCount (out , subCounts , TestStepResultStatus .SKIPPED , addComma );
93+ addComma = printSubCount (out , subCounts , TestStepResultStatus .PENDING , addComma );
94+ addComma = printSubCount (out , subCounts , TestStepResultStatus .UNDEFINED , addComma );
95+ addComma = printSubCount (out , subCounts , TestStepResultStatus .PASSED , addComma );
18196 }
18297
183- private boolean printSubCount (PrintStream out , int count , Status type , boolean addComma ) {
98+ private boolean printSubCount (PrintStream out , Map <TestStepResultStatus , Long > subCounts , TestStepResultStatus type , boolean addComma ) {
99+ long count = subCounts .getOrDefault (type , 0L );
184100 if (count != 0 ) {
185101 if (addComma ) {
186102 out .print (", " );
@@ -193,50 +109,44 @@ private boolean printSubCount(PrintStream out, int count, Status type, boolean a
193109 }
194110
195111 private void printDuration (PrintStream out ) {
196- out .print (String .format ("%dm" , (totalDuration .toNanos () / ONE_MINUTE )));
197- DecimalFormat format = new DecimalFormat ("0.000" , new DecimalFormatSymbols (locale ));
198- out .println (format .format (((double ) (totalDuration .toNanos () % ONE_MINUTE ) / ONE_SECOND )) + "s" );
112+ query .findTestRunDuration ().ifPresent (duration -> {
113+ out .printf ("%dm" , (duration .toNanos () / ONE_MINUTE ));
114+ DecimalFormat format = new DecimalFormat ("0.000" , new DecimalFormatSymbols (locale ));
115+ out .println (format .format (((double ) (duration .toNanos () % ONE_MINUTE ) / ONE_SECOND )) + "s" );
116+ });
199117 }
200118
201119 private void printNonZeroResultScenarios (PrintStream out ) {
202- printScenarios (out , failedScenarios , Status .FAILED );
203- printScenarios (out , ambiguousScenarios , Status .AMBIGUOUS );
204- printScenarios (out , pendingScenarios , Status .PENDING );
205- printScenarios (out , undefinedScenarios , Status .UNDEFINED );
120+ Map <TestStepResultStatus , List <io .cucumber .messages .types .TestCaseFinished >> testCaseFinishedByStatus = query .findAllTestCaseFinished ()
121+ .stream ()
122+ .collect (Collectors .groupingBy (testCaseFinished -> query .findMostSevereTestStepResultBy (testCaseFinished ).map (TestStepResult ::getStatus ).orElse (TestStepResultStatus .UNKNOWN )));
123+
124+ printScenarios (out , testCaseFinishedByStatus , TestStepResultStatus .FAILED );
125+ printScenarios (out , testCaseFinishedByStatus , TestStepResultStatus .AMBIGUOUS );
126+ printScenarios (out , testCaseFinishedByStatus , TestStepResultStatus .PENDING );
127+ printScenarios (out , testCaseFinishedByStatus , TestStepResultStatus .UNDEFINED );
206128 }
207129
208- private void printScenarios (PrintStream out , List <TestCase > scenarios , Status type ) {
130+ private void printScenarios (PrintStream out , Map <TestStepResultStatus , List <io .cucumber .messages .types .TestCaseFinished >> testCaseFinishedByStatus , TestStepResultStatus type ) {
131+ List <io .cucumber .messages .types .TestCaseFinished > scenarios = testCaseFinishedByStatus .getOrDefault (type , Collections .emptyList ());
209132 Format format = formats .get (type .name ().toLowerCase (ROOT ));
210133 if (!scenarios .isEmpty ()) {
211134 out .println (format .text (firstLetterCapitalizedName (type ) + " scenarios:" ));
212135 }
213- for (TestCase scenario : scenarios ) {
214- String location = scenario .getUri () + ":" + scenario .getLocation ().getLine ();
215- out .println (location + " # " + scenario .getName ());
136+ for (io .cucumber .messages .types .TestCaseFinished testCaseFinished : scenarios ) {
137+ query .findPickleBy (testCaseFinished ).ifPresent (pickle -> {
138+ String location = pickle .getUri () + query .findLocationOf (pickle ).map (Location ::getLine ).map (line -> ":" + line ).orElse ("" );
139+ out .println (location + " # " + pickle .getName ());
140+ });
216141 }
217142 if (!scenarios .isEmpty ()) {
218143 out .println ();
219144 }
220145 }
221146
222- private String firstLetterCapitalizedName (Status status ) {
147+ private String firstLetterCapitalizedName (TestStepResultStatus status ) {
223148 String name = status .name ();
224- return name .substring (0 , 1 ) + name .substring (1 ).toLowerCase (ROOT );
225- }
226-
227- static class SubCounts {
228-
229- public int passed = 0 ;
230- public int failed = 0 ;
231- public int ambiguous = 0 ;
232- public int skipped = 0 ;
233- public int pending = 0 ;
234- public int undefined = 0 ;
235-
236- int getTotal () {
237- return passed + failed + ambiguous + skipped + pending + undefined ;
238- }
239-
149+ return name .charAt (0 ) + name .substring (1 ).toLowerCase (ROOT );
240150 }
241151
242152}
0 commit comments