1 // Copyright 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.content.browser; 6 7 import androidx.test.filters.SmallTest; 8 9 import org.junit.Assert; 10 import org.junit.Before; 11 import org.junit.Rule; 12 import org.junit.Test; 13 import org.junit.runner.RunWith; 14 15 import org.chromium.base.test.params.BaseJUnit4RunnerDelegate; 16 import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameter; 17 import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameterBefore; 18 import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate; 19 import org.chromium.base.test.params.ParameterizedRunner; 20 import org.chromium.base.test.util.Batch; 21 import org.chromium.base.test.util.Feature; 22 import org.chromium.content.browser.JavaBridgeActivityTestRule.Controller; 23 24 /** 25 * Part of the test suite for the Java Bridge. This class tests the general use of arrays. 26 * 27 * The conversions should follow 28 * http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS. Places in 29 * which the implementation differs from the spec are marked with 30 * LIVECONNECT_COMPLIANCE. 31 * FIXME: Consider making our implementation more compliant, if it will not 32 * break backwards-compatibility. See b/4408210. 33 */ 34 @RunWith(ParameterizedRunner.class) 35 @UseRunnerDelegate(BaseJUnit4RunnerDelegate.class) 36 @Batch(JavaBridgeActivityTestRule.BATCH) 37 public class JavaBridgeArrayTest { 38 @Rule 39 public JavaBridgeActivityTestRule mActivityTestRule = new JavaBridgeActivityTestRule(); 40 41 private static class TestObject extends Controller { 42 private boolean mBooleanValue; 43 private int mIntValue; 44 private String mStringValue; 45 46 private int[] mIntArray; 47 private int[][] mIntIntArray; 48 49 private boolean mWasArrayMethodCalled; 50 setBooleanValue(boolean x)51 public synchronized void setBooleanValue(boolean x) { 52 mBooleanValue = x; 53 notifyResultIsReady(); 54 } setIntValue(int x)55 public synchronized void setIntValue(int x) { 56 mIntValue = x; 57 notifyResultIsReady(); 58 } setStringValue(String x)59 public synchronized void setStringValue(String x) { 60 mStringValue = x; 61 notifyResultIsReady(); 62 } 63 waitForBooleanValue()64 public synchronized boolean waitForBooleanValue() { 65 waitForResult(); 66 return mBooleanValue; 67 } waitForIntValue()68 public synchronized int waitForIntValue() { 69 waitForResult(); 70 return mIntValue; 71 } waitForStringValue()72 public synchronized String waitForStringValue() { 73 waitForResult(); 74 return mStringValue; 75 } 76 setIntArray(int[] x)77 public synchronized void setIntArray(int[] x) { 78 mIntArray = x; 79 notifyResultIsReady(); 80 } setIntIntArray(int[][] x)81 public synchronized void setIntIntArray(int[][] x) { 82 mIntIntArray = x; 83 notifyResultIsReady(); 84 } 85 waitForIntArray()86 public synchronized int[] waitForIntArray() { 87 waitForResult(); 88 return mIntArray; 89 } waitForIntIntArray()90 public synchronized int[][] waitForIntIntArray() { 91 waitForResult(); 92 return mIntIntArray; 93 } 94 arrayMethod()95 public synchronized int[] arrayMethod() { 96 mWasArrayMethodCalled = true; 97 return new int[] {42, 43, 44}; 98 } 99 wasArrayMethodCalled()100 public synchronized boolean wasArrayMethodCalled() { 101 return mWasArrayMethodCalled; 102 } 103 } 104 105 @UseMethodParameterBefore(JavaBridgeActivityTestRule.MojoTestParams.class) setupMojoTest(boolean useMojo)106 public void setupMojoTest(boolean useMojo) { 107 mActivityTestRule.setupMojoTest(useMojo); 108 } 109 110 private TestObject mTestObject; 111 112 @Before setUp()113 public void setUp() { 114 mTestObject = new TestObject(); 115 mActivityTestRule.injectObjectAndReload(mTestObject, "testObject"); 116 } 117 118 @Test 119 @SmallTest 120 @Feature({"AndroidWebView", "Android-JavaBridge"}) 121 @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) testArrayLength(boolean useMojo)122 public void testArrayLength(boolean useMojo) throws Throwable { 123 mActivityTestRule.executeJavaScript("testObject.setIntArray([42, 43, 44]);"); 124 int[] result = mTestObject.waitForIntArray(); 125 Assert.assertEquals(3, result.length); 126 Assert.assertEquals(42, result[0]); 127 Assert.assertEquals(43, result[1]); 128 Assert.assertEquals(44, result[2]); 129 } 130 131 @Test 132 @SmallTest 133 @Feature({"AndroidWebView", "Android-JavaBridge"}) 134 @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) testPassNull(boolean useMojo)135 public void testPassNull(boolean useMojo) throws Throwable { 136 mActivityTestRule.executeJavaScript("testObject.setIntArray(null);"); 137 Assert.assertNull(mTestObject.waitForIntArray()); 138 } 139 140 @Test 141 @SmallTest 142 @Feature({"AndroidWebView", "Android-JavaBridge"}) 143 @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) testPassUndefined(boolean useMojo)144 public void testPassUndefined(boolean useMojo) throws Throwable { 145 mActivityTestRule.executeJavaScript("testObject.setIntArray(undefined);"); 146 Assert.assertNull(mTestObject.waitForIntArray()); 147 } 148 149 @Test 150 @SmallTest 151 @Feature({"AndroidWebView", "Android-JavaBridge"}) 152 @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) testPassEmptyArray(boolean useMojo)153 public void testPassEmptyArray(boolean useMojo) throws Throwable { 154 mActivityTestRule.executeJavaScript("testObject.setIntArray([]);"); 155 Assert.assertEquals(0, mTestObject.waitForIntArray().length); 156 } 157 158 // Note that this requires being able to pass a string from JavaScript to 159 // Java. 160 @Test 161 @SmallTest 162 @Feature({"AndroidWebView", "Android-JavaBridge"}) 163 @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) testPassArrayToStringMethod(boolean useMojo)164 public void testPassArrayToStringMethod(boolean useMojo) throws Throwable { 165 // LIVECONNECT_COMPLIANCE: Should call toString() on array. 166 mActivityTestRule.executeJavaScript("testObject.setStringValue([42, 42, 42]);"); 167 Assert.assertEquals("undefined", mTestObject.waitForStringValue()); 168 } 169 170 // Note that this requires being able to pass an integer from JavaScript to 171 // Java. 172 @Test 173 @SmallTest 174 @Feature({"AndroidWebView", "Android-JavaBridge"}) 175 @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) testPassArrayToNonStringNonArrayMethod(boolean useMojo)176 public void testPassArrayToNonStringNonArrayMethod(boolean useMojo) throws Throwable { 177 // LIVECONNECT_COMPLIANCE: Should raise JavaScript exception. 178 mActivityTestRule.executeJavaScript("testObject.setIntValue([42, 42, 42]);"); 179 Assert.assertEquals(0, mTestObject.waitForIntValue()); 180 } 181 182 @Test 183 @SmallTest 184 @Feature({"AndroidWebView", "Android-JavaBridge"}) 185 @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) testPassNonArrayToArrayMethod(boolean useMojo)186 public void testPassNonArrayToArrayMethod(boolean useMojo) throws Throwable { 187 // LIVECONNECT_COMPLIANCE: Should raise JavaScript exception. 188 mActivityTestRule.executeJavaScript("testObject.setIntArray(42);"); 189 Assert.assertNull(mTestObject.waitForIntArray()); 190 } 191 192 @Test 193 @SmallTest 194 @Feature({"AndroidWebView", "Android-JavaBridge"}) 195 @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) testObjectWithLengthProperty(boolean useMojo)196 public void testObjectWithLengthProperty(boolean useMojo) throws Throwable { 197 mActivityTestRule.executeJavaScript("testObject.setIntArray({length: 3, 1: 42});"); 198 int[] result = mTestObject.waitForIntArray(); 199 Assert.assertEquals(3, result.length); 200 Assert.assertEquals(0, result[0]); 201 Assert.assertEquals(42, result[1]); 202 Assert.assertEquals(0, result[2]); 203 } 204 205 @Test 206 @SmallTest 207 @Feature({"AndroidWebView", "Android-JavaBridge"}) 208 @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) testNonNumericLengthProperty(boolean useMojo)209 public void testNonNumericLengthProperty(boolean useMojo) throws Throwable { 210 // LIVECONNECT_COMPLIANCE: This should not count as an array, so we 211 // should raise a JavaScript exception. 212 mActivityTestRule.executeJavaScript("testObject.setIntArray({length: \"foo\"});"); 213 Assert.assertNull(mTestObject.waitForIntArray()); 214 } 215 216 @Test 217 @SmallTest 218 @Feature({"AndroidWebView", "Android-JavaBridge"}) 219 @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) testLengthOutOfBounds(boolean useMojo)220 public void testLengthOutOfBounds(boolean useMojo) throws Throwable { 221 // LIVECONNECT_COMPLIANCE: This should not count as an array, so we 222 // should raise a JavaScript exception. 223 mActivityTestRule.executeJavaScript("testObject.setIntArray({length: -1});"); 224 Assert.assertNull(mTestObject.waitForIntArray()); 225 226 // LIVECONNECT_COMPLIANCE: This should not count as an array, so we 227 // should raise a JavaScript exception. 228 long length = Integer.MAX_VALUE + 1L; 229 mActivityTestRule.executeJavaScript("testObject.setIntArray({length: " + length + "});"); 230 Assert.assertNull(mTestObject.waitForIntArray()); 231 232 // LIVECONNECT_COMPLIANCE: This should not count as an array, so we 233 // should raise a JavaScript exception. 234 length = Integer.MAX_VALUE + 1L - Integer.MIN_VALUE + 1L; 235 mActivityTestRule.executeJavaScript("testObject.setIntArray({length: " + length + "});"); 236 Assert.assertNull(mTestObject.waitForIntArray()); 237 } 238 239 @Test 240 @SmallTest 241 @Feature({"AndroidWebView", "Android-JavaBridge"}) 242 @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) testSparseArray(boolean useMojo)243 public void testSparseArray(boolean useMojo) throws Throwable { 244 mActivityTestRule.executeJavaScript( 245 "var x = [42, 43]; x[3] = 45; testObject.setIntArray(x);"); 246 int[] result = mTestObject.waitForIntArray(); 247 Assert.assertEquals(4, result.length); 248 Assert.assertEquals(42, result[0]); 249 Assert.assertEquals(43, result[1]); 250 Assert.assertEquals(0, result[2]); 251 Assert.assertEquals(45, result[3]); 252 } 253 254 // Note that this requires being able to pass a boolean from JavaScript to 255 // Java. 256 @Test 257 @SmallTest 258 @Feature({"AndroidWebView", "Android-JavaBridge"}) 259 @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) testMethodReturningArrayNotCalled(boolean useMojo)260 public void testMethodReturningArrayNotCalled(boolean useMojo) throws Throwable { 261 // We don't invoke methods which return arrays, but note that no 262 // exception is raised. 263 // LIVECONNECT_COMPLIANCE: Should call method and convert result to 264 // JavaScript array. 265 mActivityTestRule.executeJavaScript( 266 "testObject.setBooleanValue(undefined === testObject.arrayMethod())"); 267 Assert.assertTrue(mTestObject.waitForBooleanValue()); 268 Assert.assertFalse(mTestObject.wasArrayMethodCalled()); 269 } 270 271 @Test 272 @SmallTest 273 @Feature({"AndroidWebView", "Android-JavaBridge"}) 274 @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) testMultiDimensionalArrayMethod(boolean useMojo)275 public void testMultiDimensionalArrayMethod(boolean useMojo) throws Throwable { 276 // LIVECONNECT_COMPLIANCE: Should handle multi-dimensional arrays. 277 mActivityTestRule.executeJavaScript("testObject.setIntIntArray([ [42, 43], [44, 45] ]);"); 278 Assert.assertNull(mTestObject.waitForIntIntArray()); 279 } 280 281 @Test 282 @SmallTest 283 @Feature({"AndroidWebView", "Android-JavaBridge"}) 284 @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) testPassMultiDimensionalArray(boolean useMojo)285 public void testPassMultiDimensionalArray(boolean useMojo) throws Throwable { 286 // LIVECONNECT_COMPLIANCE: Should handle multi-dimensional arrays. 287 mActivityTestRule.executeJavaScript("testObject.setIntArray([ [42, 43], [44, 45] ]);"); 288 int[] result = mTestObject.waitForIntArray(); 289 Assert.assertEquals(2, result.length); 290 Assert.assertEquals(0, result[0]); 291 Assert.assertEquals(0, result[1]); 292 } 293 294 // Verify that ArrayBuffers are not converted into arrays when passed to Java. 295 // The LiveConnect spec doesn't mention ArrayBuffers, so it doesn't seem to 296 // be a compliance issue. 297 @Test 298 @SmallTest 299 @Feature({"AndroidWebView", "Android-JavaBridge"}) 300 @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) testPassArrayBuffer(boolean useMojo)301 public void testPassArrayBuffer(boolean useMojo) throws Throwable { 302 mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(16);"); 303 mActivityTestRule.executeJavaScript("testObject.setIntArray(buffer);"); 304 Assert.assertNull(mTestObject.waitForIntArray()); 305 } 306 307 // Verify that ArrayBufferViews are not converted into arrays when passed to Java. 308 // The LiveConnect spec doesn't mention ArrayBufferViews, so it doesn't seem to 309 // be a compliance issue. 310 // Here, a DataView is used as an ArrayBufferView instance (since the latter is 311 // an interface and can't be instantiated directly). See also JavaBridgeArrayCoercionTest 312 // for typed arrays (that also subclass ArrayBufferView) tests. 313 @Test 314 @SmallTest 315 @Feature({"AndroidWebView", "Android-JavaBridge"}) 316 @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) testPassDataView(boolean useMojo)317 public void testPassDataView(boolean useMojo) throws Throwable { 318 mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(16);"); 319 mActivityTestRule.executeJavaScript("testObject.setIntArray(new DataView(buffer));"); 320 Assert.assertNull(mTestObject.waitForIntArray()); 321 } 322 } 323