1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/basictypes.h" 6 #include "base/message_loop/message_loop.h" 7 #include "base/strings/utf_string_conversions.h" 8 #include "chrome/browser/autocomplete/autocomplete_match.h" 9 #include "chrome/browser/autocomplete/extension_app_provider.h" 10 #include "chrome/browser/history/history_service.h" 11 #include "chrome/browser/history/history_service_factory.h" 12 #include "chrome/browser/history/url_database.h" 13 #include "chrome/test/base/testing_profile.h" 14 #include "content/public/test/test_browser_thread.h" 15 #include "testing/gtest/include/gtest/gtest.h" 16 17 class ExtensionAppProviderTest : public testing::Test { 18 protected: 19 struct test_data { 20 const base::string16 input; 21 const size_t num_results; 22 const GURL output[3]; 23 }; 24 25 ExtensionAppProviderTest() 26 : ui_thread_(content::BrowserThread::UI, &message_loop_), 27 history_service_(NULL) { } 28 virtual ~ExtensionAppProviderTest() { } 29 30 virtual void SetUp() OVERRIDE; 31 32 void RunTest(test_data* keyword_cases, 33 int num_cases); 34 35 protected: 36 base::MessageLoopForUI message_loop_; 37 content::TestBrowserThread ui_thread_; 38 scoped_refptr<ExtensionAppProvider> app_provider_; 39 scoped_ptr<TestingProfile> profile_; 40 HistoryService* history_service_; 41 }; 42 43 void ExtensionAppProviderTest::SetUp() { 44 profile_.reset(new TestingProfile()); 45 ASSERT_TRUE(profile_->CreateHistoryService(true, false)); 46 profile_->BlockUntilHistoryProcessesPendingRequests(); 47 history_service_ = 48 HistoryServiceFactory::GetForProfile(profile_.get(), 49 Profile::EXPLICIT_ACCESS); 50 51 app_provider_ = new ExtensionAppProvider(NULL, profile_.get()); 52 53 struct TestExtensionApp { 54 const char* app_name; 55 const char* launch_url; 56 bool should_match_against_launch_url; 57 const char* title; 58 int typed_count; 59 } kExtensionApps[] = { 60 {"COYB", "http://asdf/", true, "COYB", 7}, 61 {"NSNO", "http://fdsa/", true, "NSNO", 2}, 62 {"APPP", "chrome-extension://xyz/", false, "APPP", 2}, 63 }; 64 65 history::URLDatabase* url_db = history_service_->InMemoryDatabase(); 66 67 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kExtensionApps); ++i) { 68 // Populate the Extension Apps list. 69 ExtensionAppProvider::ExtensionApp extension_app = { 70 ASCIIToUTF16(kExtensionApps[i].app_name), 71 ASCIIToUTF16(kExtensionApps[i].launch_url), 72 kExtensionApps[i].should_match_against_launch_url 73 }; 74 app_provider_->AddExtensionAppForTesting(extension_app); 75 76 // Populate the InMemoryDatabase. 77 history::URLRow info(GURL(kExtensionApps[i].launch_url)); 78 info.set_title(UTF8ToUTF16(kExtensionApps[i].title)); 79 info.set_typed_count(kExtensionApps[i].typed_count); 80 url_db->AddURL(info); 81 } 82 } 83 84 void ExtensionAppProviderTest::RunTest( 85 test_data* keyword_cases, 86 int num_cases) { 87 ACMatches matches; 88 for (int i = 0; i < num_cases; ++i) { 89 AutocompleteInput input(keyword_cases[i].input, base::string16::npos, 90 base::string16(), GURL(), 91 AutocompleteInput::INVALID_SPEC, true, 92 false, true, AutocompleteInput::ALL_MATCHES); 93 app_provider_->Start(input, false); 94 EXPECT_TRUE(app_provider_->done()); 95 matches = app_provider_->matches(); 96 EXPECT_EQ(keyword_cases[i].num_results, matches.size()) 97 << ASCIIToUTF16("Input was: ") + keyword_cases[i].input; 98 if (matches.size() == keyword_cases[i].num_results) { 99 for (size_t j = 0; j < keyword_cases[i].num_results; ++j) 100 EXPECT_EQ(keyword_cases[i].output[j], matches[j].destination_url); 101 } 102 } 103 } 104 105 TEST_F(ExtensionAppProviderTest, BasicMatching) { 106 test_data edit_cases[] = { 107 // Searching for a nonexistent value should give nothing. 108 {ASCIIToUTF16("Not Found"), 0, { GURL() }}, 109 110 // The letter 'o' appears in both extension apps. 111 {ASCIIToUTF16("o"), 2, { GURL("http://asdf/"), 112 GURL("http://fdsa/") }}, 113 // The string 'co' appears in one extension app. 114 {ASCIIToUTF16("co"), 1, { GURL("http://asdf/") }}, 115 // Try with URL matching. 116 {ASCIIToUTF16("http://asdf/"), 1, { GURL("http://asdf/") }}, 117 {ASCIIToUTF16("http://fdsa/"), 1, { GURL("http://fdsa/") }}, 118 119 // "xyz" appears in a launch URL, but we're not matching against it. 120 {ASCIIToUTF16("xyz"), 0, { GURL() }}, 121 122 // But it should be matcheable by title. 123 {ASCIIToUTF16("APPP"), 1, { GURL("chrome-extension://xyz/") }}, 124 125 }; 126 127 RunTest(edit_cases, ARRAYSIZE_UNSAFE(edit_cases)); 128 } 129 130 TEST_F(ExtensionAppProviderTest, CreateMatchSanitize) { 131 struct TestData { 132 const char* name; 133 const char* match_contents; 134 } cases[] = { 135 { "Test", "Test" }, 136 { "Test \n Test", "Test Test" }, 137 { "Test\r\t\nTest", "TestTest" }, 138 }; 139 140 AutocompleteInput input(ASCIIToUTF16("Test"), base::string16::npos, 141 base::string16(), GURL(), 142 AutocompleteInput::INVALID_SPEC, true, true, 143 true, AutocompleteInput::BEST_MATCH); 144 base::string16 url(ASCIIToUTF16("http://example.com")); 145 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { 146 ExtensionAppProvider::ExtensionApp extension_app = 147 {ASCIIToUTF16(cases[i].name), url, true}; 148 AutocompleteMatch match = 149 app_provider_->CreateAutocompleteMatch(input, 150 extension_app, 151 0, 152 base::string16::npos); 153 EXPECT_EQ(ASCIIToUTF16(cases[i].match_contents), match.contents); 154 } 155 } 156