| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 import 'dart:async'; | 5 import 'dart:async'; |
| 6 | 6 |
| 7 import 'package:path/path.dart' as p; | 7 import 'package:path/path.dart' as p; |
| 8 import 'package:stack_trace/stack_trace.dart'; | 8 import 'package:stack_trace/stack_trace.dart'; |
| 9 import 'package:test/test.dart'; | 9 import 'package:test/test.dart'; |
| 10 | 10 |
| 11 import 'utils.dart'; | 11 import 'utils.dart'; |
| 12 | 12 |
| 13 typedef void ChainErrorCallback(stack, Chain chain); |
| 14 |
| 13 void main() { | 15 void main() { |
| 14 group('Chain.parse()', () { | 16 group('Chain.parse()', () { |
| 15 test('parses a real Chain', () { | 17 test('parses a real Chain', () { |
| 16 return captureFuture(() => inMicrotask(() => throw 'error')) | 18 return captureFuture(() => inMicrotask(() => throw 'error')) |
| 17 .then((chain) { | 19 .then((chain) { |
| 18 expect(new Chain.parse(chain.toString()).toString(), | 20 expect(new Chain.parse(chain.toString()).toString(), |
| 19 equals(chain.toString())); | 21 equals(chain.toString())); |
| 20 }); | 22 }); |
| 21 }); | 23 }); |
| 22 | 24 |
| 23 test('parses an empty string', () { | 25 test('parses an empty string', () { |
| 24 var chain = new Chain.parse(''); | 26 var chain = new Chain.parse(''); |
| 25 expect(chain.traces, isEmpty); | 27 expect(chain.traces, isEmpty); |
| 26 }); | 28 }); |
| 27 | 29 |
| 28 test('parses a chain containing empty traces', () { | 30 test('parses a chain containing empty traces', () { |
| 29 var chain = new Chain.parse( | 31 var chain = |
| 30 '===== asynchronous gap ===========================\n' | 32 new Chain.parse('===== asynchronous gap ===========================\n' |
| 31 '===== asynchronous gap ===========================\n'); | 33 '===== asynchronous gap ===========================\n'); |
| 32 expect(chain.traces, hasLength(3)); | 34 expect(chain.traces, hasLength(3)); |
| 33 expect(chain.traces[0].frames, isEmpty); | 35 expect(chain.traces[0].frames, isEmpty); |
| 34 expect(chain.traces[1].frames, isEmpty); | 36 expect(chain.traces[1].frames, isEmpty); |
| 35 expect(chain.traces[2].frames, isEmpty); | 37 expect(chain.traces[2].frames, isEmpty); |
| 36 }); | 38 }); |
| 37 }); | 39 }); |
| 38 | 40 |
| 41 group("Chain.capture() with when: false", () { |
| 42 test("with no onError doesn't block errors", () { |
| 43 expect(Chain.capture(() => new Future.error("oh no"), when: false), |
| 44 throwsA("oh no")); |
| 45 }); |
| 46 |
| 47 test("with onError blocks errors", () { |
| 48 Chain.capture(() { |
| 49 return new Future.error("oh no"); |
| 50 }, onError: expectAsync2((error, chain) { |
| 51 expect(error, equals("oh no")); |
| 52 expect(chain, new isInstanceOf<Chain>()); |
| 53 }), when: false); |
| 54 }); |
| 55 |
| 56 test("doesn't enable chain-tracking", () { |
| 57 return Chain.disable(() { |
| 58 return Chain.capture(() { |
| 59 var completer = new Completer(); |
| 60 inMicrotask(() { |
| 61 completer.complete(new Chain.current()); |
| 62 }); |
| 63 |
| 64 return completer.future.then((chain) { |
| 65 expect(chain.traces, hasLength(1)); |
| 66 }); |
| 67 }, when: false); |
| 68 }); |
| 69 }); |
| 70 }); |
| 71 |
| 72 group("Chain.disable()", () { |
| 73 test("disables chain-tracking", () { |
| 74 return Chain.disable(() { |
| 75 var completer = new Completer(); |
| 76 inMicrotask(() => completer.complete(new Chain.current())); |
| 77 |
| 78 return completer.future.then((chain) { |
| 79 expect(chain.traces, hasLength(1)); |
| 80 }); |
| 81 }); |
| 82 }); |
| 83 |
| 84 test("Chain.capture() re-enables chain-tracking", () { |
| 85 return Chain.disable(() { |
| 86 return Chain.capture(() { |
| 87 var completer = new Completer(); |
| 88 inMicrotask(() => completer.complete(new Chain.current())); |
| 89 |
| 90 return completer.future.then((chain) { |
| 91 expect(chain.traces, hasLength(2)); |
| 92 }); |
| 93 }); |
| 94 }); |
| 95 }); |
| 96 |
| 97 test("preserves parent zones of the capture zone", () { |
| 98 // The outer disable call turns off the test package's chain-tracking. |
| 99 return Chain.disable(() { |
| 100 return runZoned(() { |
| 101 return Chain.capture(() { |
| 102 expect(Chain.disable(() => Zone.current[#enabled]), isTrue); |
| 103 }); |
| 104 }, zoneValues: {#enabled: true}); |
| 105 }); |
| 106 }); |
| 107 |
| 108 test("preserves child zones of the capture zone", () { |
| 109 // The outer disable call turns off the test package's chain-tracking. |
| 110 return Chain.disable(() { |
| 111 return Chain.capture(() { |
| 112 return runZoned(() { |
| 113 expect(Chain.disable(() => Zone.current[#enabled]), isTrue); |
| 114 }, zoneValues: {#enabled: true}); |
| 115 }); |
| 116 }); |
| 117 }); |
| 118 |
| 119 test("with when: false doesn't disable", () { |
| 120 return Chain.capture(() { |
| 121 return Chain.disable(() { |
| 122 var completer = new Completer(); |
| 123 inMicrotask(() => completer.complete(new Chain.current())); |
| 124 |
| 125 return completer.future.then((chain) { |
| 126 expect(chain.traces, hasLength(2)); |
| 127 }); |
| 128 }, when: false); |
| 129 }); |
| 130 }); |
| 131 }); |
| 132 |
| 39 test("toString() ensures that all traces are aligned", () { | 133 test("toString() ensures that all traces are aligned", () { |
| 40 var chain = new Chain([ | 134 var chain = new Chain([ |
| 41 new Trace.parse('short 10:11 Foo.bar\n'), | 135 new Trace.parse('short 10:11 Foo.bar\n'), |
| 42 new Trace.parse('loooooooooooong 10:11 Zop.zoop') | 136 new Trace.parse('loooooooooooong 10:11 Zop.zoop') |
| 43 ]); | 137 ]); |
| 44 | 138 |
| 45 expect(chain.toString(), equals( | 139 expect( |
| 46 'short 10:11 Foo.bar\n' | 140 chain.toString(), |
| 47 '===== asynchronous gap ===========================\n' | 141 equals('short 10:11 Foo.bar\n' |
| 48 'loooooooooooong 10:11 Zop.zoop\n')); | 142 '===== asynchronous gap ===========================\n' |
| 143 'loooooooooooong 10:11 Zop.zoop\n')); |
| 49 }); | 144 }); |
| 50 | 145 |
| 51 var userSlashCode = p.join('user', 'code.dart'); | 146 var userSlashCode = p.join('user', 'code.dart'); |
| 52 group('Chain.terse', () { | 147 group('Chain.terse', () { |
| 53 test('makes each trace terse', () { | 148 test('makes each trace terse', () { |
| 54 var chain = new Chain([ | 149 var chain = new Chain([ |
| 55 new Trace.parse( | 150 new Trace.parse('dart:core 10:11 Foo.bar\n' |
| 56 'dart:core 10:11 Foo.bar\n' | |
| 57 'dart:core 10:11 Bar.baz\n' | 151 'dart:core 10:11 Bar.baz\n' |
| 58 'user/code.dart 10:11 Bang.qux\n' | 152 'user/code.dart 10:11 Bang.qux\n' |
| 59 'dart:core 10:11 Zip.zap\n' | 153 'dart:core 10:11 Zip.zap\n' |
| 60 'dart:core 10:11 Zop.zoop'), | 154 'dart:core 10:11 Zop.zoop'), |
| 61 new Trace.parse( | 155 new Trace.parse('user/code.dart 10:11 Bang.qux\n' |
| 62 'user/code.dart 10:11 Bang.qux\n' | |
| 63 'dart:core 10:11 Foo.bar\n' | 156 'dart:core 10:11 Foo.bar\n' |
| 64 'package:stack_trace/stack_trace.dart 10:11 Bar.baz\n' | 157 'package:stack_trace/stack_trace.dart 10:11 Bar.baz\n' |
| 65 'dart:core 10:11 Zip.zap\n' | 158 'dart:core 10:11 Zip.zap\n' |
| 66 'user/code.dart 10:11 Zop.zoop') | 159 'user/code.dart 10:11 Zop.zoop') |
| 67 ]); | 160 ]); |
| 68 | 161 |
| 69 expect(chain.terse.toString(), equals( | 162 expect( |
| 70 'dart:core Bar.baz\n' | 163 chain.terse.toString(), |
| 71 '$userSlashCode 10:11 Bang.qux\n' | 164 equals('dart:core Bar.baz\n' |
| 72 '===== asynchronous gap ===========================\n' | 165 '$userSlashCode 10:11 Bang.qux\n' |
| 73 '$userSlashCode 10:11 Bang.qux\n' | 166 '===== asynchronous gap ===========================\n' |
| 74 'dart:core Zip.zap\n' | 167 '$userSlashCode 10:11 Bang.qux\n' |
| 75 '$userSlashCode 10:11 Zop.zoop\n')); | 168 'dart:core Zip.zap\n' |
| 169 '$userSlashCode 10:11 Zop.zoop\n')); |
| 76 }); | 170 }); |
| 77 | 171 |
| 78 test('eliminates internal-only traces', () { | 172 test('eliminates internal-only traces', () { |
| 79 var chain = new Chain([ | 173 var chain = new Chain([ |
| 80 new Trace.parse( | 174 new Trace.parse('user/code.dart 10:11 Foo.bar\n' |
| 81 'user/code.dart 10:11 Foo.bar\n' | |
| 82 'dart:core 10:11 Bar.baz'), | 175 'dart:core 10:11 Bar.baz'), |
| 83 new Trace.parse( | 176 new Trace.parse('dart:core 10:11 Foo.bar\n' |
| 84 'dart:core 10:11 Foo.bar\n' | |
| 85 'package:stack_trace/stack_trace.dart 10:11 Bar.baz\n' | 177 'package:stack_trace/stack_trace.dart 10:11 Bar.baz\n' |
| 86 'dart:core 10:11 Zip.zap'), | 178 'dart:core 10:11 Zip.zap'), |
| 87 new Trace.parse( | 179 new Trace.parse('user/code.dart 10:11 Foo.bar\n' |
| 88 'user/code.dart 10:11 Foo.bar\n' | |
| 89 'dart:core 10:11 Bar.baz') | 180 'dart:core 10:11 Bar.baz') |
| 90 ]); | 181 ]); |
| 91 | 182 |
| 92 expect(chain.terse.toString(), equals( | 183 expect( |
| 93 '$userSlashCode 10:11 Foo.bar\n' | 184 chain.terse.toString(), |
| 94 '===== asynchronous gap ===========================\n' | 185 equals('$userSlashCode 10:11 Foo.bar\n' |
| 95 '$userSlashCode 10:11 Foo.bar\n')); | 186 '===== asynchronous gap ===========================\n' |
| 187 '$userSlashCode 10:11 Foo.bar\n')); |
| 96 }); | 188 }); |
| 97 | 189 |
| 98 test("doesn't return an empty chain", () { | 190 test("doesn't return an empty chain", () { |
| 99 var chain = new Chain([ | 191 var chain = new Chain([ |
| 100 new Trace.parse( | 192 new Trace.parse('dart:core 10:11 Foo.bar\n' |
| 101 'dart:core 10:11 Foo.bar\n' | |
| 102 'package:stack_trace/stack_trace.dart 10:11 Bar.baz\n' | 193 'package:stack_trace/stack_trace.dart 10:11 Bar.baz\n' |
| 103 'dart:core 10:11 Zip.zap'), | 194 'dart:core 10:11 Zip.zap'), |
| 104 new Trace.parse( | 195 new Trace.parse('dart:core 10:11 A.b\n' |
| 105 'dart:core 10:11 A.b\n' | |
| 106 'package:stack_trace/stack_trace.dart 10:11 C.d\n' | 196 'package:stack_trace/stack_trace.dart 10:11 C.d\n' |
| 107 'dart:core 10:11 E.f') | 197 'dart:core 10:11 E.f') |
| 108 ]); | 198 ]); |
| 109 | 199 |
| 110 expect(chain.terse.toString(), equals('dart:core E.f\n')); | 200 expect(chain.terse.toString(), equals('dart:core E.f\n')); |
| 111 }); | 201 }); |
| 202 |
| 203 // Regression test for #9 |
| 204 test("doesn't crash on empty traces", () { |
| 205 var chain = new Chain([ |
| 206 new Trace.parse('user/code.dart 10:11 Bang.qux'), |
| 207 new Trace([]), |
| 208 new Trace.parse('user/code.dart 10:11 Bang.qux') |
| 209 ]); |
| 210 |
| 211 expect( |
| 212 chain.terse.toString(), |
| 213 equals('$userSlashCode 10:11 Bang.qux\n' |
| 214 '===== asynchronous gap ===========================\n' |
| 215 '$userSlashCode 10:11 Bang.qux\n')); |
| 216 }); |
| 112 }); | 217 }); |
| 113 | 218 |
| 114 group('Chain.foldFrames', () { | 219 group('Chain.foldFrames', () { |
| 115 test('folds each trace', () { | 220 test('folds each trace', () { |
| 116 var chain = new Chain([ | 221 var chain = new Chain([ |
| 117 new Trace.parse( | 222 new Trace.parse('a.dart 10:11 Foo.bar\n' |
| 118 'a.dart 10:11 Foo.bar\n' | |
| 119 'a.dart 10:11 Bar.baz\n' | 223 'a.dart 10:11 Bar.baz\n' |
| 120 'b.dart 10:11 Bang.qux\n' | 224 'b.dart 10:11 Bang.qux\n' |
| 121 'a.dart 10:11 Zip.zap\n' | 225 'a.dart 10:11 Zip.zap\n' |
| 122 'a.dart 10:11 Zop.zoop'), | 226 'a.dart 10:11 Zop.zoop'), |
| 123 new Trace.parse( | 227 new Trace.parse('a.dart 10:11 Foo.bar\n' |
| 124 'a.dart 10:11 Foo.bar\n' | |
| 125 'a.dart 10:11 Bar.baz\n' | 228 'a.dart 10:11 Bar.baz\n' |
| 126 'a.dart 10:11 Bang.qux\n' | 229 'a.dart 10:11 Bang.qux\n' |
| 127 'a.dart 10:11 Zip.zap\n' | 230 'a.dart 10:11 Zip.zap\n' |
| 128 'b.dart 10:11 Zop.zoop') | 231 'b.dart 10:11 Zop.zoop') |
| 129 ]); | 232 ]); |
| 130 | 233 |
| 131 var folded = chain.foldFrames((frame) => frame.library == 'a.dart'); | 234 var folded = chain.foldFrames((frame) => frame.library == 'a.dart'); |
| 132 expect(folded.toString(), equals( | 235 expect( |
| 133 'a.dart 10:11 Bar.baz\n' | 236 folded.toString(), |
| 134 'b.dart 10:11 Bang.qux\n' | 237 equals('a.dart 10:11 Bar.baz\n' |
| 135 'a.dart 10:11 Zop.zoop\n' | 238 'b.dart 10:11 Bang.qux\n' |
| 136 '===== asynchronous gap ===========================\n' | 239 'a.dart 10:11 Zop.zoop\n' |
| 137 'a.dart 10:11 Zip.zap\n' | 240 '===== asynchronous gap ===========================\n' |
| 138 'b.dart 10:11 Zop.zoop\n')); | 241 'a.dart 10:11 Zip.zap\n' |
| 242 'b.dart 10:11 Zop.zoop\n')); |
| 139 }); | 243 }); |
| 140 | 244 |
| 141 test('with terse: true, folds core frames as well', () { | 245 test('with terse: true, folds core frames as well', () { |
| 142 var chain = new Chain([ | 246 var chain = new Chain([ |
| 143 new Trace.parse( | 247 new Trace.parse('a.dart 10:11 Foo.bar\n' |
| 144 'a.dart 10:11 Foo.bar\n' | |
| 145 'dart:async-patch/future.dart 10:11 Zip.zap\n' | 248 'dart:async-patch/future.dart 10:11 Zip.zap\n' |
| 146 'b.dart 10:11 Bang.qux\n' | 249 'b.dart 10:11 Bang.qux\n' |
| 147 'dart:core 10:11 Bar.baz\n' | 250 'dart:core 10:11 Bar.baz\n' |
| 148 'a.dart 10:11 Zop.zoop'), | 251 'a.dart 10:11 Zop.zoop'), |
| 149 new Trace.parse( | 252 new Trace.parse('a.dart 10:11 Foo.bar\n' |
| 150 'a.dart 10:11 Foo.bar\n' | |
| 151 'a.dart 10:11 Bar.baz\n' | 253 'a.dart 10:11 Bar.baz\n' |
| 152 'a.dart 10:11 Bang.qux\n' | 254 'a.dart 10:11 Bang.qux\n' |
| 153 'a.dart 10:11 Zip.zap\n' | 255 'a.dart 10:11 Zip.zap\n' |
| 154 'b.dart 10:11 Zop.zoop') | 256 'b.dart 10:11 Zop.zoop') |
| 155 ]); | 257 ]); |
| 156 | 258 |
| 157 var folded = chain.foldFrames((frame) => frame.library == 'a.dart', | 259 var folded = |
| 158 terse: true); | 260 chain.foldFrames((frame) => frame.library == 'a.dart', terse: true); |
| 159 expect(folded.toString(), equals( | 261 expect( |
| 160 'dart:async Zip.zap\n' | 262 folded.toString(), |
| 161 'b.dart 10:11 Bang.qux\n' | 263 equals('dart:async Zip.zap\n' |
| 162 'a.dart Zop.zoop\n' | 264 'b.dart 10:11 Bang.qux\n' |
| 163 '===== asynchronous gap ===========================\n' | 265 '===== asynchronous gap ===========================\n' |
| 164 'a.dart Zip.zap\n' | 266 'a.dart Zip.zap\n' |
| 165 'b.dart 10:11 Zop.zoop\n')); | 267 'b.dart 10:11 Zop.zoop\n')); |
| 166 }); | 268 }); |
| 167 | 269 |
| 168 test('eliminates completely-folded traces', () { | 270 test('eliminates completely-folded traces', () { |
| 169 var chain = new Chain([ | 271 var chain = new Chain([ |
| 170 new Trace.parse( | 272 new Trace.parse('a.dart 10:11 Foo.bar\n' |
| 171 'a.dart 10:11 Foo.bar\n' | |
| 172 'b.dart 10:11 Bang.qux'), | 273 'b.dart 10:11 Bang.qux'), |
| 173 new Trace.parse( | 274 new Trace.parse('a.dart 10:11 Foo.bar\n' |
| 174 'a.dart 10:11 Foo.bar\n' | |
| 175 'a.dart 10:11 Bang.qux'), | 275 'a.dart 10:11 Bang.qux'), |
| 176 new Trace.parse( | 276 new Trace.parse('a.dart 10:11 Zip.zap\n' |
| 177 'a.dart 10:11 Zip.zap\n' | |
| 178 'b.dart 10:11 Zop.zoop') | 277 'b.dart 10:11 Zop.zoop') |
| 179 ]); | 278 ]); |
| 180 | 279 |
| 181 var folded = chain.foldFrames((frame) => frame.library == 'a.dart'); | 280 var folded = chain.foldFrames((frame) => frame.library == 'a.dart'); |
| 182 expect(folded.toString(), equals( | 281 expect( |
| 183 'a.dart 10:11 Foo.bar\n' | 282 folded.toString(), |
| 184 'b.dart 10:11 Bang.qux\n' | 283 equals('a.dart 10:11 Foo.bar\n' |
| 185 '===== asynchronous gap ===========================\n' | 284 'b.dart 10:11 Bang.qux\n' |
| 186 'a.dart 10:11 Zip.zap\n' | 285 '===== asynchronous gap ===========================\n' |
| 187 'b.dart 10:11 Zop.zoop\n')); | 286 'a.dart 10:11 Zip.zap\n' |
| 287 'b.dart 10:11 Zop.zoop\n')); |
| 188 }); | 288 }); |
| 189 | 289 |
| 190 test("doesn't return an empty trace", () { | 290 test("doesn't return an empty trace", () { |
| 191 var chain = new Chain([ | 291 var chain = new Chain([ |
| 192 new Trace.parse( | 292 new Trace.parse('a.dart 10:11 Foo.bar\n' |
| 193 'a.dart 10:11 Foo.bar\n' | |
| 194 'a.dart 10:11 Bang.qux') | 293 'a.dart 10:11 Bang.qux') |
| 195 ]); | 294 ]); |
| 196 | 295 |
| 197 var folded = chain.foldFrames((frame) => frame.library == 'a.dart'); | 296 var folded = chain.foldFrames((frame) => frame.library == 'a.dart'); |
| 198 expect(folded.toString(), equals('a.dart 10:11 Bang.qux\n')); | 297 expect(folded.toString(), equals('a.dart 10:11 Bang.qux\n')); |
| 199 }); | 298 }); |
| 200 }); | 299 }); |
| 201 | 300 |
| 202 test('Chain.toTrace eliminates asynchronous gaps', () { | 301 test('Chain.toTrace eliminates asynchronous gaps', () { |
| 203 var trace = new Chain([ | 302 var trace = new Chain([ |
| 204 new Trace.parse( | 303 new Trace.parse('user/code.dart 10:11 Foo.bar\n' |
| 205 'user/code.dart 10:11 Foo.bar\n' | |
| 206 'dart:core 10:11 Bar.baz'), | 304 'dart:core 10:11 Bar.baz'), |
| 207 new Trace.parse( | 305 new Trace.parse('user/code.dart 10:11 Foo.bar\n' |
| 208 'user/code.dart 10:11 Foo.bar\n' | |
| 209 'dart:core 10:11 Bar.baz') | 306 'dart:core 10:11 Bar.baz') |
| 210 ]).toTrace(); | 307 ]).toTrace(); |
| 211 | 308 |
| 212 expect(trace.toString(), equals( | 309 expect( |
| 213 '$userSlashCode 10:11 Foo.bar\n' | 310 trace.toString(), |
| 214 'dart:core 10:11 Bar.baz\n' | 311 equals('$userSlashCode 10:11 Foo.bar\n' |
| 215 '$userSlashCode 10:11 Foo.bar\n' | 312 'dart:core 10:11 Bar.baz\n' |
| 216 'dart:core 10:11 Bar.baz\n')); | 313 '$userSlashCode 10:11 Foo.bar\n' |
| 314 'dart:core 10:11 Bar.baz\n')); |
| 217 }); | 315 }); |
| 218 | 316 } |
| 219 group('Chain.track(Future)', () { | |
| 220 test('forwards the future value within Chain.capture()', () { | |
| 221 Chain.capture(() { | |
| 222 expect(Chain.track(new Future.value('value')), | |
| 223 completion(equals('value'))); | |
| 224 | |
| 225 var trace = new Trace.current(); | |
| 226 expect(Chain.track(new Future.error('error', trace)) | |
| 227 .catchError((e, stackTrace) { | |
| 228 expect(e, equals('error')); | |
| 229 expect(stackTrace.toString(), equals(trace.toString())); | |
| 230 }), completes); | |
| 231 }); | |
| 232 }); | |
| 233 | |
| 234 test('forwards the future value outside of Chain.capture()', () { | |
| 235 expect(Chain.track(new Future.value('value')), | |
| 236 completion(equals('value'))); | |
| 237 | |
| 238 var trace = new Trace.current(); | |
| 239 expect(Chain.track(new Future.error('error', trace)) | |
| 240 .catchError((e, stackTrace) { | |
| 241 expect(e, equals('error')); | |
| 242 expect(stackTrace.toString(), equals(trace.toString())); | |
| 243 }), completes); | |
| 244 }); | |
| 245 }); | |
| 246 | |
| 247 group('Chain.track(Stream)', () { | |
| 248 test('forwards stream values within Chain.capture()', () { | |
| 249 Chain.capture(() { | |
| 250 var controller = new StreamController() | |
| 251 ..add(1)..add(2)..add(3)..close(); | |
| 252 expect(Chain.track(controller.stream).toList(), | |
| 253 completion(equals([1, 2, 3]))); | |
| 254 | |
| 255 var trace = new Trace.current(); | |
| 256 controller = new StreamController()..addError('error', trace); | |
| 257 expect(Chain.track(controller.stream).toList() | |
| 258 .catchError((e, stackTrace) { | |
| 259 expect(e, equals('error')); | |
| 260 expect(stackTrace.toString(), equals(trace.toString())); | |
| 261 }), completes); | |
| 262 }); | |
| 263 }); | |
| 264 | |
| 265 test('forwards stream values outside of Chain.capture()', () { | |
| 266 Chain.capture(() { | |
| 267 var controller = new StreamController() | |
| 268 ..add(1)..add(2)..add(3)..close(); | |
| 269 expect(Chain.track(controller.stream).toList(), | |
| 270 completion(equals([1, 2, 3]))); | |
| 271 | |
| 272 var trace = new Trace.current(); | |
| 273 controller = new StreamController()..addError('error', trace); | |
| 274 expect(Chain.track(controller.stream).toList() | |
| 275 .catchError((e, stackTrace) { | |
| 276 expect(e, equals('error')); | |
| 277 expect(stackTrace.toString(), equals(trace.toString())); | |
| 278 }), completes); | |
| 279 }); | |
| 280 }); | |
| 281 }); | |
| 282 } | |
| OLD | NEW |