| 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 <cmath> | |
| 8 #include <map> | |
| 9 #include <string> | |
| 10 #include <vector> | |
| 11 | |
| 12 #include "base/memory/scoped_ptr.h" | |
| 13 #include "base/message_loop/message_loop.h" | |
| 14 #include "base/strings/string16.h" | |
| 15 #include "base/strings/string_number_conversions.h" | |
| 16 #include "base/strings/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 // Initializes |contact| with the passed-in data. | |
| 35 void InitContact(const std::string& contact_id, | |
| 36 const std::string& full_name, | |
| 37 const std::string& given_name, | |
| 38 const std::string& family_name, | |
| 39 contacts::Contact* contact) { | |
| 40 contact->set_contact_id(contact_id); | |
| 41 contact->set_full_name(full_name); | |
| 42 contact->set_given_name(given_name); | |
| 43 contact->set_family_name(family_name); | |
| 44 } | |
| 45 | |
| 46 } // namespace | |
| 47 | |
| 48 class ContactProviderTest : public testing::Test { | |
| 49 public: | |
| 50 ContactProviderTest() : ui_thread_(BrowserThread::UI, &message_loop_) {} | |
| 51 virtual ~ContactProviderTest() {} | |
| 52 | |
| 53 protected: | |
| 54 // testing::Test implementation. | |
| 55 virtual void SetUp() OVERRIDE { | |
| 56 profile_manager_.reset( | |
| 57 new TestingProfileManager(TestingBrowserProcess::GetGlobal())); | |
| 58 ASSERT_TRUE(profile_manager_->SetUp()); | |
| 59 profile_ = profile_manager_->CreateTestingProfile("test_profile"); | |
| 60 contact_manager_.reset(new contacts::ContactManagerStub(profile_)); | |
| 61 contact_provider_ = | |
| 62 new ContactProvider(NULL, profile_, contact_manager_->GetWeakPtr()); | |
| 63 } | |
| 64 | |
| 65 // Starts a (synchronous) query for |utf8_text| in |contact_provider_|. | |
| 66 void StartQuery(const std::string& utf8_text) { | |
| 67 contact_provider_->Start( | |
| 68 AutocompleteInput(base::UTF8ToUTF16(utf8_text), | |
| 69 base::string16::npos, | |
| 70 base::string16(), | |
| 71 GURL(), | |
| 72 AutocompleteInput::INVALID_SPEC, | |
| 73 false, | |
| 74 false, | |
| 75 false, | |
| 76 AutocompleteInput::ALL_MATCHES), | |
| 77 false); // minimal_changes | |
| 78 } | |
| 79 | |
| 80 // Returns the contact ID in |match|'s additional info, or an empty string if | |
| 81 // no ID is present. | |
| 82 std::string GetContactIdFromMatch(const AutocompleteMatch& match) { | |
| 83 AutocompleteMatch::AdditionalInfo::const_iterator it = | |
| 84 match.additional_info.find(ContactProvider::kMatchContactIdKey); | |
| 85 return it != match.additional_info.end() ? it->second : std::string(); | |
| 86 } | |
| 87 | |
| 88 // Returns pointers to all of the Contact objects referenced in | |
| 89 // |contact_provider_|'s current results. | |
| 90 contacts::ContactPointers GetMatchedContacts() { | |
| 91 contacts::ContactPointers contacts; | |
| 92 const ACMatches& matches = contact_provider_->matches(); | |
| 93 for (size_t i = 0; i < matches.size(); ++i) { | |
| 94 const contacts::Contact* contact = contact_manager_->GetContactById( | |
| 95 profile_, GetContactIdFromMatch(matches[i])); | |
| 96 DCHECK(contact) << "Unable to find contact for match " << i; | |
| 97 contacts.push_back(contact); | |
| 98 } | |
| 99 return contacts; | |
| 100 } | |
| 101 | |
| 102 // Returns a semicolon-separated string containing string representations (as | |
| 103 // provided by AutocompleteMatch::ClassificationsToString()) of the | |
| 104 // |contents_class| fields of all current matches. Results are sorted by | |
| 105 // contact ID. | |
| 106 std::string GetMatchClassifications() { | |
| 107 typedef std::map<std::string, std::string> StringMap; | |
| 108 StringMap contact_id_classifications; | |
| 109 const ACMatches& matches = contact_provider_->matches(); | |
| 110 for (size_t i = 0; i < matches.size(); ++i) { | |
| 111 std::string id = GetContactIdFromMatch(matches[i]); | |
| 112 DCHECK(!id.empty()) << "Match " << i << " lacks contact ID"; | |
| 113 contact_id_classifications[id] = AutocompleteMatch:: | |
| 114 ClassificationsToString(matches[i].contents_class); | |
| 115 } | |
| 116 | |
| 117 std::string result; | |
| 118 for (StringMap::const_iterator it = contact_id_classifications.begin(); | |
| 119 it != contact_id_classifications.end(); ++it) { | |
| 120 if (!result.empty()) | |
| 121 result += ";"; | |
| 122 result += it->second; | |
| 123 } | |
| 124 return result; | |
| 125 } | |
| 126 | |
| 127 base::MessageLoopForUI message_loop_; | |
| 128 content::TestBrowserThread ui_thread_; | |
| 129 | |
| 130 scoped_ptr<TestingProfileManager> profile_manager_; | |
| 131 TestingProfile* profile_; | |
| 132 | |
| 133 scoped_ptr<contacts::ContactManagerStub> contact_manager_; | |
| 134 scoped_refptr<ContactProvider> contact_provider_; | |
| 135 }; | |
| 136 | |
| 137 TEST_F(ContactProviderTest, BasicMatching) { | |
| 138 const std::string kContactId1 = "contact_1"; | |
| 139 scoped_ptr<contacts::Contact> contact1(new contacts::Contact); | |
| 140 InitContact(kContactId1, "Bob Smith", "Bob", "Smith", contact1.get()); | |
| 141 | |
| 142 const std::string kContactId2 = "contact_2"; | |
| 143 scoped_ptr<contacts::Contact> contact2(new contacts::Contact); | |
| 144 InitContact(kContactId2, "Dr. Jane Smith", "Jane", "Smith", contact2.get()); | |
| 145 | |
| 146 contacts::ContactPointers contacts; | |
| 147 contacts.push_back(contact1.get()); | |
| 148 contacts.push_back(contact2.get()); | |
| 149 contact_manager_->SetContacts(contacts); | |
| 150 contact_manager_->NotifyObserversAboutUpdatedContacts(); | |
| 151 | |
| 152 StartQuery("b"); | |
| 153 EXPECT_EQ( | |
| 154 contacts::test::VarContactsToString(1, contact1.get()), | |
| 155 contacts::test::ContactsToString(GetMatchedContacts())); | |
| 156 EXPECT_EQ("0,2,1,0", GetMatchClassifications()); | |
| 157 | |
| 158 StartQuery("bob"); | |
| 159 EXPECT_EQ( | |
| 160 contacts::test::VarContactsToString(1, contact1.get()), | |
| 161 contacts::test::ContactsToString(GetMatchedContacts())); | |
| 162 EXPECT_EQ("0,2,3,0", GetMatchClassifications()); | |
| 163 | |
| 164 StartQuery("bob smith"); | |
| 165 EXPECT_EQ( | |
| 166 contacts::test::VarContactsToString(1, contact1.get()), | |
| 167 contacts::test::ContactsToString(GetMatchedContacts())); | |
| 168 EXPECT_EQ("0,2", GetMatchClassifications()); | |
| 169 | |
| 170 StartQuery("sm"); | |
| 171 EXPECT_EQ( | |
| 172 contacts::test::VarContactsToString(2, contact1.get(), contact2.get()), | |
| 173 contacts::test::ContactsToString(GetMatchedContacts())); | |
| 174 EXPECT_EQ("0,0,4,2,6,0;" "0,0,9,2,11,0", GetMatchClassifications()); | |
| 175 | |
| 176 StartQuery("smith"); | |
| 177 EXPECT_EQ( | |
| 178 contacts::test::VarContactsToString(2, contact1.get(), contact2.get()), | |
| 179 contacts::test::ContactsToString(GetMatchedContacts())); | |
| 180 EXPECT_EQ("0,0,4,2;" "0,0,9,2", GetMatchClassifications()); | |
| 181 | |
| 182 StartQuery("smIth BOb"); | |
| 183 EXPECT_EQ( | |
| 184 contacts::test::VarContactsToString(1, contact1.get()), | |
| 185 contacts::test::ContactsToString(GetMatchedContacts())); | |
| 186 EXPECT_EQ("0,2,3,0,4,2", GetMatchClassifications()); | |
| 187 | |
| 188 StartQuery("bobo"); | |
| 189 EXPECT_EQ("", contacts::test::ContactsToString(GetMatchedContacts())); | |
| 190 EXPECT_EQ("", GetMatchClassifications()); | |
| 191 | |
| 192 StartQuery("mith"); | |
| 193 EXPECT_EQ("", contacts::test::ContactsToString(GetMatchedContacts())); | |
| 194 EXPECT_EQ("", GetMatchClassifications()); | |
| 195 | |
| 196 StartQuery("dr"); | |
| 197 EXPECT_EQ( | |
| 198 contacts::test::VarContactsToString(1, contact2.get()), | |
| 199 contacts::test::ContactsToString(GetMatchedContacts())); | |
| 200 EXPECT_EQ("0,2,2,0", GetMatchClassifications()); | |
| 201 | |
| 202 StartQuery("dr. j"); | |
| 203 EXPECT_EQ( | |
| 204 contacts::test::VarContactsToString(1, contact2.get()), | |
| 205 contacts::test::ContactsToString(GetMatchedContacts())); | |
| 206 EXPECT_EQ("0,2,5,0", GetMatchClassifications()); | |
| 207 | |
| 208 StartQuery("jane"); | |
| 209 EXPECT_EQ( | |
| 210 contacts::test::VarContactsToString(1, contact2.get()), | |
| 211 contacts::test::ContactsToString(GetMatchedContacts())); | |
| 212 EXPECT_EQ("0,0,4,2,8,0", GetMatchClassifications()); | |
| 213 } | |
| 214 | |
| 215 TEST_F(ContactProviderTest, Collation) { | |
| 216 scoped_ptr<contacts::Contact> contact(new contacts::Contact); | |
| 217 InitContact("1", "Bj\xC3\xB6rn Adelsv\xC3\xA4rd", | |
| 218 "Bj\xC3\xB6rn", "Adelsv\xC3\xA4rd", | |
| 219 contact.get()); | |
| 220 | |
| 221 contacts::ContactPointers contacts; | |
| 222 contacts.push_back(contact.get()); | |
| 223 contact_manager_->SetContacts(contacts); | |
| 224 contact_manager_->NotifyObserversAboutUpdatedContacts(); | |
| 225 | |
| 226 StartQuery("bjorn"); | |
| 227 EXPECT_EQ( | |
| 228 contacts::test::VarContactsToString(1, contact.get()), | |
| 229 contacts::test::ContactsToString(GetMatchedContacts())); | |
| 230 EXPECT_EQ("0,2,5,0", GetMatchClassifications()); | |
| 231 | |
| 232 StartQuery("adelsvard"); | |
| 233 EXPECT_EQ( | |
| 234 contacts::test::VarContactsToString(1, contact.get()), | |
| 235 contacts::test::ContactsToString(GetMatchedContacts())); | |
| 236 EXPECT_EQ("0,0,6,2", GetMatchClassifications()); | |
| 237 } | |
| 238 | |
| 239 TEST_F(ContactProviderTest, Relevance) { | |
| 240 // Create more contacts than the maximum number of results that an | |
| 241 // AutocompleteProvider should return. Give them all the same family name and | |
| 242 // ascending affinities from 0.0 to 1.0. | |
| 243 const size_t kNumContacts = AutocompleteProvider::kMaxMatches + 1; | |
| 244 const std::string kFamilyName = "Jones"; | |
| 245 | |
| 246 ScopedVector<contacts::Contact> contacts; | |
| 247 contacts::ContactPointers contact_pointers; | |
| 248 for (size_t i = 0; i < kNumContacts; ++i) { | |
| 249 contacts::Contact* contact = new contacts::Contact; | |
| 250 std::string id_string = base::IntToString(static_cast<int>(i)); | |
| 251 InitContact(id_string, id_string, kFamilyName, | |
| 252 id_string + " " + kFamilyName, contact); | |
| 253 contact->set_affinity(static_cast<float>(i) / kNumContacts); | |
| 254 contacts.push_back(contact); | |
| 255 contact_pointers.push_back(contact); | |
| 256 } | |
| 257 | |
| 258 contact_manager_->SetContacts(contact_pointers); | |
| 259 contact_manager_->NotifyObserversAboutUpdatedContacts(); | |
| 260 | |
| 261 // Do a search for the family name and check that the total number of results | |
| 262 // is limited as expected and that the results are ordered by descending | |
| 263 // affinity. | |
| 264 StartQuery(kFamilyName); | |
| 265 const ACMatches& matches = contact_provider_->matches(); | |
| 266 ASSERT_EQ(AutocompleteProvider::kMaxMatches, matches.size()); | |
| 267 | |
| 268 int previous_relevance = 0; | |
| 269 for (size_t i = 0; i < matches.size(); ++i) { | |
| 270 const contacts::Contact& exp_contact = | |
| 271 *(contacts[kNumContacts - 1 - i]); | |
| 272 std::string match_id = GetContactIdFromMatch(matches[i]); | |
| 273 EXPECT_EQ(exp_contact.contact_id(), match_id) | |
| 274 << "Expected contact ID " << exp_contact.contact_id() | |
| 275 << " for match " << i << " but got " << match_id << " instead"; | |
| 276 if (i > 0) { | |
| 277 EXPECT_LE(matches[i].relevance, previous_relevance) | |
| 278 << "Match " << i << " has greater relevance than previous match"; | |
| 279 } | |
| 280 EXPECT_FALSE(matches[i].allowed_to_be_default_match); | |
| 281 previous_relevance = matches[i].relevance; | |
| 282 } | |
| 283 } | |
| OLD | NEW |