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