Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 // TODO(nweiz): Add support for calling [schedule] while the schedule is already | 5 // TODO(nweiz): Add support for calling [schedule] while the schedule is already |
| 6 // running. | 6 // running. |
| 7 // TODO(nweiz): Port the non-Pub-specific scheduled test libraries from Pub. | 7 // TODO(nweiz): Port the non-Pub-specific scheduled test libraries from Pub. |
| 8 /// A package for writing readable tests of asynchronous behavior. | 8 /// A package for writing readable tests of asynchronous behavior. |
| 9 /// | 9 /// |
| 10 /// This package works by building up a queue of asynchronous tasks called a | 10 /// This package works by building up a queue of asynchronous tasks called a |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 102 /// }); | 102 /// }); |
| 103 /// }); | 103 /// }); |
| 104 /// } | 104 /// } |
| 105 /// | 105 /// |
| 106 /// ## Out-of-Band Callbacks | 106 /// ## Out-of-Band Callbacks |
| 107 /// | 107 /// |
| 108 /// Sometimes your tests will have callbacks that don't fit into the schedule. | 108 /// Sometimes your tests will have callbacks that don't fit into the schedule. |
| 109 /// It's important that errors in these callbacks are still registered, though, | 109 /// It's important that errors in these callbacks are still registered, though, |
| 110 /// and that [Schedule.onException] and [Schedule.onComplete] still run after | 110 /// and that [Schedule.onException] and [Schedule.onComplete] still run after |
| 111 /// they finish. When using `unittest`, you wrap these callbacks with | 111 /// they finish. When using `unittest`, you wrap these callbacks with |
| 112 /// `expectAsyncN`; when using `scheduled_test`, you use [wrapAsync]. | 112 /// `expectAsyncN`; when using `scheduled_test`, you use [wrapAsync] or |
| 113 /// [wrapFuture]. | |
| 113 /// | 114 /// |
| 114 /// [wrapAsync] has two important functions. First, any errors that occur in it | 115 /// [wrapAsync] has two important functions. First, any errors that occur in it |
| 115 /// will be passed into the [Schedule] instead of causing the whole test to | 116 /// will be passed into the [Schedule] instead of causing the whole test to |
| 116 /// crash. They can then be handled by [Schedule.onException] and | 117 /// crash. They can then be handled by [Schedule.onException] and |
| 117 /// [Schedule.onComplete]. Second, a task queue isn't considered finished until | 118 /// [Schedule.onComplete]. Second, a task queue isn't considered finished until |
| 118 /// all of its [wrapAsync]-wrapped functions have been called. This ensures that | 119 /// all of its [wrapAsync]-wrapped functions have been called. This ensures that |
| 119 /// [Schedule.onException] and [Schedule.onComplete] will always run after all | 120 /// [Schedule.onException] and [Schedule.onComplete] will always run after all |
| 120 /// the test code in the main queue. | 121 /// the test code in the main queue. |
| 121 /// | 122 /// |
| 122 /// Note that the [completes], [completion], and [throws] matchers use | 123 /// Note that the [completes], [completion], and [throws] matchers use |
| 123 /// [wrapAsync] internally, so they're safe to use in conjunction with scheduled | 124 /// [wrapAsync] internally, so they're safe to use in conjunction with scheduled |
| 124 /// tests. | 125 /// tests. |
| 125 /// | 126 /// |
| 126 /// Here's an example of a test using [wrapAsync] to catch errors thrown in the | 127 /// Here's an example of a test using [wrapAsync] to catch errors thrown in the |
| 127 /// callback of a fictional `startServer` function: | 128 /// callback of a fictional `startServer` function: |
| 128 /// | 129 /// |
| 129 /// import 'package:scheduled_test/scheduled_test.dart'; | 130 /// import 'package:scheduled_test/scheduled_test.dart'; |
| 130 /// | 131 /// |
| 131 /// void main() { | 132 /// void main() { |
| 132 /// test('sendRequest sends a request', () { | 133 /// test('sendRequest sends a request', () { |
| 133 /// startServer(wrapAsync((request) { | 134 /// startServer(wrapAsync((request) { |
| 134 /// expect(request.body, equals('payload')); | 135 /// expect(request.body, equals('payload')); |
| 135 /// request.response.close(); | 136 /// request.response.close(); |
| 136 /// })); | 137 /// })); |
| 137 /// | 138 /// |
| 138 /// schedule(() => sendRequest('payload')); | 139 /// schedule(() => sendRequest('payload')); |
| 139 /// }); | 140 /// }); |
| 140 /// } | 141 /// } |
| 141 /// | 142 /// |
| 143 /// [wrapFuture] works similarly to [wrapAsync], but instead of wrapping a | |
| 144 /// single callback it wraps a whole [Future] chain. Like [wrapAsync], it | |
| 145 /// ensures that the task quque doesn't complete until the out-of-band chain has | |
|
Bob Nystrom
2013/02/19 23:15:04
"quque" -> "queue"
nweiz
2013/02/20 00:23:12
Done.
| |
| 146 /// finished, and that any errors in the chain are piped back into the scheduled | |
| 147 /// test. For example: | |
| 148 /// | |
| 149 /// import 'package:scheduled_test/scheduled_test.dart'; | |
| 150 /// | |
| 151 /// void main() { | |
| 152 /// test('sendRequest sends a request', () { | |
| 153 /// wrapFuture(server.nextRequest.then((request) { | |
| 154 /// expect(request.body, equals('payload')); | |
| 155 /// expect(request.headers['content-type'], equals('text/plain')); | |
| 156 /// })); | |
| 157 /// | |
| 158 /// schedule(() => sendRequest('payload')); | |
| 159 /// }); | |
| 160 /// } | |
| 161 /// | |
| 142 /// ## Timeouts | 162 /// ## Timeouts |
| 143 /// | 163 /// |
| 144 /// `scheduled_test` has a built-in timeout of 30 seconds (configurable via | 164 /// `scheduled_test` has a built-in timeout of 30 seconds (configurable via |
| 145 /// [Schedule.timeout]). This timeout is aware of the structure of the schedule; | 165 /// [Schedule.timeout]). This timeout is aware of the structure of the schedule; |
| 146 /// this means that it will reset for each task in a queue, when moving between | 166 /// this means that it will reset for each task in a queue, when moving between |
| 147 /// queues, or almost any other sort of interaction with [currentSchedule]. As | 167 /// queues, or almost any other sort of interaction with [currentSchedule]. As |
| 148 /// long as the [Schedule] knows your test is making some sort of progress, it | 168 /// long as the [Schedule] knows your test is making some sort of progress, it |
| 149 /// won't time out. | 169 /// won't time out. |
| 150 /// | 170 /// |
| 151 /// If a single task might take a long time, you can also manually tell the | 171 /// If a single task might take a long time, you can also manually tell the |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 237 /// [fn] returns a [Future], tasks after it won't be run until that [Future] | 257 /// [fn] returns a [Future], tasks after it won't be run until that [Future] |
| 238 /// completes. | 258 /// completes. |
| 239 /// | 259 /// |
| 240 /// The return value will be completed once the scheduled task has finished | 260 /// The return value will be completed once the scheduled task has finished |
| 241 /// running. Its return value is the same as the return value of [fn], or the | 261 /// running. Its return value is the same as the return value of [fn], or the |
| 242 /// value it completes to if it's a [Future]. | 262 /// value it completes to if it's a [Future]. |
| 243 /// | 263 /// |
| 244 /// If [description] is passed, it's used to describe the task for debugging | 264 /// If [description] is passed, it's used to describe the task for debugging |
| 245 /// purposes when an error occurs. | 265 /// purposes when an error occurs. |
| 246 /// | 266 /// |
| 247 /// This function is identical to [currentSchedule.tasks.schedule]. | 267 /// If this is called when a task queue is currently running, it will run [fn] |
| 268 /// on the next event loop iteration rather than adding it to a queue. The | |
| 269 /// current task will not complete until [fn] (and any [Future] it returns) has | |
| 270 /// finished running. Any errors in [fn] will automatically be handled. | |
| 248 Future schedule(fn(), [String description]) => | 271 Future schedule(fn(), [String description]) => |
| 249 currentSchedule.tasks.schedule(fn, description); | 272 currentSchedule.tasks.schedule(fn, description); |
| 250 | 273 |
| 251 /// Register a [setUp] function for a test [group]. This has the same semantics | 274 /// Register a [setUp] function for a test [group]. This has the same semantics |
| 252 /// as [unittest.setUp]. Tasks may be scheduled using [schedule] within | 275 /// as [unittest.setUp]. Tasks may be scheduled using [schedule] within |
| 253 /// [setUpFn], and [currentSchedule] may be accessed as well. | 276 /// [setUpFn], and [currentSchedule] may be accessed as well. |
| 254 /// | 277 /// |
| 255 /// Note that there is no associated [tearDown] function. Instead, tasks should | 278 /// Note that there is no associated [tearDown] function. Instead, tasks should |
| 256 /// be scheduled for [currentSchedule.onComplete] or | 279 /// be scheduled for [currentSchedule.onComplete] or |
| 257 /// [currentSchedule.onException]. These tasks will be run after each test's | 280 /// [currentSchedule.onException]. These tasks will be run after each test's |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 295 unittest.ensureInitialized(); | 318 unittest.ensureInitialized(); |
| 296 unittest.wrapAsync = (f) { | 319 unittest.wrapAsync = (f) { |
| 297 if (currentSchedule == null) { | 320 if (currentSchedule == null) { |
| 298 throw new StateError("Unexpected call to wrapAsync with no current " | 321 throw new StateError("Unexpected call to wrapAsync with no current " |
| 299 "schedule."); | 322 "schedule."); |
| 300 } | 323 } |
| 301 | 324 |
| 302 return currentSchedule.wrapAsync(f); | 325 return currentSchedule.wrapAsync(f); |
| 303 }; | 326 }; |
| 304 } | 327 } |
| 328 | |
| 329 /// Like [wrapAsync], this ensures that the current task queue waits for | |
| 330 /// out-of-band asynchronous code, and that errors raised in that code are | |
| 331 /// handled correctly. However, [wrapFuture] wraps a [Future] chain rather than | |
| 332 /// a single callback. | |
| 333 /// | |
| 334 /// The returned [Future] completes to the same value or error as [future]. | |
| 335 Future wrapFuture(Future future) { | |
| 336 if (currentSchedule == null) { | |
| 337 throw new StateError("Unexpected call to wrapFuture with no current " | |
| 338 "schedule."); | |
| 339 } | |
| 340 | |
| 341 return currentSchedule.wrapFuture(future); | |
| 342 } | |
| OLD | NEW |