diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
commit | 09911bf300f1a419907a9412154760efd0b7abc3 (patch) | |
tree | f131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/browser/autocomplete/autocomplete_unittest.cc | |
parent | 586acc5fe142f498261f52c66862fa417c3d52d2 (diff) | |
download | chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2 |
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/autocomplete/autocomplete_unittest.cc')
-rw-r--r-- | chrome/browser/autocomplete/autocomplete_unittest.cc | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/chrome/browser/autocomplete/autocomplete_unittest.cc b/chrome/browser/autocomplete/autocomplete_unittest.cc new file mode 100644 index 0000000..e2fc2f5 --- /dev/null +++ b/chrome/browser/autocomplete/autocomplete_unittest.cc @@ -0,0 +1,361 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "base/message_loop.h" +#include "base/ref_counted.h" +#include "chrome/browser/autocomplete/autocomplete.h" +#include "testing/gtest/include/gtest/gtest.h" + +// identifiers for known autocomplete providers +#define HISTORY_IDENTIFIER L"Chrome:History" +#define SEARCH_IDENTIFIER L"google.com/websearch/en" + +namespace { + +const int num_results_per_provider = 3; + +// Autocomplete provider that provides known results. Note that this is +// refcounted so that it can also be a task on the message loop. +class TestProvider : public AutocompleteProvider { + public: + TestProvider(int relevance, const std::wstring& prefix) + : AutocompleteProvider(NULL, NULL, ""), + relevance_(relevance), + prefix_(prefix) { + } + + virtual void Start(const AutocompleteInput& input, + bool minimal_changes, + bool synchronous_only); + + void set_listener(ACProviderListener* listener) { + listener_ = listener; + } + + private: + void Run(); + + void AddResults(int start_at, int num); + + int relevance_; + const std::wstring prefix_; +}; + +void TestProvider::Start(const AutocompleteInput& input, + bool minimal_changes, + bool synchronous_only) { + if (minimal_changes) + return; + + matches_.clear(); + + // Generate one result synchronously, the rest later. + AddResults(0, 1); + + if (!synchronous_only) { + done_ = false; + MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( + this, &TestProvider::Run)); + } +} + +void TestProvider::Run() { + DCHECK(num_results_per_provider > 0); + AddResults(1, num_results_per_provider); + done_ = true; + DCHECK(listener_); + listener_->OnProviderUpdate(true); +} + +void TestProvider::AddResults(int start_at, int num) { + for (int i = start_at; i < num; i++) { + AutocompleteMatch match(this, relevance_ - i, false); + + wchar_t str[16]; + swprintf_s(str, L"%d", i); + match.fill_into_edit = prefix_ + str; + match.destination_url = match.fill_into_edit; + + match.contents = match.destination_url; + match.contents_class.push_back( + ACMatchClassification(0, ACMatchClassification::NONE)); + match.description = match.destination_url; + match.description_class.push_back( + ACMatchClassification(0, ACMatchClassification::NONE)); + + matches_.push_back(match); + } +} + +class AutocompleteProviderTest : public testing::Test, + public ACControllerListener { + public: + // ACControllerListener + virtual void OnAutocompleteUpdate(bool updated_result, bool query_complete); + + protected: + // testing::Test + virtual void SetUp(); + + void ResetController(bool same_destinations); + + // Runs a query on the input "a", and makes sure both providers' input is + // properly collected. + void RunTest(); + + // These providers are owned by the controller once it's created. + ACProviders providers_; + + AutocompleteResult result_; + + private: + scoped_ptr<AutocompleteController> controller_; +}; + +void AutocompleteProviderTest::SetUp() { + ResetController(false); +} + +void AutocompleteProviderTest::ResetController(bool same_destinations) { + // Forget about any existing providers. The controller owns them and will + // Release() them below, when we delete it during the call to reset(). + providers_.clear(); + + // Construct two new providers, with either the same or different prefixes. + TestProvider* providerA = new TestProvider(num_results_per_provider, L"a"); + providerA->AddRef(); + providers_.push_back(providerA); + + TestProvider* providerB = new TestProvider(num_results_per_provider * 2, + same_destinations ? L"a" : L"b"); + providerB->AddRef(); + providers_.push_back(providerB); + + // Reset the controller to contain our new providers. + AutocompleteController* controller = + new AutocompleteController(this, providers_); + controller_.reset(controller); + providerA->set_listener(controller); + providerB->set_listener(controller); +} + +void AutocompleteProviderTest::OnAutocompleteUpdate(bool updated_result, + bool query_complete) { + controller_->GetResult(&result_); + if (query_complete) + MessageLoop::current()->Quit(); +} + +void AutocompleteProviderTest::RunTest() { + result_.Reset(); + const AutocompleteInput input(L"a", std::wstring(), true); + EXPECT_FALSE(controller_->Start(input, false, false)); + + // The message loop will terminate when all autocomplete input has been + // collected. + MessageLoop::current()->Run(); +} + +} // namespace + +std::ostream& operator<<(std::ostream& os, + const AutocompleteResult::const_iterator& iter) { + return os << static_cast<const AutocompleteMatch*>(&(*iter)); +} + +// Tests that the default selection is set properly when updating results. +TEST_F(AutocompleteProviderTest, Query) { + RunTest(); + + // Make sure the default match gets set to the highest relevance match when + // we have no preference. The highest relevance matches should come from + // the second provider. + AutocompleteResult::Selection selection; + result_.SetDefaultMatch(selection); + EXPECT_EQ(num_results_per_provider * 2, result_.size()); // two providers + ASSERT_NE(result_.end(), result_.default_match()); + EXPECT_EQ(providers_[1], result_.default_match()->provider); + + // Change provider affinity. + selection.provider_affinity = providers_[0]; + result_.SetDefaultMatch(selection); + ASSERT_NE(result_.end(), result_.default_match()); + EXPECT_EQ(providers_[0], result_.default_match()->provider); +} + +TEST_F(AutocompleteProviderTest, UpdateSelection) { + RunTest(); + + // An empty selection should simply result in the default match overall. + AutocompleteResult::Selection selection; + result_.SetDefaultMatch(selection); + ASSERT_NE(result_.end(), result_.default_match()); + EXPECT_EQ(providers_[1], result_.default_match()->provider); + + // ...As should specifying a provider that didn't return results. + scoped_refptr<TestProvider> test_provider = new TestProvider(0, L""); + selection.provider_affinity = test_provider.get(); + result_.SetDefaultMatch(selection); + ASSERT_NE(result_.end(), result_.default_match()); + EXPECT_EQ(providers_[1], result_.default_match()->provider); + selection.provider_affinity = NULL; + test_provider = NULL; + + // ...As should specifying a destination URL that doesn't exist, and no + // provider. + selection.destination_url = L"garbage"; + selection.provider_affinity = NULL; + result_.SetDefaultMatch(selection); + ASSERT_NE(result_.end(), result_.default_match()); + EXPECT_EQ(providers_[1], result_.default_match()->provider); + delete selection.provider_affinity; + + // Specifying a valid provider should result in the default match from that + // provider. + selection.destination_url.clear(); + selection.provider_affinity = providers_[0]; + result_.SetDefaultMatch(selection); + ASSERT_NE(result_.end(), result_.default_match()); + EXPECT_EQ(providers_[0], result_.default_match()->provider); + + // ...And nothing should change if we specify a destination that doesn't + // exist. + selection.destination_url = L"garbage"; + result_.SetDefaultMatch(selection); + ASSERT_NE(result_.end(), result_.default_match()); + EXPECT_EQ(providers_[0], result_.default_match()->provider); + + // Specifying a particular URL should match that URL. + std::wstring non_default_url_from_provider_0(L"a2"); + selection.destination_url = non_default_url_from_provider_0; + selection.provider_affinity = providers_[0]; + result_.SetDefaultMatch(selection); + ASSERT_NE(result_.end(), result_.default_match()); + EXPECT_EQ(non_default_url_from_provider_0, + result_.default_match()->destination_url); + + // ...Even when we ask for a different provider. + selection.provider_affinity = providers_[1]; + result_.SetDefaultMatch(selection); + ASSERT_NE(result_.end(), result_.default_match()); + EXPECT_EQ(non_default_url_from_provider_0, + result_.default_match()->destination_url); + + // ...Or when we don't ask for a provider at all. + selection.provider_affinity = NULL; + result_.SetDefaultMatch(selection); + ASSERT_NE(result_.end(), result_.default_match()); + EXPECT_EQ(non_default_url_from_provider_0, + result_.default_match()->destination_url); +} + +TEST_F(AutocompleteProviderTest, RemoveDuplicates) { + // Set up the providers to provide duplicate results. + ResetController(true); + + RunTest(); + + // Make sure all the first provider's results were eliminated by the second + // provider's. + EXPECT_EQ(num_results_per_provider, result_.size()); + for (AutocompleteResult::const_iterator i(result_.begin()); + i != result_.end(); ++i) + EXPECT_EQ(providers_[1], i->provider); + + // Set things back to the default for the benefit of any tests that run after + // us. + ResetController(false); +} + +TEST(AutocompleteTest, InputType) { + struct test_data { + const wchar_t* input; + const AutocompleteInput::Type type; + } input_cases[] = { + { L"", AutocompleteInput::INVALID }, + { L"?", AutocompleteInput::FORCED_QUERY }, + { L"?foo", AutocompleteInput::FORCED_QUERY }, + { L"?foo bar", AutocompleteInput::FORCED_QUERY }, + { L"?http://foo.com/bar", AutocompleteInput::FORCED_QUERY }, + { L"foo", AutocompleteInput::UNKNOWN }, + { L"foo.com", AutocompleteInput::URL }, + { L"foo/bar", AutocompleteInput::URL }, + { L"foo/bar baz", AutocompleteInput::UNKNOWN }, + { L"http://foo/bar baz", AutocompleteInput::URL }, + { L"foo bar", AutocompleteInput::QUERY }, + { L"link:foo.com", AutocompleteInput::UNKNOWN }, + { L"www.foo.com:81", AutocompleteInput::URL }, + { L"localhost:8080", AutocompleteInput::URL }, + { L"en.wikipedia.org/wiki/James Bond", AutocompleteInput::URL }, + // In Chrome itself, mailto: will get handled by ShellExecute, but in + // unittest mode, we don't have the data loaded in the external protocol + // handler to know this. + // { L"mailto:abuse@foo.com", AutocompleteInput::URL }, + { L"view-source:http://www.foo.com/", AutocompleteInput::URL }, + { L"javascript:alert(\"Hey there!\");", AutocompleteInput::URL }, + { L"C:\\Program Files", AutocompleteInput::URL }, + { L"\\\\Server\\Folder\\File", AutocompleteInput::URL }, + { L"http://foo.com/", AutocompleteInput::URL }, + { L"127.0.0.1", AutocompleteInput::URL }, + { L"browser.tabs.closeButtons", AutocompleteInput::UNKNOWN }, + }; + + for (int i = 0; i < arraysize(input_cases); ++i) { + AutocompleteInput input(input_cases[i].input, std::wstring(), true); + EXPECT_EQ(input_cases[i].type, input.type()) << "Input: " << + input_cases[i].input; + } +} + +// Test that we can properly compare matches' relevance when at least one is +// negative. +TEST(AutocompleteMatch, MoreRelevant) { + struct RelevantCases { + int r1; + int r2; + bool expected_result; + } cases[] = { + { 10, 0, true }, + { 10, -5, true }, + { -5, 10, false }, + { 0, 10, false }, + { -10, -5, true }, + { -5, -10, false }, + }; + + AutocompleteMatch m1; + AutocompleteMatch m2; + + for (int i = 0; i < arraysize(cases); ++i) { + m1.relevance = cases[i].r1; + m2.relevance = cases[i].r2; + EXPECT_EQ(cases[i].expected_result, + AutocompleteMatch::MoreRelevant(m1, m2)); + } +} |