/*
* Created on 20/giu/2010
*
* Copyright 2010 by Andrea Vacondio (andrea.vacondio@gmail.com).
*
* This file is part of the Sejda source code
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sejda.core.support.io;
import static org.apache.commons.lang3.SystemUtils.IS_OS_WINDOWS;
import static org.hamcrest.CoreMatchers.hasItem;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sejda.model.exception.TaskIOException;
import org.sejda.model.output.ExistingOutputPolicy;
import org.sejda.model.task.Task;
import org.sejda.model.task.TaskExecutionContext;
/**
* Test unit for the {@link OutputWriterHelper}
*
* @author Andrea Vacondio
*
*/
public class OutputWriterHelperTest {
@Rule
public TemporaryFolder folder = new TemporaryFolder();
@Rule
public TemporaryFolder outputFolder = new TemporaryFolder();
private TaskExecutionContext context;
@Before
public void setUp() {
context = new TaskExecutionContext(mock(Task.class), true);
}
@Test
public void copyStreamZipped() throws IOException {
File tempFile = folder.newFile();
Map<String, File> files = new HashMap<String, File>();
files.put("newName", tempFile);
ByteArrayOutputStream out = new ByteArrayOutputStream();
OutputWriterHelper.copyToStreamZipped(files, out);
assertFalse("temporary file not deleted", tempFile.exists());
assertTrue(out.size() > 0);
}
@Test
public void copyStreamSingleFile() throws IOException {
File tempFile = folder.newFile();
Map<String, File> files = new HashMap<String, File>();
files.put("newName", tempFile);
ByteArrayOutputStream out = new ByteArrayOutputStream();
OutputWriterHelper.copyToStream(files.values().iterator().next(), out);
assertFalse("temporary file not deleted", tempFile.exists());
assertEquals(out.size(), tempFile.length());
}
@Test
public void copyFailsMapSize() {
Map<String, File> files = new HashMap<String, File>();
File outFile = mock(File.class);
when(outFile.isFile()).thenReturn(Boolean.TRUE);
try {
OutputWriterHelper.moveToFile(files, outFile, ExistingOutputPolicy.OVERWRITE, context);
fail("Exception expected");
} catch (IOException e) {
assertTrue("Different exception expected.", e.getMessage().startsWith("Wrong files map size"));
}
}
@Test
public void copyFailsFileType() throws IOException {
Map<String, File> files = new HashMap<String, File>();
files.put("newName", folder.newFile());
File outFile = mock(File.class);
when(outFile.isFile()).thenReturn(Boolean.FALSE);
when(outFile.exists()).thenReturn(Boolean.TRUE);
try {
OutputWriterHelper.moveToFile(files, outFile, ExistingOutputPolicy.OVERWRITE, context);
fail("Exception expected");
} catch (IOException e) {
assertTrue("Different exception expected.", e.getMessage().endsWith("must be a file."));
}
}
@Test
public void copyFailsOverwrite() throws IOException {
Map<String, File> files = new HashMap<String, File>();
files.put("newName", folder.newFile());
File outFile = mock(File.class);
when(outFile.isFile()).thenReturn(Boolean.TRUE);
when(outFile.exists()).thenReturn(Boolean.TRUE);
try {
OutputWriterHelper.moveToFile(files, outFile, ExistingOutputPolicy.FAIL, context);
fail("Exception expected");
} catch (IOException e) {
assertTrue("Different exception expected.", e.getMessage().startsWith("Unable to write"));
}
}
@Test
public void copySingleFileSkipFallbacksToFail() throws IOException {
Map<String, File> files = new HashMap<String, File>();
files.put("newName", folder.newFile());
File outFile = mock(File.class);
when(outFile.isFile()).thenReturn(Boolean.TRUE);
when(outFile.exists()).thenReturn(Boolean.TRUE);
try {
OutputWriterHelper.moveToFile(files, outFile, ExistingOutputPolicy.SKIP, context);
fail("Exception expected");
} catch (IOException e) {
assertTrue("Different exception expected.", e.getMessage().startsWith("Unable to write"));
}
}
@Test
public void copyFailsDirectoryType() throws IOException {
Map<String, File> files = new HashMap<String, File>();
files.put("newName", folder.newFile());
try {
OutputWriterHelper.moveToDirectory(files, folder.newFile(), ExistingOutputPolicy.OVERWRITE, context);
fail("Exception expected");
} catch (IOException e) {
assertTrue("Different exception expected.", e.getMessage().startsWith("Wrong output destination"));
}
}
@Test
public void copyDirectorySkips() throws IOException {
File dest = folder.newFolder();
File tempFile = folder.newFile();
Map<String, File> files = populateWithOneExisting(dest, tempFile);
OutputWriterHelper.moveToDirectory(files, dest, ExistingOutputPolicy.SKIP, context);
assertEquals(2, dest.list().length);
assertEquals(1, context.notifiableTaskMetadata().taskOutput().size());
}
@Test
public void moveUnhide() throws IOException, TaskIOException {
if (IS_OS_WINDOWS) {
File dest = new File(folder.newFolder().getAbsolutePath(), "dest.tmp");
File tmp = IOUtils.createTemporaryBuffer();
IOUtils.hide(tmp.toPath());
assertEquals(Boolean.TRUE, (Boolean) Files.getAttribute(tmp.toPath(), "dos:hidden"));
OutputWriterHelper.moveFile(tmp, dest, ExistingOutputPolicy.FAIL, context);
assertEquals(Boolean.FALSE, (Boolean) Files.getAttribute(dest.toPath(), "dos:hidden"));
}
}
@Test
public void copyDirectoryOverwrite() throws IOException {
File dest = folder.newFolder();
File tempFile = folder.newFile();
Map<String, File> files = populateWithOneExisting(dest, tempFile);
OutputWriterHelper.moveToDirectory(files, dest, ExistingOutputPolicy.OVERWRITE, context);
assertEquals(2, dest.list().length);
assertEquals(2, context.notifiableTaskMetadata().taskOutput().size());
}
@Test(expected = IOException.class)
public void copyDirectoryFail() throws IOException {
File dest = folder.newFolder();
File tempFile = folder.newFile();
Map<String, File> files = populateWithOneExisting(dest, tempFile);
OutputWriterHelper.moveToDirectory(files, dest, ExistingOutputPolicy.FAIL, context);
}
private Map<String, File> populateWithOneExisting(File dest, File tempFile) throws IOException {
Map<String, File> files = new HashMap<String, File>();
files.put("newName", tempFile);
File existing = File.createTempFile("Chuck", "Norris", dest);
files.put(existing.getName(), folder.newFile());
return files;
}
@Test
public void copyFailsDirectoryMkdirs() throws IOException {
File tempFile = folder.newFile();
Map<String, File> files = new HashMap<String, File>();
files.put("newName", tempFile);
File outFile = mock(File.class);
when(outFile.isDirectory()).thenReturn(Boolean.TRUE);
when(outFile.exists()).thenReturn(Boolean.FALSE);
when(outFile.mkdirs()).thenReturn(Boolean.FALSE);
try {
OutputWriterHelper.moveToDirectory(files, outFile, ExistingOutputPolicy.OVERWRITE, context);
fail("Exception expected");
} catch (IOException e) {
assertTrue("Different exception expected.", e.getMessage().startsWith("Unable to make destination"));
}
}
@Test
public void existingOutputPolicyRENAME_conflict() throws IOException {
Map<String, File> files = new HashMap<String, File>();
files.put("existing.pdf", folder.newFile());
File outFile = outputFolder.newFile("existing.pdf");
outputFolder.newFile("existing(1).pdf");
outputFolder.newFile("existing(2).pdf");
OutputWriterHelper.moveToFile(files, outFile, ExistingOutputPolicy.RENAME, context);
assertThat(Arrays.asList(outputFolder.getRoot().list()), hasItem("existing(3).pdf"));
}
@Test
public void existingOutputPolicyRENAME_noConflict() throws IOException {
Map<String, File> files = new HashMap<String, File>();
files.put("ok.pdf", folder.newFile());
File outFile = new File(outputFolder.getRoot(), "ok.pdf");
OutputWriterHelper.moveToFile(files, outFile, ExistingOutputPolicy.RENAME, context);
assertThat(Arrays.asList(outputFolder.getRoot().list()), hasItem("ok.pdf"));
}
@Test
public void existingOutputPolicyRENAME_exception() throws IOException {
Map<String, File> files = new HashMap<String, File>();
files.put("existing.pdf", folder.newFile());
File outFile = outputFolder.newFile("existing.pdf");
for (int i = 1; i <= 100; i++) {
outputFolder.newFile(String.format("existing(%d).pdf", i));
}
try {
OutputWriterHelper.moveToFile(files, outFile, ExistingOutputPolicy.RENAME, context);
fail("Exception expected, about the fact that a new filename that doesn't exist could not be generated");
} catch (IOException e) {
assertTrue("Different exception expected, got: " + e.getMessage(),
e.getMessage().startsWith("Unable to generate a new filename that does not exist"));
}
}
@Test
public void moveCreatesDirectoryTree() throws IOException {
Map<String, File> files = new HashMap<String, File>();
files.put("file.pdf", folder.newFile());
Path out = Paths.get(outputFolder.newFolder().getAbsolutePath(), "this", "does", "not", "exist");
assertFalse(Files.isDirectory(out));
OutputWriterHelper.moveToDirectory(files, out.toFile(), ExistingOutputPolicy.OVERWRITE, context);
assertTrue(Files.isDirectory(out));
}
}