| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 // Tests for CppBoundClass, in conjunction with CppBindingExample. Binds | |
| 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. | |
| 8 | |
| 9 #include <vector> | |
| 10 | |
| 11 #include "base/bind.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" | |
| 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" | |
| 29 #include "webkit/glue/webkit_glue.h" | |
| 30 #include "webkit/user_agent/user_agent.h" | |
| 31 #include "webkit/user_agent/user_agent_util.h" | |
| 32 | |
| 33 using WebKit::WebFrame; | |
| 34 using WebKit::WebView; | |
| 35 using webkit_glue::CppArgumentList; | |
| 36 using webkit_glue::CppBindingExample; | |
| 37 using webkit_glue::CppVariant; | |
| 38 | |
| 39 namespace { | |
| 40 | |
| 41 class CppBindingExampleSubObject : public CppBindingExample { | |
| 42 public: | |
| 43 CppBindingExampleSubObject() { | |
| 44 sub_value_.Set("sub!"); | |
| 45 BindProperty("sub_value", &sub_value_); | |
| 46 } | |
| 47 private: | |
| 48 CppVariant sub_value_; | |
| 49 }; | |
| 50 | |
| 51 | |
| 52 class CppBindingExampleWithOptionalFallback : public CppBindingExample { | |
| 53 public: | |
| 54 CppBindingExampleWithOptionalFallback() { | |
| 55 BindProperty("sub_object", sub_object_.GetAsCppVariant()); | |
| 56 } | |
| 57 | |
| 58 void set_fallback_method_enabled(bool state) { | |
| 59 BindFallbackCallback(state ? | |
| 60 base::Bind(&CppBindingExampleWithOptionalFallback::fallbackMethod, | |
| 61 base::Unretained(this)) | |
| 62 : CppBoundClass::Callback()); | |
| 63 } | |
| 64 | |
| 65 // The fallback method does nothing, but because of it the JavaScript keeps | |
| 66 // running when a nonexistent method is called on an object. | |
| 67 void fallbackMethod(const CppArgumentList& args, CppVariant* result) { | |
| 68 } | |
| 69 | |
| 70 private: | |
| 71 CppBindingExampleSubObject sub_object_; | |
| 72 }; | |
| 73 | |
| 74 class TestWebFrameClient : public WebKit::WebFrameClient { | |
| 75 public: | |
| 76 virtual void didClearWindowObject(WebKit::WebFrame* frame) OVERRIDE { | |
| 77 example_bound_class_.BindToJavascript(frame, "example"); | |
| 78 } | |
| 79 void set_fallback_method_enabled(bool use_fallback) { | |
| 80 example_bound_class_.set_fallback_method_enabled(use_fallback); | |
| 81 } | |
| 82 private: | |
| 83 CppBindingExampleWithOptionalFallback example_bound_class_; | |
| 84 }; | |
| 85 | |
| 86 class TestWebViewClient : public WebKit::WebViewClient { | |
| 87 }; | |
| 88 | |
| 89 class CppBoundClassTest : public testing::Test, public WebKit::WebFrameClient { | |
| 90 public: | |
| 91 CppBoundClassTest() : webview_(NULL) { } | |
| 92 | |
| 93 virtual void SetUp() OVERRIDE { | |
| 94 webview_ = WebView::create(&webview_client_); | |
| 95 webview_->settings()->setJavaScriptEnabled(true); | |
| 96 webview_->initializeMainFrame(&webframe_client_); | |
| 97 webframe_client_.set_fallback_method_enabled(useFallback()); | |
| 98 webkit_glue::SetUserAgent(webkit_glue::BuildUserAgentFromProduct( | |
| 99 "TestShell/0.0.0.0"), false); | |
| 100 | |
| 101 WebKit::WebURLRequest urlRequest; | |
| 102 urlRequest.initialize(); | |
| 103 urlRequest.setURL(GURL("about:blank")); | |
| 104 webframe()->loadRequest(urlRequest); | |
| 105 } | |
| 106 | |
| 107 virtual void TearDown() OVERRIDE { | |
| 108 if (webview_) | |
| 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 } | |
| 134 | |
| 135 // Executes the specified JavaScript and checks that the resulting document | |
| 136 // text is empty. | |
| 137 void CheckJavaScriptFailure(const std::string& javascript) { | |
| 138 ExecuteJavaScript(javascript); | |
| 139 EXPECT_EQ("", UTF16ToASCII(webkit_glue::DumpDocumentText(webframe()))); | |
| 140 } | |
| 141 | |
| 142 // Constructs a JavaScript snippet that evaluates and compares the left and | |
| 143 // right expressions, printing "SUCCESS" to the page if they are equal and | |
| 144 // printing their actual values if they are not. Any strings in the | |
| 145 // expressions should be enclosed in single quotes, and no double quotes | |
| 146 // should appear in either expression (even if escaped). (If a test case | |
| 147 // is added that needs fancier quoting, Json::valueToQuotedString could be | |
| 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 } | |
| 160 | |
| 161 protected: | |
| 162 virtual bool useFallback() { | |
| 163 return false; | |
| 164 } | |
| 165 | |
| 166 private: | |
| 167 WebView* webview_; | |
| 168 TestWebFrameClient webframe_client_; | |
| 169 TestWebViewClient webview_client_; | |
| 170 }; | |
| 171 | |
| 172 class CppBoundClassWithFallbackMethodTest : public CppBoundClassTest { | |
| 173 protected: | |
| 174 virtual bool useFallback() OVERRIDE { | |
| 175 return true; | |
| 176 } | |
| 177 }; | |
| 178 | |
| 179 // Ensures that the example object has been bound to JS. | |
| 180 TEST_F(CppBoundClassTest, ObjectExists) { | |
| 181 std::string js = BuildJSCondition("typeof window.example", "'object'"); | |
| 182 CheckJavaScriptSuccess(js); | |
| 183 | |
| 184 // An additional check to test our test. | |
| 185 js = BuildJSCondition("typeof window.invalid_object", "'undefined'"); | |
| 186 CheckJavaScriptSuccess(js); | |
| 187 } | |
| 188 | |
| 189 TEST_F(CppBoundClassTest, PropertiesAreInitialized) { | |
| 190 std::string js = BuildJSCondition("example.my_value", "10"); | |
| 191 CheckJavaScriptSuccess(js); | |
| 192 | |
| 193 js = BuildJSCondition("example.my_other_value", "'Reinitialized!'"); | |
| 194 CheckJavaScriptSuccess(js); | |
| 195 } | |
| 196 | |
| 197 TEST_F(CppBoundClassTest, SubOject) { | |
| 198 std::string js = BuildJSCondition("typeof window.example.sub_object", | |
| 199 "'object'"); | |
| 200 CheckJavaScriptSuccess(js); | |
| 201 | |
| 202 js = BuildJSCondition("example.sub_object.sub_value", "'sub!'"); | |
| 203 CheckJavaScriptSuccess(js); | |
| 204 } | |
| 205 | |
| 206 TEST_F(CppBoundClassTest, SetAndGetProperties) { | |
| 207 // 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. | |
| 209 static const std::string tests[] = { | |
| 210 "example.my_value", "7", | |
| 211 "example.my_value", "'test'", | |
| 212 "example.my_other_value", "3.14", | |
| 213 "example.my_other_value", "false", | |
| 214 "" // Array end marker: insert additional test pairs before this. | |
| 215 }; | |
| 216 | |
| 217 for (int i = 0; tests[i] != ""; i += 2) { | |
| 218 std::string left = tests[i]; | |
| 219 std::string right = tests[i + 1]; | |
| 220 // left = right; | |
| 221 std::string js = left; | |
| 222 js.append(" = "); | |
| 223 js.append(right); | |
| 224 js.append(";"); | |
| 225 js.append(BuildJSCondition(left, right)); | |
| 226 CheckJavaScriptSuccess(js); | |
| 227 } | |
| 228 } | |
| 229 | |
| 230 TEST_F(CppBoundClassTest, SetAndGetPropertiesWithCallbacks) { | |
| 231 // TODO(dglazkov): fix NPObject issues around failing property setters and | |
| 232 // getters and add tests for situations when GetProperty or SetProperty fail. | |
| 233 std::string js = "var result = 'SUCCESS';\n" | |
| 234 "example.my_value_with_callback = 10;\n" | |
| 235 "if (example.my_value_with_callback != 10)\n" | |
| 236 " result = 'FAIL: unable to set property.';\n" | |
| 237 "example.my_value_with_callback = 11;\n" | |
| 238 "if (example.my_value_with_callback != 11)\n" | |
| 239 " result = 'FAIL: unable to set property again';\n" | |
| 240 "if (example.same != 42)\n" | |
| 241 " result = 'FAIL: same property should always be 42';\n" | |
| 242 "example.same = 24;\n" | |
| 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 } | |
| 248 | |
| 249 TEST_F(CppBoundClassTest, InvokeMethods) { | |
| 250 // The expression on the left is expected to return the value on the right. | |
| 251 static const std::string tests[] = { | |
| 252 "example.echoValue(true)", "true", | |
| 253 "example.echoValue(13)", "13", | |
| 254 "example.echoValue(2.718)", "2.718", | |
| 255 "example.echoValue('yes')", "'yes'", | |
| 256 "example.echoValue()", "null", // Too few arguments | |
| 257 | |
| 258 "example.echoType(false)", "true", | |
| 259 "example.echoType(19)", "3.14159", | |
| 260 "example.echoType(9.876)", "3.14159", | |
| 261 "example.echoType('test string')", "'Success!'", | |
| 262 "example.echoType()", "null", // Too few arguments | |
| 263 | |
| 264 // Comparing floats that aren't integer-valued is usually problematic due | |
| 265 // to rounding, but exact powers of 2 should also be safe. | |
| 266 "example.plus(2.5, 18.0)", "20.5", | |
| 267 "example.plus(2, 3.25)", "5.25", | |
| 268 "example.plus(2, 3)", "5", | |
| 269 "example.plus()", "null", // Too few arguments | |
| 270 "example.plus(1)", "null", // Too few arguments | |
| 271 "example.plus(1, 'test')", "null", // Wrong argument type | |
| 272 "example.plus('test', 2)", "null", // Wrong argument type | |
| 273 "example.plus('one', 'two')", "null", // Wrong argument type | |
| 274 "" // Array end marker: insert additional test pairs before this. | |
| 275 }; | |
| 276 | |
| 277 for (int i = 0; tests[i] != ""; i+= 2) { | |
| 278 std::string left = tests[i]; | |
| 279 std::string right = tests[i + 1]; | |
| 280 std::string js = BuildJSCondition(left, right); | |
| 281 CheckJavaScriptSuccess(js); | |
| 282 } | |
| 283 | |
| 284 std::string js = "example.my_value = 3.25; example.my_other_value = 1.25;"; | |
| 285 js.append(BuildJSCondition( | |
| 286 "example.plus(example.my_value, example.my_other_value)", "4.5")); | |
| 287 CheckJavaScriptSuccess(js); | |
| 288 } | |
| 289 | |
| 290 // Tests that invoking a nonexistent method with no fallback method stops the | |
| 291 // script's execution | |
| 292 TEST_F(CppBoundClassTest, | |
| 293 InvokeNonexistentMethodNoFallback) { | |
| 294 std::string js = "example.nonExistentMethod();document.writeln('SUCCESS');"; | |
| 295 CheckJavaScriptFailure(js); | |
| 296 } | |
| 297 | |
| 298 // Ensures existent methods can be invoked successfully when the fallback method | |
| 299 // is used | |
| 300 TEST_F(CppBoundClassWithFallbackMethodTest, | |
| 301 InvokeExistentMethodsWithFallback) { | |
| 302 std::string js = BuildJSCondition("example.echoValue(34)", "34"); | |
| 303 CheckJavaScriptSuccess(js); | |
| 304 } | |
| 305 | |
| 306 } // namespace | |
| OLD | NEW |