blob: 20c685b53674f91a172d5618d174585be88c183a [file] [log] [blame]
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:test/test.dart';
import 'foo.dart';
import 'foo_sub.dart';
import 'generated_mocks_test.mocks.dart';
T returnsTypeVariableShim<T>() => [1, 1.5].whereType<T>().first!;
T returnsBoundedTypeVariableShim<T extends num?>() =>
[1, 1.5].whereType<T>().first!;
T returnsTypeVariableFromTwoShim<T, U>() => [1, 1.5].whereType<T>().first!;
T typeVariableFieldShim<T>() =>
throw UnsupportedError('typeVariableField cannot be used');
T Function(T) returnsGenericFunctionShim<T>() => (T _) => null as T;
@GenerateMocks([
Foo,
FooSub,
Bar
], customMocks: [
MockSpec<Foo>(as: #MockFooRelaxed, returnNullOnMissingStub: true),
MockSpec<Foo>(
as: #MockFooWithDefaults,
onMissingStub: OnMissingStub.returnDefault,
),
MockSpec<Bar>(as: #MockBarRelaxed, returnNullOnMissingStub: true),
MockSpec<Baz>(
as: #MockBazWithUnsupportedMembers,
unsupportedMembers: {
#returnsTypeVariable,
#returnsBoundedTypeVariable,
#returnsTypeVariableFromTwo,
#returnsGenericFunction,
#typeVariableField,
},
),
MockSpec<Baz>(
as: #MockBazWithFallbackGenerators,
fallbackGenerators: {
#returnsTypeVariable: returnsTypeVariableShim,
#returnsBoundedTypeVariable: returnsBoundedTypeVariableShim,
#returnsTypeVariableFromTwo: returnsTypeVariableFromTwoShim,
#returnsGenericFunction: returnsGenericFunctionShim,
#typeVariableField: typeVariableFieldShim,
},
),
MockSpec<HasPrivate>(mixingIn: [HasPrivateMixin]),
])
@GenerateNiceMocks([MockSpec<Foo>(as: #MockFooNice)])
void main() {
group('for a generated mock,', () {
late MockFoo<Object> foo;
late FooSub fooSub;
setUp(() {
foo = MockFoo();
fooSub = MockFooSub();
});
tearDown(() {
// In some of the tests that expect an Error to be thrown, Mockito's
// global state can become invalid. Reset it.
resetMockitoState();
});
test('a method with a positional parameter can be stubbed', () {
when(foo.positionalParameter(42)).thenReturn('Stubbed');
expect(foo.positionalParameter(42), equals('Stubbed'));
});
test('a method with a named parameter can be stubbed', () {
when(foo.namedParameter(x: 42)).thenReturn('Stubbed');
expect(foo.namedParameter(x: 42), equals('Stubbed'));
});
test('a getter can be stubbed', () {
when(foo.getter).thenReturn('Stubbed');
expect(foo.getter, equals('Stubbed'));
});
test('an operator can be stubbed', () {
when(foo + 1).thenReturn(0);
expect(foo + 1, equals(0));
});
test('a method with a parameter with a default value can be stubbed', () {
when(foo.parameterWithDefault(42)).thenReturn('Stubbed');
expect(foo.parameterWithDefault(42), equals('Stubbed'));
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', () {
when(fooSub.positionalParameter(42)).thenReturn('Stubbed');
expect(fooSub.positionalParameter(42), equals('Stubbed'));
});
test('a setter can be called without stubbing', () {
expect(() => foo.setter = 7, returnsNormally);
});
test('a method which returns void can be called without stubbing', () {
expect(() => foo.returnsVoid(), returnsNormally);
});
test('a method which returns Future<void> can be called without stubbing',
() {
expect(() => foo.returnsFutureVoid(), returnsNormally);
});
test('a method which returns Future<void>? can be called without stubbing',
() {
expect(() => foo.returnsNullableFutureVoid(), returnsNormally);
});
test(
'a method with a non-nullable positional parameter accepts an argument '
'matcher while stubbing', () {
when(foo.positionalParameter(any)).thenReturn('Stubbed');
expect(foo.positionalParameter(42), equals('Stubbed'));
});
test(
'a method with a non-nullable named parameter accepts an argument '
'matcher while stubbing', () {
when(foo.namedParameter(x: anyNamed('x'))).thenReturn('Stubbed');
expect(foo.namedParameter(x: 42), equals('Stubbed'));
});
test(
'a method with a non-nullable parameter accepts an argument matcher '
'while verifying', () {
when(foo.positionalParameter(any)).thenReturn('Stubbed');
foo.positionalParameter(42);
expect(() => verify(foo.positionalParameter(any)), returnsNormally);
});
test('a method with a non-nullable parameter can capture an argument', () {
when(foo.positionalParameter(any)).thenReturn('Stubbed');
foo.positionalParameter(42);
var captured = verify(foo.positionalParameter(captureAny)).captured;
expect(captured[0], equals(42));
});
test('an unstubbed method throws', () {
when(foo.namedParameter(x: 42)).thenReturn('Stubbed');
expect(
() => foo.namedParameter(x: 43),
throwsA(TypeMatcher<MissingStubError>().having((e) => e.toString(),
'toString()', contains('namedParameter({x: 43})'))),
);
});
test('an unstubbed getter throws', () {
expect(
() => foo.getter,
throwsA(TypeMatcher<MissingStubError>()
.having((e) => e.toString(), 'toString()', contains('getter'))),
);
});
});
group('for a generated mock using unsupportedMembers', () {
late Baz baz;
setUp(() {
baz = MockBazWithUnsupportedMembers();
});
test('a real method call throws', () {
expect(() => baz.returnsTypeVariable(), throwsUnsupportedError);
});
test('a real getter call (or field access) throws', () {
expect(() => baz.typeVariableField, throwsUnsupportedError);
});
});
group('for a generated mock using fallbackGenerators,', () {
late Baz baz;
setUp(() {
baz = MockBazWithFallbackGenerators();
});
test('a method with a type variable return type can be called', () {
when(baz.returnsTypeVariable()).thenReturn(3);
baz.returnsTypeVariable();
});
test('a method with a bounded type variable return type can be called', () {
when(baz.returnsBoundedTypeVariable()).thenReturn(3);
baz.returnsBoundedTypeVariable();
});
test(
'a method with multiple type parameters and a type variable return '
'type can be called', () {
when(baz.returnsTypeVariable()).thenReturn(3);
baz.returnsTypeVariable();
});
});
group('for a generated mock using returnNullOnMissingStub,', () {
late Foo<Object> foo;
setUp(() {
foo = MockFooRelaxed();
});
test('an unstubbed method returning a non-nullable type throws a TypeError',
() {
when(foo.namedParameter(x: 42)).thenReturn('Stubbed');
expect(
() => foo.namedParameter(x: 43), throwsA(TypeMatcher<TypeError>()));
});
test('an unstubbed getter returning a non-nullable type throws a TypeError',
() {
expect(() => foo.getter, throwsA(TypeMatcher<TypeError>()));
});
test('an unstubbed method returning a nullable type returns null', () {
when(foo.nullableMethod(42)).thenReturn('Stubbed');
expect(foo.nullableMethod(43), isNull);
});
test('an unstubbed getter returning a nullable type returns null', () {
expect(foo.nullableGetter, isNull);
});
});
group('for a generated mock using OnMissingStub.returnDefault,', () {
late Foo<Object> foo;
setUp(() {
foo = MockFooWithDefaults();
});
test('an unstubbed method returns a value', () {
when(foo.namedParameter(x: 42)).thenReturn('Stubbed');
expect(foo.namedParameter(x: 43), equals(''));
});
test('an unstubbed getter returns a value', () {
expect(foo.getter, equals(''));
});
});
group('for a generated nice mock', () {
late Foo<Object> foo;
setUp(() {
foo = MockFooNice();
});
test('an unstubbed method returns a value', () {
when(foo.namedParameter(x: 42)).thenReturn('Stubbed');
expect(foo.namedParameter(x: 43), equals(''));
});
test('an unstubbed getter returns a value', () {
expect(foo.getter, equals(''));
});
test('an unstubbed method returning non-core type returns a fake', () {
when(foo.returnsBar(42)).thenReturn(Bar());
expect(foo.returnsBar(43), isA<SmartFake>());
});
test('a fake throws a FakeUsedError if a getter is called', () {
when(foo.returnsBar(42)).thenReturn(Bar());
final bar = foo.returnsBar(43);
expect(
() => bar.x,
throwsA(isA<FakeUsedError>().having(
(e) => e.toString(), 'toString()', contains('returnsBar(43)'))));
});
test('a fake throws a FakeUsedError if a method is called', () {
when(foo.returnsBar(42)).thenReturn(Bar());
final bar = foo.returnsBar(43);
expect(
() => bar.f(),
throwsA(isA<FakeUsedError>().having(
(e) => e.toString(), 'toString()', contains('returnsBar(43)'))));
});
});
test('a generated mock can be used as a stub argument', () {
var foo = MockFoo();
var bar = MockBar();
when(foo.methodWithBarArg(bar)).thenReturn('mocked result');
expect(foo.methodWithBarArg(bar), equals('mocked result'));
});
test(
'a generated mock which returns null on missing stubs can be used as a '
'stub argument', () {
var foo = MockFooRelaxed();
var bar = MockBarRelaxed();
when(foo.methodWithBarArg(bar)).thenReturn('mocked result');
expect(foo.methodWithBarArg(bar), equals('mocked result'));
});
test('a generated mock with a mixed in type can use mixed in members', () {
var hasPrivate = MockHasPrivate();
// This should not throw, when `setPrivate` accesses a private member on
// `hasPrivate`.
setPrivate(hasPrivate);
});
}