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 }