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 test checks that we correctly convert Java 26 * values to JavaScript values when returning them from the methods of injected Java objects. 27 * 28 * The conversions should follow 29 * http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS. Places in 30 * which the implementation differs from the spec are marked with 31 * LIVECONNECT_COMPLIANCE. 32 * FIXME: Consider making our implementation more compliant, if it will not 33 * break backwards-compatibility. See b/4408210. 34 */ 35 @RunWith(ParameterizedRunner.class) 36 @UseRunnerDelegate(BaseJUnit4RunnerDelegate.class) 37 @Batch(JavaBridgeActivityTestRule.BATCH) 38 public class JavaBridgeReturnValuesTest { 39 @Rule 40 public JavaBridgeActivityTestRule mActivityTestRule = new JavaBridgeActivityTestRule(); 41 42 // An instance of this class is injected into the page to test returning 43 // Java values to JavaScript. 44 private static class TestObject extends Controller { 45 private String mStringResult; 46 private boolean mBooleanResult; 47 48 // These four methods are used to control the test. setStringResult(String x)49 public synchronized void setStringResult(String x) { 50 mStringResult = x; 51 notifyResultIsReady(); 52 } waitForStringResult()53 public synchronized String waitForStringResult() { 54 waitForResult(); 55 return mStringResult; 56 } setBooleanResult(boolean x)57 public synchronized void setBooleanResult(boolean x) { 58 mBooleanResult = x; 59 notifyResultIsReady(); 60 } waitForBooleanResult()61 public synchronized boolean waitForBooleanResult() { 62 waitForResult(); 63 return mBooleanResult; 64 } 65 getBooleanValue()66 public boolean getBooleanValue() { 67 return true; 68 } getByteValue()69 public byte getByteValue() { 70 return 42; 71 } getCharValue()72 public char getCharValue() { 73 return '\u002A'; 74 } getShortValue()75 public short getShortValue() { 76 return 42; 77 } getIntValue()78 public int getIntValue() { 79 return 42; 80 } getLongValue()81 public long getLongValue() { 82 return 42L; 83 } getFloatValue()84 public float getFloatValue() { 85 return 42.1f; 86 } getFloatValueNoDecimal()87 public float getFloatValueNoDecimal() { 88 return 42.0f; 89 } getDoubleValue()90 public double getDoubleValue() { 91 return 42.1; 92 } getDoubleValueNoDecimal()93 public double getDoubleValueNoDecimal() { 94 return 42.0; 95 } getStringValue()96 public String getStringValue() { 97 return "foo"; 98 } getEmptyStringValue()99 public String getEmptyStringValue() { 100 return ""; 101 } getNullStringValue()102 public String getNullStringValue() { 103 return null; 104 } getObjectValue()105 public Object getObjectValue() { 106 return new Object(); 107 } getNullObjectValue()108 public Object getNullObjectValue() { 109 return null; 110 } getCustomTypeValue()111 public CustomType getCustomTypeValue() { 112 return new CustomType(); 113 } getVoidValue()114 public void getVoidValue() { 115 } 116 } 117 118 // A custom type used when testing passing objects. 119 private static class CustomType { 120 } 121 122 @UseMethodParameterBefore(JavaBridgeActivityTestRule.MojoTestParams.class) setupMojoTest(boolean useMojo)123 public void setupMojoTest(boolean useMojo) { 124 mActivityTestRule.setupMojoTest(useMojo); 125 } 126 127 TestObject mTestObject; 128 129 @Before setUp()130 public void setUp() { 131 mTestObject = new TestObject(); 132 mActivityTestRule.injectObjectAndReload(mTestObject, "testObject"); 133 } 134 135 // Note that this requires that we can pass a JavaScript string to Java. executeJavaScriptAndGetStringResult(String script)136 protected String executeJavaScriptAndGetStringResult(String script) throws Throwable { 137 mActivityTestRule.executeJavaScript("testObject.setStringResult(" + script + ");"); 138 return mTestObject.waitForStringResult(); 139 } 140 141 // Note that this requires that we can pass a JavaScript boolean to Java. executeJavaScriptAndGetBooleanResult(String script)142 private boolean executeJavaScriptAndGetBooleanResult(String script) throws Throwable { 143 mActivityTestRule.executeJavaScript("testObject.setBooleanResult(" + script + ");"); 144 return mTestObject.waitForBooleanResult(); 145 } 146 147 @Test 148 @SmallTest 149 @Feature({"AndroidWebView", "Android-JavaBridge"}) 150 @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) testMethodReturnTypes(boolean useMojo)151 public void testMethodReturnTypes(boolean useMojo) throws Throwable { 152 Assert.assertEquals("boolean", 153 executeJavaScriptAndGetStringResult("typeof testObject.getBooleanValue()")); 154 Assert.assertEquals( 155 "number", executeJavaScriptAndGetStringResult("typeof testObject.getByteValue()")); 156 // char values are returned to JavaScript as numbers. 157 Assert.assertEquals( 158 "number", executeJavaScriptAndGetStringResult("typeof testObject.getCharValue()")); 159 Assert.assertEquals( 160 "number", executeJavaScriptAndGetStringResult("typeof testObject.getShortValue()")); 161 Assert.assertEquals( 162 "number", executeJavaScriptAndGetStringResult("typeof testObject.getIntValue()")); 163 Assert.assertEquals( 164 "number", executeJavaScriptAndGetStringResult("typeof testObject.getLongValue()")); 165 Assert.assertEquals( 166 "number", executeJavaScriptAndGetStringResult("typeof testObject.getFloatValue()")); 167 Assert.assertEquals("number", 168 executeJavaScriptAndGetStringResult("typeof testObject.getFloatValueNoDecimal()")); 169 Assert.assertEquals("number", 170 executeJavaScriptAndGetStringResult("typeof testObject.getDoubleValue()")); 171 Assert.assertEquals("number", 172 executeJavaScriptAndGetStringResult("typeof testObject.getDoubleValueNoDecimal()")); 173 Assert.assertEquals("string", 174 executeJavaScriptAndGetStringResult("typeof testObject.getStringValue()")); 175 Assert.assertEquals("string", 176 executeJavaScriptAndGetStringResult("typeof testObject.getEmptyStringValue()")); 177 // LIVECONNECT_COMPLIANCE: This should have type object. 178 Assert.assertEquals("undefined", 179 executeJavaScriptAndGetStringResult("typeof testObject.getNullStringValue()")); 180 Assert.assertEquals("object", 181 executeJavaScriptAndGetStringResult("typeof testObject.getObjectValue()")); 182 Assert.assertEquals("object", 183 executeJavaScriptAndGetStringResult("typeof testObject.getNullObjectValue()")); 184 Assert.assertEquals("object", 185 executeJavaScriptAndGetStringResult("typeof testObject.getCustomTypeValue()")); 186 Assert.assertEquals("undefined", 187 executeJavaScriptAndGetStringResult("typeof testObject.getVoidValue()")); 188 } 189 190 @Test 191 @SmallTest 192 @Feature({"AndroidWebView", "Android-JavaBridge"}) 193 @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) testMethodReturnValues(boolean useMojo)194 public void testMethodReturnValues(boolean useMojo) throws Throwable { 195 // We do the string comparison in JavaScript, to avoid relying on the 196 // coercion algorithm from JavaScript to Java. 197 Assert.assertTrue(executeJavaScriptAndGetBooleanResult("testObject.getBooleanValue()")); 198 Assert.assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getByteValue()")); 199 // char values are returned to JavaScript as numbers. 200 Assert.assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getCharValue()")); 201 Assert.assertTrue( 202 executeJavaScriptAndGetBooleanResult("42 === testObject.getShortValue()")); 203 Assert.assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getIntValue()")); 204 Assert.assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getLongValue()")); 205 Assert.assertTrue(executeJavaScriptAndGetBooleanResult( 206 "Math.abs(42.1 - testObject.getFloatValue()) < 0.001")); 207 Assert.assertTrue(executeJavaScriptAndGetBooleanResult( 208 "42.0 === testObject.getFloatValueNoDecimal()")); 209 Assert.assertTrue(executeJavaScriptAndGetBooleanResult( 210 "Math.abs(42.1 - testObject.getDoubleValue()) < 0.001")); 211 Assert.assertTrue(executeJavaScriptAndGetBooleanResult( 212 "42.0 === testObject.getDoubleValueNoDecimal()")); 213 Assert.assertEquals( 214 "foo", executeJavaScriptAndGetStringResult("testObject.getStringValue()")); 215 Assert.assertEquals( 216 "", executeJavaScriptAndGetStringResult("testObject.getEmptyStringValue()")); 217 Assert.assertTrue( 218 executeJavaScriptAndGetBooleanResult("undefined === testObject.getVoidValue()")); 219 } 220 } 221