001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: /**********************
017: * *
018: * DO NOT FORMAT *
019: * *
020: **********************/package com.google.gwt.dev.jjs.test;
021:
022: import com.google.gwt.core.client.GWT;
023: import com.google.gwt.core.client.JavaScriptObject;
024: import com.google.gwt.junit.client.GWTTestCase;
025:
026: import java.util.AbstractList;
027: import java.util.ArrayList;
028: import java.util.Arrays;
029: import java.util.List;
030:
031: /**
032: * Tests several tricky aspects of hosted mode.
033: */
034: public class HostedTest extends GWTTestCase {
035:
036: /**
037: * Tests that we can use a source level name for a nested type instead of the
038: * binary name.
039: */
040: static class A {
041:
042: static class B {
043: int b = 1;
044:
045: public native int getUsingBinaryRef() /*-{
046: return this.@com.google.gwt.dev.jjs.test.HostedTest$A$B::b;
047: }-*/;
048:
049: public native int getUsingSourceRef() /*-{
050: return this.@com.google.gwt.dev.jjs.test.HostedTest.A.B::b;
051: }-*/;
052: }
053: }
054:
055: private static class TestGenericList extends AbstractList<Object> {
056: @Override
057: public Object get(int index) {
058: return this ;
059: }
060:
061: @Override
062: public int size() {
063: return 42;
064: }
065: }
066:
067: private static class TestCovariantChild extends TestCovariantSuper {
068: @Override
069: public native String foo(String val) /*-{
070: return val;
071: }-*/;
072: }
073:
074: private static class TestCovariantSuper {
075: public native Object foo(String val) /*-{
076: return val;
077: }-*/;
078: }
079:
080: private static enum TestEnum {
081: VAL1, VAL2, VAL3
082: }
083:
084: static String sFoo(String s) {
085: return s + "foo";
086: }
087:
088: private native static JavaScriptObject getBoxedBooleanAsObject(
089: boolean v) /*-{
090: return new Boolean(v);
091: }-*/;
092:
093: private native static JavaScriptObject getBoxedNumberAsObject(
094: double v) /*-{
095: return new Number(v);
096: }-*/;
097:
098: private native static JavaScriptObject getBoxedStringAsObject(
099: String v) /*-{
100: return new String(v);
101: }-*/;
102:
103: private native static String getBoxedStringAsString(String v) /*-{
104: return new String(v);
105: }-*/;
106:
107: private native static double getDouble(double v) /*-{
108: return -v;
109: }-*/;
110:
111: private static native float getFloat() /*-{
112: return myFloatValue;
113: }-*/;
114:
115: private static native float getFloatString() /*-{
116: return Number(myFloatValue.toString());
117: }-*/;
118:
119: private native static int getInt(int v) /*-{
120: return -v;
121: }-*/;
122:
123: // this should cause an exception
124: private static native Object getIntAsObject() /*-{
125: return 5;
126: }-*/;
127:
128: private native static String getJSOAsString(JavaScriptObject jso) /*-{
129: return "" + jso;
130: }-*/;
131:
132: private native static Object getObject(Object o) /*-{
133: return o;
134: }-*/;
135:
136: private static native JavaScriptObject getsFooFunc() /*-{
137: return @com.google.gwt.dev.jjs.test.HostedTest::sFoo(Ljava/lang/String;);
138: }-*/;
139:
140: private native static String getString(String s) /*-{
141: return s + "me";
142: }-*/;
143:
144: // ok to return JS string from an Object method
145: private static native Object getStringAsObject() /*-{
146: return "test";
147: }-*/;
148:
149: private native static int getStringLength(String s) /*-{
150: return s.length;
151: }-*/;
152:
153: private static native int passThroughInt(int val) /*-{
154: return val;
155: }-*/;
156:
157: private static native String sFooCall(String s) /*-{
158: var func = @com.google.gwt.dev.jjs.test.HostedTest::sFoo(Ljava/lang/String;);
159: return func.call(null, s);
160: }-*/;
161:
162: private static native String sFooDirect(String s) /*-{
163: return @com.google.gwt.dev.jjs.test.HostedTest::sFoo(Ljava/lang/String;)(s);
164: }-*/;
165:
166: private static native String sFooFuncAsStr() /*-{
167: var f = @com.google.gwt.dev.jjs.test.HostedTest::sFoo(Ljava/lang/String;);
168: return "" + f;
169: }-*/;
170:
171: private static native String sFooFuncToString() /*-{
172: var f = @com.google.gwt.dev.jjs.test.HostedTest::sFoo(Ljava/lang/String;);
173: return f.toString();
174: }-*/;
175:
176: private static native String sFooInvoke(String s) /*-{
177: var func = @com.google.gwt.dev.jjs.test.HostedTest::sFoo(Ljava/lang/String;);
178: return func(s);
179: }-*/;
180:
181: private static native String sFooRoundTrip(
182: JavaScriptObject fooFunc, String s) /*-{
183: return fooFunc(s);
184: }-*/;
185:
186: private static native void storeFloat(float f) /*-{
187: myFloatValue = f;
188: }-*/;
189:
190: @Override
191: public String getModuleName() {
192: return "com.google.gwt.dev.jjs.CompilerSuite";
193: }
194:
195: public void test32BitInt() {
196: assertEquals(Integer.MAX_VALUE,
197: passThroughInt(Integer.MAX_VALUE));
198: assertEquals(Integer.MIN_VALUE,
199: passThroughInt(Integer.MIN_VALUE));
200: }
201:
202: /*
203: * Test that returning JavaScript boxed primitives works as expected.
204: * Note that Boolean and Number cannot be supported properly in web
205: * mode, so we do not support it in hosted mode and therefore do not
206: * test it here.
207: */
208: public void testAutoBoxing() {
209: JavaScriptObject bvo = getBoxedBooleanAsObject(true);
210: assertEquals(getJSOAsString(bvo), "true");
211: JavaScriptObject nvo = getBoxedNumberAsObject(42);
212: assertEquals(getJSOAsString(nvo), "42");
213: JavaScriptObject svo = getBoxedStringAsObject("test");
214: assertEquals(getJSOAsString(svo), "test");
215: String sv = getBoxedStringAsString("test");
216: assertEquals(sv, "test");
217: }
218:
219: public void testBasic() {
220: int iv = getInt(14);
221: assertEquals(iv, -14);
222: double dv = getDouble(31.5);
223: assertEquals(dv, -31.5, 0.0);
224: String sv = getString("test");
225: assertEquals(sv, "testme");
226: Object oin = String.class;
227: Object oout = getObject(oin);
228: assertEquals(oin, oout);
229: }
230:
231: public void testByteMarshalling() {
232: byte b = 100;
233: assertEquals(100, byteAsInt(b));
234: b = -125;
235: assertEquals(-125, byteAsInt(b));
236: }
237:
238: public void testCovariant() {
239: TestCovariantSuper parent = new TestCovariantSuper();
240: TestCovariantChild child = new TestCovariantChild();
241: Object val1 = parent.foo("bar");
242: assertTrue(val1 instanceof String);
243: assertEquals("bar", val1);
244: String val2 = child.foo("bar");
245: assertEquals("bar", val2);
246: }
247:
248: public void testEmbeddedNullsInStrings() {
249: String s = "Pre\u0000Post";
250: assertEquals(s.length(), getStringLength(s));
251: assertEquals(s + "me", getString(s));
252: }
253:
254: @Override
255: public boolean catchExceptions() {
256: return false;
257: }
258:
259: public void testEnum() {
260: TestEnum val = enumSimple(TestEnum.VAL2);
261: assertEquals(TestEnum.VAL2, val);
262: int ord = enumValue(val);
263: assertEquals(TestEnum.VAL2.ordinal(), ord);
264: String name = enumName(val);
265: assertEquals(TestEnum.VAL2.name(), name);
266: }
267:
268: public void testFloat() {
269: storeFloat(Float.MIN_VALUE);
270: float f = getFloat();
271: assertTrue(f == Float.MIN_VALUE);
272: f = getFloatString();
273: assertTrue(f == Float.MIN_VALUE);
274: storeFloat(Float.MAX_VALUE);
275: f = getFloat();
276: assertTrue(f == Float.MAX_VALUE);
277: f = getFloatString();
278: assertTrue(f == Float.MAX_VALUE);
279: }
280:
281: public void testFunctionCaching() {
282: assertEquals("barfoo", sFooCall("bar"));
283: assertEquals("barfoo", sFooDirect("bar"));
284: assertEquals("barfoo", sFooInvoke("bar"));
285: assertEquals("barfoo", sFooRoundTrip(getsFooFunc(), "bar"));
286:
287: assertEquals("barfoo", fooCall("bar"));
288: assertEquals("barfoo", fooDirect("bar"));
289: assertEquals("barfoo", fooRoundTrip(getFooFunc(), "bar"));
290:
291: String sFooString = getsFooFunc().toString();
292: assertEquals(sFooString, sFooFuncAsStr());
293: assertEquals(sFooString, sFooFuncToString());
294: String fooString = getFooFunc().toString();
295: assertEquals(fooString, fooFuncAsStr());
296: assertEquals(fooString, fooFuncToString());
297: }
298:
299: public void testGenerics() {
300: String s = genericSimple("test");
301: assertEquals("test", s);
302: String v = genericGet(s);
303: assertEquals("test", v);
304: List<String> list = new ArrayList<String>();
305: list.add("foo");
306: Object obj = genericWildcard(list);
307: assertTrue(obj instanceof String);
308: assertEquals("foo", obj);
309: obj = genericSubtype("test");
310: List<Object> list2 = genericSubtype(new TestGenericList());
311: assertTrue(list2 instanceof TestGenericList);
312: assertEquals(42, list2.size());
313: assertEquals(list2, list2.get(0));
314: String[] array = new String[] { "foo", "bar" };
315: String[] ret = genericArray(array);
316: assertEquals(2, ret.length);
317: assertEquals("bar", ret[1]);
318: assertTrue(Arrays.deepEquals(array, ret));
319: }
320:
321: /**
322: * Tests that we are able to use binary and source level names when referencing
323: * a Java identifier from JSNI.
324: */
325: public void testJavaMemberRefResolution() {
326: A.B b = new A.B();
327: assertEquals(1, b.getUsingSourceRef());
328: assertEquals(1, b.getUsingBinaryRef());
329: }
330:
331: public void testJsniFormats() {
332: jsniA();
333: jsniB();
334: jsniC();
335: jsniD();
336: jsniE();
337: jsniF();
338: jsniG();
339: jsniH();
340: jsniI();
341: jsniJ();
342: jsniK();
343: jsniL();
344: }
345:
346: /**
347: * Tests that using the JavaScript toString method results in a call to
348: * the java.lang.Object::toString() method.
349: *
350: */
351: public void testJSNIToStringResolution() {
352: class Foo {
353: @Override
354: public String toString() {
355: return "FOO";
356: }
357: }
358:
359: assertEquals("FOO", callJSNIToString(new Foo()));
360: }
361:
362: public void testLocalJsni() {
363:
364: class Foo {
365: native String a() /*-{
366: return "blah";
367: }-*/;
368:
369: native String b() /*-{
370: return this.@com.google.gwt.dev.jjs.test.HostedTest$2Foo::a()();
371: }-*/;
372:
373: String c() {
374: return a();
375: }
376: }
377:
378: Foo f = new Foo();
379: assertEquals(f.a(), "blah");
380: assertEquals(f.b(), "blah");
381: assertEquals(f.c(), "blah");
382:
383: Foo fo = new Foo() {
384: @Override
385: native String a() /*-{
386: return "oblah";
387: }-*/;
388:
389: @Override
390: native String b() /*-{
391: return this.@com.google.gwt.dev.jjs.test.HostedTest$2Foo::a()();
392: }-*/;
393:
394: @Override
395: native String c() /*-{
396: return this.@com.google.gwt.dev.jjs.test.HostedTest$1::a()();
397: }-*/;
398: };
399:
400: assertEquals(fo.a(), "oblah");
401: assertEquals(fo.b(), "oblah");
402: assertEquals(fo.c(), "oblah");
403: }
404:
405: public void testLongMarshalling() {
406: // a big number that cannot accurately be represented as a double
407: long l = 1234567890123456789L;
408: double d = l;
409: assertTrue(isEq(l, d));
410: }
411:
412: /*
413: * Test that returning strings from methods declared as returning Object
414: * works, and that returning a primitive does not.
415: */
416: public void testObjectReturns() {
417: String str = (String) getStringAsObject();
418: assertEquals(str, "test");
419: try {
420: getIntAsObject();
421: // should have thrown an exception in hosted mode,
422: // so fail unless we are in web mode
423: assertTrue(GWT.isScript());
424: } catch (IllegalArgumentException e) {
425: // expected exception
426: }
427: }
428:
429: public void testVarargs() {
430: String[] strs = varargsHelper("foo", "bar");
431: assertEquals(2, strs.length);
432: assertEquals("bar", strs[1]);
433: // TODO: not sure if we want to support this or not.
434: // strs = varargsFromJS1();
435: // assertEquals(2, strs.length);
436: // assertEquals("bar", strs[1]);
437: strs = varargsFromJS2(strs);
438: assertEquals(2, strs.length);
439: assertEquals("bar", strs[1]);
440: }
441:
442: String foo(String s) {
443: return s + "foo";
444: }
445:
446: private native int byteAsInt(byte b) /*-{
447: return b;
448: }-*/;
449:
450: private native String callJSNIToString(Object obj) /*-{
451: return obj.toString();
452: }-*/;
453:
454: private native String enumName(TestEnum val) /*-{
455: return val.@java.lang.Enum::name()();
456: }-*/;
457:
458: private native TestEnum enumSimple(TestEnum val) /*-{
459: return val;
460: }-*/;
461:
462: private native int enumValue(TestEnum val) /*-{
463: return val.@java.lang.Enum::ordinal()();
464: }-*/;
465:
466: private native String fooCall(String s) /*-{
467: var f = this.@com.google.gwt.dev.jjs.test.HostedTest::foo(Ljava/lang/String;);
468: return f.call(this, s);
469: }-*/;
470:
471: private native String fooDirect(String s) /*-{
472: return this.@com.google.gwt.dev.jjs.test.HostedTest::foo(Ljava/lang/String;)(s);
473: }-*/;
474:
475: private native String fooFuncAsStr() /*-{
476: var f = this.@com.google.gwt.dev.jjs.test.HostedTest::foo(Ljava/lang/String;);
477: return "" + f;
478: }-*/;
479:
480: private native String fooFuncToString() /*-{
481: var f = this.@com.google.gwt.dev.jjs.test.HostedTest::foo(Ljava/lang/String;);
482: return f.toString();
483: }-*/;
484:
485: private native String fooRoundTrip(JavaScriptObject fooFunc,
486: String s) /*-{
487: return fooFunc.call(this, s);
488: }-*/;
489:
490: // Make this a JSNI method calling the Java method when that is implemented.
491: private native <T> T[] genericArray(T[] array) /*-{
492: // return genericPassthrough(array);
493: return this.@com.google.gwt.dev.jjs.test.HostedTest::genericPassthrough([Ljava/lang/Object;)(array);
494: }-*/;
495:
496: /*
497: * Since we can't generate a generic instance from within JS, K and V
498: * have to actually be compatible.
499: */
500: private native <K, V> V genericGet(K key) /*-{
501: return key;
502: }-*/;
503:
504: @SuppressWarnings("unused")
505: // called by JSNI
506: private <T> T[] genericPassthrough(T[] array) {
507: return array;
508: }
509:
510: // generics helper methods
511: private native <T> T genericSimple(T val) /*-{
512: return val;
513: }-*/;
514:
515: private native <T, U extends T> T genericSubtype(U val) /*-{
516: return val;
517: }-*/;
518:
519: private native Object genericWildcard(List<?> list) /*-{
520: return list.@java.util.List::get(I)(0);
521: }-*/;
522:
523: private native JavaScriptObject getFooFunc() /*-{
524: return this.@com.google.gwt.dev.jjs.test.HostedTest::foo(Ljava/lang/String;);
525: }-*/;
526:
527: private native boolean isEq(long l, double d) /*-{
528: return l == d;
529: }-*/;
530:
531: private native void jsniA()/*-{}-*/;
532:
533: private native void jsniB()/*-{
534: }-*/;
535:
536: private native void jsniC()
537: /*-{
538: }-*/;
539:
540: private native void jsniD()
541: /*-{}-*/;
542:
543: /**
544: * comment.
545: */
546: private native void jsniE()/*-{}-*/;
547:
548: /** comment. */
549: private native void jsniF()/*-{}-*/;
550:
551: /** comment */
552: private native void jsniG()/*-{}-*/;
553:
554: /*
555: * comment
556: */
557: private native void jsniH()/*-{}-*/;
558:
559: /* comment */private native void jsniI()/*-{}-*/;
560:
561: // comment
562: private native void jsniJ()/*-{}-*/;
563:
564: private native void jsniK()
565: /*-{
566: }-*/;
567:
568: /*-{ try to mess with compiler }-*/
569: private native void jsniL()/*-{}-*/;
570:
571: // test that JS can pass a series of arguments to a varargs function
572: private native String[] varargsFromJS1() /*-{
573: return this.@com.google.gwt.dev.jjs.test.HostedTest::varargsPassthrough([Ljava/lang/String;)("foo", "bar");
574: }-*/;
575:
576: // test that JS can pass a Java-created array to a varargs function
577: private native String[] varargsFromJS2(String[] arr) /*-{
578: return this.@com.google.gwt.dev.jjs.test.HostedTest::varargsPassthrough([Ljava/lang/String;)(arr);
579: }-*/;
580:
581: private native String[] varargsHelper(String... args) /*-{
582: return args;
583: }-*/;
584:
585: @SuppressWarnings("unused")
586: // called from JSNI
587: private String[] varargsPassthrough(String... args) {
588: return args;
589: }
590:
591: }
|