mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 23:59:47 +00:00
65032b4e4e
Change-Id: I5bae11c115c7ee2c9a581ce71f2d29203b92f923 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/149783 Auto-Submit: Bob Nystrom <rnystrom@google.com> Commit-Queue: Nicholas Shahan <nshahan@google.com> Reviewed-by: Nicholas Shahan <nshahan@google.com>
174 lines
5 KiB
Dart
174 lines
5 KiB
Dart
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
// Dart test program testing that NoSuchMethod is properly called.
|
|
|
|
import "package:expect/expect.dart";
|
|
|
|
class Cat {
|
|
bool eatFood(String food) => true;
|
|
String scratch(String furniture) => 'purr';
|
|
String mood = '';
|
|
}
|
|
|
|
class MockCat implements Cat {
|
|
dynamic noSuchMethod(Invocation invocation) {
|
|
var arg = invocation.positionalArguments[0];
|
|
return arg is String && arg.isNotEmpty;
|
|
}
|
|
}
|
|
|
|
class MockCat2 extends MockCat {
|
|
// this apparently works.
|
|
noSuchMethod(_);
|
|
}
|
|
|
|
class MockCat3 extends MockCat2 implements Cat {
|
|
bool eatFood(String food, {double amount});
|
|
String scratch(String furniture, [String? furniture2]);
|
|
|
|
dynamic noSuchMethod(Invocation invocation) {
|
|
if (invocation.memberName == #scratch) {
|
|
return invocation.positionalArguments.join(',');
|
|
}
|
|
|
|
return (invocation.positionalArguments[0] as String).isNotEmpty &&
|
|
invocation.namedArguments[#amount] > 0.5;
|
|
}
|
|
}
|
|
|
|
class MockWithGenerics {
|
|
List<Type> doStuff<T>(T t);
|
|
|
|
noSuchMethod(i) => (i as dynamic).typeArguments;
|
|
}
|
|
|
|
class MockWithGetterSetter {
|
|
get getter;
|
|
set setter(value);
|
|
|
|
late Invocation invocation;
|
|
noSuchMethod(i) {
|
|
invocation = i;
|
|
}
|
|
}
|
|
|
|
class Callable {
|
|
int call() => 1;
|
|
int m() => 2;
|
|
}
|
|
|
|
class MockCallable implements Callable {
|
|
noSuchMethod(i) => i.memberName == #call ? 42 : 0;
|
|
}
|
|
|
|
void main() {
|
|
MockCat mock = new MockCat();
|
|
Expect.isTrue((mock as dynamic).eatFood("cat food"));
|
|
Expect.isFalse(mock.eatFood(""));
|
|
mock.mood = 'sleepy';
|
|
(mock as dynamic).mood = 'playful';
|
|
Expect.throwsTypeError(() {
|
|
(mock as dynamic).mood = 42;
|
|
});
|
|
|
|
// In strong mode this will be a runtime type error:
|
|
// bool is not a String. VM will fail with noSuchMethod +.
|
|
Expect.throws(() => mock.scratch("couch") + '');
|
|
|
|
var mock2 = new MockCat2();
|
|
Expect.isTrue(mock2.eatFood("cat food"));
|
|
|
|
var mock3 = new MockCat3();
|
|
Expect.isTrue(mock3.eatFood("cat food", amount: 0.9));
|
|
Expect.isFalse(mock3.eatFood("cat food", amount: 0.3));
|
|
Expect.equals("chair,null", mock3.scratch("chair"));
|
|
Expect.equals("chair,couch", mock3.scratch("chair", "couch"));
|
|
Expect.equals("chair,null", mock3.scratch("chair", null));
|
|
Expect.equals("chair,", mock3.scratch("chair", ""));
|
|
|
|
var g = new MockWithGenerics();
|
|
Expect.listEquals([int], g.doStuff(42));
|
|
Expect.listEquals([num], g.doStuff<num>(42));
|
|
Expect.listEquals([String], g.doStuff('hi'));
|
|
|
|
var s = new MockWithGetterSetter();
|
|
s.getter;
|
|
Expect.equals(0, s.invocation.positionalArguments.length);
|
|
Expect.isTrue(s.invocation.isGetter);
|
|
Expect.isFalse(s.invocation.isSetter);
|
|
Expect.isFalse(s.invocation.isMethod);
|
|
s.setter = 42;
|
|
Expect.equals(42, s.invocation.positionalArguments.single);
|
|
Expect.isFalse(s.invocation.isGetter);
|
|
Expect.isTrue(s.invocation.isSetter);
|
|
Expect.isFalse(s.invocation.isMethod);
|
|
|
|
testMockTearoffs();
|
|
testMockCallable();
|
|
testMockCallableTearoff();
|
|
}
|
|
|
|
testMockCallable() {
|
|
Callable call = new MockCallable();
|
|
Expect.equals(42, call());
|
|
Expect.equals(42, (call as dynamic)());
|
|
Expect.equals(0, call.m());
|
|
Expect.equals(0, (call as dynamic).m());
|
|
}
|
|
|
|
testMockCallableTearoff() {
|
|
var mock = new MockCallable();
|
|
Function f = mock;
|
|
Expect.equals(42, f());
|
|
Expect.equals(42, (f as dynamic)());
|
|
Expect.equals(f, mock.call);
|
|
Expect.equals(f.call, mock.call);
|
|
Expect.equals((f as dynamic).call, mock.call);
|
|
Expect.equals(f.call, (mock as dynamic).call);
|
|
}
|
|
|
|
typedef bool EatFoodType(String food);
|
|
|
|
testMockTearoffs() {
|
|
var mock2 = new MockCat2();
|
|
var eat = mock2.eatFood;
|
|
var eat2 = (mock2 as dynamic).eatFood;
|
|
|
|
Expect.isTrue(eat is EatFoodType, 'eat is EatFoodType');
|
|
Expect.isTrue(eat2 is EatFoodType, 'eat2 is EatFoodType');
|
|
Expect.equals(eat, eat2, 'eat == eat2');
|
|
Expect.isTrue(eat.runtimeType == eat2.runtimeType,
|
|
'eat.runtimeType == eat2.runtimeType');
|
|
|
|
Expect.isTrue(eat("cat food"), 'eat("cat food")');
|
|
Expect.isFalse(eat(""), 'eat("")');
|
|
Expect.isTrue(eat2("cat food"), 'eat2("cat food")');
|
|
Expect.isFalse(eat2(""), 'eat2("")');
|
|
|
|
var g = new MockWithGenerics();
|
|
var doStuff = g.doStuff;
|
|
var doStuff2 = (g as dynamic).doStuff;
|
|
|
|
Expect.equals(doStuff, doStuff2, 'doStuff == doStuff2');
|
|
Expect.equals(doStuff.runtimeType, doStuff2.runtimeType,
|
|
'doStuff.runtimeType == doStuff2.runtimeType');
|
|
|
|
Expect.listEquals([int], doStuff(42));
|
|
Expect.listEquals([num], doStuff<num>(42));
|
|
Expect.listEquals([String], doStuff('hi'));
|
|
|
|
// no inference happens because `doStuff2` is dynamic.
|
|
Expect.listEquals([num], doStuff2<num>(42));
|
|
expectIsDynamicOrObject(List types) {
|
|
Expect.equals(1, types.length);
|
|
var t = types[0];
|
|
// TODO(jmesserly): allows either type because of
|
|
// https://github.com/dart-lang/sdk/issues/32483
|
|
Expect.isTrue(t == dynamic || t == Object, '$t == dynamic || $t == Object');
|
|
}
|
|
|
|
expectIsDynamicOrObject(doStuff2(42));
|
|
expectIsDynamicOrObject(doStuff2('hi'));
|
|
}
|