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 |