Skip to content

Commit 5c7605b

Browse files
committed
Address feedback, remove type annotations; fork tests for DDC
1 parent 34cbfda commit 5c7605b

File tree

5 files changed

+581
-93
lines changed

5 files changed

+581
-93
lines changed

README.md

+7-10
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ Analyzing [lib/cat_test.dart]...
190190
This code is not Strong mode-compliant. Let's change it to use `typed`:
191191

192192
```dart
193-
when(cat.eatFood(typed/*<List<String>>*/(any)))
193+
when(cat.eatFood(typed(any)))
194194
```
195195

196196
```
@@ -202,19 +202,16 @@ No issues found
202202
Great! A little ugly, but it works. Here are some more examples:
203203

204204
```dart
205-
when(cat.eatFood(typed/*<List<String>>*/(any), typed/*<List<String>>*/(any)))
206-
.thenReturn(true);
207-
when(cat.eatFood(typed/*<List<String>>*/(argThat(contains("fish")))))
208-
.thenReturn(true);
205+
when(cat.eatFood(typed(any), typed(any))).thenReturn(true);
206+
when(cat.eatFood(typed(argThat(contains("fish"))))).thenReturn(true);
209207
```
210208

211209
Named args require one more component: `typed` needs to know what named argument it is
212210
being passed into:
213211

214212
```dart
215-
when(cat.walk(
216-
typed/*<List<String>>*/(any),
217-
gaits: typed/*<Map<String, String>>*/(any, named: 'gaits'))).thenReturn(true);
213+
when(cat.walk(typed(any), gaits: typed(any, named: 'gaits')))
214+
.thenReturn(true);
218215
```
219216

220217
Note the `named` argument. Mockito should fail gracefully if you forget to name a `typed`
@@ -224,10 +221,10 @@ One more note about the `typed` API: you cannot mix `typed` arguments with `null
224221
arguments:
225222

226223
```dart
227-
when(cat.eatFood(null, typed/*<List<String>>*/(any))).thenReturn(true); // Throws!
224+
when(cat.eatFood(null, typed(any))).thenReturn(true); // Throws!
228225
when(cat.eatFood(
229226
argThat(equals(null)),
230-
typed/*<List<String>>*/(any))).thenReturn(true); // Works.
227+
typed(any))).thenReturn(true); // Works.
231228
```
232229

233230
[Strong mode]: https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md

lib/src/mock.dart

