- improve parser/test case debugging efficiency
diff --git a/test/bin/diffutils/diff.exe b/test/bin/diffutils/diff.exe new file mode 100644 index 0000000..85f370d --- /dev/null +++ b/test/bin/diffutils/diff.exe Binary files differ
diff --git a/test/bin/diffutils/libiconv2.dll b/test/bin/diffutils/libiconv2.dll new file mode 100644 index 0000000..fb1ffba --- /dev/null +++ b/test/bin/diffutils/libiconv2.dll Binary files differ
diff --git a/test/bin/diffutils/libintl3.dll b/test/bin/diffutils/libintl3.dll new file mode 100644 index 0000000..ec11e6b --- /dev/null +++ b/test/bin/diffutils/libintl3.dll Binary files differ
diff --git a/test/prettify/PrettifyTest.java b/test/prettify/PrettifyTest.java index 6ada004..49f2543 100644 --- a/test/prettify/PrettifyTest.java +++ b/test/prettify/PrettifyTest.java
@@ -13,6 +13,7 @@ // limitations under the License. package prettify; +import java.io.Closeable; import prettify.parser.Util; import prettify.parser.Job; import prettify.parser.Prettify; @@ -24,8 +25,12 @@ import java.util.ArrayList; import java.io.File; import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; @@ -39,6 +44,7 @@ */ public class PrettifyTest { + private static final Logger LOG = Logger.getLogger(PrettifyTest.class.getName()); static { // set debug mode System.setProperty("PrettifyDebugMode", "true"); @@ -87,28 +93,57 @@ * @throws IOException error occurred when reading source or result file */ public void test(String extension, String code, boolean removeJSLineNumbering) throws IOException { - String source = unescapeHtmlSpecialChars(new String(readFile(new File(packagePath + "source/" + code + ".txt")), "UTF-8")); - Job job = new Job(0, source); - prettify.langHandlerForExtension(extension, source).decorate(job); - List<Object> decorations = removeJSLineNumbering ? removeNewLines(job.getDecorations(), source) : job.getDecorations(); - final byte[] bytes = readFile(new File(packagePath + "result/" + code + ".txt")); - final StringBuilder plainResult = new StringBuilder(); - List<Object> compare = readResult(unescapeHtmlSpecialChars(new String(bytes, "UTF-8")), removeJSLineNumbering, plainResult); + System.out.println("+ performing '" + code + "' test..."); + String sourceString = unescapeHtmlSpecialChars(new String(readFile(new File(packagePath + "source/" + code + ".txt")), "UTF-8")); - if (!removeJSLineNumbering) { - assertEquals(source, plainResult.toString()); + List<Object> decorations = null; + // parse/decorate the sourceString + Job prettifyJob = new Job(0, sourceString); + prettify.langHandlerForExtension(extension, sourceString).decorate(prettifyJob); + decorations = removeJSLineNumbering ? removeNewLines(prettifyJob.getDecorations(), sourceString) : prettifyJob.getDecorations(); + + String plainResult = null; + String resultString = null; + // read expected result + final StringBuilder plainResultSb = new StringBuilder(); + resultString = new String(readFile(new File(packagePath + "result/" + code + ".txt")), "UTF-8"); + List<Object> compare = readResult(unescapeHtmlSpecialChars(resultString), removeJSLineNumbering, plainResultSb); + plainResult = plainResultSb.toString(); + + + boolean testPassed = true; + + if (!removeJSLineNumbering && !sourceString.equals(plainResult)) { + // check to ensure source and result, without decorations, are the same + testPassed = false; + } + if (!Arrays.equals(compare.toArray(), decorations.toArray())) { + testPassed = false; } - if (Arrays.equals(compare.toArray(), decorations.toArray())) { - return; - } + if (!testPassed) { + String parsedSourceString = prettify(sourceString, compare); + String parsedResultString = prettify(sourceString, decorations); - final StringBuilder errorMessage = new StringBuilder(); - errorMessage.append("Prettify failed. Expected:\n"); - errorMessage.append(prettify(source, compare)); - errorMessage.append("\n\nBut was:\n"); - errorMessage.append(prettify(source, decorations)); - fail(errorMessage.toString()); + // generate files for WinMerge + File originalResultFile = new File(code + "_original.txt"); + File revisedResultFile = new File(code + "_revised.txt"); + writeFile(originalResultFile, resultString); + writeFile(revisedResultFile, parsedResultString); + + // generate diff file + diff(originalResultFile, revisedResultFile, new File(code + ".diff")); + + final StringBuilder errorMessage = new StringBuilder(); + errorMessage.append("++++++++++++++++++++++++++++++ Expected Result ++++++++++++++++++++++++++++++"); + errorMessage.append("\n"); + errorMessage.append(parsedSourceString); + errorMessage.append("\n\n"); + errorMessage.append("++++++++++++++++++++++++++++++ Actual Result ++++++++++++++++++++++++++++++"); + errorMessage.append("\n"); + errorMessage.append(parsedResultString); + fail(errorMessage.toString()); + } } @Test @@ -352,28 +387,110 @@ return inputString.replace("<", "<").replace(">", ">").replace(" ", " ").replace("&", "&"); } - private static String prettify(String source, List<Object> decorations) { - if (decorations.size() % 2 != 0) { - throw new IllegalArgumentException(); - } + private static String prettify(String source, List<Object> decorations) { + if (decorations.size() % 2 != 0) { + throw new IllegalArgumentException(); + } - final StringBuilder result = new StringBuilder(); - for (int index = 0; index < decorations.size(); index+=2) { - final int start = ((Integer)decorations.get(index)).intValue(); - final int end = index < decorations.size() - 2 ? ((Integer)decorations.get(index + 2)).intValue() : source.length(); - final String type = (String)decorations.get(index + 1); - result.append("`"); - result.append(type.toUpperCase()); - if (end > source.length()) { - result.append("..."); - break; - } + final StringBuilder result = new StringBuilder(); + for (int index = 0; index < decorations.size(); index += 2) { + final int start = ((Integer) decorations.get(index)).intValue(); + final int end = index < decorations.size() - 2 ? ((Integer) decorations.get(index + 2)).intValue() : source.length(); + final String type = (String) decorations.get(index + 1); + result.append("`"); + result.append(type.toUpperCase()); + if (end > source.length()) { + result.append("..."); + break; + } - result.append(source.substring(start, end)); - result.append("`"); - result.append("END"); - } + result.append(source.substring(start, end)); + result.append("`"); + result.append("END"); + } - return result.toString(); - } + return result.toString(); + } + + protected static void diff(File originalFile, File revisedFile, File diffFileSaveTo) { + ProcessBuilder builder = new ProcessBuilder(new String[]{"test/bin/diffutils/diff.exe", originalFile.getAbsolutePath(), revisedFile.getAbsolutePath()}); + Process process = null; + FileOutputStream fout = null; + try { + process = builder.start(); + fout = new FileOutputStream(diffFileSaveTo); + + // not good code of course + // need to read all error output stream in order to finish + InputStream stream = process.getInputStream(); + int byteRead = -1; + while ((byteRead = stream.read()) != -1) { + fout.write(byteRead); + } + } catch (Exception ex) { + LOG.log(Level.SEVERE, "Failed to generate diff file, saveTo: " + diffFileSaveTo.getAbsolutePath(), ex); + } finally { + closeQuietly(fout); + } + try { + process.waitFor(); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + + /** + * Write the string into the file. + * + * @param file the file to write to + * @param content the content to write into the file + * @throws IOException error occurred when writing the content into the file + */ + public static void writeFile(File file, String content) throws IOException { + if (file == null) { + throw new NullPointerException("argument 'file' cannot be null"); + } + if (content == null) { + throw new NullPointerException("argument 'content' cannot be null"); + } + writeFile(file, content.getBytes("UTF-8")); + } + + /** + * Write the byte array into the file. + * + * @param file the file to write to + * @param content the content to write into the file + * @throws IOException error occurred when writing the content into the file + */ + public static void writeFile(File file, byte[] content) throws IOException { + if (file == null) { + throw new NullPointerException("argument 'file' cannot be null"); + } + if (content == null) { + throw new NullPointerException("argument 'content' cannot be null"); + } + FileOutputStream fout = null; + try { + fout = new FileOutputStream(file); + fout.write(content); + } finally { + closeQuietly(fout); + } + } + + /** + * Close the stream quietly without throwing any IO exception. + * + * @param closeable the stream to close, accept null + */ + public static void closeQuietly(Closeable closeable) { + if (closeable != null) { + try { + closeable.close(); + } catch (IOException ex) { + LOG.log(Level.FINE, null, ex); + } + } + } }