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 class tests the
19 * general use of arrays.
20 *
21 * The conversions should follow
22 * http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS. Places in
23 * which the implementation differs from the spec are marked with
24 * LIVECONNECT_COMPLIANCE.
25 * FIXME: Consider making our implementation more compliant, if it will not
26 * break backwards-compatibility. See b/4408210.
27 *
28 * To run this test ...
29 *  adb shell am instrument -w -e class com.android.webviewtests.JavaBridgeArrayTest \
30 *     com.android.webviewtests/android.test.InstrumentationTestRunner
31 */
32
33package com.android.webviewtests;
34
35public class JavaBridgeArrayTest extends JavaBridgeTestBase {
36    private class TestObject extends Controller {
37        private boolean mBooleanValue;
38        private int mIntValue;
39        private String mStringValue;
40
41        private int[] mIntArray;
42        private int[][] mIntIntArray;
43
44        private boolean mWasArrayMethodCalled;
45
46        public synchronized void setBooleanValue(boolean x) {
47            mBooleanValue = x;
48            notifyResultIsReady();
49        }
50        public synchronized void setIntValue(int x) {
51            mIntValue = x;
52            notifyResultIsReady();
53        }
54        public synchronized void setStringValue(String x) {
55            mStringValue = x;
56            notifyResultIsReady();
57        }
58
59        public synchronized boolean waitForBooleanValue() {
60            waitForResult();
61            return mBooleanValue;
62        }
63        public synchronized int waitForIntValue() {
64            waitForResult();
65            return mIntValue;
66        }
67        public synchronized String waitForStringValue() {
68            waitForResult();
69            return mStringValue;
70        }
71
72        public synchronized void setIntArray(int[] x) {
73            mIntArray = x;
74            notifyResultIsReady();
75        }
76        public synchronized void setIntIntArray(int[][] x) {
77            mIntIntArray = x;
78            notifyResultIsReady();
79        }
80
81        public synchronized int[] waitForIntArray() {
82            waitForResult();
83            return mIntArray;
84        }
85        public synchronized int[][] waitForIntIntArray() {
86            waitForResult();
87            return mIntIntArray;
88        }
89
90        public synchronized int[] arrayMethod() {
91            mWasArrayMethodCalled = true;
92            return new int[] {42, 43, 44};
93        }
94
95        public synchronized boolean wasArrayMethodCalled() {
96            return mWasArrayMethodCalled;
97        }
98    }
99
100    private TestObject mTestObject;
101
102    @Override
103    protected void setUp() throws Exception {
104        super.setUp();
105        mTestObject = new TestObject();
106        setUpWebView(mTestObject, "testObject");
107    }
108
109    public void testArrayLength() throws Throwable {
110        executeJavaScript("testObject.setIntArray([42, 43, 44]);");
111        int[] result = mTestObject.waitForIntArray();
112        assertEquals(3, result.length);
113        assertEquals(42, result[0]);
114        assertEquals(43, result[1]);
115        assertEquals(44, result[2]);
116    }
117
118    public void testPassNull() throws Throwable {
119        executeJavaScript("testObject.setIntArray(null);");
120        assertNull(mTestObject.waitForIntArray());
121    }
122
123    public void testPassUndefined() throws Throwable {
124        executeJavaScript("testObject.setIntArray(undefined);");
125        assertNull(mTestObject.waitForIntArray());
126    }
127
128    public void testPassEmptyArray() throws Throwable {
129        executeJavaScript("testObject.setIntArray([]);");
130        assertEquals(0, mTestObject.waitForIntArray().length);
131    }
132
133    // Note that this requires being able to pass a string from JavaScript to
134    // Java.
135    public void testPassArrayToStringMethod() throws Throwable {
136        // LIVECONNECT_COMPLIANCE: Should call toString() on array.
137        executeJavaScript("testObject.setStringValue([42, 42, 42]);");
138        assertEquals("undefined", mTestObject.waitForStringValue());
139    }
140
141    // Note that this requires being able to pass an integer from JavaScript to
142    // Java.
143    public void testPassArrayToNonStringNonArrayMethod() throws Throwable {
144        // LIVECONNECT_COMPLIANCE: Should raise JavaScript exception.
145        executeJavaScript("testObject.setIntValue([42, 42, 42]);");
146        assertEquals(0, mTestObject.waitForIntValue());
147    }
148
149    public void testPassNonArrayToArrayMethod() throws Throwable {
150        // LIVECONNECT_COMPLIANCE: Should raise JavaScript exception.
151        executeJavaScript("testObject.setIntArray(42);");
152        assertNull(mTestObject.waitForIntArray());
153    }
154
155    public void testObjectWithLengthProperty() throws Throwable {
156        executeJavaScript("testObject.setIntArray({length: 3, 1: 42});");
157        int[] result = mTestObject.waitForIntArray();
158        assertEquals(3, result.length);
159        assertEquals(0, result[0]);
160        assertEquals(42, result[1]);
161        assertEquals(0, result[2]);
162    }
163
164    public void testNonNumericLengthProperty() throws Throwable {
165        // LIVECONNECT_COMPLIANCE: This should not count as an array, so we
166        // should raise a JavaScript exception.
167        executeJavaScript("testObject.setIntArray({length: \"foo\"});");
168        assertNull(mTestObject.waitForIntArray());
169    }
170
171    public void testLengthOutOfBounds() throws Throwable {
172        // LIVECONNECT_COMPLIANCE: This should not count as an array, so we
173        // should raise a JavaScript exception.
174        executeJavaScript("testObject.setIntArray({length: -1});");
175        assertNull(mTestObject.waitForIntArray());
176
177        // LIVECONNECT_COMPLIANCE: This should not count as an array, so we
178        // should raise a JavaScript exception.
179        long length = (long)Integer.MAX_VALUE + 1L;
180        executeJavaScript("testObject.setIntArray({length: " + length + "});");
181        assertNull(mTestObject.waitForIntArray());
182
183        // LIVECONNECT_COMPLIANCE: This should not count as an array, so we
184        // should raise a JavaScript exception.
185        length = (long)Integer.MAX_VALUE + 1L - (long)Integer.MIN_VALUE + 1L;
186        executeJavaScript("testObject.setIntArray({length: " + length + "});");
187        assertNull(mTestObject.waitForIntArray());
188    }
189
190    public void testSparseArray() throws Throwable {
191        executeJavaScript("var x = [42, 43]; x[3] = 45; testObject.setIntArray(x);");
192        int[] result = mTestObject.waitForIntArray();
193        assertEquals(4, result.length);
194        assertEquals(42, result[0]);
195        assertEquals(43, result[1]);
196        assertEquals(0, result[2]);
197        assertEquals(45, result[3]);
198    }
199
200    // Note that this requires being able to pass a boolean from JavaScript to
201    // Java.
202    public void testMethodReturningArrayNotCalled() throws Throwable {
203        // We don't invoke methods which return arrays, but note that no
204        // exception is raised.
205        // LIVECONNECT_COMPLIANCE: Should call method and convert result to
206        // JavaScript array.
207        executeJavaScript("testObject.setBooleanValue(undefined === testObject.arrayMethod())");
208        assertTrue(mTestObject.waitForBooleanValue());
209        assertFalse(mTestObject.wasArrayMethodCalled());
210    }
211
212    public void testMultiDimensionalArrayMethod() throws Throwable {
213        // LIVECONNECT_COMPLIANCE: Should handle multi-dimensional arrays.
214        executeJavaScript("testObject.setIntIntArray([ [42, 43], [44, 45] ]);");
215        assertNull(mTestObject.waitForIntIntArray());
216    }
217
218    public void testPassMultiDimensionalArray() throws Throwable {
219        // LIVECONNECT_COMPLIANCE: Should handle multi-dimensional arrays.
220        executeJavaScript("testObject.setIntArray([ [42, 43], [44, 45] ]);");
221        int[] result = mTestObject.waitForIntArray();
222        assertEquals(2, result.length);
223        assertEquals(0, result[0]);
224        assertEquals(0, result[1]);
225    }
226}
227