1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/**
18 * Part of the test suite for the WebView's Java Bridge. This test checks that
19 * we correctly convert Java values to JavaScript values when returning them
20 * from the methods of injected Java objects.
21 *
22 * The conversions should follow
23 * http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS. Places in
24 * which the implementation differs from the spec are marked with
25 * LIVECONNECT_COMPLIANCE.
26 * FIXME: Consider making our implementation more compliant, if it will not
27 * break backwards-compatibility. See b/4408210.
28 *
29 * To run this test ...
30 *  adb shell am instrument -w -e class com.android.webviewtests.JavaBridgeReturnValuesTest \
31 *     com.android.webviewtests/android.test.InstrumentationTestRunner
32 */
33
34package com.android.webviewtests;
35
36public class JavaBridgeReturnValuesTest extends JavaBridgeTestBase {
37    // An instance of this class is injected into the page to test returning
38    // Java values to JavaScript.
39    private class TestObject extends Controller {
40        private String mStringValue;
41        private boolean mBooleanValue;
42
43        // These four methods are used to control the test.
44        public synchronized void setStringValue(String x) {
45            mStringValue = x;
46            notifyResultIsReady();
47        }
48        public synchronized String waitForStringValue() {
49            waitForResult();
50            return mStringValue;
51        }
52        public synchronized void setBooleanValue(boolean x) {
53            mBooleanValue = x;
54            notifyResultIsReady();
55        }
56        public synchronized boolean waitForBooleanValue() {
57            waitForResult();
58            return mBooleanValue;
59        }
60
61        public boolean getBooleanValue() {
62            return true;
63        }
64        public byte getByteValue() {
65            return 42;
66        }
67        public char getCharValue() {
68            return '\u002A';
69        }
70        public short getShortValue() {
71            return 42;
72        }
73        public int getIntValue() {
74            return 42;
75        }
76        public long getLongValue() {
77            return 42L;
78        }
79        public float getFloatValue() {
80            return 42.1f;
81        }
82        public float getFloatValueNoDecimal() {
83            return 42.0f;
84        }
85        public double getDoubleValue() {
86            return 42.1;
87        }
88        public double getDoubleValueNoDecimal() {
89            return 42.0;
90        }
91        public String getStringValue() {
92            return "foo";
93        }
94        public String getEmptyStringValue() {
95            return "";
96        }
97        public String getNullStringValue() {
98            return null;
99        }
100        public Object getObjectValue() {
101            return new Object();
102        }
103        public Object getNullObjectValue() {
104            return null;
105        }
106        public CustomType getCustomTypeValue() {
107            return new CustomType();
108        }
109        public void getVoidValue() {
110        }
111    }
112
113    // A custom type used when testing passing objects.
114    private class CustomType {
115    }
116
117    TestObject mTestObject;
118
119    @Override
120    protected void setUp() throws Exception {
121        super.setUp();
122        mTestObject = new TestObject();
123        setUpWebView(mTestObject, "testObject");
124    }
125
126    // Note that this requires that we can pass a JavaScript string to Java.
127    protected String executeJavaScriptAndGetStringResult(String script) throws Throwable {
128        executeJavaScript("testObject.setStringValue(" + script + ");");
129        return mTestObject.waitForStringValue();
130    }
131
132    // Note that this requires that we can pass a JavaScript boolean to Java.
133    private boolean executeJavaScriptAndGetBooleanResult(String script) throws Throwable {
134        executeJavaScript("testObject.setBooleanValue(" + script + ");");
135        return mTestObject.waitForBooleanValue();
136    }
137
138    public void testMethodReturnTypes() throws Throwable {
139        assertEquals("boolean",
140                executeJavaScriptAndGetStringResult("typeof testObject.getBooleanValue()"));
141        assertEquals("number",
142                executeJavaScriptAndGetStringResult("typeof testObject.getByteValue()"));
143        // char values are returned to JavaScript as numbers.
144        assertEquals("number",
145                executeJavaScriptAndGetStringResult("typeof testObject.getCharValue()"));
146        assertEquals("number",
147                executeJavaScriptAndGetStringResult("typeof testObject.getShortValue()"));
148        assertEquals("number",
149                executeJavaScriptAndGetStringResult("typeof testObject.getIntValue()"));
150        assertEquals("number",
151                executeJavaScriptAndGetStringResult("typeof testObject.getLongValue()"));
152        assertEquals("number",
153                executeJavaScriptAndGetStringResult("typeof testObject.getFloatValue()"));
154        assertEquals("number",
155                executeJavaScriptAndGetStringResult("typeof testObject.getFloatValueNoDecimal()"));
156        assertEquals("number",
157                executeJavaScriptAndGetStringResult("typeof testObject.getDoubleValue()"));
158        assertEquals("number",
159                executeJavaScriptAndGetStringResult("typeof testObject.getDoubleValueNoDecimal()"));
160        assertEquals("string",
161                executeJavaScriptAndGetStringResult("typeof testObject.getStringValue()"));
162        assertEquals("string",
163                executeJavaScriptAndGetStringResult("typeof testObject.getEmptyStringValue()"));
164        // LIVECONNECT_COMPLIANCE: This should have type object.
165        assertEquals("undefined",
166                executeJavaScriptAndGetStringResult("typeof testObject.getNullStringValue()"));
167        assertEquals("object",
168                executeJavaScriptAndGetStringResult("typeof testObject.getObjectValue()"));
169        assertEquals("object",
170                executeJavaScriptAndGetStringResult("typeof testObject.getNullObjectValue()"));
171        assertEquals("object",
172                executeJavaScriptAndGetStringResult("typeof testObject.getCustomTypeValue()"));
173        assertEquals("undefined",
174                executeJavaScriptAndGetStringResult("typeof testObject.getVoidValue()"));
175    }
176
177    public void testMethodReturnValues() throws Throwable {
178        // We do the string comparison in JavaScript, to avoid relying on the
179        // coercion algorithm from JavaScript to Java.
180        assertTrue(executeJavaScriptAndGetBooleanResult("testObject.getBooleanValue()"));
181        assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getByteValue()"));
182        // char values are returned to JavaScript as numbers.
183        assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getCharValue()"));
184        assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getShortValue()"));
185        assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getIntValue()"));
186        assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getLongValue()"));
187        assertTrue(executeJavaScriptAndGetBooleanResult(
188                "Math.abs(42.1 - testObject.getFloatValue()) < 0.001"));
189        assertTrue(executeJavaScriptAndGetBooleanResult(
190                "42.0 === testObject.getFloatValueNoDecimal()"));
191        assertTrue(executeJavaScriptAndGetBooleanResult(
192                "Math.abs(42.1 - testObject.getDoubleValue()) < 0.001"));
193        assertTrue(executeJavaScriptAndGetBooleanResult(
194                "42.0 === testObject.getDoubleValueNoDecimal()"));
195        assertEquals("foo", executeJavaScriptAndGetStringResult("testObject.getStringValue()"));
196        assertEquals("", executeJavaScriptAndGetStringResult("testObject.getEmptyStringValue()"));
197        assertTrue(executeJavaScriptAndGetBooleanResult("undefined === testObject.getVoidValue()"));
198    }
199}
200