Skip to content

Conversation

@grouma
Copy link
Member

@grouma grouma commented Jun 16, 2017

  • Allow StackTraceMapper to be serialized and deserialized
  • Send StackTraceMapper to remote isolate
  • Move all test chaining to the remote isolate
  • Enable new configurations for stack trace folding
  • Add corresponding tests

This will close #416

@grouma grouma requested a review from nex3 June 16, 2017 22:15
Copy link
Member

@nex3 nex3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also needs tests in configuration_test.dart.

CHANGELOG.md Outdated
@@ -1,3 +1,8 @@
## 0.12.23

* Add a `fold_stack_frame` field for `dart_test.yaml`. This will
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"frames"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


This field indicates which packages will be folded when producing stack traces.
Packages contained in the `exclude` option will be folded. If `only` is provided,
all packages not contained in this list will be folded. If no options are provided,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Long line.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


### `fold_stack_frames`

This field indicates which packages will be folded when producing stack traces.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it'll be clear to an unfamiliar user what "folding" means in this context. Maybe "This field controls which packages' stack frames will be folded away when displaying stack traces." It would also be good to include an example stack trace.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

This field indicates which packages will be folded when producing stack traces.
Packages contained in the `exclude` option will be folded. If `only` is provided,
all packages not contained in this list will be folded. If no options are provided,
we fold `package:test` and `package:stream_channel` by default.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This document doesn't use the second person elsewhere, so it probably shouldn't do so here. Maybe "By default, frames from the test package and the stream_channel package are folded."

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

```yaml
fold_stack_frames:
only:
- some_package
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: To match other lists in this doc, the -s should be aligned with the beginning of the keys.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -0,0 +1,103 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2017

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -0,0 +1,25 @@
import 'package:stack_trace/stack_trace.dart';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget the copyright header.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

throw "oh no";
});
}
""";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just create this file in a setUp() call.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

["Invalid option for fold_stack_frames value", "^^^^^^"]));
await test.shouldExit(exit_codes.data);
});

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test what happens if both only and except keys are set.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

var test = await runTest(["test.dart"]);
var testOutput = (await test.stdoutStream().toList());
for (var output in testOutput) {
expect(output.contains('package:stream_channel'), isFalse);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd use the neverEmits() matcher for this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. Done.

/// Converts [stackTrace] to a [Chain] following the test's configuration.
Chain testChain(StackTrace stackTrace, {bool verbose: false}) {
var testTrace = currentMapper(stackTrace);
void configureTestChaining(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Document this.

if (onlyPackages != null) _onlyPackages = onlyPackages;
}

Chain terseChain(StackTrace stackTrace, {bool verbose: false}) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Document this as well.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

}, value: (valueNode) {
if (valueNode is! YamlList ||
(valueNode as YamlList).firstWhere((value) => value is! String,
orElse: () => null) !=
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See section 16.33 of the spec. We don't have to worry about built-in identifiers, but we should enforce the syntactic requirements.

'Must be a list of strings.',
valueNode.span,
_source);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The if statement that throws an exception if valueNode isn't correct.

channel.sink.add({
"type": "error",
"error": RemoteException.serialize(error, stackTrace)
"error": RemoteException.serialize(error, testChain(stackTrace))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll need to access the verboseTrace flag on the suite-level metadata that was passed in as part of the initial message.

if (keyNode.value != "only" && keyNode.value != "except") {
throw new SourceSpanFormatException(
'Must be "only" or "except".', keyNode.span, _source);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any statement of the form if (something about value) { throw } should probably be a call to _validate() instead.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

}

/// Returns a [Set] from a JSON serialized list.
static Set<String> _setFromSerializedList(List<String> list) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I'd call this _deserializeSet() to match other serialization functions.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


import 'dart:async';
import 'package:collection/collection.dart';

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't where the newline should go. See Effective Dart.

class StackTraceMapper {
/// The parsed source map.
final Mapping _mapping;
Mapping _mapping;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mention in the documentation that this is initialized lazily in mapStackTrace().

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

static Map<String, String> _serializablePackageConfigMap(
/// Converts a [packageConfigMap] into a format suitable for JSON
/// serialization.
static Map<String, String> _serializePackageConfigMap(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These shouldn't be static. Generally, don't make helpers static unless they need to be used in other static methods.

Set<String> onlyPackages}) {
if (mapper != null) _mapper = mapper;
if (exceptPackages != null) _exceptPackages = exceptPackages;
if (onlyPackages != null) _onlyPackages = onlyPackages;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These != null checks are unnecessary.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The null check is necessary since we don't check for nullness in terseChain.

_foldTraceExcept = _list(foldTraceExcept),
_foldTraceOnly = _list(foldTraceOnly),
_foldTraceExcept = foldTraceExcept != null
? new Set.from(_list(foldTraceExcept))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just add a _set() helper method.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

foldTraceExcept = new Set.from(other._foldTraceExcept)
.union(new Set.from(_foldTraceExcept))
.toList();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think nested ifs would be clearer. Broken out, the differences between each condition get lost especially when some conditions duplicate logic in others.

///
/// The key `except` will correspond to the list of packages to fold.
/// The key `only` will correspond to the list of packages to keep in a
/// test [Chain].
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the map only has string keys, the type annotation should indicate that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

'Must be a list of strings.',
valueNode.span,
_source);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still needs to be done.

@grouma
Copy link
Member Author

grouma commented Jun 22, 2017

@nex3 I think I have addressed all open comments. This UI is kind of terrible though.

foldTraceOnly = other._foldTraceOnly.intersection(_foldTraceOnly);
}

var foldTraceExcept = other._foldTraceExcept ?? _foldTraceExcept;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point, I don't think it makes sense to set these by default since they'll always either be overridden or end up as null.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed offline. There is a case where we want to default.


_validate(
valueNode,
"Invalid package identifier",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"identifier" -> "name"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

}
_validate(
valueNode,
"Folded packages must be strings",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These messages need trailing periods.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

"Folded packages must be strings",
(valueList) =>
valueList is YamlList &&
!(valueList).any((value) => value is! String));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

valueList.every((value) => value is String)

Same below.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

(valueList) =>
valueList is YamlList &&
!(valueList).any((value) => value is! String));
(valueList).every((value) => value is String));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parentheses around valueList are unnecessary.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Originally was casting. Fixed.

@grouma grouma merged commit 960bbe6 into dart-lang:master Jun 23, 2017
@grouma grouma deleted the remote-mapping branch June 23, 2017 17:13
natebosch added a commit that referenced this pull request Sep 13, 2021
These constructors became identical in #650 so we can drop the private
copy altogether.
natebosch added a commit that referenced this pull request Sep 13, 2021
These constructors became identical in #650 so we can drop the private
copy altogether.
natebosch added a commit that referenced this pull request Sep 14, 2021
These constructors became identical in #650 so we can drop the private
copy altogether.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add the ability to customize which packages' frames are folded

3 participants