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/profiles/profile_info_cache_unittest.h"
6
7#include <vector>
8
9#include "base/command_line.h"
10#include "base/files/file_util.h"
11#include "base/prefs/testing_pref_service.h"
12#include "base/strings/stringprintf.h"
13#include "base/strings/utf_string_conversions.h"
14#include "base/time/time.h"
15#include "chrome/browser/browser_process.h"
16#include "chrome/browser/chrome_notification_types.h"
17#include "chrome/browser/prefs/pref_service_syncable.h"
18#include "chrome/browser/profiles/profile_avatar_downloader.h"
19#include "chrome/browser/profiles/profile_avatar_icon_util.h"
20#include "chrome/browser/profiles/profile_info_cache.h"
21#include "chrome/browser/profiles/profile_manager.h"
22#include "chrome/common/chrome_switches.h"
23#include "chrome/test/base/testing_browser_process.h"
24#include "components/signin/core/common/profile_management_switches.h"
25#include "content/public/browser/notification_observer.h"
26#include "content/public/browser/notification_registrar.h"
27#include "content/public/browser/notification_service.h"
28#include "content/public/test/test_browser_thread_bundle.h"
29#include "content/public/test/test_utils.h"
30#include "third_party/skia/include/core/SkBitmap.h"
31#include "ui/base/resource/resource_bundle.h"
32#include "ui/gfx/image/image.h"
33#include "ui/gfx/image/image_unittest_util.h"
34
35using base::ASCIIToUTF16;
36using base::UTF8ToUTF16;
37using content::BrowserThread;
38
39ProfileNameVerifierObserver::ProfileNameVerifierObserver(
40    TestingProfileManager* testing_profile_manager)
41    : testing_profile_manager_(testing_profile_manager) {
42  DCHECK(testing_profile_manager_);
43}
44
45ProfileNameVerifierObserver::~ProfileNameVerifierObserver() {
46}
47
48void ProfileNameVerifierObserver::OnProfileAdded(
49    const base::FilePath& profile_path) {
50  base::string16 profile_name = GetCache()->GetNameOfProfileAtIndex(
51      GetCache()->GetIndexOfProfileWithPath(profile_path));
52  EXPECT_TRUE(profile_names_.find(profile_name) == profile_names_.end());
53  profile_names_.insert(profile_name);
54}
55
56void ProfileNameVerifierObserver::OnProfileWillBeRemoved(
57    const base::FilePath& profile_path) {
58  base::string16 profile_name = GetCache()->GetNameOfProfileAtIndex(
59      GetCache()->GetIndexOfProfileWithPath(profile_path));
60  EXPECT_TRUE(profile_names_.find(profile_name) != profile_names_.end());
61  profile_names_.erase(profile_name);
62}
63
64void ProfileNameVerifierObserver::OnProfileWasRemoved(
65    const base::FilePath& profile_path,
66    const base::string16& profile_name) {
67  EXPECT_TRUE(profile_names_.find(profile_name) == profile_names_.end());
68}
69
70void ProfileNameVerifierObserver::OnProfileNameChanged(
71    const base::FilePath& profile_path,
72    const base::string16& old_profile_name) {
73  base::string16 new_profile_name = GetCache()->GetNameOfProfileAtIndex(
74      GetCache()->GetIndexOfProfileWithPath(profile_path));
75  EXPECT_TRUE(profile_names_.find(old_profile_name) != profile_names_.end());
76  EXPECT_TRUE(profile_names_.find(new_profile_name) == profile_names_.end());
77  profile_names_.erase(old_profile_name);
78  profile_names_.insert(new_profile_name);
79}
80
81void ProfileNameVerifierObserver::OnProfileAvatarChanged(
82    const base::FilePath& profile_path) {
83  base::string16 profile_name = GetCache()->GetNameOfProfileAtIndex(
84      GetCache()->GetIndexOfProfileWithPath(profile_path));
85  EXPECT_TRUE(profile_names_.find(profile_name) != profile_names_.end());
86}
87
88ProfileInfoCache* ProfileNameVerifierObserver::GetCache() {
89  return testing_profile_manager_->profile_info_cache();
90}
91
92ProfileInfoCacheTest::ProfileInfoCacheTest()
93    : testing_profile_manager_(TestingBrowserProcess::GetGlobal()),
94      name_observer_(&testing_profile_manager_) {
95}
96
97ProfileInfoCacheTest::~ProfileInfoCacheTest() {
98}
99
100void ProfileInfoCacheTest::SetUp() {
101  ASSERT_TRUE(testing_profile_manager_.SetUp());
102  testing_profile_manager_.profile_info_cache()->AddObserver(&name_observer_);
103}
104
105void ProfileInfoCacheTest::TearDown() {
106  // Drain the UI thread to make sure all tasks are completed. This prevents
107  // memory leaks.
108  base::RunLoop().RunUntilIdle();
109}
110
111ProfileInfoCache* ProfileInfoCacheTest::GetCache() {
112  return testing_profile_manager_.profile_info_cache();
113}
114
115base::FilePath ProfileInfoCacheTest::GetProfilePath(
116    const std::string& base_name) {
117  return testing_profile_manager_.profile_manager()->user_data_dir().
118      AppendASCII(base_name);
119}
120
121void ProfileInfoCacheTest::ResetCache() {
122  testing_profile_manager_.DeleteProfileInfoCache();
123}
124
125TEST_F(ProfileInfoCacheTest, AddProfiles) {
126  EXPECT_EQ(0u, GetCache()->GetNumberOfProfiles());
127
128  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
129  for (uint32 i = 0; i < 4; ++i) {
130    base::FilePath profile_path =
131        GetProfilePath(base::StringPrintf("path_%ud", i));
132    base::string16 profile_name =
133        ASCIIToUTF16(base::StringPrintf("name_%ud", i));
134    const SkBitmap* icon = rb.GetImageNamed(
135        profiles::GetDefaultAvatarIconResourceIDAtIndex(
136            i)).ToSkBitmap();
137    std::string supervised_user_id = i == 3 ? "TEST_ID" : "";
138
139    GetCache()->AddProfileToCache(profile_path, profile_name, base::string16(),
140                                  i, supervised_user_id);
141    GetCache()->SetBackgroundStatusOfProfileAtIndex(i, true);
142    base::string16 gaia_name = ASCIIToUTF16(base::StringPrintf("gaia_%ud", i));
143    GetCache()->SetGAIANameOfProfileAtIndex(i, gaia_name);
144
145    EXPECT_EQ(i + 1, GetCache()->GetNumberOfProfiles());
146    EXPECT_EQ(profile_name, GetCache()->GetNameOfProfileAtIndex(i));
147    EXPECT_EQ(profile_path, GetCache()->GetPathOfProfileAtIndex(i));
148    const SkBitmap* actual_icon =
149        GetCache()->GetAvatarIconOfProfileAtIndex(i).ToSkBitmap();
150    EXPECT_EQ(icon->width(), actual_icon->width());
151    EXPECT_EQ(icon->height(), actual_icon->height());
152    EXPECT_EQ(i == 3, GetCache()->ProfileIsSupervisedAtIndex(i));
153    EXPECT_EQ(i == 3, GetCache()->IsOmittedProfileAtIndex(i));
154    EXPECT_EQ(supervised_user_id,
155              GetCache()->GetSupervisedUserIdOfProfileAtIndex(i));
156  }
157
158  // Reset the cache and test the it reloads correctly.
159  ResetCache();
160
161  EXPECT_EQ(4u, GetCache()->GetNumberOfProfiles());
162  for (uint32 i = 0; i < 4; ++i) {
163    base::FilePath profile_path =
164          GetProfilePath(base::StringPrintf("path_%ud", i));
165    EXPECT_EQ(i, GetCache()->GetIndexOfProfileWithPath(profile_path));
166    base::string16 profile_name =
167        ASCIIToUTF16(base::StringPrintf("name_%ud", i));
168    EXPECT_EQ(profile_name, GetCache()->GetNameOfProfileAtIndex(i));
169    EXPECT_EQ(i, GetCache()->GetAvatarIconIndexOfProfileAtIndex(i));
170    EXPECT_EQ(true, GetCache()->GetBackgroundStatusOfProfileAtIndex(i));
171    base::string16 gaia_name = ASCIIToUTF16(base::StringPrintf("gaia_%ud", i));
172    EXPECT_EQ(gaia_name, GetCache()->GetGAIANameOfProfileAtIndex(i));
173  }
174}
175
176TEST_F(ProfileInfoCacheTest, DeleteProfile) {
177  EXPECT_EQ(0u, GetCache()->GetNumberOfProfiles());
178
179  base::FilePath path_1 = GetProfilePath("path_1");
180  GetCache()->AddProfileToCache(path_1, ASCIIToUTF16("name_1"),
181                                base::string16(), 0, std::string());
182  EXPECT_EQ(1u, GetCache()->GetNumberOfProfiles());
183
184  base::FilePath path_2 = GetProfilePath("path_2");
185  base::string16 name_2 = ASCIIToUTF16("name_2");
186  GetCache()->AddProfileToCache(path_2, name_2, base::string16(), 0,
187                                std::string());
188  EXPECT_EQ(2u, GetCache()->GetNumberOfProfiles());
189
190  GetCache()->DeleteProfileFromCache(path_1);
191  EXPECT_EQ(1u, GetCache()->GetNumberOfProfiles());
192  EXPECT_EQ(name_2, GetCache()->GetNameOfProfileAtIndex(0));
193
194  GetCache()->DeleteProfileFromCache(path_2);
195  EXPECT_EQ(0u, GetCache()->GetNumberOfProfiles());
196}
197
198TEST_F(ProfileInfoCacheTest, MutateProfile) {
199  GetCache()->AddProfileToCache(
200      GetProfilePath("path_1"), ASCIIToUTF16("name_1"),
201      base::string16(), 0, std::string());
202  GetCache()->AddProfileToCache(
203      GetProfilePath("path_2"), ASCIIToUTF16("name_2"),
204      base::string16(), 0, std::string());
205
206  base::string16 new_name = ASCIIToUTF16("new_name");
207  GetCache()->SetNameOfProfileAtIndex(1, new_name);
208  EXPECT_EQ(new_name, GetCache()->GetNameOfProfileAtIndex(1));
209  EXPECT_NE(new_name, GetCache()->GetNameOfProfileAtIndex(0));
210
211  base::string16 new_user_name = ASCIIToUTF16("user_name");
212  GetCache()->SetUserNameOfProfileAtIndex(1, new_user_name);
213  EXPECT_EQ(new_user_name, GetCache()->GetUserNameOfProfileAtIndex(1));
214  EXPECT_NE(new_user_name, GetCache()->GetUserNameOfProfileAtIndex(0));
215
216  size_t new_icon_index = 3;
217  GetCache()->SetAvatarIconOfProfileAtIndex(1, new_icon_index);
218  // Not much to test.
219  GetCache()->GetAvatarIconOfProfileAtIndex(1);
220}
221
222TEST_F(ProfileInfoCacheTest, Sort) {
223  base::string16 name_a = ASCIIToUTF16("apple");
224  GetCache()->AddProfileToCache(
225      GetProfilePath("path_a"), name_a, base::string16(), 0, std::string());
226
227  base::string16 name_c = ASCIIToUTF16("cat");
228  GetCache()->AddProfileToCache(
229      GetProfilePath("path_c"), name_c, base::string16(), 0, std::string());
230
231  // Sanity check the initial order.
232  EXPECT_EQ(name_a, GetCache()->GetNameOfProfileAtIndex(0));
233  EXPECT_EQ(name_c, GetCache()->GetNameOfProfileAtIndex(1));
234
235  // Add a new profile (start with a capital to test case insensitive sorting.
236  base::string16 name_b = ASCIIToUTF16("Banana");
237  GetCache()->AddProfileToCache(
238      GetProfilePath("path_b"), name_b, base::string16(), 0, std::string());
239
240  // Verify the new order.
241  EXPECT_EQ(name_a, GetCache()->GetNameOfProfileAtIndex(0));
242  EXPECT_EQ(name_b, GetCache()->GetNameOfProfileAtIndex(1));
243  EXPECT_EQ(name_c, GetCache()->GetNameOfProfileAtIndex(2));
244
245  // Change the name of an existing profile.
246  name_a = UTF8ToUTF16("dog");
247  GetCache()->SetNameOfProfileAtIndex(0, name_a);
248
249  // Verify the new order.
250  EXPECT_EQ(name_b, GetCache()->GetNameOfProfileAtIndex(0));
251  EXPECT_EQ(name_c, GetCache()->GetNameOfProfileAtIndex(1));
252  EXPECT_EQ(name_a, GetCache()->GetNameOfProfileAtIndex(2));
253
254  // Delete a profile.
255  GetCache()->DeleteProfileFromCache(GetProfilePath("path_c"));
256
257  // Verify the new order.
258  EXPECT_EQ(name_b, GetCache()->GetNameOfProfileAtIndex(0));
259  EXPECT_EQ(name_a, GetCache()->GetNameOfProfileAtIndex(1));
260}
261
262TEST_F(ProfileInfoCacheTest, BackgroundModeStatus) {
263  GetCache()->AddProfileToCache(
264      GetProfilePath("path_1"), ASCIIToUTF16("name_1"),
265      base::string16(), 0, std::string());
266  GetCache()->AddProfileToCache(
267      GetProfilePath("path_2"), ASCIIToUTF16("name_2"),
268      base::string16(), 0, std::string());
269
270  EXPECT_FALSE(GetCache()->GetBackgroundStatusOfProfileAtIndex(0));
271  EXPECT_FALSE(GetCache()->GetBackgroundStatusOfProfileAtIndex(1));
272
273  GetCache()->SetBackgroundStatusOfProfileAtIndex(1, true);
274
275  EXPECT_FALSE(GetCache()->GetBackgroundStatusOfProfileAtIndex(0));
276  EXPECT_TRUE(GetCache()->GetBackgroundStatusOfProfileAtIndex(1));
277
278  GetCache()->SetBackgroundStatusOfProfileAtIndex(0, true);
279
280  EXPECT_TRUE(GetCache()->GetBackgroundStatusOfProfileAtIndex(0));
281  EXPECT_TRUE(GetCache()->GetBackgroundStatusOfProfileAtIndex(1));
282
283  GetCache()->SetBackgroundStatusOfProfileAtIndex(1, false);
284
285  EXPECT_TRUE(GetCache()->GetBackgroundStatusOfProfileAtIndex(0));
286  EXPECT_FALSE(GetCache()->GetBackgroundStatusOfProfileAtIndex(1));
287}
288
289TEST_F(ProfileInfoCacheTest, ProfileActiveTime) {
290  GetCache()->AddProfileToCache(
291      GetProfilePath("path_1"), ASCIIToUTF16("name_1"),
292      base::string16(), 0, std::string());
293  EXPECT_EQ(base::Time(), GetCache()->GetProfileActiveTimeAtIndex(0));
294  // Before & After times are artificially shifted because just relying upon
295  // the system time can yield problems due to inaccuracies in the
296  // underlying storage system (which uses a double with only 52 bits of
297  // precision to store the 64-bit "time" number).  http://crbug.com/346827
298  base::Time before = base::Time::Now();
299  before -= base::TimeDelta::FromSeconds(1);
300  GetCache()->SetProfileActiveTimeAtIndex(0);
301  base::Time after = base::Time::Now();
302  after += base::TimeDelta::FromSeconds(1);
303  EXPECT_LE(before, GetCache()->GetProfileActiveTimeAtIndex(0));
304  EXPECT_GE(after, GetCache()->GetProfileActiveTimeAtIndex(0));
305}
306
307TEST_F(ProfileInfoCacheTest, GAIAName) {
308  GetCache()->AddProfileToCache(
309      GetProfilePath("path_1"), ASCIIToUTF16("Person 1"),
310      base::string16(), 0, std::string());
311  base::string16 profile_name(ASCIIToUTF16("Person 2"));
312  GetCache()->AddProfileToCache(
313      GetProfilePath("path_2"), profile_name, base::string16(), 0,
314      std::string());
315
316  int index1 = GetCache()->GetIndexOfProfileWithPath(GetProfilePath("path_1"));
317  int index2 = GetCache()->GetIndexOfProfileWithPath(GetProfilePath("path_2"));
318
319  // Sanity check.
320  EXPECT_TRUE(GetCache()->GetGAIANameOfProfileAtIndex(index1).empty());
321  EXPECT_TRUE(GetCache()->GetGAIANameOfProfileAtIndex(index2).empty());
322
323  // Set GAIA name. This re-sorts the cache.
324  base::string16 gaia_name(ASCIIToUTF16("Pat Smith"));
325  GetCache()->SetGAIANameOfProfileAtIndex(index2, gaia_name);
326  index1 = GetCache()->GetIndexOfProfileWithPath(GetProfilePath("path_1"));
327  index2 = GetCache()->GetIndexOfProfileWithPath(GetProfilePath("path_2"));
328
329  // Since there is a GAIA name, we use that as a display name.
330  EXPECT_TRUE(GetCache()->GetGAIANameOfProfileAtIndex(index1).empty());
331  EXPECT_EQ(gaia_name, GetCache()->GetGAIANameOfProfileAtIndex(index2));
332  EXPECT_EQ(gaia_name, GetCache()->GetNameOfProfileAtIndex(index2));
333
334  // Don't use GAIA name as profile name. This re-sorts the cache.
335  base::string16 custom_name(ASCIIToUTF16("Custom name"));
336  GetCache()->SetNameOfProfileAtIndex(index2, custom_name);
337  GetCache()->SetProfileIsUsingDefaultNameAtIndex(index2, false);
338
339  index1 = GetCache()->GetIndexOfProfileWithPath(GetProfilePath("path_1"));
340  index2 = GetCache()->GetIndexOfProfileWithPath(GetProfilePath("path_2"));
341
342  EXPECT_EQ(custom_name, GetCache()->GetNameOfProfileAtIndex(index2));
343  EXPECT_EQ(gaia_name, GetCache()->GetGAIANameOfProfileAtIndex(index2));
344}
345
346TEST_F(ProfileInfoCacheTest, GAIAPicture) {
347  const int kDefaultAvatarIndex = 0;
348  const int kOtherAvatarIndex = 1;
349  const int kGaiaPictureSize = 256;  // Standard size of a Gaia account picture.
350  GetCache()->AddProfileToCache(
351      GetProfilePath("path_1"), ASCIIToUTF16("name_1"),
352      base::string16(), kDefaultAvatarIndex, std::string());
353  GetCache()->AddProfileToCache(
354      GetProfilePath("path_2"), ASCIIToUTF16("name_2"),
355      base::string16(), kDefaultAvatarIndex, std::string());
356
357  // Sanity check.
358  EXPECT_EQ(NULL, GetCache()->GetGAIAPictureOfProfileAtIndex(0));
359  EXPECT_EQ(NULL, GetCache()->GetGAIAPictureOfProfileAtIndex(1));
360  EXPECT_FALSE(GetCache()->IsUsingGAIAPictureOfProfileAtIndex(0));
361  EXPECT_FALSE(GetCache()->IsUsingGAIAPictureOfProfileAtIndex(1));
362
363  // The profile icon should be the default one.
364  EXPECT_TRUE(GetCache()->ProfileIsUsingDefaultAvatarAtIndex(0));
365  EXPECT_TRUE(GetCache()->ProfileIsUsingDefaultAvatarAtIndex(1));
366  int default_avatar_id =
367      profiles::GetDefaultAvatarIconResourceIDAtIndex(kDefaultAvatarIndex);
368  const gfx::Image& default_avatar_image(
369      ResourceBundle::GetSharedInstance().GetImageNamed(default_avatar_id));
370  EXPECT_TRUE(gfx::test::IsEqual(
371      default_avatar_image, GetCache()->GetAvatarIconOfProfileAtIndex(1)));
372
373  // Set GAIA picture.
374  gfx::Image gaia_image(gfx::test::CreateImage(
375      kGaiaPictureSize, kGaiaPictureSize));
376  GetCache()->SetGAIAPictureOfProfileAtIndex(1, &gaia_image);
377  EXPECT_EQ(NULL, GetCache()->GetGAIAPictureOfProfileAtIndex(0));
378  EXPECT_TRUE(gfx::test::IsEqual(
379      gaia_image, *GetCache()->GetGAIAPictureOfProfileAtIndex(1)));
380  // Since we're still using the default avatar, the GAIA image should be
381  // preferred over the generic avatar image.
382  EXPECT_TRUE(GetCache()->ProfileIsUsingDefaultAvatarAtIndex(1));
383  EXPECT_TRUE(GetCache()->IsUsingGAIAPictureOfProfileAtIndex(1));
384  EXPECT_TRUE(gfx::test::IsEqual(
385      gaia_image, GetCache()->GetAvatarIconOfProfileAtIndex(1)));
386
387  // Set a non-default avatar. This should be preferred over the GAIA image.
388  GetCache()->SetAvatarIconOfProfileAtIndex(1, kOtherAvatarIndex);
389  GetCache()->SetProfileIsUsingDefaultAvatarAtIndex(1, false);
390  EXPECT_FALSE(GetCache()->ProfileIsUsingDefaultAvatarAtIndex(1));
391  EXPECT_FALSE(GetCache()->IsUsingGAIAPictureOfProfileAtIndex(1));
392  int other_avatar_id =
393      profiles::GetDefaultAvatarIconResourceIDAtIndex(kOtherAvatarIndex);
394  const gfx::Image& other_avatar_image(
395      ResourceBundle::GetSharedInstance().GetImageNamed(other_avatar_id));
396  EXPECT_TRUE(gfx::test::IsEqual(
397      other_avatar_image, GetCache()->GetAvatarIconOfProfileAtIndex(1)));
398
399  // Explicitly setting the GAIA picture should make it preferred again.
400  GetCache()->SetIsUsingGAIAPictureOfProfileAtIndex(1, true);
401  EXPECT_TRUE(GetCache()->IsUsingGAIAPictureOfProfileAtIndex(1));
402  EXPECT_TRUE(gfx::test::IsEqual(
403      gaia_image, *GetCache()->GetGAIAPictureOfProfileAtIndex(1)));
404  EXPECT_TRUE(gfx::test::IsEqual(
405      gaia_image, GetCache()->GetAvatarIconOfProfileAtIndex(1)));
406
407  // Clearing the IsUsingGAIAPicture flag should result in the generic image
408  // being used again.
409  GetCache()->SetIsUsingGAIAPictureOfProfileAtIndex(1, false);
410  EXPECT_FALSE(GetCache()->IsUsingGAIAPictureOfProfileAtIndex(1));
411  EXPECT_TRUE(gfx::test::IsEqual(
412      gaia_image, *GetCache()->GetGAIAPictureOfProfileAtIndex(1)));
413  EXPECT_TRUE(gfx::test::IsEqual(
414      other_avatar_image, GetCache()->GetAvatarIconOfProfileAtIndex(1)));
415}
416
417TEST_F(ProfileInfoCacheTest, PersistGAIAPicture) {
418  GetCache()->AddProfileToCache(
419      GetProfilePath("path_1"), ASCIIToUTF16("name_1"),
420      base::string16(), 0, std::string());
421  gfx::Image gaia_image(gfx::test::CreateImage());
422
423  content::WindowedNotificationObserver save_observer(
424      chrome::NOTIFICATION_PROFILE_CACHE_PICTURE_SAVED,
425      content::NotificationService::AllSources());
426  GetCache()->SetGAIAPictureOfProfileAtIndex(0, &gaia_image);
427  EXPECT_TRUE(gfx::test::IsEqual(
428      gaia_image, *GetCache()->GetGAIAPictureOfProfileAtIndex(0)));
429
430  // Wait for the file to be written to disk then reset the cache.
431  save_observer.Wait();
432  ResetCache();
433
434  // Try to get the GAIA picture. This should return NULL until the read from
435  // disk is done.
436  content::WindowedNotificationObserver read_observer(
437      chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
438      content::NotificationService::AllSources());
439  EXPECT_EQ(NULL, GetCache()->GetGAIAPictureOfProfileAtIndex(0));
440  read_observer.Wait();
441  EXPECT_TRUE(gfx::test::IsEqual(
442    gaia_image, *GetCache()->GetGAIAPictureOfProfileAtIndex(0)));
443}
444
445TEST_F(ProfileInfoCacheTest, SetSupervisedUserId) {
446  GetCache()->AddProfileToCache(
447      GetProfilePath("test"), ASCIIToUTF16("Test"),
448      base::string16(), 0, std::string());
449  EXPECT_FALSE(GetCache()->ProfileIsSupervisedAtIndex(0));
450
451  GetCache()->SetSupervisedUserIdOfProfileAtIndex(0, "TEST_ID");
452  EXPECT_TRUE(GetCache()->ProfileIsSupervisedAtIndex(0));
453  EXPECT_EQ("TEST_ID", GetCache()->GetSupervisedUserIdOfProfileAtIndex(0));
454
455  ResetCache();
456  EXPECT_TRUE(GetCache()->ProfileIsSupervisedAtIndex(0));
457
458  GetCache()->SetSupervisedUserIdOfProfileAtIndex(0, std::string());
459  EXPECT_FALSE(GetCache()->ProfileIsSupervisedAtIndex(0));
460  EXPECT_EQ("", GetCache()->GetSupervisedUserIdOfProfileAtIndex(0));
461}
462
463TEST_F(ProfileInfoCacheTest, EmptyGAIAInfo) {
464  base::string16 profile_name = ASCIIToUTF16("name_1");
465  int id = profiles::GetDefaultAvatarIconResourceIDAtIndex(0);
466  const gfx::Image& profile_image(
467      ResourceBundle::GetSharedInstance().GetImageNamed(id));
468
469  GetCache()->AddProfileToCache(
470      GetProfilePath("path_1"), profile_name, base::string16(), 0,
471                     std::string());
472
473  // Set empty GAIA info.
474  GetCache()->SetGAIANameOfProfileAtIndex(0, base::string16());
475  GetCache()->SetGAIAPictureOfProfileAtIndex(0, NULL);
476  GetCache()->SetIsUsingGAIAPictureOfProfileAtIndex(0, true);
477
478  // Verify that the profile name and picture are not empty.
479  EXPECT_EQ(profile_name, GetCache()->GetNameOfProfileAtIndex(0));
480  EXPECT_TRUE(gfx::test::IsEqual(
481      profile_image, GetCache()->GetAvatarIconOfProfileAtIndex(0)));
482}
483
484TEST_F(ProfileInfoCacheTest, CreateSupervisedTestingProfile) {
485  testing_profile_manager_.CreateTestingProfile("default");
486  base::string16 supervised_user_name = ASCIIToUTF16("Supervised User");
487  testing_profile_manager_.CreateTestingProfile(
488      "test1", scoped_ptr<PrefServiceSyncable>(),
489      supervised_user_name, 0, "TEST_ID", TestingProfile::TestingFactories());
490  for (size_t i = 0; i < GetCache()->GetNumberOfProfiles(); i++) {
491    bool is_supervised =
492        GetCache()->GetNameOfProfileAtIndex(i) == supervised_user_name;
493    EXPECT_EQ(is_supervised, GetCache()->ProfileIsSupervisedAtIndex(i));
494    std::string supervised_user_id = is_supervised ? "TEST_ID" : "";
495    EXPECT_EQ(supervised_user_id,
496              GetCache()->GetSupervisedUserIdOfProfileAtIndex(i));
497  }
498
499  // Supervised profiles have a custom theme, which needs to be deleted on the
500  // FILE thread. Reset the profile manager now so everything is deleted while
501  // we still have a FILE thread.
502  TestingBrowserProcess::GetGlobal()->SetProfileManager(NULL);
503}
504
505TEST_F(ProfileInfoCacheTest, AddStubProfile) {
506  EXPECT_EQ(0u, GetCache()->GetNumberOfProfiles());
507
508  // Add some profiles with and without a '.' in their paths.
509  const struct {
510    const char* profile_path;
511    const char* profile_name;
512  } kTestCases[] = {
513    { "path.test0", "name_0" },
514    { "path_test1", "name_1" },
515    { "path.test2", "name_2" },
516    { "path_test3", "name_3" },
517  };
518
519  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) {
520    base::FilePath profile_path = GetProfilePath(kTestCases[i].profile_path);
521    base::string16 profile_name = ASCIIToUTF16(kTestCases[i].profile_name);
522
523    GetCache()->AddProfileToCache(profile_path, profile_name, base::string16(),
524                                  i, "");
525
526    EXPECT_EQ(profile_path, GetCache()->GetPathOfProfileAtIndex(i));
527    EXPECT_EQ(profile_name, GetCache()->GetNameOfProfileAtIndex(i));
528  }
529
530  ASSERT_EQ(4U, GetCache()->GetNumberOfProfiles());
531
532  // Check that the profiles can be extracted from the local state.
533  std::vector<base::string16> names = ProfileInfoCache::GetProfileNames();
534  for (size_t i = 0; i < 4; i++)
535    ASSERT_FALSE(names[i].empty());
536}
537
538// High res avatar downloading is only supported on desktop.
539#if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_CHROMEOS)
540TEST_F(ProfileInfoCacheTest, DownloadHighResAvatarTest) {
541  switches::EnableNewAvatarMenuForTesting(CommandLine::ForCurrentProcess());
542
543  EXPECT_EQ(0U, GetCache()->GetNumberOfProfiles());
544  base::FilePath path_1 = GetProfilePath("path_1");
545  GetCache()->AddProfileToCache(path_1, ASCIIToUTF16("name_1"),
546                                base::string16(), 0, std::string());
547  EXPECT_EQ(1U, GetCache()->GetNumberOfProfiles());
548
549  // We haven't downloaded any high-res avatars yet.
550  EXPECT_EQ(0U, GetCache()->cached_avatar_images_.size());
551
552  // After adding a new profile, the download of high-res avatar will be
553  // triggered if the flag kNewAvatarMenu has been set. But the downloader
554  // won't ever call OnFetchComplete in the test.
555  EXPECT_EQ(1U, GetCache()->avatar_images_downloads_in_progress_.size());
556
557  EXPECT_FALSE(GetCache()->GetHighResAvatarOfProfileAtIndex(0));
558
559  // Simulate downloading a high-res avatar.
560  const size_t kIconIndex = 0;
561  ProfileAvatarDownloader avatar_downloader(
562      kIconIndex, GetCache()->GetPathOfProfileAtIndex(0), GetCache());
563
564  // Put a real bitmap into "bitmap".  2x2 bitmap of green 32 bit pixels.
565  SkBitmap bitmap;
566  bitmap.allocN32Pixels(2, 2);
567  bitmap.eraseColor(SK_ColorGREEN);
568
569  avatar_downloader.OnFetchComplete(
570      GURL("http://www.google.com/avatar.png"), &bitmap);
571
572  std::string file_name =
573      profiles::GetDefaultAvatarIconFileNameAtIndex(kIconIndex);
574
575  // The file should have been cached and saved.
576  EXPECT_EQ(1U, GetCache()->avatar_images_downloads_in_progress_.size());
577  EXPECT_EQ(1U, GetCache()->cached_avatar_images_.size());
578  EXPECT_TRUE(GetCache()->GetHighResAvatarOfProfileAtIndex(0));
579  EXPECT_EQ(GetCache()->cached_avatar_images_[file_name],
580      GetCache()->GetHighResAvatarOfProfileAtIndex(0));
581
582  // Make sure everything has completed, and the file has been written to disk.
583  base::RunLoop().RunUntilIdle();
584
585  // Clean up.
586  base::FilePath icon_path =
587      profiles::GetPathOfHighResAvatarAtIndex(kIconIndex);
588  EXPECT_NE(std::string::npos, icon_path.MaybeAsASCII().find(file_name));
589  EXPECT_TRUE(base::PathExists(icon_path));
590  EXPECT_TRUE(base::DeleteFile(icon_path, true));
591  EXPECT_FALSE(base::PathExists(icon_path));
592}
593
594TEST_F(ProfileInfoCacheTest, MigrateLegacyProfileNamesWithNewAvatarMenu) {
595  switches::EnableNewAvatarMenuForTesting(CommandLine::ForCurrentProcess());
596  EXPECT_EQ(0U, GetCache()->GetNumberOfProfiles());
597
598  base::FilePath path_1 = GetProfilePath("path_1");
599  GetCache()->AddProfileToCache(path_1, ASCIIToUTF16("Default Profile"),
600                                base::string16(), 0, std::string());
601  base::FilePath path_2 = GetProfilePath("path_2");
602  GetCache()->AddProfileToCache(path_2, ASCIIToUTF16("First user"),
603                                base::string16(), 1, std::string());
604  base::string16 name_3 = ASCIIToUTF16("Lemonade");
605  base::FilePath path_3 = GetProfilePath("path_3");
606  GetCache()->AddProfileToCache(path_3, name_3,
607                                base::string16(), 2, std::string());
608  base::string16 name_4 = ASCIIToUTF16("Batman");
609  base::FilePath path_4 = GetProfilePath("path_4");
610  GetCache()->AddProfileToCache(path_4, name_4,
611                                base::string16(), 3, std::string());
612  base::string16 name_5 = ASCIIToUTF16("Person 2");
613  base::FilePath path_5 = GetProfilePath("path_5");
614  GetCache()->AddProfileToCache(path_5, name_5,
615                                base::string16(), 2, std::string());
616
617  EXPECT_EQ(5U, GetCache()->GetNumberOfProfiles());
618
619
620  ResetCache();
621
622  // Legacy profile names like "Default Profile" and "First user" should be
623  // migrated to "Person %n" type names.
624  EXPECT_EQ(ASCIIToUTF16("Person 1"), GetCache()->GetNameOfProfileAtIndex(
625      GetCache()->GetIndexOfProfileWithPath(path_1)));
626  EXPECT_EQ(ASCIIToUTF16("Person 3"), GetCache()->GetNameOfProfileAtIndex(
627      GetCache()->GetIndexOfProfileWithPath(path_2)));
628
629  // Other profile names should not be migrated even if they're the old
630  // default cartoon profile names.
631  EXPECT_EQ(name_3, GetCache()->GetNameOfProfileAtIndex(
632      GetCache()->GetIndexOfProfileWithPath(path_3)));
633  EXPECT_EQ(name_4, GetCache()->GetNameOfProfileAtIndex(
634      GetCache()->GetIndexOfProfileWithPath(path_4)));
635  EXPECT_EQ(name_5, GetCache()->GetNameOfProfileAtIndex(
636      GetCache()->GetIndexOfProfileWithPath(path_5)));
637}
638#endif
639
640TEST_F(ProfileInfoCacheTest,
641       DontMigrateLegacyProfileNamesWithoutNewAvatarMenu) {
642  switches::DisableNewAvatarMenuForTesting(CommandLine::ForCurrentProcess());
643
644  EXPECT_EQ(0U, GetCache()->GetNumberOfProfiles());
645
646  base::string16 name_1 = ASCIIToUTF16("Default Profile");
647  base::FilePath path_1 = GetProfilePath("path_1");
648  GetCache()->AddProfileToCache(path_1, name_1,
649                                base::string16(), 0, std::string());
650  base::string16 name_2 = ASCIIToUTF16("First user");
651  base::FilePath path_2 = GetProfilePath("path_2");
652  GetCache()->AddProfileToCache(path_2, name_2,
653                                base::string16(), 1, std::string());
654  base::string16 name_3 = ASCIIToUTF16("Lemonade");
655  base::FilePath path_3 = GetProfilePath("path_3");
656  GetCache()->AddProfileToCache(path_3, name_3,
657                                base::string16(), 2, std::string());
658  base::string16 name_4 = ASCIIToUTF16("Batman");
659  base::FilePath path_4 = GetProfilePath("path_4");
660  GetCache()->AddProfileToCache(path_4, name_4,
661                                base::string16(), 3, std::string());
662  EXPECT_EQ(4U, GetCache()->GetNumberOfProfiles());
663
664  ResetCache();
665
666  // Profile names should have been preserved.
667  EXPECT_EQ(name_1, GetCache()->GetNameOfProfileAtIndex(
668      GetCache()->GetIndexOfProfileWithPath(path_1)));
669  EXPECT_EQ(name_2, GetCache()->GetNameOfProfileAtIndex(
670      GetCache()->GetIndexOfProfileWithPath(path_2)));
671  EXPECT_EQ(name_3, GetCache()->GetNameOfProfileAtIndex(
672      GetCache()->GetIndexOfProfileWithPath(path_3)));
673  EXPECT_EQ(name_4, GetCache()->GetNameOfProfileAtIndex(
674      GetCache()->GetIndexOfProfileWithPath(path_4)));
675}
676
677