|  | // 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); | 
|  |  | 
|  | 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')); | 
|  | } |