Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,9 @@
.packages
.pub
pubspec.lock
build/

coverage/

# ignore generated mocks
**/*.mocks.dart
16 changes: 11 additions & 5 deletions lib/src/builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1233,8 +1233,9 @@ class _MockClassInfo {
if (parameter.isNamed) pBuilder.named = true;
if (parameter.defaultValueCode != null) {
try {
pBuilder.defaultTo =
_expressionFromDartObject(parameter.computeConstantValue()!).code;
pBuilder.defaultTo = _expressionFromDartObject(
parameter.computeConstantValue()!, parameter)
.code;
} on _ReviveException catch (e) {
final method = parameter.enclosingElement!;
final clazz = method.enclosingElement!;
Expand All @@ -1248,11 +1249,13 @@ class _MockClassInfo {
}

/// Creates a code_builder [Expression] from [object], a constant object from
/// analyzer.
/// analyzer and [parameter], an optional [ParameterElement], when the
/// expression is created for a method parameter.
///
/// This is very similar to Angular's revive code, in
/// angular_compiler/analyzer/di/injector.dart.
Expression _expressionFromDartObject(DartObject object) {
Expression _expressionFromDartObject(DartObject object,
[ParameterElement? parameter]) {
final constant = ConstantReader(object);
if (constant.isNull) {
return literalNull;
Expand Down Expand Up @@ -1318,7 +1321,10 @@ class _MockClassInfo {
for (var pair in revivable.namedArguments.entries)
pair.key: _expressionFromDartObject(pair.value)
};
final type = referImported(name, _typeImport(object.type!.element));
final element = parameter != null && name != object.type!.element!.name
? parameter.type.element
: object.type!.element;
final type = referImported(name, _typeImport(element));
if (revivable.accessor.isNotEmpty) {
return type.constInstanceNamed(
revivable.accessor,
Expand Down
11 changes: 9 additions & 2 deletions test/end2end/foo.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import 'foo_sub.dart';

class Foo<T> {
const Foo();

const factory Foo.sub() = FooSub2;

String positionalParameter(int x) => 'Real';
String namedParameter({required int x}) => 'Real';
String get getter => 'Real';
int operator +(int arg) => arg + 1;
String parameterWithDefault([int x = 0]) => 'Real';
String parameterWithDefault2([Foo<int> x = const FooSub()]) => 'Real';
String parameterWithDefaultFactoryRedirect([Foo<T> x = const Foo.sub()]) =>
'Real';
String? nullableMethod(int x) => 'Real';
String? get nullableGetter => 'Real';
String methodWithBarArg(Bar bar) => 'result';
Expand All @@ -13,8 +22,6 @@ class Foo<T> {
Future<void>? returnsNullableFutureVoid() => Future.value();
}

class FooSub extends Foo<int> {}

class Bar {}

abstract class Baz {
Expand Down
9 changes: 9 additions & 0 deletions test/end2end/foo_sub.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import 'foo.dart';

class FooSub extends Foo<int> {
const FooSub();
}

class FooSub2<T> extends Foo<T> {
const FooSub2();
}
19 changes: 19 additions & 0 deletions test/end2end/generated_mocks_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:mockito/mockito.dart';
import 'package:test/test.dart';

import 'foo.dart';
import 'foo_sub.dart';
import 'generated_mocks_test.mocks.dart';

T dummyMethod<T>() => [1, 1.5].whereType<T>().first!;
Expand Down Expand Up @@ -66,6 +67,24 @@ void main() {

when(foo.parameterWithDefault()).thenReturn('Default');
expect(foo.parameterWithDefault(), equals('Default'));

const foo2 = FooSub();
when(foo.parameterWithDefault2(foo2)).thenReturn('Stubbed');
expect(foo.parameterWithDefault2(foo2), equals('Stubbed'));

when(foo.parameterWithDefault2()).thenReturn('Default');
expect(foo.parameterWithDefault2(), equals('Default'));
});

test(
'a method with a parameter with a default value factory redirect can be stubbed',
() {
const foo2 = FooSub2<int>();
when(foo.parameterWithDefaultFactoryRedirect(foo2)).thenReturn('Stubbed');
expect(foo.parameterWithDefaultFactoryRedirect(foo2), equals('Stubbed'));

when(foo.parameterWithDefaultFactoryRedirect()).thenReturn('Default');
expect(foo.parameterWithDefaultFactoryRedirect(), equals('Default'));
});

test('an inherited method can be stubbed', () {
Expand Down