/*
* Created on Feb 9, 2008
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* Copyright @2008-2013 the original author or authors.
*/
package org.fest.assertions;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.*;
import java.util.List;
import static java.lang.String.format;
import static org.fest.assertions.FileContentComparator.LineDiff.lineDiff;
import static org.fest.util.Closeables.closeQuietly;
import static org.fest.util.Lists.newArrayList;
import static org.fest.util.Objects.*;
import static org.fest.util.Strings.quote;
/**
* Compares the contents of two files.
*
* @author David DIDIER
* @author Alex Ruiz
* @author Yvonne Wang
*/
class FileContentComparator {
private static final String EOF = "EOF";
/*
* Verifies that the given files have the same content. Adapted from <a
* href="http://junit-addons.sourceforge.net/junitx/framework/FileAssert.html" target="_blank">FileAssert</a> (from <a
* href="http://sourceforge.net/projects/junit-addons">JUnit-addons</a>.)
*/
@Nonnull LineDiff[] compareContents(@Nonnull File actual, @Nonnull File expected) throws IOException {
InputStream ais = null;
InputStream eis = null;
try {
ais = new FileInputStream(actual);
eis = new FileInputStream(expected);
List<LineDiff> diffs = verifyEqualContent(readerFor(ais), readerFor(eis));
return diffs.toArray(new LineDiff[diffs.size()]);
} finally {
closeQuietly(eis);
closeQuietly(ais);
}
}
private @Nonnull LineNumberReader readerFor(@Nonnull InputStream inputStream) {
return new LineNumberReader(new BufferedReader(new InputStreamReader(inputStream)));
}
private @Nonnull List<LineDiff> verifyEqualContent(
@Nonnull LineNumberReader actual, @Nonnull LineNumberReader expected) throws IOException {
List<LineDiff> diffs = newArrayList();
while (true) {
if (!expected.ready() && !actual.ready()) {
return diffs;
}
int lineNumber = expected.getLineNumber();
String actualLine = actual.readLine();
String expectedLine = expected.readLine();
if (areEqual(actualLine, expectedLine)) {
continue;
}
diffs.add(lineDiff(lineNumber, actualLine, expectedLine));
if (!actual.ready() && expected.ready()) {
diffs.add(lineDiff(lineNumber, EOF, expectedLine));
return diffs;
}
if (actual.ready() && !expected.ready()) {
diffs.add(lineDiff(lineNumber, actualLine, EOF));
return diffs;
}
}
}
static class LineDiff {
final int lineNumber;
final String actual;
final String expected;
private LineDiff(int lineNumber, @Nullable String actual, @Nullable String expected) {
this.lineNumber = lineNumber;
this.actual = actual;
this.expected = expected;
}
static LineDiff lineDiff(int lineNumber, @Nullable String actual, @Nullable String expected) {
return new LineDiff(lineNumber, actual, expected);
}
@Override
public int hashCode() {
final int prime = HASH_CODE_PRIME;
int result = 1;
result = prime * result + hashCodeFor(actual);
result = prime * result + hashCodeFor(expected);
result = prime * result + lineNumber;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
LineDiff other = (LineDiff) obj;
if (!areEqual(actual, other.actual)) {
return false;
}
if (!areEqual(expected, other.expected)) {
return false;
}
return lineNumber == other.lineNumber;
}
@Override
public String toString() {
return format("LineDiff [actual=%s, expected=%s, lineNumber=%d]", quote(actual), quote(expected), lineNumber);
}
}
}