Line data Source code
1 : // Copyright (c) 2018, 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 : import 'dart:async'; 6 : 7 : import 'package:stack_trace/stack_trace.dart'; 8 : 9 : import 'invoker.dart'; 10 : import 'stack_trace_mapper.dart'; 11 : 12 : /// The key used to look up [StackTraceFormatter.current] in a zone. 13 33 : final _currentKey = Object(); 14 : 15 : /// A class that tracks how to format a stack trace according to the user's 16 : /// configuration. 17 : /// 18 : /// This can convert JavaScript stack traces to Dart using source maps, and fold 19 : /// irrelevant frames out of the stack trace. 20 : class StackTraceFormatter { 21 : /// A class that converts [trace] into a Dart stack trace, or `null` to use it 22 : /// as-is. 23 : StackTraceMapper? _mapper; 24 : 25 : /// The set of packages to fold when producing terse [Chain]s. 26 : var _except = {'test', 'stream_channel', 'test_api'}; 27 : 28 : /// If non-empty, all packages not in this list will be folded when producing 29 : /// terse [Chain]s. 30 : var _only = <String>{}; 31 : 32 : /// Returns the current manager, or `null` if this isn't called within a call 33 : /// to [asCurrent]. 34 11 : static StackTraceFormatter? get current => 35 33 : Zone.current[_currentKey] as StackTraceFormatter?; 36 : 37 : /// Runs [body] with this as [StackTraceFormatter.current]. 38 : /// 39 : /// This is zone-scoped, so this will be the current configuration in any 40 : /// asynchronous callbacks transitively created by [body]. 41 11 : T asCurrent<T>(T Function() body) => 42 33 : runZoned(body, zoneValues: {_currentKey: this}); 43 : 44 : /// Configure how stack traces are formatted. 45 : /// 46 : /// The [mapper] is used to convert JavaScript traces into Dart traces. The 47 : /// [except] set indicates packages whose frames should be folded away. If 48 : /// [only] is non-empty, it indicates packages whose frames should *not* be 49 : /// folded away. 50 11 : void configure( 51 : {StackTraceMapper? mapper, Set<String>? except, Set<String>? only}) { 52 0 : if (mapper != null) _mapper = mapper; 53 0 : if (except != null) _except = except; 54 0 : if (only != null) _only = only; 55 : } 56 : 57 : /// Converts [stackTrace] to a [Chain] and formats it according to the user's 58 : /// preferences. 59 : /// 60 : /// If [verbose] is `true`, this doesn't fold out irrelevant stack frames. It 61 : /// defaults to the current test's [Metadata.verboseTrace] configuration, or 62 : /// `false` if there is no current test. 63 11 : Chain formatStackTrace(StackTrace stackTrace, {bool? verbose}) { 64 11 : verbose ??= Invoker.current?.liveTest.test.metadata.verboseTrace ?? false; 65 : 66 : var chain = 67 22 : Chain.forTrace(_mapper?.mapStackTrace(stackTrace) ?? stackTrace); 68 : if (verbose) return chain; 69 : 70 22 : return chain.foldFrames((frame) { 71 22 : if (_only.isNotEmpty) return !_only.contains(frame.package); 72 33 : return _except.contains(frame.package); 73 : }, terse: true); 74 : } 75 : }