package com.novoda.downloadmanager.lib;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.Test;
import static com.novoda.downloadmanager.lib.IOHelpers.closeAfterWrite;
import static com.novoda.downloadmanager.lib.IOHelpers.closeQuietly;
import static org.fest.assertions.api.Assertions.assertThat;
public class TarTruncatorTest {
private static final long TRUNCATED_TEST_FILE_SIZE = 52819968L;
private InputStream resourceAsStream;
private FileOutputStream fileOutputStream;
private DownloadTask.State state;
private TarTruncator tarTruncator;
@Test
public void itTruncatesProperlyTarFileThatContainsEndBlockMarker() throws Exception {
givenATarFileWithEndBlockMarker();
state = tarTruncator.transferData(state, resourceAsStream);
tarFileShouldHaveBeenTruncatedProperly();
}
@Test
public void itDoesNotModifyATarFileWithoutEndBlockMarker() throws Exception {
givenATarFileWithoutEndBlockMarker();
state = tarTruncator.transferData(state, resourceAsStream);
tarFileShouldBeUntouched();
}
@Test
public void itShouldPauseWhenDataTransferIsOver() throws Exception {
givenATarFileWithEndBlockMarker();
state = tarTruncator.transferData(state, resourceAsStream);
stateShouldBeSetToShouldPause();
}
@Test
public void itShouldUpdateTotalBytesToMatchTruncatedFileSize() throws Exception {
givenATarFileWithEndBlockMarker();
state = tarTruncator.transferData(state, resourceAsStream);
stateShouldMatchTruncatedFileSize();
}
@After
public void tearDown() throws Exception {
new File("TarFileTruncatorTest.tar").delete();
}
private void givenATarFileWithEndBlockMarker() throws IOException {
resourceAsStream = getResourceAsStream("tar/testOriginal.tar");
fileOutputStream = new FileOutputStream("TarFileTruncatorTest.tar");
tarTruncator = new TarTruncator(new TestDataWriter(fileOutputStream));
state = new DownloadTask.State();
}
private void givenATarFileWithoutEndBlockMarker() throws IOException {
resourceAsStream = getResourceAsStream("tar/testExpectedResult.tar");
fileOutputStream = new FileOutputStream("TarFileTruncatorTest.tar");
tarTruncator = new TarTruncator(new TestDataWriter(fileOutputStream));
state = new DownloadTask.State();
}
private void tarFileShouldHaveBeenTruncatedProperly() throws IOException {
closeAfterWrite(fileOutputStream, fileOutputStream.getFD());
closeQuietly(resourceAsStream);
boolean contentEquals = IOUtils.contentEquals(new FileInputStream("TarFileTruncatorTest.tar"), getResourceAsStream("tar/testExpectedResult.tar"));
assertThat(contentEquals).isTrue();
}
private void tarFileShouldBeUntouched() throws IOException {
closeAfterWrite(fileOutputStream, fileOutputStream.getFD());
closeQuietly(resourceAsStream);
boolean contentEquals = IOUtils.contentEquals(new FileInputStream("TarFileTruncatorTest.tar"), getResourceAsStream("tar/testExpectedResult.tar"));
assertThat(contentEquals).isTrue();
}
private void stateShouldBeSetToShouldPause() {
assertThat(state.shouldPause).isTrue();
}
private void stateShouldMatchTruncatedFileSize() {
assertThat(state.totalBytes).isEqualTo(TRUNCATED_TEST_FILE_SIZE);
}
private static InputStream getResourceAsStream(String resName) {
return Thread.currentThread().getContextClassLoader().getResourceAsStream(resName);
}
private static class TestDataWriter implements DataWriter {
private final OutputStream outputStream;
public TestDataWriter(OutputStream outputStream) {
this.outputStream = outputStream;
}
@Override
public DownloadTask.State write(DownloadTask.State state, byte[] buffer, int count) throws StopRequestException {
try {
state.gotData = true;
outputStream.write(buffer, 0, count);
state.currentBytes += count;
return state;
} catch (IOException e) {
throw new StopRequestException(
DownloadStatus.FILE_ERROR,
"Failed to write data: " + e);
}
}
}
}