View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.surefire.common.junit4;
20  
21  import org.apache.maven.surefire.api.report.SafeThrowable;
22  import org.apache.maven.surefire.api.report.StackTraceWriter;
23  import org.apache.maven.surefire.api.util.internal.ClassMethod;
24  import org.apache.maven.surefire.report.SmartStackTraceParser;
25  import org.junit.runner.notification.Failure;
26  
27  import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.toClassMethod;
28  import static org.apache.maven.surefire.report.SmartStackTraceParser.stackTraceWithFocusOnClassAsString;
29  
30  /**
31   * Writes out a specific {@link org.junit.runner.notification.Failure} for
32   * surefire as a stacktrace.
33   *
34   * @author Karl M. Davis
35   */
36  public class JUnit4StackTraceWriter implements StackTraceWriter {
37      private final Failure junitFailure;
38  
39      /**
40       * Constructor.
41       *
42       * @param junitFailure the {@link Failure} that this will be operating on
43       */
44      public JUnit4StackTraceWriter(Failure junitFailure) {
45          this.junitFailure = junitFailure;
46      }
47  
48      /*
49       * (non-Javadoc)
50       *
51       * @see org.apache.maven.surefire.report.StackTraceWriter#writeTraceToString()
52       */
53      @Override
54      public String writeTraceToString() {
55          Throwable t = junitFailure.getException();
56          if (t != null) {
57              String originalTrace = junitFailure.getTrace();
58              if (isMultiLineExceptionMessage(t)) {
59                  // SUREFIRE-986
60                  StringBuilder builder = new StringBuilder(originalTrace);
61                  String exc = t.getClass().getName() + ": ";
62                  if (originalTrace.startsWith(exc)) {
63                      builder.insert(exc.length(), '\n');
64                  }
65                  return builder.toString();
66              }
67              return originalTrace;
68          }
69          return "";
70      }
71  
72      @Override
73      public String smartTrimmedStackTrace() {
74          Throwable exception = junitFailure.getException();
75          ClassMethod classMethod = toClassMethod(junitFailure.getDescription());
76          return exception == null
77                  ? junitFailure.getMessage()
78                  : new SmartStackTraceParser(classMethod.getClazz(), exception, classMethod.getMethod()).getString();
79      }
80  
81      /**
82       * At the moment, returns the same as {@link #writeTraceToString()}.
83       *
84       * @see StackTraceWriter#writeTrimmedTraceToString()
85       */
86      @Override
87      public String writeTrimmedTraceToString() {
88          String testClass = toClassMethod(junitFailure.getDescription()).getClazz();
89          try {
90              Throwable e = junitFailure.getException();
91              return stackTraceWithFocusOnClassAsString(e, testClass);
92          } catch (Throwable t) {
93              return stackTraceWithFocusOnClassAsString(t, testClass);
94          }
95      }
96  
97      /**
98       * Returns the exception associated with this failure.
99       *
100      * @see StackTraceWriter#getThrowable()
101      */
102     @Override
103     public SafeThrowable getThrowable() {
104         return new SafeThrowable(junitFailure.getException());
105     }
106 
107     private static boolean isMultiLineExceptionMessage(Throwable t) {
108         String msg = t.getLocalizedMessage();
109         if (msg != null) {
110             int countNewLines = 0;
111             for (int i = 0, length = msg.length(); i < length; i++) {
112                 if (msg.charAt(i) == '\n') {
113                     if (++countNewLines == 2) {
114                         break;
115                     }
116                 }
117             }
118             return countNewLines > 1 || countNewLines == 1 && !msg.trim().endsWith("\n");
119         }
120         return false;
121     }
122 }