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