package com.canoo.webtest.extension;
import java.io.IOException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.ArrayUtils;
import com.canoo.webtest.engine.StepExecutionException;
import com.gargoylesoftware.htmlunit.WebResponse;
/**
* Performs a binary comparison of the content.
* @author Marc Guillemot
*/
public class VerifyContentBinDiff implements VerifyContentDiff
{
/**
* {@inheritDoc}
*/
public String compare(final WebResponse reference, final WebResponse actual,
final String referenceLabel, final String actualLabel) {
if (sameContent(reference, actual))
{
return null;
}
else
{
final byte[] actualBytes, refBytes;
try {
actualBytes = IOUtils.toByteArray(actual.getContentAsStream());
refBytes = IOUtils.toByteArray(reference.getContentAsStream());
}
catch (final IOException e) {
throw new RuntimeException(e);
}
return produceBinDiffMessage(actualBytes, refBytes);
}
}
private boolean sameContent(final WebResponse reference, final WebResponse actual) {
try {
return IOUtils.contentEquals(reference.getContentAsStream(), actual.getContentAsStream());
}
catch (final IOException e) {
throw new StepExecutionException("Error reading content", e);
}
}
protected String produceBinDiffMessage(final byte[] actualBytes, final byte[] referenceBytes)
{
final int extractLength = 10;
final int minLength = Math.min(actualBytes.length, referenceBytes.length);
for (int i = 0; i < minLength; i++)
{
if (actualBytes[i] != referenceBytes[i])
{
// extract 10 bytes (if available) to show difference in context
final byte[] extract1 = ArrayUtils.subarray(actualBytes, i, i+extractLength);
final byte[] extract2 = ArrayUtils.subarray(referenceBytes, i, i+extractLength);
return "First difference at position " + (i+1)
+ ": " + String.valueOf(Hex.encodeHex(extract1)) + " <> " + String.valueOf(Hex.encodeHex(extract2));
}
}
// one file is contained in the other
final byte[] longerArray;
final String msg;
if (actualBytes.length < referenceBytes.length)
{
longerArray = referenceBytes;
msg = "Reference binary content starts with actual binary content";
}
else
{
longerArray = actualBytes;
msg = "Actual binary content starts with reference binary content";
}
final byte[] startOfLonger = ArrayUtils.subarray(longerArray, minLength, minLength+extractLength);
return msg + ". Longer content continues with: " + String.valueOf(Hex.encodeHex(startOfLonger));
}
}