MockBuilder: catch when users try to mock an un-subtypable class.
The Dart language forbids mocking these classes, so any test would fail to run.
PiperOrigin-RevId: 315566299
diff --git a/lib/src/builder.dart b/lib/src/builder.dart
index 96465ef..b935030 100644
--- a/lib/src/builder.dart
+++ b/lib/src/builder.dart
@@ -130,8 +130,12 @@
'The "classes" argument includes an enum: '
'${elementToMock.displayName}');
}
- // TODO(srawlins): Catch when someone tries to generate mocks for an
- // un-subtypable class, like bool, String, FutureOr, etc.
+ if (typeProvider.nonSubtypableClasses.contains(elementToMock)) {
+ throw InvalidMockitoAnnotationException(
+ 'The "classes" argument includes a non-subtypable type: '
+ '${elementToMock.displayName}. It is illegal to subtype this '
+ 'type.');
+ }
mockClasses.add(_buildMockClass(dartTypeToMock, elementToMock));
} else if (elementToMock is GenericFunctionTypeElement &&
elementToMock.enclosingElement is FunctionTypeAliasElement) {
diff --git a/test/builder_test.dart b/test/builder_test.dart
index 3798bff..409a23c 100644
--- a/test/builder_test.dart
+++ b/test/builder_test.dart
@@ -920,35 +920,6 @@
);
});
- test('deduplicates fake classes', () async {
- await _expectSingleNonNullableOutput(
- dedent(r'''
- class Foo {
- Bar m1() => Bar('name1');
- Bar m2() => Bar('name2');
- }
- class Bar {
- final String name;
- Bar(this.name);
- }
- '''),
- dedent(r'''
- import 'package:mockito/mockito.dart' as _i1;
- import 'package:foo/foo.dart' as _i2;
-
- class _FakeBar extends _i1.Fake implements _i2.Bar {}
-
- /// A class which mocks [Foo].
- ///
- /// See the documentation for Mockito's code generation for more information.
- class MockFoo extends _i1.Mock implements _i2.Foo {
- _i2.Bar m1() => super.noSuchMethod(Invocation.method(#m1, []), _FakeBar());
- _i2.Bar m2() => super.noSuchMethod(Invocation.method(#m2, []), _FakeBar());
- }
- '''),
- );
- });
-
test('creates dummy non-null return values for enums', () async {
await _expectSingleNonNullableOutput(
dedent(r'''
@@ -1007,13 +978,39 @@
);
});
+ test('deduplicates fake classes', () async {
+ await _expectSingleNonNullableOutput(
+ dedent(r'''
+ class Foo {
+ Bar m1() => Bar('name1');
+ Bar m2() => Bar('name2');
+ }
+ class Bar {
+ final String name;
+ Bar(this.name);
+ }
+ '''),
+ dedent(r'''
+ import 'package:mockito/mockito.dart' as _i1;
+ import 'package:foo/foo.dart' as _i2;
+
+ class _FakeBar extends _i1.Fake implements _i2.Bar {}
+
+ /// A class which mocks [Foo].
+ ///
+ /// See the documentation for Mockito's code generation for more information.
+ class MockFoo extends _i1.Mock implements _i2.Foo {
+ _i2.Bar m1() => super.noSuchMethod(Invocation.method(#m1, []), _FakeBar());
+ _i2.Bar m2() => super.noSuchMethod(Invocation.method(#m2, []), _FakeBar());
+ }
+ '''),
+ );
+ });
+
test('throws when GenerateMocks is missing an argument', () async {
_expectBuilderThrows(
assets: {
...annotationsAsset,
- 'foo|lib/foo.dart': dedent(r'''
- class Foo {}
- '''),
'foo|test/foo_test.dart': dedent('''
import 'package:mockito/annotations.dart';
// Missing required argument to GenerateMocks.
@@ -1047,9 +1044,6 @@
_expectBuilderThrows(
assets: {
...annotationsAsset,
- 'foo|lib/foo.dart': dedent(r'''
- class Foo {}
- '''),
'foo|test/foo_test.dart': dedent('''
import 'package:mockito/annotations.dart';
@GenerateMocks([7])
@@ -1099,6 +1093,21 @@
);
});
+ test('throws when GenerateMocks references a non-subtypeable type', () async {
+ _expectBuilderThrows(
+ assets: {
+ ...annotationsAsset,
+ 'foo|test/foo_test.dart': dedent('''
+ import 'package:mockito/annotations.dart';
+ @GenerateMocks([int])
+ void main() {}
+ '''),
+ },
+ message: contains(
+ 'The "classes" argument includes a non-subtypable type: int'),
+ );
+ });
+
test('given a pre-non-nullable library, does not override any members',
() async {
await _testPreNonNullable(