blob: 8f146b7f804f78a666f9922937a80644f85134f4 [file] [log] [blame]
// 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';
class MockCat implements Cat {
dynamic noSuchMethod(Invocation invocation) {
return (invocation.positionalArguments[0] as String).isNotEmpty;
class MockCat2 extends MockCat {
// this apparently works.
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);
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"));
// 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", 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();
Expect.equals(0, s.invocation.positionalArguments.length);
s.setter = 42;
Expect.equals(42, s.invocation.positionalArguments.single);
// TODO(jmesserly): enable these tests once we have implicit call tearoff.
// 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 as dynamic).call,;
Expect.equals(, (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([dynamic], doStuff2(42));
Expect.listEquals([num], doStuff2<num>(42));
Expect.listEquals([dynamic], doStuff2('hi'));