• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.junit;
2 
3 /**
4  * Thrown when an {@link org.junit.Assert#assertEquals(Object, Object) assertEquals(String, String)} fails. Create and throw
5  * a <code>ComparisonFailure</code> manually if you want to show users the difference between two complex
6  * strings.
7  *
8  * Inspired by a patch from Alex Chaffee (alex@purpletech.com)
9  */
10 public class ComparisonFailure extends AssertionError {
11 	/**
12 	 * The maximum length for fExpected and fActual. If it is exceeded, the strings should be shortened.
13 	 * @see ComparisonCompactor
14 	 */
15 	private static final int MAX_CONTEXT_LENGTH= 20;
16 	private static final long serialVersionUID= 1L;
17 
18 	private String fExpected;
19 	private String fActual;
20 
21 	/**
22 	 * Constructs a comparison failure.
23 	 * @param message the identifying message or null
24 	 * @param expected the expected string value
25 	 * @param actual the actual string value
26 	 */
ComparisonFailure(String message, String expected, String actual)27 	public ComparisonFailure (String message, String expected, String actual) {
28 		super (message);
29 		fExpected= expected;
30 		fActual= actual;
31 	}
32 
33 	/**
34 	 * Returns "..." in place of common prefix and "..." in
35 	 * place of common suffix between expected and actual.
36 	 *
37 	 * @see Throwable#getMessage()
38 	 */
39 	@Override
getMessage()40 	public String getMessage() {
41 		return new ComparisonCompactor(MAX_CONTEXT_LENGTH, fExpected, fActual).compact(super.getMessage());
42 	}
43 
44 	/**
45 	 * Returns the actual string value
46 	 * @return the actual string value
47 	 */
getActual()48 	public String getActual() {
49 		return fActual;
50 	}
51 	/**
52 	 * Returns the expected string value
53 	 * @return the expected string value
54 	 */
getExpected()55 	public String getExpected() {
56 		return fExpected;
57 	}
58 
59 	private static class ComparisonCompactor {
60 		private static final String ELLIPSIS= "...";
61 		private static final String DELTA_END= "]";
62 		private static final String DELTA_START= "[";
63 
64 		/**
65 		 * The maximum length for <code>expected</code> and <code>actual</code>. When <code>contextLength</code>
66 		 * is exceeded, the Strings are shortened
67 		 */
68 		private int fContextLength;
69 		private String fExpected;
70 		private String fActual;
71 		private int fPrefix;
72 		private int fSuffix;
73 
74 		/**
75 		 * @param contextLength the maximum length for <code>expected</code> and <code>actual</code>. When contextLength
76 		 * is exceeded, the Strings are shortened
77 		 * @param expected the expected string value
78 		 * @param actual the actual string value
79 		 */
ComparisonCompactor(int contextLength, String expected, String actual)80 		public ComparisonCompactor(int contextLength, String expected, String actual) {
81 			fContextLength= contextLength;
82 			fExpected= expected;
83 			fActual= actual;
84 		}
85 
compact(String message)86 		private String compact(String message) {
87 			if (fExpected == null || fActual == null || areStringsEqual())
88 				return Assert.format(message, fExpected, fActual);
89 
90 			findCommonPrefix();
91 			findCommonSuffix();
92 			String expected= compactString(fExpected);
93 			String actual= compactString(fActual);
94 			return Assert.format(message, expected, actual);
95 		}
96 
compactString(String source)97 		private String compactString(String source) {
98 			String result= DELTA_START + source.substring(fPrefix, source.length() - fSuffix + 1) + DELTA_END;
99 			if (fPrefix > 0)
100 				result= computeCommonPrefix() + result;
101 			if (fSuffix > 0)
102 				result= result + computeCommonSuffix();
103 			return result;
104 		}
105 
findCommonPrefix()106 		private void findCommonPrefix() {
107 			fPrefix= 0;
108 			int end= Math.min(fExpected.length(), fActual.length());
109 			for (; fPrefix < end; fPrefix++) {
110 				if (fExpected.charAt(fPrefix) != fActual.charAt(fPrefix))
111 					break;
112 			}
113 		}
114 
findCommonSuffix()115 		private void findCommonSuffix() {
116 			int expectedSuffix= fExpected.length() - 1;
117 			int actualSuffix= fActual.length() - 1;
118 			for (; actualSuffix >= fPrefix && expectedSuffix >= fPrefix; actualSuffix--, expectedSuffix--) {
119 				if (fExpected.charAt(expectedSuffix) != fActual.charAt(actualSuffix))
120 					break;
121 			}
122 			fSuffix=  fExpected.length() - expectedSuffix;
123 		}
124 
computeCommonPrefix()125 		private String computeCommonPrefix() {
126 			return (fPrefix > fContextLength ? ELLIPSIS : "") + fExpected.substring(Math.max(0, fPrefix - fContextLength), fPrefix);
127 		}
128 
computeCommonSuffix()129 		private String computeCommonSuffix() {
130 			int end= Math.min(fExpected.length() - fSuffix + 1 + fContextLength, fExpected.length());
131 			return fExpected.substring(fExpected.length() - fSuffix + 1, end) + (fExpected.length() - fSuffix + 1 < fExpected.length() - fContextLength ? ELLIPSIS : "");
132 		}
133 
areStringsEqual()134 		private boolean areStringsEqual() {
135 			return fExpected.equals(fActual);
136 		}
137 	}
138 }