Allow real method calls for unstubbed methods if they return void or Future<void>.
This requires a breaking change, changing Mock.noSuchMethod's optional second parameter to two optional named parameters. Any code which calls noSuchMethod with a second positional parameter, or which overrides Mock.noSuchMethod, will need to change.
Users have found the throw-if-unstubbed setting to be too constrained for setters, other methods that return void, and methods which return a (non-nullable) Future<void>. The method calls should be allowed, as stubbing is probably meaningless.
Fixes https://github.com/dart-lang/mockito/issues/305
PiperOrigin-RevId: 355438518
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2c26fc2..2735969 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,12 @@
* Migrate example code to null safety.
* **Breaking change:** Change the error which is thrown if a method is called
and no method stub was found, from NoSuchMethodError to MissingStubError.
+* **Breaking change**: `Mock.noSuchMethod`'s optional positional parameter,
+ "returnValue" is changed to a named parameter, and a second named parameter is
+ added. Any manual mocks which call `Mock.noSuchMethod` with a second
+ positional argument will need to instead use the named parameter.
+* Allow real calls to mock methods which return `void` (like setters) or
+ `Future<void>`, even if unstubbed.
## 5.0.0-nullsafety.5
diff --git a/lib/src/builder.dart b/lib/src/builder.dart
index 622b1bb..0342bbe 100644
--- a/lib/src/builder.dart
+++ b/lib/src/builder.dart
@@ -851,13 +851,23 @@
literalList(invocationPositionalArgs),
if (invocationNamedArgs.isNotEmpty) literalMap(invocationNamedArgs),
]);
- final noSuchMethodArgs = <Expression>[invocation];
- if (_returnTypeIsNonNullable(method)) {
- final dummyReturnValue = _dummyValue(method.returnType);
- noSuchMethodArgs.add(dummyReturnValue);
+
+ Expression returnValueForMissingStub;
+ if (method.returnType.isVoid) {
+ returnValueForMissingStub = refer('null');
+ } else if (method.returnType ==
+ typeProvider.futureType2(typeProvider.voidType)) {
+ returnValueForMissingStub = refer('Future').property('value').call([]);
}
+ final namedArgs = {
+ if (_returnTypeIsNonNullable(method))
+ 'returnValue': _dummyValue(method.returnType),
+ if (returnValueForMissingStub != null)
+ 'returnValueForMissingStub': returnValueForMissingStub,
+ };
+
var superNoSuchMethod =
- refer('super').property('noSuchMethod').call(noSuchMethodArgs);
+ refer('super').property('noSuchMethod').call([invocation], namedArgs);
if (!method.returnType.isVoid && !method.returnType.isDynamic) {
superNoSuchMethod =
superNoSuchMethod.asA(_typeReference(method.returnType));
@@ -1127,9 +1137,9 @@
final invocation = refer('Invocation').property('getter').call([
refer('#${getter.displayName}'),
]);
- final noSuchMethodArgs = [invocation, _dummyValue(getter.returnType)];
+ final namedArgs = {'returnValue': _dummyValue(getter.returnType)};
var superNoSuchMethod =
- refer('super').property('noSuchMethod').call(noSuchMethodArgs);
+ refer('super').property('noSuchMethod').call([invocation], namedArgs);
if (!getter.returnType.isVoid && !getter.returnType.isDynamic) {
superNoSuchMethod =
superNoSuchMethod.asA(_typeReference(getter.returnType));
@@ -1167,8 +1177,9 @@
refer('#${setter.displayName}'),
invocationPositionalArgs.single,
]);
- final returnNoSuchMethod =
- refer('super').property('noSuchMethod').call([invocation]);
+ final returnNoSuchMethod = refer('super')
+ .property('noSuchMethod')
+ .call([invocation], {'returnValueForMissingStub': refer('null')});
builder.body = returnNoSuchMethod.code;
}
diff --git a/lib/src/mock.dart b/lib/src/mock.dart
index 45ea812..1a4b3a3 100644
--- a/lib/src/mock.dart
+++ b/lib/src/mock.dart
@@ -113,6 +113,11 @@
_responses.add(cannedResponse);
}
+ /// A sentinal value used as the default argument for noSuchMethod's
+ /// 'returnValueForMissingStub' parameter.
+ @protected
+ static const deferToDefaultResponse = Object();
+
/// Handles method stubbing, method call verification, and real method calls.
///
/// If passed, [returnValue] will be returned during method stubbing and
@@ -121,7 +126,9 @@
/// return type.
@override
@visibleForTesting
- dynamic noSuchMethod(Invocation invocation, [Object? returnValue]) {
+ dynamic noSuchMethod(Invocation invocation,
+ {Object? returnValue,
+ Object? returnValueForMissingStub = deferToDefaultResponse}) {
// noSuchMethod is that 'magic' that allows us to ignore implementing fields
// and methods and instead define them later at compile-time per instance.
invocation = _useMatchedInvocationIfSet(invocation);
@@ -135,11 +142,18 @@
_untilCall = _UntilCall(this, invocation);
return returnValue;
} else {
+ _ReturnsCannedResponse defaultResponse;
+ if (returnValueForMissingStub == deferToDefaultResponse) {
+ defaultResponse = _defaultResponse;
+ } else {
+ defaultResponse = () =>
+ CallPair<Object?>.allInvocations((_) => returnValueForMissingStub);
+ }
_realCalls.add(RealCall(this, invocation));
_invocationStreamController.add(invocation);
var cannedResponse = _responses.lastWhere(
(cr) => cr.call.matches(invocation, {}),
- orElse: _defaultResponse);
+ orElse: defaultResponse);
var response = cannedResponse.response(invocation);
return response;
}
diff --git a/test/builder/auto_mocks_test.dart b/test/builder/auto_mocks_test.dart
index a29f1aa..7252a42 100644
--- a/test/builder/auto_mocks_test.dart
+++ b/test/builder/auto_mocks_test.dart
@@ -202,8 +202,8 @@
void m(int a) {}
}
'''),
- _containsAllOf('void m(int? a) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a]));'),
+ _containsAllOf(
+ 'void m(int? a) => super.noSuchMethod(Invocation.method(#m, [a])'),
);
});
@@ -215,7 +215,7 @@
}
'''),
_containsAllOf('void m(int? a, [int? b, int? c = 0]) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a, b, c]));'),
+ 'super.noSuchMethod(Invocation.method(#m, [a, b, c])'),
);
});
@@ -227,7 +227,7 @@
}
'''),
_containsAllOf('void m(int? a, {int? b, int? c = 0}) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a], {#b: b, #c: c}));'),
+ 'super.noSuchMethod(Invocation.method(#m, [a], {#b: b, #c: c})'),
);
});
@@ -239,7 +239,7 @@
}
'''),
_containsAllOf('void m([int? a, int? b = 0]) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a, b]));'),
+ 'super.noSuchMethod(Invocation.method(#m, [a, b])'),
);
});
@@ -251,7 +251,7 @@
}
'''),
_containsAllOf('void m([bool? a = true, bool? b = false]) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a, b]));'),
+ 'super.noSuchMethod(Invocation.method(#m, [a, b])'),
);
});
@@ -263,7 +263,7 @@
}
'''),
_containsAllOf('void m([int? a = 0, double? b = 0.5]) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a, b]));'),
+ 'super.noSuchMethod(Invocation.method(#m, [a, b])'),
);
});
@@ -276,7 +276,7 @@
'''),
_containsAllOf(
"void m([String? a = r'Hello', String? b = r'Hello World']) =>",
- 'super.noSuchMethod(Invocation.method(#m, [a, b]));'),
+ 'super.noSuchMethod(Invocation.method(#m, [a, b])'),
);
});
@@ -289,7 +289,7 @@
'''),
_containsAllOf(
'void m([List<int>? a = const [], Map<int, int>? b = const {}]) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a, b]));'),
+ 'super.noSuchMethod(Invocation.method(#m, [a, b])'),
);
});
@@ -301,7 +301,7 @@
}
'''),
_containsAllOf('void m([List<int>? a = const [1, 2, 3]]) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a]));'),
+ 'super.noSuchMethod(Invocation.method(#m, [a])'),
);
});
@@ -314,7 +314,7 @@
'''),
_containsAllOf(
"void m([Map<int, String>? a = const {1: r'a', 2: r'b'}]) =>",
- 'super.noSuchMethod(Invocation.method(#m, [a]));'),
+ 'super.noSuchMethod(Invocation.method(#m, [a])'),
);
});
@@ -327,7 +327,7 @@
'''),
_containsAllOf(
"void m([Map<int, String>? a = const {1: r'a', 2: r'b'}]) =>",
- 'super.noSuchMethod(Invocation.method(#m, [a]));'),
+ 'super.noSuchMethod(Invocation.method(#m, [a])'),
);
});
@@ -343,7 +343,7 @@
}
'''),
_containsAllOf('void m([_i2.Bar? a = const _i2.Bar()]) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a]));'),
+ 'super.noSuchMethod(Invocation.method(#m, [a])'),
);
});
@@ -356,7 +356,7 @@
}
'''),
_containsAllOf('void m([Duration? a = const Duration(days: 1)]) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a]));'),
+ 'super.noSuchMethod(Invocation.method(#m, [a])'),
);
});
@@ -372,7 +372,7 @@
}
'''),
_containsAllOf('void m([_i2.Bar? a = const _i2.Bar.named()]) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a]));'),
+ 'super.noSuchMethod(Invocation.method(#m, [a])'),
);
});
@@ -389,7 +389,7 @@
}
'''),
_containsAllOf('void m([_i2.Bar? a = const _i2.Bar(7)]) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a]));'),
+ 'super.noSuchMethod(Invocation.method(#m, [a])'),
);
});
@@ -406,7 +406,7 @@
}
'''),
_containsAllOf('void m([_i2.Bar? a = const _i2.Bar(i: 7)]) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a]));'),
+ 'super.noSuchMethod(Invocation.method(#m, [a])'),
);
});
@@ -419,8 +419,8 @@
}
const x = 1;
'''),
- _containsAllOf('void m([int? a = 1]) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a]));'),
+ _containsAllOf(
+ 'void m([int? a = 1]) => super.noSuchMethod(Invocation.method(#m, [a])'),
);
});
@@ -435,7 +435,7 @@
}
'''),
_containsAllOf('void m([_i2.Callback? a = _i2.defaultCallback]) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a]));'),
+ 'super.noSuchMethod(Invocation.method(#m, [a])'),
);
});
@@ -448,8 +448,8 @@
void m([int a = x]) {}
}
'''),
- _containsAllOf('void m([int? a = 1]) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a]));'),
+ _containsAllOf(
+ 'void m([int? a = 1]) => super.noSuchMethod(Invocation.method(#m, [a])'),
);
});
@@ -522,8 +522,11 @@
Future<void> m() async => print(s);
}
'''),
- _containsAllOf('_i3.Future<void> m() =>',
- '(super.noSuchMethod(Invocation.method(#m, []), Future.value(null))'),
+ _containsAllOf(dedent2('''
+ _i3.Future<void> m() => (super.noSuchMethod(Invocation.method(#m, []),
+ returnValue: Future.value(null),
+ returnValueForMissingStub: Future.value()) as _i3.Future<void>);
+ ''')),
);
});
@@ -534,8 +537,10 @@
Stream<int> m() async* { yield 7; }
}
'''),
- _containsAllOf('_i3.Stream<int> m() =>',
- '(super.noSuchMethod(Invocation.method(#m, []), Stream<int>.empty())'),
+ _containsAllOf(dedent2('''
+ _i3.Stream<int> m() => (super.noSuchMethod(Invocation.method(#m, []),
+ returnValue: Stream<int>.empty()) as _i3.Stream<int>);
+ ''')),
);
});
@@ -546,8 +551,11 @@
Iterable<int> m() sync* { yield 7; }
}
'''),
- _containsAllOf('Iterable<int> m() =>',
- '(super.noSuchMethod(Invocation.method(#m, []), [])'),
+ _containsAllOf(dedent2('''
+ Iterable<int> m() =>
+ (super.noSuchMethod(Invocation.method(#m, []), returnValue: [])
+ as Iterable<int>);
+ ''')),
);
});
@@ -559,8 +567,8 @@
}
class Foo extends FooBase {}
'''),
- _containsAllOf('void m(int? a) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a]));'),
+ _containsAllOf(
+ 'void m(int? a) => super.noSuchMethod(Invocation.method(#m, [a])'),
);
});
@@ -573,8 +581,8 @@
}
class Foo extends FooBase<int> {}
'''),
- _containsAllOf('void m(int? a) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a]));'),
+ _containsAllOf(
+ 'void m(int? a) => super.noSuchMethod(Invocation.method(#m, [a])'),
);
});
@@ -586,8 +594,8 @@
}
class Foo with Mixin<int> {}
'''),
- _containsAllOf('void m(int? a) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a]));'),
+ _containsAllOf(
+ 'void m(int? a) => super.noSuchMethod(Invocation.method(#m, [a])'),
);
});
@@ -602,8 +610,8 @@
class FooBase1<T> extends FooBase2<T> {}
class Foo extends FooBase2<int> {}
'''),
- _containsAllOf('void m(int? a) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a]));'),
+ _containsAllOf(
+ 'void m(int? a) =>', 'super.noSuchMethod(Invocation.method(#m, [a])'),
);
});
@@ -627,7 +635,7 @@
class Foo<T> extends FooBase<T> {}
'''),
_containsAllOf(
- 'void m(T? a) =>', 'super.noSuchMethod(Invocation.method(#m, [a]));'),
+ 'void m(T? a) =>', 'super.noSuchMethod(Invocation.method(#m, [a])'),
);
});
@@ -767,8 +775,7 @@
}
'''),
_containsAllOf(
- 'void m(dynamic a, int? b) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a, b]));',
+ 'void m(dynamic a, int? b) => super.noSuchMethod(Invocation.method(#m, [a, b])',
),
);
});
@@ -781,7 +788,7 @@
}
'''),
_containsAllOf(
- 'void m<T>(T? a) => super.noSuchMethod(Invocation.method(#m, [a]));',
+ 'void m<T>(T? a) => super.noSuchMethod(Invocation.method(#m, [a])',
),
);
});
@@ -1024,7 +1031,7 @@
}
'''),
_containsAllOf('void m(_i2.Foo Function()? a) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a]));'),
+ 'super.noSuchMethod(Invocation.method(#m, [a])'),
);
});
@@ -1037,7 +1044,7 @@
}
'''),
_containsAllOf('void m(void Function(_i2.Foo)? a) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a]));'),
+ 'super.noSuchMethod(Invocation.method(#m, [a])'),
);
});
@@ -1050,7 +1057,7 @@
}
'''),
_containsAllOf('void m(_i2.Foo Function()? a) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a]));'),
+ 'super.noSuchMethod(Invocation.method(#m, [a])'),
);
});
@@ -1062,7 +1069,7 @@
}
'''),
_containsAllOf(
- 'void m(int? a, int? b) => super.noSuchMethod(Invocation.method(#m, [a, b]));'),
+ 'void m(int? a, int? b) => super.noSuchMethod(Invocation.method(#m, [a, b])'),
);
});
@@ -1076,7 +1083,7 @@
}
'''),
_containsAllOf(
- 'void m(int? a, T? b) => super.noSuchMethod(Invocation.method(#m, [a, b]));'),
+ 'void m(int? a, T? b) => super.noSuchMethod(Invocation.method(#m, [a, b])'),
);
});
@@ -1087,8 +1094,7 @@
void m(List<int?> a, List<int> b);
}
'''),
- _containsAllOf('void m(List<int?>? a, List<int>? b) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a, b]));'),
+ _containsAllOf('void m(List<int?>? a, List<int>? b) =>'),
);
});
@@ -1101,8 +1107,7 @@
void m(int? Function() a, int Function() b);
}
'''),
- _containsAllOf('void m(int? Function()? a, int Function()? b) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a, b]));'),
+ _containsAllOf('void m(int? Function()? a, int Function()? b) =>'),
);
});
@@ -1115,8 +1120,8 @@
void m(void Function(int?) a, void Function(int) b);
}
'''),
- _containsAllOf('void m(void Function(int?)? a, void Function(int)? b) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a, b]));'),
+ _containsAllOf(
+ 'void m(void Function(int?)? a, void Function(int)? b) =>'),
);
});
@@ -1128,8 +1133,7 @@
void m(int? a(), int b());
}
'''),
- _containsAllOf('void m(int? Function()? a, int Function()? b) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a, b]));'),
+ _containsAllOf('void m(int? Function()? a, int Function()? b) =>'),
);
});
@@ -1142,8 +1146,8 @@
void m(void a(int? x), void b(int x));
}
'''),
- _containsAllOf('void m(void Function(int?)? a, void Function(int)? b) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a, b]));'),
+ _containsAllOf(
+ 'void m(void Function(int?)? a, void Function(int)? b) =>'),
);
});
@@ -1154,8 +1158,7 @@
void m<T>(T? a, T b);
}
'''),
- _containsAllOf(
- 'void m<T>(T? a, T? b) => super.noSuchMethod(Invocation.method(#m, [a, b]));'),
+ _containsAllOf('void m<T>(T? a, T? b) =>'),
);
});
@@ -1166,8 +1169,7 @@
void m(dynamic a, int b);
}
'''),
- _containsAllOf('void m(dynamic a, int? b) =>',
- 'super.noSuchMethod(Invocation.method(#m, [a, b]));'),
+ _containsAllOf('void m(dynamic a, int? b) =>'),
);
});
@@ -1178,8 +1180,7 @@
int m(int a);
}
'''),
- _containsAllOf(
- 'int m(int? a) => (super.noSuchMethod(Invocation.method(#m, [a]), 0)'),
+ _containsAllOf('int m(int? a) =>'),
);
});
@@ -1190,8 +1191,7 @@
int? m(int a);
}
'''),
- _containsAllOf(
- 'int? m(int? a) => (super.noSuchMethod(Invocation.method(#m, [a]))'),
+ _containsAllOf('int? m(int? a) =>'),
);
});
@@ -1202,8 +1202,7 @@
List<int?> m(int a);
}
'''),
- _containsAllOf('List<int?> m(int? a) =>',
- '(super.noSuchMethod(Invocation.method(#m, [a]), <int?>[])'),
+ _containsAllOf('List<int?> m(int? a) =>'),
);
});
@@ -1214,8 +1213,7 @@
T? m<T>(int a);
}
'''),
- _containsAllOf(
- 'T? m<T>(int? a) => (super.noSuchMethod(Invocation.method(#m, [a]))'),
+ _containsAllOf('T? m<T>(int? a) =>'),
);
});
@@ -1358,8 +1356,10 @@
int m();
}
'''),
- _containsAllOf(
- 'int m() => (super.noSuchMethod(Invocation.method(#m, []), 0)'),
+ _containsAllOf(dedent2('''
+ int m() =>
+ (super.noSuchMethod(Invocation.method(#m, []), returnValue: 0) as int);
+ ''')),
);
});
@@ -1376,7 +1376,7 @@
},
outputs: {
'foo|test/foo_test.mocks.dart': _containsAllOf(
- 'void m(T? a) => super.noSuchMethod(Invocation.method(#m, [a]));'),
+ 'void m(T? a) => super.noSuchMethod(Invocation.method(#m, [a])'),
},
);
});
@@ -1399,8 +1399,10 @@
int get m => 7;
}
'''),
- _containsAllOf(
- 'int get m => (super.noSuchMethod(Invocation.getter(#m), 0)'),
+ _containsAllOf(dedent2('''
+ int get m =>
+ (super.noSuchMethod(Invocation.getter(#m), returnValue: 0) as int);
+ ''')),
);
});
@@ -1421,21 +1423,25 @@
}
class Foo extends FooBase {}
'''),
- _containsAllOf(
- 'int get m => (super.noSuchMethod(Invocation.getter(#m), 0)'),
+ _containsAllOf(dedent2('''
+ int get m =>
+ (super.noSuchMethod(Invocation.getter(#m), returnValue: 0) as int);
+ ''')),
);
});
test('overrides non-nullable instance setters', () async {
- var mocksContent = await buildWithSingleNonNullableSource(dedent(r'''
+ await expectSingleNonNullableOutput(
+ dedent('''
class Foo {
void set m(int a) {}
}
- '''));
- expect(
- mocksContent,
- contains('set m(int? a) => '
- 'super.noSuchMethod(Invocation.setter(#m, a));'));
+ '''),
+ _containsAllOf(dedent2('''
+ set m(int? a) => super
+ .noSuchMethod(Invocation.setter(#m, a), returnValueForMissingStub: null);
+ ''')),
+ );
});
test('does not override nullable instance setters', () async {
@@ -1448,16 +1454,18 @@
});
test('overrides inherited non-nullable instance setters', () async {
- var mocksContent = await buildWithSingleNonNullableSource(dedent(r'''
+ await expectSingleNonNullableOutput(
+ dedent('''
class FooBase {
void set m(int a) {}
}
class Foo extends FooBase {}
- '''));
- expect(
- mocksContent,
- contains('set m(int? a) => '
- 'super.noSuchMethod(Invocation.setter(#m, a));'));
+ '''),
+ _containsAllOf(dedent2('''
+ set m(int? a) => super
+ .noSuchMethod(Invocation.setter(#m, a), returnValueForMissingStub: null);
+ ''')),
+ );
});
test('overrides non-nullable fields', () async {
@@ -1467,9 +1475,13 @@
int m;
}
'''),
- _containsAllOf(
- 'int get m => (super.noSuchMethod(Invocation.getter(#m), 0)',
- 'set m(int? _m) => super.noSuchMethod(Invocation.setter(#m, _m));'),
+ _containsAllOf(dedent2('''
+ int get m =>
+ (super.noSuchMethod(Invocation.getter(#m), returnValue: 0) as int);
+ '''), dedent2('''
+ set m(int? _m) => super
+ .noSuchMethod(Invocation.setter(#m, _m), returnValueForMissingStub: null);
+ ''')),
);
});
@@ -1481,9 +1493,13 @@
}
class Foo extends FooBase {}
'''),
- _containsAllOf(
- 'int get m => (super.noSuchMethod(Invocation.getter(#m), 0)',
- 'set m(int? _m) => super.noSuchMethod(Invocation.setter(#m, _m));'),
+ _containsAllOf(dedent2('''
+ int get m =>
+ (super.noSuchMethod(Invocation.getter(#m), returnValue: 0) as int);
+ '''), dedent2('''
+ set m(int? _m) => super
+ .noSuchMethod(Invocation.setter(#m, _m), returnValueForMissingStub: null);
+ ''')),
);
});
@@ -1495,8 +1511,10 @@
Foo(this.m);
}
'''),
- _containsAllOf(
- 'int get m => (super.noSuchMethod(Invocation.getter(#m), 0)'),
+ _containsAllOf(dedent2('''
+ int get m =>
+ (super.noSuchMethod(Invocation.getter(#m), returnValue: 0) as int);
+ ''')),
);
});
@@ -1534,8 +1552,11 @@
int operator +(Foo other) => 7;
}
'''),
- _containsAllOf('int operator +(_i2.Foo? other) =>',
- '(super.noSuchMethod(Invocation.method(#+, [other]), 0)'),
+ _containsAllOf(dedent2('''
+ int operator +(_i2.Foo? other) =>
+ (super.noSuchMethod(Invocation.method(#+, [other]), returnValue: 0)
+ as int);
+ ''')),
);
});
@@ -1546,8 +1567,10 @@
int operator [](int x) => 7;
}
'''),
- _containsAllOf('int operator [](int? x) =>',
- '(super.noSuchMethod(Invocation.method(#[], [x]), 0)'),
+ _containsAllOf(dedent2('''
+ int operator [](int? x) =>
+ (super.noSuchMethod(Invocation.method(#[], [x]), returnValue: 0) as int);
+ ''')),
);
});
@@ -1558,8 +1581,10 @@
int operator ~() => 7;
}
'''),
- _containsAllOf(
- 'int operator ~() => (super.noSuchMethod(Invocation.method(#~, []), 0)'),
+ _containsAllOf(dedent2('''
+ int operator ~() =>
+ (super.noSuchMethod(Invocation.method(#~, []), returnValue: 0) as int);
+ ''')),
);
});
@@ -1570,8 +1595,10 @@
bool m() => false;
}
'''),
- _containsAllOf(
- 'bool m() => (super.noSuchMethod(Invocation.method(#m, []), false)'),
+ _containsAllOf(dedent2('''
+ bool m() => (super.noSuchMethod(Invocation.method(#m, []), returnValue: false)
+ as bool);
+ ''')),
);
});
@@ -1582,8 +1609,10 @@
double m() => 3.14;
}
'''),
- _containsAllOf(
- 'double m() => (super.noSuchMethod(Invocation.method(#m, []), 0.0)'),
+ _containsAllOf(dedent2('''
+ double m() => (super.noSuchMethod(Invocation.method(#m, []), returnValue: 0.0)
+ as double);
+ ''')),
);
});
@@ -1594,8 +1623,10 @@
int m() => 7;
}
'''),
- _containsAllOf(
- 'int m() => (super.noSuchMethod(Invocation.method(#m, []), 0)'),
+ _containsAllOf(dedent2('''
+ int m() =>
+ (super.noSuchMethod(Invocation.method(#m, []), returnValue: 0) as int);
+ ''')),
);
});
@@ -1606,8 +1637,10 @@
String m() => "Hello";
}
'''),
- _containsAllOf(
- "String m() => (super.noSuchMethod(Invocation.method(#m, []), '')"),
+ _containsAllOf(dedent2('''
+ String m() => (super.noSuchMethod(Invocation.method(#m, []), returnValue: '')
+ as String);
+ ''')),
);
});
@@ -1618,8 +1651,11 @@
List<Foo> m() => [Foo()];
}
'''),
- _containsAllOf('List<_i2.Foo> m() =>',
- '(super.noSuchMethod(Invocation.method(#m, []), <_i2.Foo>[])'),
+ _containsAllOf(dedent2('''
+ List<_i2.Foo> m() =>
+ (super.noSuchMethod(Invocation.method(#m, []), returnValue: <_i2.Foo>[])
+ as List<_i2.Foo>);
+ ''')),
);
});
@@ -1630,8 +1666,11 @@
Set<Foo> m() => {Foo()};
}
'''),
- _containsAllOf('Set<_i2.Foo> m() =>',
- '(super.noSuchMethod(Invocation.method(#m, []), <_i2.Foo>{})'),
+ _containsAllOf(dedent2('''
+ Set<_i2.Foo> m() =>
+ (super.noSuchMethod(Invocation.method(#m, []), returnValue: <_i2.Foo>{})
+ as Set<_i2.Foo>);
+ ''')),
);
});
@@ -1642,8 +1681,10 @@
Map<int, Foo> m() => {7: Foo()};
}
'''),
- _containsAllOf('Map<int, _i2.Foo> m() =>',
- '(super.noSuchMethod(Invocation.method(#m, []), <int, _i2.Foo>{})'),
+ _containsAllOf(dedent2('''
+ Map<int, _i2.Foo> m() => (super.noSuchMethod(Invocation.method(#m, []),
+ returnValue: <int, _i2.Foo>{}) as Map<int, _i2.Foo>);
+ ''')),
);
});
@@ -1654,8 +1695,10 @@
Map m();
}
'''),
- _containsAllOf('Map<dynamic, dynamic> m() =>',
- '(super.noSuchMethod(Invocation.method(#m, []), <dynamic, dynamic>{})'),
+ _containsAllOf(dedent2('''
+ Map<dynamic, dynamic> m() => (super.noSuchMethod(Invocation.method(#m, []),
+ returnValue: <dynamic, dynamic>{}) as Map<dynamic, dynamic>);
+ ''')),
);
});
@@ -1667,8 +1710,10 @@
Future<bool> m() async => false;
}
'''),
- _containsAllOf('_i3.Future<bool> m() =>',
- '(super.noSuchMethod(Invocation.method(#m, []), Future.value(false))'),
+ _containsAllOf(dedent2('''
+ _i3.Future<bool> m() => (super.noSuchMethod(Invocation.method(#m, []),
+ returnValue: Future.value(false)) as _i3.Future<bool>);
+ ''')),
);
});
@@ -1679,8 +1724,10 @@
Stream<int> m();
}
'''),
- _containsAllOf('Stream<int> m() =>',
- '(super.noSuchMethod(Invocation.method(#m, []), Stream<int>.empty())'),
+ _containsAllOf(dedent2('''
+ _i3.Stream<int> m() => (super.noSuchMethod(Invocation.method(#m, []),
+ returnValue: Stream<int>.empty()) as _i3.Stream<int>);
+ ''')),
);
});
@@ -1695,8 +1742,11 @@
Bar(this.name);
}
'''),
- _containsAllOf('_i2.Bar m() =>',
- '(super.noSuchMethod(Invocation.method(#m, []), _FakeBar())'),
+ _containsAllOf(dedent2('''
+ _i2.Bar m() =>
+ (super.noSuchMethod(Invocation.method(#m, []), returnValue: _FakeBar())
+ as _i2.Bar);
+ ''')),
);
});
@@ -1708,8 +1758,10 @@
}
class Bar<T> {}
'''),
- _containsAllOf('Bar<int> m() =>',
- 'super.noSuchMethod(Invocation.method(#m, []), _FakeBar<int>())'),
+ _containsAllOf(dedent2('''
+ _i2.Bar<int> m() => (super.noSuchMethod(Invocation.method(#m, []),
+ returnValue: _FakeBar<int>()) as _i2.Bar<int>);
+ ''')),
);
});
@@ -1724,8 +1776,11 @@
two,
}
'''),
- _containsAllOf('_i2.Bar m1() =>',
- '(super.noSuchMethod(Invocation.method(#m1, []), _i2.Bar.one)'),
+ _containsAllOf(dedent2('''
+ _i2.Bar m1() =>
+ (super.noSuchMethod(Invocation.method(#m1, []), returnValue: _i2.Bar.one)
+ as _i2.Bar);
+ ''')),
);
});
@@ -1738,8 +1793,12 @@
void Function(int, [String]) m() => (int i, [String s]) {};
}
'''),
- _containsAllOf('void Function(int, [String]) m() => (super',
- '.noSuchMethod(Invocation.method(#m, []), (int __p0, [String __p1]) {})'),
+ _containsAllOf(dedent2('''
+ void Function(int, [String]) m() => (super.noSuchMethod(
+ Invocation.method(#m, []),
+ returnValue: (int __p0, [String __p1]) {})
+ as void Function(int, [String]));
+ ''')),
);
});
@@ -1752,8 +1811,12 @@
void Function(Foo, {bool b}) m() => (Foo f, {bool b}) {};
}
'''),
- _containsAllOf('void Function(_i2.Foo, {bool b}) m() => (super',
- '.noSuchMethod(Invocation.method(#m, []), (_i2.Foo __p0, {bool b}) {})'),
+ _containsAllOf(dedent2('''
+ void Function(_i2.Foo, {bool b}) m() =>
+ (super.noSuchMethod(Invocation.method(#m, []),
+ returnValue: (_i2.Foo __p0, {bool b}) {})
+ as void Function(_i2.Foo, {bool b}));
+ ''')),
);
});
@@ -1766,8 +1829,9 @@
Foo Function() m() => () => Foo();
}
'''),
- _containsAllOf('_i2.Foo Function() m() =>',
- 'super.noSuchMethod(Invocation.method(#m, []), () => _FakeFoo())'),
+ _containsAllOf(
+ '_i2.Foo Function() m() => (super.noSuchMethod(Invocation.method(#m, []),\n'
+ ' returnValue: () => _FakeFoo()) as _i2.Foo Function());'),
);
});
@@ -1781,8 +1845,10 @@
'''),
// TODO(srawlins): This output is invalid: `T __p0` is out of the scope
// where T is defined.
- _containsAllOf('T? Function<T>(T) m() =>',
- 'super.noSuchMethod(Invocation.method(#m, []), (T __p0) => null)'),
+ _containsAllOf(dedent2('''
+ T? Function<T>(T) m() => (super.noSuchMethod(Invocation.method(#m, []),
+ returnValue: (T __p0) => null) as T? Function<T>(T));
+ ''')),
);
});
@@ -2340,3 +2406,12 @@
return input.splitMapJoin('\n',
onNonMatch: (s) => s.replaceFirst(RegExp('^$indent'), ''));
}
+
+/// Dedent [input], so that each line is shifted to the left, so that the first
+/// line is at column 2 (starting position for a class member).
+String dedent2(String input) {
+ final indentMatch = RegExp(r'^ (\s*)').firstMatch(input);
+ final indent = ''.padRight(indentMatch.group(1).length);
+ return input.replaceFirst(RegExp(r'\s*$'), '').splitMapJoin('\n',
+ onNonMatch: (s) => s.replaceFirst(RegExp('^$indent'), ''));
+}
diff --git a/test/end2end/foo.dart b/test/end2end/foo.dart
index 9e6d08f..8dcf99d 100644
--- a/test/end2end/foo.dart
+++ b/test/end2end/foo.dart
@@ -7,6 +7,8 @@
String? nullableMethod(int x) => 'Real';
String? get nullableGetter => 'Real';
String methodWithBarArg(Bar bar) => 'result';
+ set setter(int value) {}
+ Future<void> returnsFutureVoid() => Future.value();
}
class FooSub extends Foo<int> {}
diff --git a/test/end2end/generated_mocks_test.dart b/test/end2end/generated_mocks_test.dart
index c74c31e..716806a 100644
--- a/test/end2end/generated_mocks_test.dart
+++ b/test/end2end/generated_mocks_test.dart
@@ -56,6 +56,15 @@
expect(fooSub.positionalParameter(42), equals('Stubbed'));
});
+ test('a setter can be called without stubbing', () {
+ expect(() => foo.setter = 7, returnsNormally);
+ });
+
+ test('a method which returns Future<void> can be called without stubbing',
+ () {
+ expect(() => foo.returnsFutureVoid(), returnsNormally);
+ });
+
test(
'a method with a non-nullable positional parameter accepts an argument '
'matcher while stubbing', () {
diff --git a/test/manual_mocks_test.dart b/test/manual_mocks_test.dart
index 5d145bb..87e6855 100644
--- a/test/manual_mocks_test.dart
+++ b/test/manual_mocks_test.dart
@@ -54,7 +54,8 @@
@override
int nonNullableReturn(int? x) =>
- super.noSuchMethod(Invocation.method(#nonNullableReturn, [x]), 1) as int;
+ super.noSuchMethod(Invocation.method(#nonNullableReturn, [x]),
+ returnValue: 1) as int;
// A generic return type is very tricky to work with in a manually mocked
// method. What value can be passed as the second argument to
@@ -63,16 +64,17 @@
// is optional, so that the override is still legal.
@override
T nonNullableReturn2<T>(T? x, {T? sentinal}) =>
- super.noSuchMethod(Invocation.method(#nonNullableReturn2, [x]), sentinal!)
- as T;
+ super.noSuchMethod(Invocation.method(#nonNullableReturn2, [x]),
+ returnValue: sentinal!) as T;
@override
- Future<int> nonNullableFutureReturn(int? x) => super.noSuchMethod(
- Invocation.method(#nonNullableFutureReturn, [x]), Future.value(1))
- as Future<int>;
+ Future<int> nonNullableFutureReturn(int? x) =>
+ super.noSuchMethod(Invocation.method(#nonNullableFutureReturn, [x]),
+ returnValue: Future.value(1)) as Future<int>;
@override
- int get getter => super.noSuchMethod(Invocation.getter(#getter), 1) as int;
+ int get getter =>
+ super.noSuchMethod(Invocation.getter(#getter), returnValue: 1) as int;
}
void main() {
diff --git a/test/nnbd_support_test.dart b/test/nnbd_support_test.dart
index 9e31129..dc0724a 100644
--- a/test/nnbd_support_test.dart
+++ b/test/nnbd_support_test.dart
@@ -26,8 +26,8 @@
class MockFoo extends Mock implements Foo {
@override
String returnsNonNullableString() {
- return super.noSuchMethod(
- Invocation.method(#returnsNonNullableString, []), 'Dummy') as String;
+ return super.noSuchMethod(Invocation.method(#returnsNonNullableString, []),
+ returnValue: 'Dummy') as String;
}
}