diff options
author | Ben Murdoch <benm@google.com> | 2010-07-29 17:14:53 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2010-08-04 14:29:45 +0100 |
commit | c407dc5cd9bdc5668497f21b26b09d988ab439de (patch) | |
tree | 7eaf8707c0309516bdb042ad976feedaf72b0bb1 /webkit/glue/cpp_bound_class_unittest.cc | |
parent | 0998b1cdac5733f299c12d88bc31ef9c8035b8fa (diff) | |
download | external_chromium-c407dc5cd9bdc5668497f21b26b09d988ab439de.zip external_chromium-c407dc5cd9bdc5668497f21b26b09d988ab439de.tar.gz external_chromium-c407dc5cd9bdc5668497f21b26b09d988ab439de.tar.bz2 |
Merge Chromium src@r53293
Change-Id: Ia79acf8670f385cee48c45b0a75371d8e950af34
Diffstat (limited to 'webkit/glue/cpp_bound_class_unittest.cc')
-rw-r--r-- | webkit/glue/cpp_bound_class_unittest.cc | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/webkit/glue/cpp_bound_class_unittest.cc b/webkit/glue/cpp_bound_class_unittest.cc new file mode 100644 index 0000000..71a56e6 --- /dev/null +++ b/webkit/glue/cpp_bound_class_unittest.cc @@ -0,0 +1,288 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Tests for CppBoundClass, in conjunction with CppBindingExample. Binds +// a CppBindingExample class into JavaScript in a custom test shell and tests +// the binding from the outside by loading JS into the shell. + +#include <vector> + +#include "base/message_loop.h" +#include "third_party/WebKit/WebKit/chromium/public/WebData.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURL.h" +#include "third_party/WebKit/WebKit/chromium/public/WebView.h" +#include "webkit/glue/cpp_binding_example.h" +#include "webkit/glue/webkit_glue.h" +#include "webkit/tools/test_shell/test_shell_test.h" + +using WebKit::WebFrame; + +namespace { + +class CppBindingExampleSubObject : public CppBindingExample { + public: + CppBindingExampleSubObject() { + sub_value_.Set("sub!"); + BindProperty("sub_value", &sub_value_); + } + private: + CppVariant sub_value_; +}; + + +class CppBindingExampleWithOptionalFallback : public CppBindingExample { + public: + CppBindingExampleWithOptionalFallback() { + BindProperty("sub_object", sub_object_.GetAsCppVariant()); + } + + void set_fallback_method_enabled(bool state) { + BindFallbackMethod(state ? + &CppBindingExampleWithOptionalFallback::fallbackMethod + : NULL); + } + + // The fallback method does nothing, but because of it the JavaScript keeps + // running when a nonexistent method is called on an object. + void fallbackMethod(const CppArgumentList& args, CppVariant* result) { + } + + private: + CppBindingExampleSubObject sub_object_; +}; + +class ExampleTestShell : public TestShell { + public: + + ExampleTestShell(bool use_fallback_method) { + example_bound_class_.set_fallback_method_enabled(use_fallback_method); + } + + // When called by WebViewDelegate::WindowObjectCleared method, this binds a + // CppExampleObject to window.example. + virtual void BindJSObjectsToWindow(WebFrame* frame) { + example_bound_class_.BindToJavascript(frame, L"example"); + // We use the layoutTestController binding for notifyDone. + TestShell::BindJSObjectsToWindow(frame); + } + + // This is a public interface to TestShell's protected method, so it + // can be called by our CreateEmptyWindow. + bool PublicInitialize(const std::string& starting_url) { + return Initialize(GURL(starting_url)); + } + + CppBindingExampleWithOptionalFallback example_bound_class_; +}; + +class CppBoundClassTest : public TestShellTest { + protected: + // Adapted from TestShell::CreateNewWindow, this creates an + // ExampleTestShellWindow rather than a regular TestShell. + virtual void CreateEmptyWindow() { + ExampleTestShell* host = new ExampleTestShell(useFallback()); + ASSERT_TRUE(host != NULL); + bool rv = host->PublicInitialize("about:blank"); + if (rv) { + test_shell_ = host; + TestShell::windowList()->push_back(host->mainWnd()); + webframe_ = test_shell_->webView()->mainFrame(); + ASSERT_TRUE(webframe_ != NULL); + } else { + delete host; + } + } + + // Wraps the given JavaScript snippet in <html><body><script> tags, then + // loads it into a webframe so it is executed. + void ExecuteJavaScript(const std::string& javascript) { + std::string html = "<html><body>"; + html.append(TestShellTest::kJavascriptDelayExitScript); + html.append("<script>"); + html.append(javascript); + html.append("</script></body></html>"); + // The base URL doesn't matter. + webframe_->loadHTMLString(html, GURL("about:blank")); + + test_shell_->WaitTestFinished(); + } + + // Executes the specified JavaScript and checks to be sure that the resulting + // document text is exactly "SUCCESS". + void CheckJavaScriptSuccess(const std::string& javascript) { + ExecuteJavaScript(javascript); + EXPECT_EQ(L"SUCCESS", webkit_glue::DumpDocumentText(webframe_)); + } + + // Executes the specified JavaScript and checks that the resulting document + // text is empty. + void CheckJavaScriptFailure(const std::string& javascript) { + ExecuteJavaScript(javascript); + EXPECT_EQ(L"", webkit_glue::DumpDocumentText(webframe_)); + } + + // Constructs a JavaScript snippet that evaluates and compares the left and + // right expressions, printing "SUCCESS" to the page if they are equal and + // printing their actual values if they are not. Any strings in the + // expressions should be enclosed in single quotes, and no double quotes + // should appear in either expression (even if escaped). (If a test case + // is added that needs fancier quoting, Json::valueToQuotedString could be + // used here. For now, it's not worth adding the dependency.) + std::string BuildJSCondition(std::string left, std::string right) { + return "var leftval = " + left + ";" + + "var rightval = " + right + ";" + + "if (leftval == rightval) {" + + " document.writeln('SUCCESS');" + + "} else {" + + " document.writeln(\"" + + left + " [\" + leftval + \"] != " + + right + " [\" + rightval + \"]\");" + + "}"; + } + +protected: + virtual bool useFallback() { + return false; + } + +private: + WebFrame* webframe_; +}; + +class CppBoundClassWithFallbackMethodTest : public CppBoundClassTest { +protected: + virtual bool useFallback() { + return true; + } +}; + +// Ensures that the example object has been bound to JS. +TEST_F(CppBoundClassTest, ObjectExists) { + std::string js = BuildJSCondition("typeof window.example", "'object'"); + CheckJavaScriptSuccess(js); + + // An additional check to test our test. + js = BuildJSCondition("typeof window.invalid_object", "'undefined'"); + CheckJavaScriptSuccess(js); +} + +TEST_F(CppBoundClassTest, PropertiesAreInitialized) { + std::string js = BuildJSCondition("example.my_value", "10"); + CheckJavaScriptSuccess(js); + + js = BuildJSCondition("example.my_other_value", "'Reinitialized!'"); + CheckJavaScriptSuccess(js); +} + +TEST_F(CppBoundClassTest, SubOject) { + std::string js = BuildJSCondition("typeof window.example.sub_object", + "'object'"); + CheckJavaScriptSuccess(js); + + js = BuildJSCondition("example.sub_object.sub_value", "'sub!'"); + CheckJavaScriptSuccess(js); +} + +TEST_F(CppBoundClassTest, SetAndGetProperties) { + // The property on the left will be set to the value on the right, then + // checked to make sure it holds that same value. + static const std::string tests[] = { + "example.my_value", "7", + "example.my_value", "'test'", + "example.my_other_value", "3.14", + "example.my_other_value", "false", + "" // Array end marker: insert additional test pairs before this. + }; + + for (int i = 0; tests[i] != ""; i += 2) { + std::string left = tests[i]; + std::string right = tests[i + 1]; + // left = right; + std::string js = left; + js.append(" = "); + js.append(right); + js.append(";"); + js.append(BuildJSCondition(left, right)); + CheckJavaScriptSuccess(js); + } +} + +TEST_F(CppBoundClassTest, SetAndGetPropertiesWithCallbacks) { + // TODO(dglazkov): fix NPObject issues around failing property setters and + // getters and add tests for situations when GetProperty or SetProperty fail. + std::string js = "var result = 'SUCCESS';\n" + "example.my_value_with_callback = 10;\n" + "if (example.my_value_with_callback != 10)\n" + " result = 'FAIL: unable to set property.';\n" + "example.my_value_with_callback = 11;\n" + "if (example.my_value_with_callback != 11)\n" + " result = 'FAIL: unable to set property again';\n" + "if (example.same != 42)\n" + " result = 'FAIL: same property should always be 42';\n" + "example.same = 24;\n" + "if (example.same != 42)\n" + " result = 'FAIL: same property should always be 42';\n" + "document.writeln(result);\n"; + CheckJavaScriptSuccess(js); +} + +TEST_F(CppBoundClassTest, InvokeMethods) { + // The expression on the left is expected to return the value on the right. + static const std::string tests[] = { + "example.echoValue(true)", "true", + "example.echoValue(13)", "13", + "example.echoValue(2.718)", "2.718", + "example.echoValue('yes')", "'yes'", + "example.echoValue()", "null", // Too few arguments + + "example.echoType(false)", "true", + "example.echoType(19)", "7", + "example.echoType(9.876)", "3.14159", + "example.echoType('test string')", "'Success!'", + "example.echoType()", "null", // Too few arguments + + // Comparing floats that aren't integer-valued is usually problematic due + // to rounding, but exact powers of 2 should also be safe. + "example.plus(2.5, 18.0)", "20.5", + "example.plus(2, 3.25)", "5.25", + "example.plus(2, 3)", "5", + "example.plus()", "null", // Too few arguments + "example.plus(1)", "null", // Too few arguments + "example.plus(1, 'test')", "null", // Wrong argument type + "example.plus('test', 2)", "null", // Wrong argument type + "example.plus('one', 'two')", "null", // Wrong argument type + "" // Array end marker: insert additional test pairs before this. + }; + + for (int i = 0; tests[i] != ""; i+= 2) { + std::string left = tests[i]; + std::string right = tests[i + 1]; + std::string js = BuildJSCondition(left, right); + CheckJavaScriptSuccess(js); + } + + std::string js = "example.my_value = 3.25; example.my_other_value = 1.25;"; + js.append(BuildJSCondition( + "example.plus(example.my_value, example.my_other_value)", "4.5")); + CheckJavaScriptSuccess(js); +} + +// Tests that invoking a nonexistent method with no fallback method stops the +// script's execution +TEST_F(CppBoundClassTest, + InvokeNonexistentMethodNoFallback) { + std::string js = "example.nonExistentMethod();document.writeln('SUCCESS');"; + CheckJavaScriptFailure(js); +} + +// Ensures existent methods can be invoked successfully when the fallback method +// is used +TEST_F(CppBoundClassWithFallbackMethodTest, + InvokeExistentMethodsWithFallback) { + std::string js = BuildJSCondition("example.echoValue(34)", "34"); + CheckJavaScriptSuccess(js); +} + +} // namespace |