@@ -77,6 +77,9 @@ public class TeamCityPlugin implements EventListener {
77
77
+ "[testFinished timestamp = '%s' duration = '%s' name = '%s']" ;
78
78
private static final String TEMPLATE_TEST_FAILED = TEAMCITY_PREFIX
79
79
+ "[testFailed timestamp = '%s' duration = '%s' message = '%s' details = '%s' name = '%s']" ;
80
+
81
+ private static final String TEMPLATE_TEST_COMPARISON_FAILED = TEAMCITY_PREFIX
82
+ + "[testFailed timestamp = '%s' duration = '%s' message = '%s' details = '%s' expected='%s' actual='%s' name = '%s']" ;
80
83
private static final String TEMPLATE_TEST_IGNORED = TEAMCITY_PREFIX
81
84
+ "[testIgnored timestamp = '%s' duration = '%s' message = '%s' name = '%s']" ;
82
85
@@ -101,6 +104,22 @@ public class TeamCityPlugin implements EventListener {
101
104
private static final Pattern ANNOTATION_GLUE_CODE_LOCATION_PATTERN = Pattern .compile ("^(.*)\\ .(.*)\\ ([^:]*\\ )" );
102
105
private static final Pattern LAMBDA_GLUE_CODE_LOCATION_PATTERN = Pattern .compile ("^(.*)\\ .(.*)\\ (.*:.*\\ )" );
103
106
107
+ private static final Pattern [] COMPARE_PATTERNS = new Pattern [] {
108
+ Pattern .compile ("expected: is \" (.*)\" \n \\ s*got: \" (.*)\" " ,
109
+ Pattern .DOTALL | Pattern .CASE_INSENSITIVE ),
110
+ Pattern .compile ("expected: is \" (.*)\" \n \\ s*but:\\ s+was \" (.*)\" " ,
111
+ Pattern .DOTALL | Pattern .CASE_INSENSITIVE ),
112
+ Pattern .compile ("expected:\\ s*(.*)\n \\ s*got:\\ s*(.*)" , Pattern .DOTALL | Pattern .CASE_INSENSITIVE ),
113
+ Pattern .compile ("expected same:<(.*)> was not:<(.*)>" , Pattern .DOTALL | Pattern .CASE_INSENSITIVE ),
114
+ Pattern .compile ("expected:\\ s*\" (.*)\" \n \\ s*but: was\\ s*\" (.*)\" " ,
115
+ Pattern .DOTALL | Pattern .CASE_INSENSITIVE ),
116
+ Pattern .compile ("expected:\\ s*(.*)\n \\ s*but: was\\ s*(.*)" , Pattern .DOTALL | Pattern .CASE_INSENSITIVE ),
117
+ Pattern .compile ("expected:\\ s*(.*)\\ s+but was:\\ s*(.*)" ,
118
+ Pattern .DOTALL | Pattern .CASE_INSENSITIVE ),
119
+ Pattern .compile ("expecting:\\ s+<(.*)> to be equal to:\\ s+<(.*)>\\ s+but was not" ,
120
+ Pattern .DOTALL | Pattern .CASE_INSENSITIVE )
121
+ };
122
+
104
123
private final PrintStream out ;
105
124
private final List <SnippetsSuggestedEvent > suggestions = new ArrayList <>();
106
125
private final Map <URI , Collection <Node >> parsedTestSources = new HashMap <>();
@@ -281,7 +300,16 @@ private void printTestStepFinished(TestStepFinished event) {
281
300
case AMBIGUOUS :
282
301
case FAILED : {
283
302
String details = printStackTrace (error );
284
- print (TEMPLATE_TEST_FAILED , timeStamp , duration , "Step failed" , details , name );
303
+ String message = error .getMessage ();
304
+ ComparisonFailureData comparisonFailureData = message != null
305
+ ? createExceptionNotification (message .trim ())
306
+ : null ;
307
+ if (comparisonFailureData != null ) {
308
+ print (TEMPLATE_TEST_COMPARISON_FAILED , timeStamp , duration , "Step failed" , details ,
309
+ comparisonFailureData .getExpected (), comparisonFailureData .getActual (), name );
310
+ } else {
311
+ print (TEMPLATE_TEST_FAILED , timeStamp , duration , "Step failed" , details , name );
312
+ }
285
313
break ;
286
314
}
287
315
default :
@@ -290,6 +318,27 @@ private void printTestStepFinished(TestStepFinished event) {
290
318
print (TEMPLATE_TEST_FINISHED , timeStamp , duration , name );
291
319
}
292
320
321
+ private static ComparisonFailureData createExceptionNotification (String message , Pattern pattern ) {
322
+ final Matcher matcher = pattern .matcher (message );
323
+ if (matcher .find () && matcher .end () == message .length ()) {
324
+ String expected = matcher .group (1 );
325
+ String actual = matcher .group (2 );
326
+ return new ComparisonFailureData (expected .replaceAll ("\\ \\ n" , "\n " ),
327
+ actual .replaceAll ("\\ \\ n" , "\n " ));
328
+ }
329
+ return null ;
330
+ }
331
+
332
+ private static ComparisonFailureData createExceptionNotification (String message ) {
333
+ for (Pattern pattern : COMPARE_PATTERNS ) {
334
+ ComparisonFailureData result = createExceptionNotification (message , pattern );
335
+ if (result != null ) {
336
+ return result ;
337
+ }
338
+ }
339
+ return null ;
340
+ }
341
+
293
342
private String extractName (TestStep step ) {
294
343
if (step instanceof PickleStepTestStep ) {
295
344
PickleStepTestStep pickleStepTestStep = (PickleStepTestStep ) step ;
@@ -420,4 +469,39 @@ private String escape(String source) {
420
469
.replace ("]" , "|]" );
421
470
}
422
471
472
+ private static class ComparisonFailureData {
473
+ private final String expected ;
474
+
475
+ private final String actual ;
476
+
477
+ ComparisonFailureData (String expected , String actual ) {
478
+ if (isWrappedWith (expected , '<' , '>' ) && isWrappedWith (actual , '<' , '>' )) {
479
+ expected = unwrap (expected );
480
+ actual = unwrap (actual );
481
+ }
482
+ if (isWrappedWith (expected , '[' , ']' ) && isWrappedWith (actual , '[' , ']' )) {
483
+ expected = unwrap (expected );
484
+ actual = unwrap (actual );
485
+ }
486
+ this .expected = expected ;
487
+ this .actual = actual ;
488
+ }
489
+
490
+ private static boolean isWrappedWith (String text , char startChar , char endChar ) {
491
+ return text != null && text .length () > 0 &&
492
+ text .charAt (0 ) == startChar && text .charAt (text .length () - 1 ) == endChar ;
493
+ }
494
+
495
+ private static String unwrap (String text ) {
496
+ return text .substring (1 , text .length () - 1 );
497
+ }
498
+
499
+ public String getExpected () {
500
+ return expected ;
501
+ }
502
+
503
+ public String getActual () {
504
+ return actual ;
505
+ }
506
+ }
423
507
}
0 commit comments