Open Source Repository

Home /junit/junit-4.10 | Repository Home


org/junit/ComparisonFailure.java
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.
 
 * Inspired by a patch from Alex Chaffee ([email protected])
 */
public class ComparisonFailure extends AssertionError {  
  /** 
   * The maximum length for fExpected and fActual. If it is exceeded, the strings should be shortened. 
   @see ComparisonCompactor
   */
  private static final int MAX_CONTEXT_LENGTH= 20;
  private static final long serialVersionUID= 1L;
  
  private String fExpected;
  private String fActual;

  /**
   * Constructs a comparison failure.
   @param message the identifying message or null
   @param expected the expected string value
   @param actual the actual string value
   */
  public ComparisonFailure (String message, String expected, String actual) {
    super (message);
    fExpected= expected;
    fActual= actual;
  }
  
  /**
   * Returns "..." in place of common prefix and "..." in
   * place of common suffix between expected and actual.
   
   @see Throwable#getMessage()
   */
  @Override
  public String getMessage() {
    return new ComparisonCompactor(MAX_CONTEXT_LENGTH, fExpected, fActual).compact(super.getMessage());
  }
  
  /**
   * Returns the actual string value
   @return the actual string value
   */
  public String getActual() {
    return fActual;
  }
  /**
   * Returns the expected string value
   @return the expected string value
   */
  public String getExpected() {
    return fExpected;
  }
  
  private static class ComparisonCompactor {
    private static final String ELLIPSIS= "...";
    private static final String DELTA_END= "]";
    private static final String DELTA_START= "[";
    
    /**
     * The maximum length for <code>expected</code> and <code>actual</code>. When <code>contextLength</code> 
     * is exceeded, the Strings are shortened
     */
    private int fContextLength;
    private String fExpected;
    private String fActual;
    private int fPrefix;
    private int fSuffix;

    /**
     @param contextLength the maximum length for <code>expected</code> and <code>actual</code>. When contextLength 
     * is exceeded, the Strings are shortened
     @param expected the expected string value
     @param actual the actual string value
     */
    public ComparisonCompactor(int contextLength, String expected, String actual) {
      fContextLength= contextLength;
      fExpected= expected;
      fActual= actual;
    }

    private String compact(String message) {
      if (fExpected == null || fActual == null || areStringsEqual())
        return Assert.format(message, fExpected, fActual);

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

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

    private void findCommonPrefix() {
      fPrefix= 0;
      int end= Math.min(fExpected.length(), fActual.length());
      for (; fPrefix < end; fPrefix++) {
        if (fExpected.charAt(fPrefix!= fActual.charAt(fPrefix))
          break;
      }
    }

    private void findCommonSuffix() {
      int expectedSuffix= fExpected.length() 1;
      int actualSuffix= fActual.length() 1;
      for (; actualSuffix >= fPrefix && expectedSuffix >= fPrefix; actualSuffix--, expectedSuffix--) {
        if (fExpected.charAt(expectedSuffix!= fActual.charAt(actualSuffix))
          break;
      }
      fSuffix=  fExpected.length() - expectedSuffix;
    }

    private String computeCommonPrefix() {
      return (fPrefix > fContextLength ? ELLIPSIS : ""+ fExpected.substring(Math.max(0, fPrefix - fContextLength), fPrefix);
    }

    private String computeCommonSuffix() {
      int end= Math.min(fExpected.length() - fSuffix + + fContextLength, fExpected.length());
      return fExpected.substring(fExpected.length() - fSuffix + 1, end(fExpected.length() - fSuffix + < fExpected.length() - fContextLength ? ELLIPSIS : "");
    }

    private boolean areStringsEqual() {
      return fExpected.equals(fActual);
    }
  }
}