OLD | NEW |
(Empty) | |
| 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 "chrome/browser/autocomplete/contact_provider_chromeos.h" |
| 6 |
| 7 #include <string> |
| 8 #include <utility> |
| 9 #include <vector> |
| 10 |
| 11 #include "base/memory/scoped_ptr.h" |
| 12 #include "base/message_loop.h" |
| 13 #include "base/string16.h" |
| 14 #include "base/string_number_conversions.h" |
| 15 #include "base/string_split.h" |
| 16 #include "base/utf_string_conversions.h" |
| 17 #include "chrome/browser/autocomplete/autocomplete_input.h" |
| 18 #include "chrome/browser/autocomplete/autocomplete_match.h" |
| 19 #include "chrome/browser/autocomplete/autocomplete_provider.h" |
| 20 #include "chrome/browser/chromeos/contacts/contact.pb.h" |
| 21 #include "chrome/browser/chromeos/contacts/contact_manager_stub.h" |
| 22 #include "chrome/browser/chromeos/contacts/contact_test_util.h" |
| 23 #include "chrome/test/base/testing_browser_process.h" |
| 24 #include "chrome/test/base/testing_profile.h" |
| 25 #include "chrome/test/base/testing_profile_manager.h" |
| 26 #include "content/public/browser/browser_thread.h" |
| 27 #include "content/public/test/test_browser_thread.h" |
| 28 #include "testing/gtest/include/gtest/gtest.h" |
| 29 |
| 30 using content::BrowserThread; |
| 31 |
| 32 namespace { |
| 33 |
| 34 // Given a string of comma-separated "index:length" spans like "0:1,5:3", |
| 35 // returns a vector of pairs containing the same information. |
| 36 ContactProvider::MatchSpans MatchSpansFromString(const std::string& str) { |
| 37 ContactProvider::MatchSpans spans; |
| 38 std::vector<std::string> parts; |
| 39 base::SplitString(str, ',', &parts); |
| 40 for (size_t i = 0; i < parts.size(); ++i) { |
| 41 std::vector<std::string> index_and_length; |
| 42 base::SplitString(parts[i], ':', &index_and_length); |
| 43 CHECK(index_and_length.size() == 2); |
| 44 |
| 45 ContactProvider::MatchSpan span; |
| 46 CHECK(base::StringToUint64(index_and_length[0], &span.first)); |
| 47 CHECK(base::StringToUint64(index_and_length[1], &span.second)); |
| 48 spans.push_back(span); |
| 49 } |
| 50 return spans; |
| 51 } |
| 52 |
| 53 // Given a vector of classifications, returns a comma-separated string |
| 54 // consisting of each classifications offset followed by a character describing |
| 55 // its style ('n' for "none", 'u' for "URL", 'm' for "match", and 'd' for |
| 56 // "dim"), e.g. "0n,5m,8n". |
| 57 std::string ACMatchClassificationsToString( |
| 58 const AutocompleteMatch::ACMatchClassifications& classifications) { |
| 59 std::string result; |
| 60 for (size_t i = 0; i < classifications.size(); ++i) { |
| 61 if (!result.empty()) |
| 62 result += ","; |
| 63 |
| 64 result += base::Uint64ToString( |
| 65 static_cast<uint64>(classifications[i].offset)); |
| 66 |
| 67 switch (classifications[i].style) { |
| 68 case AutocompleteMatch::ACMatchClassification::NONE: |
| 69 result += "n"; |
| 70 break; |
| 71 case AutocompleteMatch::ACMatchClassification::URL: |
| 72 result += "u"; |
| 73 break; |
| 74 case AutocompleteMatch::ACMatchClassification::MATCH: |
| 75 result += "m"; |
| 76 break; |
| 77 case AutocompleteMatch::ACMatchClassification::DIM: |
| 78 result += "d"; |
| 79 break; |
| 80 default: |
| 81 NOTREACHED() << "Unknown style " << classifications[i].style; |
| 82 } |
| 83 } |
| 84 |
| 85 return result; |
| 86 } |
| 87 |
| 88 // Initializes |contact| with the passed-in data. |
| 89 void InitContact(const std::string& contact_id, |
| 90 const std::string& full_name, |
| 91 const std::string& given_name, |
| 92 const std::string& family_name, |
| 93 contacts::Contact* contact) { |
| 94 contact->set_contact_id(contact_id); |
| 95 contact->set_full_name(full_name); |
| 96 contact->set_given_name(given_name); |
| 97 contact->set_family_name(family_name); |
| 98 } |
| 99 |
| 100 } // namespace |
| 101 |
| 102 class ContactProviderTest : public testing::Test { |
| 103 public: |
| 104 ContactProviderTest() : ui_thread_(BrowserThread::UI, &message_loop_) {} |
| 105 virtual ~ContactProviderTest() {} |
| 106 |
| 107 protected: |
| 108 // testing::Test implementation. |
| 109 virtual void SetUp() OVERRIDE { |
| 110 profile_manager_.reset( |
| 111 new TestingProfileManager( |
| 112 static_cast<TestingBrowserProcess*>(g_browser_process))); |
| 113 ASSERT_TRUE(profile_manager_->SetUp()); |
| 114 profile_ = profile_manager_->CreateTestingProfile("test_profile"); |
| 115 contact_manager_.reset(new contacts::ContactManagerStub(profile_)); |
| 116 contact_provider_ = |
| 117 new ContactProvider(NULL, profile_, contact_manager_->GetWeakPtr()); |
| 118 } |
| 119 |
| 120 // Starts a (synchronous) query for |utf8_text| in |contact_provider_|. |
| 121 void StartQuery(const std::string& utf8_text) { |
| 122 contact_provider_->Start( |
| 123 AutocompleteInput(UTF8ToUTF16(utf8_text), |
| 124 string16(), // desired_tld |
| 125 false, // prevent_inline_autocomplete |
| 126 false, // prefer_keyword |
| 127 false, // allow_exact_keyword_match |
| 128 AutocompleteInput::ALL_MATCHES), |
| 129 false); // minimal_changes |
| 130 } |
| 131 |
| 132 // Returns pointers to all of the Contact objects referenced in |
| 133 // |contact_provider_|'s current results. |
| 134 contacts::ContactPointers GetMatchedContacts() { |
| 135 contacts::ContactPointers contacts; |
| 136 const ACMatches& matches = contact_provider_->matches(); |
| 137 for (size_t i = 0; i < matches.size(); ++i) { |
| 138 const AutocompleteMatch& match = matches[i]; |
| 139 |
| 140 std::map<std::string, std::string>::const_iterator info_it = |
| 141 match.additional_info.find(ContactProvider::kMatchContactIdKey); |
| 142 if (info_it == match.additional_info.end()) { |
| 143 LOG(ERROR) << "Unable to find contact ID in match"; |
| 144 continue; |
| 145 } |
| 146 const std::string& contact_id = info_it->second; |
| 147 |
| 148 const contacts::Contact* contact = |
| 149 contact_manager_->GetContactById(profile_, contact_id); |
| 150 if (!contact) { |
| 151 LOG(ERROR) << "Unable to find contact with ID " << contact_id; |
| 152 continue; |
| 153 } |
| 154 |
| 155 contacts.push_back(contact); |
| 156 } |
| 157 return contacts; |
| 158 } |
| 159 |
| 160 MessageLoopForUI message_loop_; |
| 161 content::TestBrowserThread ui_thread_; |
| 162 |
| 163 scoped_ptr<TestingProfileManager> profile_manager_; |
| 164 TestingProfile* profile_; |
| 165 |
| 166 scoped_ptr<contacts::ContactManagerStub> contact_manager_; |
| 167 scoped_refptr<ContactProvider> contact_provider_; |
| 168 }; |
| 169 |
| 170 TEST_F(ContactProviderTest, FillACMatchClassifications) { |
| 171 // We should end up with a single unstyled classification if we pass in an |
| 172 // empty list of spans or a single 0-length span. |
| 173 EXPECT_EQ( |
| 174 "0n", |
| 175 ACMatchClassificationsToString( |
| 176 ContactProvider::TestAPI::RunFillACMatchClassifications( |
| 177 MatchSpansFromString(""), 10))); |
| 178 EXPECT_EQ( |
| 179 "0n", |
| 180 ACMatchClassificationsToString( |
| 181 ContactProvider::TestAPI::RunFillACMatchClassifications( |
| 182 MatchSpansFromString("5:0"), 10))); |
| 183 |
| 184 EXPECT_EQ( |
| 185 "0m,3n,5m,6n", |
| 186 ACMatchClassificationsToString( |
| 187 ContactProvider::TestAPI::RunFillACMatchClassifications( |
| 188 MatchSpansFromString("0:3,5:1"), 10))); |
| 189 |
| 190 // Overlapping and adjacent spans should be collapsed. |
| 191 EXPECT_EQ( |
| 192 "0n,2m,7n,8m", |
| 193 ACMatchClassificationsToString( |
| 194 ContactProvider::TestAPI::RunFillACMatchClassifications( |
| 195 MatchSpansFromString("2:1,2:5,3:1,8:1,9:1"), 10))); |
| 196 |
| 197 // Unsorted input should fail. |
| 198 EXPECT_EQ( |
| 199 "", |
| 200 ACMatchClassificationsToString( |
| 201 ContactProvider::TestAPI::RunFillACMatchClassifications( |
| 202 MatchSpansFromString("2:1,1:1"), 10))); |
| 203 |
| 204 // We should also report failure if a span exceeds the length of the string. |
| 205 EXPECT_EQ( |
| 206 "", |
| 207 ACMatchClassificationsToString( |
| 208 ContactProvider::TestAPI::RunFillACMatchClassifications( |
| 209 MatchSpansFromString("9:2"), 10))); |
| 210 } |
| 211 |
| 212 TEST_F(ContactProviderTest, Basic) { |
| 213 const std::string kContactId1 = "contact_1"; |
| 214 scoped_ptr<contacts::Contact> contact1(new contacts::Contact); |
| 215 InitContact(kContactId1, "Bob Smith", "Bob", "Smith", contact1.get()); |
| 216 |
| 217 const std::string kContactId2 = "contact_2"; |
| 218 scoped_ptr<contacts::Contact> contact2(new contacts::Contact); |
| 219 InitContact(kContactId2, "Dr. Jane Doe", "Jane", "Doe", contact2.get()); |
| 220 |
| 221 contacts::ContactPointers contacts; |
| 222 contacts.push_back(contact1.get()); |
| 223 contacts.push_back(contact2.get()); |
| 224 contact_manager_->SetContacts(contacts); |
| 225 contact_manager_->NotifyObserversAboutUpdatedContacts(); |
| 226 |
| 227 StartQuery("b"); |
| 228 EXPECT_EQ( |
| 229 contacts::test::VarContactsToString(1, contact1.get()), |
| 230 contacts::test::ContactsToString(GetMatchedContacts())); |
| 231 |
| 232 StartQuery("bob"); |
| 233 EXPECT_EQ( |
| 234 contacts::test::VarContactsToString(1, contact1.get()), |
| 235 contacts::test::ContactsToString(GetMatchedContacts())); |
| 236 |
| 237 StartQuery("bob smith"); |
| 238 EXPECT_EQ( |
| 239 contacts::test::VarContactsToString(1, contact1.get()), |
| 240 contacts::test::ContactsToString(GetMatchedContacts())); |
| 241 |
| 242 StartQuery("sm"); |
| 243 EXPECT_EQ( |
| 244 contacts::test::VarContactsToString(1, contact1.get()), |
| 245 contacts::test::ContactsToString(GetMatchedContacts())); |
| 246 |
| 247 StartQuery("smith"); |
| 248 EXPECT_EQ( |
| 249 contacts::test::VarContactsToString(1, contact1.get()), |
| 250 contacts::test::ContactsToString(GetMatchedContacts())); |
| 251 |
| 252 StartQuery("smIth BOb"); |
| 253 EXPECT_EQ( |
| 254 contacts::test::VarContactsToString(1, contact1.get()), |
| 255 contacts::test::ContactsToString(GetMatchedContacts())); |
| 256 |
| 257 StartQuery("bobo"); |
| 258 EXPECT_EQ("", contacts::test::ContactsToString(GetMatchedContacts())); |
| 259 |
| 260 StartQuery("mith"); |
| 261 EXPECT_EQ("", contacts::test::ContactsToString(GetMatchedContacts())); |
| 262 |
| 263 StartQuery("dr"); |
| 264 EXPECT_EQ( |
| 265 contacts::test::VarContactsToString(1, contact2.get()), |
| 266 contacts::test::ContactsToString(GetMatchedContacts())); |
| 267 |
| 268 StartQuery("dr. j"); |
| 269 EXPECT_EQ( |
| 270 contacts::test::VarContactsToString(1, contact2.get()), |
| 271 contacts::test::ContactsToString(GetMatchedContacts())); |
| 272 |
| 273 StartQuery("jane"); |
| 274 EXPECT_EQ( |
| 275 contacts::test::VarContactsToString(1, contact2.get()), |
| 276 contacts::test::ContactsToString(GetMatchedContacts())); |
| 277 |
| 278 StartQuery("doe"); |
| 279 EXPECT_EQ( |
| 280 contacts::test::VarContactsToString(1, contact2.get()), |
| 281 contacts::test::ContactsToString(GetMatchedContacts())); |
| 282 } |
OLD | NEW |