/*
* Created on Jul 1, 2011
* Copyright 2011 by Eduard Weissmann (edi.weissmann@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.cli;
import static org.apache.commons.io.FilenameUtils.separatorsToWindows;
import static org.hamcrest.CoreMatchers.endsWith;
import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.core.CombinableMatcher.either;
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 java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.hamcrest.Matcher;
import org.junit.Before;
import org.junit.Test;
import org.sejda.cli.command.StandardTestableTask;
import org.sejda.model.input.PdfFileSource;
import org.sejda.model.input.PdfMergeInput;
import org.sejda.model.outline.OutlinePolicy;
import org.sejda.model.parameter.MergeParameters;
import org.sejda.model.pdf.form.AcroFormPolicy;
import org.sejda.model.pdf.page.PageRange;
import org.sejda.model.toc.ToCPolicy;
/**
* Tests for the MergeTask command line interface
*
* @author Eduard Weissmann
*
*/
public class MergeTaskTest extends AbstractTaskTest {
public MergeTaskTest() {
super(StandardTestableTask.MERGE);
}
@Override
@Before
public void setUp() {
super.setUp();
createTestPdfFile("/tmp/merge/file1.pdf");
createTestPdfFile("/tmp/merge/file2.pdf");
createTestPdfFile("/tmp/merge/file3.pdf");
createTestPdfFile("/tmp/merge/file4.pdf");
createTestPdfFile("/tmp/merge/file5.txt");
createTestPdfFile("/tmp/merge/subdir/file5.pdf");
createTestTextFile("./location/filenames.csv",
"/tmp/merge/file3.pdf, /tmp/merge/file1.pdf, /tmp/merge/file2.pdf");
createTestTextFile("./location/empty_filenames.csv", "");
createTestTextFile("./location/filenames_invalidPaths.csv",
"/tmp/merge/fileDoesntExist.pdf,/tmp/merge/file1.pdf");
createTestTextFile("/tmp/filenames.xml", getClass().getResourceAsStream("/merge-filelist-config.xml"));
// files inside
createTestPdfFile("/tmp/pdf/inputFile.pdf");
createTestPdfFile("/tmp/pdf/inputFile2.pdf");
createTestPdfFile("/tmp/inputFile1.pdf");
createTestPdfFile("/tmp/inputFile2.pdf");
createTestPdfFile("/tmp/subdir/inputFile1.pdf");
createTestPdfFile("/tmp/subdir3/inputFile2.pdf");
createTestPdfFile("/tmp/subdir2/inputFile1.pdf");
createTestPdfFile("/tmp/subdir2/inputFile2.pdf");
createTestPdfFile("/tmp/subdir2/inputFile3.pdf");
createTestTextFile("./location/filenames_invalidXml.xml", "<filelist><file value=\"/tmp/merge/file1.pdf \">");
createTestFolder("/tmp/emptyFolder");
createTestPdfFile("./location/filenames.xls");
}
@Test
public void onAddBlanks() {
MergeParameters parameters = defaultCommandLine().withFlag("--addBlanks").invokeSejdaConsole();
assertTrue(parameters.isBlankPageIfOdd());
}
@Test
public void offAddBlankss() {
MergeParameters parameters = defaultCommandLine().invokeSejdaConsole();
assertFalse(parameters.isBlankPageIfOdd());
}
@Test
public void onDiscardBookmarks() {
MergeParameters parameters = defaultCommandLine().with("-b", "discard").invokeSejdaConsole();
assertEquals(OutlinePolicy.DISCARD, parameters.getOutlinePolicy());
}
@Test
public void onOneEachDoc() {
MergeParameters parameters = defaultCommandLine().with("-b", "one_entry_each_doc").invokeSejdaConsole();
assertEquals(OutlinePolicy.ONE_ENTRY_EACH_DOC, parameters.getOutlinePolicy());
}
@Test
public void addFooter() {
MergeParameters parameters = defaultCommandLine().withFlag("--footer").invokeSejdaConsole();
assertTrue(parameters.isFilenameFooter());
}
@Test
public void onDefault() {
MergeParameters parameters = defaultCommandLine().invokeSejdaConsole();
assertEquals(OutlinePolicy.RETAIN, parameters.getOutlinePolicy());
assertEquals(AcroFormPolicy.DISCARD, parameters.getAcroFormPolicy());
assertEquals(ToCPolicy.NONE, parameters.getTableOfContentsPolicy());
assertFalse(parameters.isFilenameFooter());
}
@Test
public void onRetainAsOneEntry() {
MergeParameters parameters = defaultCommandLine().with("-b", "retain_as_one_entry").invokeSejdaConsole();
assertEquals(OutlinePolicy.RETAIN_AS_ONE_ENTRY, parameters.getOutlinePolicy());
}
@Test
public void onMergeAcroForms() {
MergeParameters parameters = defaultCommandLine().with("-a", "merge").invokeSejdaConsole();
assertEquals(AcroFormPolicy.MERGE, parameters.getAcroFormPolicy());
}
@Test
public void onFlattenAcroForms() {
MergeParameters parameters = defaultCommandLine().with("-a", "flatten").invokeSejdaConsole();
assertEquals(AcroFormPolicy.FLATTEN, parameters.getAcroFormPolicy());
}
@Test
public void onMergeRenamingAcroForms() {
MergeParameters parameters = defaultCommandLine().with("-a", "merge_renaming").invokeSejdaConsole();
assertEquals(AcroFormPolicy.MERGE_RENAMING_EXISTING_FIELDS, parameters.getAcroFormPolicy());
}
@Test
public void onTextNamesToC() {
MergeParameters parameters = defaultCommandLine().with("-t", "file_names").invokeSejdaConsole();
assertEquals(ToCPolicy.FILE_NAMES, parameters.getTableOfContentsPolicy());
}
@Test
public void onTextTitlesToC() {
MergeParameters parameters = defaultCommandLine().with("-t", "doc_titles").invokeSejdaConsole();
assertEquals(ToCPolicy.DOC_TITLES, parameters.getTableOfContentsPolicy());
}
@Test
public void folderInput() {
MergeParameters parameters = defaultCommandLine().without("-f").with("-d", "/tmp/merge").invokeSejdaConsole();
assertPdfMergeInputsFilesList(parameters, filesList("/tmp/merge/file1.pdf", "/tmp/merge/file2.pdf",
"/tmp/merge/file3.pdf", "/tmp/merge/file4.pdf"));
}
@Test
public void folderInputWithRegexp() {
MergeParameters parameters = defaultCommandLine().without("-f").with("-d", "/tmp/merge")
.with("-e", "([^\\s]+(1|4)(?i)(\\.pdf)$)").invokeSejdaConsole();
assertPdfMergeInputsFilesList(parameters, filesList("/tmp/merge/file1.pdf", "/tmp/merge/file4.pdf"));
}
@Test
public void folderInputWithRegexpFilteringEverythig() {
defaultCommandLine().without("-f").with("-d", "/tmp/merge").with("-e", "([^\\s]+(\\.(norris))$)")
.assertConsoleOutputContains("No input files specified in");
}
@Test
public void wildcardInput() {
MergeParameters parameters = defaultCommandLine().without("-f")
.with("-f", "/tmp/merge/*.pdf /tmp/inputFile1.pdf").invokeSejdaConsole();
assertPdfMergeInputsFilesList(parameters, filesList("/tmp/merge/file1.pdf", "/tmp/merge/file2.pdf",
"/tmp/merge/file3.pdf", "/tmp/merge/file4.pdf", "/tmp/inputFile1.pdf"));
}
@Test
public void folderInput_emptyFolder() {
defaultCommandLine().with("-d", "/tmp/emptyFolder").assertConsoleOutputContains("No input files specified in");
}
private static List<Matcher<Iterable<? super String>>> filesList(String... filenames) {
List<Matcher<Iterable<? super String>>> result = new ArrayList<Matcher<Iterable<? super String>>>();
for (String current : filenames) {
String filename = current.toString();
result.add(either(hasItem(filename)).or(hasItem(endsWith(separatorsToWindows(filename)))));
}
return result;
}
@Test
public void fileListConfigInput_csv() {
MergeParameters parameters = defaultCommandLine().without("-f").with("-l", "./location/filenames.csv")
.invokeSejdaConsole();
assertPdfMergeInputsFilesList(parameters,
filesList("/tmp/merge/file3.pdf", "/tmp/merge/file1.pdf", "/tmp/merge/file2.pdf"));
}
@Test
public void fileListConfigInput_csv_invalidPaths() {
defaultCommandLine().without("-f").with("-l", "./location/filenames_invalidPaths.csv")
.assertConsoleOutputContains("Invalid filename found");
}
@Test
public void fileListConfigInput_csv_doesntExist() {
defaultCommandLine().without("-f").with("-l", "./location/doesntExist.csv")
.assertConsoleOutputContains("does not exist");
}
@Test
public void fileListConfigInput_xml_invalidXml() {
defaultCommandLine().without("-f").with("-l", "./location/filenames_invalidXml.xml")
.assertConsoleOutputContains("Can't extract filenames from");
}
@Test
public void fileListConfigInput_xml_invalidContents() {
defaultCommandLine().without("-f").with("-l", "./location/filenames_invalidXml.xml")
.assertConsoleOutputContains("Can't extract filenames from");
}
@Test
public void inputFiles_csv_empty() {
defaultCommandLine().without("-f").with("-l", "./location/empty_filenames.csv")
.assertConsoleOutputContains("No input files specified in ");
}
@Test
public void inputFiles_unsupportedFormatConfigList() {
defaultCommandLine().without("-f").with("-l", "./location/filenames.xls")
.assertConsoleOutputContains("Unsupported file format: xls");
}
@Test
public void filesInput() {
MergeParameters parameters = defaultCommandLine().with("-f", "/tmp/merge/file4.pdf /tmp/merge/file2.pdf")
.invokeSejdaConsole();
assertPdfMergeInputsFilesList(parameters, filesList("/tmp/merge/file4.pdf", "/tmp/merge/file2.pdf"));
}
@Test
public void input_noOptionGiven() {
defaultCommandLine().without("-f").without("-d").without("-l")
.assertConsoleOutputContains("No option given for input");
}
@Test
public void input_tooManyOptionsGiven() {
defaultCommandLine().without("-f").with("-d", "/tmp/merge").with("-l", "./location/filenames.xls")
.assertConsoleOutputContains("Too many options given");
}
private void assertPdfMergeInputsFilesList(MergeParameters parameters,
Collection<Matcher<Iterable<? super String>>> expectedFilesMatchers) {
assertPdfMergeInputsFilesList(parameters, expectedFilesMatchers,
nullsFilledList(parameters.getInputList().size()));
}
private List<String> nullsFilledList(int size) {
List<String> result = new ArrayList<String>();
for (int i = 0; i < size; i++) {
result.add(null);
}
return result;
}
private void assertPdfMergeInputsFilesList(MergeParameters parameters,
Collection<Matcher<Iterable<? super String>>> expectedFilesMatchers, List<String> expectedFilesPasswords) {
List<String> actualFileList = new ArrayList<String>();
List<String> actualPasswords = new ArrayList<String>();
for (int i = 0; i < parameters.getInputList().size(); i++) {
PdfMergeInput each = parameters.getPdfInputList().get(i);
PdfFileSource pdfFileSource = (PdfFileSource) each.getSource();
actualFileList.add(pdfFileSource.getSource().getAbsolutePath());
actualPasswords.add(pdfFileSource.getPassword());
}
for (Matcher<Iterable<? super String>> expectedFileMatcher : expectedFilesMatchers) {
assertThat(actualFileList, expectedFileMatcher);
}
assertEquals(expectedFilesPasswords, actualPasswords);
}
@Test
public void fileListConfigInput_xml() {
MergeParameters parameters = defaultCommandLine().without("-f").with("-l", "/tmp/filenames.xml")
.invokeSejdaConsole();
assertPdfMergeInputsFilesList(parameters,
filesList("/tmp/pdf/inputFile.pdf", "/tmp/pdf/inputFile2.pdf", "/tmp/inputFile1.pdf",
"/tmp/inputFile2.pdf", "/tmp/subdir/inputFile1.pdf", "/tmp/subdir3/inputFile2.pdf",
"/tmp/subdir2/inputFile1.pdf", "/tmp/subdir2/inputFile2.pdf", "/tmp/subdir2/inputFile3.pdf"),
Arrays.asList(null, "test", null, null, null, null, null, "secret2", null));
}
private static final String NO_PASSWORD = null;
private static final Set<PageRange> NO_PAGE_RANGE_SPECIFIED = Collections.emptySet();
private static final Set<PageRange> ALL_PAGES = Collections.emptySet();
@Test
public void pageRange_empty() {
MergeParameters parameters = defaultCommandLine().invokeSejdaConsole();
assertHasPdfMergeInput(parameters, "inputs/input.pdf", NO_PAGE_RANGE_SPECIFIED);
}
@Test
public void pageRange_simpleInterval() {
MergeParameters parameters = defaultCommandLine().with("-s", "3003-3010").invokeSejdaConsole();
assertHasPdfMergeInput(parameters, "inputs/input.pdf", Arrays.asList(new PageRange(3003, 3010)));
assertHasPdfMergeInput(parameters, "inputs/second_input.pdf", NO_PAGE_RANGE_SPECIFIED);
}
@Test
public void pageRange_openedInterval() {
MergeParameters parameters = defaultCommandLine().with("-s", "2-").invokeSejdaConsole();
assertHasPdfMergeInput(parameters, "inputs/input.pdf", Arrays.asList(new PageRange(2)));
assertHasPdfMergeInput(parameters, "inputs/second_input.pdf", NO_PAGE_RANGE_SPECIFIED);
}
@Test
public void pageRange_singlePage() {
MergeParameters parameters = defaultCommandLine().with("-s", "3003").invokeSejdaConsole();
assertHasPdfMergeInput(parameters, "inputs/input.pdf", Arrays.asList(new PageRange(3003, 3003)));
assertHasPdfMergeInput(parameters, "inputs/second_input.pdf", NO_PAGE_RANGE_SPECIFIED);
}
@Test
public void pageRange_allPages() {
MergeParameters parameters = defaultCommandLine().with("-s", "all").invokeSejdaConsole();
assertHasPdfMergeInput(parameters, "inputs/input.pdf", ALL_PAGES);
assertHasPdfMergeInput(parameters, "inputs/second_input.pdf", NO_PAGE_RANGE_SPECIFIED);
}
@Test
public void pageRange_combined() {
MergeParameters parameters = defaultCommandLine().with("-s", "all:3,5,8-10,2,2,9-9,30-").invokeSejdaConsole();
assertHasPdfMergeInput(parameters, "inputs/input.pdf", ALL_PAGES);
assertHasPdfMergeInput(parameters, "inputs/second_input.pdf",
Arrays.asList(new PageRange(3, 3), new PageRange(5, 5), new PageRange(8, 10), new PageRange(2, 2),
new PageRange(9, 9), new PageRange(30)));
}
private void assertHasPdfMergeInput(MergeParameters parameters, String filename,
Collection<PageRange> expectedPageRanges) {
assertHasPdfMergeInput(parameters, filename, NO_PASSWORD, expectedPageRanges);
}
private void assertHasPdfMergeInput(MergeParameters parameters, String filename, String password,
Collection<PageRange> expectedPageRanges) {
boolean found = false;
File file = new File(filename);
for (PdfMergeInput each : parameters.getPdfInputList()) {
PdfFileSource pdfFileSource = (PdfFileSource) each.getSource();
if (matchesPdfFileSource(file, password, pdfFileSource)) {
assertContainsAll("For file " + pdfFileSource.getName(), expectedPageRanges, each.getPageSelection());
found = true;
}
}
assertTrue(
"File '" + file + "'"
+ (StringUtils.isEmpty(password) ? " and no password" : " and password '" + password + "'"),
found);
}
}