1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | import 'dart:async'; |
6 | |
7 | import 'package:flutter/foundation.dart'; |
8 | import 'package:flutter_test/flutter_test.dart'; |
9 | import 'package:stack_trace/stack_trace.dart' as stack_trace; |
10 | |
11 | Future<void> main() async { |
12 | // We use AutomatedTestWidgetsFlutterBinding to allow the test binding to set |
13 | // FlutterError.demangleStackTrace and FlutterError.onError without testWidgets. |
14 | final AutomatedTestWidgetsFlutterBinding binding = AutomatedTestWidgetsFlutterBinding(); |
15 | |
16 | test('FlutterErrorDetails demangles' , () async { |
17 | await binding.runTest(() async { |
18 | // When we call toString on a FlutterErrorDetails, it attempts to parse and |
19 | // filter the stack trace, which fails if demangleStackTrace returns a |
20 | // mangled stack trace. |
21 | FlutterErrorDetails( |
22 | exception: const CustomException(), |
23 | stack: await getMangledStack(), |
24 | ).toString(); |
25 | |
26 | // Additional logic is used to parse assertion stack traces. |
27 | FlutterErrorDetails( |
28 | exception: AssertionError('Some assertion' ), |
29 | stack: await getMangledStack(), |
30 | ).toString(); |
31 | }, () {}); |
32 | binding.postTest(); |
33 | }); |
34 | |
35 | test('debugPrintStack demangles' , () async { |
36 | await binding.runTest(() async { |
37 | final DebugPrintCallback oldDebugPrint = debugPrint; |
38 | try { |
39 | debugPrint = (String? message, {int? wrapWidth}) {}; |
40 | debugPrintStack(stackTrace: await getMangledStack()); |
41 | } finally { |
42 | debugPrint = oldDebugPrint; |
43 | } |
44 | }, () {}); |
45 | binding.postTest(); |
46 | }); |
47 | } |
48 | |
49 | Future<StackTrace> getMangledStack() { |
50 | // package:test uses package:stack_trace to wrap tests in a Zone that overrides |
51 | // errorCallback, the error callback transforms any StackTrace propagated |
52 | // to futures into a Chain, which has a format different from the vm. |
53 | final Completer<StackTrace> stackCompleter = Completer<StackTrace>(); |
54 | final Completer<void> completer = Completer<void>(); |
55 | completer.future.then( |
56 | (void value) { |
57 | assert(false); |
58 | }, |
59 | onError: (Object error, StackTrace stack) { |
60 | expect(error, isA<CustomException>()); |
61 | expect(stack, isA<stack_trace.Chain>()); |
62 | stackCompleter.complete(stack); |
63 | }, |
64 | ); |
65 | completer.completeError(const CustomException()); |
66 | return stackCompleter.future; |
67 | } |
68 | |
69 | class CustomException implements Exception { |
70 | const CustomException(); |
71 | } |
72 | |