mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 04:27:17 +00:00
d4154ac6dc
Change-Id: Iad2963c7f9c184b089dc6d15aa4442f58d194bc2 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/151983 Reviewed-by: Nicholas Shahan <nshahan@google.com> Commit-Queue: Bob Nystrom <rnystrom@google.com> Auto-Submit: Bob Nystrom <rnystrom@google.com>
318 lines
12 KiB
Dart
318 lines
12 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.
|
|
|
|
import "package:expect/expect.dart";
|
|
|
|
// Invocation and noSuchMethod testing.
|
|
|
|
Map<Symbol, dynamic> listToNamedArguments(list) {
|
|
var iterator = list.iterator;
|
|
var result = new Map<Symbol, dynamic>();
|
|
while (iterator.moveNext()) {
|
|
Symbol key = iterator.current;
|
|
Expect.isTrue(iterator.moveNext());
|
|
result[key] = iterator.current;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/** 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(Invocation m) => last = m;
|
|
|
|
flif(int x) {
|
|
Expect.fail("never get here");
|
|
}
|
|
|
|
flaf([int x = -1]) {
|
|
Expect.fail("never get here");
|
|
}
|
|
|
|
flof({int y = -1}) {
|
|
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 Invocation.
|
|
*
|
|
* Call without optionals for getters, with only positional for setters,
|
|
* and with both optionals for everything else.
|
|
*/
|
|
testInvocationMirror(Invocation im, Symbol name,
|
|
[List? positional, List? named, List? typeArgs]) {
|
|
Expect.isTrue(im is Invocation, "is Invocation");
|
|
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;
|
|
}
|
|
Map<Symbol, dynamic> namedArguments = listToNamedArguments(named);
|
|
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.listEquals(positional!, im.positionalArguments);
|
|
|
|
Expect.equals(
|
|
namedArguments.length, im.namedArguments.length, "$name:#named");
|
|
namedArguments.forEach((k, v) {
|
|
Expect.isTrue(
|
|
im.namedArguments.containsKey(k), "$name:?namedArguments[$k]");
|
|
Expect.equals(v, im.namedArguments[k], "$name:namedArguments[$k]");
|
|
});
|
|
var imTypeArgs = (im as dynamic).typeArguments as List<Type>;
|
|
Expect.listEquals(typeArgs ?? [], imTypeArgs);
|
|
}
|
|
|
|
// Test different ways that noSuchMethod can be called.
|
|
testInvocationMirrors() {
|
|
dynamic n = new N();
|
|
dynamic c = new C();
|
|
|
|
// Missing property/method access.
|
|
testInvocationMirror(n.bar, const Symbol('bar'));
|
|
testInvocationMirror((n..bar = 42).last, const Symbol('bar='), [42]);
|
|
testInvocationMirror(n.bar(), const Symbol('bar'), [], []);
|
|
testInvocationMirror(n.bar(42), const Symbol('bar'), [42], []);
|
|
testInvocationMirror(
|
|
n.bar(x: 42), const Symbol('bar'), [], [const Symbol("x"), 42]);
|
|
testInvocationMirror(
|
|
n.bar(37, x: 42), const Symbol('bar'), [37], [const Symbol("x"), 42]);
|
|
|
|
// Missing operator access.
|
|
testInvocationMirror(n + 4, const Symbol('+'), [4], []);
|
|
testInvocationMirror(n - 4, const Symbol('-'), [4], []);
|
|
testInvocationMirror(-n, const Symbol('unary-'), [], []);
|
|
testInvocationMirror(n[42], const Symbol('[]'), [42], []);
|
|
testInvocationMirror((n..[37] = 42).last, const Symbol('[]='), [37, 42], []);
|
|
|
|
// Calling as function when it's not.
|
|
testInvocationMirror(n(), const Symbol('call'), [], []);
|
|
testInvocationMirror(n(42), const Symbol('call'), [42], []);
|
|
testInvocationMirror(
|
|
n(x: 42), const Symbol('call'), [], [const Symbol("x"), 42]);
|
|
testInvocationMirror(
|
|
n(37, x: 42), const Symbol('call'), [37], [const Symbol("x"), 42]);
|
|
|
|
// Calling with arguments not matching existing call method.
|
|
testInvocationMirror(c(), const Symbol('call'), [], []);
|
|
testInvocationMirror(c(37, 42), const Symbol('call'), [37, 42], []);
|
|
testInvocationMirror(
|
|
c(x: 42), const Symbol('call'), [], [const Symbol("x"), 42]);
|
|
testInvocationMirror(
|
|
c(37, x: 42), const Symbol('call'), [37], [const Symbol("x"), 42]);
|
|
|
|
// Wrong arguments to existing function.
|
|
testInvocationMirror(n.flif(), const Symbol("flif"), [], []);
|
|
testInvocationMirror(n.flif(37, 42), const Symbol("flif"), [37, 42], []);
|
|
testInvocationMirror(
|
|
n.flif(x: 42), const Symbol("flif"), [], [const Symbol("x"), 42]);
|
|
testInvocationMirror(
|
|
n.flif(37, x: 42), const Symbol("flif"), [37], [const Symbol("x"), 42]);
|
|
testInvocationMirror((n..flif = 42).last, const Symbol("flif="), [42]);
|
|
|
|
testInvocationMirror(n.flaf(37, 42), const Symbol("flaf"), [37, 42], []);
|
|
testInvocationMirror(
|
|
n.flaf(x: 42), const Symbol("flaf"), [], [const Symbol("x"), 42]);
|
|
testInvocationMirror(
|
|
n.flaf(37, x: 42), const Symbol("flaf"), [37], [const Symbol("x"), 42]);
|
|
testInvocationMirror((n..flaf = 42).last, const Symbol("flaf="), [42]);
|
|
|
|
testInvocationMirror(n.flof(37, 42), const Symbol("flof"), [37, 42], []);
|
|
testInvocationMirror(
|
|
n.flof(x: 42), const Symbol("flof"), [], [const Symbol("x"), 42]);
|
|
testInvocationMirror(
|
|
n.flof(37, y: 42), const Symbol("flof"), [37], [const Symbol("y"), 42]);
|
|
testInvocationMirror((n..flof = 42).last, const Symbol("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, const Symbol("wut="), [42]);
|
|
testInvocationMirror((n..plif = 42).last, const Symbol("plif="), [42]);
|
|
testInvocationMirror((n..plaf = 42).last, const Symbol("plaf="), [42]);
|
|
|
|
// Trick call to n.call - wut is a getter returning n again.
|
|
testInvocationMirror(n.wut(42), const Symbol("call"), [42], []);
|
|
|
|
// Calling noSuchMethod itself, badly.
|
|
testInvocationMirror(n.noSuchMethod(), const Symbol("noSuchMethod"), [], []);
|
|
testInvocationMirror(
|
|
n.noSuchMethod(37, 42), const Symbol("noSuchMethod"), [37, 42], []);
|
|
testInvocationMirror(n.noSuchMethod(37, x: 42), const Symbol("noSuchMethod"),
|
|
[37], [const Symbol("x"), 42]);
|
|
testInvocationMirror(n.noSuchMethod(x: 42), const Symbol("noSuchMethod"), [],
|
|
[const Symbol("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.throwsNoSuchMethodError(() {
|
|
var x = n.flif;
|
|
x(37, 42);
|
|
});
|
|
Expect.throwsNoSuchMethodError(() {
|
|
var x = c.call;
|
|
x(37, 42);
|
|
});
|
|
}
|
|
|
|
class M extends N {
|
|
testSelfCalls() {
|
|
// Missing property/method access.
|
|
dynamic self = this;
|
|
testInvocationMirror(self.bar, const Symbol('bar'));
|
|
testInvocationMirror(() {
|
|
self.bar = 42;
|
|
return last;
|
|
}(), const Symbol('bar='), [42]);
|
|
testInvocationMirror(self.bar(), const Symbol('bar'), [], []);
|
|
testInvocationMirror(self.bar(42), const Symbol('bar'), [42], []);
|
|
testInvocationMirror(
|
|
self.bar(x: 42), const Symbol('bar'), [], [const Symbol("x"), 42]);
|
|
testInvocationMirror(self.bar(37, x: 42), const Symbol('bar'), [37],
|
|
[const Symbol("x"), 42]);
|
|
|
|
// Missing operator access.
|
|
testInvocationMirror(self + 4, const Symbol('+'), [4], []);
|
|
testInvocationMirror(self - 4, const Symbol('-'), [4], []);
|
|
testInvocationMirror(-self, const Symbol('unary-'), [], []);
|
|
testInvocationMirror(self[42], const Symbol('[]'), [42], []);
|
|
testInvocationMirror(() {
|
|
self[37] = 42;
|
|
return last;
|
|
}(), const Symbol('[]='), [37, 42], []);
|
|
|
|
// Wrong arguments to existing function.
|
|
testInvocationMirror(self.flif(), const Symbol("flif"), [], []);
|
|
testInvocationMirror(self.flif(37, 42), const Symbol("flif"), [37, 42], []);
|
|
testInvocationMirror(
|
|
self.flif(x: 42), const Symbol("flif"), [], [const Symbol("x"), 42]);
|
|
testInvocationMirror(self.flif(37, x: 42), const Symbol("flif"), [37],
|
|
[const Symbol("x"), 42]);
|
|
testInvocationMirror(() {
|
|
self.flif = 42;
|
|
return last;
|
|
}(), const Symbol("flif="), [42]);
|
|
|
|
testInvocationMirror(self.flaf(37, 42), const Symbol("flaf"), [37, 42], []);
|
|
testInvocationMirror(
|
|
self.flaf(x: 42), const Symbol("flaf"), [], [const Symbol("x"), 42]);
|
|
testInvocationMirror(self.flaf(37, x: 42), const Symbol("flaf"), [37],
|
|
[const Symbol("x"), 42]);
|
|
testInvocationMirror(() {
|
|
self.flaf = 42;
|
|
return last;
|
|
}(), const Symbol("flaf="), [42]);
|
|
|
|
testInvocationMirror(self.flof(37, 42), const Symbol("flof"), [37, 42], []);
|
|
testInvocationMirror(
|
|
self.flof(x: 42), const Symbol("flof"), [], [const Symbol("x"), 42]);
|
|
testInvocationMirror(self.flof(37, y: 42), const Symbol("flof"), [37],
|
|
[const Symbol("y"), 42]);
|
|
testInvocationMirror(() {
|
|
self.flof = 42;
|
|
return last;
|
|
}(), const Symbol("flof="), [42]);
|
|
|
|
// Reading works.
|
|
Expect.isTrue(self.flif is Function);
|
|
Expect.isTrue(self.flaf is Function);
|
|
Expect.isTrue(self.flof is Function);
|
|
|
|
// Writing to read-only fields.
|
|
testInvocationMirror(() {
|
|
self.wut = 42;
|
|
return last;
|
|
}(), const Symbol("wut="), [42]);
|
|
testInvocationMirror(() {
|
|
self.plif = 42;
|
|
return last;
|
|
}(), const Symbol("plif="), [42]);
|
|
testInvocationMirror(() {
|
|
self.plaf = 42;
|
|
return last;
|
|
}(), const Symbol("plaf="), [42]);
|
|
|
|
// Calling noSuchMethod itself, badly.
|
|
testInvocationMirror(
|
|
self.noSuchMethod(), const Symbol("noSuchMethod"), [], []);
|
|
testInvocationMirror(
|
|
self.noSuchMethod(37, 42), const Symbol("noSuchMethod"), [37, 42], []);
|
|
testInvocationMirror(self.noSuchMethod(37, x: 42),
|
|
const Symbol("noSuchMethod"), [37], [const Symbol("x"), 42]);
|
|
testInvocationMirror(self.noSuchMethod(x: 42), const Symbol("noSuchMethod"),
|
|
[], [const Symbol("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.throwsNoSuchMethodError(() {
|
|
var x = self.flif;
|
|
x(37, 42);
|
|
});
|
|
}
|
|
}
|
|
|
|
// Test the NoSuchMethodError thrown by different incorrect calls.
|
|
testNoSuchMethodErrors() {
|
|
dynamic n = new N();
|
|
dynamic o = new Object();
|
|
Expect.throwsNoSuchMethodError(() => o.bar);
|
|
Expect.throwsNoSuchMethodError(() => o.bar = 42);
|
|
Expect.throwsNoSuchMethodError(() => o.bar());
|
|
Expect.throwsNoSuchMethodError(() => o + 2);
|
|
Expect.throwsNoSuchMethodError(() => -o);
|
|
Expect.throwsNoSuchMethodError(() => o[0]);
|
|
Expect.throwsNoSuchMethodError(() => o[0] = 42);
|
|
Expect.throwsNoSuchMethodError(() => o());
|
|
Expect.throwsNoSuchMethodError(() => o.toString = 42);
|
|
Expect.throwsNoSuchMethodError(() => o.toString(42));
|
|
Expect.throwsNoSuchMethodError(() => o.toString(x: 37));
|
|
Expect.throwsNoSuchMethodError(() => o.hashCode = 42);
|
|
Expect.throwsNoSuchMethodError(() => (n.flif)()); // Extracted method has no noSuchMethod.
|
|
}
|
|
|
|
main() {
|
|
testInvocationMirrors();
|
|
testNoSuchMethodErrors();
|
|
new M().testSelfCalls();
|
|
}
|