diff options
author | beaudoin@chromium.org <beaudoin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-29 00:27:38 +0000 |
---|---|---|
committer | beaudoin@chromium.org <beaudoin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-29 00:27:38 +0000 |
commit | 8cd4ea9f4eaea5557c16a88c7239f3e61fd9c892 (patch) | |
tree | 09a65c08cf434dfe2006e80e334cc43c666a2ebb | |
parent | e0845d5f582add16baf03fcd32ef6f9001b3e347 (diff) | |
download | chromium_src-8cd4ea9f4eaea5557c16a88c7239f3e61fd9c892.zip chromium_src-8cd4ea9f4eaea5557c16a88c7239f3e61fd9c892.tar.gz chromium_src-8cd4ea9f4eaea5557c16a88c7239f3e61fd9c892.tar.bz2 |
Initial unit tests for the discovery API.
Includes a slight change to the behavior of chrome.discovery.suggest, documentation updated.
BUG=none
TEST=none
Review URL: https://chromiumcodereview.appspot.com/10388192
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@139273 0039d316-1c4b-4281-b951-d872f2087c98
5 files changed, 245 insertions, 18 deletions
diff --git a/chrome/browser/extensions/api/README.txt b/chrome/browser/extensions/api/README.txt index f15e243..74d72d6 100644 --- a/chrome/browser/extensions/api/README.txt +++ b/chrome/browser/extensions/api/README.txt @@ -19,16 +19,20 @@ Create "chrome/common/extensions/api/experimental_foo.json". For inspiration look at the "app" API. Include descriptions fields to generate the documentation. -2) Add your API specification to the project. +2) Add your API specification to extensions_api_resources.grd. Add an "<include ...>" line with your JSON specification file to "chrome/common/extensions_api_resources.grd". -3) Write the API function handlers. +3) Add your API specification to api.gyp. +Add "experimental_foo.json" to the "json_schema_files" section in +"chrome/common/extensions/api/api.gyp". + +4) Write the API function handlers. Create foo_api.cc and foo_api.h under "chrome/browser/extensions/api/foo". You -should use the JSON Schema Compiler. Look at the "alarms_api.cc" for details on -how to do that. +should use the JSON Schema Compiler. Look at the "permissions_api.cc" for +details on how to do that. -4) Register function handlers. +5) Register function handlers. In "chrome/browser/extensions/extension_function_registry.cc" include foo_api.h and instantiate a RegisterFunction for each function you created in (3). @@ -40,7 +44,7 @@ Create "chrome/common/extensions/api/experimental_foo.idl". For inspiration look at "alarms.idl". Include comments, they will be used to automatically generate the documentation. -2) Add your API specification to the project. +2) Add your API specification to api.gyp. Add "experimental_foo.idl" to the "idl_schema_files" section in "chrome/common/extensions/api/api.gyp". @@ -49,34 +53,34 @@ Create foo_api.cc and foo_api.h under "chrome/browser/extensions/api/foo". You should use the JSON Schema Compiler. Look at the "alarms_api.cc" for details on how to do that. -4) Nothing to do! Function handlers are automatically registered for you. +4-5) Nothing to do! Function handlers are automatically registered for you. -------------------------------------------------------------------------------- STEPS COMMON TO BOTH APPROACHES -5) Write support classes for your API +6) Write support classes for your API If your API needs any support classes add them to "chrome/browser/extensions/api/foo". Some old APIs added their support classes directly to chrome/browser/extensions. Don't do that. -6) Update the project with your new files. +7) Update the project with your new files. The files you created in (3) and (5) should be added to "chrome/chrome_browser_extensions.gypi". -------------------------------------------------------------------------------- GENERATING DOCUMENTATION -7) Build the project. (Only required if you used IDL files.) +8) Build the project. (Only required if you used IDL files.) If you used IDL files, you need to build the project once in order for the documentation to be properly generated. Do this now. (This is required in order to generate the JSON file used to generate documentation.) -8) Add your JSON file to the documentation controller +9) Add your JSON file to the documentation controller Open "chrome/common/extensions/docs/js/api_page_generator.js" and add a line referring to "../api/experimental_foo.json". Do this even if you used the IDL approach as this JSON file has been generated in (7). -9) Write the static HTML page. +10) Write the static HTML page. Write a small snippet of static HTML describing your API in "chrome/common/extensions/docs/static/experimental.foo.html". For the moment, just include the following in this file, adjusting it to describe your API: @@ -87,7 +91,7 @@ just include the following in this file, adjusting it to describe your API: <p>The current methods allow applications to...</p> <!-- END AUTHORED CONTENT --> -10) Build the documentation. +11) Build the documentation. You will need to build DumpRenderTree once before you can build the documentation. Once this is done, from "chrome/common/extensions/docs" run "build/build.py". For more information on building documentation see README.txt @@ -96,5 +100,7 @@ in "chrome/common/extensions/docs". -------------------------------------------------------------------------------- WRITING TESTS -TODO(beaudoin) - +12) Write a unit test for your API. +Create "chrome/browser/extensions/api/foo/foo_api_unittest.cc" and test each of +your API methods. See "alarms_api_unittest.cc" for details. Once done add your +.cc to "chrome/chrome_tests.gypi". diff --git a/chrome/browser/extensions/api/discovery/discovery_api_unittest.cc b/chrome/browser/extensions/api/discovery/discovery_api_unittest.cc new file mode 100644 index 0000000..267c88e --- /dev/null +++ b/chrome/browser/extensions/api/discovery/discovery_api_unittest.cc @@ -0,0 +1,205 @@ +// 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. + +// This file tests the chrome.alarms extension API. + +#include "base/json/json_writer.h" +#include "base/values.h" +#include "chrome/browser/browser_process_impl.h" +#include "chrome/browser/extensions/api/discovery/discovery_api.h" +#include "chrome/browser/extensions/api/discovery/suggested_link.h" +#include "chrome/browser/extensions/api/discovery/suggested_links_registry.h" +#include "chrome/browser/extensions/api/discovery/suggested_links_registry_factory.h" +#include "chrome/browser/extensions/extension_function_test_utils.h" +#include "chrome/browser/extensions/test_extension_system.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/common/extensions/api/experimental_discovery.h" +#include "chrome/test/base/browser_with_test_window_test.h" +#include "chrome/test/base/testing_browser_process.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace utils = extension_function_test_utils; + +namespace { +typedef extensions::SuggestedLinksRegistry::SuggestedLinkList SuggestedLinkList; +typedef extensions::api::experimental_discovery::SuggestDetails SuggestDetails; + +// Converts suggest details used as parameter into a JSON string. +std::string SuggestDetailsParamToJSON(const SuggestDetails& suggest_details) { + std::string result; + scoped_ptr<base::DictionaryValue> value = suggest_details.ToValue(); + base::ListValue params; + params.Append(value.release()); // |params| takes ownership of |value|. + base::JSONWriter::Write(¶ms, &result); + return result; +} + +// Converts the parameters to the API Suggest method to JSON (without score). +std::string UnscoredSuggestParamsToJSON(const std::string& link_url, + const std::string& link_text) { + SuggestDetails suggest_details; + suggest_details.link_url = link_url; + suggest_details.link_text = link_text; + return SuggestDetailsParamToJSON(suggest_details); +} + + +// Converts the parameters to the API Suggest method to JSON. +std::string SuggestParamsToJSON(const std::string& link_url, + const std::string& link_text, + double score) { + SuggestDetails suggest_details; + suggest_details.score.reset(new double(score)); + suggest_details.link_url = link_url; + suggest_details.link_text = link_text; + return SuggestDetailsParamToJSON(suggest_details); +} + +// Converts the parameters to the API RemoveSuggestion method to JSON. +std::string RemoveSuggestionParamsToJSON(const std::string& link_url) { + std::string result; + base::ListValue params; + params.Append(base::Value::CreateStringValue(link_url)); + base::JSONWriter::Write(¶ms, &result); + return result; +} + +} // namespace + +namespace extensions { + +class ExtensionDiscoveryTest : public BrowserWithTestWindowTest { + public: + virtual void SetUp() { + BrowserWithTestWindowTest::SetUp(); + extension_ = utils::CreateEmptyExtensionWithLocation(Extension::LOAD); + } + + // Runs a function and returns a pointer to a value, transferring ownership. + base::Value* RunFunctionWithExtension( + UIThreadExtensionFunction* function, const std::string& args) { + function->set_extension(extension_.get()); + return utils::RunFunctionAndReturnResult(function, args, browser()); + } + + // Runs a function and ignores the return value. + void RunFunction(UIThreadExtensionFunction* function, + const std::string& args) { + scoped_ptr<base::Value> result(RunFunctionWithExtension(function, args)); + } + + // Runs a function without argumentsand ignores the return value. + void RunFunctionWithoutArguments(UIThreadExtensionFunction* function, + const std::string& args) { + scoped_ptr<base::Value> result(RunFunctionWithExtension(function, args)); + } + + // Runs a function, expect an error, and return it in a string. + std::string RunFunctionAndReturnError(UIThreadExtensionFunction* function, + const std::string& args) { + function->set_extension(extension_.get()); + return utils::RunFunctionAndReturnError(function, args, browser()); + } + + const std::string& GetExtensionId() const { + return extension_->id(); + } + + protected: + scoped_refptr<Extension> extension_; +}; + +TEST_F(ExtensionDiscoveryTest, Suggest) { + RunFunction(new DiscoverySuggestFunction(), + SuggestParamsToJSON("http://www.google.com", "Google", 0.5)); + + extensions::SuggestedLinksRegistry* registry = + extensions::SuggestedLinksRegistryFactory::GetForProfile( + browser()->profile()); + + const SuggestedLinkList* links = registry->GetAll(GetExtensionId()); + ASSERT_EQ(1u, links->size()); + ASSERT_EQ("http://www.google.com", links->at(0)->link_url()); + ASSERT_EQ("Google", links->at(0)->link_text()); + ASSERT_DOUBLE_EQ(0.5, links->at(0)->score()); +} + +TEST_F(ExtensionDiscoveryTest, SuggestWithoutScore) { + RunFunction(new DiscoverySuggestFunction(), + UnscoredSuggestParamsToJSON("https://amazon.com/", "Amazon")); + + extensions::SuggestedLinksRegistry* registry = + extensions::SuggestedLinksRegistryFactory::GetForProfile( + browser()->profile()); + + const SuggestedLinkList* links = registry->GetAll(GetExtensionId()); + ASSERT_EQ(1u, links->size()); + ASSERT_EQ("https://amazon.com/", links->at(0)->link_url()); + ASSERT_EQ("Amazon", links->at(0)->link_text()); + ASSERT_DOUBLE_EQ(1.0, links->at(0)->score()); // Score should default to 1. +} + +TEST_F(ExtensionDiscoveryTest, SuggestTwiceSameUrl) { + // Suggesting the same URL a second time should override the first. + RunFunction(new DiscoverySuggestFunction(), + SuggestParamsToJSON("http://www.google.com", "Google", 0.5)); + RunFunction(new DiscoverySuggestFunction(), + SuggestParamsToJSON("http://www.google.com", "Google2", 0.1)); + + extensions::SuggestedLinksRegistry* registry = + extensions::SuggestedLinksRegistryFactory::GetForProfile( + browser()->profile()); + + const SuggestedLinkList* links = registry->GetAll(GetExtensionId()); + ASSERT_EQ(1u, links->size()); + ASSERT_EQ("http://www.google.com", links->at(0)->link_url()); + ASSERT_EQ("Google2", links->at(0)->link_text()); + ASSERT_DOUBLE_EQ(0.1, links->at(0)->score()); +} + +TEST_F(ExtensionDiscoveryTest, Remove) { + RunFunction(new DiscoverySuggestFunction(), + UnscoredSuggestParamsToJSON("http://www.google.com", "Google")); + RunFunction(new DiscoverySuggestFunction(), + UnscoredSuggestParamsToJSON("https://amazon.com/", "Amazon")); + RunFunction(new DiscoverySuggestFunction(), + UnscoredSuggestParamsToJSON("http://www.youtube.com/watch?v=zH5bJSG0DZk", + "YouTube")); + RunFunction(new DiscoveryRemoveSuggestionFunction(), + RemoveSuggestionParamsToJSON("https://amazon.com/")); + + extensions::SuggestedLinksRegistry* registry = + extensions::SuggestedLinksRegistryFactory::GetForProfile( + browser()->profile()); + + const SuggestedLinkList* links = registry->GetAll(GetExtensionId()); + ASSERT_EQ(2u, links->size()); + ASSERT_EQ("http://www.google.com", links->at(0)->link_url()); + ASSERT_EQ("Google", links->at(0)->link_text()); + ASSERT_DOUBLE_EQ(1.0, links->at(0)->score()); + ASSERT_EQ("http://www.youtube.com/watch?v=zH5bJSG0DZk", + links->at(1)->link_url()); + ASSERT_EQ("YouTube", links->at(1)->link_text()); + ASSERT_DOUBLE_EQ(1.0, links->at(1)->score()); +} + +TEST_F(ExtensionDiscoveryTest, ClearAll) { + RunFunction(new DiscoverySuggestFunction(), + UnscoredSuggestParamsToJSON("http://www.google.com", "Google")); + RunFunction(new DiscoverySuggestFunction(), + UnscoredSuggestParamsToJSON("https://amazon.com/", "Amazon")); + RunFunction(new DiscoverySuggestFunction(), + UnscoredSuggestParamsToJSON("http://www.youtube.com/watch?v=zH5bJSG0DZk", + "YouTube")); + RunFunction(new DiscoveryClearAllSuggestionsFunction(), "[]"); + + extensions::SuggestedLinksRegistry* registry = + extensions::SuggestedLinksRegistryFactory::GetForProfile( + browser()->profile()); + + const SuggestedLinkList* links = registry->GetAll(GetExtensionId()); + ASSERT_EQ(0u, links->size()); +} + +} // namespace extensions diff --git a/chrome/browser/extensions/api/discovery/suggested_links_registry.cc b/chrome/browser/extensions/api/discovery/suggested_links_registry.cc index 7c7f5fe..0265690 100644 --- a/chrome/browser/extensions/api/discovery/suggested_links_registry.cc +++ b/chrome/browser/extensions/api/discovery/suggested_links_registry.cc @@ -8,10 +8,16 @@ namespace { typedef extensions::SuggestedLinksRegistry::SuggestedLinkList SuggestedLinkList; -void RemoveLinkFromList(const std::string& link_url, SuggestedLinkList* list) { +SuggestedLinkList::iterator FindUrlInList(const std::string& link_url, + SuggestedLinkList* list) { SuggestedLinkList::iterator found = list->begin(); for (; found != list->end(); ++found) if (link_url.compare((*found)->link_url()) == 0) break; + return found; +} + +void RemoveLinkFromList(const std::string& link_url, SuggestedLinkList* list) { + SuggestedLinkList::iterator found = FindUrlInList(link_url, list); if (found != list->end()) list->erase(found); } @@ -28,7 +34,12 @@ SuggestedLinksRegistry::~SuggestedLinksRegistry() { void SuggestedLinksRegistry::Add(const std::string& extension_id, scoped_ptr<extensions::SuggestedLink> item) { SuggestedLinkList& list = GetAllInternal(extension_id); - list.push_back(linked_ptr<extensions::SuggestedLink>(item.release())); + SuggestedLinkList::iterator found = FindUrlInList(item->link_url(), &list); + linked_ptr<extensions::SuggestedLink> new_item(item.release()); + if (found != list.end()) + *found = new_item; + else + list.push_back(new_item); } const SuggestedLinkList* SuggestedLinksRegistry::GetAll( @@ -36,7 +47,7 @@ const SuggestedLinkList* SuggestedLinksRegistry::GetAll( SuggestedLinksMap::const_iterator found = suggested_links_.find(extension_id); if (found != suggested_links_.end()) return &found->second; - return NULL; + return &empty_list_; } void SuggestedLinksRegistry::Remove(const std::string& extension_id, diff --git a/chrome/browser/extensions/api/discovery/suggested_links_registry.h b/chrome/browser/extensions/api/discovery/suggested_links_registry.h index df850d8..228a960 100644 --- a/chrome/browser/extensions/api/discovery/suggested_links_registry.h +++ b/chrome/browser/extensions/api/discovery/suggested_links_registry.h @@ -48,6 +48,10 @@ class SuggestedLinksRegistry : public ProfileKeyedService { SuggestedLinksMap suggested_links_; + // An empty list of suggestions that can be returned for non-existing + // extensions. + SuggestedLinkList empty_list_; + DISALLOW_COPY_AND_ASSIGN(SuggestedLinksRegistry); }; diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index b807b4f..6a38196 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1167,6 +1167,7 @@ 'browser/extensions/api/cookies/cookies_unittest.cc', 'browser/extensions/api/declarative/initializing_rules_registry_unittest.cc', 'browser/extensions/api/declarative/rules_registry_service_unittest.cc', + 'browser/extensions/api/discovery/discovery_api_unittest.cc', 'browser/extensions/api/declarative/rules_registry_with_cache_unittest.cc', 'browser/extensions/api/declarative_webrequest/webrequest_action_unittest.cc', 'browser/extensions/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc', |