d273efd45f
of noSuchMethod or into throwing of NoSuchMethodError according to spec. Return result of InvocationMirror.invokeOn to caller. Fix various tests. Review URL: https://codereview.chromium.org//11669015 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@16463 260f80e4-7a28-3924-810f-c04153c831b5
245 lines
9.6 KiB
Dart
245 lines
9.6 KiB
Dart
// Copyright (c) 2012, 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.
|
|
|
|
// InvocationMirror and noSuchMethod testing.
|
|
|
|
/** Class with noSuchMethod that returns the mirror */
|
|
class N {
|
|
// Storage for the last argument to noSuchMethod.
|
|
// Needed for setters, which don't evaluate to the return value.
|
|
var last;
|
|
noSuchMethod(InvocationMirror m) => last = m;
|
|
|
|
flif(int x) { Expect.fail("never get here"); }
|
|
flaf([int x]) { Expect.fail("never get here"); }
|
|
flof({int y}) { Expect.fail("never get here"); }
|
|
|
|
get wut => this;
|
|
final int plif = 99;
|
|
int get plaf { Expect.fail("never get here"); return 0; }
|
|
}
|
|
|
|
/** As [N] but also implements 'call', so we can call it with wrong arguments.*/
|
|
class C extends N {
|
|
call(int x) { Expect.fail("never get here"); }
|
|
}
|
|
|
|
/**
|
|
* Checks the data of an InvocationMirror.
|
|
*
|
|
* Call without optionals for getters, with only positional for setters,
|
|
* and with both optionals for everything else.
|
|
*/
|
|
testInvocationMirror(InvocationMirror im, String name,
|
|
[List positional, Map named]) {
|
|
Expect.isTrue(im is InvocationMirror, "is InvocationMirror");
|
|
Expect.equals(name, im.memberName, "name");
|
|
if (named == null) {
|
|
Expect.isTrue(im.isAccessor, "$name:isAccessor");
|
|
Expect.isFalse(im.isMethod, "$name:isMethod");
|
|
if (positional == null) {
|
|
Expect.isTrue(im.isGetter, "$name:isGetter");
|
|
Expect.isFalse(im.isSetter, "$name:isSetter");
|
|
Expect.equals(0, im.positionalArguments.length, "$name:#positional");
|
|
Expect.equals(0, im.namedArguments.length, "$name:#named");
|
|
return;
|
|
}
|
|
Expect.isTrue(im.isSetter, "$name:isSetter");
|
|
Expect.isFalse(im.isGetter, "$name:isGetter");
|
|
Expect.equals(1, im.positionalArguments.length, "$name:#positional");
|
|
Expect.equals(positional[0], im.positionalArguments[0],
|
|
"$name:positional[0]");
|
|
Expect.equals(0, im.namedArguments.length, "$name:#named");
|
|
return;
|
|
}
|
|
Expect.isTrue(im.isMethod, "$name:isMethod");
|
|
Expect.isFalse(im.isAccessor, "$name:isAccessor");
|
|
Expect.isFalse(im.isSetter, "$name:isSetter");
|
|
Expect.isFalse(im.isGetter, "$name:isGetter");
|
|
|
|
Expect.equals(positional.length, im.positionalArguments.length);
|
|
for (int i = 0; i < positional.length; i++) {
|
|
Expect.equals(positional[i], im.positionalArguments[i],
|
|
"$name:positional[$i]");
|
|
}
|
|
Expect.equals(named.length, im.namedArguments.length, "$name:#named");
|
|
named.forEach((k, v) {
|
|
Expect.isTrue(im.namedArguments.containsKey(k), "$name:?named[$k]");
|
|
Expect.equals(v, im.namedArguments[k], "$name:named[$k]");
|
|
});
|
|
}
|
|
|
|
|
|
// Test different ways that noSuchMethod can be called.
|
|
testInvocationMirrors() {
|
|
var n = new N();
|
|
var c = new C();
|
|
|
|
// Missing property/method access.
|
|
testInvocationMirror(n.bar, 'bar');
|
|
testInvocationMirror((n..bar = 42).last, 'bar=', [42]);
|
|
testInvocationMirror(n.bar(), 'bar', [], {});
|
|
testInvocationMirror(n.bar(42), 'bar', [42], {});
|
|
testInvocationMirror(n.bar(x: 42), 'bar', [], {"x": 42});
|
|
testInvocationMirror(n.bar(37, x: 42), 'bar', [37], {"x": 42});
|
|
|
|
// Missing operator access.
|
|
testInvocationMirror(n + 4, '+', [4], {});
|
|
testInvocationMirror(n - 4, '-', [4], {});
|
|
testInvocationMirror(-n, 'unary-', [], {});
|
|
testInvocationMirror(n[42], '[]', [42], {});
|
|
testInvocationMirror((n..[37] = 42).last, '[]=', [37, 42], {});
|
|
|
|
// Calling as function when it's not.
|
|
testInvocationMirror(n(), 'call', [], {});
|
|
testInvocationMirror(n(42), 'call', [42], {});
|
|
testInvocationMirror(n(x: 42), 'call', [], {"x": 42});
|
|
testInvocationMirror(n(37, x: 42), 'call', [37], {"x": 42});
|
|
|
|
// Calling with arguments not matching existing call method.
|
|
testInvocationMirror(c(), 'call', [], {});
|
|
testInvocationMirror(c(37, 42), 'call', [37, 42], {});
|
|
testInvocationMirror(c(x: 42), 'call', [], {"x": 42});
|
|
testInvocationMirror(c(37, x: 42), 'call', [37], {"x": 42});
|
|
|
|
// Wrong arguments to existing function.
|
|
testInvocationMirror(n.flif(), "flif", [], {});
|
|
testInvocationMirror(n.flif(37, 42), "flif", [37, 42], {});
|
|
testInvocationMirror(n.flif(x: 42), "flif", [], {"x": 42});
|
|
testInvocationMirror(n.flif(37, x: 42), "flif", [37], {"x": 42});
|
|
testInvocationMirror((n..flif = 42).last, "flif=", [42]);
|
|
|
|
testInvocationMirror(n.flaf(37, 42), "flaf", [37, 42], {});
|
|
testInvocationMirror(n.flaf(x: 42), "flaf", [], {"x": 42});
|
|
testInvocationMirror(n.flaf(37, x: 42), "flaf", [37], {"x": 42});
|
|
testInvocationMirror((n..flaf = 42).last, "flaf=", [42]);
|
|
|
|
testInvocationMirror(n.flof(37, 42), "flof", [37, 42], {});
|
|
testInvocationMirror(n.flof(x: 42), "flof", [], {"x": 42});
|
|
testInvocationMirror(n.flof(37, y: 42), "flof", [37], {"y": 42});
|
|
testInvocationMirror((n..flof = 42).last, "flof=", [42]);
|
|
|
|
// Reading works.
|
|
Expect.isTrue(n.flif is Function);
|
|
Expect.isTrue(n.flaf is Function);
|
|
Expect.isTrue(n.flof is Function);
|
|
|
|
// Writing to read-only fields.
|
|
testInvocationMirror((n..wut = 42).last, "wut=", [42]);
|
|
testInvocationMirror((n..plif = 42).last, "plif=", [42]);
|
|
testInvocationMirror((n..plaf = 42).last, "plaf=", [42]);
|
|
|
|
// Trick call to n.call - wut is a getter returning n again.
|
|
testInvocationMirror(n.wut(42), "call", [42], {});
|
|
|
|
// Calling noSuchMethod itself, badly.
|
|
testInvocationMirror(n.noSuchMethod(), "noSuchMethod", [], {});
|
|
testInvocationMirror(n.noSuchMethod(37, 42), "noSuchMethod", [37, 42], {});
|
|
testInvocationMirror(n.noSuchMethod(37, x:42),
|
|
"noSuchMethod", [37], {"x": 42});
|
|
testInvocationMirror(n.noSuchMethod(x:42), "noSuchMethod", [], {"x": 42});
|
|
|
|
// Closurizing a method means that calling it badly will not hit the
|
|
// original receivers noSuchMethod, only the one inherited from Object
|
|
// by the closure object.
|
|
Expect.throws(() { var x = n.flif; x(37, 42); },
|
|
(e) => e is NoSuchMethodError);
|
|
Expect.throws(() { var x = c.call; x(37, 42); },
|
|
(e) => e is NoSuchMethodError);
|
|
}
|
|
|
|
class M extends N {
|
|
noSuchMethod(InvocationMirror m) { throw "never get here"; }
|
|
|
|
testSuperCalls() {
|
|
// Missing property/method access.
|
|
testInvocationMirror(super.bar, 'bar');
|
|
testInvocationMirror((){super.bar = 42; return last;}(), 'bar=', [42]);
|
|
testInvocationMirror(super.bar(), 'bar', [], {});
|
|
testInvocationMirror(super.bar(42), 'bar', [42], {});
|
|
testInvocationMirror(super.bar(x: 42), 'bar', [], {"x": 42});
|
|
testInvocationMirror(super.bar(37, x: 42), 'bar', [37], {"x": 42});
|
|
|
|
// Missing operator access.
|
|
testInvocationMirror(super + 4, '+', [4], {});
|
|
testInvocationMirror(super - 4, '-', [4], {});
|
|
testInvocationMirror(-super, 'unary-', [], {});
|
|
testInvocationMirror(super[42], '[]', [42], {});
|
|
testInvocationMirror((){super[37] = 42; return last;}(), '[]=', [37, 42], {});
|
|
|
|
// Wrong arguments to existing function.
|
|
testInvocationMirror(super.flif(), "flif", [], {});
|
|
testInvocationMirror(super.flif(37, 42), "flif", [37, 42], {});
|
|
testInvocationMirror(super.flif(x: 42), "flif", [], {"x": 42});
|
|
testInvocationMirror(super.flif(37, x: 42), "flif", [37], {"x": 42});
|
|
testInvocationMirror((){super.flif = 42; return last;}(), "flif=", [42]);
|
|
|
|
testInvocationMirror(super.flaf(37, 42), "flaf", [37, 42], {});
|
|
testInvocationMirror(super.flaf(x: 42), "flaf", [], {"x": 42});
|
|
testInvocationMirror(super.flaf(37, x: 42), "flaf", [37], {"x": 42});
|
|
testInvocationMirror((){super.flaf = 42; return last;}(), "flaf=", [42]);
|
|
|
|
testInvocationMirror(super.flof(37, 42), "flof", [37, 42], {});
|
|
testInvocationMirror(super.flof(x: 42), "flof", [], {"x": 42});
|
|
testInvocationMirror(super.flof(37, y: 42), "flof", [37], {"y": 42});
|
|
testInvocationMirror((){super.flof = 42; return last;}(), "flof=", [42]);
|
|
|
|
// Reading works.
|
|
Expect.isTrue(super.flif is Function);
|
|
Expect.isTrue(super.flaf is Function);
|
|
Expect.isTrue(super.flof is Function);
|
|
|
|
// Writing to read-only fields.
|
|
testInvocationMirror((){super.wut = 42; return last;}(), "wut=", [42]);
|
|
testInvocationMirror((){super.plif = 42; return last;}(), "plif=", [42]);
|
|
testInvocationMirror((){super.plaf = 42; return last;}(), "plaf=", [42]);
|
|
|
|
// Calling noSuchMethod itself, badly.
|
|
testInvocationMirror(super.noSuchMethod(), "noSuchMethod", [], {});
|
|
testInvocationMirror(super.noSuchMethod(37, 42),
|
|
"noSuchMethod", [37, 42], {});
|
|
testInvocationMirror(super.noSuchMethod(37, x:42),
|
|
"noSuchMethod", [37], {"x": 42});
|
|
testInvocationMirror(super.noSuchMethod(x:42),
|
|
"noSuchMethod", [], {"x": 42});
|
|
|
|
// Closurizing a method means that calling it badly will not hit the
|
|
// original receivers noSuchMethod, only the one inherited from Object
|
|
// by the closure object.
|
|
Expect.throws(() { var x = super.flif; x(37, 42); },
|
|
(e) => e is NoSuchMethodError);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Test the NoSuchMethodError thrown by different incorrect calls.
|
|
testNoSuchMethodErrors() {
|
|
test(Function block) {
|
|
Expect.throws(block, (e) => e is NoSuchMethodError);
|
|
}
|
|
var n = new N();
|
|
var o = new Object();
|
|
test(() => o.bar);
|
|
test(() => o.bar = 42);
|
|
test(() => o.bar());
|
|
test(() => o + 2);
|
|
test(() => -o);
|
|
test(() => o[0]);
|
|
test(() => o[0] = 42);
|
|
test(() => o());
|
|
test(() => o.toString = 42);
|
|
test(() => o.toString(42));
|
|
test(() => o.toString(x: 37));
|
|
test(() => o.hashCode = 42);
|
|
test(() => o.hashCode()); // Thrown by int.noSuchMethod.
|
|
test(() => (n.flif)()); // Extracted method has no noSuchMethod.
|
|
}
|
|
|
|
main() {
|
|
testInvocationMirrors();
|
|
testNoSuchMethodErrors();
|
|
new M().testSuperCalls();
|
|
}
|