| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 // InvocationMirror and noSuchMethod testing. | 5 // InvocationMirror and noSuchMethod testing. |
| 6 | 6 |
| 7 /** Class with noSuchMethod that returns the mirror */ | 7 /** Class with noSuchMethod that returns the mirror */ |
| 8 class N { | 8 class N { |
| 9 noSuchMethod(InvocationMirror m) => m; | 9 // Storage for the last argument to noSuchMethod. |
| 10 // Needed for setters, which don't evaluate to the return value. |
| 11 var last; |
| 12 noSuchMethod(InvocationMirror m) => last = m; |
| 10 | 13 |
| 11 get wut => this; | 14 get wut => this; |
| 12 | 15 |
| 13 flif(int x) { Expect.fail("never get here"); } | 16 flif(int x) { Expect.fail("never get here"); } |
| 14 flaf([int x]) { Expect.fail("never get here"); } | 17 flaf([int x]) { Expect.fail("never get here"); } |
| 15 flof({int y}) { Expect.fail("never get here"); } | 18 flof({int y}) { Expect.fail("never get here"); } |
| 16 | 19 |
| 17 final int plif = 99; | 20 final int plif = 99; |
| 18 int get plaf { Expect.fail("never get here"); return 0; } | 21 int get plaf { Expect.fail("never get here"); return 0; } |
| 19 } | 22 } |
| 20 | 23 |
| 21 /** As [N] but also implements 'call', so we can call it with wrong arguments.*/ | 24 /** As [N] but also implements 'call', so we can call it with wrong arguments.*/ |
| 22 class C extends N { | 25 class C extends N { |
| 23 call(int x) { Expect.fail("never get here"); } | 26 call(int x) { Expect.fail("never get here"); } |
| 24 } | 27 } |
| 25 | 28 |
| 29 |
| 30 /** Class with a variety of static members and constructors. */ |
| 31 class Statics { |
| 32 Statics(int x); |
| 33 int get foo => throw "not called!"; |
| 34 static final bar = 42; |
| 35 static const baz = 87; |
| 36 static int method(int x) => x; |
| 37 static int call() => 37; |
| 38 } |
| 39 |
| 26 /** | 40 /** |
| 27 * Checks the data of an InvocationMirror. | 41 * Checks the data of an InvocationMirror. |
| 28 * | 42 * |
| 29 * Call without optionals for getters, with only positional for setters, | 43 * Call without optionals for getters, with only positional for setters, |
| 30 * and with both optionals for everything else. | 44 * and with both optionals for everything else. |
| 31 */ | 45 */ |
| 32 testInvocationMirror(InvocationMirror im, String name, | 46 testInvocationMirror(InvocationMirror im, String name, |
| 33 [List positional, Map named]) { | 47 [List positional, Map named]) { |
| 34 Expect.isTrue(im is InvocationMirror); | 48 Expect.isTrue(im is InvocationMirror, "is InvocationMirror"); |
| 35 Expect.equals(name, im.memberName); | 49 Expect.equals(name, im.memberName, "name"); |
| 36 if (named == null) { | 50 if (named == null) { |
| 37 Expect.isTrue(im.isAccessor); | 51 Expect.isTrue(im.isAccessor, "$name:isAccessor"); |
| 38 Expect.isFalse(im.isMethod); | 52 Expect.isFalse(im.isMethod, "$name:isMethod"); |
| 39 if (positional == null) { | 53 if (positional == null) { |
| 40 Expect.isTrue(im.isGetter); | 54 Expect.isTrue(im.isGetter, "$name:isGetter"); |
| 41 Expect.isFalse(im.isSetter); | 55 Expect.isFalse(im.isSetter, "$name:isSetter"); |
| 42 Expect.equals(null, im.positionalArguments); | 56 Expect.equals(null, im.positionalArguments, "$name:positional"); |
| 43 Expect.equals(null, im.positionalArguments); | 57 Expect.equals(null, im.namedArguments, "$name:named"); |
| 44 return; | 58 return; |
| 45 } | 59 } |
| 46 Expect.isTrue(im.isSetter); | 60 Expect.isTrue(im.isSetter, "$name:isSetter"); |
| 47 Expect.isFalse(im.isGetter); | 61 Expect.isFalse(im.isGetter, "$name:isGetter"); |
| 48 Expect.equals(1, im.positionalArguments.length); | 62 Expect.equals(1, im.positionalArguments.length, "$name:#positional"); |
| 49 Expect.equals(positional[0], im.positionalArguments[0]); | 63 Expect.equals(positional[0], im.positionalArguments[0], |
| 50 Expect.equals(null, im.namedArguments); | 64 "$name:positional[0]"); |
| 65 Expect.equals(null, im.namedArguments, "$name:named"); |
| 51 return; | 66 return; |
| 52 } | 67 } |
| 53 Expect.isTrue(im.isMethod); | 68 Expect.isTrue(im.isMethod, "$name:isMethod"); |
| 54 Expect.isFalse(im.isAccessor); | 69 Expect.isFalse(im.isAccessor, "$name:isAccessor"); |
| 55 Expect.isFalse(im.isSetter); | 70 Expect.isFalse(im.isSetter, "$name:isSetter"); |
| 56 Expect.isFalse(im.isGetter); | 71 Expect.isFalse(im.isGetter, "$name:isGetter"); |
| 57 | 72 |
| 58 Expect.equals(positional.length, im.positionalArguments.length); | 73 Expect.equals(positional.length, im.positionalArguments.length); |
| 59 for (int i = 0; i < positional.length; i++) { | 74 for (int i = 0; i < positional.length; i++) { |
| 60 Expect.equals(positional[i], im.positionalArguments[i]); | 75 Expect.equals(positional[i], im.positionalArguments[i], |
| 76 "$name:positional[$i]"); |
| 61 } | 77 } |
| 62 Expect.equals(named.length, im.namedArguments.length); | 78 Expect.equals(named.length, im.namedArguments.length, "$name:#named"); |
| 63 named.forEach((k, v) { | 79 named.forEach((k, v) { |
| 64 Expect.isTrue(im.namedArguments.containsKey(k)); | 80 Expect.isTrue(im.namedArguments.containsKey(k), "$name:?named[$k]"); |
| 65 Expect.equals(v, im.namedArguments[k]); | 81 Expect.equals(v, im.namedArguments[k], "$name:named[$k]"); |
| 66 }); | 82 }); |
| 67 } | 83 } |
| 68 | 84 |
| 69 | 85 |
| 70 // Test different ways that noSuchMethod can be called. | 86 // Test different ways that noSuchMethod can be called. |
| 71 testInvocationMirrors() { | 87 testInvocationMirrors() { |
| 72 var n = new N(); | 88 var n = new N(); |
| 73 var c = new C(); | 89 var c = new C(); |
| 74 | 90 |
| 75 // Missing property/method access. | 91 // Missing property/method access. |
| 76 testInvocationMirror(n.bar, 'bar'); | 92 testInvocationMirror(n.bar, 'bar'); |
| 77 testInvocationMirror(n.bar = 42, 'bar=', [42]); | 93 testInvocationMirror((n..bar = 42).last, 'bar=', [42]); |
| 78 testInvocationMirror(n.bar(), 'bar', [], {}); | 94 testInvocationMirror(n.bar(), 'bar', [], {}); |
| 79 testInvocationMirror(n.bar(42), 'bar', [42], {}); | 95 testInvocationMirror(n.bar(42), 'bar', [42], {}); |
| 80 testInvocationMirror(n.bar(x: 42), 'bar', [], {"x": 42}); | 96 testInvocationMirror(n.bar(x: 42), 'bar', [], {"x": 42}); |
| 81 testInvocationMirror(n.bar(37, x: 42), 'bar', [37], {"x": 42}); | 97 testInvocationMirror(n.bar(37, x: 42), 'bar', [37], {"x": 42}); |
| 82 testInvocationMirror((n.bar)(), 'bar', [], {}); | 98 testInvocationMirror((n.bar)(), 'bar', [], {}); |
| 83 testInvocationMirror((n.bar)(42), 'bar', [42]); | 99 testInvocationMirror((n.bar)(42), 'bar', [42]); |
| 84 testInvocationMirror((n.bar)(x: 42), 'bar', [], {"x": 42}); | 100 testInvocationMirror((n.bar)(x: 42), 'bar', [], {"x": 42}); |
| 85 testInvocationMirror((n.bar)(37, x: 42), 'bar', [37], {"x": 42}); | 101 testInvocationMirror((n.bar)(37, x: 42), 'bar', [37], {"x": 42}); |
| 86 | 102 |
| 87 // Missing operator access. | 103 // Missing operator access. |
| 88 testInvocationMirror(n + 4, '+', [4], {}); | 104 testInvocationMirror(n + 4, '+', [4], {}); |
| 89 testInvocationMirror(n - 4, '-', [4], {}); | 105 testInvocationMirror(n - 4, '-', [4], {}); |
| 90 testInvocationMirror(-n, '+', [], {}); | 106 testInvocationMirror(-n, '-', [], {}); |
| 91 testInvocationMirror(n[42], '[]', [42], {}); | 107 testInvocationMirror(n[42], '[]', [42], {}); |
| 92 testInvocationMirror(n[37] = 42, '[]=', [37, 42], {}); | 108 testInvocationMirror((n..[37] = 42).last, '[]=', [37, 42], {}); |
| 93 | 109 |
| 94 // Calling as function when it's not. | 110 // Calling as function when it's not. |
| 95 testInvocationMirror(n(), 'call', [], {}); | 111 testInvocationMirror(n(), 'call', [], {}); |
| 96 testInvocationMirror(n(42), 'call', [42], {}); | 112 testInvocationMirror(n(42), 'call', [42], {}); |
| 97 testInvocationMirror(n(x: 42), 'call', [], {"x": 42}); | 113 testInvocationMirror(n(x: 42), 'call', [], {"x": 42}); |
| 98 testInvocationMirror(n(37, x: 42), 'call', [37], {"x": 42}); | 114 testInvocationMirror(n(37, x: 42), 'call', [37], {"x": 42}); |
| 99 | 115 |
| 100 // Calling with arguments not matching existing call method. | 116 // Calling with arguments not matching existing call method. |
| 101 testInvocationMirror(c(), 'call', [], {}); | 117 testInvocationMirror(c(), 'call', [], {}); |
| 102 testInvocationMirror(c(37, 42), 'call', [37, 42], {}); | 118 testInvocationMirror(c(37, 42), 'call', [37, 42], {}); |
| 103 testInvocationMirror(c(x: 42), 'call', [], {"x": 42}); | 119 testInvocationMirror(c(x: 42), 'call', [], {"x": 42}); |
| 104 testInvocationMirror(c(37, x: 42), 'call', [37], {"x": 42}); | 120 testInvocationMirror(c(37, x: 42), 'call', [37], {"x": 42}); |
| 105 | 121 |
| 106 // Wrong arguments to existing function. | 122 // Wrong arguments to existing function. |
| 107 testInvocationMirror(n.flif(), "flif", [], {}); | 123 testInvocationMirror(n.flif(), "flif", [], {}); |
| 108 testInvocationMirror(n.flif(37, 42), "flif", [37, 42], {}); | 124 testInvocationMirror(n.flif(37, 42), "flif", [37, 42], {}); |
| 109 testInvocationMirror(n.flif(x: 42), "flif", [], {"x": 42}); | 125 testInvocationMirror(n.flif(x: 42), "flif", [], {"x": 42}); |
| 110 testInvocationMirror(n.flif(37, x: 42), "flif", [37], {"x": 42}); | 126 testInvocationMirror(n.flif(37, x: 42), "flif", [37], {"x": 42}); |
| 111 testInvocationMirror(n.flif = 42, "flif=", [42]); | 127 testInvocationMirror((n..flif = 42).last, "flif=", [42]); |
| 112 | 128 |
| 113 testInvocationMirror(n.flaf(37, 42), "flaf", [37, 42], {}); | 129 testInvocationMirror(n.flaf(37, 42), "flaf", [37, 42], {}); |
| 114 testInvocationMirror(n.flaf(x: 42), "flaf", [], {"x": 42}); | 130 testInvocationMirror(n.flaf(x: 42), "flaf", [], {"x": 42}); |
| 115 testInvocationMirror(n.flaf(37, x: 42), "flaf", [37], {"x": 42}); | 131 testInvocationMirror(n.flaf(37, x: 42), "flaf", [37], {"x": 42}); |
| 116 testInvocationMirror(n.flaf = 42, "flaf=", [42]); | 132 testInvocationMirror((n..flaf = 42).last, "flaf=", [42]); |
| 117 | 133 |
| 118 testInvocationMirror(n.flof(37, 42), "flof", [37, 42], {}); | 134 testInvocationMirror(n.flof(37, 42), "flof", [37, 42], {}); |
| 119 testInvocationMirror(n.flof(x: 42), "flof", [], {"x": 42}); | 135 testInvocationMirror(n.flof(x: 42), "flof", [], {"x": 42}); |
| 120 testInvocationMirror(n.flof(37, y: 42), "flof", [37], {"y": 42}); | 136 testInvocationMirror(n.flof(37, y: 42), "flof", [37], {"y": 42}); |
| 121 testInvocationMirror(n.flof = 42, "flof=", [42]); | 137 testInvocationMirror((n..flof = 42).last, "flof=", [42]); |
| 122 | 138 |
| 123 // Reading works. | 139 // Reading works. |
| 124 Expect.isTrue(n.flif is Function); | 140 Expect.isTrue(n.flif is Function); |
| 125 Expect.isTrue(n.flaf is Function); | 141 Expect.isTrue(n.flaf is Function); |
| 126 Expect.isTrue(n.flof is Function); | 142 Expect.isTrue(n.flof is Function); |
| 127 | 143 |
| 128 // Writing to read-only fields. | 144 // Writing to read-only fields. |
| 129 testInvocationMirror(n.wut = 42, "wut=", [42]); | 145 testInvocationMirror((n..wut = 42).last, "wut=", [42]); |
| 130 testInvocationMirror(n.plif = 42, "plif=", [42]); | 146 testInvocationMirror((n..plif = 42).last, "plif=", [42]); |
| 131 testInvocationMirror(n.plaf = 42, "plaf=", [42]); | 147 testInvocationMirror((n..plaf = 42).last, "plaf=", [42]); |
| 132 | 148 |
| 133 // Trick call to n.call - wut is a getter returning n again. | 149 // Trick call to n.call - wut is a getter returning n again. |
| 134 testInvocationMirror(n.wut(42), "call", [42]); | 150 testInvocationMirror(n.wut(42), "call", [42], {}); |
| 135 | 151 |
| 136 // Closurizing a method means that calling it badly will not hit the | 152 // Closurizing a method means that calling it badly will not hit the |
| 137 // original receivers noSuchMethod, only the one inherited from Object | 153 // original receivers noSuchMethod, only the one inherited from Object |
| 138 // by the closure object. | 154 // by the closure object. |
| 139 Expect.throws(() { var x = n.flif; x(37, 42); }, | 155 Expect.throws(() { var x = n.flif; x(37, 42); }, |
| 140 (e) => e is NoSuchMethodError); | 156 (e) => e is NoSuchMethodError); |
| 141 Expect.throws(() { var x = c.call; x(37, 42); }, | 157 Expect.throws(() { var x = c.call; x(37, 42); }, |
| 142 (e) => e is NoSuchMethodError); | 158 (e) => e is NoSuchMethodError); |
| 143 } | 159 } |
| 144 | 160 |
| 145 // Test the NoSuchMethodError thrown by different incorrect calls. | 161 // Test the NoSuchMethodError thrown by different incorrect calls. |
| 146 testNoSuchMethodErrors() { | 162 testNoSuchMethodErrors() { |
| 147 test(Function block) { | 163 test(Function block) { |
| 148 Expect.throws(block, (e) => e is NoSuchMethodError); | 164 Expect.throws(block, (e) => e is NoSuchMethodError); |
| 149 } | 165 } |
| 150 | 166 |
| 167 // Static members. |
| 168 // Get, set or call non-existing static member or constructor. |
| 169 test(() => Statics.notThere); |
| 170 test(() => Statics.notThere = 42); |
| 171 test(() => Statics.notThere()); |
| 172 test(() => new Statics.notThere()); |
| 173 // Set existing non-settable member. |
| 174 test(() => Statics.foo = 42); |
| 175 test(() => Statics.bar = 42); |
| 176 test(() => Statics.baz = 42); |
| 177 test(() => Statics.method = 42); |
| 178 // Call existing method with incorrect arguments. |
| 179 test(() => Statics.method()); |
| 180 test(() => Statics.method(37, 42)); |
| 181 test(() => Statics.method(x: 42)); |
| 182 // Call constructor with incorrect arguments. |
| 183 test(() => new Statics()); |
| 184 test(() => new Statics(37, 42)); |
| 185 test(() => new Statics(x: 42)); |
| 186 |
| 151 var o = new Object(); | 187 var o = new Object(); |
| 188 // Instance members of Object (no custom noSuchMethod method). |
| 189 // Use non-existing instance members or operators. |
| 152 test(() => o.bar); | 190 test(() => o.bar); |
| 153 test(() => o.bar = 42); | 191 test(() => o.bar = 42); |
| 154 test(() => o.bar()); | 192 test(() => o.bar()); |
| 193 test(() => o()); |
| 194 test(() => o + 2); |
| 195 test(() => -o); |
| 196 test(() => o[0]); |
| 197 test(() => o[0] = 37); |
| 198 // Assign to existing member with no setter. |
| 155 test(() => o.toString = 42); | 199 test(() => o.toString = 42); |
| 200 test(() => o.hashCode = 42); |
| 201 // Call existing method with incorrect arguments. |
| 156 test(() => o.toString(42)); | 202 test(() => o.toString(42)); |
| 157 test(() => o.toString(x: 37)); | 203 test(() => o.toString(x: 37)); |
| 158 test(() => o.hashCode = 42); | 204 // Calling a getter calls the return value. |
| 159 test(() => o.hashCode()); // Thrown by int.noSuchMethod. | 205 test(() => o.hashCode()); // Thrown by int.noSuchMethod. |
| 160 test(() => o()); | |
| 161 } | 206 } |
| 162 | 207 |
| 163 main() { | 208 main() { |
| 164 testInvocationMirrors(); | 209 testInvocationMirrors(); |
| 210 // TODO(lrn): Test InvocationMirror of private property. |
| 165 testNoSuchMethodErrors(); | 211 testNoSuchMethodErrors(); |
| 166 } | 212 } |
| OLD | NEW |