blob: b789da40ba4ba4df09f377c08e59982fe62d547d [file] [log] [blame]
// Copyright 2015 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 <stddef.h>
#include <unordered_set>
#include "base/format_macros.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/profiles/profile_avatar_icon_util.h"
#include "chrome/browser/profiles/profile_info_cache.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/supervised_user/supervised_user_constants.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
// The ProfileMetadataEntry accessors aren't just plain old accessors to local
// members so they'll be tested. The following helpers will make the testing
// code less verbose.
#define TEST_ACCESSORS(entry_type, entry, member, first_value, second_value) \
TestAccessors(&entry, \
&entry_type::Get ## member, \
&entry_type::Set ## member, \
first_value, \
second_value);
#define TEST_STRING16_ACCESSORS(entry_type, entry, member) \
TEST_ACCESSORS(entry_type, entry, member, \
base::ASCIIToUTF16("first_" #member "_value"), \
base::ASCIIToUTF16("second_" #member "_value"));
#define TEST_STRING_ACCESSORS(entry_type, entry, member) \
TEST_ACCESSORS(entry_type, entry, member, \
std::string("first_" #member "_value"), \
std::string("second_" #member "_value"));
#define TEST_BOOL_ACCESSORS(entry_type, entry, member) \
TestAccessors(&entry, \
&entry_type::member, \
&entry_type::Set ## member, \
false, \
true);
#define TEST_STAT_ACCESSORS(entry_type, entry, member) \
TestStatAccessors(&entry, \
&entry_type::Has ## member, \
&entry_type::Get ## member, \
&entry_type::Set ## member, \
10, \
20);
template<typename TValue, typename TGetter, typename TSetter>
void TestAccessors(ProfileAttributesEntry** entry,
TGetter getter_func,
TSetter setter_func,
TValue first_value,
TValue second_value) {
(*entry->*setter_func)(first_value);
EXPECT_EQ(first_value, (*entry->*getter_func)());
(*entry->*setter_func)(second_value);
EXPECT_EQ(second_value, (*entry->*getter_func)());
}
template<typename TValue, typename TExist, typename TGetter, typename TSetter>
void TestStatAccessors(ProfileAttributesEntry** entry,
TExist exist_func,
TGetter getter_func,
TSetter setter_func,
TValue first_value,
TValue second_value) {
EXPECT_FALSE((*entry->*exist_func)());
(*entry->*setter_func)(first_value);
EXPECT_TRUE((*entry->*exist_func)());
EXPECT_EQ(first_value, (*entry->*getter_func)());
(*entry->*setter_func)(second_value);
EXPECT_TRUE((*entry->*exist_func)());
EXPECT_EQ(second_value, (*entry->*getter_func)());
}
} // namespace
class ProfileAttributesStorageTest : public testing::Test {
public:
ProfileAttributesStorageTest()
: testing_profile_manager_(TestingBrowserProcess::GetGlobal()) {}
~ProfileAttributesStorageTest() override {}
protected:
void SetUp() override {
ASSERT_TRUE(testing_profile_manager_.SetUp());
}
void TearDown() override {
}
base::FilePath GetProfilePath(const std::string& base_name) {
return testing_profile_manager_.profile_manager()->user_data_dir().
AppendASCII(base_name);
}
ProfileAttributesStorage* storage() {
return profile_info_cache();
}
ProfileInfoCache* profile_info_cache() {
return testing_profile_manager_.profile_info_cache();
}
void AddTestingProfile() {
size_t number_of_profiles = storage()->GetNumberOfProfiles();
storage()->AddProfile(
GetProfilePath(base::StringPrintf("testing_profile_path%" PRIuS,
number_of_profiles)),
base::ASCIIToUTF16(base::StringPrintf("testing_profile_name%" PRIuS,
number_of_profiles)),
base::StringPrintf("testing_profile_gaia%" PRIuS, number_of_profiles),
base::ASCIIToUTF16(base::StringPrintf("testing_profile_user%" PRIuS,
number_of_profiles)),
number_of_profiles,
std::string(""));
EXPECT_EQ(number_of_profiles + 1, storage()->GetNumberOfProfiles());
}
private:
TestingProfileManager testing_profile_manager_;
content::TestBrowserThreadBundle thread_bundle_;
};
TEST_F(ProfileAttributesStorageTest, ProfileNotFound) {
EXPECT_EQ(0U, storage()->GetNumberOfProfiles());
ProfileAttributesEntry* entry;
ASSERT_FALSE(storage()->GetProfileAttributesWithPath(
GetProfilePath("testing_profile_path0"), &entry));
AddTestingProfile();
EXPECT_EQ(1U, storage()->GetNumberOfProfiles());
ASSERT_TRUE(storage()->GetProfileAttributesWithPath(
GetProfilePath("testing_profile_path0"), &entry));
ASSERT_FALSE(storage()->GetProfileAttributesWithPath(
GetProfilePath("testing_profile_path1"), &entry));
}
TEST_F(ProfileAttributesStorageTest, AddProfile) {
EXPECT_EQ(0U, storage()->GetNumberOfProfiles());
storage()->AddProfile(GetProfilePath("new_profile_path_1"),
base::ASCIIToUTF16("new_profile_name_1"),
std::string("new_profile_gaia_1"),
base::ASCIIToUTF16("new_profile_username_1"),
1,
std::string(""));
EXPECT_EQ(1U, storage()->GetNumberOfProfiles());
ProfileAttributesEntry* entry;
ASSERT_TRUE(storage()->GetProfileAttributesWithPath(
GetProfilePath("new_profile_path_1"), &entry));
EXPECT_EQ(base::ASCIIToUTF16("new_profile_name_1"), entry->GetName());
}
TEST_F(ProfileAttributesStorageTest, RemoveProfile) {
EXPECT_EQ(0U, storage()->GetNumberOfProfiles());
ProfileAttributesEntry* entry;
ASSERT_FALSE(storage()->GetProfileAttributesWithPath(
GetProfilePath("testing_profile_path0"), &entry));
AddTestingProfile();
EXPECT_EQ(1U, storage()->GetNumberOfProfiles());
// Deleting an existing profile should make it un-retrievable.
storage()->RemoveProfile(GetProfilePath("testing_profile_path0"));
EXPECT_EQ(0U, storage()->GetNumberOfProfiles());
ASSERT_FALSE(storage()->GetProfileAttributesWithPath(
GetProfilePath("testing_profile_path1"), &entry));
ASSERT_FALSE(storage()->GetProfileAttributesWithPath(
GetProfilePath("testing_profile_path1"), &entry));
}
TEST_F(ProfileAttributesStorageTest, MultipleProfiles) {
EXPECT_EQ(0U, storage()->GetNumberOfProfiles());
for (size_t i = 0; i < 5; ++i) {
AddTestingProfile();
EXPECT_EQ(i + 1, storage()->GetNumberOfProfiles());
std::vector<ProfileAttributesEntry*> entries =
storage()->GetAllProfilesAttributes();
EXPECT_EQ(i + 1, entries.size());
}
EXPECT_EQ(5U, storage()->GetNumberOfProfiles());
ProfileAttributesEntry* entry;
ASSERT_TRUE(storage()->GetProfileAttributesWithPath(
GetProfilePath("testing_profile_path0"), &entry));
EXPECT_EQ(base::ASCIIToUTF16("testing_profile_name0"), entry->GetName());
storage()->RemoveProfile(GetProfilePath("testing_profile_path0"));
ASSERT_FALSE(storage()->GetProfileAttributesWithPath(
GetProfilePath("testing_profile_path0"), &entry));
EXPECT_EQ(4U, storage()->GetNumberOfProfiles());
std::vector<ProfileAttributesEntry*> entries =
storage()->GetAllProfilesAttributes();
for (auto* entry : entries) {
EXPECT_NE(GetProfilePath("testing_profile_path0"), entry->GetPath());
}
}
TEST_F(ProfileAttributesStorageTest, InitialValues) {
AddTestingProfile();
ProfileAttributesEntry* entry;
ASSERT_TRUE(storage()->GetProfileAttributesWithPath(
GetProfilePath("testing_profile_path0"), &entry));
EXPECT_EQ(GetProfilePath("testing_profile_path0"), entry->GetPath());
EXPECT_EQ(base::ASCIIToUTF16("testing_profile_name0"), entry->GetName());
EXPECT_EQ(std::string("testing_profile_gaia0"), entry->GetGAIAId());
EXPECT_EQ(base::ASCIIToUTF16("testing_profile_user0"), entry->GetUserName());
EXPECT_EQ(0U, entry->GetAvatarIconIndex());
EXPECT_EQ(std::string(""), entry->GetSupervisedUserId());
}
TEST_F(ProfileAttributesStorageTest, EntryAccessors) {
AddTestingProfile();
ProfileAttributesEntry* entry;
ASSERT_TRUE(storage()->GetProfileAttributesWithPath(
GetProfilePath("testing_profile_path0"), &entry));
EXPECT_EQ(GetProfilePath("testing_profile_path0"), entry->GetPath());
TEST_STRING16_ACCESSORS(ProfileAttributesEntry, entry, Name);
TEST_STRING16_ACCESSORS(ProfileAttributesEntry, entry, ShortcutName);
TEST_STRING_ACCESSORS(ProfileAttributesEntry, entry, LocalAuthCredentials);
TEST_STRING_ACCESSORS(
ProfileAttributesEntry, entry, PasswordChangeDetectionToken);
TEST_ACCESSORS(ProfileAttributesEntry, entry, BackgroundStatus, false, true);
TEST_STRING16_ACCESSORS(ProfileAttributesEntry, entry, GAIAName);
TEST_STRING16_ACCESSORS(ProfileAttributesEntry, entry, GAIAGivenName);
TEST_BOOL_ACCESSORS(ProfileAttributesEntry, entry, IsUsingGAIAPicture);
TEST_BOOL_ACCESSORS(ProfileAttributesEntry, entry, IsOmitted);
TEST_BOOL_ACCESSORS(ProfileAttributesEntry, entry, IsSigninRequired);
TEST_STRING_ACCESSORS(ProfileAttributesEntry, entry, SupervisedUserId);
TEST_BOOL_ACCESSORS(ProfileAttributesEntry, entry, IsEphemeral);
TEST_BOOL_ACCESSORS(ProfileAttributesEntry, entry, IsUsingDefaultName);
TEST_BOOL_ACCESSORS(ProfileAttributesEntry, entry, IsUsingDefaultAvatar);
TEST_BOOL_ACCESSORS(ProfileAttributesEntry, entry, IsAuthError);
TEST_STAT_ACCESSORS(ProfileAttributesEntry, entry, StatsBrowsingHistory);
TEST_STAT_ACCESSORS(ProfileAttributesEntry, entry, StatsBookmarks);
TEST_STAT_ACCESSORS(ProfileAttributesEntry, entry, StatsPasswords);
TEST_STAT_ACCESSORS(ProfileAttributesEntry, entry, StatsSettings);
}
TEST_F(ProfileAttributesStorageTest, AuthInfo) {
AddTestingProfile();
ProfileAttributesEntry* entry;
ASSERT_TRUE(storage()->GetProfileAttributesWithPath(
GetProfilePath("testing_profile_path0"), &entry));
entry->SetAuthInfo("", base::string16());
ASSERT_FALSE(entry->IsAuthenticated());
EXPECT_EQ(base::string16(), entry->GetUserName());
EXPECT_EQ("", entry->GetGAIAId());
entry->SetAuthInfo("foo", base::ASCIIToUTF16("bar"));
ASSERT_TRUE(entry->IsAuthenticated());
EXPECT_EQ(base::ASCIIToUTF16("bar"), entry->GetUserName());
EXPECT_EQ("foo", entry->GetGAIAId());
}
TEST_F(ProfileAttributesStorageTest, SupervisedUsersAccessors) {
AddTestingProfile();
ProfileAttributesEntry* entry;
ASSERT_TRUE(storage()->GetProfileAttributesWithPath(
GetProfilePath("testing_profile_path0"), &entry));
entry->SetSupervisedUserId("");
ASSERT_FALSE(entry->IsSupervised());
ASSERT_FALSE(entry->IsChild());
ASSERT_FALSE(entry->IsLegacySupervised());
entry->SetSupervisedUserId("some_supervised_user_id");
ASSERT_TRUE(entry->IsSupervised());
ASSERT_FALSE(entry->IsChild());
ASSERT_TRUE(entry->IsLegacySupervised());
entry->SetSupervisedUserId(supervised_users::kChildAccountSUID);
ASSERT_TRUE(entry->IsSupervised());
ASSERT_TRUE(entry->IsChild());
ASSERT_FALSE(entry->IsLegacySupervised());
}
TEST_F(ProfileAttributesStorageTest, ReSortTriggered) {
storage()->AddProfile(GetProfilePath("alpha_path"),
base::ASCIIToUTF16("alpha"),
std::string("alpha_gaia"),
base::ASCIIToUTF16("alpha_username"),
1,
std::string(""));
storage()->AddProfile(GetProfilePath("lima_path"),
base::ASCIIToUTF16("lima"),
std::string("lima_gaia"),
base::ASCIIToUTF16("lima_username"),
1,
std::string(""));
ProfileAttributesEntry* entry;
ASSERT_TRUE(storage()->GetProfileAttributesWithPath(
GetProfilePath("alpha_path"), &entry));
// Trigger a ProfileInfoCache re-sort.
entry->SetName(base::ASCIIToUTF16("zulu_name"));
EXPECT_EQ(GetProfilePath("alpha_path"), entry->GetPath());
}
TEST_F(ProfileAttributesStorageTest, RemoveOtherProfile) {
AddTestingProfile();
AddTestingProfile();
AddTestingProfile();
EXPECT_EQ(3U, storage()->GetNumberOfProfiles());
ProfileAttributesEntry* first_entry;
ASSERT_TRUE(storage()->GetProfileAttributesWithPath(
GetProfilePath("testing_profile_path0"), &first_entry));
ProfileAttributesEntry* second_entry;
ASSERT_TRUE(storage()->GetProfileAttributesWithPath(
GetProfilePath("testing_profile_path1"), &second_entry));
EXPECT_EQ(
base::ASCIIToUTF16("testing_profile_name0"), first_entry->GetName());
storage()->RemoveProfile(GetProfilePath("testing_profile_path1"));
ASSERT_FALSE(storage()->GetProfileAttributesWithPath(
GetProfilePath("testing_profile_path1"), &second_entry));
EXPECT_EQ(GetProfilePath("testing_profile_path0"), first_entry->GetPath());
EXPECT_EQ(
base::ASCIIToUTF16("testing_profile_name0"), first_entry->GetName());
// Deleting through the ProfileInfoCache should be reflected in the
// ProfileAttributesStorage as well.
profile_info_cache()->RemoveProfile(
GetProfilePath("testing_profile_path2"));
ASSERT_FALSE(storage()->GetProfileAttributesWithPath(
GetProfilePath("testing_profile_path2"), &second_entry));
}
TEST_F(ProfileAttributesStorageTest, AccessFromElsewhere) {
AddTestingProfile();
ProfileAttributesEntry* first_entry;
ASSERT_TRUE(storage()->GetProfileAttributesWithPath(
GetProfilePath("testing_profile_path0"), &first_entry));
ProfileAttributesEntry* second_entry;
ASSERT_TRUE(storage()->GetProfileAttributesWithPath(
GetProfilePath("testing_profile_path0"), &second_entry));
first_entry->SetName(base::ASCIIToUTF16("NewName"));
EXPECT_EQ(base::ASCIIToUTF16("NewName"), second_entry->GetName());
EXPECT_EQ(first_entry, second_entry);
// The ProfileInfoCache should also reflect the changes and its changes
// should be reflected by the ProfileAttributesStorage.
size_t index = profile_info_cache()->GetIndexOfProfileWithPath(
GetProfilePath("testing_profile_path0"));
EXPECT_EQ(base::ASCIIToUTF16("NewName"),
profile_info_cache()->GetNameOfProfileAtIndex(index));
profile_info_cache()->SetNameOfProfileAtIndex(
index, base::ASCIIToUTF16("OtherNewName"));
EXPECT_EQ(base::ASCIIToUTF16("OtherNewName"), first_entry->GetName());
}
TEST_F(ProfileAttributesStorageTest, ChooseAvatarIconIndexForNewProfile) {
size_t total_icon_count = profiles::GetDefaultAvatarIconCount();
#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
size_t generic_icon_count = profiles::GetGenericAvatarIconCount();
ASSERT_LE(generic_icon_count, total_icon_count);
#endif
// Run ChooseAvatarIconIndexForNewProfile |num_iterations| times before using
// the final |icon_index| to add a profile. Multiple checks are needed because
// ChooseAvatarIconIndexForNewProfile is non-deterministic.
const int num_iterations = 10;
std::unordered_set<int> used_icon_indices;
for (size_t i = 0; i < total_icon_count; ++i) {
EXPECT_EQ(i, storage()->GetNumberOfProfiles());
size_t icon_index = 0;
for (int iter = 0; iter < num_iterations; ++iter) {
icon_index = storage()->ChooseAvatarIconIndexForNewProfile();
// Icon must not be used.
ASSERT_EQ(0u, used_icon_indices.count(icon_index));
ASSERT_GT(total_icon_count, icon_index);
#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
if (i < total_icon_count - generic_icon_count)
ASSERT_LE(generic_icon_count, icon_index);
else
ASSERT_GT(generic_icon_count, icon_index);
#endif
}
used_icon_indices.insert(icon_index);
storage()->AddProfile(
GetProfilePath(base::StringPrintf("testing_profile_path%" PRIuS, i)),
base::string16(),
std::string(),
base::string16(),
icon_index,
std::string());
}
for (int iter = 0; iter < num_iterations; ++iter) {
// All icons are used up, expect any valid icon.
ASSERT_GT(total_icon_count,
storage()->ChooseAvatarIconIndexForNewProfile());
}
}