+35-26
Original file line numberDiff line numberDiff line change
@@ -63,21 +63,22 @@ class Mock {
6363
// Return a new [Invocation], reconstituted from [invocation], [_typedArgs],
6464
// and [_typedNamedArgs].
6565
Invocation _reconstituteInvocation(Invocation invocation) =>
66-
new FakeInvocation(invocation);
66+
new _InvocationForTypedArguments(invocation);
6767

68-
/// An Invocation implementation that allows all attributes to be passed into
69-
/// the constructor.
70-
class FakeInvocation extends Invocation {
68+
/// An Invocation implementation that takes arguments from [_typedArgs] and
69+
/// [_typedNamedArgs].
70+
class _InvocationForTypedArguments extends Invocation {
7171
final Symbol memberName;
7272
final Map<Symbol, dynamic> namedArguments;
7373
final List<dynamic> positionalArguments;
7474
final bool isGetter;
7575
final bool isMethod;
7676
final bool isSetter;
7777

78-
factory FakeInvocation(Invocation invocation) {
78+
factory _InvocationForTypedArguments(Invocation invocation) {
7979
if (_typedArgs.isEmpty && _typedNamedArgs.isEmpty) {
80-
throw new StateError("FakeInvocation called when no typed calls have been saved.");
80+
throw new StateError(
81+
"_InvocationForTypedArguments called when no typed calls have been saved.");
8182
}
8283

8384
// Handle named arguments first, so that we can provide useful errors for
@@ -90,7 +91,7 @@ class FakeInvocation extends Invocation {
9091
_typedArgs.clear();
9192
_typedNamedArgs.clear();
9293

93-
return new FakeInvocation._(
94+
return new _InvocationForTypedArguments._(
9495
invocation.memberName,
9596
positionalArguments,
9697
namedArguments,
@@ -99,6 +100,11 @@ class FakeInvocation extends Invocation {
99100
invocation.isSetter);
100101
}
101102

103+
// Reconstitutes the named arguments in an invocation from [_typedNamedArgs].
104+
//
105+
// The namedArguments in [invocation] which are null should be represented
106+
// by a stored value in [_typedNamedArgs]. The null presumably came from
107+
// [typed].
102108
static Map<Symbol,dynamic> _reconstituteNamedArgs(Invocation invocation) {
103109
var namedArguments = <Symbol, dynamic>{};
104110
var _typedNamedArgSymbols = _typedNamedArgs.keys.map((name) => new Symbol(name));
@@ -119,22 +125,24 @@ class FakeInvocation extends Invocation {
119125
}
120126
});
121127

128+
// Iterate through the stored named args (stored with [typed]), validate
129+
// them, and add them to the return map.
122130
_typedNamedArgs.forEach((name, arg) {
123131
Symbol nameSymbol = new Symbol(name);
124132
if (!invocation.namedArguments.containsKey(nameSymbol)) {
125-
// Incorrect usage of [name], something like:
126-
// `when(obj.fn(typed(any, named: 'a')))`.
127133
throw new ArgumentError(
128134
'A typed argument was declared as named $name, but was not passed '
129-
'as an argument named $name.');
135+
'as an argument named $name.\n\n'
136+
'BAD: when(obj.fn(typed(any, named: "a")))\n'
137+
'GOOD: when(obj.fn(a: typed(any, named: "a")))');
130138
}
131139
if (invocation.namedArguments[nameSymbol] != null) {
132-
// Incorrect usage of [name], something like:
133-
// `when(obj.fn(a: typed(any, named: 'b'), b: "string"))`.
134140
throw new ArgumentError(
135141
'A typed argument was declared as named $name, but a different '
136142
'value (${invocation.namedArguments[nameSymbol]}) was passed as '
137-
'$name.');
143+
'$name.\n\n'
144+
'BAD: when(obj.fn(b: typed(any, name: "a")))\n'
145+
'GOOD: when(obj.fn(b: typed(any, name: "b")))');
138146
}
139147
namedArguments[nameSymbol] = arg;
140148
});
@@ -151,31 +159,32 @@ class FakeInvocation extends Invocation {
151159
'null arguments are not allowed alongside typed(); use '
152160
'"typed(eq(null))"');
153161
}
154-
int i = 0;
155-
int j = 0;
156-
while (i < _typedArgs.length && j < invocation.positionalArguments.length) {
157-
var arg = _typedArgs[i];
158-
if (invocation.positionalArguments[j] == null) {
162+
int typedIndex = 0;
163+
int positionalIndex = 0;
164+
while (typedIndex < _typedArgs.length &&
165+
positionalIndex < invocation.positionalArguments.length) {
166+
var arg = _typedArgs[typedIndex];
167+
if (invocation.positionalArguments[positionalIndex] == null) {
159168
// [typed] was used; add the [_ArgMatcher] given to [typed].
160169
positionalArguments.add(arg);
161-
i++;
162-
j++;
170+
typedIndex++;
171+
positionalIndex++;
163172
} else {
164173
// [typed] was not used; add the [_ArgMatcher] from [invocation].
165-
positionalArguments.add(invocation.positionalArguments[j]);
166-
j++;
174+
positionalArguments.add(invocation.positionalArguments[positionalIndex]);
175+
positionalIndex++;
167176
}
168177
}
169-
while (j < invocation.positionalArguments.length) {
178+
while (positionalIndex < invocation.positionalArguments.length) {
170179
// Some trailing non-[typed] arguments.
171-
positionalArguments.add(invocation.positionalArguments[j]);
172-
j++;
180+
positionalArguments.add(invocation.positionalArguments[positionalIndex]);
181+
positionalIndex++;
173182
}
174183

175184
return positionalArguments;
176185
}
177186

178-
FakeInvocation._(
187+
_InvocationForTypedArguments._(
179188
this.memberName,
180189
this.positionalArguments,
181190
this.namedArguments,

test/mockito_test.dart

+41-57
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ class RealClass {
1111
String methodWithObjArgs(RealClass x) => "Real";
1212
// "SpecialArgs" here means type-parameterized args. But that makes for a long
1313
// method name.
14-
String methodWithSpecialArgs(
14+
String typeParameterizedFn(
1515
List<int> w, List<int> x, [List<int> y, List<int> z]) => "Real";
1616
// "SpecialNamedArgs" here means type-parameterized, named args. But that
1717
// makes for a long method name.
18-
String methodWithSpecialNamedArgs(List<int> w, List<int> x, {List<int> y, List<int> z}) =>
18+
String typeParameterizedNamedFn(List<int> w, List<int> x, {List<int> y, List<int> z}) =>
1919
"Real";
2020
String get getter => "Real";
2121
void set setter(String arg) {
@@ -219,93 +219,78 @@ void main() {
219219
expect(mock.methodWithNormalArgs(43), equals("43"));
220220
});
221221
test("should mock method with typed arg matchers", () {
222-
when(mock.methodWithSpecialArgs(
223-
typed/*<List<int>>*/(any), typed/*<List<int>>*/(any)))
222+
when(mock.typeParameterizedFn(typed(any), typed(any)))
224223
.thenReturn("A lot!");
225-
expect(mock.methodWithSpecialArgs([42], [43]), equals("A lot!"));
226-
expect(mock.methodWithSpecialArgs([43], [44]), equals("A lot!"));
224+
expect(mock.typeParameterizedFn([42], [43]), equals("A lot!"));
225+
expect(mock.typeParameterizedFn([43], [44]), equals("A lot!"));
227226
});
228227
test("should mock method with an optional typed arg matcher", () {
229-
when(mock.methodWithSpecialArgs(
230-
typed/*<List<int>>*/(any),
231-
typed/*<List<int>>*/(any),
232-
typed/*<List<int>>*/(any)))
228+
when(mock.typeParameterizedFn(typed(any), typed(any), typed(any)))
233229
.thenReturn("A lot!");
234-
expect(mock.methodWithSpecialArgs([42], [43], [44]), equals("A lot!"));
230+
expect(mock.typeParameterizedFn([42], [43], [44]), equals("A lot!"));
235231
});
236232
test("should mock method with an optional typed arg matcher and an optional real arg", () {
237-
when(mock.methodWithSpecialArgs(
238-
typed/*<List<int>>*/(any),
239-
typed/*<List<int>>*/(any),
240-
[44],
241-
typed/*<List<int>>*/(any)))
233+
when(mock.typeParameterizedFn(typed(any), typed(any), [44], typed(any)))
242234
.thenReturn("A lot!");
243-
expect(mock.methodWithSpecialArgs([42], [43], [44], [45]), equals("A lot!"));
235+
expect(mock.typeParameterizedFn([42], [43], [44], [45]), equals("A lot!"));
244236
});
245237
test("should mock method with only some typed arg matchers", () {
246-
when(mock.methodWithSpecialArgs(
247-
typed/*<List<int>>*/(any), [43], typed/*<List<int>>*/(any)))
238+
when(mock.typeParameterizedFn(typed(any), [43], typed(any)))
248239
.thenReturn("A lot!");
249-
expect(mock.methodWithSpecialArgs([42], [43], [44]), equals("A lot!"));
250-
when(mock.methodWithSpecialArgs(typed/*<List<int>>*/(any), [43]))
240+
expect(mock.typeParameterizedFn([42], [43], [44]), equals("A lot!"));
241+
when(mock.typeParameterizedFn(typed(any), [43]))
251242
.thenReturn("A bunch!");
252-
expect(mock.methodWithSpecialArgs([42], [43]), equals("A bunch!"));
243+
expect(mock.typeParameterizedFn([42], [43]), equals("A bunch!"));
253244
});
254245
test("should throw when [typed] used alongside [null].", () {
255-
expect(() => when(mock.methodWithSpecialArgs(
256-
typed/*<List<int>>*/(any), null, typed/*<List<int>>*/(any))),
246+
expect(() => when(mock.typeParameterizedFn(typed(any), null, typed(any))),
257247
throwsArgumentError);
258-
expect(() => when(mock.methodWithSpecialArgs(
259-
typed/*<List<int>>*/(any), typed/*<List<int>>*/(any), null)),
248+
expect(() => when(mock.typeParameterizedFn(typed(any), typed(any), null)),
260249
throwsArgumentError);
261250
});
262251
test("should mock method when [typed] used alongside matched [null].", () {
263-
when(mock.methodWithSpecialArgs(
264-
typed/*<List<int>>*/(any), argThat(equals(null)), typed/*<List<int>>*/(any)))
252+
when(mock.typeParameterizedFn(
253+
typed(any), argThat(equals(null)), typed(any)))
265254
.thenReturn("A lot!");
266-
expect(mock.methodWithSpecialArgs([42], null, [44]), equals("A lot!"));
255+
expect(mock.typeParameterizedFn([42], null, [44]), equals("A lot!"));
267256
});
268257
test("should mock method with named, typed arg matcher", () {
269-
when(mock.methodWithSpecialNamedArgs(
270-
typed/*<List<int>>*/(any), [43], y: typed/*<List<int>>*/(any, named: "y")))
258+
when(mock.typeParameterizedNamedFn(
259+
typed(any), [43], y: typed(any, named: "y")))
271260
.thenReturn("A lot!");
272-
expect(mock.methodWithSpecialNamedArgs([42], [43], y: [44]), equals("A lot!"));
261+
expect(mock.typeParameterizedNamedFn([42], [43], y: [44]), equals("A lot!"));
273262
});
274263
test("should mock method with named, typed arg matcher and an arg matcher", () {
275264
when(
276-
mock.methodWithSpecialNamedArgs(
277-
typed/*<List<int>>*/(any),
278-
[43],
279-
y: typed/*<List<int>>*/(any, named: "y"),
280-
z: argThat(contains(45))))
265+
mock.typeParameterizedNamedFn(
266+
typed(any), [43],
267+
y: typed(any, named: "y"), z: argThat(contains(45))))
281268
.thenReturn("A lot!");
282-
expect(mock.methodWithSpecialNamedArgs([42], [43], y: [44], z: [45]),
269+
expect(mock.typeParameterizedNamedFn([42], [43], y: [44], z: [45]),
283270
equals("A lot!"));
284271
});
285272
test("should mock method with named, typed arg matcher and a regular arg", () {
286273
when(
287-
mock.methodWithSpecialNamedArgs(
288-
typed/*<List<int>>*/(any),
289-
[43],
290-
y: typed/*<List<int>>*/(any, named: "y"),
291-
z: [45]))
274+
mock.typeParameterizedNamedFn(
275+
typed(any), [43],
276+
y: typed(any, named: "y"), z: [45]))
292277
.thenReturn("A lot!");
293-
expect(mock.methodWithSpecialNamedArgs([42], [43], y: [44], z: [45]),
278+
expect(mock.typeParameterizedNamedFn([42], [43], y: [44], z: [45]),
294279
equals("A lot!"));
295280
});
296281
test("should throw when [typed] used as a named arg, without `named:`", () {
297-
expect(() => when(mock.methodWithSpecialNamedArgs(
298-
typed/*<List<int>>*/(any), [43], y: typed/*<List<int>>*/(any))),
282+
expect(() => when(mock.typeParameterizedNamedFn(
283+
typed(any), [43], y: typed(any))),
299284
throwsArgumentError);
300285
});
301286
test("should throw when [typed] used as a positional arg, with `named:`", () {
302-
expect(() => when(mock.methodWithSpecialNamedArgs(
303-
typed/*<List<int>>*/(any), typed/*<List<int>>*/(any, named: "y"))),
287+
expect(() => when(mock.typeParameterizedNamedFn(
288+
typed(any), typed(any, named: "y"))),
304289
throwsArgumentError);
305290
});
306291
test("should throw when [typed] used as a named arg, with the wrong `named:`", () {
307-
expect(() => when(mock.methodWithSpecialNamedArgs(
308-
typed/*<List<int>>*/(any), [43], y: typed/*<List<int>>*/(any, named: "z"))),
292+
expect(() => when(mock.typeParameterizedNamedFn(
293+
typed(any), [43], y: typed(any, named: "z"))),
309294
throwsArgumentError);
310295
});
311296
});
@@ -424,15 +409,14 @@ void main() {
424409
verify(mock.setter = "A");
425410
});
426411
test("should verify method with typed arg matchers", () {
427-
mock.methodWithSpecialArgs([42], [43]);
428-
verify(mock.methodWithSpecialArgs(
429-
typed/*<List<int>>*/(any), typed/*<List<int>>*/(any)));
412+
mock.typeParameterizedFn([42], [43]);
413+
verify(mock.typeParameterizedFn(typed(any), typed(any)));
430414
});
431415
test("should verify method with argument capturer", () {
432-
mock.methodWithSpecialArgs([50], [17]);
433-
mock.methodWithSpecialArgs([100], [17]);
434-
expect(verify(mock.methodWithSpecialArgs(
435-
typed/*<List<int>>*/(captureAny), [17])).captured,
416+
mock.typeParameterizedFn([50], [17]);
417+
mock.typeParameterizedFn([100], [17]);
418+
expect(verify(mock.typeParameterizedFn(
419+
typed(captureAny), [17])).captured,
436420
equals([[50], [100]]));
437421
});
438422
});

0 commit comments

Comments
 (0)