// 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 AutomatedTestWidgetsFlutterBinding 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 Completer<StackTrace> stackCompleter = Completer<StackTrace>(); final Completer<void> 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(); }