blob: b3a43bc790079a87da9bc2a6cd47826fff1415fe [file] [log] [blame]
// Copyright 2016 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "base/optional.h"
#include "cobalt/bindings/testing/bindings_test_base.h"
#include "cobalt/bindings/testing/callback_interface_interface.h"
#include "cobalt/bindings/testing/script_object_owner.h"
#include "cobalt/bindings/testing/single_operation_interface.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
using ::testing::ContainsRegex;
using ::testing::Invoke;
using ::testing::Return;
namespace cobalt {
namespace bindings {
namespace testing {
namespace {
class CallbackInterfaceTest
: public InterfaceBindingsTest<CallbackInterfaceInterface> {
public:
typedef ScriptObjectOwner<script::ScriptValue<SingleOperationInterface> >
InterfaceOwner;
CallbackInterfaceTest()
: callback_arg_(new ArbitraryInterface()), had_exception_(true) {}
protected:
// The argument that will be passed to the CallbackInterface's function.
scoped_refptr<ArbitraryInterface> callback_arg_;
bool had_exception_;
};
} // namespace
TEST_F(CallbackInterfaceTest, ObjectCanImplementInterface) {
std::string result;
InterfaceOwner interface_owner(&test_mock());
EXPECT_CALL(test_mock(), RegisterCallback(_))
.WillOnce(Invoke(&interface_owner, &InterfaceOwner::TakeOwnership));
// Register an object that implements the callback interface.
EXPECT_TRUE(
EvaluateScript("var someFunction = function(arg) { "
" this.someOperation();"
" arg.arbitraryFunction();"
" return 7;"
"};"
"var implementer = {};"
"test.registerCallback(implementer);"));
ASSERT_TRUE(interface_owner.IsSet());
// Try executing the callback. There should be a TypeError because there is no
// "handleCallback" property set.
interface_owner.reference().value().HandleCallback(test_mock_, callback_arg_,
&had_exception_);
EXPECT_TRUE(had_exception_);
// Set the "handleCallback" property.
EXPECT_TRUE(EvaluateScript("implementer.handleCallback = someFunction;"));
// Execute the callback.
EXPECT_CALL(*callback_arg_, ArbitraryFunction());
EXPECT_CALL(test_mock(), SomeOperation());
had_exception_ = true;
base::Optional<int32_t> return_value =
interface_owner.reference().value().HandleCallback(
test_mock_, callback_arg_, &had_exception_);
EXPECT_FALSE(had_exception_);
EXPECT_EQ(7, return_value);
}
TEST_F(CallbackInterfaceTest, FunctionCanImplementInterface) {
std::string result;
InterfaceOwner interface_owner(&test_mock());
EXPECT_CALL(test_mock(), RegisterCallback(_))
.WillOnce(Invoke(&interface_owner, &InterfaceOwner::TakeOwnership));
// Register a function for the callback interface.
EXPECT_TRUE(
EvaluateScript("var someFunction = function(arg) { "
" this.someOperation();"
" arg.arbitraryFunction();"
" return 7;"
"};"
"test.registerCallback(someFunction);"));
ASSERT_TRUE(interface_owner.IsSet());
// Execute the callback.
EXPECT_CALL(*callback_arg_, ArbitraryFunction());
EXPECT_CALL(test_mock(), SomeOperation());
had_exception_ = true;
base::Optional<int32_t> return_value =
interface_owner.reference().value().HandleCallback(
test_mock_, callback_arg_, &had_exception_);
EXPECT_FALSE(had_exception_);
ASSERT_TRUE(return_value);
EXPECT_EQ(7, *return_value);
}
TEST_F(CallbackInterfaceTest, PropertyOnObjectIsNotCallable) {
std::string result;
InterfaceOwner interface_owner(&test_mock());
EXPECT_CALL(test_mock(), RegisterCallback(_))
.WillOnce(Invoke(&interface_owner, &InterfaceOwner::TakeOwnership));
// Define an object that has the correct property, but the property value is
// not callable.
EXPECT_TRUE(
EvaluateScript("var implementer = {};"
"implementer.handleCallback = 45;"
"test.registerCallback(implementer);"));
ASSERT_TRUE(interface_owner.IsSet());
// Execute the callback. Callback should not have been fired.
had_exception_ = false;
interface_owner.reference().value().HandleCallback(test_mock_, callback_arg_,
&had_exception_);
EXPECT_TRUE(had_exception_);
}
TEST_F(CallbackInterfaceTest, ObjectThatDoesNotImplementInterface) {
std::string result;
InterfaceOwner interface_owner(&test_mock());
EXPECT_CALL(test_mock(), RegisterCallback(_))
.WillOnce(Invoke(&interface_owner, &InterfaceOwner::TakeOwnership));
// Set a function to the wrong property name on an object.
EXPECT_TRUE(
EvaluateScript("var someFunction = function(arg) { "
" this.someOperation();"
" arg.arbitraryFunction();"
"};"
"var implementer = {};"
"implementer.wrongOne = someFunction;"
"test.registerCallback(implementer);"));
ASSERT_TRUE(interface_owner.IsSet());
// Execute the callback. Callback should not have been fired.
had_exception_ = false;
interface_owner.reference().value().HandleCallback(test_mock_, callback_arg_,
&had_exception_);
EXPECT_TRUE(had_exception_);
}
TEST_F(CallbackInterfaceTest, NotAnObjectOrFunction) {
// TypeError should occur.
std::string result;
EXPECT_FALSE(EvaluateScript("test.registerCallback(\"foo\");", &result));
EXPECT_THAT(result.c_str(), ContainsRegex("TypeError:"));
}
TEST_F(CallbackInterfaceTest, ExceptionInCallback) {
std::string result;
InterfaceOwner interface_owner(&test_mock());
EXPECT_CALL(test_mock(), RegisterCallback(_))
.WillOnce(Invoke(&interface_owner, &InterfaceOwner::TakeOwnership));
// Set up a function that will throw an exception and pass it as a callback
// interface.
EXPECT_TRUE(
EvaluateScript("var someFunction = function(arg) { "
" arg.arbitraryFunction();"
" throw \"SomeException\";"
"};"
"test.registerCallback(someFunction);"));
ASSERT_TRUE(interface_owner.IsSet());
// Execute the callback. Callback should be fired but exception occurs.
EXPECT_CALL(*callback_arg_, ArbitraryFunction());
bool had_exception = true;
interface_owner.reference().value().HandleCallback(test_mock_, callback_arg_,
&had_exception);
EXPECT_TRUE(had_exception);
}
TEST_F(CallbackInterfaceTest, FunctionsAreEqual) {
std::string result;
InterfaceOwner interface_owner_first(&test_mock());
InterfaceOwner interface_owner_second(&test_mock());
EXPECT_CALL(test_mock(), RegisterCallback(_))
.Times(2)
.WillOnce(Invoke(&interface_owner_first, &InterfaceOwner::TakeOwnership))
.WillOnce(
Invoke(&interface_owner_second, &InterfaceOwner::TakeOwnership));
EXPECT_TRUE(
EvaluateScript("var someFunction = function(arg) { };"
"test.registerCallback(someFunction);"
"test.registerCallback(someFunction);"));
ASSERT_TRUE(interface_owner_first.IsSet());
ASSERT_TRUE(interface_owner_second.IsSet());
EXPECT_TRUE(interface_owner_first.reference().referenced_value().EqualTo(
interface_owner_second.reference().referenced_value()));
}
TEST_F(CallbackInterfaceTest, FunctionsAreNotEqual) {
std::string result;
InterfaceOwner interface_owner_first(&test_mock());
InterfaceOwner interface_owner_second(&test_mock());
EXPECT_CALL(test_mock(), RegisterCallback(_))
.Times(2)
.WillOnce(Invoke(&interface_owner_first, &InterfaceOwner::TakeOwnership))
.WillOnce(
Invoke(&interface_owner_second, &InterfaceOwner::TakeOwnership));
EXPECT_TRUE(
EvaluateScript("var someFunction = function(arg) { };"
"var someOtherFunction = function(arg) { };"
"test.registerCallback(someFunction);"
"test.registerCallback(someOtherFunction);"));
ASSERT_TRUE(interface_owner_first.IsSet());
ASSERT_TRUE(interface_owner_second.IsSet());
EXPECT_FALSE(interface_owner_first.reference().referenced_value().EqualTo(
interface_owner_second.reference().referenced_value()));
}
TEST_F(CallbackInterfaceTest, ObjectsAreEqual) {
std::string result;
InterfaceOwner interface_owner_first(&test_mock());
InterfaceOwner interface_owner_second(&test_mock());
EXPECT_CALL(test_mock(), RegisterCallback(_))
.Times(2)
.WillOnce(Invoke(&interface_owner_first, &InterfaceOwner::TakeOwnership))
.WillOnce(
Invoke(&interface_owner_second, &InterfaceOwner::TakeOwnership));
EXPECT_TRUE(
EvaluateScript("var someObject = { };"
"test.registerCallback(someObject);"
"test.registerCallback(someObject);"));
ASSERT_TRUE(interface_owner_first.IsSet());
ASSERT_TRUE(interface_owner_second.IsSet());
EXPECT_TRUE(interface_owner_first.reference().referenced_value().EqualTo(
interface_owner_second.reference().referenced_value()));
}
TEST_F(CallbackInterfaceTest, ObjectsAreNotEqual) {
std::string result;
InterfaceOwner interface_owner_first(&test_mock());
InterfaceOwner interface_owner_second(&test_mock());
EXPECT_CALL(test_mock(), RegisterCallback(_))
.Times(2)
.WillOnce(Invoke(&interface_owner_first, &InterfaceOwner::TakeOwnership))
.WillOnce(
Invoke(&interface_owner_second, &InterfaceOwner::TakeOwnership));
EXPECT_TRUE(
EvaluateScript("var someObject = { };"
"var someOtherObject = { };"
"test.registerCallback(someObject);"
"test.registerCallback(someOtherObject);"));
ASSERT_TRUE(interface_owner_first.IsSet());
ASSERT_TRUE(interface_owner_second.IsSet());
EXPECT_FALSE(interface_owner_first.reference().referenced_value().EqualTo(
interface_owner_second.reference().referenced_value()));
}
TEST_F(CallbackInterfaceTest, GetAndSetAttribute) {
std::string result;
InterfaceOwner interface_owner(&test_mock());
EXPECT_CALL(test_mock(), set_callback_attribute(_))
.WillOnce(Invoke(&interface_owner, &InterfaceOwner::TakeOwnership));
// Set the attribute.
EXPECT_TRUE(
EvaluateScript("var implementer = {};"
"test.callbackAttribute = implementer;"));
ASSERT_TRUE(interface_owner.IsSet());
// Get the attribute value and check that it's equal.
EXPECT_CALL(test_mock(), callback_attribute())
.WillOnce(Return(&interface_owner.reference().referenced_value()));
EXPECT_TRUE(
EvaluateScript("test.callbackAttribute === implementer;", &result));
EXPECT_STREQ("true", result.c_str());
}
} // namespace testing
} // namespace bindings
} // namespace cobalt