| // Copyright 2014 The Flutter Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| import 'dart:async'; | |
| import 'package:flutter/foundation.dart'; | |
| import 'package:flutter_test/flutter_test.dart'; | |
| import 'package:stack_trace/stack_trace.dart' as stack_trace; | |
| Future<void> main() async { | |
| // We use AutomatedTestWidgetsFlutterBinding to allow the test binding to set | |
| // FlutterError.demangleStackTrace and FlutterError.onError without testWidgets. | |
| final binding = AutomatedTestWidgetsFlutterBinding(); | |
| test('FlutterErrorDetails demangles', () async { | |
| await binding.runTest(() async { | |
| // When we call toString on a FlutterErrorDetails, it attempts to parse and | |
| // filter the stack trace, which fails if demangleStackTrace returns a | |
| // mangled stack trace. | |
| FlutterErrorDetails( | |
| exception: const CustomException(), | |
| stack: await getMangledStack(), | |
| ).toString(); | |
| // Additional logic is used to parse assertion stack traces. | |
| FlutterErrorDetails( | |
| exception: AssertionError('Some assertion'), | |
| stack: await getMangledStack(), | |
| ).toString(); | |
| }, () {}); | |
| binding.postTest(); | |
| }); | |
| test('debugPrintStack demangles', () async { | |
| await binding.runTest(() async { | |
| final DebugPrintCallback oldDebugPrint = debugPrint; | |
| try { | |
| debugPrint = (String? message, {int? wrapWidth}) {}; | |
| debugPrintStack(stackTrace: await getMangledStack()); | |
| } finally { | |
| debugPrint = oldDebugPrint; | |
| } | |
| }, () {}); | |
| binding.postTest(); | |
| }); | |
| } | |
| Future<StackTrace> getMangledStack() { | |
| // package:test uses package:stack_trace to wrap tests in a Zone that overrides | |
| // errorCallback, the error callback transforms any StackTrace propagated | |
| // to futures into a Chain, which has a format different from the vm. | |
| final stackCompleter = Completer<StackTrace>(); | |
| final completer = Completer<void>(); | |
| completer.future.then( | |
| (void value) { | |
| assert(false); | |
| }, | |
| onError: (Object error, StackTrace stack) { | |
| expect(error, isA<CustomException>()); | |
| expect(stack, isA<stack_trace.Chain>()); | |
| stackCompleter.complete(stack); | |
| }, | |
| ); | |
| completer.completeError(const CustomException()); | |
| return stackCompleter.future; | |
| } | |
| class CustomException implements Exception { | |
| const CustomException(); | |
| } |