/* * Copyright 2011 Carsten Pfeiffer * * 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. */ package org.outerj.daisy.diff.html; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import java.io.*; import java.net.URL; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.outerj.daisy.diff.BetterParameterized; /** * Runs all tests in the testdata directory. * The directories may be nested until the files <code>a.html</code> and <code>b.html</code> are * found, in which case the directory is considered a leaf directory * containing actual test data. * * A two-way diff will be performed using the file <code>a.html</code> as the "old" * version and the file <code>b.html</code> as the "new" version. * * Optionally a file <code>ancestor.html</code> may be present, which will be used * as the ancestor version in a three-way diff. No two-way diffing will * be performed in that case. * * The expected results of the two- or three-way diff must be provided * in the file <code>expected.html</code> * * A test case fails if the results of the diff does not exactly match the contents * of the <code>expected.html</code> * * Note: The files are expected to be UTF-8 encoded. * * @author Carsten Pfeiffer <carsten.pfeiffer@gebit.de> * @version 05 Jul 2011 */ @RunWith(BetterParameterized.class) public class FileBasedTest{ /** * For creating (missing) test results from current output. */ private static final boolean CREATE_EXPECTED_RESULTS; /** * For debugging: If empty, all tests residing in the directory will be executed * Otherwise, only tests whose directory name is in this set will be executed. */ private static final Set<String> ONLY_TESTS = new HashSet<String>(); static { // ONLY_TESTS.add("table-discontinuous-cellcontents-replaced"); String onlyTests= System.getenv("ONLY_TESTS"); if( onlyTests!=null && !"".equals(onlyTests) ) { ONLY_TESTS.add( onlyTests ); } String createExpected= System.getenv( "CREATE_EXPECTED_RESULTS"); CREATE_EXPECTED_RESULTS= createExpected!=null && !"".equals(createExpected) && !"false".equals(createExpected); } private final File testDirectory; public FileBasedTest(File testDirectory) { this.testDirectory = testDirectory; System.setProperty("line.separator", "\n"); } /** * Runs a file-based test for the given test directory. Inside this * directory, the files a.html, b.html and expected.html are, optionally * also the file ancestor.html. * @throws Exception */ @Test public void test() throws Exception { File aTestDir = this.testDirectory; TestHelper tempHelper = new TestHelper(aTestDir); String tempResults = null; if (tempHelper.hasAncestor()) { tempResults = HtmlTestFixture.diff( tempHelper.readContents(tempHelper.getAncestor()), tempHelper.readContents(tempHelper.getOld()), tempHelper.readContents(tempHelper.getNew())); } else { tempResults = HtmlTestFixture.diff( tempHelper.readContents(tempHelper.getOld()), tempHelper.readContents(tempHelper.getNew())); } tempResults = new StringBuilder(tempResults) .insert(0, tempHelper.getHtmlHeader()).append(tempHelper.getHtmlFooter()).toString(); String tempExpected = null; try { tempExpected = tempHelper.getExpectedResults(); } catch (FileNotFoundException ex) { writeResultsFile(aTestDir, tempResults); if (CREATE_EXPECTED_RESULTS) { // create all missing results instead of bailing out return; } throw ex; } if (!tempExpected.equals(tempResults)) { System.out.println("Length: expected: " + tempExpected.length() + ", actual: " + tempResults.length()); writeResultsFile(aTestDir, tempResults); System.err.println("Expected:"); System.err.println(tempExpected); System.err.println("Actual:"); System.err.println(tempResults); assertEquals("Content for test: " + testDirectory, tempExpected, tempResults); } } /** * Writes the given contents into a file of the given directory. By default, * the file is named _actual_result.html. This is useful for generating initial * testresults (expected.html) * @param aDirectory * @param someContents */ private void writeResultsFile(File aDirectory, String someContents) { String tempName = CREATE_EXPECTED_RESULTS ? TestHelper.EXPECTED_NAME : "_actual_result.html"; System.err.println("Results file " + TestHelper.EXPECTED_NAME + " not found for " + aDirectory.getAbsolutePath() + ", writing actual diff to " + tempName); try { Writer tempWriter = new OutputStreamWriter(new FileOutputStream(new File(aDirectory, tempName)), TestHelper.ENCODING); tempWriter.write(someContents); tempWriter.flush(); tempWriter.close(); } catch (Exception ex) { //ignore, this is just for easier testresults creation } } @Parameterized.Parameters public static List<Object[]> findAllTestDataDirs() throws IOException { //File tempRootDir = new File("testdata"); URL tempRootDirURL = Thread.currentThread().getContextClassLoader().getResource("testdata"); File tempRootDir = new File(tempRootDirURL.getPath()); return findTestDataDirsRecursive(tempRootDir); } /** * Returns a list of all directories which contain testdata, that is, a.html, b.html etc. * @param aRootDir the directory to start with */ private static List<Object[]> findTestDataDirsRecursive(File aRootDir) throws IOException { final List<File> tempIntermediateDirs = new ArrayList<File>(); File[] tempTestDataDirs = aRootDir.listFiles( new FileFilter() { public boolean accept(File aFile) { if (!aFile.isDirectory() || aFile.getName().startsWith(".")) { return false; } if (TestHelper.isTestDataDir(aFile)) { if (ONLY_TESTS.isEmpty()) { return true; } return ONLY_TESTS.contains(aFile.getName()); } else { // must be an intermediate directory tempIntermediateDirs.add(aFile); } return false; } } ); List<Object[]> tempResult = new ArrayList<Object[]>(); for (File tempTestDataDir : tempTestDataDirs){ // to match the full path, use tempTestDataDir.getCanonicalPath() tempResult.add( new Object[]{ tempTestDataDir} ); } // recursively find all further test data directories for (File tempIntermediate : tempIntermediateDirs) { tempResult.addAll(findTestDataDirsRecursive(tempIntermediate)); } if (ONLY_TESTS.isEmpty() && tempIntermediateDirs.size() > 0 && tempResult.size() == tempTestDataDirs.length) { // we had intermediate dirs, but they did not contain any test data directories: fail StringBuilder tempBuilder = new StringBuilder(); for (File tempFile : tempIntermediateDirs) { tempBuilder.append(tempFile.getAbsolutePath()).append("\n"); } fail("Directories without testdata found: " + tempBuilder.toString()); } return tempResult; } }