blob: ad3ebf02b26afa5cbe6836847da43fbe328a204a [file] [log] [blame]
// Copyright 2019 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 "components/password_manager/core/browser/leak_detection_dialog_utils.h"
#include "base/i18n/message_formatter.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "build/branding_buildflags.h"
#include "build/build_config.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "components/strings/grit/components_strings.h"
#include "components/url_formatter/elide_url.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
#include "url/gurl.h"
#include "url/origin.h"
using password_manager::CreateLeakType;
using password_manager::CredentialLeakFlags;
using password_manager::CredentialLeakType;
using password_manager::IsReused;
using password_manager::IsSaved;
using password_manager::IsSyncing;
using password_manager::metrics_util::LeakDialogType;
namespace password_manager {
namespace {
// Contains information that should be displayed on the leak dialog for
// specified |leak_type|.
const struct {
// Specifies the test case.
CredentialLeakType leak_type;
// The rest of the fields specify what should be displayed for this test case.
int accept_button_id;
int cancel_button_id;
int leak_message_id;
int leak_title_id;
bool should_show_cancel_button;
bool should_check_passwords;
} kLeakTypesTestCases[] = {
{CreateLeakType(IsSaved(false),
IsReused(false),
IsSyncing(false),
HasChangeScript(false)),
IDS_OK, IDS_CLOSE,
#if BUILDFLAG(IS_IOS) || BUILDFLAG(GOOGLE_CHROME_BRANDING)
IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_MESSAGE_GPM_BRANDED,
#elif !BUILDFLAG(GOOGLE_CHROME_BRANDING)
IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_MESSAGE_GPM_NON_BRANDED,
#endif
IDS_CREDENTIAL_LEAK_TITLE_CHANGE, false, false},
{CreateLeakType(IsSaved(false),
IsReused(false),
IsSyncing(true),
HasChangeScript(false)),
IDS_OK, IDS_CLOSE, IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_MESSAGE_GPM_BRANDED,
IDS_CREDENTIAL_LEAK_TITLE_CHANGE, false, false},
{CreateLeakType(IsSaved(false),
IsReused(true),
IsSyncing(true),
HasChangeScript(false)),
IDS_LEAK_CHECK_CREDENTIALS, IDS_CLOSE,
IDS_CREDENTIAL_LEAK_CHANGE_AND_CHECK_PASSWORDS_MESSAGE_GPM_BRANDED,
IDS_CREDENTIAL_LEAK_TITLE_CHECK_GPM, true, true},
{CreateLeakType(IsSaved(false),
IsReused(false),
IsSyncing(true),
HasChangeScript(true)),
IDS_OK, IDS_CLOSE, IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_MESSAGE_GPM_BRANDED,
IDS_CREDENTIAL_LEAK_TITLE_CHANGE, false, false},
{CreateLeakType(IsSaved(true),
IsReused(false),
IsSyncing(true),
HasChangeScript(false)),
IDS_OK, IDS_CLOSE, IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_MESSAGE_GPM_BRANDED,
IDS_CREDENTIAL_LEAK_TITLE_CHANGE, false, false},
{CreateLeakType(IsSaved(true),
IsReused(true),
IsSyncing(true),
HasChangeScript(false)),
IDS_LEAK_CHECK_CREDENTIALS, IDS_CLOSE,
IDS_CREDENTIAL_LEAK_CHECK_PASSWORDS_MESSAGE_GPM_BRANDED,
IDS_CREDENTIAL_LEAK_TITLE_CHECK_GPM, true, true},
};
struct BulkCheckParams {
// Specifies the test case.
CredentialLeakType leak_type;
bool should_check_passwords;
} kBulkCheckTestCases[] = {{CreateLeakType(IsSaved(false),
IsReused(false),
IsSyncing(false),
HasChangeScript(false)),
false},
{CreateLeakType(IsSaved(true),
IsReused(false),
IsSyncing(false),
HasChangeScript(false)),
false},
{CreateLeakType(IsSaved(false),
IsReused(true),
IsSyncing(false),
HasChangeScript(false)),
true},
{CreateLeakType(IsSaved(true),
IsReused(true),
IsSyncing(false),
HasChangeScript(false)),
true},
{CreateLeakType(IsSaved(true),
IsReused(true),
IsSyncing(true),
HasChangeScript(false)),
true}};
} // namespace
class CredentialLeakDialogUtilsTest : public testing::Test {
public:
CredentialLeakDialogUtilsTest() {
#if BUILDFLAG(IS_IOS)
feature_list_.InitAndEnableFeature(
features::kIOSEnablePasswordManagerBrandingUpdate);
#elif BUILDFLAG(IS_ANDROID)
feature_list_.InitAndEnableFeature(
features::kUnifiedPasswordManagerAndroid);
#else
feature_list_.InitAndEnableFeature(
features::kUnifiedPasswordManagerDesktop);
#endif
}
private:
base::test::ScopedFeatureList feature_list_;
};
TEST_F(CredentialLeakDialogUtilsTest, GetAcceptButtonLabel) {
for (size_t i = 0; i < std::size(kLeakTypesTestCases); ++i) {
SCOPED_TRACE(testing::Message() << i);
EXPECT_EQ(
l10n_util::GetStringUTF16(kLeakTypesTestCases[i].accept_button_id),
GetAcceptButtonLabel(kLeakTypesTestCases[i].leak_type));
}
}
TEST_F(CredentialLeakDialogUtilsTest, LeakDialogTraits_GetAcceptButtonLabel) {
for (size_t i = 0; i < std::size(kLeakTypesTestCases); ++i) {
SCOPED_TRACE(testing::Message() << i);
EXPECT_EQ(
l10n_util::GetStringUTF16(kLeakTypesTestCases[i].accept_button_id),
CreateDialogTraits(kLeakTypesTestCases[i].leak_type)
->GetAcceptButtonLabel());
}
}
TEST_F(CredentialLeakDialogUtilsTest, GetCancelButtonLabel) {
for (size_t i = 0; i < std::size(kLeakTypesTestCases); ++i) {
SCOPED_TRACE(testing::Message() << i);
EXPECT_EQ(
l10n_util::GetStringUTF16(kLeakTypesTestCases[i].cancel_button_id),
GetCancelButtonLabel(kLeakTypesTestCases[i].leak_type));
}
}
TEST_F(CredentialLeakDialogUtilsTest, LeakDialogTraits_GetCancelButtonLabel) {
for (size_t i = 0; i < std::size(kLeakTypesTestCases); ++i) {
SCOPED_TRACE(testing::Message() << i);
EXPECT_EQ(
l10n_util::GetStringUTF16(kLeakTypesTestCases[i].cancel_button_id),
CreateDialogTraits(kLeakTypesTestCases[i].leak_type)
->GetCancelButtonLabel());
}
}
TEST_F(CredentialLeakDialogUtilsTest, GetDescription) {
for (size_t i = 0; i < std::size(kLeakTypesTestCases); ++i) {
SCOPED_TRACE(testing::Message() << i);
std::u16string expected_message =
l10n_util::GetStringUTF16(kLeakTypesTestCases[i].leak_message_id);
EXPECT_EQ(expected_message,
GetDescription(kLeakTypesTestCases[i].leak_type));
}
}
TEST_F(CredentialLeakDialogUtilsTest, LeakDialogTraits_GetDescription) {
for (size_t i = 0; i < std::size(kLeakTypesTestCases); ++i) {
SCOPED_TRACE(testing::Message() << i);
EXPECT_EQ(
l10n_util::GetStringUTF16(kLeakTypesTestCases[i].leak_message_id),
CreateDialogTraits(kLeakTypesTestCases[i].leak_type)->GetDescription());
}
}
TEST_F(CredentialLeakDialogUtilsTest, GetTitle) {
for (size_t i = 0; i < std::size(kLeakTypesTestCases); ++i) {
SCOPED_TRACE(testing::Message() << i);
EXPECT_EQ(l10n_util::GetStringUTF16(kLeakTypesTestCases[i].leak_title_id),
GetTitle(kLeakTypesTestCases[i].leak_type));
}
}
TEST_F(CredentialLeakDialogUtilsTest, LeakDialogTraits_GetTitle) {
for (size_t i = 0; i < std::size(kLeakTypesTestCases); ++i) {
SCOPED_TRACE(testing::Message() << i);
EXPECT_EQ(l10n_util::GetStringUTF16(kLeakTypesTestCases[i].leak_title_id),
CreateDialogTraits(kLeakTypesTestCases[i].leak_type)->GetTitle());
}
}
TEST_F(CredentialLeakDialogUtilsTest, ShouldCheckPasswords) {
for (size_t i = 0; i < std::size(kLeakTypesTestCases); ++i) {
SCOPED_TRACE(testing::Message() << i);
EXPECT_EQ(kLeakTypesTestCases[i].should_check_passwords,
ShouldCheckPasswords(kLeakTypesTestCases[i].leak_type));
}
}
TEST_F(CredentialLeakDialogUtilsTest, LeakDialogTraits_ShouldCheckPasswords) {
for (size_t i = 0; i < std::size(kLeakTypesTestCases); ++i) {
SCOPED_TRACE(testing::Message() << i);
EXPECT_EQ(kLeakTypesTestCases[i].should_check_passwords,
CreateDialogTraits(kLeakTypesTestCases[i].leak_type)
->ShouldCheckPasswords());
}
}
TEST_F(CredentialLeakDialogUtilsTest, ShouldShowCancelButton) {
for (size_t i = 0; i < std::size(kLeakTypesTestCases); ++i) {
SCOPED_TRACE(testing::Message() << i);
EXPECT_EQ(kLeakTypesTestCases[i].should_show_cancel_button,
ShouldShowCancelButton(kLeakTypesTestCases[i].leak_type));
}
}
TEST_F(CredentialLeakDialogUtilsTest, LeakDialogTraits_ShouldShowCancelButton) {
for (size_t i = 0; i < std::size(kLeakTypesTestCases); ++i) {
SCOPED_TRACE(testing::Message() << i);
EXPECT_EQ(kLeakTypesTestCases[i].should_show_cancel_button,
CreateDialogTraits(kLeakTypesTestCases[i].leak_type)
->ShouldShowCancelButton());
}
}
class BulkCheckCredentialLeakDialogUtilsTest
: public testing::TestWithParam<BulkCheckParams> {
public:
BulkCheckCredentialLeakDialogUtilsTest() {
#if BUILDFLAG(IS_IOS)
feature_list_.InitAndEnableFeature(
features::kIOSEnablePasswordManagerBrandingUpdate);
#elif BUILDFLAG(IS_ANDROID)
feature_list_.InitAndEnableFeature(
features::kUnifiedPasswordManagerAndroid);
#endif
}
private:
base::test::ScopedFeatureList feature_list_;
};
TEST_P(BulkCheckCredentialLeakDialogUtilsTest, ShouldCheckPasswords) {
SCOPED_TRACE(testing::Message() << GetParam().leak_type);
EXPECT_EQ(GetParam().should_check_passwords,
ShouldCheckPasswords(GetParam().leak_type));
}
TEST_P(BulkCheckCredentialLeakDialogUtilsTest, Buttons) {
SCOPED_TRACE(testing::Message() << GetParam().leak_type);
EXPECT_EQ(GetParam().should_check_passwords,
ShouldShowCancelButton(GetParam().leak_type));
EXPECT_EQ(l10n_util::GetStringUTF16(GetParam().should_check_passwords
? IDS_LEAK_CHECK_CREDENTIALS
: IDS_OK),
GetAcceptButtonLabel(GetParam().leak_type));
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_CLOSE),
GetCancelButtonLabel(GetParam().leak_type));
}
TEST_P(BulkCheckCredentialLeakDialogUtilsTest, Title) {
SCOPED_TRACE(testing::Message() << GetParam().leak_type);
EXPECT_EQ(l10n_util::GetStringUTF16(GetParam().should_check_passwords
? IDS_CREDENTIAL_LEAK_TITLE_CHECK_GPM
: IDS_CREDENTIAL_LEAK_TITLE_CHANGE),
GetTitle(GetParam().leak_type));
}
INSTANTIATE_TEST_SUITE_P(InstantiationName,
BulkCheckCredentialLeakDialogUtilsTest,
testing::ValuesIn(kBulkCheckTestCases));
#if BUILDFLAG(IS_ANDROID)
struct PasswordChangeParams {
// Specifies the test case. Note that the HasChangeScript(false) cases are
// covered in a separate test.
CredentialLeakType leak_type;
// The rest of the fields specify what should be displayed for this test case.
int accept_button_id;
int cancel_button_id;
bool should_show_cancel_button;
bool should_show_change_password_button;
} kPasswordChangeTestCases[] = {
{CreateLeakType(IsSaved(false),
IsReused(false),
IsSyncing(false),
HasChangeScript(true)),
IDS_OK, 0, false, false},
{CreateLeakType(IsSaved(false),
IsReused(false),
IsSyncing(true),
HasChangeScript(true)),
IDS_OK, 0, false, false},
{CreateLeakType(IsSaved(false),
IsReused(true),
IsSyncing(false),
HasChangeScript(true)),
IDS_LEAK_CHECK_CREDENTIALS, IDS_CLOSE, true, false},
{CreateLeakType(IsSaved(false),
IsReused(true),
IsSyncing(true),
HasChangeScript(true)),
IDS_LEAK_CHECK_CREDENTIALS, IDS_CLOSE, true, false},
{CreateLeakType(IsSaved(true),
IsReused(false),
IsSyncing(false),
HasChangeScript(true)),
IDS_OK, 0, false, false},
{CreateLeakType(IsSaved(true),
IsReused(false),
IsSyncing(true),
HasChangeScript(true)),
IDS_CREDENTIAL_LEAK_CHANGE_AUTOMATICALLY, IDS_CLOSE, true, true},
{CreateLeakType(IsSaved(true),
IsReused(true),
IsSyncing(false),
HasChangeScript(true)),
IDS_LEAK_CHECK_CREDENTIALS, IDS_CLOSE, true, false},
{CreateLeakType(IsSaved(true),
IsReused(true),
IsSyncing(true),
HasChangeScript(true)),
IDS_CREDENTIAL_LEAK_CHANGE_AUTOMATICALLY, IDS_CLOSE, true, true}};
class PasswordChangeCredentialLeakDialogUtilsTest
: public testing::TestWithParam<PasswordChangeParams> {
public:
PasswordChangeCredentialLeakDialogUtilsTest() {
feature_list_.InitAndEnableFeature(features::kPasswordChange);
}
private:
base::test::ScopedFeatureList feature_list_;
};
TEST_P(PasswordChangeCredentialLeakDialogUtilsTest,
ShouldNotShowChangePasswordButtonWithoutScript) {
// Get IsSaved, IsReused, and IsSyncing from the test parameter...
IsSaved is_saved = IsSaved(IsPasswordSaved(GetParam().leak_type));
IsReused is_reused =
IsReused(IsPasswordUsedOnOtherSites(GetParam().leak_type));
IsSyncing is_syncing =
IsSyncing(IsSyncingPasswordsNormally(GetParam().leak_type));
// ...but set HasChangeScript to false.
CredentialLeakType leak_type =
CreateLeakType(is_saved, is_reused, is_syncing, HasChangeScript(false));
SCOPED_TRACE(testing::Message() << leak_type);
EXPECT_FALSE(ShouldShowAutomaticChangePasswordButton(leak_type));
EXPECT_NE(l10n_util::GetStringUTF16(IDS_CREDENTIAL_LEAK_CHANGE_AUTOMATICALLY),
GetAcceptButtonLabel(leak_type));
}
TEST_P(PasswordChangeCredentialLeakDialogUtilsTest,
ShouldShowAutomaticChangePasswordButton) {
SCOPED_TRACE(testing::Message() << GetParam().leak_type);
// ShouldCheckPasswords and ShouldShowAutomaticChangePasswordButton
// should never be true both.
EXPECT_FALSE(ShouldCheckPasswords(GetParam().leak_type) &&
ShouldShowAutomaticChangePasswordButton(GetParam().leak_type));
EXPECT_EQ(GetParam().should_show_change_password_button,
ShouldShowAutomaticChangePasswordButton(GetParam().leak_type));
}
TEST_P(PasswordChangeCredentialLeakDialogUtilsTest, ShouldShowCancelButton) {
SCOPED_TRACE(testing::Message() << GetParam().leak_type);
EXPECT_EQ(GetParam().should_show_cancel_button,
ShouldShowCancelButton(GetParam().leak_type));
}
TEST_P(PasswordChangeCredentialLeakDialogUtilsTest, GetAcceptButtonLabel) {
SCOPED_TRACE(testing::Message() << GetParam().leak_type);
EXPECT_EQ(l10n_util::GetStringUTF16(GetParam().accept_button_id),
GetAcceptButtonLabel(GetParam().leak_type));
}
TEST_P(PasswordChangeCredentialLeakDialogUtilsTest, GetCancelButtonLabel) {
SCOPED_TRACE(testing::Message() << GetParam().leak_type);
if (GetParam().should_show_cancel_button) {
EXPECT_EQ(l10n_util::GetStringUTF16(GetParam().cancel_button_id),
GetCancelButtonLabel(GetParam().leak_type));
}
}
INSTANTIATE_TEST_SUITE_P(InstantiationName,
PasswordChangeCredentialLeakDialogUtilsTest,
testing::ValuesIn(kPasswordChangeTestCases));
#endif
} // namespace password_manager