| /* |
| * Copyright 2008 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package com.google.gwt.dev.jjs.test; |
| |
| import com.google.gwt.core.client.JavaScriptObject; |
| import com.google.gwt.junit.client.GWTTestCase; |
| |
| /** |
| * Tests {@link JavaScriptObject} and subclasses. |
| */ |
| public class JsoTest extends GWTTestCase { |
| |
| static class Bar extends JavaScriptObject { |
| public static int field; |
| |
| public static native String staticNative() /*-{ |
| return "nativeBar"; |
| }-*/; |
| |
| public static String staticValue() { |
| return "Bar" + field; |
| } |
| |
| protected Bar() { |
| } |
| |
| public final native String getBar() /*-{ |
| return this.bar; |
| }-*/; |
| |
| public final String value() { |
| return "Bar"; |
| } |
| } |
| |
| static final class ClinitStaticFieldFirst extends JavaScriptObject { |
| public static String[] FIELD = new String[]{"a","b","c"}; |
| protected ClinitStaticFieldFirst() { |
| } |
| public Object invokeInstanceMethod() { |
| if (FIELD == null) { |
| return null; |
| } |
| return FIELD; |
| } |
| public static Object invokeStaticMethod() { |
| if (FIELD == null) { |
| return null; |
| } |
| return FIELD; |
| } |
| } |
| |
| static final class ClinitInstanceMethodFirst extends JavaScriptObject { |
| public static String[] FIELD = new String[]{"a","b","c"}; |
| protected ClinitInstanceMethodFirst() { |
| } |
| public Object invokeInstanceMethod() { |
| if (FIELD == null) { |
| return null; |
| } |
| return FIELD; |
| } |
| public static Object invokeStaticMethod() { |
| if (FIELD == null) { |
| return null; |
| } |
| return FIELD; |
| } |
| } |
| |
| static final class ClinitStaticMethodFirst extends JavaScriptObject { |
| public static String[] FIELD = new String[]{"a","b","c"}; |
| protected ClinitStaticMethodFirst() { |
| } |
| public Object invokeInstanceMethod() { |
| if (FIELD == null) { |
| return null; |
| } |
| return FIELD; |
| } |
| public static Object invokeStaticMethod() { |
| if (FIELD == null) { |
| return null; |
| } |
| return FIELD; |
| } |
| } |
| |
| static class Foo extends JavaScriptObject { |
| public static int field; |
| |
| public static native String staticNative() /*-{ |
| return "nativeFoo"; |
| }-*/; |
| |
| /** |
| * Ensure that a supertype can refer to members of a subtype. |
| */ |
| public static native String staticNativeToSub() /*-{ |
| return @com.google.gwt.dev.jjs.test.JsoTest.FooSub::staticValueSub()(); |
| }-*/; |
| |
| public static String staticValue() { |
| return "Foo" + field; |
| } |
| |
| protected Foo() { |
| } |
| |
| public final native String getFoo() /*-{ |
| return this.foo; |
| }-*/; |
| |
| public final String value() { |
| return "Foo"; |
| } |
| } |
| |
| static class FooSub extends Foo { |
| static String staticValueSub() { |
| return "FooSub"; |
| } |
| |
| protected FooSub() { |
| } |
| |
| public final String anotherValue() { |
| return "Still Foo"; |
| } |
| |
| public final String superCall() { |
| return super.value(); |
| } |
| } |
| |
| static class JsArray<T> extends JavaScriptObject { |
| public static native <T> JsArray<T> create() /*-{ |
| return []; |
| }-*/; |
| |
| protected JsArray() { |
| } |
| |
| public final native T get(int index) /*-{ |
| return this[index]; |
| }-*/; |
| |
| public final native int length() /*-{ |
| return this.length; |
| }-*/; |
| |
| public final native void put(int index, T value) /*-{ |
| this[index] = value; |
| }-*/; |
| } |
| |
| static class MethodMangleClash { |
| @SuppressWarnings("unused") |
| public static String func(JavaScriptObject this_) { |
| return "funcJavaScriptObject"; |
| } |
| |
| @SuppressWarnings("unused") |
| public static String func(MethodMangleClash this_) { |
| return "funcMethodMangleClash"; |
| } |
| |
| @SuppressWarnings("unused") |
| public String func() { |
| return "func"; |
| } |
| } |
| |
| static class Overloads { |
| private static volatile boolean FALSE = false; |
| |
| @SuppressWarnings("unused") |
| static String sFunc(Bar b) { |
| return "sFunc Bar"; |
| } |
| |
| @SuppressWarnings("unused") |
| static String sFunc(Bar[][] b) { |
| return "sFunc Bar[][]"; |
| } |
| |
| @SuppressWarnings("unused") |
| static String sFunc(Foo f) { |
| return "sFunc Foo"; |
| } |
| |
| @SuppressWarnings("unused") |
| static String sFunc(Foo[][] f) { |
| return "sFunc Foo[][]"; |
| } |
| |
| @SuppressWarnings("unused") |
| public Overloads(Bar b) { |
| } |
| |
| @SuppressWarnings("unused") |
| public Overloads(Bar[][] b) { |
| } |
| |
| @SuppressWarnings("unused") |
| public Overloads(Foo f) { |
| } |
| |
| @SuppressWarnings("unused") |
| public Overloads(Foo[][] f) { |
| } |
| |
| @SuppressWarnings("unused") |
| String func(Bar b) { |
| if (FALSE) { |
| // prevent inlining |
| return func(b); |
| } |
| return "func Bar"; |
| } |
| |
| @SuppressWarnings("unused") |
| String func(Bar[][] b) { |
| if (FALSE) { |
| // prevent inlining |
| return func(b); |
| } |
| return "func Bar[][]"; |
| } |
| |
| @SuppressWarnings("unused") |
| String func(Foo f) { |
| if (FALSE) { |
| // prevent inlining |
| return func(f); |
| } |
| return "func Foo"; |
| } |
| |
| @SuppressWarnings("unused") |
| String func(Foo[][] f) { |
| if (FALSE) { |
| // prevent inlining |
| return func(f); |
| } |
| return "func Foo[][]"; |
| } |
| } |
| |
| private static native Bar makeBar() /*-{ |
| return { |
| toString:function() { |
| return "bar"; |
| }, |
| bar: "this is bar", |
| }; |
| }-*/; |
| |
| private static native Foo makeFoo() /*-{ |
| return { |
| toString:function() { |
| return "foo"; |
| }, |
| foo: "this is foo", |
| }; |
| }-*/; |
| |
| private static native JavaScriptObject makeJSO() /*-{ |
| return { |
| toString:function() { |
| return "jso"; |
| }, |
| foo: "jso foo", |
| bar: "jso bar", |
| }; |
| }-*/; |
| |
| private static native JavaScriptObject makeMixedArray() /*-{ |
| return [ |
| @com.google.gwt.dev.jjs.test.JsoTest::makeJSO()(), |
| "foo", |
| @com.google.gwt.dev.jjs.test.JsoTest::makeObject()(), |
| null |
| ]; |
| }-*/; |
| |
| private static Object makeObject() { |
| return new Object() { |
| @Override |
| public String toString() { |
| return "myObject"; |
| } |
| }; |
| } |
| |
| private static native JavaScriptObject returnMe(JavaScriptObject jso) /*-{ |
| return jso; |
| }-*/; |
| |
| @Override |
| public String getModuleName() { |
| return "com.google.gwt.dev.jjs.CompilerSuite"; |
| } |
| |
| public void testArrayInit() { |
| Object[] array = {makeJSO(), new Object(), ""}; |
| assertTrue(array[0] instanceof JavaScriptObject); |
| assertFalse(array[1] instanceof JavaScriptObject); |
| assertFalse(array[2] instanceof JavaScriptObject); |
| } |
| |
| public void testArrayStore() { |
| JavaScriptObject[] jsoArray = new JavaScriptObject[1]; |
| jsoArray[0] = makeJSO(); |
| jsoArray[0] = makeFoo(); |
| jsoArray[0] = makeBar(); |
| |
| Foo[] fooArray = new Foo[1]; |
| fooArray[0] = (Foo) makeJSO(); |
| fooArray[0] = makeFoo(); |
| fooArray[0] = makeBar().cast(); |
| |
| Bar[] barArray = new Bar[1]; |
| barArray[0] = (Bar) makeJSO(); |
| barArray[0] = makeBar(); |
| barArray[0] = makeFoo().cast(); |
| |
| Object[] objArray = jsoArray; |
| try { |
| objArray[0] = new Object(); |
| fail("Expected ArrayStoreException"); |
| } catch (ArrayStoreException expected) { |
| } |
| |
| objArray = new Object[1]; |
| objArray[0] = makeJSO(); |
| objArray[0] = makeFoo(); |
| objArray[0] = makeBar(); |
| |
| Foo[][] foo = new Foo[10][]; |
| Object[][] fooAsObject = foo; |
| fooAsObject[0] = new Bar[1]; |
| } |
| |
| public void testBasic() { |
| JavaScriptObject jso = makeJSO(); |
| assertEquals("jso", jso.toString()); |
| |
| Foo foo = (Foo) jso; |
| assertEquals("jso", foo.toString()); |
| assertEquals("jso foo", foo.getFoo()); |
| assertEquals("Foo", foo.value()); |
| |
| Bar bar = (Bar) jso; |
| assertEquals("jso", bar.toString()); |
| assertEquals("jso bar", bar.getBar()); |
| assertEquals("Bar", bar.value()); |
| |
| foo = makeFoo(); |
| assertEquals("foo", foo.toString()); |
| assertEquals("this is foo", foo.getFoo()); |
| assertEquals("Foo", foo.value()); |
| |
| bar = makeBar(); |
| assertEquals("bar", bar.toString()); |
| assertEquals("this is bar", bar.getBar()); |
| assertEquals("Bar", bar.value()); |
| } |
| |
| @SuppressWarnings("cast") |
| public void testCasts() { |
| JavaScriptObject jso = makeJSO(); |
| assertTrue(jso instanceof JavaScriptObject); |
| assertTrue(jso instanceof Foo); |
| assertTrue(jso instanceof Bar); |
| |
| Foo foo = (Foo) jso; |
| foo = makeFoo(); |
| assertTrue((JavaScriptObject) foo instanceof Bar); |
| Bar bar = (Bar) (JavaScriptObject) makeFoo(); |
| bar = makeFoo().cast(); |
| |
| bar = (Bar) jso; |
| bar = makeBar(); |
| assertTrue((JavaScriptObject) bar instanceof Foo); |
| foo = (Foo) (JavaScriptObject) makeBar(); |
| foo = makeBar().cast(); |
| |
| // Implicit |
| jso = foo; |
| jso = bar; |
| |
| Object o = new Object(); |
| assertFalse(o instanceof JavaScriptObject); |
| assertFalse(o instanceof Foo); |
| assertFalse(o instanceof Bar); |
| try { |
| jso = (JavaScriptObject) o; |
| fail("Expected ClassCastException"); |
| } catch (ClassCastException expected) { |
| } |
| |
| o = "foo"; |
| assertFalse(o instanceof JavaScriptObject); |
| assertFalse(o instanceof Foo); |
| assertFalse(o instanceof Bar); |
| try { |
| jso = (JavaScriptObject) o; |
| fail("Expected ClassCastException"); |
| } catch (ClassCastException expected) { |
| } |
| |
| o = jso; |
| assertFalse(o instanceof String); |
| try { |
| String s = (String) o; |
| s = s.toString(); |
| fail("Expected ClassCastException"); |
| } catch (ClassCastException expected) { |
| } |
| } |
| |
| @SuppressWarnings("cast") |
| public void testCastsArray() { |
| JavaScriptObject[][] jso = new JavaScriptObject[0][0]; |
| assertTrue(jso instanceof JavaScriptObject[][]); |
| assertTrue(jso instanceof Foo[][]); |
| assertTrue(jso instanceof Bar[][]); |
| |
| Foo[][] foo = (Foo[][]) jso; |
| foo = new Foo[0][0]; |
| assertTrue((JavaScriptObject[][]) foo instanceof Bar[][]); |
| Bar[][] bar = (Bar[][]) (JavaScriptObject[][]) new Foo[0][0]; |
| |
| bar = (Bar[][]) jso; |
| bar = new Bar[0][0]; |
| assertTrue((JavaScriptObject[][]) bar instanceof Foo[][]); |
| foo = (Foo[][]) (JavaScriptObject[][]) new Bar[0][0]; |
| |
| Object[][] o = new Object[0][0]; |
| assertFalse(o instanceof JavaScriptObject[][]); |
| assertFalse(o instanceof Foo[][]); |
| assertFalse(o instanceof Bar[][]); |
| try { |
| jso = (JavaScriptObject[][]) o; |
| fail("Expected ClassCastException"); |
| } catch (ClassCastException expected) { |
| } |
| |
| o = jso; |
| assertFalse(o instanceof String[][]); |
| try { |
| String[][] s = (String[][]) o; |
| s.getClass(); |
| fail("Expected ClassCastException"); |
| } catch (ClassCastException expected) { |
| } |
| } |
| |
| public void testClassInitializerRun() { |
| ClinitStaticMethodFirst staticMethodFirst = JavaScriptObject.createObject().cast(); |
| assertNotNull("static method", ClinitStaticMethodFirst.invokeStaticMethod()); |
| assertNotNull("instance method after static method", staticMethodFirst.invokeInstanceMethod()); |
| |
| ClinitStaticFieldFirst staticFieldFirst = JavaScriptObject.createObject().cast(); |
| assertNotNull("field access", ClinitStaticFieldFirst.FIELD); |
| assertNotNull("instance method after field access", staticFieldFirst.invokeInstanceMethod()); |
| |
| ClinitInstanceMethodFirst instanceMethodFirst = JavaScriptObject.createObject().cast(); |
| assertNotNull("instance method", instanceMethodFirst.invokeInstanceMethod()); |
| assertNotNull("static method after instance method", ClinitInstanceMethodFirst.invokeStaticMethod()); |
| } |
| |
| public void testClassLiterals() { |
| JavaScriptObject jso = makeJSO(); |
| Foo foo = makeFoo(); |
| Bar bar = makeBar(); |
| assertEquals(JavaScriptObject.class, jso.getClass()); |
| assertEquals(Foo.class, jso.getClass()); |
| assertEquals(Bar.class, jso.getClass()); |
| assertEquals(JavaScriptObject.class, foo.getClass()); |
| assertEquals(Foo.class, foo.getClass()); |
| assertEquals(Bar.class, foo.getClass()); |
| assertEquals(JavaScriptObject.class, bar.getClass()); |
| assertEquals(Foo.class, bar.getClass()); |
| assertEquals(Bar.class, bar.getClass()); |
| assertEquals(JavaScriptObject.class, Foo.class); |
| assertEquals(JavaScriptObject.class, Bar.class); |
| assertEquals(Foo.class, Bar.class); |
| |
| if (!JavaScriptObject.class.getName().startsWith("Class$")) { |
| // Class metadata could be disabled |
| assertEquals("com.google.gwt.core.client.JavaScriptObject$", |
| JavaScriptObject.class.getName()); |
| } |
| } |
| |
| public void testClassLiteralsArray() { |
| JavaScriptObject[][] jso = new JavaScriptObject[0][0]; |
| Foo[][] foo = new Foo[0][0]; |
| Bar[][] bar = new Bar[0][0]; |
| assertEquals(JavaScriptObject[][].class, jso.getClass()); |
| assertEquals(Foo[][].class, jso.getClass()); |
| assertEquals(Bar[][].class, jso.getClass()); |
| assertEquals(JavaScriptObject[][].class, foo.getClass()); |
| assertEquals(Foo[][].class, foo.getClass()); |
| assertEquals(Bar[][].class, foo.getClass()); |
| assertEquals(JavaScriptObject[][].class, bar.getClass()); |
| assertEquals(Foo[][].class, bar.getClass()); |
| assertEquals(Bar[][].class, bar.getClass()); |
| assertEquals(JavaScriptObject[][].class, Foo[][].class); |
| assertEquals(JavaScriptObject[][].class, Bar[][].class); |
| assertEquals(Foo[][].class, Bar[][].class); |
| |
| if (!JavaScriptObject.class.getName().startsWith("Class$")) { |
| // Class metadata could be disabled |
| assertEquals("[[Lcom.google.gwt.core.client.JavaScriptObject$;", |
| JavaScriptObject[][].class.getName()); |
| } |
| } |
| |
| static class MyJSO extends JavaScriptObject { |
| protected MyJSO() { |
| } |
| |
| public final boolean equalMethod(Object o) { |
| return this == o; |
| } |
| } |
| |
| public void testEquality() { |
| JavaScriptObject jso = makeJSO(); |
| assertEquals(jso, jso); |
| |
| JavaScriptObject jso2 = makeJSO(); |
| assertFalse(jso.equals(jso2)); |
| assertFalse(jso2.equals(jso)); |
| |
| jso2 = returnMe(jso); |
| assertEquals(jso, jso2); |
| |
| MyJSO jso3 = (MyJSO) makeJSO(); |
| MyJSO jso4 = (MyJSO) makeJSO(); |
| assertTrue(jso3.equalMethod(jso3)); |
| assertFalse(jso3.equalMethod(jso4)); |
| } |
| |
| public void testGenericsJsos() { |
| JsArray<JavaScriptObject> a = JsArray.create(); |
| a.put(0, makeJSO()); |
| a.put(1, makeFoo()); |
| a.put(2, makeBar()); |
| a.put(3, null); |
| assertEquals(4, a.length()); |
| assertEquals("jso", a.get(0).toString()); |
| assertEquals("foo", a.get(1).toString()); |
| assertEquals("bar", a.get(2).toString()); |
| assertEquals(null, a.get(3)); |
| } |
| |
| public void testGenericsMixed() { |
| JsArray<Object> a = JsArray.create(); |
| a.put(0, makeJSO()); |
| a.put(1, "foo"); |
| a.put(2, makeObject()); |
| a.put(3, null); |
| assertEquals(4, a.length()); |
| assertEquals("jso", a.get(0).toString()); |
| assertEquals("foo", a.get(1)); |
| assertEquals("myObject", a.get(2).toString()); |
| assertEquals(null, a.get(3)); |
| } |
| |
| @SuppressWarnings("unchecked") |
| public void testGenericsRawJson() { |
| JsArray a = (JsArray) makeMixedArray(); |
| assertEquals(4, a.length()); |
| assertEquals("jso", a.get(0).toString()); |
| assertEquals("foo", a.get(1)); |
| assertEquals("myObject", a.get(2).toString()); |
| assertEquals(null, a.get(3)); |
| } |
| |
| public void testGenericsStrings() { |
| JsArray<String> a = JsArray.create(); |
| a.put(0, "foo"); |
| a.put(1, "bar"); |
| a.put(2, "baz"); |
| a.put(3, null); |
| assertEquals(4, a.length()); |
| assertEquals("foo", a.get(0)); |
| assertEquals("bar", a.get(1)); |
| assertEquals("baz", a.get(2)); |
| assertEquals(null, a.get(3)); |
| } |
| |
| public void testHashCode() { |
| // TODO: make this better. |
| JavaScriptObject jso = makeJSO(); |
| int jsoHashCode = jso.hashCode(); |
| Foo foo = makeFoo(); |
| Bar bar = makeBar(); |
| Object o = new Object() { |
| @Override |
| public int hashCode() { |
| // Return something unlikely so as not to collide with the JSOs. |
| return 0xDEADBEEF; |
| } |
| }; |
| |
| assertEquals(jsoHashCode, jso.hashCode()); |
| assertFalse(jsoHashCode == foo.hashCode()); |
| assertFalse(jsoHashCode == bar.hashCode()); |
| assertFalse(jsoHashCode == o.hashCode()); |
| assertFalse(foo.hashCode() == bar.hashCode()); |
| assertFalse(foo.hashCode() == o.hashCode()); |
| assertFalse(bar.hashCode() == o.hashCode()); |
| |
| o = jso; |
| assertEquals(jsoHashCode, o.hashCode()); |
| |
| String s = "foo"; |
| int stringHashCode = s.hashCode(); |
| o = s; |
| assertEquals(stringHashCode, o.hashCode()); |
| } |
| |
| public void testIdentity() { |
| JavaScriptObject jso = makeJSO(); |
| assertSame(jso, jso); |
| |
| JavaScriptObject jso2 = makeJSO(); |
| assertNotSame(jso, jso2); |
| |
| jso2 = returnMe(jso); |
| assertSame(jso, jso2); |
| } |
| |
| public void testInheritance() { |
| Foo foo = makeFoo(); |
| FooSub fooSub = (FooSub) foo; |
| assertEquals("Foo", fooSub.value()); |
| assertEquals("Still Foo", fooSub.anotherValue()); |
| assertEquals("Foo", fooSub.superCall()); |
| } |
| |
| public void testMethodMangleClash() { |
| assertEquals("funcJavaScriptObject", |
| MethodMangleClash.func((JavaScriptObject) null)); |
| assertEquals("funcMethodMangleClash", |
| MethodMangleClash.func((MethodMangleClash) null)); |
| assertEquals("func", new MethodMangleClash().func()); |
| } |
| |
| public void testOverloads() { |
| Foo foo = makeFoo(); |
| assertEquals("func Foo", new Overloads(foo).func(foo)); |
| assertEquals("sFunc Foo", Overloads.sFunc(foo)); |
| |
| Bar bar = makeBar(); |
| assertEquals("func Bar", new Overloads(bar).func(bar)); |
| assertEquals("sFunc Bar", Overloads.sFunc(bar)); |
| } |
| |
| public void testOverloadsArray() { |
| Foo[][] foo = new Foo[0][0]; |
| assertEquals("func Foo[][]", new Overloads(foo).func(foo)); |
| assertEquals("sFunc Foo[][]", Overloads.sFunc(foo)); |
| |
| Bar[][] bar = new Bar[0][0]; |
| assertEquals("func Bar[][]", new Overloads(bar).func(bar)); |
| assertEquals("sFunc Bar[][]", Overloads.sFunc(bar)); |
| } |
| |
| public native void testOverloadsArrayNative() /*-{ |
| var o = @com.google.gwt.dev.jjs.test.JsoTest.Overloads::new([[Lcom/google/gwt/dev/jjs/test/JsoTest$Foo;)(null); |
| @junit.framework.Assert::assertEquals(Ljava/lang/Object;Ljava/lang/Object;)("func Foo[][]", o.@com.google.gwt.dev.jjs.test.JsoTest.Overloads::func([[Lcom/google/gwt/dev/jjs/test/JsoTest$Foo;)(null)); |
| @junit.framework.Assert::assertEquals(Ljava/lang/Object;Ljava/lang/Object;)("sFunc Foo[][]", @com.google.gwt.dev.jjs.test.JsoTest.Overloads::sFunc([[Lcom/google/gwt/dev/jjs/test/JsoTest$Foo;)(null)); |
| |
| var o = @com.google.gwt.dev.jjs.test.JsoTest.Overloads::new([[Lcom/google/gwt/dev/jjs/test/JsoTest$Bar;)(null); |
| @junit.framework.Assert::assertEquals(Ljava/lang/Object;Ljava/lang/Object;)("func Bar[][]", o.@com.google.gwt.dev.jjs.test.JsoTest.Overloads::func([[Lcom/google/gwt/dev/jjs/test/JsoTest$Bar;)(null)); |
| @junit.framework.Assert::assertEquals(Ljava/lang/Object;Ljava/lang/Object;)("sFunc Bar[][]", @com.google.gwt.dev.jjs.test.JsoTest.Overloads::sFunc([[Lcom/google/gwt/dev/jjs/test/JsoTest$Bar;)(null)); |
| }-*/; |
| |
| public native void testOverloadsNative() /*-{ |
| var o = @com.google.gwt.dev.jjs.test.JsoTest.Overloads::new(Lcom/google/gwt/dev/jjs/test/JsoTest$Foo;)(null); |
| @junit.framework.Assert::assertEquals(Ljava/lang/Object;Ljava/lang/Object;)("func Foo", o.@com.google.gwt.dev.jjs.test.JsoTest.Overloads::func(Lcom/google/gwt/dev/jjs/test/JsoTest$Foo;)(null)); |
| @junit.framework.Assert::assertEquals(Ljava/lang/Object;Ljava/lang/Object;)("sFunc Foo", @com.google.gwt.dev.jjs.test.JsoTest.Overloads::sFunc(Lcom/google/gwt/dev/jjs/test/JsoTest$Foo;)(null)); |
| |
| var o = @com.google.gwt.dev.jjs.test.JsoTest.Overloads::new(Lcom/google/gwt/dev/jjs/test/JsoTest$Bar;)(null); |
| @junit.framework.Assert::assertEquals(Ljava/lang/Object;Ljava/lang/Object;)("func Bar", o.@com.google.gwt.dev.jjs.test.JsoTest.Overloads::func(Lcom/google/gwt/dev/jjs/test/JsoTest$Bar;)(null)); |
| @junit.framework.Assert::assertEquals(Ljava/lang/Object;Ljava/lang/Object;)("sFunc Bar", @com.google.gwt.dev.jjs.test.JsoTest.Overloads::sFunc(Lcom/google/gwt/dev/jjs/test/JsoTest$Bar;)(null)); |
| }-*/; |
| |
| public void testStaticAccess() { |
| Foo.field = 3; |
| assertEquals(3, Foo.field--); |
| assertEquals("Foo2", Foo.staticValue()); |
| assertEquals("nativeFoo", Foo.staticNative()); |
| assertEquals("FooSub", Foo.staticNativeToSub()); |
| |
| Bar.field = 10; |
| assertEquals(11, ++Bar.field); |
| assertEquals("Bar11", Bar.staticValue()); |
| assertEquals("nativeBar", Bar.staticNative()); |
| } |
| |
| public native void testStaticAccessNative() /*-{ |
| @com.google.gwt.dev.jjs.test.JsoTest.Foo::field = 3; |
| @junit.framework.Assert::assertEquals(II)(3, @com.google.gwt.dev.jjs.test.JsoTest.Foo::field--); |
| @junit.framework.Assert::assertEquals(Ljava/lang/Object;Ljava/lang/Object;)("Foo2", @com.google.gwt.dev.jjs.test.JsoTest.Foo::staticValue()()); |
| @junit.framework.Assert::assertEquals(Ljava/lang/Object;Ljava/lang/Object;)("nativeFoo", @com.google.gwt.dev.jjs.test.JsoTest.Foo::staticNative()()); |
| |
| @com.google.gwt.dev.jjs.test.JsoTest.Bar::field = 10; |
| @junit.framework.Assert::assertEquals(II)(11, ++@com.google.gwt.dev.jjs.test.JsoTest.Bar::field); |
| @junit.framework.Assert::assertEquals(Ljava/lang/Object;Ljava/lang/Object;)("Bar11", @com.google.gwt.dev.jjs.test.JsoTest.Bar::staticValue()()); |
| @junit.framework.Assert::assertEquals(Ljava/lang/Object;Ljava/lang/Object;)("nativeBar", @com.google.gwt.dev.jjs.test.JsoTest.Bar::staticNative()()); |
| }-*/; |
| |
| public void testStaticAccessSubclass() { |
| FooSub.field = 3; |
| assertEquals(3, FooSub.field--); |
| assertEquals("Foo2", FooSub.staticValue()); |
| assertEquals("nativeFoo", FooSub.staticNative()); |
| } |
| |
| static JavaScriptObject someObject; |
| static class JSO1 extends JavaScriptObject { |
| protected JSO1() { |
| } |
| static native JSO1 create() /*-{ |
| @com.google.gwt.dev.jjs.test.JsoTest::someObject = |
| @com.google.gwt.dev.jjs.test.JsoTest::someObject || []; |
| return @com.google.gwt.dev.jjs.test.JsoTest::someObject; |
| }-*/; |
| } |
| |
| static class JSO2 extends JavaScriptObject { |
| protected JSO2() { |
| } |
| static native JSO2 create() /*-{ |
| @com.google.gwt.dev.jjs.test.JsoTest::someObject = |
| @com.google.gwt.dev.jjs.test.JsoTest::someObject || []; |
| return @com.google.gwt.dev.jjs.test.JsoTest::someObject; |
| }-*/; |
| } |
| |
| /** |
| * Some final JSOs classes to make sure exactness (inferred from final) does not affect |
| * JSO cast semantics. |
| */ |
| static final class FinalJSO1 extends JavaScriptObject { |
| protected FinalJSO1() { |
| } |
| static native FinalJSO1 create() /*-{ |
| @com.google.gwt.dev.jjs.test.JsoTest::someObject = |
| @com.google.gwt.dev.jjs.test.JsoTest::someObject || []; |
| return @com.google.gwt.dev.jjs.test.JsoTest::someObject; |
| }-*/; |
| } |
| |
| static final class FinalJSO2 extends JavaScriptObject { |
| protected FinalJSO2() { |
| } |
| static native FinalJSO2 create() /*-{ |
| @com.google.gwt.dev.jjs.test.JsoTest::someObject = |
| @com.google.gwt.dev.jjs.test.JsoTest::someObject || []; |
| return @com.google.gwt.dev.jjs.test.JsoTest::someObject; |
| }-*/; |
| } |
| |
| interface I { |
| } |
| |
| /** |
| * A JSO class that is the sole implementor of an interface to make sure that the logic in |
| * {@link TypeTightener#getSingleConcreteType()} does not create an EXACT JSO type. |
| */ |
| static class JSOImplementingI extends JavaScriptObject implements I { |
| protected JSOImplementingI() { |
| } |
| static native I create() /*-{ |
| @com.google.gwt.dev.jjs.test.JsoTest::someObject = |
| @com.google.gwt.dev.jjs.test.JsoTest::someObject || []; |
| return @com.google.gwt.dev.jjs.test.JsoTest::someObject; |
| }-*/; |
| } |
| |
| /** |
| * Tests various crosscasting scenarios to make sure that casts are erased and not transformed |
| * into throws. |
| */ |
| public void testCrossCasting() { |
| JSO1 jso1 = JSO1.create(); |
| JSO2 jso2 = JSO2.create(); |
| FinalJSO1 finalJso1 = FinalJSO1.create(); |
| FinalJSO2 finalJso2 = FinalJSO2.create(); |
| I i = JSOImplementingI.create(); |
| |
| assertTrue(jso1 == (JSO1) (trueFn() ? jso2 : (JavaScriptObject) null)); |
| assertTrue(jso1 == (JSO1) (trueFn() ? i : (JavaScriptObject) null)); |
| assertTrue(jso1 == (JSO1) (trueFn() ? finalJso1 : (JavaScriptObject) null)); |
| assertTrue(jso1 == (JSO1) (trueFn() ? finalJso2 : (JavaScriptObject) null)); |
| |
| assertTrue(jso2 == (JSO2) (trueFn() ? jso1 : (JavaScriptObject) null)); |
| assertTrue(jso2 == (JSO2) (trueFn() ? i : (JavaScriptObject) null)); |
| assertTrue(jso2 == (JSO2) (trueFn() ? finalJso1 : (JavaScriptObject) null)); |
| assertTrue(jso2 == (JSO2) (trueFn() ? finalJso2 : (JavaScriptObject) null)); |
| |
| assertTrue(finalJso1 == (FinalJSO1) (trueFn() ? jso1 : (JavaScriptObject) null)); |
| assertTrue(finalJso1 == (FinalJSO1) (trueFn() ? i : (JavaScriptObject) null)); |
| assertTrue(finalJso1 == (FinalJSO1) (trueFn() ? jso2 : (JavaScriptObject) null)); |
| assertTrue(finalJso1 == (FinalJSO1) (trueFn() ? finalJso2 : (JavaScriptObject) null)); |
| |
| assertTrue(finalJso2 == (FinalJSO2) (trueFn() ? jso1 : (JavaScriptObject) null)); |
| assertTrue(finalJso2 == (FinalJSO2) (trueFn() ? i : (JavaScriptObject) null)); |
| assertTrue(finalJso2 == (FinalJSO2) (trueFn() ? jso2 : (JavaScriptObject) null)); |
| assertTrue(finalJso2 == (FinalJSO2) (trueFn() ? finalJso1 : (JavaScriptObject) null)); |
| |
| assertTrue(i == (I) (trueFn() ? jso1 : (JavaScriptObject) null)); |
| assertTrue(i == (I) (trueFn() ? jso2 : (JavaScriptObject) null)); |
| assertTrue(i == (I) (trueFn() ? finalJso1 : (JavaScriptObject) null)); |
| assertTrue(i == (I) (trueFn() ? finalJso2 : (JavaScriptObject) null)); |
| } |
| |
| /** |
| * |
| * Test that nullability optimizations don't break the assumption that null is considered a JSO. |
| */ |
| public void testNonNullableOptimization() { |
| // TODO(rluble): fix semantics to be more coherent by adding a nullness check for devirtualized |
| // methods in draft mode. |
| JavaScriptObject nullJso = (trueFn() ? null : JavaScriptObject.createArray()); |
| // This statement should throw NPE (at least in draft mode) but it does not due to JSO |
| // devirtualization. These semantics are exploited in GWT standard library. Improvemnts and |
| // fixes to optimization passes might break these assumptions. |
| JSO1 someJso = nullJso.cast(); |
| assertTrue(someJso == null); |
| } |
| |
| private boolean trueFn() { |
| return true; |
| } |
| } |