comparison graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java @ 13809:030e75d4d7dc

SL: added junit integration for external tests.
author Christian Humer <christian.humer@gmail.com>
date Tue, 28 Jan 2014 19:37:26 +0100
parents b5b64fe6963f
children b16ec83edc73
comparison
equal deleted inserted replaced
13808:5dfc531a5af1 13809:030e75d4d7dc
21 * questions. 21 * questions.
22 */ 22 */
23 package com.oracle.truffle.sl.test; 23 package com.oracle.truffle.sl.test;
24 24
25 import java.io.*; 25 import java.io.*;
26 import java.nio.charset.*;
26 import java.nio.file.*; 27 import java.nio.file.*;
27 import java.nio.file.attribute.*; 28 import java.nio.file.attribute.*;
28 import java.util.*; 29 import java.util.*;
29 30
30 import org.junit.*; 31 import org.junit.*;
32 import org.junit.internal.*;
33 import org.junit.runner.*;
34 import org.junit.runner.manipulation.*;
35 import org.junit.runner.notification.*;
36 import org.junit.runners.*;
37 import org.junit.runners.model.*;
31 38
32 import com.oracle.truffle.api.*; 39 import com.oracle.truffle.api.*;
33 import com.oracle.truffle.api.source.*; 40 import com.oracle.truffle.api.source.*;
34 import com.oracle.truffle.sl.*; 41 import com.oracle.truffle.sl.*;
35 import com.oracle.truffle.sl.runtime.*; 42 import com.oracle.truffle.sl.runtime.*;
36 43 import com.oracle.truffle.sl.test.SLTestRunner.TestCase;
37 public class SLTestRunner { 44
45 public final class SLTestRunner extends ParentRunner<TestCase> {
38 46
39 private static final int REPEATS = 10; 47 private static final int REPEATS = 10;
40 private static final String TEST_DIR = "graal/com.oracle.truffle.sl.test/tests"; 48
41 private static final String INPUT_SUFFIX = ".sl"; 49 private static final String INPUT_SUFFIX = ".sl";
42 private static final String OUTPUT_SUFFIX = ".output"; 50 private static final String OUTPUT_SUFFIX = ".output";
43 51
44 static class TestCase { 52 private static final String LF = System.getProperty("line.separator");
45 protected final String name; 53
46 protected final Source input; 54 public static final class TestCase {
47 protected final String expectedOutput; 55 private final Source input;
48 protected String actualOutput; 56 private final String expectedOutput;
49 57 private final Description name;
50 protected TestCase(String name, Source input, String expectedOutput) { 58
51 this.name = name; 59 public TestCase(Class<?> testClass, String name, Source input, String expectedOutput) {
52 this.input = input; 60 this.input = input;
53 this.expectedOutput = expectedOutput; 61 this.expectedOutput = expectedOutput;
54 } 62 this.name = Description.createTestDescription(testClass, name);
55 } 63 }
56 64 }
57 protected boolean useConsole = false; 65
58 66 private final SourceManager sourceManager = new SourceManager();
59 protected final SourceManager sourceManager = new SourceManager(); 67 private final List<TestCase> testCases;
60 protected final List<TestCase> testCases = new ArrayList<>(); 68
61 69 public SLTestRunner(Class<?> runningClass) throws InitializationError {
62 protected boolean runTests(String namePattern) throws IOException { 70 super(runningClass);
63 Path testsRoot = FileSystems.getDefault().getPath(TEST_DIR); 71 try {
64 72 testCases = createTests(runningClass);
65 Files.walkFileTree(testsRoot, new SimpleFileVisitor<Path>() { 73 } catch (IOException e) {
74 throw new InitializationError(e);
75 }
76 }
77
78 @Override
79 protected Description describeChild(TestCase child) {
80 return child.name;
81 }
82
83 @Override
84 protected List<TestCase> getChildren() {
85 return testCases;
86 }
87
88 @Override
89 public void filter(Filter filter) throws NoTestsRemainException {
90 super.filter(filter);
91 }
92
93 protected List<TestCase> createTests(final Class<?> c) throws IOException, InitializationError {
94 SLTestSuite suite = c.getAnnotation(SLTestSuite.class);
95 if (suite == null) {
96 throw new InitializationError(String.format("@%s annotation required on class '%s' to run with '%s'.", SLTestSuite.class.getSimpleName(), c.getName(), SLTestRunner.class.getSimpleName()));
97 }
98
99 String[] pathes = suite.value();
100
101 Path root = null;
102 for (String path : pathes) {
103 root = FileSystems.getDefault().getPath(path);
104 if (Files.exists(root)) {
105 break;
106 }
107 }
108 if (root == null && pathes.length > 0) {
109 throw new FileNotFoundException(pathes[0]);
110 }
111
112 final Path rootPath = root;
113
114 final List<TestCase> foundCases = new ArrayList<>();
115 Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() {
66 @Override 116 @Override
67 public FileVisitResult visitFile(Path inputFile, BasicFileAttributes attrs) throws IOException { 117 public FileVisitResult visitFile(Path inputFile, BasicFileAttributes attrs) throws IOException {
68 String name = inputFile.getFileName().toString(); 118 String name = inputFile.getFileName().toString();
69 if (name.endsWith(INPUT_SUFFIX)) { 119 if (name.endsWith(INPUT_SUFFIX)) {
70 name = name.substring(0, name.length() - INPUT_SUFFIX.length()); 120 String baseName = name.substring(0, name.length() - INPUT_SUFFIX.length());
71 Path outputFile = inputFile.resolveSibling(name + OUTPUT_SUFFIX); 121
122 Path outputFile = inputFile.resolveSibling(baseName + OUTPUT_SUFFIX);
72 if (!Files.exists(outputFile)) { 123 if (!Files.exists(outputFile)) {
73 throw new Error("Output file does not exist: " + outputFile); 124 throw new Error("Output file does not exist: " + outputFile);
74 } 125 }
75 126
76 testCases.add(new TestCase(name, sourceManager.get(inputFile.toString()), new String(Files.readAllBytes(outputFile)))); 127 // fix line feeds for non unix os
128 StringBuilder outFile = new StringBuilder();
129 for (String line : Files.readAllLines(outputFile, Charset.defaultCharset())) {
130 outFile.append(line);
131 outFile.append(LF);
132 }
133 foundCases.add(new TestCase(c, baseName, sourceManager.get(inputFile.toString()), outFile.toString()));
77 } 134 }
78 return FileVisitResult.CONTINUE; 135 return FileVisitResult.CONTINUE;
79 } 136 }
80 }); 137 });
81 138 return foundCases;
82 if (testCases.size() == 0) { 139 }
83 System.out.format("No test cases match filter %s", namePattern); 140
84 return false; 141 @Override
85 } 142 protected void runChild(TestCase testCase, RunNotifier notifier) {
86 143 notifier.fireTestStarted(testCase.name);
87 boolean success = true;
88 for (TestCase testCase : testCases) {
89 if (namePattern.length() == 0 || testCase.name.toLowerCase().contains(namePattern.toLowerCase())) {
90 success = success & executeTest(testCase);
91 }
92 }
93 return success;
94 }
95
96 protected boolean executeTest(TestCase testCase) {
97 System.out.format("Running %s\n", testCase.name);
98 144
99 ByteArrayOutputStream out = new ByteArrayOutputStream(); 145 ByteArrayOutputStream out = new ByteArrayOutputStream();
100 PrintStream printer = new PrintStream(useConsole ? new SplitOutputStream(out, System.err) : out); 146 PrintStream printer = new PrintStream(out);
101 PrintStream origErr = System.err; 147 PrintStream origErr = System.err;
102 try { 148 try {
103 System.setErr(printer); 149 System.setErr(printer);
104 SLContext context = new SLContext(sourceManager, printer); 150 SLContext context = new SLContext(sourceManager, printer);
105 SLMain.run(context, testCase.input, null, REPEATS); 151 SLMain.run(context, testCase.input, null, REPEATS);
152
153 String actualOutput = new String(out.toByteArray());
154
155 Assert.assertEquals(repeat(testCase.expectedOutput, REPEATS), actualOutput);
156 } catch (AssertionError e) {
157 notifier.fireTestFailure(new Failure(testCase.name, e));
106 } catch (Throwable ex) { 158 } catch (Throwable ex) {
107 ex.printStackTrace(printer); 159 notifier.fireTestFailure(new Failure(testCase.name, ex));
108 } finally { 160 } finally {
109 System.setErr(origErr); 161 System.setErr(origErr);
110 } 162 notifier.fireTestFinished(testCase.name);
111 testCase.actualOutput = new String(out.toByteArray());
112
113 if (testCase.actualOutput.equals(repeat(testCase.expectedOutput, REPEATS))) {
114 System.out.format("OK %s\n", testCase.name);
115 return true;
116 } else {
117 if (!useConsole) {
118 System.out.format("== Expected ==\n%s\n", testCase.expectedOutput);
119 System.out.format("== Actual ==\n%s\n", testCase.actualOutput);
120 }
121 System.out.format("FAILED %s\n", testCase.name);
122 return false;
123 } 163 }
124 } 164 }
125 165
126 private static String repeat(String s, int count) { 166 private static String repeat(String s, int count) {
127 StringBuilder result = new StringBuilder(s.length() * count); 167 StringBuilder result = new StringBuilder(s.length() * count);
129 result.append(s); 169 result.append(s);
130 } 170 }
131 return result.toString(); 171 return result.toString();
132 } 172 }
133 173
134 public static void main(String[] args) throws IOException { 174 public static void runInMain(Class<?> testClass, String[] args) throws InitializationError, NoTestsRemainException {
135 String namePattern = ""; 175 JUnitCore core = new JUnitCore();
176 core.addListener(new TextListener(System.out));
177 SLTestRunner suite = new SLTestRunner(testClass);
136 if (args.length > 0) { 178 if (args.length > 0) {
137 namePattern = args[0]; 179 suite.filter(new NameFilter(args[0]));
138 } 180 }
139 boolean success = new SLTestRunner().runTests(namePattern); 181 Result r = core.run(suite);
140 if (!success) { 182 if (!r.wasSuccessful()) {
141 System.exit(1); 183 System.exit(1);
142 } 184 }
143 } 185 }
144 186
145 @Test 187 private static final class NameFilter extends Filter {
146 public void test() throws IOException { 188 private final String pattern;
147 Assert.assertTrue(runTests("")); 189
148 } 190 private NameFilter(String pattern) {
191 this.pattern = pattern.toLowerCase();
192 }
193
194 @Override
195 public boolean shouldRun(Description description) {
196 return description.getMethodName().toLowerCase().contains(pattern);
197 }
198
199 @Override
200 public String describe() {
201 return "Filter contains " + pattern;
202 }
203 }
204
149 } 205 }