| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 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 // Tests for CppBoundClass, in conjunction with CppBindingExample. Binds | 5 // Tests for CppBoundClass, in conjunction with CppBindingExample. Binds |
| 6 // a CppBindingExample class into JavaScript in a custom test shell and tests | 6 // a CppBindingExample class into JavaScript in a custom test shell and tests |
| 7 // the binding from the outside by loading JS into the shell. | 7 // the binding from the outside by loading JS into the shell. |
| 8 | 8 |
| 9 #include <vector> | 9 #include "base/utf_string_conversions.h" |
| 10 | 10 #include "content/public/renderer/render_view_observer.h" |
| 11 #include "base/bind.h" | 11 #include "content/public/test/render_view_test.h" |
| 12 #include "base/bind_helpers.h" | |
| 13 #include "base/message_loop.h" | |
| 14 #include "base/string_util.h" | |
| 15 #include "testing/gtest/include/gtest/gtest.h" | |
| 16 #include "third_party/WebKit/Source/Platform/chromium/public/Platform.h" | |
| 17 #include "third_party/WebKit/Source/Platform/chromium/public/WebData.h" | |
| 18 #include "third_party/WebKit/Source/Platform/chromium/public/WebSize.h" | |
| 19 #include "third_party/WebKit/Source/Platform/chromium/public/WebString.h" | |
| 20 #include "third_party/WebKit/Source/Platform/chromium/public/WebURL.h" | |
| 21 #include "third_party/WebKit/Source/Platform/chromium/public/WebURLRequest.h" | 12 #include "third_party/WebKit/Source/Platform/chromium/public/WebURLRequest.h" |
| 22 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" | |
| 23 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrameClient.h" | |
| 24 #include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h" | |
| 25 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSettings.h" | |
| 26 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" | |
| 27 #include "third_party/WebKit/Source/WebKit/chromium/public/WebViewClient.h" | |
| 28 #include "webkit/glue/cpp_binding_example.h" | 13 #include "webkit/glue/cpp_binding_example.h" |
| 29 #include "webkit/glue/webkit_glue.h" | 14 #include "webkit/glue/webkit_glue.h" |
| 30 #include "webkit/user_agent/user_agent.h" | |
| 31 #include "webkit/user_agent/user_agent_util.h" | |
| 32 | 15 |
| 33 using WebKit::WebFrame; | |
| 34 using WebKit::WebView; | |
| 35 using webkit_glue::CppArgumentList; | 16 using webkit_glue::CppArgumentList; |
| 36 using webkit_glue::CppBindingExample; | 17 using webkit_glue::CppBindingExample; |
| 37 using webkit_glue::CppVariant; | 18 using webkit_glue::CppVariant; |
| 38 | 19 |
| 39 namespace { | 20 namespace content { |
| 40 | 21 |
| 41 class CppBindingExampleSubObject : public CppBindingExample { | 22 class CppBindingExampleSubObject : public CppBindingExample { |
| 42 public: | 23 public: |
| 43 CppBindingExampleSubObject() { | 24 CppBindingExampleSubObject() { |
| 44 sub_value_.Set("sub!"); | 25 sub_value_.Set("sub!"); |
| 45 BindProperty("sub_value", &sub_value_); | 26 BindProperty("sub_value", &sub_value_); |
| 46 } | 27 } |
| 47 private: | 28 private: |
| 48 CppVariant sub_value_; | 29 CppVariant sub_value_; |
| 49 }; | 30 }; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 64 | 45 |
| 65 // The fallback method does nothing, but because of it the JavaScript keeps | 46 // The fallback method does nothing, but because of it the JavaScript keeps |
| 66 // running when a nonexistent method is called on an object. | 47 // running when a nonexistent method is called on an object. |
| 67 void fallbackMethod(const CppArgumentList& args, CppVariant* result) { | 48 void fallbackMethod(const CppArgumentList& args, CppVariant* result) { |
| 68 } | 49 } |
| 69 | 50 |
| 70 private: | 51 private: |
| 71 CppBindingExampleSubObject sub_object_; | 52 CppBindingExampleSubObject sub_object_; |
| 72 }; | 53 }; |
| 73 | 54 |
| 74 class TestWebFrameClient : public WebKit::WebFrameClient { | 55 class TestObserver : public RenderViewObserver { |
| 75 public: | 56 public: |
| 76 virtual void didClearWindowObject(WebKit::WebFrame* frame) OVERRIDE { | 57 explicit TestObserver(RenderView* render_view) |
| 58 : RenderViewObserver(render_view) {} |
| 59 virtual void DidClearWindowObject(WebKit::WebFrame* frame) OVERRIDE { |
| 77 example_bound_class_.BindToJavascript(frame, "example"); | 60 example_bound_class_.BindToJavascript(frame, "example"); |
| 78 } | 61 } |
| 79 void set_fallback_method_enabled(bool use_fallback) { | 62 void set_fallback_method_enabled(bool use_fallback) { |
| 80 example_bound_class_.set_fallback_method_enabled(use_fallback); | 63 example_bound_class_.set_fallback_method_enabled(use_fallback); |
| 81 } | 64 } |
| 82 private: | 65 private: |
| 83 CppBindingExampleWithOptionalFallback example_bound_class_; | 66 CppBindingExampleWithOptionalFallback example_bound_class_; |
| 84 }; | 67 }; |
| 85 | 68 |
| 86 class TestWebViewClient : public WebKit::WebViewClient { | 69 class CppBoundClassTest : public RenderViewTest { |
| 87 }; | |
| 88 | |
| 89 class CppBoundClassTest : public testing::Test, public WebKit::WebFrameClient { | |
| 90 public: | 70 public: |
| 91 CppBoundClassTest() : webview_(NULL) { } | 71 CppBoundClassTest() {} |
| 92 | 72 |
| 93 virtual void SetUp() OVERRIDE { | 73 virtual void SetUp() OVERRIDE { |
| 94 webview_ = WebView::create(&webview_client_); | 74 RenderViewTest::SetUp(); |
| 95 webview_->settings()->setJavaScriptEnabled(true); | 75 observer_.reset(new TestObserver(view_)); |
| 96 webview_->initializeMainFrame(&webframe_client_); | 76 observer_->set_fallback_method_enabled(useFallback()); |
| 97 webframe_client_.set_fallback_method_enabled(useFallback()); | |
| 98 webkit_glue::SetUserAgent(webkit_glue::BuildUserAgentFromProduct( | |
| 99 "TestShell/0.0.0.0"), false); | |
| 100 | 77 |
| 101 WebKit::WebURLRequest urlRequest; | 78 WebKit::WebURLRequest url_request; |
| 102 urlRequest.initialize(); | 79 url_request.initialize(); |
| 103 urlRequest.setURL(GURL("about:blank")); | 80 url_request.setURL(GURL("about:blank")); |
| 104 webframe()->loadRequest(urlRequest); | |
| 105 } | |
| 106 | 81 |
| 107 virtual void TearDown() OVERRIDE { | 82 GetMainFrame()->loadRequest(url_request); |
| 108 if (webview_) | 83 ProcessPendingMessages(); |
| 109 webview_->close(); | |
| 110 } | |
| 111 | |
| 112 WebFrame* webframe() { | |
| 113 return webview_->mainFrame(); | |
| 114 } | |
| 115 | |
| 116 // Wraps the given JavaScript snippet in <html><body><script> tags, then | |
| 117 // loads it into a webframe so it is executed. | |
| 118 void ExecuteJavaScript(const std::string& javascript) { | |
| 119 std::string html = "<html><body>"; | |
| 120 html.append("<script>"); | |
| 121 html.append(javascript); | |
| 122 html.append("</script></body></html>"); | |
| 123 webframe()->loadHTMLString(html, GURL("about:blank")); | |
| 124 MessageLoop::current()->RunUntilIdle(); | |
| 125 } | |
| 126 | |
| 127 // Executes the specified JavaScript and checks to be sure that the resulting | |
| 128 // document text is exactly "SUCCESS". | |
| 129 void CheckJavaScriptSuccess(const std::string& javascript) { | |
| 130 ExecuteJavaScript(javascript); | |
| 131 EXPECT_EQ("SUCCESS", | |
| 132 UTF16ToASCII(webkit_glue::DumpDocumentText(webframe()))); | |
| 133 } | 84 } |
| 134 | 85 |
| 135 // Executes the specified JavaScript and checks that the resulting document | 86 // Executes the specified JavaScript and checks that the resulting document |
| 136 // text is empty. | 87 // text is empty. |
| 137 void CheckJavaScriptFailure(const std::string& javascript) { | 88 void CheckJavaScriptFailure(const std::string& javascript) { |
| 138 ExecuteJavaScript(javascript); | 89 ExecuteJavaScript(javascript.c_str()); |
| 139 EXPECT_EQ("", UTF16ToASCII(webkit_glue::DumpDocumentText(webframe()))); | 90 EXPECT_EQ("", UTF16ToASCII(webkit_glue::DumpDocumentText(GetMainFrame()))); |
| 140 } | 91 } |
| 141 | 92 |
| 142 // Constructs a JavaScript snippet that evaluates and compares the left and | 93 void CheckTrue(const std::string& expression) { |
| 143 // right expressions, printing "SUCCESS" to the page if they are equal and | 94 int was_page_a = -1; |
| 144 // printing their actual values if they are not. Any strings in the | 95 string16 check_page_a = |
| 145 // expressions should be enclosed in single quotes, and no double quotes | 96 ASCIIToUTF16(std::string("Number(") + expression + ")"); |
| 146 // should appear in either expression (even if escaped). (If a test case | 97 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a, &was_page_a)); |
| 147 // is added that needs fancier quoting, Json::valueToQuotedString could be | 98 EXPECT_EQ(1, was_page_a); |
| 148 // used here. For now, it's not worth adding the dependency.) | |
| 149 std::string BuildJSCondition(std::string left, std::string right) { | |
| 150 return "var leftval = " + left + ";" + | |
| 151 "var rightval = " + right + ";" + | |
| 152 "if (leftval == rightval) {" + | |
| 153 " document.writeln('SUCCESS');" + | |
| 154 "} else {" + | |
| 155 " document.writeln(\"" + | |
| 156 left + " [\" + leftval + \"] != " + | |
| 157 right + " [\" + rightval + \"]\");" + | |
| 158 "}"; | |
| 159 } | 99 } |
| 160 | 100 |
| 161 protected: | 101 protected: |
| 162 virtual bool useFallback() { | 102 virtual bool useFallback() { |
| 163 return false; | 103 return false; |
| 164 } | 104 } |
| 165 | 105 |
| 166 private: | 106 private: |
| 167 WebView* webview_; | 107 scoped_ptr<TestObserver> observer_; |
| 168 TestWebFrameClient webframe_client_; | |
| 169 TestWebViewClient webview_client_; | |
| 170 }; | 108 }; |
| 171 | 109 |
| 172 class CppBoundClassWithFallbackMethodTest : public CppBoundClassTest { | 110 class CppBoundClassWithFallbackMethodTest : public CppBoundClassTest { |
| 173 protected: | 111 protected: |
| 174 virtual bool useFallback() OVERRIDE { | 112 virtual bool useFallback() OVERRIDE { |
| 175 return true; | 113 return true; |
| 176 } | 114 } |
| 177 }; | 115 }; |
| 178 | 116 |
| 179 // Ensures that the example object has been bound to JS. | 117 // Ensures that the example object has been bound to JS. |
| 180 TEST_F(CppBoundClassTest, ObjectExists) { | 118 TEST_F(CppBoundClassTest, ObjectExists) { |
| 181 std::string js = BuildJSCondition("typeof window.example", "'object'"); | 119 CheckTrue("typeof window.example == 'object'"); |
| 182 CheckJavaScriptSuccess(js); | |
| 183 | 120 |
| 184 // An additional check to test our test. | 121 // An additional check to test our test. |
| 185 js = BuildJSCondition("typeof window.invalid_object", "'undefined'"); | 122 CheckTrue("typeof window.invalid_object == 'undefined'"); |
| 186 CheckJavaScriptSuccess(js); | |
| 187 } | 123 } |
| 188 | 124 |
| 189 TEST_F(CppBoundClassTest, PropertiesAreInitialized) { | 125 TEST_F(CppBoundClassTest, PropertiesAreInitialized) { |
| 190 std::string js = BuildJSCondition("example.my_value", "10"); | 126 CheckTrue("example.my_value == 10"); |
| 191 CheckJavaScriptSuccess(js); | |
| 192 | 127 |
| 193 js = BuildJSCondition("example.my_other_value", "'Reinitialized!'"); | 128 CheckTrue("example.my_other_value == 'Reinitialized!'"); |
| 194 CheckJavaScriptSuccess(js); | |
| 195 } | 129 } |
| 196 | 130 |
| 197 TEST_F(CppBoundClassTest, SubOject) { | 131 TEST_F(CppBoundClassTest, SubOject) { |
| 198 std::string js = BuildJSCondition("typeof window.example.sub_object", | 132 CheckTrue("typeof window.example.sub_object == 'object'"); |
| 199 "'object'"); | |
| 200 CheckJavaScriptSuccess(js); | |
| 201 | 133 |
| 202 js = BuildJSCondition("example.sub_object.sub_value", "'sub!'"); | 134 CheckTrue("example.sub_object.sub_value == 'sub!'"); |
| 203 CheckJavaScriptSuccess(js); | |
| 204 } | 135 } |
| 205 | 136 |
| 206 TEST_F(CppBoundClassTest, SetAndGetProperties) { | 137 TEST_F(CppBoundClassTest, SetAndGetProperties) { |
| 207 // The property on the left will be set to the value on the right, then | 138 // The property on the left will be set to the value on the right, then |
| 208 // checked to make sure it holds that same value. | 139 // checked to make sure it holds that same value. |
| 209 static const std::string tests[] = { | 140 static const std::string tests[] = { |
| 210 "example.my_value", "7", | 141 "example.my_value", "7", |
| 211 "example.my_value", "'test'", | 142 "example.my_value", "'test'", |
| 212 "example.my_other_value", "3.14", | 143 "example.my_other_value", "3.14", |
| 213 "example.my_other_value", "false", | 144 "example.my_other_value", "false", |
| 214 "" // Array end marker: insert additional test pairs before this. | 145 "" // Array end marker: insert additional test pairs before this. |
| 215 }; | 146 }; |
| 216 | 147 |
| 217 for (int i = 0; tests[i] != ""; i += 2) { | 148 for (int i = 0; tests[i] != ""; i += 2) { |
| 218 std::string left = tests[i]; | 149 std::string left = tests[i]; |
| 219 std::string right = tests[i + 1]; | 150 std::string right = tests[i + 1]; |
| 220 // left = right; | 151 // left = right; |
| 221 std::string js = left; | 152 std::string js = left; |
| 222 js.append(" = "); | 153 js.append(" = "); |
| 223 js.append(right); | 154 js.append(right); |
| 224 js.append(";"); | 155 js.append(";"); |
| 225 js.append(BuildJSCondition(left, right)); | 156 ExecuteJavaScript(js.c_str()); |
| 226 CheckJavaScriptSuccess(js); | 157 std::string expression = left; |
| 158 expression += " == "; |
| 159 expression += right; |
| 160 CheckTrue(expression); |
| 227 } | 161 } |
| 228 } | 162 } |
| 229 | 163 |
| 230 TEST_F(CppBoundClassTest, SetAndGetPropertiesWithCallbacks) { | 164 TEST_F(CppBoundClassTest, SetAndGetPropertiesWithCallbacks) { |
| 231 // TODO(dglazkov): fix NPObject issues around failing property setters and | 165 // TODO(dglazkov): fix NPObject issues around failing property setters and |
| 232 // getters and add tests for situations when GetProperty or SetProperty fail. | 166 // getters and add tests for situations when GetProperty or SetProperty fail. |
| 233 std::string js = "var result = 'SUCCESS';\n" | 167 ExecuteJavaScript("example.my_value_with_callback = 10;"); |
| 234 "example.my_value_with_callback = 10;\n" | 168 CheckTrue("example.my_value_with_callback == 10"); |
| 235 "if (example.my_value_with_callback != 10)\n" | 169 |
| 236 " result = 'FAIL: unable to set property.';\n" | 170 ExecuteJavaScript("example.my_value_with_callback = 11;"); |
| 237 "example.my_value_with_callback = 11;\n" | 171 CheckTrue("example.my_value_with_callback == 11"); |
| 238 "if (example.my_value_with_callback != 11)\n" | 172 |
| 239 " result = 'FAIL: unable to set property again';\n" | 173 CheckTrue("example.same == 42"); |
| 240 "if (example.same != 42)\n" | 174 |
| 241 " result = 'FAIL: same property should always be 42';\n" | 175 ExecuteJavaScript("example.same = 24;"); |
| 242 "example.same = 24;\n" | 176 CheckTrue("example.same == 42"); |
| 243 "if (example.same != 42)\n" | |
| 244 " result = 'FAIL: same property should always be 42';\n" | |
| 245 "document.writeln(result);\n"; | |
| 246 CheckJavaScriptSuccess(js); | |
| 247 } | 177 } |
| 248 | 178 |
| 249 TEST_F(CppBoundClassTest, InvokeMethods) { | 179 TEST_F(CppBoundClassTest, InvokeMethods) { |
| 250 // The expression on the left is expected to return the value on the right. | 180 // The expression on the left is expected to return the value on the right. |
| 251 static const std::string tests[] = { | 181 static const std::string tests[] = { |
| 252 "example.echoValue(true)", "true", | 182 "example.echoValue(true) == true", |
| 253 "example.echoValue(13)", "13", | 183 "example.echoValue(13) == 13", |
| 254 "example.echoValue(2.718)", "2.718", | 184 "example.echoValue(2.718) == 2.718", |
| 255 "example.echoValue('yes')", "'yes'", | 185 "example.echoValue('yes') == 'yes'", |
| 256 "example.echoValue()", "null", // Too few arguments | 186 "example.echoValue() == null", // Too few arguments |
| 257 | 187 |
| 258 "example.echoType(false)", "true", | 188 "example.echoType(false) == true", |
| 259 "example.echoType(19)", "3.14159", | 189 "example.echoType(19) == 3.14159", |
| 260 "example.echoType(9.876)", "3.14159", | 190 "example.echoType(9.876) == 3.14159", |
| 261 "example.echoType('test string')", "'Success!'", | 191 "example.echoType('test string') == 'Success!'", |
| 262 "example.echoType()", "null", // Too few arguments | 192 "example.echoType() == null", // Too few arguments |
| 263 | 193 |
| 264 // Comparing floats that aren't integer-valued is usually problematic due | 194 // Comparing floats that aren't integer-valued is usually problematic due |
| 265 // to rounding, but exact powers of 2 should also be safe. | 195 // to rounding, but exact powers of 2 should also be safe. |
| 266 "example.plus(2.5, 18.0)", "20.5", | 196 "example.plus(2.5, 18.0) == 20.5", |
| 267 "example.plus(2, 3.25)", "5.25", | 197 "example.plus(2, 3.25) == 5.25", |
| 268 "example.plus(2, 3)", "5", | 198 "example.plus(2, 3) == 5", |
| 269 "example.plus()", "null", // Too few arguments | 199 "example.plus() == null", // Too few arguments |
| 270 "example.plus(1)", "null", // Too few arguments | 200 "example.plus(1) == null", // Too few arguments |
| 271 "example.plus(1, 'test')", "null", // Wrong argument type | 201 "example.plus(1, 'test') == null", // Wrong argument type |
| 272 "example.plus('test', 2)", "null", // Wrong argument type | 202 "example.plus('test', 2) == null", // Wrong argument type |
| 273 "example.plus('one', 'two')", "null", // Wrong argument type | 203 "example.plus('one', 'two') == null", // Wrong argument type |
| 274 "" // Array end marker: insert additional test pairs before this. | 204 "" // Array end marker: insert additional test pairs before this. |
| 275 }; | 205 }; |
| 276 | 206 |
| 277 for (int i = 0; tests[i] != ""; i+= 2) { | 207 for (int i = 0; tests[i] != ""; i++) |
| 278 std::string left = tests[i]; | 208 CheckTrue(tests[i]); |
| 279 std::string right = tests[i + 1]; | |
| 280 std::string js = BuildJSCondition(left, right); | |
| 281 CheckJavaScriptSuccess(js); | |
| 282 } | |
| 283 | 209 |
| 284 std::string js = "example.my_value = 3.25; example.my_other_value = 1.25;"; | 210 ExecuteJavaScript("example.my_value = 3.25; example.my_other_value = 1.25;"); |
| 285 js.append(BuildJSCondition( | 211 CheckTrue("example.plus(example.my_value, example.my_other_value) == 4.5"); |
| 286 "example.plus(example.my_value, example.my_other_value)", "4.5")); | |
| 287 CheckJavaScriptSuccess(js); | |
| 288 } | 212 } |
| 289 | 213 |
| 290 // Tests that invoking a nonexistent method with no fallback method stops the | 214 // Tests that invoking a nonexistent method with no fallback method stops the |
| 291 // script's execution | 215 // script's execution |
| 292 TEST_F(CppBoundClassTest, | 216 TEST_F(CppBoundClassTest, |
| 293 InvokeNonexistentMethodNoFallback) { | 217 InvokeNonexistentMethodNoFallback) { |
| 294 std::string js = "example.nonExistentMethod();document.writeln('SUCCESS');"; | 218 std::string js = "example.nonExistentMethod();document.writeln('SUCCESS');"; |
| 295 CheckJavaScriptFailure(js); | 219 CheckJavaScriptFailure(js); |
| 296 } | 220 } |
| 297 | 221 |
| 298 // Ensures existent methods can be invoked successfully when the fallback method | 222 // Ensures existent methods can be invoked successfully when the fallback method |
| 299 // is used | 223 // is used |
| 300 TEST_F(CppBoundClassWithFallbackMethodTest, | 224 TEST_F(CppBoundClassWithFallbackMethodTest, |
| 301 InvokeExistentMethodsWithFallback) { | 225 InvokeExistentMethodsWithFallback) { |
| 302 std::string js = BuildJSCondition("example.echoValue(34)", "34"); | 226 CheckTrue("example.echoValue(34) == 34"); |
| 303 CheckJavaScriptSuccess(js); | |
| 304 } | 227 } |
| 305 | 228 |
| 306 } // namespace | 229 } // namespace content |
| OLD | NEW |