Skip to content

Commit

Permalink
Prepare mockito for the 'wildcard-variables' language feature.
Browse files Browse the repository at this point in the history
We generally preserve positional parameter names, but in the case of wildcard
parameters, we must rename them. We cannot override a wildcard parameter with a
wildcard parameter, since we do use the parameter (we pass it to
`super.noSuchMethod` in a call to `Invocation.method`). This change introduces
some renaming logic for wildcard parameters, using new method-unique parameter
names.

PiperOrigin-RevId: 696158750
  • Loading branch information
srawlins authored and copybara-github committed Nov 13, 2024
1 parent f72791d commit 67c3237
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 14 deletions.
34 changes: 24 additions & 10 deletions lib/src/builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1318,14 +1318,21 @@ class _MockClassInfo {
if (parameter.isRequiredPositional || parameter.isOptionalPositional) {
final superParameterType =
_escapeCovariance(parameter, position: position);
final matchingParameter = _matchingParameter(parameter,
superParameterType: superParameterType, forceNullable: true);
final matchingParameter = _matchingParameter(
parameter,
superParameterType: superParameterType,
// A parameter in the overridden method may be a wildcard, in which
// case we need to rename it, as we use the parameter when we pass
// it to `Invocation.method`.
defaultName: '_$position',
forceNullable: true,
);
if (parameter.isRequiredPositional) {
builder.requiredParameters.add(matchingParameter);
} else {
builder.optionalParameters.add(matchingParameter);
}
invocationPositionalArgs.add(refer(parameter.displayName));
invocationPositionalArgs.add(refer(matchingParameter.name));
position++;
} else if (parameter.isNamed) {
final superParameterType =
Expand Down Expand Up @@ -1712,12 +1719,14 @@ class _MockClassInfo {
{required analyzer.DartType superParameterType,
String? defaultName,
bool forceNullable = false}) {
final parameterHasName = parameter.name.isNotEmpty && parameter.name != '_';
assert(
parameter.name.isNotEmpty || defaultName != null,
'parameter must have a non-empty name, or non-null defaultName must be '
'passed, but parameter name is "${parameter.name}" and defaultName is '
'$defaultName');
final name = parameter.name.isEmpty ? defaultName! : parameter.name;
parameterHasName || defaultName != null,
'parameter must have a non-empty name, or non-null defaultName must be '
'passed, but parameter name is "${parameter.name}" and defaultName is '
'$defaultName',
);
final name = !parameterHasName ? defaultName! : parameter.name;
return Parameter((pBuilder) {
pBuilder.name = name;
if (!superParameterType.containsPrivateName) {
Expand Down Expand Up @@ -1980,8 +1989,13 @@ class _MockClassInfo {

assert(setter.parameters.length == 1);
final parameter = setter.parameters.single;
// The parameter in the overridden setter may be a wildcard, in which case
// we need to rename it, as we use the parameter when we pass it to
// `Invocation.setter`.
final parameterName =
parameter.displayName == '_' ? '_value' : parameter.displayName;
builder.requiredParameters.add(Parameter((pBuilder) {
pBuilder.name = parameter.displayName;
pBuilder.name = parameterName;
if (!parameter.type.containsPrivateName) {
pBuilder.type = _typeReference(parameter.type,
forceNullable: true, overrideVoid: true);
Expand Down Expand Up @@ -2012,7 +2026,7 @@ class _MockClassInfo {
final invocation =
referImported('Invocation', 'dart:core').property('setter').call([
refer('#$name'),
refer(parameter.displayName),
refer(parameterName),
]);
final returnNoSuchMethod = refer('super')
.property('noSuchMethod')
Expand Down
35 changes: 31 additions & 4 deletions test/builder/auto_mocks_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1364,7 +1364,6 @@ void main() {
test('prefixes parameter type on generic function-typed parameter', () async {
await expectSingleNonNullableOutput(
dedent(r'''
import 'dart:async';
class Foo {
dynamic m(void Function(Foo f) a) {}
}
Expand All @@ -1377,7 +1376,6 @@ void main() {
test('prefixes return type on generic function-typed parameter', () async {
await expectSingleNonNullableOutput(
dedent(r'''
import 'dart:async';
class Foo {
void m(Foo Function() a) {}
}
Expand All @@ -1389,7 +1387,6 @@ void main() {
test('prefixes parameter type on function-typed parameter', () async {
await expectSingleNonNullableOutput(
dedent(r'''
import 'dart:async';
class Foo {
void m(void a(Foo f)) {}
}
Expand All @@ -1402,7 +1399,6 @@ void main() {
test('prefixes return type on function-typed parameter', () async {
await expectSingleNonNullableOutput(
dedent(r'''
import 'dart:async';
class Foo {
void m(Foo a()) {}
}
Expand All @@ -1411,6 +1407,20 @@ void main() {
);
});

test('renames wildcard parameters', () async {
await expectSingleNonNullableOutput(
dedent(r'''
class Foo {
void m(int _, int _) {}
}
'''),
_containsAllOf(
'void m(int? _0, int? _1) => super.noSuchMethod(Invocation.method(',
'Invocation.method(#m, [_0, _1])',
),
);
});

test('widens the type of parameters to be nullable', () async {
await expectSingleNonNullableOutput(
dedent(r'''
Expand Down Expand Up @@ -2046,6 +2056,23 @@ void main() {
);
});

test('overrides nullable instance setters with wildcard parameters',
() async {
await expectSingleNonNullableOutput(
dedent('''
class Foo {
void set m(int? _) {}
}
'''),
_containsAllOf(dedent2('''
set m(int? _value) => super.noSuchMethod(
Invocation.setter(#m, _value),
returnValueForMissingStub: null,
);
''')),
);
});

test('overrides inherited non-nullable instance setters', () async {
await expectSingleNonNullableOutput(
dedent('''
Expand Down

0 comments on commit 67c3237

Please sign in to comment.