// Copyright (c) 2011, David J. Pearce (djp@ecs.vuw.ac.nz) // All rights reserved. // // This software may be modified and distributed under the terms // of the BSD license. See the LICENSE file for details. package wyc.util; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import wybs.lang.Build; import wybs.lang.NameID; import wybs.util.StdProject; import wyc.Activator; import wyc.commands.Compile; import wyc.commands.Run; import wycc.util.Logger; import wycc.util.Pair; import wyfs.lang.Content; import wyfs.lang.Path; import wyfs.util.DirectoryRoot; import wyil.lang.Type; import wyil.util.interpreter.Interpreter; public class TestUtils { /** * Scan a directory to get the names of all the whiley source files * in that directory. The list of file names can be used as input * parameters to a JUnit test. * * If the system property <code>test.name.contains</code> is set, * then the list of files returned will be filtered. Only file * names that contain the property will be returned. This makes it * possible to run a subset of tests when testing interactively * from the command line. * * @param srcDir The path of the directory to scan. */ public static Collection<Object[]> findTestNames(String srcDir) { final String suffix = ".whiley"; String containsFilter = System.getProperty("test.name.contains"); ArrayList<Object[]> testcases = new ArrayList<>(); for (File f : new File(srcDir).listFiles()) { // Check it's a file if (!f.isFile()) { continue; } String name = f.getName(); // Check it's a whiley source file if (!name.endsWith(suffix)) { continue; } // Get rid of ".whiley" extension String testName = name.substring(0, name.length() - suffix.length()); // If there's a filter, check the name matches if (containsFilter != null && !testName.contains(containsFilter)) { continue; } testcases.add(new Object[] { testName }); } // Sort the result by filename Collections.sort(testcases, new Comparator<Object[]>() { @Override public int compare(Object[] o1, Object[] o2) { return ((String) o1[0]).compareTo((String) o2[0]); } }); return testcases; } /** * Run the Whiley Compiler with the given list of arguments. * * @param args * --- list of command-line arguments to provide to the Whiley * Compiler. * @return * @throws IOException */ public static Pair<Compile.Result,String> compile(File whileydir, boolean verify, String... args) throws IOException { ByteArrayOutputStream syserr = new ByteArrayOutputStream(); ByteArrayOutputStream sysout = new ByteArrayOutputStream(); Content.Registry registry = new wyc.Activator.Registry(); Compile cmd = new Compile(registry,Logger.NULL,sysout,syserr); cmd.setWhileydir(whileydir); cmd.setWyaldir(whileydir); // if(verify) { cmd.setVerify(); } Compile.Result result = cmd.execute(args); byte[] errBytes = syserr.toByteArray(); byte[] outBytes = sysout.toByteArray(); String output = new String(errBytes) + new String(outBytes); return new Pair<>(result,output); } /** * Execute a given WyIL file using the default interpreter. * * @param wyilDir * The root directory to look for the WyIL file. * @param id * The name of the WyIL file * @throws IOException */ public static void execWyil(File wyilDir, Path.ID id) throws IOException { Content.Registry registry = new wyc.Activator.Registry(); Run cmd = new Run(registry,Logger.NULL); cmd.setWyildir(wyilDir); cmd.execute(id.toString(),"test"); } /** * Compare the output of executing java on the test case with a reference * file. If the output differs from the reference output, then the offending * line is written to the stdout and an exception is thrown. * * @param output * This provides the output from executing java on the test case. * @param referenceFile * The full path to the reference file. This should use the * appropriate separator char for the host operating system. * @throws IOException */ public static boolean compare(String output, String referenceFile) throws IOException { BufferedReader outReader = new BufferedReader(new StringReader(output)); BufferedReader refReader = new BufferedReader(new FileReader(new File(referenceFile))); boolean match = true; while (true) { String l1 = refReader.readLine(); String l2 = outReader.readLine(); if (l1 != null && l2 != null) { if (!l1.equals(l2)) { System.err.println(" < " + l1); System.err.println(" > " + l2); match = false; } } else if (l1 != null) { System.err.println(" < " + l1); match = false; } else if (l2 != null) { System.err.println(" > " + l2); match = false; } else { break; } } if (!match) { System.err.println(); return false; } return true; } /** * Grab everything produced by a given input stream until the End-Of-File * (EOF) is reached. This is implemented as a separate thread to ensure that * reading from other streams can happen concurrently. For example, we can * read concurrently from <code>stdin</code> and <code>stderr</code> for * some process without blocking that process. * * @author David J. Pearce * */ static public class StreamGrabber extends Thread { private InputStream input; private StringBuffer buffer; public StreamGrabber(InputStream input, StringBuffer buffer) { this.input = input; this.buffer = buffer; start(); } @Override public void run() { try { int nextChar; // keep reading!! while ((nextChar = input.read()) != -1) { buffer.append((char) nextChar); } } catch (IOException ioe) { } } } }