| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.content.browser; | 5 package org.chromium.content.browser; |
| 6 | 6 |
| 7 import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout; | 7 import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout; |
| 8 | 8 |
| 9 import android.support.test.InstrumentationRegistry; |
| 9 import android.support.test.filters.SmallTest; | 10 import android.support.test.filters.SmallTest; |
| 10 | 11 |
| 11 import junit.framework.Assert; | 12 import org.junit.Assert; |
| 13 import org.junit.Rule; |
| 14 import org.junit.Test; |
| 15 import org.junit.runner.RunWith; |
| 12 | 16 |
| 13 import org.chromium.base.annotations.SuppressFBWarnings; | 17 import org.chromium.base.annotations.SuppressFBWarnings; |
| 14 import org.chromium.base.test.util.CommandLineFlags; | 18 import org.chromium.base.test.BaseJUnit4ClassRunner; |
| 19 import org.chromium.base.test.util.CommandLineTestRule; |
| 15 import org.chromium.base.test.util.Feature; | 20 import org.chromium.base.test.util.Feature; |
| 16 import org.chromium.content.browser.JavaBridgeTestCommon.Controller; | 21 import org.chromium.content.browser.JavaBridgeTestCommon.Controller; |
| 17 import org.chromium.content.browser.test.util.TestCallbackHelperContainer; | 22 import org.chromium.content.browser.test.util.TestCallbackHelperContainer; |
| 23 import org.chromium.content.common.ContentSwitches; |
| 18 import org.chromium.content_public.browser.LoadUrlParams; | 24 import org.chromium.content_public.browser.LoadUrlParams; |
| 19 | 25 |
| 20 import java.lang.annotation.ElementType; | 26 import java.lang.annotation.ElementType; |
| 21 import java.lang.annotation.Retention; | 27 import java.lang.annotation.Retention; |
| 22 import java.lang.annotation.RetentionPolicy; | 28 import java.lang.annotation.RetentionPolicy; |
| 23 import java.lang.annotation.Target; | 29 import java.lang.annotation.Target; |
| 24 import java.lang.ref.WeakReference; | 30 import java.lang.ref.WeakReference; |
| 25 import java.util.concurrent.CountDownLatch; | 31 import java.util.concurrent.CountDownLatch; |
| 26 | 32 |
| 27 /** | 33 /** |
| 28 * Part of the test suite for the Java Bridge. Tests a number of features includ
ing ... | 34 * Part of the test suite for the Java Bridge. Tests a number of features includ
ing ... |
| 29 * - The type of injected objects | 35 * - The type of injected objects |
| 30 * - The type of their methods | 36 * - The type of their methods |
| 31 * - Replacing objects | 37 * - Replacing objects |
| 32 * - Removing objects | 38 * - Removing objects |
| 33 * - Access control | 39 * - Access control |
| 34 * - Calling methods on returned objects | 40 * - Calling methods on returned objects |
| 35 * - Multiply injected objects | 41 * - Multiply injected objects |
| 36 * - Threading | 42 * - Threading |
| 37 * - Inheritance | 43 * - Inheritance |
| 38 */ | 44 */ |
| 45 @RunWith(BaseJUnit4ClassRunner.class) |
| 39 @SuppressFBWarnings( | 46 @SuppressFBWarnings( |
| 40 {"UMAC_UNCALLABLE_METHOD_OF_ANONYMOUS_CLASS", "URF_UNREAD_PUBLIC_OR_PROT
ECTED_FIELD"}) | 47 {"UMAC_UNCALLABLE_METHOD_OF_ANONYMOUS_CLASS", "URF_UNREAD_PUBLIC_OR_PROT
ECTED_FIELD"}) |
| 41 public class JavaBridgeBasicsTest extends JavaBridgeTestBase { | 48 public class JavaBridgeBasicsTest { |
| 49 @Rule |
| 50 public JavaBridgeActivityTestRule mActivityTestRule = new JavaBridgeActivity
TestRule(false); |
| 51 |
| 52 @Rule |
| 53 public CommandLineTestRule mCommandLineRule = new CommandLineTestRule(false)
; |
| 54 |
| 42 @SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD") | 55 @SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD") |
| 43 private static class TestController extends Controller { | 56 private static class TestController extends Controller { |
| 44 private int mIntValue; | 57 private int mIntValue; |
| 45 private long mLongValue; | 58 private long mLongValue; |
| 46 private String mStringValue; | 59 private String mStringValue; |
| 47 private boolean mBooleanValue; | 60 private boolean mBooleanValue; |
| 48 | 61 |
| 49 public synchronized void setIntValue(int x) { | 62 public synchronized void setIntValue(int x) { |
| 50 mIntValue = x; | 63 mIntValue = x; |
| 51 notifyResultIsReady(); | 64 notifyResultIsReady(); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 } | 99 } |
| 87 | 100 |
| 88 private static class ObjectWithStaticMethod { | 101 private static class ObjectWithStaticMethod { |
| 89 public static String staticMethod() { | 102 public static String staticMethod() { |
| 90 return "foo"; | 103 return "foo"; |
| 91 } | 104 } |
| 92 } | 105 } |
| 93 | 106 |
| 94 TestController mTestController; | 107 TestController mTestController; |
| 95 | 108 |
| 96 @Override | 109 private void setUpHelper() throws Exception { |
| 97 protected void setUp() throws Exception { | 110 mActivityTestRule.setUpContentView(); |
| 98 super.setUp(); | |
| 99 mTestController = new TestController(); | 111 mTestController = new TestController(); |
| 100 injectObjectAndReload(mTestController, "testController"); | 112 mActivityTestRule.injectObjectAndReload(mTestController, "testController
"); |
| 101 } | 113 } |
| 102 | 114 |
| 103 // Note that this requires that we can pass a JavaScript string to Java. | 115 // Note that this requires that we can pass a JavaScript string to Java. |
| 104 protected String executeJavaScriptAndGetStringResult(String script) throws T
hrowable { | 116 protected String executeJavaScriptAndGetStringResult(String script) throws T
hrowable { |
| 105 executeJavaScript("testController.setStringValue(" + script + ");"); | 117 mActivityTestRule.executeJavaScript("testController.setStringValue(" + s
cript + ");"); |
| 106 return mTestController.waitForStringValue(); | 118 return mTestController.waitForStringValue(); |
| 107 } | 119 } |
| 108 | 120 |
| 109 // Note that this requires that we can pass a JavaScript boolean to Java. | 121 // Note that this requires that we can pass a JavaScript boolean to Java. |
| 110 private void executeAndSetIfException(String script) throws Throwable { | 122 private void executeAndSetIfException(String script) throws Throwable { |
| 111 executeJavaScript("try {" | 123 mActivityTestRule.executeJavaScript("try {" + script + ";" |
| 112 + script + ";" | |
| 113 + " testController.setBooleanValue(false);" | 124 + " testController.setBooleanValue(false);" |
| 114 + "} catch (exception) {" | 125 + "} catch (exception) {" |
| 115 + " testController.setBooleanValue(true);" | 126 + " testController.setBooleanValue(true);" |
| 116 + "}"); | 127 + "}"); |
| 117 } | 128 } |
| 118 | 129 |
| 119 private void assertRaisesException(String script) throws Throwable { | 130 private void assertRaisesException(String script) throws Throwable { |
| 120 executeAndSetIfException(script); | 131 executeAndSetIfException(script); |
| 121 assertTrue(mTestController.waitForBooleanValue()); | 132 Assert.assertTrue(mTestController.waitForBooleanValue()); |
| 122 } | 133 } |
| 123 | 134 |
| 124 private void assertNoRaisedException(String script) throws Throwable { | 135 private void assertNoRaisedException(String script) throws Throwable { |
| 125 executeAndSetIfException(script); | 136 executeAndSetIfException(script); |
| 126 assertFalse(mTestController.waitForBooleanValue()); | 137 Assert.assertFalse(mTestController.waitForBooleanValue()); |
| 127 } | 138 } |
| 128 | 139 |
| 140 @Test |
| 129 @SmallTest | 141 @SmallTest |
| 130 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 142 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 131 public void testTypeOfInjectedObject() throws Throwable { | 143 public void testTypeOfInjectedObject() throws Throwable { |
| 132 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testC
ontroller")); | 144 setUpHelper(); |
| 145 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f testController")); |
| 133 } | 146 } |
| 134 | 147 |
| 148 @Test |
| 135 @SmallTest | 149 @SmallTest |
| 136 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 150 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 137 public void testAdditionNotReflectedUntilReload() throws Throwable { | 151 public void testAdditionNotReflectedUntilReload() throws Throwable { |
| 138 assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof te
stObject")); | 152 setUpHelper(); |
| 139 runTestOnUiThread(new Runnable() { | 153 Assert.assertEquals("undefined", executeJavaScriptAndGetStringResult("ty
peof testObject")); |
| 154 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable(
) { |
| 140 @Override | 155 @Override |
| 141 public void run() { | 156 public void run() { |
| 142 getContentViewCore().addPossiblyUnsafeJavascriptInterface( | 157 mActivityTestRule.getContentViewCore().addPossiblyUnsafeJavascri
ptInterface( |
| 143 new Object(), "testObject", null); | 158 new Object(), "testObject", null); |
| 144 } | 159 } |
| 145 }); | 160 }); |
| 146 assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof te
stObject")); | 161 Assert.assertEquals("undefined", executeJavaScriptAndGetStringResult("ty
peof testObject")); |
| 147 synchronousPageReload(); | 162 mActivityTestRule.synchronousPageReload(); |
| 148 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testO
bject")); | 163 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f testObject")); |
| 149 } | 164 } |
| 150 | 165 |
| 166 @Test |
| 151 @SmallTest | 167 @SmallTest |
| 152 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 168 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 153 public void testRemovalNotReflectedUntilReload() throws Throwable { | 169 public void testRemovalNotReflectedUntilReload() throws Throwable { |
| 154 injectObjectAndReload(new Object() { | 170 setUpHelper(); |
| 171 mActivityTestRule.injectObjectAndReload(new Object() { |
| 155 public void method() { | 172 public void method() { |
| 156 mTestController.setStringValue("I'm here"); | 173 mTestController.setStringValue("I'm here"); |
| 157 } | 174 } |
| 158 }, "testObject"); | 175 }, "testObject"); |
| 159 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testO
bject")); | 176 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f testObject")); |
| 160 executeJavaScript("testObject.method()"); | 177 mActivityTestRule.executeJavaScript("testObject.method()"); |
| 161 assertEquals("I'm here", mTestController.waitForStringValue()); | 178 Assert.assertEquals("I'm here", mTestController.waitForStringValue()); |
| 162 runTestOnUiThread(new Runnable() { | 179 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable(
) { |
| 163 @Override | 180 @Override |
| 164 public void run() { | 181 public void run() { |
| 165 getContentViewCore().removeJavascriptInterface("testObject"); | 182 mActivityTestRule.getContentViewCore().removeJavascriptInterface
("testObject"); |
| 166 } | 183 } |
| 167 }); | 184 }); |
| 168 // Check that the Java object is being held by the Java bridge, thus it'
s not | 185 // Check that the Java object is being held by the Java bridge, thus it'
s not |
| 169 // collected. Note that despite that what JavaDoc says about invoking "g
c()", both Dalvik | 186 // collected. Note that despite that what JavaDoc says about invoking "g
c()", both Dalvik |
| 170 // and ART actually run the collector if called via Runtime. | 187 // and ART actually run the collector if called via Runtime. |
| 171 Runtime.getRuntime().gc(); | 188 Runtime.getRuntime().gc(); |
| 172 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testO
bject")); | 189 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f testObject")); |
| 173 executeJavaScript("testObject.method()"); | 190 mActivityTestRule.executeJavaScript("testObject.method()"); |
| 174 assertEquals("I'm here", mTestController.waitForStringValue()); | 191 Assert.assertEquals("I'm here", mTestController.waitForStringValue()); |
| 175 synchronousPageReload(); | 192 mActivityTestRule.synchronousPageReload(); |
| 176 assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof te
stObject")); | 193 Assert.assertEquals("undefined", executeJavaScriptAndGetStringResult("ty
peof testObject")); |
| 177 } | 194 } |
| 178 | 195 |
| 196 @Test |
| 179 @SmallTest | 197 @SmallTest |
| 180 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 198 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 181 public void testRemoveObjectNotAdded() throws Throwable { | 199 public void testRemoveObjectNotAdded() throws Throwable { |
| 200 setUpHelper(); |
| 182 TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = | 201 TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = |
| 183 getTestCallBackHelperContainer().getOnPageFinishedHelper(); | 202 mActivityTestRule.getTestCallBackHelperContainer().getOnPageFini
shedHelper(); |
| 184 int currentCallCount = onPageFinishedHelper.getCallCount(); | 203 int currentCallCount = onPageFinishedHelper.getCallCount(); |
| 185 runTestOnUiThread(new Runnable() { | 204 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable(
) { |
| 186 @Override | 205 @Override |
| 187 public void run() { | 206 public void run() { |
| 188 getContentViewCore().removeJavascriptInterface("foo"); | 207 mActivityTestRule.getContentViewCore().removeJavascriptInterface
("foo"); |
| 189 getContentViewCore().getWebContents().getNavigationController().
reload(true); | 208 mActivityTestRule.getContentViewCore() |
| 209 .getWebContents() |
| 210 .getNavigationController() |
| 211 .reload(true); |
| 190 } | 212 } |
| 191 }); | 213 }); |
| 192 onPageFinishedHelper.waitForCallback(currentCallCount); | 214 onPageFinishedHelper.waitForCallback(currentCallCount); |
| 193 assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof fo
o")); | 215 Assert.assertEquals("undefined", executeJavaScriptAndGetStringResult("ty
peof foo")); |
| 194 } | 216 } |
| 195 | 217 |
| 218 @Test |
| 196 @SmallTest | 219 @SmallTest |
| 197 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 220 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 198 public void testTypeOfMethod() throws Throwable { | 221 public void testTypeOfMethod() throws Throwable { |
| 199 assertEquals("function", | 222 setUpHelper(); |
| 223 Assert.assertEquals("function", |
| 200 executeJavaScriptAndGetStringResult("typeof testController.setSt
ringValue")); | 224 executeJavaScriptAndGetStringResult("typeof testController.setSt
ringValue")); |
| 201 } | 225 } |
| 202 | 226 |
| 227 @Test |
| 203 @SmallTest | 228 @SmallTest |
| 204 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 229 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 205 public void testTypeOfInvalidMethod() throws Throwable { | 230 public void testTypeOfInvalidMethod() throws Throwable { |
| 206 assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof te
stController.foo")); | 231 setUpHelper(); |
| 232 Assert.assertEquals( |
| 233 "undefined", executeJavaScriptAndGetStringResult("typeof testCon
troller.foo")); |
| 207 } | 234 } |
| 208 | 235 |
| 236 @Test |
| 209 @SmallTest | 237 @SmallTest |
| 210 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 238 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 211 public void testCallingInvalidMethodRaisesException() throws Throwable { | 239 public void testCallingInvalidMethodRaisesException() throws Throwable { |
| 240 setUpHelper(); |
| 212 assertRaisesException("testController.foo()"); | 241 assertRaisesException("testController.foo()"); |
| 213 } | 242 } |
| 214 | 243 |
| 244 @Test |
| 215 @SmallTest | 245 @SmallTest |
| 216 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 246 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 217 public void testUncaughtJavaExceptionRaisesJavaScriptException() throws Thro
wable { | 247 public void testUncaughtJavaExceptionRaisesJavaScriptException() throws Thro
wable { |
| 218 injectObjectAndReload(new Object() { | 248 setUpHelper(); |
| 249 mActivityTestRule.injectObjectAndReload(new Object() { |
| 219 public void method() { | 250 public void method() { |
| 220 throw new RuntimeException("foo"); | 251 throw new RuntimeException("foo"); |
| 221 } | 252 } |
| 222 }, "testObject"); | 253 }, "testObject"); |
| 223 assertRaisesException("testObject.method()"); | 254 assertRaisesException("testObject.method()"); |
| 224 } | 255 } |
| 225 | 256 |
| 257 @Test |
| 226 @SmallTest | 258 @SmallTest |
| 227 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 259 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 228 public void testCallingAsConstructorRaisesException() throws Throwable { | 260 public void testCallingAsConstructorRaisesException() throws Throwable { |
| 261 setUpHelper(); |
| 229 assertRaisesException("new testController.setStringValue('foo')"); | 262 assertRaisesException("new testController.setStringValue('foo')"); |
| 230 } | 263 } |
| 231 | 264 |
| 265 @Test |
| 232 @SmallTest | 266 @SmallTest |
| 233 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 267 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 234 public void testCallingOnNonInjectedObjectRaisesException() throws Throwable
{ | 268 public void testCallingOnNonInjectedObjectRaisesException() throws Throwable
{ |
| 269 setUpHelper(); |
| 235 assertRaisesException("testController.setStringValue.call({}, 'foo')"); | 270 assertRaisesException("testController.setStringValue.call({}, 'foo')"); |
| 236 } | 271 } |
| 237 | 272 |
| 273 @Test |
| 238 @SmallTest | 274 @SmallTest |
| 239 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 275 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 240 public void testCallingOnInstanceOfOtherClassRaisesException() throws Throwa
ble { | 276 public void testCallingOnInstanceOfOtherClassRaisesException() throws Throwa
ble { |
| 241 injectObjectAndReload(new Object(), "testObject"); | 277 setUpHelper(); |
| 242 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testO
bject")); | 278 mActivityTestRule.injectObjectAndReload(new Object(), "testObject"); |
| 243 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testC
ontroller")); | 279 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f testObject")); |
| 244 assertEquals("function", | 280 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f testController")); |
| 281 Assert.assertEquals("function", |
| 245 executeJavaScriptAndGetStringResult("typeof testController.setSt
ringValue")); | 282 executeJavaScriptAndGetStringResult("typeof testController.setSt
ringValue")); |
| 246 assertRaisesException("testController.setStringValue.call(testObject, 'f
oo')"); | 283 assertRaisesException("testController.setStringValue.call(testObject, 'f
oo')"); |
| 247 } | 284 } |
| 248 | 285 |
| 249 // Note that this requires that we can pass a JavaScript string to Java. | 286 // Note that this requires that we can pass a JavaScript string to Java. |
| 287 @Test |
| 250 @SmallTest | 288 @SmallTest |
| 251 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 289 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 252 public void testTypeOfStaticMethod() throws Throwable { | 290 public void testTypeOfStaticMethod() throws Throwable { |
| 253 injectObjectAndReload(new ObjectWithStaticMethod(), "testObject"); | 291 setUpHelper(); |
| 254 executeJavaScript("testController.setStringValue(typeof testObject.stati
cMethod)"); | 292 mActivityTestRule.injectObjectAndReload(new ObjectWithStaticMethod(), "t
estObject"); |
| 255 assertEquals("function", mTestController.waitForStringValue()); | 293 mActivityTestRule.executeJavaScript( |
| 294 "testController.setStringValue(typeof testObject.staticMethod)")
; |
| 295 Assert.assertEquals("function", mTestController.waitForStringValue()); |
| 256 } | 296 } |
| 257 | 297 |
| 258 // Note that this requires that we can pass a JavaScript string to Java. | 298 // Note that this requires that we can pass a JavaScript string to Java. |
| 299 @Test |
| 259 @SmallTest | 300 @SmallTest |
| 260 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 301 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 261 public void testCallStaticMethod() throws Throwable { | 302 public void testCallStaticMethod() throws Throwable { |
| 262 injectObjectAndReload(new ObjectWithStaticMethod(), "testObject"); | 303 setUpHelper(); |
| 263 executeJavaScript("testController.setStringValue(testObject.staticMethod
())"); | 304 mActivityTestRule.injectObjectAndReload(new ObjectWithStaticMethod(), "t
estObject"); |
| 264 assertEquals("foo", mTestController.waitForStringValue()); | 305 mActivityTestRule.executeJavaScript( |
| 306 "testController.setStringValue(testObject.staticMethod())"); |
| 307 Assert.assertEquals("foo", mTestController.waitForStringValue()); |
| 265 } | 308 } |
| 266 | 309 |
| 310 @Test |
| 267 @SmallTest | 311 @SmallTest |
| 268 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 312 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 269 public void testPrivateMethodNotExposed() throws Throwable { | 313 public void testPrivateMethodNotExposed() throws Throwable { |
| 270 injectObjectAndReload(new Object() { | 314 setUpHelper(); |
| 315 mActivityTestRule.injectObjectAndReload(new Object() { |
| 271 private void method() {} | 316 private void method() {} |
| 272 protected void method2() {} | 317 protected void method2() {} |
| 273 }, "testObject"); | 318 }, "testObject"); |
| 274 assertEquals("undefined", | 319 Assert.assertEquals( |
| 275 executeJavaScriptAndGetStringResult("typeof testObject.method"))
; | 320 "undefined", executeJavaScriptAndGetStringResult("typeof testObj
ect.method")); |
| 276 assertEquals("undefined", | 321 Assert.assertEquals( |
| 277 executeJavaScriptAndGetStringResult("typeof testObject.method2")
); | 322 "undefined", executeJavaScriptAndGetStringResult("typeof testObj
ect.method2")); |
| 278 } | 323 } |
| 279 | 324 |
| 325 @Test |
| 280 @SmallTest | 326 @SmallTest |
| 281 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 327 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 282 public void testReplaceInjectedObject() throws Throwable { | 328 public void testReplaceInjectedObject() throws Throwable { |
| 283 injectObjectAndReload(new Object() { | 329 setUpHelper(); |
| 330 mActivityTestRule.injectObjectAndReload(new Object() { |
| 284 public void method() { | 331 public void method() { |
| 285 mTestController.setStringValue("object 1"); | 332 mTestController.setStringValue("object 1"); |
| 286 } | 333 } |
| 287 }, "testObject"); | 334 }, "testObject"); |
| 288 executeJavaScript("testObject.method()"); | 335 mActivityTestRule.executeJavaScript("testObject.method()"); |
| 289 assertEquals("object 1", mTestController.waitForStringValue()); | 336 Assert.assertEquals("object 1", mTestController.waitForStringValue()); |
| 290 | 337 |
| 291 injectObjectAndReload(new Object() { | 338 mActivityTestRule.injectObjectAndReload(new Object() { |
| 292 public void method() { | 339 public void method() { |
| 293 mTestController.setStringValue("object 2"); | 340 mTestController.setStringValue("object 2"); |
| 294 } | 341 } |
| 295 }, "testObject"); | 342 }, "testObject"); |
| 296 executeJavaScript("testObject.method()"); | 343 mActivityTestRule.executeJavaScript("testObject.method()"); |
| 297 assertEquals("object 2", mTestController.waitForStringValue()); | 344 Assert.assertEquals("object 2", mTestController.waitForStringValue()); |
| 298 } | 345 } |
| 299 | 346 |
| 347 @Test |
| 300 @SmallTest | 348 @SmallTest |
| 301 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 349 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 302 public void testInjectNullObjectIsIgnored() throws Throwable { | 350 public void testInjectNullObjectIsIgnored() throws Throwable { |
| 303 injectObjectAndReload(null, "testObject"); | 351 setUpHelper(); |
| 304 assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof te
stObject")); | 352 mActivityTestRule.injectObjectAndReload(null, "testObject"); |
| 353 Assert.assertEquals("undefined", executeJavaScriptAndGetStringResult("ty
peof testObject")); |
| 305 } | 354 } |
| 306 | 355 |
| 356 @Test |
| 307 @SmallTest | 357 @SmallTest |
| 308 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 358 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 309 public void testReplaceInjectedObjectWithNullObjectIsIgnored() throws Throwa
ble { | 359 public void testReplaceInjectedObjectWithNullObjectIsIgnored() throws Throwa
ble { |
| 310 injectObjectAndReload(new Object(), "testObject"); | 360 setUpHelper(); |
| 311 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testO
bject")); | 361 mActivityTestRule.injectObjectAndReload(new Object(), "testObject"); |
| 312 injectObjectAndReload(null, "testObject"); | 362 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f testObject")); |
| 313 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testO
bject")); | 363 mActivityTestRule.injectObjectAndReload(null, "testObject"); |
| 364 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f testObject")); |
| 314 } | 365 } |
| 315 | 366 |
| 367 @Test |
| 316 @SmallTest | 368 @SmallTest |
| 317 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 369 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 318 public void testCallOverloadedMethodWithDifferentNumberOfArguments() throws
Throwable { | 370 public void testCallOverloadedMethodWithDifferentNumberOfArguments() throws
Throwable { |
| 319 injectObjectAndReload(new Object() { | 371 setUpHelper(); |
| 372 mActivityTestRule.injectObjectAndReload(new Object() { |
| 320 public void method() { | 373 public void method() { |
| 321 mTestController.setStringValue("0 args"); | 374 mTestController.setStringValue("0 args"); |
| 322 } | 375 } |
| 323 | 376 |
| 324 public void method(int x) { | 377 public void method(int x) { |
| 325 mTestController.setStringValue("1 arg"); | 378 mTestController.setStringValue("1 arg"); |
| 326 } | 379 } |
| 327 | 380 |
| 328 public void method(int x, int y) { | 381 public void method(int x, int y) { |
| 329 mTestController.setStringValue("2 args"); | 382 mTestController.setStringValue("2 args"); |
| 330 } | 383 } |
| 331 }, "testObject"); | 384 }, "testObject"); |
| 332 executeJavaScript("testObject.method()"); | 385 mActivityTestRule.executeJavaScript("testObject.method()"); |
| 333 assertEquals("0 args", mTestController.waitForStringValue()); | 386 Assert.assertEquals("0 args", mTestController.waitForStringValue()); |
| 334 executeJavaScript("testObject.method(42)"); | 387 mActivityTestRule.executeJavaScript("testObject.method(42)"); |
| 335 assertEquals("1 arg", mTestController.waitForStringValue()); | 388 Assert.assertEquals("1 arg", mTestController.waitForStringValue()); |
| 336 executeJavaScript("testObject.method(null)"); | 389 mActivityTestRule.executeJavaScript("testObject.method(null)"); |
| 337 assertEquals("1 arg", mTestController.waitForStringValue()); | 390 Assert.assertEquals("1 arg", mTestController.waitForStringValue()); |
| 338 executeJavaScript("testObject.method(undefined)"); | 391 mActivityTestRule.executeJavaScript("testObject.method(undefined)"); |
| 339 assertEquals("1 arg", mTestController.waitForStringValue()); | 392 Assert.assertEquals("1 arg", mTestController.waitForStringValue()); |
| 340 executeJavaScript("testObject.method(42, 42)"); | 393 mActivityTestRule.executeJavaScript("testObject.method(42, 42)"); |
| 341 assertEquals("2 args", mTestController.waitForStringValue()); | 394 Assert.assertEquals("2 args", mTestController.waitForStringValue()); |
| 342 } | 395 } |
| 343 | 396 |
| 397 @Test |
| 344 @SmallTest | 398 @SmallTest |
| 345 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 399 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 346 public void testCallMethodWithWrongNumberOfArgumentsRaisesException() throws
Throwable { | 400 public void testCallMethodWithWrongNumberOfArgumentsRaisesException() throws
Throwable { |
| 401 setUpHelper(); |
| 347 assertRaisesException("testController.setIntValue()"); | 402 assertRaisesException("testController.setIntValue()"); |
| 348 assertRaisesException("testController.setIntValue(42, 42)"); | 403 assertRaisesException("testController.setIntValue(42, 42)"); |
| 349 } | 404 } |
| 350 | 405 |
| 406 @Test |
| 351 @SmallTest | 407 @SmallTest |
| 352 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 408 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 353 public void testObjectPersistsAcrossPageLoads() throws Throwable { | 409 public void testObjectPersistsAcrossPageLoads() throws Throwable { |
| 354 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testC
ontroller")); | 410 setUpHelper(); |
| 355 synchronousPageReload(); | 411 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f testController")); |
| 356 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testC
ontroller")); | 412 mActivityTestRule.synchronousPageReload(); |
| 413 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f testController")); |
| 357 } | 414 } |
| 358 | 415 |
| 416 @Test |
| 359 @SmallTest | 417 @SmallTest |
| 360 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 418 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 361 public void testCustomPropertiesCleanedUpOnPageReloads() throws Throwable { | 419 public void testCustomPropertiesCleanedUpOnPageReloads() throws Throwable { |
| 362 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testC
ontroller")); | 420 setUpHelper(); |
| 363 executeJavaScript("testController.myProperty = 42;"); | 421 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f testController")); |
| 364 assertEquals("42", executeJavaScriptAndGetStringResult("testController.m
yProperty")); | 422 mActivityTestRule.executeJavaScript("testController.myProperty = 42;"); |
| 365 synchronousPageReload(); | 423 Assert.assertEquals("42", executeJavaScriptAndGetStringResult("testContr
oller.myProperty")); |
| 366 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testC
ontroller")); | 424 mActivityTestRule.synchronousPageReload(); |
| 367 assertEquals("undefined", executeJavaScriptAndGetStringResult("testContr
oller.myProperty")); | 425 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f testController")); |
| 426 Assert.assertEquals( |
| 427 "undefined", executeJavaScriptAndGetStringResult("testController
.myProperty")); |
| 368 } | 428 } |
| 369 | 429 |
| 430 @Test |
| 370 @SmallTest | 431 @SmallTest |
| 371 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 432 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 372 public void testSameObjectInjectedMultipleTimes() throws Throwable { | 433 public void testSameObjectInjectedMultipleTimes() throws Throwable { |
| 434 setUpHelper(); |
| 373 class TestObject { | 435 class TestObject { |
| 374 private int mNumMethodInvocations; | 436 private int mNumMethodInvocations; |
| 375 | 437 |
| 376 public void method() { | 438 public void method() { |
| 377 mTestController.setIntValue(++mNumMethodInvocations); | 439 mTestController.setIntValue(++mNumMethodInvocations); |
| 378 } | 440 } |
| 379 } | 441 } |
| 380 final TestObject testObject = new TestObject(); | 442 final TestObject testObject = new TestObject(); |
| 381 injectObjectsAndReload(testObject, "testObject1", testObject, "testObjec
t2", null); | 443 mActivityTestRule.injectObjectsAndReload( |
| 382 executeJavaScript("testObject1.method()"); | 444 testObject, "testObject1", testObject, "testObject2", null); |
| 383 assertEquals(1, mTestController.waitForIntValue()); | 445 mActivityTestRule.executeJavaScript("testObject1.method()"); |
| 384 executeJavaScript("testObject2.method()"); | 446 Assert.assertEquals(1, mTestController.waitForIntValue()); |
| 385 assertEquals(2, mTestController.waitForIntValue()); | 447 mActivityTestRule.executeJavaScript("testObject2.method()"); |
| 448 Assert.assertEquals(2, mTestController.waitForIntValue()); |
| 386 } | 449 } |
| 387 | 450 |
| 451 @Test |
| 388 @SmallTest | 452 @SmallTest |
| 389 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 453 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 390 public void testCallMethodOnReturnedObject() throws Throwable { | 454 public void testCallMethodOnReturnedObject() throws Throwable { |
| 391 injectObjectAndReload(new Object() { | 455 setUpHelper(); |
| 456 mActivityTestRule.injectObjectAndReload(new Object() { |
| 392 public Object getInnerObject() { | 457 public Object getInnerObject() { |
| 393 return new Object() { | 458 return new Object() { |
| 394 public void method(int x) { | 459 public void method(int x) { |
| 395 mTestController.setIntValue(x); | 460 mTestController.setIntValue(x); |
| 396 } | 461 } |
| 397 }; | 462 }; |
| 398 } | 463 } |
| 399 }, "testObject"); | 464 }, "testObject"); |
| 400 executeJavaScript("testObject.getInnerObject().method(42)"); | 465 mActivityTestRule.executeJavaScript("testObject.getInnerObject().method(
42)"); |
| 401 assertEquals(42, mTestController.waitForIntValue()); | 466 Assert.assertEquals(42, mTestController.waitForIntValue()); |
| 402 } | 467 } |
| 403 | 468 |
| 469 @Test |
| 404 @SmallTest | 470 @SmallTest |
| 405 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 471 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 406 public void testReturnedObjectInjectedElsewhere() throws Throwable { | 472 public void testReturnedObjectInjectedElsewhere() throws Throwable { |
| 473 setUpHelper(); |
| 407 class InnerObject { | 474 class InnerObject { |
| 408 private int mNumMethodInvocations; | 475 private int mNumMethodInvocations; |
| 409 | 476 |
| 410 public void method() { | 477 public void method() { |
| 411 mTestController.setIntValue(++mNumMethodInvocations); | 478 mTestController.setIntValue(++mNumMethodInvocations); |
| 412 } | 479 } |
| 413 } | 480 } |
| 414 final InnerObject innerObject = new InnerObject(); | 481 final InnerObject innerObject = new InnerObject(); |
| 415 final Object object = new Object() { | 482 final Object object = new Object() { |
| 416 public InnerObject getInnerObject() { | 483 public InnerObject getInnerObject() { |
| 417 return innerObject; | 484 return innerObject; |
| 418 } | 485 } |
| 419 }; | 486 }; |
| 420 injectObjectsAndReload(object, "testObject", innerObject, "innerObject",
null); | 487 mActivityTestRule.injectObjectsAndReload( |
| 421 executeJavaScript("testObject.getInnerObject().method()"); | 488 object, "testObject", innerObject, "innerObject", null); |
| 422 assertEquals(1, mTestController.waitForIntValue()); | 489 mActivityTestRule.executeJavaScript("testObject.getInnerObject().method(
)"); |
| 423 executeJavaScript("innerObject.method()"); | 490 Assert.assertEquals(1, mTestController.waitForIntValue()); |
| 424 assertEquals(2, mTestController.waitForIntValue()); | 491 mActivityTestRule.executeJavaScript("innerObject.method()"); |
| 492 Assert.assertEquals(2, mTestController.waitForIntValue()); |
| 425 } | 493 } |
| 426 | 494 |
| 427 // Verify that Java objects returned from bridge object methods are derefere
nced | 495 // Verify that Java objects returned from bridge object methods are derefere
nced |
| 428 // on the Java side once they have been fully dereferenced on the JS side. | 496 // on the Java side once they have been fully dereferenced on the JS side. |
| 429 // Failing this test would mean that methods returning objects effectively c
reate a memory | 497 // Failing this test would mean that methods returning objects effectively c
reate a memory |
| 430 // leak. | 498 // leak. |
| 499 @Test |
| 431 @SmallTest | 500 @SmallTest |
| 432 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 501 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 433 @CommandLineFlags.Add("js-flags=--expose-gc") | |
| 434 public void testReturnedObjectIsGarbageCollected() throws Throwable { | 502 public void testReturnedObjectIsGarbageCollected() throws Throwable { |
| 435 // Make sure V8 exposes "gc" property on the global object (enabled with
--expose-gc flag) | 503 mCommandLineRule.setFlags(ContentSwitches.ENABLE_TEST_INTENTS, "js-flags
=--expose-gc"); |
| 436 assertEquals("function", executeJavaScriptAndGetStringResult("typeof gc"
)); | 504 mCommandLineRule.setUp(); |
| 505 setUpHelper(); |
| 506 Assert.assertEquals("function", executeJavaScriptAndGetStringResult("typ
eof gc")); |
| 437 class InnerObject { | 507 class InnerObject { |
| 438 } | 508 } |
| 439 class TestObject { | 509 class TestObject { |
| 440 public InnerObject getInnerObject() { | 510 public InnerObject getInnerObject() { |
| 441 InnerObject inner = new InnerObject(); | 511 InnerObject inner = new InnerObject(); |
| 442 mWeakRefForInner = new WeakReference<InnerObject>(inner); | 512 mWeakRefForInner = new WeakReference<InnerObject>(inner); |
| 443 return inner; | 513 return inner; |
| 444 } | 514 } |
| 445 // A weak reference is used to check InnerObject instance reachabili
ty. | 515 // A weak reference is used to check InnerObject instance reachabili
ty. |
| 446 WeakReference<InnerObject> mWeakRefForInner; | 516 WeakReference<InnerObject> mWeakRefForInner; |
| 447 } | 517 } |
| 448 TestObject object = new TestObject(); | 518 TestObject object = new TestObject(); |
| 449 injectObjectAndReload(object, "testObject"); | 519 mActivityTestRule.injectObjectAndReload(object, "testObject"); |
| 450 // Initially, store a reference to the inner object in JS to make sure i
t's not | 520 // Initially, store a reference to the inner object in JS to make sure i
t's not |
| 451 // garbage-collected prematurely. | 521 // garbage-collected prematurely. |
| 452 assertEquals("object", executeJavaScriptAndGetStringResult( | 522 Assert.assertEquals("object", |
| 453 "(function() { " | 523 executeJavaScriptAndGetStringResult("(function() { " |
| 454 + "globalInner = testObject.getInnerObject(); return typ
eof globalInner; " | 524 + "globalInner = testObject.getInnerObject(); return typ
eof globalInner; " |
| 455 + "})()")); | 525 + "})()")); |
| 456 assertTrue(object.mWeakRefForInner.get() != null); | 526 Assert.assertTrue(object.mWeakRefForInner.get() != null); |
| 457 // Check that returned Java object is being held by the Java bridge, thu
s it's not | 527 // Check that returned Java object is being held by the Java bridge, thu
s it's not |
| 458 // collected. Note that despite that what JavaDoc says about invoking "
gc()", both Dalvik | 528 // collected. Note that despite that what JavaDoc says about invoking "
gc()", both Dalvik |
| 459 // and ART actually run the collector. | 529 // and ART actually run the collector. |
| 460 Runtime.getRuntime().gc(); | 530 Runtime.getRuntime().gc(); |
| 461 assertTrue(object.mWeakRefForInner.get() != null); | 531 Assert.assertTrue(object.mWeakRefForInner.get() != null); |
| 462 // Now dereference the inner object in JS and run GC to collect the inte
rface object. | 532 // Now dereference the inner object in JS and run GC to collect the inte
rface object. |
| 463 assertEquals("true", executeJavaScriptAndGetStringResult( | 533 Assert.assertEquals("true", |
| 464 "(function() { " | 534 executeJavaScriptAndGetStringResult("(function() { " |
| 465 + "delete globalInner; gc(); return (typeof globalInner
== 'undefined'); " | 535 + "delete globalInner; gc(); return (typeof globalInner
== 'undefined'); " |
| 466 + "})()")); | 536 + "})()")); |
| 467 // Force GC on the Java side again. The bridge had to release the inner
object, so it must | 537 // Force GC on the Java side again. The bridge had to release the inner
object, so it must |
| 468 // be collected this time. | 538 // be collected this time. |
| 469 Runtime.getRuntime().gc(); | 539 Runtime.getRuntime().gc(); |
| 470 assertEquals(null, object.mWeakRefForInner.get()); | 540 Assert.assertEquals(null, object.mWeakRefForInner.get()); |
| 471 } | 541 } |
| 472 | 542 |
| 543 @Test |
| 473 @SmallTest | 544 @SmallTest |
| 474 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 545 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 475 public void testSameReturnedObjectUsesSameWrapper() throws Throwable { | 546 public void testSameReturnedObjectUsesSameWrapper() throws Throwable { |
| 547 setUpHelper(); |
| 476 class InnerObject { | 548 class InnerObject { |
| 477 } | 549 } |
| 478 final InnerObject innerObject = new InnerObject(); | 550 final InnerObject innerObject = new InnerObject(); |
| 479 final Object injectedTestObject = new Object() { | 551 final Object injectedTestObject = new Object() { |
| 480 public InnerObject getInnerObject() { | 552 public InnerObject getInnerObject() { |
| 481 return innerObject; | 553 return innerObject; |
| 482 } | 554 } |
| 483 }; | 555 }; |
| 484 injectObjectAndReload(injectedTestObject, "injectedTestObject"); | 556 mActivityTestRule.injectObjectAndReload(injectedTestObject, "injectedTes
tObject"); |
| 485 executeJavaScript("inner1 = injectedTestObject.getInnerObject()"); | 557 mActivityTestRule.executeJavaScript("inner1 = injectedTestObject.getInne
rObject()"); |
| 486 executeJavaScript("inner2 = injectedTestObject.getInnerObject()"); | 558 mActivityTestRule.executeJavaScript("inner2 = injectedTestObject.getInne
rObject()"); |
| 487 assertEquals("object", executeJavaScriptAndGetStringResult("typeof inner
1")); | 559 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f inner1")); |
| 488 assertEquals("object", executeJavaScriptAndGetStringResult("typeof inner
2")); | 560 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f inner2")); |
| 489 assertEquals("true", executeJavaScriptAndGetStringResult("inner1 === inn
er2")); | 561 Assert.assertEquals("true", executeJavaScriptAndGetStringResult("inner1
=== inner2")); |
| 490 } | 562 } |
| 491 | 563 |
| 564 @Test |
| 492 @SmallTest | 565 @SmallTest |
| 493 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 566 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 494 public void testMethodInvokedOnBackgroundThread() throws Throwable { | 567 public void testMethodInvokedOnBackgroundThread() throws Throwable { |
| 495 injectObjectAndReload(new Object() { | 568 setUpHelper(); |
| 569 mActivityTestRule.injectObjectAndReload(new Object() { |
| 496 public void captureThreadId() { | 570 public void captureThreadId() { |
| 497 mTestController.setLongValue(Thread.currentThread().getId()); | 571 mTestController.setLongValue(Thread.currentThread().getId()); |
| 498 } | 572 } |
| 499 }, "testObject"); | 573 }, "testObject"); |
| 500 executeJavaScript("testObject.captureThreadId()"); | 574 mActivityTestRule.executeJavaScript("testObject.captureThreadId()"); |
| 501 final long threadId = mTestController.waitForLongValue(); | 575 final long threadId = mTestController.waitForLongValue(); |
| 502 assertFalse(threadId == Thread.currentThread().getId()); | 576 Assert.assertFalse(threadId == Thread.currentThread().getId()); |
| 503 runTestOnUiThread(new Runnable() { | 577 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable(
) { |
| 504 @Override | 578 @Override |
| 505 public void run() { | 579 public void run() { |
| 506 assertFalse(threadId == Thread.currentThread().getId()); | 580 Assert.assertFalse(threadId == Thread.currentThread().getId()); |
| 507 } | 581 } |
| 508 }); | 582 }); |
| 509 } | 583 } |
| 510 | 584 |
| 585 @Test |
| 511 @SmallTest | 586 @SmallTest |
| 512 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 587 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 513 public void testBlockingUiThreadDoesNotBlockCallsFromJs() throws Throwable { | 588 public void testBlockingUiThreadDoesNotBlockCallsFromJs() throws Throwable { |
| 589 setUpHelper(); |
| 514 class TestObject { | 590 class TestObject { |
| 515 private CountDownLatch mLatch; | 591 private CountDownLatch mLatch; |
| 516 public TestObject() { | 592 public TestObject() { |
| 517 mLatch = new CountDownLatch(1); | 593 mLatch = new CountDownLatch(1); |
| 518 } | 594 } |
| 519 public boolean waitOnTheLatch() throws Exception { | 595 public boolean waitOnTheLatch() throws Exception { |
| 520 return mLatch.await(scaleTimeout(10000), | 596 return mLatch.await(scaleTimeout(10000), |
| 521 java.util.concurrent.TimeUnit.MILLISECONDS); | 597 java.util.concurrent.TimeUnit.MILLISECONDS); |
| 522 } | 598 } |
| 523 public void unlockTheLatch() throws Exception { | 599 public void unlockTheLatch() throws Exception { |
| 524 mTestController.setStringValue("unlocked"); | 600 mTestController.setStringValue("unlocked"); |
| 525 mLatch.countDown(); | 601 mLatch.countDown(); |
| 526 } | 602 } |
| 527 } | 603 } |
| 528 final TestObject testObject = new TestObject(); | 604 final TestObject testObject = new TestObject(); |
| 529 injectObjectAndReload(testObject, "testObject"); | 605 mActivityTestRule.injectObjectAndReload(testObject, "testObject"); |
| 530 runTestOnUiThread(new Runnable() { | 606 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable(
) { |
| 531 @Override | 607 @Override |
| 532 public void run() { | 608 public void run() { |
| 533 // loadUrl is asynchronous, the JS code will start running on th
e renderer | 609 // loadUrl is asynchronous, the JS code will start running on th
e renderer |
| 534 // thread. As soon as we exit loadUrl, the browser UI thread wil
l be stuck waiting | 610 // thread. As soon as we exit loadUrl, the browser UI thread wil
l be stuck waiting |
| 535 // on the latch. If blocking the browser thread blocks Java Brid
ge, then the call | 611 // on the latch. If blocking the browser thread blocks Java Brid
ge, then the call |
| 536 // to "unlockTheLatch()" will be executed after the waiting time
out, thus the | 612 // to "unlockTheLatch()" will be executed after the waiting time
out, thus the |
| 537 // string value will not yet be updated by the injected object. | 613 // string value will not yet be updated by the injected object. |
| 538 mTestController.setStringValue("locked"); | 614 mTestController.setStringValue("locked"); |
| 539 getWebContents().getNavigationController().loadUrl(new LoadUrlPa
rams( | 615 mActivityTestRule.getWebContents().getNavigationController().loa
dUrl( |
| 540 "javascript:(function() { testObject.unlockTheLatch() })
()")); | 616 new LoadUrlParams( |
| 617 "javascript:(function() { testObject.unlockTheLa
tch() })()")); |
| 541 try { | 618 try { |
| 542 assertTrue(testObject.waitOnTheLatch()); | 619 Assert.assertTrue(testObject.waitOnTheLatch()); |
| 543 } catch (Exception e) { | 620 } catch (Exception e) { |
| 544 android.util.Log.e("JavaBridgeBasicsTest", "Wait exception",
e); | 621 android.util.Log.e("JavaBridgeBasicsTest", "Wait exception",
e); |
| 545 Assert.fail("Wait exception"); | 622 Assert.fail("Wait exception"); |
| 546 } | 623 } |
| 547 assertEquals("unlocked", mTestController.getStringValue()); | 624 Assert.assertEquals("unlocked", mTestController.getStringValue()
); |
| 548 } | 625 } |
| 549 }); | 626 }); |
| 550 } | 627 } |
| 551 | 628 |
| 629 @Test |
| 552 @SmallTest | 630 @SmallTest |
| 553 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 631 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 554 public void testPublicInheritedMethod() throws Throwable { | 632 public void testPublicInheritedMethod() throws Throwable { |
| 633 setUpHelper(); |
| 555 class Base { | 634 class Base { |
| 556 public void method(int x) { | 635 public void method(int x) { |
| 557 mTestController.setIntValue(x); | 636 mTestController.setIntValue(x); |
| 558 } | 637 } |
| 559 } | 638 } |
| 560 class Derived extends Base { | 639 class Derived extends Base { |
| 561 } | 640 } |
| 562 injectObjectAndReload(new Derived(), "testObject"); | 641 mActivityTestRule.injectObjectAndReload(new Derived(), "testObject"); |
| 563 assertEquals("function", executeJavaScriptAndGetStringResult("typeof tes
tObject.method")); | 642 Assert.assertEquals( |
| 564 executeJavaScript("testObject.method(42)"); | 643 "function", executeJavaScriptAndGetStringResult("typeof testObje
ct.method")); |
| 565 assertEquals(42, mTestController.waitForIntValue()); | 644 mActivityTestRule.executeJavaScript("testObject.method(42)"); |
| 645 Assert.assertEquals(42, mTestController.waitForIntValue()); |
| 566 } | 646 } |
| 567 | 647 |
| 648 @Test |
| 568 @SmallTest | 649 @SmallTest |
| 569 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 650 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 570 public void testPrivateInheritedMethod() throws Throwable { | 651 public void testPrivateInheritedMethod() throws Throwable { |
| 652 setUpHelper(); |
| 571 class Base { | 653 class Base { |
| 572 private void method() {} | 654 private void method() {} |
| 573 } | 655 } |
| 574 class Derived extends Base { | 656 class Derived extends Base { |
| 575 } | 657 } |
| 576 injectObjectAndReload(new Derived(), "testObject"); | 658 mActivityTestRule.injectObjectAndReload(new Derived(), "testObject"); |
| 577 assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof te
stObject.method")); | 659 Assert.assertEquals( |
| 660 "undefined", executeJavaScriptAndGetStringResult("typeof testObj
ect.method")); |
| 578 } | 661 } |
| 579 | 662 |
| 663 @Test |
| 580 @SmallTest | 664 @SmallTest |
| 581 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 665 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 582 public void testOverriddenMethod() throws Throwable { | 666 public void testOverriddenMethod() throws Throwable { |
| 667 setUpHelper(); |
| 583 class Base { | 668 class Base { |
| 584 public void method() { | 669 public void method() { |
| 585 mTestController.setStringValue("base"); | 670 mTestController.setStringValue("base"); |
| 586 } | 671 } |
| 587 } | 672 } |
| 588 class Derived extends Base { | 673 class Derived extends Base { |
| 589 @Override | 674 @Override |
| 590 public void method() { | 675 public void method() { |
| 591 mTestController.setStringValue("derived"); | 676 mTestController.setStringValue("derived"); |
| 592 } | 677 } |
| 593 } | 678 } |
| 594 injectObjectAndReload(new Derived(), "testObject"); | 679 mActivityTestRule.injectObjectAndReload(new Derived(), "testObject"); |
| 595 executeJavaScript("testObject.method()"); | 680 mActivityTestRule.executeJavaScript("testObject.method()"); |
| 596 assertEquals("derived", mTestController.waitForStringValue()); | 681 Assert.assertEquals("derived", mTestController.waitForStringValue()); |
| 597 } | 682 } |
| 598 | 683 |
| 684 @Test |
| 599 @SmallTest | 685 @SmallTest |
| 600 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 686 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 601 public void testEnumerateMembers() throws Throwable { | 687 public void testEnumerateMembers() throws Throwable { |
| 602 injectObjectAndReload(new Object() { | 688 setUpHelper(); |
| 689 mActivityTestRule.injectObjectAndReload(new Object() { |
| 603 public void method() {} | 690 public void method() {} |
| 604 private void privateMethod() {} | 691 private void privateMethod() {} |
| 605 @SuppressFBWarnings("UUF_UNUSED") | 692 @SuppressFBWarnings("UUF_UNUSED") |
| 606 public int field; | 693 public int field; |
| 607 @SuppressFBWarnings("UUF_UNUSED") | 694 @SuppressFBWarnings("UUF_UNUSED") |
| 608 private int mPrivateField; | 695 private int mPrivateField; |
| 609 }, "testObject"); | 696 }, "testObject"); |
| 610 executeJavaScript( | 697 mActivityTestRule.executeJavaScript("var result = \"\"; " |
| 611 "var result = \"\"; " | |
| 612 + "for (x in testObject) { result += \" \" + x } " | 698 + "for (x in testObject) { result += \" \" + x } " |
| 613 + "testController.setStringValue(result);"); | 699 + "testController.setStringValue(result);"); |
| 614 assertEquals(" equals getClass hashCode method notify notifyAll toString
wait", | 700 Assert.assertEquals(" equals getClass hashCode method notify notifyAll t
oString wait", |
| 615 mTestController.waitForStringValue()); | 701 mTestController.waitForStringValue()); |
| 616 } | 702 } |
| 617 | 703 |
| 704 @Test |
| 618 @SmallTest | 705 @SmallTest |
| 619 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 706 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 620 public void testReflectPublicMethod() throws Throwable { | 707 public void testReflectPublicMethod() throws Throwable { |
| 621 injectObjectAndReload(new Object() { | 708 setUpHelper(); |
| 709 mActivityTestRule.injectObjectAndReload(new Object() { |
| 622 public Class<?> myGetClass() { | 710 public Class<?> myGetClass() { |
| 623 return getClass(); | 711 return getClass(); |
| 624 } | 712 } |
| 625 | 713 |
| 626 public String method() { | 714 public String method() { |
| 627 return "foo"; | 715 return "foo"; |
| 628 } | 716 } |
| 629 }, "testObject"); | 717 }, "testObject"); |
| 630 assertEquals("foo", executeJavaScriptAndGetStringResult( | 718 Assert.assertEquals("foo", |
| 631 "testObject.myGetClass().getMethod('method', null).invoke(testOb
ject, null)" | 719 executeJavaScriptAndGetStringResult( |
| 632 + ".toString()")); | 720 "testObject.myGetClass().getMethod('method', null).invok
e(testObject, null)" |
| 721 + ".toString()")); |
| 633 } | 722 } |
| 634 | 723 |
| 724 @Test |
| 635 @SmallTest | 725 @SmallTest |
| 636 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 726 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 637 public void testReflectPublicField() throws Throwable { | 727 public void testReflectPublicField() throws Throwable { |
| 638 injectObjectAndReload(new Object() { | 728 setUpHelper(); |
| 729 mActivityTestRule.injectObjectAndReload(new Object() { |
| 639 public Class<?> myGetClass() { | 730 public Class<?> myGetClass() { |
| 640 return getClass(); | 731 return getClass(); |
| 641 } | 732 } |
| 642 | 733 |
| 643 public String field = "foo"; | 734 public String field = "foo"; |
| 644 }, "testObject"); | 735 }, "testObject"); |
| 645 assertEquals("foo", executeJavaScriptAndGetStringResult( | 736 Assert.assertEquals("foo", |
| 646 "testObject.myGetClass().getField('field').get(testObject).toStr
ing()")); | 737 executeJavaScriptAndGetStringResult( |
| 738 "testObject.myGetClass().getField('field').get(testObjec
t).toString()")); |
| 647 } | 739 } |
| 648 | 740 |
| 741 @Test |
| 649 @SmallTest | 742 @SmallTest |
| 650 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 743 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 651 public void testReflectPrivateMethodRaisesException() throws Throwable { | 744 public void testReflectPrivateMethodRaisesException() throws Throwable { |
| 652 injectObjectAndReload(new Object() { | 745 setUpHelper(); |
| 746 mActivityTestRule.injectObjectAndReload(new Object() { |
| 653 public Class<?> myGetClass() { | 747 public Class<?> myGetClass() { |
| 654 return getClass(); | 748 return getClass(); |
| 655 } | 749 } |
| 656 | 750 |
| 657 private void method() {}; | 751 private void method() {}; |
| 658 }, "testObject"); | 752 }, "testObject"); |
| 659 assertRaisesException("testObject.myGetClass().getMethod('method', null)
"); | 753 assertRaisesException("testObject.myGetClass().getMethod('method', null)
"); |
| 660 // getDeclaredMethod() is able to access a private method, but invoke() | 754 // getDeclaredMethod() is able to access a private method, but invoke() |
| 661 // throws a Java exception. | 755 // throws a Java exception. |
| 662 assertRaisesException( | 756 assertRaisesException( |
| 663 "testObject.myGetClass().getDeclaredMethod('method', null)." | 757 "testObject.myGetClass().getDeclaredMethod('method', null)." |
| 664 + "invoke(testObject, null)"); | 758 + "invoke(testObject, null)"); |
| 665 } | 759 } |
| 666 | 760 |
| 761 @Test |
| 667 @SmallTest | 762 @SmallTest |
| 668 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 763 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 669 public void testReflectPrivateFieldRaisesException() throws Throwable { | 764 public void testReflectPrivateFieldRaisesException() throws Throwable { |
| 670 injectObjectAndReload(new Object() { | 765 setUpHelper(); |
| 766 mActivityTestRule.injectObjectAndReload(new Object() { |
| 671 public Class<?> myGetClass() { | 767 public Class<?> myGetClass() { |
| 672 return getClass(); | 768 return getClass(); |
| 673 } | 769 } |
| 674 | 770 |
| 675 @SuppressFBWarnings("UUF_UNUSED") | 771 @SuppressFBWarnings("UUF_UNUSED") |
| 676 private int mField; | 772 private int mField; |
| 677 }, "testObject"); | 773 }, "testObject"); |
| 678 String fieldName = "mField"; | 774 String fieldName = "mField"; |
| 679 assertRaisesException("testObject.myGetClass().getField('" + fieldName +
"')"); | 775 assertRaisesException("testObject.myGetClass().getField('" + fieldName +
"')"); |
| 680 // getDeclaredField() is able to access a private field, but getInt() | 776 // getDeclaredField() is able to access a private field, but getInt() |
| 681 // throws a Java exception. | 777 // throws a Java exception. |
| 682 assertNoRaisedException("testObject.myGetClass().getDeclaredField('" + f
ieldName + "')"); | 778 assertNoRaisedException("testObject.myGetClass().getDeclaredField('" + f
ieldName + "')"); |
| 683 assertRaisesException( | 779 assertRaisesException( |
| 684 "testObject.myGetClass().getDeclaredField('" + fieldName + "').g
etInt(testObject)"); | 780 "testObject.myGetClass().getDeclaredField('" + fieldName + "').g
etInt(testObject)"); |
| 685 } | 781 } |
| 686 | 782 |
| 783 @Test |
| 687 @SmallTest | 784 @SmallTest |
| 688 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 785 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 689 public void testAllowNonAnnotatedMethods() throws Throwable { | 786 public void testAllowNonAnnotatedMethods() throws Throwable { |
| 690 injectObjectAndReload(new Object() { | 787 setUpHelper(); |
| 788 mActivityTestRule.injectObjectAndReload(new Object() { |
| 691 public String allowed() { | 789 public String allowed() { |
| 692 return "foo"; | 790 return "foo"; |
| 693 } | 791 } |
| 694 }, "testObject", null); | 792 }, "testObject", null); |
| 695 | 793 |
| 696 // Test calling a method of an explicitly inherited class (Base#allowed(
)). | 794 // Test calling a method of an explicitly inherited class (Base#allowed(
)). |
| 697 assertEquals("foo", executeJavaScriptAndGetStringResult("testObject.allo
wed()")); | 795 Assert.assertEquals("foo", executeJavaScriptAndGetStringResult("testObje
ct.allowed()")); |
| 698 | 796 |
| 699 // Test calling a method of an implicitly inherited class (Object#toStri
ng()). | 797 // Test calling a method of an implicitly inherited class (Object#toStri
ng()). |
| 700 assertEquals("string", executeJavaScriptAndGetStringResult("typeof testO
bject.toString()")); | 798 Assert.assertEquals( |
| 799 "string", executeJavaScriptAndGetStringResult("typeof testObject
.toString()")); |
| 701 } | 800 } |
| 702 | 801 |
| 802 @Test |
| 703 @SmallTest | 803 @SmallTest |
| 704 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 804 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 705 public void testAllowOnlyAnnotatedMethods() throws Throwable { | 805 public void testAllowOnlyAnnotatedMethods() throws Throwable { |
| 706 injectObjectAndReload(new Object() { | 806 setUpHelper(); |
| 807 mActivityTestRule.injectObjectAndReload(new Object() { |
| 707 @JavascriptInterface | 808 @JavascriptInterface |
| 708 public String allowed() { | 809 public String allowed() { |
| 709 return "foo"; | 810 return "foo"; |
| 710 } | 811 } |
| 711 | 812 |
| 712 public String disallowed() { | 813 public String disallowed() { |
| 713 return "bar"; | 814 return "bar"; |
| 714 } | 815 } |
| 715 }, "testObject", JavascriptInterface.class); | 816 }, "testObject", JavascriptInterface.class); |
| 716 | 817 |
| 717 // getClass() is an Object method and does not have the @JavascriptInter
face annotation and | 818 // getClass() is an Object method and does not have the @JavascriptInter
face annotation and |
| 718 // should not be able to be called. | 819 // should not be able to be called. |
| 719 assertRaisesException("testObject.getClass()"); | 820 assertRaisesException("testObject.getClass()"); |
| 720 assertEquals("undefined", executeJavaScriptAndGetStringResult( | 821 Assert.assertEquals( |
| 721 "typeof testObject.getClass")); | 822 "undefined", executeJavaScriptAndGetStringResult("typeof testObj
ect.getClass")); |
| 722 | 823 |
| 723 // allowed() is marked with the @JavascriptInterface annotation and shou
ld be allowed to be | 824 // allowed() is marked with the @JavascriptInterface annotation and shou
ld be allowed to be |
| 724 // called. | 825 // called. |
| 725 assertEquals("foo", executeJavaScriptAndGetStringResult("testObject.allo
wed()")); | 826 Assert.assertEquals("foo", executeJavaScriptAndGetStringResult("testObje
ct.allowed()")); |
| 726 | 827 |
| 727 // disallowed() is not marked with the @JavascriptInterface annotation a
nd should not be | 828 // disallowed() is not marked with the @JavascriptInterface annotation a
nd should not be |
| 728 // able to be called. | 829 // able to be called. |
| 729 assertRaisesException("testObject.disallowed()"); | 830 assertRaisesException("testObject.disallowed()"); |
| 730 assertEquals("undefined", executeJavaScriptAndGetStringResult( | 831 Assert.assertEquals( |
| 731 "typeof testObject.disallowed")); | 832 "undefined", executeJavaScriptAndGetStringResult("typeof testObj
ect.disallowed")); |
| 732 } | 833 } |
| 733 | 834 |
| 835 @Test |
| 734 @SmallTest | 836 @SmallTest |
| 735 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 837 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 736 public void testAnnotationRequirementRetainsPropertyAcrossObjects() throws T
hrowable { | 838 public void testAnnotationRequirementRetainsPropertyAcrossObjects() throws T
hrowable { |
| 839 setUpHelper(); |
| 737 class Test { | 840 class Test { |
| 738 @JavascriptInterface | 841 @JavascriptInterface |
| 739 public String safe() { | 842 public String safe() { |
| 740 return "foo"; | 843 return "foo"; |
| 741 } | 844 } |
| 742 | 845 |
| 743 public String unsafe() { | 846 public String unsafe() { |
| 744 return "bar"; | 847 return "bar"; |
| 745 } | 848 } |
| 746 } | 849 } |
| 747 | 850 |
| 748 class TestReturner { | 851 class TestReturner { |
| 749 @JavascriptInterface | 852 @JavascriptInterface |
| 750 public Test getTest() { | 853 public Test getTest() { |
| 751 return new Test(); | 854 return new Test(); |
| 752 } | 855 } |
| 753 } | 856 } |
| 754 | 857 |
| 755 // First test with safe mode off. | 858 // First test with safe mode off. |
| 756 injectObjectAndReload(new TestReturner(), "unsafeTestObject", null); | 859 mActivityTestRule.injectObjectAndReload(new TestReturner(), "unsafeTestO
bject", null); |
| 757 | 860 |
| 758 // safe() should be able to be called regardless of whether or not we ar
e in safe mode. | 861 // safe() should be able to be called regardless of whether or not we ar
e in safe mode. |
| 759 assertEquals("foo", executeJavaScriptAndGetStringResult( | 862 Assert.assertEquals( |
| 760 "unsafeTestObject.getTest().safe()")); | 863 "foo", executeJavaScriptAndGetStringResult("unsafeTestObject.get
Test().safe()")); |
| 761 // unsafe() should be able to be called because we are not in safe mode. | 864 // unsafe() should be able to be called because we are not in safe mode. |
| 762 assertEquals("bar", executeJavaScriptAndGetStringResult( | 865 Assert.assertEquals( |
| 763 "unsafeTestObject.getTest().unsafe()")); | 866 "bar", executeJavaScriptAndGetStringResult("unsafeTestObject.get
Test().unsafe()")); |
| 764 | 867 |
| 765 // Now test with safe mode on. | 868 // Now test with safe mode on. |
| 766 injectObjectAndReload(new TestReturner(), "safeTestObject", JavascriptIn
terface.class); | 869 mActivityTestRule.injectObjectAndReload( |
| 870 new TestReturner(), "safeTestObject", JavascriptInterface.class)
; |
| 767 | 871 |
| 768 // safe() should be able to be called regardless of whether or not we ar
e in safe mode. | 872 // safe() should be able to be called regardless of whether or not we ar
e in safe mode. |
| 769 assertEquals("foo", executeJavaScriptAndGetStringResult( | 873 Assert.assertEquals( |
| 770 "safeTestObject.getTest().safe()")); | 874 "foo", executeJavaScriptAndGetStringResult("safeTestObject.getTe
st().safe()")); |
| 771 // unsafe() should not be able to be called because we are in safe mode. | 875 // unsafe() should not be able to be called because we are in safe mode. |
| 772 assertRaisesException("safeTestObject.getTest().unsafe()"); | 876 assertRaisesException("safeTestObject.getTest().unsafe()"); |
| 773 assertEquals("undefined", executeJavaScriptAndGetStringResult( | 877 Assert.assertEquals("undefined", |
| 774 "typeof safeTestObject.getTest().unsafe")); | 878 executeJavaScriptAndGetStringResult("typeof safeTestObject.getTe
st().unsafe")); |
| 775 // getClass() is an Object method and does not have the @JavascriptInter
face annotation and | 879 // getClass() is an Object method and does not have the @JavascriptInter
face annotation and |
| 776 // should not be able to be called. | 880 // should not be able to be called. |
| 777 assertRaisesException("safeTestObject.getTest().getClass()"); | 881 assertRaisesException("safeTestObject.getTest().getClass()"); |
| 778 assertEquals("undefined", executeJavaScriptAndGetStringResult( | 882 Assert.assertEquals("undefined", |
| 779 "typeof safeTestObject.getTest().getClass")); | 883 executeJavaScriptAndGetStringResult("typeof safeTestObject.getTe
st().getClass")); |
| 780 } | 884 } |
| 781 | 885 |
| 886 @Test |
| 782 @SmallTest | 887 @SmallTest |
| 783 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 888 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 784 public void testAnnotationDoesNotGetInherited() throws Throwable { | 889 public void testAnnotationDoesNotGetInherited() throws Throwable { |
| 890 setUpHelper(); |
| 785 class Base { | 891 class Base { |
| 786 @JavascriptInterface | 892 @JavascriptInterface |
| 787 public void base() { } | 893 public void base() { } |
| 788 } | 894 } |
| 789 | 895 |
| 790 class Child extends Base { | 896 class Child extends Base { |
| 791 @Override | 897 @Override |
| 792 public void base() { } | 898 public void base() { } |
| 793 } | 899 } |
| 794 | 900 |
| 795 injectObjectAndReload(new Child(), "testObject", JavascriptInterface.cla
ss); | 901 mActivityTestRule.injectObjectAndReload( |
| 902 new Child(), "testObject", JavascriptInterface.class); |
| 796 | 903 |
| 797 // base() is inherited. The inherited method does not have the @Javascr
iptInterface | 904 // base() is inherited. The inherited method does not have the @Javascr
iptInterface |
| 798 // annotation and should not be able to be called. | 905 // annotation and should not be able to be called. |
| 799 assertRaisesException("testObject.base()"); | 906 assertRaisesException("testObject.base()"); |
| 800 assertEquals("undefined", executeJavaScriptAndGetStringResult( | 907 Assert.assertEquals( |
| 801 "typeof testObject.base")); | 908 "undefined", executeJavaScriptAndGetStringResult("typeof testObj
ect.base")); |
| 802 } | 909 } |
| 803 | 910 |
| 804 @SuppressWarnings("javadoc") | 911 @SuppressWarnings("javadoc") |
| 805 @Retention(RetentionPolicy.RUNTIME) | 912 @Retention(RetentionPolicy.RUNTIME) |
| 806 @Target({ElementType.METHOD}) | 913 @Target({ElementType.METHOD}) |
| 807 @interface TestAnnotation { | 914 @interface TestAnnotation { |
| 808 } | 915 } |
| 809 | 916 |
| 917 @Test |
| 810 @SmallTest | 918 @SmallTest |
| 811 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 919 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 812 public void testCustomAnnotationRestriction() throws Throwable { | 920 public void testCustomAnnotationRestriction() throws Throwable { |
| 921 setUpHelper(); |
| 813 class Test { | 922 class Test { |
| 814 @TestAnnotation | 923 @TestAnnotation |
| 815 public String checkTestAnnotationFoo() { | 924 public String checkTestAnnotationFoo() { |
| 816 return "bar"; | 925 return "bar"; |
| 817 } | 926 } |
| 818 | 927 |
| 819 @JavascriptInterface | 928 @JavascriptInterface |
| 820 public String checkJavascriptInterfaceFoo() { | 929 public String checkJavascriptInterfaceFoo() { |
| 821 return "bar"; | 930 return "bar"; |
| 822 } | 931 } |
| 823 } | 932 } |
| 824 | 933 |
| 825 // Inject javascriptInterfaceObj and require the JavascriptInterface ann
otation. | 934 // Inject javascriptInterfaceObj and require the JavascriptInterface ann
otation. |
| 826 injectObjectAndReload(new Test(), "javascriptInterfaceObj", JavascriptIn
terface.class); | 935 mActivityTestRule.injectObjectAndReload( |
| 936 new Test(), "javascriptInterfaceObj", JavascriptInterface.class)
; |
| 827 | 937 |
| 828 // Test#testAnnotationFoo() should fail, as it isn't annotated with Java
scriptInterface. | 938 // Test#testAnnotationFoo() should fail, as it isn't annotated with Java
scriptInterface. |
| 829 assertRaisesException("javascriptInterfaceObj.checkTestAnnotationFoo()")
; | 939 assertRaisesException("javascriptInterfaceObj.checkTestAnnotationFoo()")
; |
| 830 assertEquals("undefined", executeJavaScriptAndGetStringResult( | 940 Assert.assertEquals("undefined", |
| 831 "typeof javascriptInterfaceObj.checkTestAnnotationFoo")); | 941 executeJavaScriptAndGetStringResult( |
| 942 "typeof javascriptInterfaceObj.checkTestAnnotationFoo"))
; |
| 832 | 943 |
| 833 // Test#javascriptInterfaceFoo() should pass, as it is annotated with Ja
vascriptInterface. | 944 // Test#javascriptInterfaceFoo() should pass, as it is annotated with Ja
vascriptInterface. |
| 834 assertEquals("bar", executeJavaScriptAndGetStringResult( | 945 Assert.assertEquals("bar", |
| 835 "javascriptInterfaceObj.checkJavascriptInterfaceFoo()")); | 946 executeJavaScriptAndGetStringResult( |
| 947 "javascriptInterfaceObj.checkJavascriptInterfaceFoo()"))
; |
| 836 | 948 |
| 837 // Inject testAnnotationObj and require the TestAnnotation annotation. | 949 // Inject testAnnotationObj and require the TestAnnotation annotation. |
| 838 injectObjectAndReload(new Test(), "testAnnotationObj", TestAnnotation.cl
ass); | 950 mActivityTestRule.injectObjectAndReload( |
| 951 new Test(), "testAnnotationObj", TestAnnotation.class); |
| 839 | 952 |
| 840 // Test#testAnnotationFoo() should pass, as it is annotated with TestAnn
otation. | 953 // Test#testAnnotationFoo() should pass, as it is annotated with TestAnn
otation. |
| 841 assertEquals("bar", executeJavaScriptAndGetStringResult( | 954 Assert.assertEquals("bar", |
| 842 "testAnnotationObj.checkTestAnnotationFoo()")); | 955 executeJavaScriptAndGetStringResult("testAnnotationObj.checkTest
AnnotationFoo()")); |
| 843 | 956 |
| 844 // Test#javascriptInterfaceFoo() should fail, as it isn't annotated with
TestAnnotation. | 957 // Test#javascriptInterfaceFoo() should fail, as it isn't annotated with
TestAnnotation. |
| 845 assertRaisesException("testAnnotationObj.checkJavascriptInterfaceFoo()")
; | 958 assertRaisesException("testAnnotationObj.checkJavascriptInterfaceFoo()")
; |
| 846 assertEquals("undefined", executeJavaScriptAndGetStringResult( | 959 Assert.assertEquals("undefined", |
| 847 "typeof testAnnotationObj.checkJavascriptInterfaceFoo")); | 960 executeJavaScriptAndGetStringResult( |
| 961 "typeof testAnnotationObj.checkJavascriptInterfaceFoo"))
; |
| 848 } | 962 } |
| 849 | 963 |
| 964 @Test |
| 850 @SmallTest | 965 @SmallTest |
| 851 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 966 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 852 public void testAddJavascriptInterfaceIsSafeByDefault() throws Throwable { | 967 public void testAddJavascriptInterfaceIsSafeByDefault() throws Throwable { |
| 968 setUpHelper(); |
| 853 class Test { | 969 class Test { |
| 854 public String blocked() { | 970 public String blocked() { |
| 855 return "bar"; | 971 return "bar"; |
| 856 } | 972 } |
| 857 | 973 |
| 858 @JavascriptInterface | 974 @JavascriptInterface |
| 859 public String allowed() { | 975 public String allowed() { |
| 860 return "bar"; | 976 return "bar"; |
| 861 } | 977 } |
| 862 } | 978 } |
| 863 | 979 |
| 864 // Manually inject the Test object, making sure to use the | 980 // Manually inject the Test object, making sure to use the |
| 865 // ContentViewCore#addJavascriptInterface, not the possibly unsafe versi
on. | 981 // ContentViewCore#addJavascriptInterface, not the possibly unsafe versi
on. |
| 866 TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = | 982 TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = |
| 867 getTestCallBackHelperContainer().getOnPageFinishedHelper(); | 983 mActivityTestRule.getTestCallBackHelperContainer().getOnPageFini
shedHelper(); |
| 868 int currentCallCount = onPageFinishedHelper.getCallCount(); | 984 int currentCallCount = onPageFinishedHelper.getCallCount(); |
| 869 runTestOnUiThread(new Runnable() { | 985 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable(
) { |
| 870 @Override | 986 @Override |
| 871 public void run() { | 987 public void run() { |
| 872 getContentViewCore().addJavascriptInterface(new Test(), | 988 mActivityTestRule.getContentViewCore().addJavascriptInterface( |
| 873 "testObject"); | 989 new Test(), "testObject"); |
| 874 getContentViewCore().getWebContents().getNavigationController().
reload(true); | 990 mActivityTestRule.getContentViewCore() |
| 991 .getWebContents() |
| 992 .getNavigationController() |
| 993 .reload(true); |
| 875 } | 994 } |
| 876 }); | 995 }); |
| 877 onPageFinishedHelper.waitForCallback(currentCallCount); | 996 onPageFinishedHelper.waitForCallback(currentCallCount); |
| 878 | 997 |
| 879 // Test#allowed() should pass, as it is annotated with JavascriptInterfa
ce. | 998 // Test#allowed() should pass, as it is annotated with JavascriptInterfa
ce. |
| 880 assertEquals("bar", executeJavaScriptAndGetStringResult( | 999 Assert.assertEquals("bar", executeJavaScriptAndGetStringResult("testObje
ct.allowed()")); |
| 881 "testObject.allowed()")); | |
| 882 | 1000 |
| 883 // Test#blocked() should fail, as it isn't annotated with JavascriptInte
rface. | 1001 // Test#blocked() should fail, as it isn't annotated with JavascriptInte
rface. |
| 884 assertRaisesException("testObject.blocked()"); | 1002 assertRaisesException("testObject.blocked()"); |
| 885 assertEquals("undefined", executeJavaScriptAndGetStringResult( | 1003 Assert.assertEquals( |
| 886 "typeof testObject.blocked")); | 1004 "undefined", executeJavaScriptAndGetStringResult("typeof testObj
ect.blocked")); |
| 887 } | 1005 } |
| 888 | 1006 |
| 1007 @Test |
| 889 @SmallTest | 1008 @SmallTest |
| 890 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 1009 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 891 public void testObjectsInspection() throws Throwable { | 1010 public void testObjectsInspection() throws Throwable { |
| 1011 setUpHelper(); |
| 892 class Test { | 1012 class Test { |
| 893 @JavascriptInterface | 1013 @JavascriptInterface |
| 894 public String m1() { | 1014 public String m1() { |
| 895 return "foo"; | 1015 return "foo"; |
| 896 } | 1016 } |
| 897 | 1017 |
| 898 @JavascriptInterface | 1018 @JavascriptInterface |
| 899 public String m2() { | 1019 public String m2() { |
| 900 return "bar"; | 1020 return "bar"; |
| 901 } | 1021 } |
| 902 | 1022 |
| 903 @JavascriptInterface | 1023 @JavascriptInterface |
| 904 public String m2(int x) { | 1024 public String m2(int x) { |
| 905 return "bar " + x; | 1025 return "bar " + x; |
| 906 } | 1026 } |
| 907 } | 1027 } |
| 908 | 1028 |
| 909 final String jsObjectKeysTestTemplate = "Object.keys(%s).toString()"; | 1029 final String jsObjectKeysTestTemplate = "Object.keys(%s).toString()"; |
| 910 final String jsForInTestTemplate = | 1030 final String jsForInTestTemplate = |
| 911 "(function(){" | 1031 "(function(){" |
| 912 + " var s=[]; for(var m in %s) s.push(m); return s.join(\",\")" | 1032 + " var s=[]; for(var m in %s) s.push(m); return s.join(\",\")" |
| 913 + "})()"; | 1033 + "})()"; |
| 914 final String inspectableObjectName = "testObj1"; | 1034 final String inspectableObjectName = "testObj1"; |
| 915 final String nonInspectableObjectName = "testObj2"; | 1035 final String nonInspectableObjectName = "testObj2"; |
| 916 | 1036 |
| 917 // Inspection is enabled by default. | 1037 // Inspection is enabled by default. |
| 918 injectObjectAndReload(new Test(), inspectableObjectName, JavascriptInter
face.class); | 1038 mActivityTestRule.injectObjectAndReload( |
| 1039 new Test(), inspectableObjectName, JavascriptInterface.class); |
| 919 | 1040 |
| 920 assertEquals("m1,m2", executeJavaScriptAndGetStringResult( | 1041 Assert.assertEquals("m1,m2", |
| 1042 executeJavaScriptAndGetStringResult( |
| 921 String.format(jsObjectKeysTestTemplate, inspectableObjec
tName))); | 1043 String.format(jsObjectKeysTestTemplate, inspectableObjec
tName))); |
| 922 assertEquals("m1,m2", executeJavaScriptAndGetStringResult( | 1044 Assert.assertEquals("m1,m2", |
| 1045 executeJavaScriptAndGetStringResult( |
| 923 String.format(jsForInTestTemplate, inspectableObjectName
))); | 1046 String.format(jsForInTestTemplate, inspectableObjectName
))); |
| 924 | 1047 |
| 925 runTestOnUiThread(new Runnable() { | 1048 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable(
) { |
| 926 @Override | 1049 @Override |
| 927 public void run() { | 1050 public void run() { |
| 928 getContentViewCore().setAllowJavascriptInterfacesInspection(fals
e); | 1051 mActivityTestRule.getContentViewCore().setAllowJavascriptInterfa
cesInspection( |
| 1052 false); |
| 929 } | 1053 } |
| 930 }); | 1054 }); |
| 931 | 1055 |
| 932 injectObjectAndReload(new Test(), nonInspectableObjectName, JavascriptIn
terface.class); | 1056 mActivityTestRule.injectObjectAndReload( |
| 1057 new Test(), nonInspectableObjectName, JavascriptInterface.class)
; |
| 933 | 1058 |
| 934 assertEquals("", executeJavaScriptAndGetStringResult( | 1059 Assert.assertEquals("", |
| 1060 executeJavaScriptAndGetStringResult( |
| 935 String.format(jsObjectKeysTestTemplate, nonInspectableOb
jectName))); | 1061 String.format(jsObjectKeysTestTemplate, nonInspectableOb
jectName))); |
| 936 assertEquals("", executeJavaScriptAndGetStringResult( | 1062 Assert.assertEquals("", |
| 1063 executeJavaScriptAndGetStringResult( |
| 937 String.format(jsForInTestTemplate, nonInspectableObjectN
ame))); | 1064 String.format(jsForInTestTemplate, nonInspectableObjectN
ame))); |
| 938 } | 1065 } |
| 939 | 1066 |
| 1067 @Test |
| 940 @SmallTest | 1068 @SmallTest |
| 941 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 1069 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 942 public void testAccessToObjectGetClassIsBlocked() throws Throwable { | 1070 public void testAccessToObjectGetClassIsBlocked() throws Throwable { |
| 943 injectObjectAndReload(new Object(), "testObject"); | 1071 setUpHelper(); |
| 944 assertEquals("function", executeJavaScriptAndGetStringResult("typeof tes
tObject.getClass")); | 1072 mActivityTestRule.injectObjectAndReload(new Object(), "testObject"); |
| 1073 Assert.assertEquals( |
| 1074 "function", executeJavaScriptAndGetStringResult("typeof testObje
ct.getClass")); |
| 945 assertRaisesException("testObject.getClass()"); | 1075 assertRaisesException("testObject.getClass()"); |
| 946 } | 1076 } |
| 947 | 1077 |
| 1078 @Test |
| 948 @SmallTest | 1079 @SmallTest |
| 949 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 1080 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 950 public void testReplaceJavascriptInterface() throws Throwable { | 1081 public void testReplaceJavascriptInterface() throws Throwable { |
| 1082 setUpHelper(); |
| 951 class Test { | 1083 class Test { |
| 952 public Test(int value) { | 1084 public Test(int value) { |
| 953 mValue = value; | 1085 mValue = value; |
| 954 } | 1086 } |
| 955 @JavascriptInterface | 1087 @JavascriptInterface |
| 956 public int getValue() { | 1088 public int getValue() { |
| 957 return mValue; | 1089 return mValue; |
| 958 } | 1090 } |
| 959 private int mValue; | 1091 private int mValue; |
| 960 } | 1092 } |
| 961 injectObjectAndReload(new Test(13), "testObject"); | 1093 mActivityTestRule.injectObjectAndReload(new Test(13), "testObject"); |
| 962 assertEquals("13", executeJavaScriptAndGetStringResult("testObject.getVa
lue()")); | 1094 Assert.assertEquals("13", executeJavaScriptAndGetStringResult("testObjec
t.getValue()")); |
| 963 // The documentation doesn't specify, what happens if the embedder is tr
ying | 1095 // The documentation doesn't specify, what happens if the embedder is tr
ying |
| 964 // to inject a different object under the same name. The current impleme
ntation | 1096 // to inject a different object under the same name. The current impleme
ntation |
| 965 // simply replaces the old object with the new one. | 1097 // simply replaces the old object with the new one. |
| 966 injectObjectAndReload(new Test(42), "testObject"); | 1098 mActivityTestRule.injectObjectAndReload(new Test(42), "testObject"); |
| 967 assertEquals("42", executeJavaScriptAndGetStringResult("testObject.getVa
lue()")); | 1099 Assert.assertEquals("42", executeJavaScriptAndGetStringResult("testObjec
t.getValue()")); |
| 968 } | 1100 } |
| 969 | 1101 |
| 1102 @Test |
| 970 @SmallTest | 1103 @SmallTest |
| 971 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 1104 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 972 public void testMethodCalledOnAnotherInstance() throws Throwable { | 1105 public void testMethodCalledOnAnotherInstance() throws Throwable { |
| 1106 setUpHelper(); |
| 973 class TestObject { | 1107 class TestObject { |
| 974 private int mIndex; | 1108 private int mIndex; |
| 975 TestObject(int index) { | 1109 TestObject(int index) { |
| 976 mIndex = index; | 1110 mIndex = index; |
| 977 } | 1111 } |
| 978 public void method() { | 1112 public void method() { |
| 979 mTestController.setIntValue(mIndex); | 1113 mTestController.setIntValue(mIndex); |
| 980 } | 1114 } |
| 981 } | 1115 } |
| 982 final TestObject testObject1 = new TestObject(1); | 1116 final TestObject testObject1 = new TestObject(1); |
| 983 final TestObject testObject2 = new TestObject(2); | 1117 final TestObject testObject2 = new TestObject(2); |
| 984 injectObjectsAndReload(testObject1, "testObject1", testObject2, "testObj
ect2", null); | 1118 mActivityTestRule.injectObjectsAndReload( |
| 985 executeJavaScript("testObject1.method()"); | 1119 testObject1, "testObject1", testObject2, "testObject2", null); |
| 986 assertEquals(1, mTestController.waitForIntValue()); | 1120 mActivityTestRule.executeJavaScript("testObject1.method()"); |
| 987 executeJavaScript("testObject2.method()"); | 1121 Assert.assertEquals(1, mTestController.waitForIntValue()); |
| 988 assertEquals(2, mTestController.waitForIntValue()); | 1122 mActivityTestRule.executeJavaScript("testObject2.method()"); |
| 989 executeJavaScript("testObject1.method.call(testObject2)"); | 1123 Assert.assertEquals(2, mTestController.waitForIntValue()); |
| 990 assertEquals(2, mTestController.waitForIntValue()); | 1124 mActivityTestRule.executeJavaScript("testObject1.method.call(testObject2
)"); |
| 991 executeJavaScript("testObject2.method.call(testObject1)"); | 1125 Assert.assertEquals(2, mTestController.waitForIntValue()); |
| 992 assertEquals(1, mTestController.waitForIntValue()); | 1126 mActivityTestRule.executeJavaScript("testObject2.method.call(testObject1
)"); |
| 1127 Assert.assertEquals(1, mTestController.waitForIntValue()); |
| 993 } | 1128 } |
| 994 } | 1129 } |
| OLD | NEW |