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 |
(...skipping 27 matching lines...) Expand all Loading... |
38 import 'log.dart' show | 38 import 'log.dart' show |
39 logMessage, | 39 logMessage, |
40 logStepComplete, | 40 logStepComplete, |
41 logStepStart, | 41 logStepStart, |
42 logSuiteComplete, | 42 logSuiteComplete, |
43 logTestComplete, | 43 logTestComplete, |
44 logUnexpectedResult, | 44 logUnexpectedResult, |
45 splitLines; | 45 splitLines; |
46 | 46 |
47 import 'multitest.dart' show | 47 import 'multitest.dart' show |
48 MultitestTransformer; | 48 MultitestTransformer, |
| 49 isError; |
49 | 50 |
50 typedef Future<ChainContext> CreateContext( | 51 typedef Future<ChainContext> CreateContext( |
51 Chain suite, Map<String, String> environment); | 52 Chain suite, Map<String, String> environment); |
52 | 53 |
53 /// A test suite for tool chains, for example, a compiler. | 54 /// A test suite for tool chains, for example, a compiler. |
54 class Chain extends Suite { | 55 class Chain extends Suite { |
55 final Uri source; | 56 final Uri source; |
56 | 57 |
57 final Uri uri; | 58 final Uri uri; |
58 | 59 |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
133 <TestDescription, Set<Expectation>>{}; | 134 <TestDescription, Set<Expectation>>{}; |
134 int completed = 0; | 135 int completed = 0; |
135 List<Future> futures = <Future>[]; | 136 List<Future> futures = <Future>[]; |
136 for (TestDescription description in descriptions) { | 137 for (TestDescription description in descriptions) { |
137 String selector = "${suite.name}/${description.shortName}"; | 138 String selector = "${suite.name}/${description.shortName}"; |
138 if (selectors.isNotEmpty && | 139 if (selectors.isNotEmpty && |
139 !selectors.contains(selector) && | 140 !selectors.contains(selector) && |
140 !selectors.contains(suite.name)) { | 141 !selectors.contains(suite.name)) { |
141 continue; | 142 continue; |
142 } | 143 } |
143 Set<Expectation> expectedOutcomes = | 144 final Set<Expectation> expectedOutcomes = |
144 expectations.expectations(description.shortName); | 145 expectations.expectations(description.shortName); |
| 146 final StringBuffer sb = new StringBuffer(); |
| 147 final Step lastStep = steps.isNotEmpty ? steps.last : null; |
| 148 final Iterator<Step> iterator = steps.iterator; |
| 149 |
145 Result result; | 150 Result result; |
146 StringBuffer sb = new StringBuffer(); | |
147 // Records the outcome of the last step that was run. | 151 // Records the outcome of the last step that was run. |
148 Step lastStep = null; | 152 Step lastStepRun; |
149 Iterator<Step> iterator = steps.iterator; | |
150 | 153 |
151 /// Performs one step of [iterator]. | 154 /// Performs one step of [iterator]. |
152 /// | 155 /// |
153 /// If `step.isAsync` is true, the corresponding step is said to be | 156 /// If `step.isAsync` is true, the corresponding step is said to be |
154 /// asynchronous. | 157 /// asynchronous. |
155 /// | 158 /// |
156 /// If a step is asynchrouns the future returned from this function will | 159 /// If a step is asynchrouns the future returned from this function will |
157 /// complete after the the first asynchronous step is scheduled. This | 160 /// complete after the the first asynchronous step is scheduled. This |
158 /// allows us to start processing the next test while an external process | 161 /// allows us to start processing the next test while an external process |
159 /// completes as steps can be interleaved. To ensure all steps are | 162 /// completes as steps can be interleaved. To ensure all steps are |
160 /// completed, wait for [futures]. | 163 /// completed, wait for [futures]. |
161 /// | 164 /// |
162 /// Otherwise, the future returned will complete when all steps are | 165 /// Otherwise, the future returned will complete when all steps are |
163 /// completed. This ensures that tests are run in sequence without | 166 /// completed. This ensures that tests are run in sequence without |
164 /// interleaving steps. | 167 /// interleaving steps. |
165 Future doStep(dynamic input) async { | 168 Future doStep(dynamic input) async { |
166 Future future; | 169 Future future; |
167 bool isAsync = false; | 170 bool isAsync = false; |
168 if (iterator.moveNext()) { | 171 if (iterator.moveNext()) { |
169 Step step = iterator.current; | 172 Step step = iterator.current; |
170 lastStep = step; | 173 lastStepRun = step; |
171 isAsync = step.isAsync; | 174 isAsync = step.isAsync; |
172 logStepStart(completed, unexpectedResults.length, descriptions.length, | 175 logStepStart(completed, unexpectedResults.length, descriptions.length, |
173 suite, description, step); | 176 suite, description, step); |
174 future = runGuarded(() async { | 177 future = runGuarded(() async { |
175 try { | 178 try { |
176 return await step.run(input, this); | 179 return await step.run(input, this); |
177 } catch (error, trace) { | 180 } catch (error, trace) { |
178 return step.unhandledError(error, trace); | 181 return step.unhandledError(error, trace); |
179 } | 182 } |
180 }, printLineOnStdout: sb.writeln); | 183 }, printLineOnStdout: sb.writeln); |
181 } else { | 184 } else { |
182 future = new Future.value(null); | 185 future = new Future.value(null); |
183 } | 186 } |
184 future = future.then((Result currentResult) { | 187 future = future.then((Result currentResult) { |
185 if (currentResult != null) { | 188 if (currentResult != null) { |
186 logStepComplete(completed, unexpectedResults.length, | 189 logStepComplete(completed, unexpectedResults.length, |
187 descriptions.length, suite, description, lastStep); | 190 descriptions.length, suite, description, lastStepRun); |
188 result = currentResult; | 191 result = currentResult; |
189 if (currentResult.outcome == Expectation.PASS) { | 192 if (currentResult.outcome == Expectation.PASS) { |
190 // The input to the next step is the output of this step. | 193 // The input to the next step is the output of this step. |
191 return doStep(result.output); | 194 return doStep(result.output); |
192 } | 195 } |
193 } | 196 } |
194 if (steps.isNotEmpty && steps.last == lastStep && | 197 if (description.multitestExpectations != null) { |
| 198 if (isError(description.multitestExpectations)) { |
| 199 result = result.toNegativeTestResult(); |
| 200 } |
| 201 } else if (lastStep == lastStepRun && |
195 description.shortName.endsWith("negative_test")) { | 202 description.shortName.endsWith("negative_test")) { |
196 if (result.outcome == Expectation.PASS) { | 203 if (result.outcome == Expectation.PASS) { |
197 result.addLog("Negative test didn't report an error.\n"); | 204 result.addLog("Negative test didn't report an error.\n"); |
198 } else if (result.outcome == Expectation.FAIL) { | 205 } else if (result.outcome == Expectation.FAIL) { |
199 result.addLog("Negative test reported an error as expeceted.\n"); | 206 result.addLog("Negative test reported an error as expeceted.\n"); |
200 } | 207 } |
201 result = result.toNegativeTestResult(); | 208 result = result.toNegativeTestResult(); |
202 } | 209 } |
203 if (!expectedOutcomes.contains(result.outcome)) { | 210 if (!expectedOutcomes.contains(result.outcome)) { |
204 result.addLog("$sb"); | 211 result.addLog("$sb"); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
255 } | 262 } |
256 } | 263 } |
257 | 264 |
258 abstract class Step<I, O, C extends ChainContext> { | 265 abstract class Step<I, O, C extends ChainContext> { |
259 const Step(); | 266 const Step(); |
260 | 267 |
261 String get name; | 268 String get name; |
262 | 269 |
263 bool get isAsync => false; | 270 bool get isAsync => false; |
264 | 271 |
| 272 bool get isCompiler => false; |
| 273 |
| 274 bool get isRuntime => false; |
| 275 |
265 Future<Result<O>> run(I input, C context); | 276 Future<Result<O>> run(I input, C context); |
266 | 277 |
267 Result<O> unhandledError(error, StackTrace trace) { | 278 Result<O> unhandledError(error, StackTrace trace) { |
268 return new Result<O>.crash(error, trace); | 279 return new Result<O>.crash(error, trace); |
269 } | 280 } |
270 | 281 |
271 Result<O> pass(O output) => new Result<O>.pass(output); | 282 Result<O> pass(O output) => new Result<O>.pass(output); |
272 | 283 |
273 Result<O> crash(error, StackTrace trace) => new Result<O>.crash(error, trace); | 284 Result<O> crash(error, StackTrace trace) => new Result<O>.crash(error, trace); |
274 | 285 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
321 Future<Null> runChain( | 332 Future<Null> runChain( |
322 CreateContext f, Map<String, String> environment, Set<String> selectors, | 333 CreateContext f, Map<String, String> environment, Set<String> selectors, |
323 String json) { | 334 String json) { |
324 return withErrorHandling(() async { | 335 return withErrorHandling(() async { |
325 Chain suite = new Suite.fromJsonMap(Uri.base, JSON.decode(json)); | 336 Chain suite = new Suite.fromJsonMap(Uri.base, JSON.decode(json)); |
326 print("Running ${suite.name}"); | 337 print("Running ${suite.name}"); |
327 ChainContext context = await f(suite, environment); | 338 ChainContext context = await f(suite, environment); |
328 return context.run(suite, selectors); | 339 return context.run(suite, selectors); |
329 }); | 340 }); |
330 } | 341 } |
OLD | NEW |