// 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. #include "base/basictypes.h" #include "base/message_loop/message_loop.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/autocomplete/autocomplete_match.h" #include "chrome/browser/autocomplete/extension_app_provider.h" #include "chrome/browser/history/history_service.h" #include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/history/url_database.h" #include "chrome/test/base/testing_profile.h" #include "content/public/test/test_browser_thread.h" #include "testing/gtest/include/gtest/gtest.h" using base::ASCIIToUTF16; class ExtensionAppProviderTest : public testing::Test { protected: struct test_data { const base::string16 input; const size_t num_results; const GURL output[3]; }; ExtensionAppProviderTest() : ui_thread_(content::BrowserThread::UI, &message_loop_), history_service_(NULL) { } virtual ~ExtensionAppProviderTest() { } virtual void SetUp() OVERRIDE; void RunTest(test_data* keyword_cases, int num_cases); protected: base::MessageLoopForUI message_loop_; content::TestBrowserThread ui_thread_; scoped_refptr app_provider_; scoped_ptr profile_; HistoryService* history_service_; }; void ExtensionAppProviderTest::SetUp() { profile_.reset(new TestingProfile()); ASSERT_TRUE(profile_->CreateHistoryService(true, false)); profile_->BlockUntilHistoryProcessesPendingRequests(); history_service_ = HistoryServiceFactory::GetForProfile(profile_.get(), Profile::EXPLICIT_ACCESS); app_provider_ = new ExtensionAppProvider(NULL, profile_.get()); struct TestExtensionApp { const char* app_name; const char* launch_url; bool should_match_against_launch_url; const char* title; int typed_count; } kExtensionApps[] = { {"COYB", "http://asdf/", true, "COYB", 7}, {"NSNO", "http://fdsa/", true, "NSNO", 2}, {"APPP", "chrome-extension://xyz/", false, "APPP", 2}, }; history::URLDatabase* url_db = history_service_->InMemoryDatabase(); for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kExtensionApps); ++i) { // Populate the Extension Apps list. ExtensionAppProvider::ExtensionApp extension_app = { ASCIIToUTF16(kExtensionApps[i].app_name), ASCIIToUTF16(kExtensionApps[i].launch_url), kExtensionApps[i].should_match_against_launch_url }; app_provider_->AddExtensionAppForTesting(extension_app); // Populate the InMemoryDatabase. history::URLRow info(GURL(kExtensionApps[i].launch_url)); info.set_title(base::UTF8ToUTF16(kExtensionApps[i].title)); info.set_typed_count(kExtensionApps[i].typed_count); url_db->AddURL(info); } } void ExtensionAppProviderTest::RunTest( test_data* keyword_cases, int num_cases) { ACMatches matches; for (int i = 0; i < num_cases; ++i) { AutocompleteInput input(keyword_cases[i].input, base::string16::npos, base::string16(), GURL(), AutocompleteInput::INVALID_SPEC, true, false, true, AutocompleteInput::ALL_MATCHES); app_provider_->Start(input, false); EXPECT_TRUE(app_provider_->done()); matches = app_provider_->matches(); EXPECT_EQ(keyword_cases[i].num_results, matches.size()) << ASCIIToUTF16("Input was: ") + keyword_cases[i].input; if (matches.size() == keyword_cases[i].num_results) { for (size_t j = 0; j < keyword_cases[i].num_results; ++j) EXPECT_EQ(keyword_cases[i].output[j], matches[j].destination_url); } } } TEST_F(ExtensionAppProviderTest, BasicMatching) { test_data edit_cases[] = { // Searching for a nonexistent value should give nothing. {ASCIIToUTF16("Not Found"), 0, { GURL() }}, // The letter 'o' appears in both extension apps. {ASCIIToUTF16("o"), 2, { GURL("http://asdf/"), GURL("http://fdsa/") }}, // The string 'co' appears in one extension app. {ASCIIToUTF16("co"), 1, { GURL("http://asdf/") }}, // Try with URL matching. {ASCIIToUTF16("http://asdf/"), 1, { GURL("http://asdf/") }}, {ASCIIToUTF16("http://fdsa/"), 1, { GURL("http://fdsa/") }}, // "xyz" appears in a launch URL, but we're not matching against it. {ASCIIToUTF16("xyz"), 0, { GURL() }}, // But it should be matcheable by title. {ASCIIToUTF16("APPP"), 1, { GURL("chrome-extension://xyz/") }}, }; RunTest(edit_cases, ARRAYSIZE_UNSAFE(edit_cases)); } TEST_F(ExtensionAppProviderTest, CreateMatchSanitize) { struct TestData { const char* name; const char* match_contents; } cases[] = { { "Test", "Test" }, { "Test \n Test", "Test Test" }, { "Test\r\t\nTest", "TestTest" }, }; AutocompleteInput input(ASCIIToUTF16("Test"), base::string16::npos, base::string16(), GURL(), AutocompleteInput::INVALID_SPEC, true, true, true, AutocompleteInput::BEST_MATCH); base::string16 url(ASCIIToUTF16("http://example.com")); for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { ExtensionAppProvider::ExtensionApp extension_app = {ASCIIToUTF16(cases[i].name), url, true}; AutocompleteMatch match = app_provider_->CreateAutocompleteMatch(input, extension_app, 0, base::string16::npos); EXPECT_EQ(ASCIIToUTF16(cases[i].match_contents), match.contents); } }