// Copyright (c) 2013, 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"; import 'dart:_js_helper' show setNativeSubclassDispatchRecord; import 'dart:_interceptors' show findInterceptorForType, findConstructorForNativeSubclassType; // Test that subclasses of native classes can be initialized by calling the // 'upgrade' constructor. var trace = []; var log; @Native("A") class A { final a1 = log(101); // Only initialized IF named constructor called. get a2 native; // Initialized by native constructor. var a3; // Initialized only by A.two. var a4 = log(104); A.one(); A.two() : a3 = log(103) { log('body(A.two)'); log(a4 += increment); } A.three(x, this.a4) { log('body(A.three)'); log(a4 = '($a4, $x)'); } get increment => 10; } class B extends A { var b1; final b2 = log(202); var b3; B.one() : super.one(); B.two() : b1 = log(201), b3 = log(203), super.two() { log('body(B.two)'); } B.three([x]) : super.three(205, x); get increment => 20; } makeB() native; @Creates('=Object') getBPrototype() native; void setup() { JS('', r""" (function(){ function B() { this.a2 = 102; } self.makeB = function(){return new B()}; self.getBPrototype = function(){return B.prototype;}; })()"""); } test_one() { trace = []; var constructor = findConstructorForNativeSubclassType(B, 'one'); Expect.isNotNull(constructor); Expect.isNull(findConstructorForNativeSubclassType(B, 'Missing')); var b = makeB(); Expect.isTrue(b is B); // Call constructor to initialize native object. var b2 = JS('', '#(#)', constructor, b); Expect.identical(b, b2); Expect.isTrue(b is B); Expect.equals(101, b.a1); Expect.equals(102, b.a2); Expect.equals(null, b.a3); Expect.equals(104, b.a4); Expect.equals(null, b.b1); Expect.equals(202, b.b2); Expect.equals(null, b.b3); Expect.equals('[202, 101, 104]', '$trace'); } test_two() { trace = []; var constructor = findConstructorForNativeSubclassType(B, 'two'); Expect.isNotNull(constructor); var b = makeB(); Expect.isTrue(b is B); // Call constructor to initialize native object. JS('', '#(#)', constructor, b); Expect.isTrue(b is B); Expect.equals(101, b.a1); Expect.equals(102, b.a2); Expect.equals(103, b.a3); Expect.equals(124, b.a4); Expect.equals(201, b.b1); Expect.equals(202, b.b2); Expect.equals(203, b.b3); Expect.equals( '[202, 201, 101, 104, 103, 203, body(A.two), 124, body(B.two)]', '$trace', ); } test_three() { trace = []; var constructor = findConstructorForNativeSubclassType(B, 'three'); Expect.isNotNull(constructor); var b = makeB(); Expect.isTrue(b is B); // Call constructor to initialize native object. // // Since the constructor takes some optional arguments that are not passed, it // is as though the web components runtime explicitly passed `null` for all // parameters. // // TODO(sra): The constructor returned by findConstructorForNativeSubclassType // should be a function that fills in the default values. JS('', '#(#)', constructor, b); Expect.isTrue(b is B); Expect.equals(101, b.a1); Expect.equals(102, b.a2); Expect.equals(null, b.a3); Expect.equals('(null, 205)', b.a4); Expect.equals(null, b.b1); Expect.equals(202, b.b2); Expect.equals(null, b.b3); print(trace); Expect.equals('[202, 101, 104, body(A.three), (null, 205)]', '$trace'); } test_new() { trace = []; checkThrows(action, description) { Expect.throws(action, (e) => true, "'$description must fail'"); } checkThrows(() => new B.one(), 'new B.one()'); checkThrows(() => new B.two(), 'new B.two()'); checkThrows(() => new B.three(), 'new B.three()'); checkThrows(() => new B.three(1), 'new B.three(1)'); checkThrows(() => new B.three([]), 'new B.three([])'); } main() { nativeTesting(); setup(); log = (message) { trace.add('$message'); return message; }; setNativeSubclassDispatchRecord(getBPrototype(), findInterceptorForType(B)); test_one(); test_two(); test_three(); test_new(); }