Files
sdk/tests/language/invocation_mirror_test.dart
T
regis@google.com d273efd45f Turn compile time errors related to missing getters and setters into invocation
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
2012-12-22 00:40:46 +00:00

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();
}