| // 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. |
| |
| import 'native_testing.dart'; |
| |
| // Test that hidden native exception classes can be marked as existing. |
| // |
| // To infer which native hidden types exist, we need |
| // (1) return types of native methods and getters |
| // (2) argument types of callbacks |
| // (3) exceptions thrown by the operation. |
| // |
| // (1) and (2) can be achieved by having nicely typed native methods, but there |
| // is no place in the Dart language to communicate (3). So we use the following |
| // fake body technique. |
| |
| // The exception type. |
| @Native("E") |
| class E { |
| E._used() native; // Bogus native constructor, called only from fake body. |
| |
| int get code native; |
| } |
| |
| // Type with exception-throwing methods. |
| @Native("A") |
| class A { |
| // Exception class E is created. |
| @Creates("E") |
| @Returns('int') |
| op(int x) native; |
| } |
| |
| // This class is here just so that a dynamic context is polymorphic. |
| class B { |
| int get code => 666; |
| op(String x) => 123; |
| } |
| |
| makeA() native; |
| |
| void setup1() { |
| JS('', r""" |
| (function(){ |
| // Ensure we are not relying on global names 'A' and 'E'. |
| A = null; |
| E = null; |
| })()"""); |
| applyTestExtensions(['E', 'A']); |
| } |
| |
| void setup2() { |
| JS('', r""" |
| (function(){ |
| // This code is all inside 'setup2' and so not accessible from the global scope. |
| function E(x){ this.code = x; } |
| |
| function A(){} |
| A.prototype.op = function (x) { |
| if (x & 1) throw new E(100); |
| return x / 2; |
| }; |
| self.makeA = function(){return new A()}; |
| |
| self.nativeConstructor(E); |
| self.nativeConstructor(A); |
| })()"""); |
| } |
| |
| int inscrutable(int x) => x == 0 ? 0 : x | inscrutable(x & (x - 1)); |
| |
| main() { |
| nativeTesting(); |
| setup1(); |
| setup2(); |
| |
| var things = [makeA(), new B()]; |
| var a = things[inscrutable(0)]; |
| var b = things[inscrutable(1)]; |
| |
| Expect.equals(25, a.op(50)); |
| Expect.equals(123, b.op('hello')); |
| Expect.equals(666, b.code); |
| |
| bool threw = false; |
| try { |
| var x = a.op(51); |
| } catch (e) { |
| threw = true; |
| Expect.isTrue(e is E); |
| Expect.equals(100, (e as E).code); |
| } |
| Expect.isTrue(threw); |
| |
| // Again, but with statically typed receivers. |
| A aa = a; |
| B bb = b; |
| |
| Expect.equals(25, aa.op(50)); |
| Expect.equals(123, bb.op('hello')); |
| Expect.equals(666, bb.code); |
| |
| threw = false; |
| try { |
| var x = aa.op(51); |
| } on E catch (e) { |
| threw = true; |
| Expect.equals(100, e.code); |
| Expect.isTrue(e is E); |
| } |
| Expect.isTrue(threw); |
| } |