| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 #library("TestFramework"); |
| 6 #import("dart:coreimpl"); |
| 7 #import("dart:isolate"); |
| 8 |
| 9 |
| 10 typedef void AsynchronousTestFunction(TestExpectation check); |
| 11 |
| 12 |
| 13 void runTests(List tests, [bool guarded = true]) { |
| 14 TestRunner runner = new TestRunner(new TestSuite(tests), guarded); |
| 15 TestResult result = new TestResult(runner); |
| 16 runner.run(result); |
| 17 } |
| 18 |
| 19 |
| 20 class TestSuite { |
| 21 |
| 22 TestSuite([List tests = const []]) : testCases = <TestCase>[] { |
| 23 for (var test in tests) { |
| 24 addTest(test); |
| 25 } |
| 26 } |
| 27 |
| 28 void addTest(var test) { |
| 29 if (test is Function) { |
| 30 addAsynchronousTestCase(test); |
| 31 } else { |
| 32 test.addToTestSuite(this); |
| 33 } |
| 34 } |
| 35 |
| 36 void addTestCase(TestCase test) { |
| 37 testCases.add(test); |
| 38 } |
| 39 |
| 40 void addAsynchronousTestCase(AsynchronousTestFunction test) { |
| 41 addTestCase(new AsynchronousTestCase(test)); |
| 42 } |
| 43 |
| 44 void run(TestResult result) { |
| 45 for (TestCase test in testCases) { |
| 46 test.run(result); |
| 47 } |
| 48 } |
| 49 |
| 50 final List<TestCase> testCases; |
| 51 |
| 52 } |
| 53 |
| 54 |
| 55 class TestCase { |
| 56 |
| 57 TestCase(); |
| 58 |
| 59 void setUp() { } |
| 60 abstract void performTest(); |
| 61 void tearDown() { } |
| 62 |
| 63 void run(TestResult result) { |
| 64 setUp(); |
| 65 result.runGuarded(this, () { |
| 66 performTest(); |
| 67 tearDown(); |
| 68 }); |
| 69 } |
| 70 |
| 71 void addToTestSuite(TestSuite suite) { |
| 72 suite.addTestCase(this); |
| 73 } |
| 74 } |
| 75 |
| 76 |
| 77 class TestResult { |
| 78 |
| 79 TestResult(this.runner) : errors = [], failures = []; |
| 80 |
| 81 void error(String message, TestCase testCase) { |
| 82 errors.add([message, testCase]); |
| 83 } |
| 84 |
| 85 void failure(String message, TestCase testCase) { |
| 86 failures.add([message, testCase]); |
| 87 } |
| 88 |
| 89 runGuarded(TestCase testCase, Function fn) { |
| 90 if (!runner.guarded) { |
| 91 return fn(); |
| 92 } |
| 93 var result = null; |
| 94 try { |
| 95 result = fn(); |
| 96 } catch (ExpectException exception) { |
| 97 failure(exception.toString(), testCase); |
| 98 testCase.tearDown(); |
| 99 } catch (var exception) { |
| 100 error(exception.toString(), testCase); |
| 101 testCase.tearDown(); |
| 102 } |
| 103 return result; |
| 104 } |
| 105 |
| 106 bool hasDefects() { |
| 107 return !(errors.isEmpty() && failures.isEmpty()); |
| 108 } |
| 109 |
| 110 final TestRunner runner; |
| 111 final List errors; |
| 112 final List failures; |
| 113 |
| 114 } |
| 115 |
| 116 |
| 117 class TestRunner { |
| 118 |
| 119 TestRunner(this.suite, this.guarded); |
| 120 |
| 121 void run(TestResult result) { |
| 122 if (waitForDoneCallback !== null) { |
| 123 waitForDoneCallback(); |
| 124 } |
| 125 suite.run(result); |
| 126 if (AsynchronousTestCase.running == 0) { |
| 127 done(result); |
| 128 } |
| 129 } |
| 130 |
| 131 void done(TestResult result) { |
| 132 if (result.hasDefects()) { |
| 133 printDefects(result); |
| 134 Expect.fail("Test suite failed."); |
| 135 } |
| 136 if (doneCallback !== null) { |
| 137 doneCallback(); |
| 138 } |
| 139 } |
| 140 |
| 141 void printDefects(TestResult result) { |
| 142 printDefectList("Errors", result.errors); |
| 143 printDefectList("Failures", result.failures); |
| 144 } |
| 145 |
| 146 static void printDefectList(String type, List defects) { |
| 147 if (!defects.isEmpty()) { |
| 148 print("$type #${defects.length}:"); |
| 149 for (List defect in defects) { |
| 150 print(" - ${defect[0]}"); |
| 151 } |
| 152 } |
| 153 } |
| 154 |
| 155 final TestSuite suite; |
| 156 final bool guarded; |
| 157 static Function waitForDoneCallback; |
| 158 static Function doneCallback; |
| 159 |
| 160 } |
| 161 |
| 162 |
| 163 class TestExpectation { |
| 164 |
| 165 TestExpectation(this.testCase, this.result); |
| 166 |
| 167 void succeeded() { |
| 168 Expect.equals(0, pendingCallbacks); |
| 169 hasSucceeded = true; |
| 170 testCase.tearDown(); |
| 171 } |
| 172 |
| 173 void failed() { |
| 174 testCase.tearDown(); |
| 175 } |
| 176 |
| 177 Future completes(Future future) { |
| 178 Completer completer = new Completer(); |
| 179 future.then(runs1((value) { |
| 180 completer.complete(value); |
| 181 })); |
| 182 return completer.future; |
| 183 } |
| 184 |
| 185 Function runs0(Function fn) { |
| 186 bool ran = false; // We only check that the function is executed once. |
| 187 pendingCallbacks++; |
| 188 return () { |
| 189 if (!ran) pendingCallbacks--; |
| 190 ran = true; |
| 191 return result.runGuarded(testCase, () => fn()); |
| 192 }; |
| 193 } |
| 194 |
| 195 Function runs1(Function fn) { |
| 196 bool ran = false; // We only check that the function is executed once. |
| 197 pendingCallbacks++; |
| 198 return (a0) { |
| 199 if (!ran) pendingCallbacks--; |
| 200 ran = true; |
| 201 return result.runGuarded(testCase, () => fn(a0)); |
| 202 }; |
| 203 } |
| 204 |
| 205 Function runs2(Function fn) { |
| 206 bool ran = false; // We only check that the function is executed once. |
| 207 pendingCallbacks++; |
| 208 return (a0, a1) { |
| 209 if (!ran) pendingCallbacks--; |
| 210 ran = true; |
| 211 return result.runGuarded(testCase, () => fn(a0, a1)); |
| 212 }; |
| 213 } |
| 214 |
| 215 bool hasPendingCallbacks() { |
| 216 return pendingCallbacks > 0; |
| 217 } |
| 218 |
| 219 final AsynchronousTestCase testCase; |
| 220 final TestResult result; |
| 221 |
| 222 int pendingCallbacks = 0; |
| 223 bool hasSucceeded = false; |
| 224 |
| 225 } |
| 226 |
| 227 |
| 228 class AsynchronousTestCase extends TestCase { |
| 229 |
| 230 AsynchronousTestCase(this.test) : super(); |
| 231 |
| 232 void run(TestResult result) { |
| 233 setUp(); |
| 234 result.runGuarded(this, () { |
| 235 addRunning(result); |
| 236 TestExpectation expect = new TestExpectation(this, result); |
| 237 test(expect); |
| 238 if (!expect.hasPendingCallbacks()) { |
| 239 Expect.isTrue(expect.hasSucceeded); |
| 240 tearDown(); |
| 241 } |
| 242 }); |
| 243 } |
| 244 |
| 245 void tearDown() { |
| 246 removeRunning(); |
| 247 } |
| 248 |
| 249 void addRunning(TestResult result) { |
| 250 if (running++ == 0) { |
| 251 final port = new ReceivePort(); |
| 252 port.receive((message, replyTo) { |
| 253 port.close(); |
| 254 result.runner.done(result); |
| 255 }); |
| 256 keepalive = port; |
| 257 } |
| 258 } |
| 259 |
| 260 void removeRunning() { |
| 261 if (--running == 0) { |
| 262 keepalive.toSendPort().send(null, null); |
| 263 keepalive = null; |
| 264 } |
| 265 } |
| 266 |
| 267 // AsynchronousTestCase.run() calls variable test, not function performTest. |
| 268 void performTest() { |
| 269 Expect.fail('performTest called in AsynchronousTestCase'); |
| 270 } |
| 271 |
| 272 AsynchronousTestFunction test; |
| 273 |
| 274 static int running = 0; |
| 275 static ReceivePort keepalive = null; |
| 276 |
| 277 } |
| OLD | NEW |