diff options
Diffstat (limited to 'chromium/content/renderer/cpp_bound_class_unittest.cc')
-rw-r--r-- | chromium/content/renderer/cpp_bound_class_unittest.cc | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/chromium/content/renderer/cpp_bound_class_unittest.cc b/chromium/content/renderer/cpp_bound_class_unittest.cc new file mode 100644 index 00000000000..2c0f75f881c --- /dev/null +++ b/chromium/content/renderer/cpp_bound_class_unittest.cc @@ -0,0 +1,241 @@ +// Copyright (c) 2012 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 "base/strings/utf_string_conversions.h" +#include "content/public/common/url_constants.h" +#include "content/public/renderer/render_view_observer.h" +#include "content/public/test/render_view_test.h" +#include "content/test/cpp_binding_example.h" +#include "third_party/WebKit/public/platform/WebURLRequest.h" +#include "third_party/WebKit/public/web/WebDocument.h" +#include "third_party/WebKit/public/web/WebElement.h" + +using webkit_glue::CppArgumentList; +using webkit_glue::CppVariant; + +namespace content { + +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) { + BindFallbackCallback(state ? + base::Bind(&CppBindingExampleWithOptionalFallback::fallbackMethod, + base::Unretained(this)) + : CppBoundClass::Callback()); + } + + // 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 TestObserver : public RenderViewObserver { + public: + explicit TestObserver(RenderView* render_view) + : RenderViewObserver(render_view) {} + virtual void DidClearWindowObject(WebKit::WebFrame* frame) OVERRIDE { + example_bound_class_.BindToJavascript(frame, "example"); + } + void set_fallback_method_enabled(bool use_fallback) { + example_bound_class_.set_fallback_method_enabled(use_fallback); + } + private: + CppBindingExampleWithOptionalFallback example_bound_class_; +}; + +} // namespace + +class CppBoundClassTest : public RenderViewTest { + public: + CppBoundClassTest() {} + + virtual void SetUp() OVERRIDE { + RenderViewTest::SetUp(); + observer_.reset(new TestObserver(view_)); + observer_->set_fallback_method_enabled(useFallback()); + + WebKit::WebURLRequest url_request; + url_request.initialize(); + url_request.setURL(GURL(kAboutBlankURL)); + + GetMainFrame()->loadRequest(url_request); + ProcessPendingMessages(); + } + + virtual void TearDown() OVERRIDE { + observer_.reset(); + RenderViewTest::TearDown(); + } + + // Executes the specified JavaScript and checks that the resulting document + // text is empty. + void CheckJavaScriptFailure(const std::string& javascript) { + ExecuteJavaScript(javascript.c_str()); + EXPECT_EQ( + "", + UTF16ToASCII(GetMainFrame()->document().documentElement().innerText())); + } + + void CheckTrue(const std::string& expression) { + int was_page_a = -1; + string16 check_page_a = + ASCIIToUTF16(std::string("Number(") + expression + ")"); + EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a, &was_page_a)); + EXPECT_EQ(1, was_page_a); + } + + protected: + virtual bool useFallback() { + return false; + } + + private: + scoped_ptr<TestObserver> observer_; +}; + +class CppBoundClassWithFallbackMethodTest : public CppBoundClassTest { + protected: + virtual bool useFallback() OVERRIDE { + return true; + } +}; + +// Ensures that the example object has been bound to JS. +TEST_F(CppBoundClassTest, ObjectExists) { + CheckTrue("typeof window.example == 'object'"); + + // An additional check to test our test. + CheckTrue("typeof window.invalid_object == 'undefined'"); +} + +TEST_F(CppBoundClassTest, PropertiesAreInitialized) { + CheckTrue("example.my_value == 10"); + + CheckTrue("example.my_other_value == 'Reinitialized!'"); +} + +TEST_F(CppBoundClassTest, SubOject) { + CheckTrue("typeof window.example.sub_object == 'object'"); + + CheckTrue("example.sub_object.sub_value == 'sub!'"); +} + +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(";"); + ExecuteJavaScript(js.c_str()); + std::string expression = left; + expression += " == "; + expression += right; + CheckTrue(expression); + } +} + +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. + ExecuteJavaScript("example.my_value_with_callback = 10;"); + CheckTrue("example.my_value_with_callback == 10"); + + ExecuteJavaScript("example.my_value_with_callback = 11;"); + CheckTrue("example.my_value_with_callback == 11"); + + CheckTrue("example.same == 42"); + + ExecuteJavaScript("example.same = 24;"); + CheckTrue("example.same == 42"); +} + +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) == 3.14159", + "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++) + CheckTrue(tests[i]); + + ExecuteJavaScript("example.my_value = 3.25; example.my_other_value = 1.25;"); + CheckTrue("example.plus(example.my_value, example.my_other_value) == 4.5"); +} + +// 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) { + CheckTrue("example.echoValue(34) == 34"); +} + +} // namespace content |