| OLD | NEW |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library error_group_test; | 1 library error_group_test; |
| 6 | |
| 7 import 'dart:async'; | 2 import 'dart:async'; |
| 8 | |
| 9 import 'package:unittest/unittest.dart'; | 3 import 'package:unittest/unittest.dart'; |
| 10 | |
| 11 import '../lib/src/error_group.dart'; | 4 import '../lib/src/error_group.dart'; |
| 12 import '../lib/src/utils.dart'; | 5 import '../lib/src/utils.dart'; |
| 13 | |
| 14 ErrorGroup errorGroup; | 6 ErrorGroup errorGroup; |
| 15 | |
| 16 // TODO(nweiz): once there's a global error handler, we should test that it does | |
| 17 // and does not get called at appropriate times. See issue 5958. | |
| 18 // | |
| 19 // One particular thing we should test that has no tests now is that a stream | |
| 20 // that has a subscription added and subsequently canceled counts as having no | |
| 21 // listeners. | |
| 22 | |
| 23 main() { | 7 main() { |
| 24 group('with no futures or streams', () { | 8 group('with no futures or streams', () { |
| 25 setUp(() { | 9 setUp(() { |
| 26 errorGroup = new ErrorGroup(); | 10 errorGroup = new ErrorGroup(); |
| 27 }); | 11 }); |
| 28 | |
| 29 test('should pass signaled errors to .done', () { | 12 test('should pass signaled errors to .done', () { |
| 30 expect(errorGroup.done, throwsFormatException); | 13 expect(errorGroup.done, throwsFormatException); |
| 31 errorGroup.signalError(new FormatException()); | 14 errorGroup.signalError(new FormatException()); |
| 32 }); | 15 }); |
| 33 | 16 test( |
| 34 test("shouldn't allow additional futures or streams once an error has been " | 17 "shouldn't allow additional futures or streams once an error has been " |
| 35 "signaled", () { | 18 "signaled", |
| 19 () { |
| 36 expect(errorGroup.done, throwsFormatException); | 20 expect(errorGroup.done, throwsFormatException); |
| 37 errorGroup.signalError(new FormatException()); | 21 errorGroup.signalError(new FormatException()); |
| 38 | 22 expect( |
| 39 expect(() => errorGroup.registerFuture(new Future.value()), | 23 () => errorGroup.registerFuture(new Future.value()), |
| 40 throwsStateError); | 24 throwsStateError); |
| 41 expect(() => errorGroup.registerStream( | 25 expect( |
| 42 new StreamController(sync: true).stream), | 26 () => errorGroup.registerStream(new StreamController(sync: true).strea
m), |
| 43 throwsStateError); | 27 throwsStateError); |
| 44 }); | 28 }); |
| 45 }); | 29 }); |
| 46 | |
| 47 group('with a single future', () { | 30 group('with a single future', () { |
| 48 Completer completer; | 31 Completer completer; |
| 49 Future future; | 32 Future future; |
| 50 | |
| 51 setUp(() { | 33 setUp(() { |
| 52 errorGroup = new ErrorGroup(); | 34 errorGroup = new ErrorGroup(); |
| 53 completer = new Completer(); | 35 completer = new Completer(); |
| 54 future = errorGroup.registerFuture(completer.future); | 36 future = errorGroup.registerFuture(completer.future); |
| 55 }); | 37 }); |
| 56 | |
| 57 test('should pass through a value from the future', () { | 38 test('should pass through a value from the future', () { |
| 58 expect(future, completion(equals('value'))); | 39 expect(future, completion(equals('value'))); |
| 59 expect(errorGroup.done, completes); | 40 expect(errorGroup.done, completes); |
| 60 completer.complete('value'); | 41 completer.complete('value'); |
| 61 }); | 42 }); |
| 62 | 43 test( |
| 63 test("shouldn't allow additional futures or streams once .done has " | 44 "shouldn't allow additional futures or streams once .done has " "been ca
lled", |
| 64 "been called", () { | 45 () { |
| 65 completer.complete('value'); | 46 completer.complete('value'); |
| 66 | 47 expect( |
| 67 expect(completer.future | 48 completer.future.then((_) => errorGroup.registerFuture(new Future.valu
e())), |
| 68 .then((_) => errorGroup.registerFuture(new Future.value())), | 49 throwsStateError); |
| 69 throwsStateError); | 50 expect( |
| 70 expect(completer.future | 51 completer.future.then( |
| 71 .then((_) => errorGroup.registerStream( | 52 (_) => errorGroup.registerStream(new StreamController(sync: true).
stream)), |
| 72 new StreamController(sync: true).stream)), | 53 throwsStateError); |
| 73 throwsStateError); | |
| 74 }); | 54 }); |
| 75 | 55 test( |
| 76 test('should pass through an exception from the future if it has a ' | 56 'should pass through an exception from the future if it has a ' 'listene
r', |
| 77 'listener', () { | 57 () { |
| 78 expect(future, throwsFormatException); | 58 expect(future, throwsFormatException); |
| 79 // errorGroup shouldn't top-level the exception | |
| 80 completer.completeError(new FormatException()); | 59 completer.completeError(new FormatException()); |
| 81 }); | 60 }); |
| 82 | 61 test( |
| 83 test('should notify the error group of an exception from the future even ' | 62 'should notify the error group of an exception from the future even ' |
| 84 'if it has a listener', () { | 63 'if it has a listener', |
| 64 () { |
| 85 expect(future, throwsFormatException); | 65 expect(future, throwsFormatException); |
| 86 expect(errorGroup.done, throwsFormatException); | 66 expect(errorGroup.done, throwsFormatException); |
| 87 completer.completeError(new FormatException()); | 67 completer.completeError(new FormatException()); |
| 88 }); | 68 }); |
| 89 | 69 test( |
| 90 test('should pass a signaled exception to the future if it has a listener ' | 70 'should pass a signaled exception to the future if it has a listener ' |
| 91 'and should ignore a subsequent value from that future', () { | 71 'and should ignore a subsequent value from that future', |
| 72 () { |
| 92 expect(future, throwsFormatException); | 73 expect(future, throwsFormatException); |
| 93 // errorGroup shouldn't top-level the exception | |
| 94 errorGroup.signalError(new FormatException()); | 74 errorGroup.signalError(new FormatException()); |
| 95 completer.complete('value'); | 75 completer.complete('value'); |
| 96 }); | 76 }); |
| 97 | 77 test( |
| 98 test('should pass a signaled exception to the future if it has a listener ' | 78 'should pass a signaled exception to the future if it has a listener ' |
| 99 'and should ignore a subsequent exception from that future', () { | 79 'and should ignore a subsequent exception from that future', |
| 80 () { |
| 100 expect(future, throwsFormatException); | 81 expect(future, throwsFormatException); |
| 101 // errorGroup shouldn't top-level the exception | |
| 102 errorGroup.signalError(new FormatException()); | 82 errorGroup.signalError(new FormatException()); |
| 103 completer.completeError(new ArgumentError()); | 83 completer.completeError(new ArgumentError()); |
| 104 }); | 84 }); |
| 105 | 85 test( |
| 106 test('should notify the error group of a signaled exception even if the ' | 86 'should notify the error group of a signaled exception even if the ' |
| 107 'future has a listener', () { | 87 'future has a listener', |
| 88 () { |
| 108 expect(future, throwsFormatException); | 89 expect(future, throwsFormatException); |
| 109 expect(errorGroup.done, throwsFormatException); | 90 expect(errorGroup.done, throwsFormatException); |
| 110 errorGroup.signalError(new FormatException()); | 91 errorGroup.signalError(new FormatException()); |
| 111 }); | 92 }); |
| 112 | 93 test( |
| 113 test("should complete .done if the future receives a value even if the " | 94 "should complete .done if the future receives a value even if the " |
| 114 "future doesn't have a listener", () { | 95 "future doesn't have a listener", |
| 96 () { |
| 115 expect(errorGroup.done, completes); | 97 expect(errorGroup.done, completes); |
| 116 completer.complete('value'); | 98 completer.complete('value'); |
| 117 | 99 expect(errorGroup.done.then((_) => future), completion(equals('value'))); |
| 118 // A listener added afterwards should receive the value | |
| 119 expect(errorGroup.done.then((_) => future), | |
| 120 completion(equals('value'))); | |
| 121 }); | 100 }); |
| 122 | 101 test( |
| 123 test("should pipe an exception from the future to .done if the future " | 102 "should pipe an exception from the future to .done if the future " |
| 124 "doesn't have a listener", () { | 103 "doesn't have a listener", |
| 104 () { |
| 125 expect(errorGroup.done, throwsFormatException); | 105 expect(errorGroup.done, throwsFormatException); |
| 126 completer.completeError(new FormatException()); | 106 completer.completeError(new FormatException()); |
| 127 | |
| 128 // A listener added afterwards should receive the exception | |
| 129 expect(errorGroup.done.catchError((_) { | 107 expect(errorGroup.done.catchError((_) { |
| 130 expect(future, throwsFormatException); | 108 expect(future, throwsFormatException); |
| 131 }), completes); | 109 }), completes); |
| 132 }); | 110 }); |
| 133 | 111 test( |
| 134 test("should pass a signaled exception to .done if the future doesn't have " | 112 "should pass a signaled exception to .done if the future doesn't have " |
| 135 "a listener", | 113 "a listener", |
| 136 () { | 114 () { |
| 137 expect(errorGroup.done, throwsFormatException); | 115 expect(errorGroup.done, throwsFormatException); |
| 138 errorGroup.signalError(new FormatException()); | 116 errorGroup.signalError(new FormatException()); |
| 139 | |
| 140 // A listener added afterwards should receive the exception | |
| 141 expect(errorGroup.done.catchError((_) { | 117 expect(errorGroup.done.catchError((_) { |
| 142 completer.complete('value'); // should be ignored | 118 completer.complete('value'); |
| 143 expect(future, throwsFormatException); | 119 expect(future, throwsFormatException); |
| 144 }), completes); | 120 }), completes); |
| 145 }); | 121 }); |
| 146 }); | 122 }); |
| 147 | |
| 148 group('with multiple futures', () { | 123 group('with multiple futures', () { |
| 149 Completer completer1; | 124 Completer completer1; |
| 150 Completer completer2; | 125 Completer completer2; |
| 151 Future future1; | 126 Future future1; |
| 152 Future future2; | 127 Future future2; |
| 153 | |
| 154 setUp(() { | 128 setUp(() { |
| 155 errorGroup = new ErrorGroup(); | 129 errorGroup = new ErrorGroup(); |
| 156 completer1 = new Completer(); | 130 completer1 = new Completer(); |
| 157 completer2 = new Completer(); | 131 completer2 = new Completer(); |
| 158 future1 = errorGroup.registerFuture(completer1.future); | 132 future1 = errorGroup.registerFuture(completer1.future); |
| 159 future2 = errorGroup.registerFuture(completer2.future); | 133 future2 = errorGroup.registerFuture(completer2.future); |
| 160 }); | 134 }); |
| 161 | 135 test( |
| 162 test("should pipe exceptions from one future to the other and to " | 136 "should pipe exceptions from one future to the other and to " ".complete
", |
| 163 ".complete", () { | 137 () { |
| 164 expect(future1, throwsFormatException); | 138 expect(future1, throwsFormatException); |
| 165 expect(future2, throwsFormatException); | 139 expect(future2, throwsFormatException); |
| 166 expect(errorGroup.done, throwsFormatException); | 140 expect(errorGroup.done, throwsFormatException); |
| 167 | |
| 168 completer1.completeError(new FormatException()); | 141 completer1.completeError(new FormatException()); |
| 169 }); | 142 }); |
| 170 | 143 test( |
| 171 test("each future should be able to complete with a value " | 144 "each future should be able to complete with a value " "independently", |
| 172 "independently", () { | 145 () { |
| 173 expect(future1, completion(equals('value1'))); | 146 expect(future1, completion(equals('value1'))); |
| 174 expect(future2, completion(equals('value2'))); | 147 expect(future2, completion(equals('value2'))); |
| 175 expect(errorGroup.done, completes); | 148 expect(errorGroup.done, completes); |
| 176 | |
| 177 completer1.complete('value1'); | 149 completer1.complete('value1'); |
| 178 completer2.complete('value2'); | 150 completer2.complete('value2'); |
| 179 }); | 151 }); |
| 180 | 152 test( |
| 181 test("shouldn't throw a top-level exception if a future receives an error " | 153 "shouldn't throw a top-level exception if a future receives an error " |
| 182 "after the other listened future completes", () { | 154 "after the other listened future completes", |
| 155 () { |
| 183 expect(future1, completion(equals('value'))); | 156 expect(future1, completion(equals('value'))); |
| 184 completer1.complete('value'); | 157 completer1.complete('value'); |
| 185 | |
| 186 expect(future1.then((_) { | 158 expect(future1.then((_) { |
| 187 // shouldn't cause a top-level exception | |
| 188 completer2.completeError(new FormatException()); | 159 completer2.completeError(new FormatException()); |
| 189 }), completes); | 160 }), completes); |
| 190 }); | 161 }); |
| 191 | 162 test( |
| 192 test("shouldn't throw a top-level exception if an error is signaled after " | 163 "shouldn't throw a top-level exception if an error is signaled after " |
| 193 "one listened future completes", () { | 164 "one listened future completes", |
| 165 () { |
| 194 expect(future1, completion(equals('value'))); | 166 expect(future1, completion(equals('value'))); |
| 195 completer1.complete('value'); | 167 completer1.complete('value'); |
| 196 | |
| 197 expect(future1.then((_) { | 168 expect(future1.then((_) { |
| 198 // shouldn't cause a top-level exception | |
| 199 errorGroup.signalError(new FormatException()); | 169 errorGroup.signalError(new FormatException()); |
| 200 }), completes); | 170 }), completes); |
| 201 }); | 171 }); |
| 202 }); | 172 }); |
| 203 | |
| 204 group('with a single stream', () { | 173 group('with a single stream', () { |
| 205 StreamController controller; | 174 StreamController controller; |
| 206 Stream stream; | 175 Stream stream; |
| 207 | |
| 208 setUp(() { | 176 setUp(() { |
| 209 errorGroup = new ErrorGroup(); | 177 errorGroup = new ErrorGroup(); |
| 210 controller = new StreamController.broadcast(sync: true); | 178 controller = new StreamController.broadcast(sync: true); |
| 211 stream = errorGroup.registerStream(controller.stream); | 179 stream = errorGroup.registerStream(controller.stream); |
| 212 }); | 180 }); |
| 213 | |
| 214 test('should pass through values from the stream', () { | 181 test('should pass through values from the stream', () { |
| 215 StreamIterator iter = new StreamIterator(stream); | 182 StreamIterator iter = new StreamIterator(stream); |
| 216 iter.moveNext().then((hasNext) { | 183 iter.moveNext().then((hasNext) { |
| 217 expect(hasNext, isTrue); | 184 expect(hasNext, isTrue); |
| 218 expect(iter.current, equals(1)); | 185 expect(iter.current, equals(1)); |
| 219 iter.moveNext().then((hasNext) { | 186 iter.moveNext().then((hasNext) { |
| 220 expect(hasNext, isTrue); | 187 expect(hasNext, isTrue); |
| 221 expect(iter.current, equals(2)); | 188 expect(iter.current, equals(2)); |
| 222 expect(iter.moveNext(), completion(isFalse)); | 189 expect(iter.moveNext(), completion(isFalse)); |
| 223 }); | 190 }); |
| 224 }); | 191 }); |
| 225 expect(errorGroup.done, completes); | 192 expect(errorGroup.done, completes); |
| 226 | 193 controller |
| 227 controller..add(1)..add(2)..close(); | 194 ..add(1) |
| 195 ..add(2) |
| 196 ..close(); |
| 228 }); | 197 }); |
| 229 | 198 test( |
| 230 test('should pass through an error from the stream if it has a ' | 199 'should pass through an error from the stream if it has a ' 'listener', |
| 231 'listener', () { | 200 () { |
| 232 expect(stream.first, throwsFormatException); | 201 expect(stream.first, throwsFormatException); |
| 233 // errorGroup shouldn't top-level the exception | |
| 234 controller.addError(new FormatException()); | 202 controller.addError(new FormatException()); |
| 235 }); | 203 }); |
| 236 | 204 test( |
| 237 test('should notify the error group of an exception from the stream even ' | 205 'should notify the error group of an exception from the stream even ' |
| 238 'if it has a listener', () { | 206 'if it has a listener', |
| 207 () { |
| 239 expect(stream.first, throwsFormatException); | 208 expect(stream.first, throwsFormatException); |
| 240 expect(errorGroup.done, throwsFormatException); | 209 expect(errorGroup.done, throwsFormatException); |
| 241 controller.addError(new FormatException()); | 210 controller.addError(new FormatException()); |
| 242 }); | 211 }); |
| 243 | 212 test( |
| 244 test('should pass a signaled exception to the stream if it has a listener ' | 213 'should pass a signaled exception to the stream if it has a listener ' |
| 245 'and should unsubscribe that stream', () { | 214 'and should unsubscribe that stream', |
| 246 // errorGroup shouldn't top-level the exception | 215 () { |
| 247 expect(stream.first, throwsFormatException); | 216 expect(stream.first, throwsFormatException); |
| 248 errorGroup.signalError(new FormatException()); | 217 errorGroup.signalError(new FormatException()); |
| 249 | |
| 250 expect(newFuture(() { | 218 expect(newFuture(() { |
| 251 controller.add('value'); | 219 controller.add('value'); |
| 252 }), completes); | 220 }), completes); |
| 253 }); | 221 }); |
| 254 | 222 test( |
| 255 test('should notify the error group of a signaled exception even if the ' | 223 'should notify the error group of a signaled exception even if the ' |
| 256 'stream has a listener', () { | 224 'stream has a listener', |
| 225 () { |
| 257 expect(stream.first, throwsFormatException); | 226 expect(stream.first, throwsFormatException); |
| 258 expect(errorGroup.done, throwsFormatException); | 227 expect(errorGroup.done, throwsFormatException); |
| 259 errorGroup.signalError(new FormatException()); | 228 errorGroup.signalError(new FormatException()); |
| 260 }); | 229 }); |
| 261 | 230 test( |
| 262 test("should see one value and complete .done when the stream is done even " | 231 "should see one value and complete .done when the stream is done even " |
| 263 "if the stream doesn't have a listener", () { | 232 "if the stream doesn't have a listener", |
| 233 () { |
| 264 expect(errorGroup.done, completes); | 234 expect(errorGroup.done, completes); |
| 265 controller.add('value'); | 235 controller.add('value'); |
| 266 controller.close(); | 236 controller.close(); |
| 267 | 237 expect( |
| 268 // Now that broadcast controllers have been removed a listener should | 238 errorGroup.done.then((_) => stream.toList()), |
| 269 // see the value that has been put into the controller. | |
| 270 expect(errorGroup.done.then((_) => stream.toList()), | |
| 271 completion(equals(['value']))); | 239 completion(equals(['value']))); |
| 272 }); | 240 }); |
| 273 | |
| 274 }); | 241 }); |
| 275 | |
| 276 group('with a single single-subscription stream', () { | 242 group('with a single single-subscription stream', () { |
| 277 StreamController controller; | 243 StreamController controller; |
| 278 Stream stream; | 244 Stream stream; |
| 279 | |
| 280 setUp(() { | 245 setUp(() { |
| 281 errorGroup = new ErrorGroup(); | 246 errorGroup = new ErrorGroup(); |
| 282 controller = new StreamController(sync: true); | 247 controller = new StreamController(sync: true); |
| 283 stream = errorGroup.registerStream(controller.stream); | 248 stream = errorGroup.registerStream(controller.stream); |
| 284 }); | 249 }); |
| 285 | 250 test( |
| 286 test("should complete .done when the stream is done even if the stream " | 251 "should complete .done when the stream is done even if the stream " |
| 287 "doesn't have a listener", () { | 252 "doesn't have a listener", |
| 253 () { |
| 288 expect(errorGroup.done, completes); | 254 expect(errorGroup.done, completes); |
| 289 controller.add('value'); | 255 controller.add('value'); |
| 290 controller.close(); | 256 controller.close(); |
| 291 | 257 expect( |
| 292 // A listener added afterwards should receive the value | 258 errorGroup.done.then((_) => stream.toList()), |
| 293 expect(errorGroup.done.then((_) => stream.toList()), | |
| 294 completion(equals(['value']))); | 259 completion(equals(['value']))); |
| 295 }); | 260 }); |
| 296 | 261 test( |
| 297 test("should pipe an exception from the stream to .done if the stream " | 262 "should pipe an exception from the stream to .done if the stream " |
| 298 "doesn't have a listener", () { | 263 "doesn't have a listener", |
| 264 () { |
| 299 expect(errorGroup.done, throwsFormatException); | 265 expect(errorGroup.done, throwsFormatException); |
| 300 controller.addError(new FormatException()); | 266 controller.addError(new FormatException()); |
| 301 | |
| 302 // A listener added afterwards should receive the exception | |
| 303 expect(errorGroup.done.catchError((_) { | 267 expect(errorGroup.done.catchError((_) { |
| 304 controller.add('value'); // should be ignored | 268 controller.add('value'); |
| 305 expect(stream.first, throwsFormatException); | 269 expect(stream.first, throwsFormatException); |
| 306 }), completes); | 270 }), completes); |
| 307 }); | 271 }); |
| 308 | 272 test( |
| 309 test("should pass a signaled exception to .done if the stream doesn't " | 273 "should pass a signaled exception to .done if the stream doesn't " |
| 310 "have a listener", | 274 "have a listener", |
| 311 () { | 275 () { |
| 312 expect(errorGroup.done, throwsFormatException); | 276 expect(errorGroup.done, throwsFormatException); |
| 313 errorGroup.signalError(new FormatException()); | 277 errorGroup.signalError(new FormatException()); |
| 314 | |
| 315 // A listener added afterwards should receive the exception | |
| 316 expect(errorGroup.done.catchError((_) { | 278 expect(errorGroup.done.catchError((_) { |
| 317 controller.add('value'); // should be ignored | 279 controller.add('value'); |
| 318 expect(stream.first, throwsFormatException); | 280 expect(stream.first, throwsFormatException); |
| 319 }), completes); | 281 }), completes); |
| 320 }); | 282 }); |
| 321 }); | 283 }); |
| 322 | |
| 323 group('with multiple streams', () { | 284 group('with multiple streams', () { |
| 324 StreamController controller1; | 285 StreamController controller1; |
| 325 StreamController controller2; | 286 StreamController controller2; |
| 326 Stream stream1; | 287 Stream stream1; |
| 327 Stream stream2; | 288 Stream stream2; |
| 328 | |
| 329 setUp(() { | 289 setUp(() { |
| 330 errorGroup = new ErrorGroup(); | 290 errorGroup = new ErrorGroup(); |
| 331 controller1 = new StreamController.broadcast(sync: true); | 291 controller1 = new StreamController.broadcast(sync: true); |
| 332 controller2 = new StreamController.broadcast(sync: true); | 292 controller2 = new StreamController.broadcast(sync: true); |
| 333 stream1 = errorGroup.registerStream(controller1.stream); | 293 stream1 = errorGroup.registerStream(controller1.stream); |
| 334 stream2 = errorGroup.registerStream(controller2.stream); | 294 stream2 = errorGroup.registerStream(controller2.stream); |
| 335 }); | 295 }); |
| 336 | 296 test( |
| 337 test("should pipe exceptions from one stream to the other and to .done", | 297 "should pipe exceptions from one stream to the other and to .done", |
| 338 () { | 298 () { |
| 339 expect(stream1.first, throwsFormatException); | 299 expect(stream1.first, throwsFormatException); |
| 340 expect(stream2.first, throwsFormatException); | 300 expect(stream2.first, throwsFormatException); |
| 341 expect(errorGroup.done, throwsFormatException); | 301 expect(errorGroup.done, throwsFormatException); |
| 342 | |
| 343 controller1.addError(new FormatException()); | 302 controller1.addError(new FormatException()); |
| 344 }); | 303 }); |
| 345 | |
| 346 test("each future should be able to emit values independently", () { | 304 test("each future should be able to emit values independently", () { |
| 347 expect(stream1.toList(), completion(equals(['value1.1', 'value1.2']))); | 305 expect(stream1.toList(), completion(equals(['value1.1', 'value1.2']))); |
| 348 expect(stream2.toList(), completion(equals(['value2.1', 'value2.2']))); | 306 expect(stream2.toList(), completion(equals(['value2.1', 'value2.2']))); |
| 349 expect(errorGroup.done, completes); | 307 expect(errorGroup.done, completes); |
| 350 | 308 controller1 |
| 351 controller1..add('value1.1')..add('value1.2')..close(); | 309 ..add('value1.1') |
| 352 controller2..add('value2.1')..add('value2.2')..close(); | 310 ..add('value1.2') |
| 311 ..close(); |
| 312 controller2 |
| 313 ..add('value2.1') |
| 314 ..add('value2.2') |
| 315 ..close(); |
| 353 }); | 316 }); |
| 354 | 317 test( |
| 355 test("shouldn't throw a top-level exception if a stream receives an error " | 318 "shouldn't throw a top-level exception if a stream receives an error " |
| 356 "after the other listened stream completes", () { | 319 "after the other listened stream completes", |
| 320 () { |
| 357 var signal = new Completer(); | 321 var signal = new Completer(); |
| 358 expect(stream1.toList().whenComplete(signal.complete), | 322 expect( |
| 359 completion(equals(['value1', 'value2']))); | 323 stream1.toList().whenComplete(signal.complete), |
| 360 controller1..add('value1')..add('value2')..close(); | 324 completion(equals(['value1', 'value2']))); |
| 361 | 325 controller1 |
| 326 ..add('value1') |
| 327 ..add('value2') |
| 328 ..close(); |
| 362 expect(signal.future.then((_) { | 329 expect(signal.future.then((_) { |
| 363 // shouldn't cause a top-level exception | |
| 364 controller2.addError(new FormatException()); | 330 controller2.addError(new FormatException()); |
| 365 }), completes); | 331 }), completes); |
| 366 }); | 332 }); |
| 367 | 333 test( |
| 368 test("shouldn't throw a top-level exception if an error is signaled after " | 334 "shouldn't throw a top-level exception if an error is signaled after " |
| 369 "one listened stream completes", () { | 335 "one listened stream completes", |
| 336 () { |
| 370 var signal = new Completer(); | 337 var signal = new Completer(); |
| 371 expect(stream1.toList().whenComplete(signal.complete), | 338 expect( |
| 372 completion(equals(['value1', 'value2']))); | 339 stream1.toList().whenComplete(signal.complete), |
| 373 controller1..add('value1')..add('value2')..close(); | 340 completion(equals(['value1', 'value2']))); |
| 374 | 341 controller1 |
| 342 ..add('value1') |
| 343 ..add('value2') |
| 344 ..close(); |
| 375 expect(signal.future.then((_) { | 345 expect(signal.future.then((_) { |
| 376 // shouldn't cause a top-level exception | |
| 377 errorGroup.signalError(new FormatException()); | 346 errorGroup.signalError(new FormatException()); |
| 378 }), completes); | 347 }), completes); |
| 379 }); | 348 }); |
| 380 }); | 349 }); |
| 381 | |
| 382 group('with a stream and a future', () { | 350 group('with a stream and a future', () { |
| 383 StreamController controller; | 351 StreamController controller; |
| 384 Stream stream; | 352 Stream stream; |
| 385 Completer completer; | 353 Completer completer; |
| 386 Future future; | 354 Future future; |
| 387 | |
| 388 setUp(() { | 355 setUp(() { |
| 389 errorGroup = new ErrorGroup(); | 356 errorGroup = new ErrorGroup(); |
| 390 controller = new StreamController.broadcast(sync: true); | 357 controller = new StreamController.broadcast(sync: true); |
| 391 stream = errorGroup.registerStream(controller.stream); | 358 stream = errorGroup.registerStream(controller.stream); |
| 392 completer = new Completer(); | 359 completer = new Completer(); |
| 393 future = errorGroup.registerFuture(completer.future); | 360 future = errorGroup.registerFuture(completer.future); |
| 394 }); | 361 }); |
| 395 | |
| 396 test("should pipe exceptions from the stream to the future", () { | 362 test("should pipe exceptions from the stream to the future", () { |
| 397 expect(stream.first, throwsFormatException); | 363 expect(stream.first, throwsFormatException); |
| 398 expect(future, throwsFormatException); | 364 expect(future, throwsFormatException); |
| 399 expect(errorGroup.done, throwsFormatException); | 365 expect(errorGroup.done, throwsFormatException); |
| 400 | |
| 401 controller.addError(new FormatException()); | 366 controller.addError(new FormatException()); |
| 402 }); | 367 }); |
| 403 | |
| 404 test("should pipe exceptions from the future to the stream", () { | 368 test("should pipe exceptions from the future to the stream", () { |
| 405 expect(stream.first, throwsFormatException); | 369 expect(stream.first, throwsFormatException); |
| 406 expect(future, throwsFormatException); | 370 expect(future, throwsFormatException); |
| 407 expect(errorGroup.done, throwsFormatException); | 371 expect(errorGroup.done, throwsFormatException); |
| 408 | |
| 409 completer.completeError(new FormatException()); | 372 completer.completeError(new FormatException()); |
| 410 }); | 373 }); |
| 411 | 374 test( |
| 412 test("the stream and the future should be able to complete/emit values " | 375 "the stream and the future should be able to complete/emit values " |
| 413 "independently", () { | 376 "independently", |
| 377 () { |
| 414 expect(stream.toList(), completion(equals(['value1.1', 'value1.2']))); | 378 expect(stream.toList(), completion(equals(['value1.1', 'value1.2']))); |
| 415 expect(future, completion(equals('value2.0'))); | 379 expect(future, completion(equals('value2.0'))); |
| 416 expect(errorGroup.done, completes); | 380 expect(errorGroup.done, completes); |
| 417 | 381 controller |
| 418 controller..add('value1.1')..add('value1.2')..close(); | 382 ..add('value1.1') |
| 383 ..add('value1.2') |
| 384 ..close(); |
| 419 completer.complete('value2.0'); | 385 completer.complete('value2.0'); |
| 420 }); | 386 }); |
| 421 | 387 test( |
| 422 test("shouldn't throw a top-level exception if the stream receives an error
" | 388 "shouldn't throw a top-level exception if the stream receives an error " |
| 423 "after the listened future completes", () { | 389 "after the listened future completes", |
| 390 () { |
| 424 expect(future, completion(equals('value'))); | 391 expect(future, completion(equals('value'))); |
| 425 completer.complete('value'); | 392 completer.complete('value'); |
| 426 | |
| 427 expect(future.then((_) { | 393 expect(future.then((_) { |
| 428 // shouldn't cause a top-level exception | |
| 429 controller.addError(new FormatException()); | 394 controller.addError(new FormatException()); |
| 430 }), completes); | 395 }), completes); |
| 431 }); | 396 }); |
| 432 | 397 test( |
| 433 test("shouldn't throw a top-level exception if the future receives an " | 398 "shouldn't throw a top-level exception if the future receives an " |
| 434 "error after the listened stream completes", () { | 399 "error after the listened stream completes", |
| 400 () { |
| 435 var signal = new Completer(); | 401 var signal = new Completer(); |
| 436 expect(stream.toList().whenComplete(signal.complete), | 402 expect( |
| 437 completion(equals(['value1', 'value2']))); | 403 stream.toList().whenComplete(signal.complete), |
| 438 controller..add('value1')..add('value2')..close(); | 404 completion(equals(['value1', 'value2']))); |
| 439 | 405 controller |
| 406 ..add('value1') |
| 407 ..add('value2') |
| 408 ..close(); |
| 440 expect(signal.future.then((_) { | 409 expect(signal.future.then((_) { |
| 441 // shouldn't cause a top-level exception | |
| 442 completer.completeError(new FormatException()); | 410 completer.completeError(new FormatException()); |
| 443 }), completes); | 411 }), completes); |
| 444 }); | 412 }); |
| 445 }); | 413 }); |
| 446 } | 414 } |
| OLD | NEW |