OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 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.md file. | 3 // BSD-style license that can be found in the LICENSE.md file. |
4 | 4 |
5 library testing.chain; | 5 library testing.chain; |
6 | 6 |
7 import 'dart:async' show | 7 import 'dart:async' show |
8 Future, | 8 Future, |
9 Stream; | 9 Stream; |
10 | 10 |
11 import 'dart:convert' show | 11 import 'dart:convert' show |
12 JSON, | 12 JSON, |
13 JsonEncoder; | 13 JsonEncoder; |
14 | 14 |
15 import 'dart:io' show | 15 import 'dart:io' show |
16 Directory, | 16 Directory, |
17 File, | 17 File, |
18 FileSystemEntity, | 18 FileSystemEntity, |
19 exitCode; | 19 exitCode; |
20 | 20 |
21 import 'suite.dart' show | 21 import 'suite.dart' show |
22 Suite; | 22 Suite; |
23 | 23 |
24 import '../testing.dart' show | 24 import '../testing.dart' show |
25 TestDescription; | 25 TestDescription; |
26 | 26 |
27 import 'test_dart/status_file_parser.dart' show | 27 import 'test_dart/status_file_parser.dart' show |
28 Expectation, | |
29 ReadTestExpectations, | 28 ReadTestExpectations, |
30 TestExpectations; | 29 TestExpectations; |
31 | 30 |
32 import 'zone_helper.dart' show | 31 import 'zone_helper.dart' show |
33 runGuarded; | 32 runGuarded; |
34 | 33 |
35 import 'error_handling.dart' show | 34 import 'error_handling.dart' show |
36 withErrorHandling; | 35 withErrorHandling; |
37 | 36 |
38 import 'log.dart' show | 37 import 'log.dart' show |
39 logMessage, | 38 logMessage, |
40 logStepComplete, | 39 logStepComplete, |
41 logStepStart, | 40 logStepStart, |
42 logSuiteComplete, | 41 logSuiteComplete, |
43 logTestComplete, | 42 logTestComplete, |
44 logUnexpectedResult, | 43 logUnexpectedResult, |
45 splitLines; | 44 splitLines; |
46 | 45 |
47 import 'multitest.dart' show | 46 import 'multitest.dart' show |
48 MultitestTransformer, | 47 MultitestTransformer, |
49 isError; | 48 isError; |
50 | 49 |
| 50 import 'expectation.dart' show |
| 51 Expectation, |
| 52 ExpectationSet; |
| 53 |
51 typedef Future<ChainContext> CreateContext( | 54 typedef Future<ChainContext> CreateContext( |
52 Chain suite, Map<String, String> environment); | 55 Chain suite, Map<String, String> environment); |
53 | 56 |
54 /// A test suite for tool chains, for example, a compiler. | 57 /// A test suite for tool chains, for example, a compiler. |
55 class Chain extends Suite { | 58 class Chain extends Suite { |
56 final Uri source; | 59 final Uri source; |
57 | 60 |
58 final Uri uri; | 61 final Uri uri; |
59 | 62 |
60 final List<RegExp> pattern; | 63 final List<RegExp> pattern; |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
112 "exclude": []..addAll(exclude.map((RegExp r) => r.pattern)), | 115 "exclude": []..addAll(exclude.map((RegExp r) => r.pattern)), |
113 }; | 116 }; |
114 } | 117 } |
115 } | 118 } |
116 | 119 |
117 abstract class ChainContext { | 120 abstract class ChainContext { |
118 const ChainContext(); | 121 const ChainContext(); |
119 | 122 |
120 List<Step> get steps; | 123 List<Step> get steps; |
121 | 124 |
| 125 ExpectationSet get expectationSet => ExpectationSet.Default; |
| 126 |
122 Future<Null> run(Chain suite, Set<String> selectors) async { | 127 Future<Null> run(Chain suite, Set<String> selectors) async { |
123 TestExpectations expectations = await ReadTestExpectations( | 128 TestExpectations expectations = await ReadTestExpectations( |
124 <String>[suite.statusFile.toFilePath()], {}); | 129 <String>[suite.statusFile.toFilePath()], {}, expectationSet); |
125 Stream<TestDescription> stream = list(suite); | 130 Stream<TestDescription> stream = list(suite); |
126 if (suite.processMultitests) { | 131 if (suite.processMultitests) { |
127 stream = stream.transform(new MultitestTransformer()); | 132 stream = stream.transform(new MultitestTransformer()); |
128 } | 133 } |
129 List<TestDescription> descriptions = await stream.toList(); | 134 List<TestDescription> descriptions = await stream.toList(); |
130 descriptions.sort(); | 135 descriptions.sort(); |
131 Map<TestDescription, Result> unexpectedResults = | 136 Map<TestDescription, Result> unexpectedResults = |
132 <TestDescription, Result>{}; | 137 <TestDescription, Result>{}; |
133 Map<TestDescription, Set<Expectation>> unexpectedOutcomes = | 138 Map<TestDescription, Set<Expectation>> unexpectedOutcomes = |
134 <TestDescription, Set<Expectation>>{}; | 139 <TestDescription, Set<Expectation>>{}; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
182 } | 187 } |
183 }, printLineOnStdout: sb.writeln); | 188 }, printLineOnStdout: sb.writeln); |
184 } else { | 189 } else { |
185 future = new Future.value(null); | 190 future = new Future.value(null); |
186 } | 191 } |
187 future = future.then((Result currentResult) { | 192 future = future.then((Result currentResult) { |
188 if (currentResult != null) { | 193 if (currentResult != null) { |
189 logStepComplete(completed, unexpectedResults.length, | 194 logStepComplete(completed, unexpectedResults.length, |
190 descriptions.length, suite, description, lastStepRun); | 195 descriptions.length, suite, description, lastStepRun); |
191 result = currentResult; | 196 result = currentResult; |
192 if (currentResult.outcome == Expectation.PASS) { | 197 if (currentResult.outcome == Expectation.Pass) { |
193 // The input to the next step is the output of this step. | 198 // The input to the next step is the output of this step. |
194 return doStep(result.output); | 199 return doStep(result.output); |
195 } | 200 } |
196 } | 201 } |
197 if (description.multitestExpectations != null) { | 202 if (description.multitestExpectations != null) { |
198 if (isError(description.multitestExpectations)) { | 203 if (isError(description.multitestExpectations)) { |
199 result = toNegativeTestResult( | 204 result = toNegativeTestResult( |
200 result, description.multitestExpectations); | 205 result, description.multitestExpectations); |
201 } | 206 } |
202 } else if (lastStep == lastStepRun && | 207 } else if (lastStep == lastStepRun && |
203 description.shortName.endsWith("negative_test")) { | 208 description.shortName.endsWith("negative_test")) { |
204 if (result.outcome == Expectation.PASS) { | 209 if (result.outcome == Expectation.Pass) { |
205 result.addLog("Negative test didn't report an error.\n"); | 210 result.addLog("Negative test didn't report an error.\n"); |
206 } else if (result.outcome == Expectation.FAIL) { | 211 } else if (result.outcome == Expectation.Fail) { |
207 result.addLog("Negative test reported an error as expeceted.\n"); | 212 result.addLog("Negative test reported an error as expeceted.\n"); |
208 } | 213 } |
209 result = toNegativeTestResult(result); | 214 result = toNegativeTestResult(result); |
210 } | 215 } |
211 if (!expectedOutcomes.contains(result.outcome)) { | 216 if (!expectedOutcomes.contains(result.outcome)) { |
212 result.addLog("$sb"); | 217 result.addLog("$sb"); |
213 unexpectedResults[description] = result; | 218 unexpectedResults[description] = result; |
214 unexpectedOutcomes[description] = expectedOutcomes; | 219 unexpectedOutcomes[description] = expectedOutcomes; |
215 logUnexpectedResult(suite, description, result, expectedOutcomes); | 220 logUnexpectedResult(suite, description, result, expectedOutcomes); |
216 } else { | 221 } else { |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
254 String path = entity.uri.path; | 259 String path = entity.uri.path; |
255 if (suite.exclude.any((RegExp r) => path.contains(r))) continue; | 260 if (suite.exclude.any((RegExp r) => path.contains(r))) continue; |
256 if (suite.pattern.any((RegExp r) => path.contains(r))) { | 261 if (suite.pattern.any((RegExp r) => path.contains(r))) { |
257 yield new TestDescription(suite.uri, entity); | 262 yield new TestDescription(suite.uri, entity); |
258 } | 263 } |
259 } | 264 } |
260 } else { | 265 } else { |
261 throw "${suite.uri} isn't a directory"; | 266 throw "${suite.uri} isn't a directory"; |
262 } | 267 } |
263 } | 268 } |
| 269 |
| 270 Result toNegativeTestResult(Result result, [Set<String> expectations]) { |
| 271 Expectation outcome = result.outcome; |
| 272 if (outcome == Expectation.Pass) { |
| 273 if (expectations == null) { |
| 274 outcome = Expectation.Fail; |
| 275 } else if (expectations.contains("compile-time error")) { |
| 276 outcome = expectationSet["MissingCompileTimeError"]; |
| 277 } else if (expectations.contains("runtime error") || |
| 278 expectations.contains("dynamic type error")) { |
| 279 outcome = expectationSet["MissingRuntimeError"]; |
| 280 } else { |
| 281 outcome = Expectation.Fail; |
| 282 } |
| 283 } else if (outcome == Expectation.Fail) { |
| 284 outcome = Expectation.Pass; |
| 285 } |
| 286 return result.copyWithOutcome(outcome); |
| 287 } |
264 } | 288 } |
265 | 289 |
266 abstract class Step<I, O, C extends ChainContext> { | 290 abstract class Step<I, O, C extends ChainContext> { |
267 const Step(); | 291 const Step(); |
268 | 292 |
269 String get name; | 293 String get name; |
270 | 294 |
271 bool get isAsync => false; | 295 bool get isAsync => false; |
272 | 296 |
273 bool get isCompiler => false; | 297 bool get isCompiler => false; |
(...skipping 22 matching lines...) Expand all Loading... |
296 | 320 |
297 final error; | 321 final error; |
298 | 322 |
299 final StackTrace trace; | 323 final StackTrace trace; |
300 | 324 |
301 final List<String> logs = <String>[]; | 325 final List<String> logs = <String>[]; |
302 | 326 |
303 Result(this.output, this.outcome, this.error, this.trace); | 327 Result(this.output, this.outcome, this.error, this.trace); |
304 | 328 |
305 Result.pass(O output) | 329 Result.pass(O output) |
306 : this(output, Expectation.PASS, null, null); | 330 : this(output, Expectation.Pass, null, null); |
307 | 331 |
308 Result.crash(error, StackTrace trace) | 332 Result.crash(error, StackTrace trace) |
309 : this(null, Expectation.CRASH, error, trace); | 333 : this(null, Expectation.Crash, error, trace); |
310 | 334 |
311 Result.fail(O output, [error, StackTrace trace]) | 335 Result.fail(O output, [error, StackTrace trace]) |
312 : this(output, Expectation.FAIL, error, trace); | 336 : this(output, Expectation.Fail, error, trace); |
313 | 337 |
314 String get log => logs.join(); | 338 String get log => logs.join(); |
315 | 339 |
316 void addLog(String log) { | 340 void addLog(String log) { |
317 logs.add(log); | 341 logs.add(log); |
318 } | 342 } |
319 | 343 |
320 Result<O> copyWithOutcome(Expectation outcome) { | 344 Result<O> copyWithOutcome(Expectation outcome) { |
321 return new Result<O>(output, outcome, error, trace) | 345 return new Result<O>(output, outcome, error, trace) |
322 ..logs.addAll(logs); | 346 ..logs.addAll(logs); |
323 } | 347 } |
324 } | 348 } |
325 | 349 |
326 /// This is called from generated code. | 350 /// This is called from generated code. |
327 Future<Null> runChain( | 351 Future<Null> runChain( |
328 CreateContext f, Map<String, String> environment, Set<String> selectors, | 352 CreateContext f, Map<String, String> environment, Set<String> selectors, |
329 String json) { | 353 String json) { |
330 return withErrorHandling(() async { | 354 return withErrorHandling(() async { |
331 Chain suite = new Suite.fromJsonMap(Uri.base, JSON.decode(json)); | 355 Chain suite = new Suite.fromJsonMap(Uri.base, JSON.decode(json)); |
332 print("Running ${suite.name}"); | 356 print("Running ${suite.name}"); |
333 ChainContext context = await f(suite, environment); | 357 ChainContext context = await f(suite, environment); |
334 return context.run(suite, selectors); | 358 return context.run(suite, selectors); |
335 }); | 359 }); |
336 } | 360 } |
337 | |
338 Result toNegativeTestResult(Result result, [Set<String> expectations]) { | |
339 Expectation outcome = result.outcome; | |
340 if (outcome == Expectation.PASS) { | |
341 if (expectations == null) { | |
342 outcome = Expectation.FAIL; | |
343 } else if (expectations.contains("compile-time error")) { | |
344 outcome = Expectation.MISSING_COMPILETIME_ERROR; | |
345 } else if (expectations.contains("runtime error") || | |
346 expectations.contains("dynamic type error")) { | |
347 outcome = Expectation.MISSING_RUNTIME_ERROR; | |
348 } else { | |
349 outcome = Expectation.FAIL; | |
350 } | |
351 } else if (outcome == Expectation.FAIL) { | |
352 outcome = Expectation.PASS; | |
353 } | |
354 return result.copyWithOutcome(outcome); | |
355 } | |
OLD | NEW |