Generate method overrides even then source lib is not null-safe
If the class to mock comes from a null-safe library. Otherwise
we don't get nice mocks (as niceness depends on overrides).
We need to be careful to generate a valid pre-null-safety code,
but so far I only found we need to skip generating `required`.
PiperOrigin-RevId: 480854047
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2fb4151..9b5e020 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 5.3.3
+
+* Fix nice mocks generation in mixed mode (generated code is pre null-safety,
+ while mocked class is null-safe).
+
## 5.3.2
* Support analyzer 5.0.0.
diff --git a/lib/src/builder.dart b/lib/src/builder.dart
index a928482..29803bb 100644
--- a/lib/src/builder.dart
+++ b/lib/src/builder.dart
@@ -1149,7 +1149,14 @@
return ExecutableMember.from2(member, substitution);
});
- if (sourceLibIsNonNullable) {
+ // The test can be pre-null-safety but if the class
+ // we want to mock is defined in a null safe library,
+ // we still need to override methods to get nice mocks.
+ final isNiceMockOfNullSafeClass = mockTarget.onMissingStub ==
+ OnMissingStub.returnDefault &&
+ typeToMock.element2.enclosingElement.library.isNonNullableByDefault;
+
+ if (sourceLibIsNonNullable || isNiceMockOfNullSafeClass) {
cBuilder.methods.addAll(
fieldOverrides(members.whereType<PropertyAccessorElement>()));
cBuilder.methods
@@ -1193,12 +1200,23 @@
if (accessor.isGetter && typeSystem._returnTypeIsNonNullable(accessor)) {
yield Method((mBuilder) => _buildOverridingGetter(mBuilder, accessor));
}
- if (accessor.isSetter) {
+ if (accessor.isSetter && sourceLibIsNonNullable) {
yield Method((mBuilder) => _buildOverridingSetter(mBuilder, accessor));
}
}
}
+ bool _methodNeedsOverride(MethodElement method) {
+ if (!sourceLibIsNonNullable) {
+ // If we get here, we are adding overrides only to make
+ // nice mocks work. We only care about return types then.
+ return typeSystem._returnTypeIsNonNullable(method);
+ }
+ return typeSystem._returnTypeIsNonNullable(method) ||
+ typeSystem._hasNonNullableParameter(method) ||
+ _needsOverrideForVoidStub(method);
+ }
+
/// Yields all of the method overrides required for [methods].
///
/// This includes methods of supertypes and mixed in types.
@@ -1225,9 +1243,7 @@
// narrow the return type.
continue;
}
- if (typeSystem._returnTypeIsNonNullable(method) ||
- typeSystem._hasNonNullableParameter(method) ||
- _needsOverrideForVoidStub(method)) {
+ if (_methodNeedsOverride(method)) {
_checkForConflictWithCore(method.name);
yield Method((mBuilder) => _buildOverridingMethod(mBuilder, method));
}
@@ -1608,7 +1624,9 @@
_typeReference(superParameterType, forceNullable: forceNullable);
}
if (parameter.isNamed) pBuilder.named = true;
- if (parameter.isRequiredNamed) pBuilder.required = true;
+ if (parameter.isRequiredNamed && sourceLibIsNonNullable) {
+ pBuilder.required = true;
+ }
if (parameter.defaultValueCode != null) {
try {
pBuilder.defaultTo = _expressionFromDartObject(
diff --git a/lib/src/version.dart b/lib/src/version.dart
index cc93276..7747aca 100644
--- a/lib/src/version.dart
+++ b/lib/src/version.dart
@@ -1 +1 @@
-const packageVersion = '5.3.2';
+const packageVersion = '5.3.3';
diff --git a/pubspec.yaml b/pubspec.yaml
index 75bfb6c..268c0ed 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
name: mockito
-version: 5.3.2
+version: 5.3.3
description: >-
A mock framework inspired by Mockito with APIs for Fakes, Mocks,
behavior verification, and stubbing.
diff --git a/test/builder/custom_mocks_test.dart b/test/builder/custom_mocks_test.dart
index 4f17585..daae016 100644
--- a/test/builder/custom_mocks_test.dart
+++ b/test/builder/custom_mocks_test.dart
@@ -651,6 +651,34 @@
test(
'generates mock methods with non-nullable return types, specifying '
+ 'legal default values for basic known types, in mixed mode', () async {
+ var mocksContent = await buildWithNonNullable({
+ ...annotationsAsset,
+ 'foo|lib/foo.dart': dedent(r'''
+ abstract class Foo {
+ int m({required int x, double? y});
+ }
+ '''),
+ 'foo|test/foo_test.dart': '''
+ // @dart=2.9
+ import 'package:foo/foo.dart';
+ import 'package:mockito/annotations.dart';
+
+ @GenerateMocks(
+ [],
+ customMocks: [
+ MockSpec<Foo>(onMissingStub: OnMissingStub.returnDefault),
+ ],
+ )
+ void main() {}
+ '''
+ });
+ expect(mocksContent, contains('returnValue: 0,'));
+ expect(mocksContent, contains('returnValueForMissingStub: 0,'));
+ });
+
+ test(
+ 'generates mock methods with non-nullable return types, specifying '
'legal default values for unknown types', () async {
var mocksContent = await buildWithNonNullable({
...annotationsAsset,