| 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 android.test.suitebuilder.annotation.SmallTest; | 7 import android.test.suitebuilder.annotation.SmallTest; |
| 8 | 8 |
| 9 import org.chromium.base.test.util.Feature; | 9 import org.chromium.base.test.util.Feature; |
| 10 import org.chromium.content.browser.test.util.TestCallbackHelperContainer; | 10 import org.chromium.content.browser.test.util.TestCallbackHelperContainer; |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 131 @Override | 131 @Override |
| 132 public void run() { | 132 public void run() { |
| 133 getContentViewCore().getWebContents().getNavigationController().
reload(true); | 133 getContentViewCore().getWebContents().getNavigationController().
reload(true); |
| 134 } | 134 } |
| 135 }); | 135 }); |
| 136 onPageFinishedHelper.waitForCallback(currentCallCount); | 136 onPageFinishedHelper.waitForCallback(currentCallCount); |
| 137 } | 137 } |
| 138 | 138 |
| 139 // Note that this requires that we can pass a JavaScript boolean to Java. | 139 // Note that this requires that we can pass a JavaScript boolean to Java. |
| 140 private void assertRaisesException(String script) throws Throwable { | 140 private void assertRaisesException(String script) throws Throwable { |
| 141 executeJavaScript("try {" + | 141 executeJavaScript("try {" |
| 142 script + ";" + | 142 + script + ";" |
| 143 " testController.setBooleanValue(false);" + | 143 + " testController.setBooleanValue(false);" |
| 144 "} catch (exception) {" + | 144 + "} catch (exception) {" |
| 145 " testController.setBooleanValue(true);" + | 145 + " testController.setBooleanValue(true);" |
| 146 "}"); | 146 + "}"); |
| 147 assertTrue(mTestController.waitForBooleanValue()); | 147 assertTrue(mTestController.waitForBooleanValue()); |
| 148 } | 148 } |
| 149 | 149 |
| 150 @SmallTest | 150 @SmallTest |
| 151 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 151 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 152 public void testTypeOfInjectedObject() throws Throwable { | 152 public void testTypeOfInjectedObject() throws Throwable { |
| 153 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testC
ontroller")); | 153 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testC
ontroller")); |
| 154 } | 154 } |
| 155 | 155 |
| 156 @SmallTest | 156 @SmallTest |
| (...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 454 return inner; | 454 return inner; |
| 455 } | 455 } |
| 456 // A weak reference is used to check InnerObject instance reachabili
ty. | 456 // A weak reference is used to check InnerObject instance reachabili
ty. |
| 457 WeakReference<InnerObject> mWeakRefForInner; | 457 WeakReference<InnerObject> mWeakRefForInner; |
| 458 } | 458 } |
| 459 TestObject object = new TestObject(); | 459 TestObject object = new TestObject(); |
| 460 injectObjectAndReload(object, "testObject"); | 460 injectObjectAndReload(object, "testObject"); |
| 461 // Initially, store a reference to the inner object in JS to make sure i
t's not | 461 // Initially, store a reference to the inner object in JS to make sure i
t's not |
| 462 // garbage-collected prematurely. | 462 // garbage-collected prematurely. |
| 463 assertEquals("object", executeJavaScriptAndGetStringResult( | 463 assertEquals("object", executeJavaScriptAndGetStringResult( |
| 464 "(function() { " + | 464 "(function() { " |
| 465 "globalInner = testObject.getInnerObject(); return typeo
f globalInner; " + | 465 + "globalInner = testObject.getInnerObject(); return typ
eof globalInner; " |
| 466 "})()")); | 466 + "})()")); |
| 467 assertTrue(object.mWeakRefForInner.get() != null); | 467 assertTrue(object.mWeakRefForInner.get() != null); |
| 468 // Check that returned Java object is being held by the Java bridge, thu
s it's not | 468 // Check that returned Java object is being held by the Java bridge, thu
s it's not |
| 469 // collected. Note that despite that what JavaDoc says about invoking "
gc()", both Dalvik | 469 // collected. Note that despite that what JavaDoc says about invoking "
gc()", both Dalvik |
| 470 // and ART actually run the collector. | 470 // and ART actually run the collector. |
| 471 Runtime.getRuntime().gc(); | 471 Runtime.getRuntime().gc(); |
| 472 assertTrue(object.mWeakRefForInner.get() != null); | 472 assertTrue(object.mWeakRefForInner.get() != null); |
| 473 // Now dereference the inner object in JS and run GC to collect the inte
rface object. | 473 // Now dereference the inner object in JS and run GC to collect the inte
rface object. |
| 474 assertEquals("true", executeJavaScriptAndGetStringResult( | 474 assertEquals("true", executeJavaScriptAndGetStringResult( |
| 475 "(function() { " + | 475 "(function() { " |
| 476 "delete globalInner; gc(); return (typeof globalInner ==
'undefined'); " + | 476 + "delete globalInner; gc(); return (typeof globalInner
== 'undefined'); " |
| 477 "})()")); | 477 + "})()")); |
| 478 // Force GC on the Java side again. The bridge had to release the inner
object, so it must | 478 // Force GC on the Java side again. The bridge had to release the inner
object, so it must |
| 479 // be collected this time. | 479 // be collected this time. |
| 480 Runtime.getRuntime().gc(); | 480 Runtime.getRuntime().gc(); |
| 481 assertEquals(null, object.mWeakRefForInner.get()); | 481 assertEquals(null, object.mWeakRefForInner.get()); |
| 482 } | 482 } |
| 483 | 483 |
| 484 @SmallTest | 484 @SmallTest |
| 485 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 485 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 486 public void testSameReturnedObjectUsesSameWrapper() throws Throwable { | 486 public void testSameReturnedObjectUsesSameWrapper() throws Throwable { |
| 487 class InnerObject { | 487 class InnerObject { |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 569 @SmallTest | 569 @SmallTest |
| 570 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 570 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 571 public void testEnumerateMembers() throws Throwable { | 571 public void testEnumerateMembers() throws Throwable { |
| 572 injectObjectAndReload(new Object() { | 572 injectObjectAndReload(new Object() { |
| 573 public void method() {} | 573 public void method() {} |
| 574 private void privateMethod() {} | 574 private void privateMethod() {} |
| 575 public int field; | 575 public int field; |
| 576 private int mPrivateField; | 576 private int mPrivateField; |
| 577 }, "testObject"); | 577 }, "testObject"); |
| 578 executeJavaScript( | 578 executeJavaScript( |
| 579 "var result = \"\"; " + | 579 "var result = \"\"; " |
| 580 "for (x in testObject) { result += \" \" + x } " + | 580 + "for (x in testObject) { result += \" \" + x } " |
| 581 "testController.setStringValue(result);"); | 581 + "testController.setStringValue(result);"); |
| 582 assertEquals(" equals getClass hashCode method notify notifyAll toString
wait", | 582 assertEquals(" equals getClass hashCode method notify notifyAll toString
wait", |
| 583 mTestController.waitForStringValue()); | 583 mTestController.waitForStringValue()); |
| 584 } | 584 } |
| 585 | 585 |
| 586 @SmallTest | 586 @SmallTest |
| 587 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 587 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 588 public void testReflectPublicMethod() throws Throwable { | 588 public void testReflectPublicMethod() throws Throwable { |
| 589 injectObjectAndReload(new Object() { | 589 injectObjectAndReload(new Object() { |
| 590 public Class<?> myGetClass() { | 590 public Class<?> myGetClass() { |
| 591 return getClass(); | 591 return getClass(); |
| 592 } | 592 } |
| 593 | 593 |
| 594 public String method() { | 594 public String method() { |
| 595 return "foo"; | 595 return "foo"; |
| 596 } | 596 } |
| 597 }, "testObject"); | 597 }, "testObject"); |
| 598 assertEquals("foo", executeJavaScriptAndGetStringResult( | 598 assertEquals("foo", executeJavaScriptAndGetStringResult( |
| 599 "testObject.myGetClass().getMethod('method', null).invoke(testOb
ject, null)" + | 599 "testObject.myGetClass().getMethod('method', null).invoke(testOb
ject, null)" |
| 600 ".toString()")); | 600 + ".toString()")); |
| 601 } | 601 } |
| 602 | 602 |
| 603 @SmallTest | 603 @SmallTest |
| 604 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 604 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 605 public void testReflectPublicField() throws Throwable { | 605 public void testReflectPublicField() throws Throwable { |
| 606 injectObjectAndReload(new Object() { | 606 injectObjectAndReload(new Object() { |
| 607 public Class<?> myGetClass() { | 607 public Class<?> myGetClass() { |
| 608 return getClass(); | 608 return getClass(); |
| 609 } | 609 } |
| 610 | 610 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 621 public Class<?> myGetClass() { | 621 public Class<?> myGetClass() { |
| 622 return getClass(); | 622 return getClass(); |
| 623 } | 623 } |
| 624 | 624 |
| 625 private void method() {}; | 625 private void method() {}; |
| 626 }, "testObject"); | 626 }, "testObject"); |
| 627 assertRaisesException("testObject.myGetClass().getMethod('method', null)
"); | 627 assertRaisesException("testObject.myGetClass().getMethod('method', null)
"); |
| 628 // getDeclaredMethod() is able to access a private method, but invoke() | 628 // getDeclaredMethod() is able to access a private method, but invoke() |
| 629 // throws a Java exception. | 629 // throws a Java exception. |
| 630 assertRaisesException( | 630 assertRaisesException( |
| 631 "testObject.myGetClass().getDeclaredMethod('method', null)." + | 631 "testObject.myGetClass().getDeclaredMethod('method', null)." |
| 632 "invoke(testObject, null)"); | 632 + "invoke(testObject, null)"); |
| 633 } | 633 } |
| 634 | 634 |
| 635 @SmallTest | 635 @SmallTest |
| 636 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 636 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 637 public void testReflectPrivateFieldRaisesException() throws Throwable { | 637 public void testReflectPrivateFieldRaisesException() throws Throwable { |
| 638 injectObjectAndReload(new Object() { | 638 injectObjectAndReload(new Object() { |
| 639 public Class<?> myGetClass() { | 639 public Class<?> myGetClass() { |
| 640 return getClass(); | 640 return getClass(); |
| 641 } | 641 } |
| 642 | 642 |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 866 } | 866 } |
| 867 | 867 |
| 868 @JavascriptInterface | 868 @JavascriptInterface |
| 869 public String m2(int x) { | 869 public String m2(int x) { |
| 870 return "bar " + x; | 870 return "bar " + x; |
| 871 } | 871 } |
| 872 } | 872 } |
| 873 | 873 |
| 874 final String jsObjectKeysTestTemplate = "Object.keys(%s).toString()"; | 874 final String jsObjectKeysTestTemplate = "Object.keys(%s).toString()"; |
| 875 final String jsForInTestTemplate = | 875 final String jsForInTestTemplate = |
| 876 "(function(){" + | 876 "(function(){" |
| 877 " var s=[]; for(var m in %s) s.push(m); return s.join(\",\")" + | 877 + " var s=[]; for(var m in %s) s.push(m); return s.join(\",\")" |
| 878 "})()"; | 878 + "})()"; |
| 879 final String inspectableObjectName = "testObj1"; | 879 final String inspectableObjectName = "testObj1"; |
| 880 final String nonInspectableObjectName = "testObj2"; | 880 final String nonInspectableObjectName = "testObj2"; |
| 881 | 881 |
| 882 // Inspection is enabled by default. | 882 // Inspection is enabled by default. |
| 883 injectObjectAndReload(new Test(), inspectableObjectName, JavascriptInter
face.class); | 883 injectObjectAndReload(new Test(), inspectableObjectName, JavascriptInter
face.class); |
| 884 | 884 |
| 885 assertEquals("m1,m2", executeJavaScriptAndGetStringResult( | 885 assertEquals("m1,m2", executeJavaScriptAndGetStringResult( |
| 886 String.format(jsObjectKeysTestTemplate, inspectableObjec
tName))); | 886 String.format(jsObjectKeysTestTemplate, inspectableObjec
tName))); |
| 887 assertEquals("m1,m2", executeJavaScriptAndGetStringResult( | 887 assertEquals("m1,m2", executeJavaScriptAndGetStringResult( |
| 888 String.format(jsForInTestTemplate, inspectableObjectName
))); | 888 String.format(jsForInTestTemplate, inspectableObjectName
))); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 902 String.format(jsForInTestTemplate, nonInspectableObjectN
ame))); | 902 String.format(jsForInTestTemplate, nonInspectableObjectN
ame))); |
| 903 } | 903 } |
| 904 | 904 |
| 905 @SmallTest | 905 @SmallTest |
| 906 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 906 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 907 public void testAccessToObjectGetClassIsBlocked() throws Throwable { | 907 public void testAccessToObjectGetClassIsBlocked() throws Throwable { |
| 908 injectObjectAndReload(new Object(), "testObject"); | 908 injectObjectAndReload(new Object(), "testObject"); |
| 909 assertEquals("function", executeJavaScriptAndGetStringResult("typeof tes
tObject.getClass")); | 909 assertEquals("function", executeJavaScriptAndGetStringResult("typeof tes
tObject.getClass")); |
| 910 assertRaisesException("testObject.getClass()"); | 910 assertRaisesException("testObject.getClass()"); |
| 911 } | 911 } |
| 912 |
| 913 @SmallTest |
| 914 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 915 public void testReplaceJavascriptInterface() throws Throwable { |
| 916 class Test { |
| 917 public Test(int value) { |
| 918 mValue = value; |
| 919 } |
| 920 @JavascriptInterface |
| 921 public int getValue() { |
| 922 return mValue; |
| 923 } |
| 924 private int mValue; |
| 925 } |
| 926 injectObjectAndReload(new Test(13), "testObject"); |
| 927 assertEquals("13", executeJavaScriptAndGetStringResult("testObject.getVa
lue()")); |
| 928 // The documentation doesn't specify, what happens if the embedder is tr
ying |
| 929 // to inject a different object under the same name. The current impleme
ntation |
| 930 // simply replaces the old object with the new one. |
| 931 injectObjectAndReload(new Test(42), "testObject"); |
| 932 assertEquals("42", executeJavaScriptAndGetStringResult("testObject.getVa
lue()")); |
| 933 } |
| 912 } | 934 } |
| OLD | NEW |