Skip to content

Commit ce2e6cf

Browse files
committed
Fix two related bugs affected by overriding toString methods.
* Properly reference types in overridden `toString` implementations. Fixes #438 * Override `toString` in a Fake implementation when the class-to-be-faked has a superclass which overrides `toString` with additional parameters. Fixes #371 PiperOrigin-RevId: 385852381
1 parent a93b434 commit ce2e6cf

File tree

3 files changed

+61
-7
lines changed

3 files changed

+61
-7
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77
type, prefer a library which exports the library in which the type is
88
declared. This avoids some confusion with conditional exports.
99
[#443](https://github.com/dart-lang/mockito/issues/443)
10+
* Properly reference types in overridden `toString` implementations.
11+
[#438](https://github.com/dart-lang/mockito/issues/438)
12+
* Override `toString` in a Fake implementation when the class-to-be-faked has
13+
a superclass which overrides `toString` with additional parameters.
14+
[#371](https://github.com/dart-lang/mockito/issues/371)
1015
* Support analyzer 2.0.0
1116

1217
## 5.0.11

lib/src/builder.dart

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,21 @@ class _TypeVisitor extends RecursiveElementVisitor<void> {
257257
type.typeArguments.forEach(_addType);
258258
if (!alreadyVisitedElement) {
259259
type.element.typeParameters.forEach(visitTypeParameterElement);
260+
261+
final toStringMethod =
262+
type.element.lookUpMethod('toString', type.element.library);
263+
if (toStringMethod != null && toStringMethod.parameters.isNotEmpty) {
264+
// In a Fake class which implements a class which overrides `toString`
265+
// with additional (optional) parameters, we must also override
266+
// `toString` and reference the same types referenced in those
267+
// parameters.
268+
for (final parameter in toStringMethod.parameters) {
269+
final parameterType = parameter.type;
270+
if (parameterType is analyzer.InterfaceType) {
271+
parameterType.element.accept(this);
272+
}
273+
}
274+
}
260275
}
261276
} else if (type is analyzer.FunctionType) {
262277
_addType(type.returnType);
@@ -1203,9 +1218,9 @@ class _MockClassInfo {
12031218
..types.addAll(typeParameters);
12041219
}));
12051220

1206-
final toStringMethod = elementToFake.methods
1207-
.firstWhereOrNull((method) => method.name == 'toString');
1208-
if (toStringMethod != null) {
1221+
final toStringMethod =
1222+
elementToFake.lookUpMethod('toString', elementToFake.library);
1223+
if (toStringMethod != null && toStringMethod.parameters.isNotEmpty) {
12091224
// If [elementToFake] includes an overriding `toString` implementation,
12101225
// we need to include an implementation which matches the signature.
12111226
cBuilder.methods.add(Method(
@@ -1483,7 +1498,8 @@ class _MockClassInfo {
14831498
assert(mockLibraryInfo.assetUris.containsKey(element),
14841499
'An element, "$element", is missing from the asset URI mapping');
14851500

1486-
return mockLibraryInfo.assetUris[element]!;
1501+
return mockLibraryInfo.assetUris[element] ??
1502+
(throw StateError('Asset URI is missing for $element'));
14871503
}
14881504

14891505
/// Returns a [Reference] to [symbol] with [url].

test/builder/auto_mocks_test.dart

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -687,13 +687,31 @@ void main() {
687687
);
688688
});
689689

690-
test('overrides `toString` with correct signature if the class overrides it',
691-
() async {
690+
test(
691+
'overrides `toString` with a correct signature if the class overrides '
692+
'it', () async {
693+
await expectSingleNonNullableOutput(
694+
dedent('''
695+
abstract class Foo {
696+
String toString({bool a = false});
697+
}
698+
'''),
699+
_containsAllOf('String toString({bool? a = false}) => super.toString()'),
700+
);
701+
});
702+
703+
test(
704+
'overrides `toString` with a correct signature if a mixed in class '
705+
'overrides it, in a Fake', () async {
692706
await expectSingleNonNullableOutput(
693707
dedent('''
694708
abstract class Foo {
709+
Bar m();
710+
}
711+
abstract class BarBase {
695712
String toString({bool a = false});
696713
}
714+
abstract class Bar extends BarBase {}
697715
'''),
698716
_containsAllOf('String toString({bool? a = false}) => super.toString()'),
699717
);
@@ -1060,7 +1078,7 @@ void main() {
10601078
});
10611079

10621080
test(
1063-
'imports libraries for external class types found in an inherited method'
1081+
'imports libraries for external class types found in an inherited method '
10641082
'via a generic instantiation', () async {
10651083
await testWithNonNullable({
10661084
...annotationsAsset,
@@ -2285,6 +2303,21 @@ void main() {
22852303
);
22862304
});
22872305

2306+
test('imports libraries for types used in generated fake classes', () async {
2307+
await expectSingleNonNullableOutput(
2308+
dedent('''
2309+
class Foo {
2310+
Bar m1() => Bar('name1');
2311+
}
2312+
class Bar {
2313+
String toString({Baz? baz}) => '';
2314+
}
2315+
class Baz {}
2316+
'''),
2317+
_containsAllOf('String toString({_i2.Baz? baz}) => super.toString();'),
2318+
);
2319+
});
2320+
22882321
test('deduplicates fake classes', () async {
22892322
var mocksContent = await buildWithSingleNonNullableSource(dedent(r'''
22902323
class Foo {

0 commit comments

Comments
 (0)