| Index: extensions/renderer/api_bindings_system_unittest.cc
|
| diff --git a/extensions/renderer/api_bindings_system_unittest.cc b/extensions/renderer/api_bindings_system_unittest.cc
|
| index 3e43733ffc869cf75438b59ea3640be03c7193f8..83caeb2806ae3921c2edc9448276bda3d4975b82 100644
|
| --- a/extensions/renderer/api_bindings_system_unittest.cc
|
| +++ b/extensions/renderer/api_bindings_system_unittest.cc
|
| @@ -35,6 +35,10 @@ const char kAlphaAPISpec[] =
|
| " 'prop1': {'type': 'string'},"
|
| " 'prop2': {'type': 'integer', 'optional': true}"
|
| " }"
|
| + " }, {"
|
| + " 'id': 'alpha.enumRef',"
|
| + " 'type': 'string',"
|
| + " 'enum': ['cat', 'dog']"
|
| " }],"
|
| " 'functions': [{"
|
| " 'name': 'functionWithCallback',"
|
| @@ -54,6 +58,9 @@ const char kAlphaAPISpec[] =
|
| " 'name': 'callback',"
|
| " 'type': 'function'"
|
| " }]"
|
| + " }, {"
|
| + " 'name': 'functionWithEnum',"
|
| + " 'parameters': [{'name': 'e', '$ref': 'alpha.enumRef'}]"
|
| " }],"
|
| " 'events': [{"
|
| " 'name': 'alphaEvent'"
|
| @@ -87,12 +94,14 @@ bool AllowAllAPIs(const std::string& name) {
|
|
|
| // The base class to test the APIBindingsSystem. This allows subclasses to
|
| // retrieve API schemas differently.
|
| -class APIBindingsSystemTestBase : public APIBindingTest {
|
| +class APIBindingsSystemTest : public APIBindingTest {
|
| public:
|
| // Returns the DictionaryValue representing the schema with the given API
|
| // name.
|
| - virtual const base::DictionaryValue& GetAPISchema(
|
| - const std::string& api_name) = 0;
|
| + const base::DictionaryValue& GetAPISchema(const std::string& api_name) {
|
| + EXPECT_TRUE(base::ContainsKey(api_schemas_, api_name));
|
| + return *api_schemas_[api_name];
|
| + }
|
|
|
| // Stores the request in |last_request_|.
|
| void OnAPIRequest(std::unique_ptr<APIRequestHandler::Request> request,
|
| @@ -106,17 +115,36 @@ class APIBindingsSystemTestBase : public APIBindingTest {
|
| v8::Local<v8::Context> context) {}
|
|
|
| protected:
|
| - APIBindingsSystemTestBase() {}
|
| + APIBindingsSystemTest() {}
|
| void SetUp() override {
|
| APIBindingTest::SetUp();
|
| +
|
| + // Create the fake API schemas.
|
| + {
|
| + struct APIData {
|
| + const char* name;
|
| + const char* spec;
|
| + } api_data[] = {
|
| + {kAlphaAPIName, kAlphaAPISpec},
|
| + {kBetaAPIName, kBetaAPISpec},
|
| + {kGammaAPIName, kGammaAPISpec},
|
| + };
|
| + for (const auto& api : api_data) {
|
| + std::unique_ptr<base::DictionaryValue> api_schema =
|
| + DictionaryValueFromString(api.spec);
|
| + ASSERT_TRUE(api_schema);
|
| + api_schemas_[api.name] = std::move(api_schema);
|
| + }
|
| + }
|
| +
|
| bindings_system_ = base::MakeUnique<APIBindingsSystem>(
|
| base::Bind(&RunFunctionOnGlobalAndIgnoreResult),
|
| base::Bind(&RunFunctionOnGlobalAndReturnHandle),
|
| - base::Bind(&APIBindingsSystemTestBase::GetAPISchema,
|
| + base::Bind(&APIBindingsSystemTest::GetAPISchema,
|
| base::Unretained(this)),
|
| - base::Bind(&APIBindingsSystemTestBase::OnAPIRequest,
|
| + base::Bind(&APIBindingsSystemTest::OnAPIRequest,
|
| base::Unretained(this)),
|
| - base::Bind(&APIBindingsSystemTestBase::OnEventListenersChanged,
|
| + base::Bind(&APIBindingsSystemTest::OnEventListenersChanged,
|
| base::Unretained(this)),
|
| APILastError(APILastError::GetParent()));
|
| }
|
| @@ -135,7 +163,29 @@ class APIBindingsSystemTestBase : public APIBindingTest {
|
| // Checks that |last_request_| exists and was provided with the
|
| // |expected_name| and |expected_arguments|.
|
| void ValidateLastRequest(const std::string& expected_name,
|
| - const std::string& expected_arguments);
|
| + const std::string& expected_arguments) {
|
| + ASSERT_TRUE(last_request());
|
| + // Note that even if no arguments are provided by the API call, we should
|
| + // have an empty list.
|
| + ASSERT_TRUE(last_request()->arguments);
|
| + EXPECT_EQ(expected_name, last_request()->method_name);
|
| + EXPECT_EQ(ReplaceSingleQuotes(expected_arguments),
|
| + ValueToString(*last_request()->arguments));
|
| + }
|
| +
|
| + void CallFunctionOnObject(v8::Local<v8::Context> context,
|
| + v8::Local<v8::Object> object,
|
| + const std::string& script_source) {
|
| + std::string wrapped_script_source =
|
| + base::StringPrintf("(function(obj) { %s })", script_source.c_str());
|
| +
|
| + v8::Local<v8::Function> func =
|
| + FunctionFromString(context, wrapped_script_source);
|
| + ASSERT_FALSE(func.IsEmpty());
|
| +
|
| + v8::Local<v8::Value> argv[] = {object};
|
| + RunFunction(func, context, 1, argv);
|
| + }
|
|
|
| const APIRequestHandler::Request* last_request() const {
|
| return last_request_.get();
|
| @@ -144,6 +194,9 @@ class APIBindingsSystemTestBase : public APIBindingTest {
|
| APIBindingsSystem* bindings_system() { return bindings_system_.get(); }
|
|
|
| private:
|
| + // The API schemas for the fake APIs.
|
| + std::map<std::string, std::unique_ptr<base::DictionaryValue>> api_schemas_;
|
| +
|
| // The APIBindingsSystem associated with the test. Safe to use across multiple
|
| // contexts.
|
| std::unique_ptr<APIBindingsSystem> bindings_system_;
|
| @@ -152,82 +205,9 @@ class APIBindingsSystemTestBase : public APIBindingTest {
|
| // there is none.
|
| std::unique_ptr<APIRequestHandler::Request> last_request_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(APIBindingsSystemTestBase);
|
| -};
|
| -
|
| -void APIBindingsSystemTestBase::ValidateLastRequest(
|
| - const std::string& expected_name,
|
| - const std::string& expected_arguments) {
|
| - ASSERT_TRUE(last_request());
|
| - // Note that even if no arguments are provided by the API call, we should have
|
| - // an empty list.
|
| - ASSERT_TRUE(last_request()->arguments);
|
| - EXPECT_EQ(expected_name, last_request()->method_name);
|
| - EXPECT_EQ(ReplaceSingleQuotes(expected_arguments),
|
| - ValueToString(*last_request()->arguments));
|
| -}
|
| -
|
| -// An implementation that works with fake/supplied APIs, for easy testability.
|
| -class APIBindingsSystemTest : public APIBindingsSystemTestBase {
|
| - protected:
|
| - APIBindingsSystemTest() {}
|
| -
|
| - // Calls a function constructed from |script_source| on the given |object|.
|
| - void CallFunctionOnObject(v8::Local<v8::Context> context,
|
| - v8::Local<v8::Object> object,
|
| - const std::string& script_source);
|
| -
|
| - private:
|
| - const base::DictionaryValue& GetAPISchema(
|
| - const std::string& api_name) override {
|
| - EXPECT_TRUE(base::ContainsKey(api_schemas_, api_name));
|
| - return *api_schemas_[api_name];
|
| - }
|
| - void SetUp() override;
|
| -
|
| - // The API schemas for the fake APIs.
|
| - std::map<std::string, std::unique_ptr<base::DictionaryValue>> api_schemas_;
|
| -
|
| DISALLOW_COPY_AND_ASSIGN(APIBindingsSystemTest);
|
| };
|
|
|
| -void APIBindingsSystemTest::CallFunctionOnObject(
|
| - v8::Local<v8::Context> context,
|
| - v8::Local<v8::Object> object,
|
| - const std::string& script_source) {
|
| - std::string wrapped_script_source =
|
| - base::StringPrintf("(function(obj) { %s })", script_source.c_str());
|
| -
|
| - v8::Local<v8::Function> func =
|
| - FunctionFromString(context, wrapped_script_source);
|
| - ASSERT_FALSE(func.IsEmpty());
|
| -
|
| - v8::Local<v8::Value> argv[] = {object};
|
| - RunFunction(func, context, 1, argv);
|
| -}
|
| -
|
| -void APIBindingsSystemTest::SetUp() {
|
| - // Create the fake API schemas.
|
| - {
|
| - struct APIData {
|
| - const char* name;
|
| - const char* spec;
|
| - } api_data[] = {
|
| - {kAlphaAPIName, kAlphaAPISpec},
|
| - {kBetaAPIName, kBetaAPISpec},
|
| - {kGammaAPIName, kGammaAPISpec},
|
| - };
|
| - for (const auto& api : api_data) {
|
| - std::unique_ptr<base::DictionaryValue> api_schema =
|
| - DictionaryValueFromString(api.spec);
|
| - ASSERT_TRUE(api_schema);
|
| - api_schemas_[api.name] = std::move(api_schema);
|
| - }
|
| - }
|
| -
|
| - APIBindingsSystemTestBase::SetUp();
|
| -}
|
| -
|
| // Tests API object initialization, calling a method on the supplied APIs, and
|
| // triggering the callback for the request.
|
| TEST_F(APIBindingsSystemTest, TestInitializationAndCallbacks) {
|
| @@ -285,6 +265,18 @@ TEST_F(APIBindingsSystemTest, TestInitializationAndCallbacks) {
|
| }
|
|
|
| {
|
| + // Test an invalid invocation -> throwing error.
|
| + const char kTestCall[] =
|
| + "(function(obj) { obj.functionWithEnum('mouse') })";
|
| + v8::Local<v8::Function> function = FunctionFromString(context, kTestCall);
|
| + v8::Local<v8::Value> args[] = {alpha_api};
|
| + RunFunctionAndExpectError(function, context, arraysize(args), args,
|
| + "Uncaught TypeError: Invalid invocation");
|
| + EXPECT_FALSE(last_request());
|
| + reset_last_request(); // Just to not pollute future results.
|
| + }
|
| +
|
| + {
|
| // Test an event registration -> event occurrence.
|
| const char kTestCall[] =
|
| "obj.alphaEvent.addListener(function() {\n"
|
| @@ -445,153 +437,4 @@ TEST_F(APIBindingsSystemTest, CrossAPIReferences) {
|
| }
|
| }
|
|
|
| -// An implementation using real API schemas.
|
| -class APIBindingsSystemTestWithRealAPI : public APIBindingsSystemTestBase {
|
| - protected:
|
| - APIBindingsSystemTestWithRealAPI() {}
|
| -
|
| - // Executes the given |script_source| in |context|, expecting no exceptions.
|
| - void ExecuteScript(v8::Local<v8::Context> context,
|
| - const std::string& script_source);
|
| -
|
| - // Executes the given |script_source| in |context| and compares a caught
|
| - // error to |expected_error|.
|
| - void ExecuteScriptAndExpectError(v8::Local<v8::Context> context,
|
| - const std::string& script_source,
|
| - const std::string& expected_error);
|
| -
|
| - private:
|
| - const base::DictionaryValue& GetAPISchema(
|
| - const std::string& api_name) override {
|
| - const base::DictionaryValue* schema =
|
| - ExtensionAPI::GetSharedInstance()->GetSchema(api_name);
|
| - EXPECT_TRUE(schema);
|
| - return *schema;
|
| - }
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(APIBindingsSystemTestWithRealAPI);
|
| -};
|
| -
|
| -void APIBindingsSystemTestWithRealAPI::ExecuteScript(
|
| - v8::Local<v8::Context> context,
|
| - const std::string& script_source) {
|
| - v8::TryCatch try_catch(isolate());
|
| - // V8ValueFromScriptSource runs the source and returns the result; here, we
|
| - // only care about running the source.
|
| - V8ValueFromScriptSource(context, script_source);
|
| - EXPECT_FALSE(try_catch.HasCaught())
|
| - << gin::V8ToString(try_catch.Message()->Get());
|
| -}
|
| -
|
| -void APIBindingsSystemTestWithRealAPI::ExecuteScriptAndExpectError(
|
| - v8::Local<v8::Context> context,
|
| - const std::string& script_source,
|
| - const std::string& expected_error) {
|
| - v8::TryCatch try_catch(isolate());
|
| - V8ValueFromScriptSource(context, script_source);
|
| - ASSERT_TRUE(try_catch.HasCaught()) << script_source;
|
| - EXPECT_EQ(expected_error, gin::V8ToString(try_catch.Message()->Get()));
|
| -}
|
| -
|
| -// The following test demonstrates how APIBindingsSystem can be used with "real"
|
| -// Extension APIs; that is, using the raw Extension API schemas, rather than a
|
| -// substituted test schema. This is useful to both show how the system is
|
| -// intended to be used in the future as well as to make sure that it works with
|
| -// actual APIs.
|
| -TEST_F(APIBindingsSystemTestWithRealAPI, RealAPIs) {
|
| - v8::HandleScope handle_scope(isolate());
|
| - v8::Local<v8::Context> context = MainContext();
|
| -
|
| - v8::Local<v8::Object> chrome = v8::Object::New(isolate());
|
| - {
|
| - v8::Maybe<bool> res = context->Global()->Set(
|
| - context, gin::StringToV8(isolate(), "chrome"), chrome);
|
| - ASSERT_TRUE(res.IsJust());
|
| - ASSERT_TRUE(res.FromJust());
|
| - }
|
| -
|
| - auto add_api_to_chrome = [this, &chrome,
|
| - &context](const std::string& api_name) {
|
| - v8::Local<v8::Object> api = bindings_system()->CreateAPIInstance(
|
| - api_name, context, context->GetIsolate(), base::Bind(&AllowAllAPIs),
|
| - nullptr);
|
| - ASSERT_FALSE(api.IsEmpty()) << api_name;
|
| - v8::Maybe<bool> res = chrome->Set(
|
| - context, gin::StringToV8(context->GetIsolate(), api_name), api);
|
| - ASSERT_TRUE(res.IsJust());
|
| - ASSERT_TRUE(res.FromJust());
|
| - };
|
| -
|
| - // Pick two relatively small APIs that don't have any custom bindings (which
|
| - // aren't supported yet).
|
| - add_api_to_chrome("idle");
|
| - add_api_to_chrome("power");
|
| -
|
| - // Test passing methods.
|
| - {
|
| - const char kTestCall[] = "chrome.power.requestKeepAwake('display');";
|
| - ExecuteScript(context, kTestCall);
|
| - ValidateLastRequest("power.requestKeepAwake", "['display']");
|
| - EXPECT_EQ(-1, last_request()->request_id);
|
| - reset_last_request();
|
| - }
|
| -
|
| - {
|
| - const char kTestCall[] = "chrome.power.releaseKeepAwake()";
|
| - ExecuteScript(context, kTestCall);
|
| - ValidateLastRequest("power.releaseKeepAwake", "[]");
|
| - EXPECT_EQ(-1, last_request()->request_id);
|
| - reset_last_request();
|
| - }
|
| -
|
| - {
|
| - const char kTestCall[] = "chrome.idle.queryState(30, function() {})";
|
| - ExecuteScript(context, kTestCall);
|
| - ValidateLastRequest("idle.queryState", "[30]");
|
| - EXPECT_NE(-1, last_request()->request_id);
|
| - reset_last_request();
|
| - }
|
| -
|
| - {
|
| - const char kTestCall[] = "chrome.idle.setDetectionInterval(30);";
|
| - ExecuteScript(context, kTestCall);
|
| - ValidateLastRequest("idle.setDetectionInterval", "[30]");
|
| - EXPECT_EQ(-1, last_request()->request_id);
|
| - reset_last_request();
|
| - }
|
| -
|
| - // Check catching errors.
|
| - const char kError[] = "Uncaught TypeError: Invalid invocation";
|
| - {
|
| - // "disp" is not an allowed enum value.
|
| - const char kTestCall[] = "chrome.power.requestKeepAwake('disp');";
|
| - ExecuteScriptAndExpectError(context, kTestCall, kError);
|
| - EXPECT_FALSE(last_request());
|
| - reset_last_request(); // Just to not pollute future results.
|
| - }
|
| -
|
| - {
|
| - // The queryState() param has a minimum of 15.
|
| - const char kTestCall[] = "chrome.idle.queryState(10, function() {});";
|
| - ExecuteScriptAndExpectError(context, kTestCall, kError);
|
| - EXPECT_FALSE(last_request());
|
| - reset_last_request(); // Just to not pollute future results.
|
| - }
|
| -
|
| - {
|
| - const char kTestCall[] =
|
| - "chrome.idle.onStateChanged.addListener(state => {\n"
|
| - " this.idleState = state;\n"
|
| - "});\n";
|
| - ExecuteScript(context, kTestCall);
|
| - EXPECT_EQ("undefined", GetStringPropertyFromObject(context->Global(),
|
| - context, "idleState"));
|
| - bindings_system()->FireEventInContext("idle.onStateChanged", context,
|
| - *ListValueFromString("['active']"));
|
| -
|
| - EXPECT_EQ("\"active\"", GetStringPropertyFromObject(context->Global(),
|
| - context, "idleState"));
|
| - }
|
| -}
|
| -
|
| } // namespace extensions
|
|
|