package de.gaalop; import java.io.File; import java.io.IOException; import java.text.DecimalFormatSymbols; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Random; import java.util.Scanner; import org.antlr.runtime.ANTLRStringStream; import org.antlr.runtime.CommonTokenStream; import org.antlr.runtime.RecognitionException; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; import de.gaalop.HorizonJUnitTest.*; import de.gaalop.testbench.CoeffReader; import de.gaalop.testbench.TestbenchGenerator; import de.gaalop.testbench.TestbenchLexer; import de.gaalop.testbench.TestbenchParser; import static org.junit.Assert.*; /** * Executes a suite of test comparing the original CLUCalc output with optimized CLUCalc and C++ outputs. <br /> * <br /> * <b>Note:</b> No not forget to clean and rebuild source files when editing CLUCalc files externally. Otherwise, cached * binary files could contain obsolete code. * * @author Christian Schwinn * */ @RunWith(Suite.class) @SuiteClasses(value = { FileTests.class, }) public class HorizonJUnitTest { public static class OutputSet { private double[] cppValues; private double[] cluOriginalValues; private double[] cluOptimizedValues; public void setCPP(String result) { cppValues = parseString(result); } public void setCLUOriginal(String result) { cluOriginalValues = parseString(result); } public void setCLUOptimized(String result) { cluOptimizedValues = parseString(result); } public double[] getCppValues() { return cppValues; } public double[] getCluOriginalValues() { return cluOriginalValues; } public double[] getCluOptimizedValues() { return cluOptimizedValues; } private double[] parseString(String string) { ANTLRStringStream input = new ANTLRStringStream(string); TestbenchLexer lexer = new TestbenchLexer(input); CommonTokenStream tokenStream = new CommonTokenStream(lexer); TestbenchParser parser = new TestbenchParser(tokenStream); try { CoeffReader reader = parser.line(); return reader.getCoeffs(); } catch (RecognitionException e) { e.printStackTrace(); } throw new IllegalStateException("Line " + string + " could not be parsed."); } } public static class FileTests { private Random r = new Random(System.currentTimeMillis()); private float nextFloat() { return r.nextFloat(); } @Before public void init() { r.setSeed(System.currentTimeMillis()); HorizonJUnitTest.init(); } /** * Tests the Horizon.clu example. * * @throws IOException */ @Test public void horizon() throws Exception { String fileName = getClass().getResource("Horizon.clu").getFile(); inputValues.put("mx", nextFloat()); inputValues.put("my", nextFloat()); inputValues.put("mz", nextFloat()); inputValues.put("px", nextFloat()); inputValues.put("py", nextFloat()); inputValues.put("pz", nextFloat()); inputValues.put("r", nextFloat()); int outputMVs = 1; compare(fileName, outputMVs); } } final static String PATH = "C:/Users/Christian/Downloads/Testbench/"; final static String INCLUDE = "C:/Program Files (x86)/CLUViz/v6_1/SDK/include"; final static String LIBPATH = "C:/Program Files (x86)/CLUViz/v6_1/SDK/lib"; static TestbenchGenerator generator; static Map<String, Float> inputValues = new HashMap<String, Float>(); static void init() { inputValues.clear(); } private static File compile() throws Exception { generator.run(); generator.createCompileScript(INCLUDE, LIBPATH); return generator.compile(); } private static Scanner run(File executable) throws IOException { ProcessBuilder pb = new ProcessBuilder(executable.getAbsolutePath()); pb.directory(executable.getParentFile()); Process p = pb.start(); return new Scanner(p.getInputStream()); } private static List<OutputSet> parseResult(Scanner scanner, int numElements) { List<OutputSet> results = new ArrayList<OutputSet>(); for (int i = 0; i < numElements; i++) { results.add(new OutputSet()); } // read CPP header printNextLine(scanner); // read CPP outputs for (int i = 0; i < numElements; i++) { String vector = printNextLine(scanner); results.get(i).setCPP(vector); } // read CLU original header printNextLine(scanner); // read CLU original outputs for (int i = 0; i < numElements; i++) { String vector = printNextLine(scanner); results.get(i).setCLUOriginal(vector); } // read CLU opt header printNextLine(scanner); // read CLU opt outputs for (int i = 0; i < numElements; i++) { String vector = printNextLine(scanner); results.get(i).setCLUOptimized(vector); } return results; } private static String printNextLine(Scanner scanner) { String line = scanner.nextLine(); System.out.println(line); return line; } static void compare(String fileName, int numVectors) throws Exception { generator = new TestbenchGenerator(fileName, PATH, inputValues); doCompare(numVectors); } static void compare(String fileName, String contents, int numVectors) throws Exception { generator = new TestbenchGenerator(fileName, contents, PATH, inputValues); doCompare(numVectors); } private static void doCompare(int numVectors) throws Exception { File exe = compile(); Scanner scanner = run(exe); List<OutputSet> results = parseResult(scanner, numVectors); compareMultivectors(results); } private static void compareMultivectors(List<OutputSet> actualList) { for (int i = 0; i < actualList.size(); i++) { OutputSet actual = actualList.get(i); for (int element = 0; element < 32; element++) { double cluOriginal = actual.getCluOriginalValues()[element]; double cluOptimized = actual.getCluOptimizedValues()[element]; double cpp = actual.getCppValues()[element]; double epsilon = getEpsilon(cluOriginal); System.out.println("Using epsilon " + epsilon + " for " + cluOriginal); assertEquals(cluOriginal, cluOptimized, epsilon); String comparison = "Index " + element + ": " + cluOriginal + " == " + cluOptimized; assertEquals(cluOriginal, cpp, epsilon); comparison += " == " + cpp; if (cluOriginal != 0.0d) { System.out.println(comparison); } } } } private static double getEpsilon(double d) { Locale.setDefault(Locale.US); String string = Double.toString(d); int decimals = string.substring(string.lastIndexOf(DecimalFormatSymbols.getInstance().getDecimalSeparator())+1).length(); return Math.pow(10, -decimals); } }