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 
33 package com.android.webviewtests;
34 
35 public 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 
setBooleanValue(boolean x)46         public synchronized void setBooleanValue(boolean x) {
47             mBooleanValue = x;
48             notifyResultIsReady();
49         }
setIntValue(int x)50         public synchronized void setIntValue(int x) {
51             mIntValue = x;
52             notifyResultIsReady();
53         }
setStringValue(String x)54         public synchronized void setStringValue(String x) {
55             mStringValue = x;
56             notifyResultIsReady();
57         }
58 
waitForBooleanValue()59         public synchronized boolean waitForBooleanValue() {
60             waitForResult();
61             return mBooleanValue;
62         }
waitForIntValue()63         public synchronized int waitForIntValue() {
64             waitForResult();
65             return mIntValue;
66         }
waitForStringValue()67         public synchronized String waitForStringValue() {
68             waitForResult();
69             return mStringValue;
70         }
71 
setIntArray(int[] x)72         public synchronized void setIntArray(int[] x) {
73             mIntArray = x;
74             notifyResultIsReady();
75         }
setIntIntArray(int[][] x)76         public synchronized void setIntIntArray(int[][] x) {
77             mIntIntArray = x;
78             notifyResultIsReady();
79         }
80 
waitForIntArray()81         public synchronized int[] waitForIntArray() {
82             waitForResult();
83             return mIntArray;
84         }
waitForIntIntArray()85         public synchronized int[][] waitForIntIntArray() {
86             waitForResult();
87             return mIntIntArray;
88         }
89 
arrayMethod()90         public synchronized int[] arrayMethod() {
91             mWasArrayMethodCalled = true;
92             return new int[] {42, 43, 44};
93         }
94 
wasArrayMethodCalled()95         public synchronized boolean wasArrayMethodCalled() {
96             return mWasArrayMethodCalled;
97         }
98     }
99 
100     private TestObject mTestObject;
101 
102     @Override
setUp()103     protected void setUp() throws Exception {
104         super.setUp();
105         mTestObject = new TestObject();
106         setUpWebView(mTestObject, "testObject");
107     }
108 
testArrayLength()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 
testPassNull()118     public void testPassNull() throws Throwable {
119         executeJavaScript("testObject.setIntArray(null);");
120         assertNull(mTestObject.waitForIntArray());
121     }
122 
testPassUndefined()123     public void testPassUndefined() throws Throwable {
124         executeJavaScript("testObject.setIntArray(undefined);");
125         assertNull(mTestObject.waitForIntArray());
126     }
127 
testPassEmptyArray()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.
testPassArrayToStringMethod()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.
testPassArrayToNonStringNonArrayMethod()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 
testPassNonArrayToArrayMethod()149     public void testPassNonArrayToArrayMethod() throws Throwable {
150         // LIVECONNECT_COMPLIANCE: Should raise JavaScript exception.
151         executeJavaScript("testObject.setIntArray(42);");
152         assertNull(mTestObject.waitForIntArray());
153     }
154 
testObjectWithLengthProperty()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 
testNonNumericLengthProperty()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 
testLengthOutOfBounds()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 
testSparseArray()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.
testMethodReturningArrayNotCalled()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 
testMultiDimensionalArrayMethod()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 
testPassMultiDimensionalArray()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