Fix and refactor NoMatchingInvocationError.toString() (#149)
* Fix NoMatchingInvocationError.toString()
`NoMatchingInvocation.toString()` attempted to avoid printing a comma
after the last argument, but the code was backwards, instead adding a
trailing comma and omitting the comma after the first argument.
* Refactor NoMatchingInvocationError.toString()
Break up `NoMatchingInvocationError.toString()` so that we can
generate human-readable string representations of `Invocation`s
elsewhere for debugging.
* Add test for `describeInvocation`, fix printing strings for named arguments
diff --git a/packages/file/lib/src/backends/record_replay/common.dart b/packages/file/lib/src/backends/record_replay/common.dart
index 00e9ac9..c494e50 100644
--- a/packages/file/lib/src/backends/record_replay/common.dart
+++ b/packages/file/lib/src/backends/record_replay/common.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'codecs.dart';
import 'events.dart';
/// Encoded value of the file system in a recording.
@@ -155,3 +156,29 @@
deeplyEqual(map1[key], map2[key]);
});
}
+
+/// Returns a human-readable representation of an [Invocation].
+String describeInvocation(Invocation invocation) {
+ StringBuffer buf = StringBuffer();
+ buf.write(getSymbolName(invocation.memberName));
+ if (invocation.isMethod) {
+ buf.write('(');
+ int i = 0;
+ for (dynamic arg in invocation.positionalArguments) {
+ if (i++ > 0) {
+ buf.write(', ');
+ }
+ buf.write(Error.safeToString(encode(arg)));
+ }
+ invocation.namedArguments.forEach((Symbol name, dynamic value) {
+ if (i++ > 0) {
+ buf.write(', ');
+ }
+ buf.write('${getSymbolName(name)}: ${Error.safeToString(encode(value))}');
+ });
+ buf.write(')');
+ } else if (invocation.isSetter) {
+ buf.write(Error.safeToString(encode(invocation.positionalArguments[0])));
+ }
+ return buf.toString();
+}
diff --git a/packages/file/lib/src/backends/record_replay/errors.dart b/packages/file/lib/src/backends/record_replay/errors.dart
index d5451f3..3d3fa12 100644
--- a/packages/file/lib/src/backends/record_replay/errors.dart
+++ b/packages/file/lib/src/backends/record_replay/errors.dart
@@ -2,7 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'codecs.dart';
import 'common.dart';
/// Error thrown during replay when there is no matching invocation in the
@@ -16,31 +15,8 @@
final Invocation invocation;
@override
- String toString() {
- StringBuffer buf = StringBuffer();
- buf.write('No matching invocation found: ');
- buf.write(getSymbolName(invocation.memberName));
- if (invocation.isMethod) {
- buf.write('(');
- int i = 0;
- for (dynamic arg in invocation.positionalArguments) {
- buf.write(Error.safeToString(encode(arg)));
- if (i++ > 0) {
- buf.write(', ');
- }
- }
- invocation.namedArguments.forEach((Symbol name, dynamic value) {
- if (i++ > 0) {
- buf.write(', ');
- }
- buf.write('${getSymbolName(name)}: ${encode(value)}');
- });
- buf.write(')');
- } else if (invocation.isSetter) {
- buf.write(Error.safeToString(encode(invocation.positionalArguments[0])));
- }
- return buf.toString();
- }
+ String toString() =>
+ 'No matching invocation found: ${describeInvocation(invocation)}';
}
/// Exception thrown during replay when an invocation recorded error, but we
diff --git a/packages/file/test/replay_test.dart b/packages/file/test/replay_test.dart
index acce6ce..e54f28d 100644
--- a/packages/file/test/replay_test.dart
+++ b/packages/file/test/replay_test.dart
@@ -7,6 +7,8 @@
import 'package:file/file.dart';
import 'package:file/memory.dart';
import 'package:file/record_replay.dart';
+import 'package:file/src/backends/record_replay/common.dart'
+ show describeInvocation;
import 'package:file_testing/file_testing.dart';
import 'package:path/path.dart' as path;
import 'package:test/test.dart';
@@ -202,6 +204,41 @@
});
});
});
+
+ group('describeInvocation', () {
+ test('noArguments', () {
+ expect(
+ describeInvocation(Invocation.method(#foo, [])),
+ 'foo()',
+ );
+ });
+
+ test('onlyPositionalArguments', () {
+ expect(
+ describeInvocation(Invocation.method(#foo, [1, 'bar', null])),
+ 'foo(1, "bar", null)',
+ );
+ });
+
+ test('onlyNamedArguments', () {
+ expect(
+ describeInvocation(
+ Invocation.method(#foo, [], {#x: 2, #y: 'baz', #z: null})),
+ 'foo(x: 2, y: "baz", z: null)',
+ );
+ });
+
+ test('positionalAndNamedArguments', () {
+ expect(
+ describeInvocation(Invocation.method(
+ #foo,
+ [1, 'bar', null],
+ {#x: 2, #y: 'baz', #z: null},
+ )),
+ 'foo(1, "bar", null, x: 2, y: "baz", z: null)',
+ );
+ });
+ });
}
/// Successfully matches against an instance of [Future].