Skip to content

Commit

Permalink
Merge pull request junit-team#919 from AlexYursha/comparison-failure
Browse files Browse the repository at this point in the history
Improve readability of ComparisonFailure
  • Loading branch information
kcooney committed May 29, 2014
2 parents 70f082f + a5d194f commit 23c8e97
Showing 1 changed file with 73 additions and 63 deletions.
136 changes: 73 additions & 63 deletions src/main/java/org/junit/ComparisonFailure.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package org.junit;

/**
* Thrown when an {@link org.junit.Assert#assertEquals(Object, Object) assertEquals(String, String)} fails. Create and throw
* a <code>ComparisonFailure</code> manually if you want to show users the difference between two complex
* strings.
*
* Thrown when an {@link org.junit.Assert#assertEquals(Object, Object) assertEquals(String, String)} fails.
* Create and throw a <code>ComparisonFailure</code> manually if you want to show users the
* difference between two complex strings.
* <p/>
* Inspired by a patch from Alex Chaffee ([email protected])
*
* @since 4.0
Expand Down Expand Up @@ -35,8 +35,7 @@ public ComparisonFailure(String message, String expected, String actual) {
}

/**
* Returns "..." in place of common prefix and "..." in
* place of common suffix between expected and actual.
* Returns "..." in place of common prefix and "..." in place of common suffix between expected and actual.
*
* @see Throwable#getMessage()
*/
Expand Down Expand Up @@ -65,28 +64,20 @@ public String getExpected() {

private static class ComparisonCompactor {
private static final String ELLIPSIS = "...";
private static final String DELTA_END = "]";
private static final String DELTA_START = "[";
private static final String DIFF_END = "]";
private static final String DIFF_START = "[";

/**
* The maximum length for <code>expected</code> and <code>actual</code> strings to show. When <code>contextLength</code>
* is exceeded, the Strings are shortened.
*/
private int contextLength;

private String expected;
private String actual;

/**
* The length of the shared prefix / suffix of the expected and actual strings.
* Equals to zero if the strings do not share a common prefix/suffix.
* The maximum length for <code>expected</code> and <code>actual</code> strings to show. When
* <code>contextLength</code> is exceeded, the Strings are shortened.
*/
private int prefix;
private int suffix;
private final int contextLength;
private final String expected;
private final String actual;

/**
* @param contextLength the maximum length for <code>expected</code> and <code>actual</code> strings. When contextLength
* is exceeded, the Strings are shortened.
* @param contextLength the maximum length of context surrounding the difference between the compared strings.
* When context length is exceeded, the prefixes and suffixes are compacted.
* @param expected the expected string value
* @param actual the actual string value
*/
Expand All @@ -96,61 +87,80 @@ public ComparisonCompactor(int contextLength, String expected, String actual) {
this.actual = actual;
}

private String compact(String message) {
if (expected == null || actual == null || areStringsEqual()) {
public String compact(String message) {
if (expected == null || actual == null || expected.equals(actual)) {
return Assert.format(message, expected, actual);
} else {
DiffExtractor extractor = new DiffExtractor();
String compactedPrefix = extractor.compactPrefix();
String compactedSuffix = extractor.compactSuffix();
return Assert.format(message,
compactedPrefix + extractor.expectedDiff() + compactedSuffix,
compactedPrefix + extractor.actualDiff() + compactedSuffix);
}

findCommonPrefix();
findCommonSuffix();
String expected = compactString(this.expected);
String actual = compactString(this.actual);
return Assert.format(message, expected, actual);
}

private String compactString(String source) {
String result = DELTA_START + source.substring(prefix, source.length() - suffix) + DELTA_END;
if (prefix > 0) {
result = computeCommonPrefix() + result;
}
if (suffix > 0) {
result = result + computeCommonSuffix();
}
return result;
}

private void findCommonPrefix() {
prefix = 0;
private String sharedPrefix() {
int end = Math.min(expected.length(), actual.length());
for (; prefix < end; prefix++) {
if (expected.charAt(prefix) != actual.charAt(prefix)) {
break;
for (int i = 0; i < end; i++) {
if (expected.charAt(i) != actual.charAt(i)) {
return expected.substring(0, i);
}
}
return expected.substring(0, end);
}

private void findCommonSuffix() {
int expectedSuffix = expected.length() - 1;
int actualSuffix = actual.length() - 1;
for (; actualSuffix >= prefix && expectedSuffix >= prefix; actualSuffix--, expectedSuffix--) {
if (expected.charAt(expectedSuffix) != actual.charAt(actualSuffix)) {
private String sharedSuffix(String prefix) {
int suffixLength = 0;
int maxSuffixLength = Math.min(expected.length() - prefix.length(),
actual.length() - prefix.length()) - 1;
for (; suffixLength <= maxSuffixLength; suffixLength++) {
if (expected.charAt(expected.length() - 1 - suffixLength)
!= actual.charAt(actual.length() - 1 - suffixLength)) {
break;
}
}
suffix = expected.length() - expectedSuffix - 1;
return expected.substring(expected.length() - suffixLength);
}

private String computeCommonPrefix() {
return (prefix > contextLength ? ELLIPSIS : "") + expected.substring(Math.max(0, prefix - contextLength), prefix);
}
private class DiffExtractor {
private final String sharedPrefix;
private final String sharedSuffix;

private String computeCommonSuffix() {
int end = Math.min(expected.length() - suffix + contextLength, expected.length());
return expected.substring(expected.length() - suffix, end) + (expected.length() - suffix < expected.length() - contextLength ? ELLIPSIS : "");
}
/**
* Can not be instantiated outside {@link org.junit.ComparisonFailure.ComparisonCompactor}.
*/
private DiffExtractor() {
sharedPrefix = sharedPrefix();
sharedSuffix = sharedSuffix(sharedPrefix);
}

private boolean areStringsEqual() {
return expected.equals(actual);
public String expectedDiff() {
return extractDiff(expected);
}

public String actualDiff() {
return extractDiff(actual);
}

public String compactPrefix() {
if (sharedPrefix.length() <= contextLength) {
return sharedPrefix;
}
return ELLIPSIS + sharedPrefix.substring(sharedPrefix.length() - contextLength);
}

public String compactSuffix() {
if (sharedSuffix.length() <= contextLength) {
return sharedSuffix;
}
return sharedSuffix.substring(0, contextLength) + ELLIPSIS;
}

private String extractDiff(String source) {
return DIFF_START + source.substring(sharedPrefix.length(), source.length() - sharedSuffix.length())
+ DIFF_END;
}
}
}
}
}

0 comments on commit 23c8e97

Please sign in to comment.