1 // Copyright 2015 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 "components/password_manager/core/browser/password_bubble_experiment.h"
6 
7 #include <ostream>
8 
9 #include "base/strings/string_number_conversions.h"
10 #include "base/test/scoped_feature_list.h"
11 #include "components/password_manager/core/common/password_manager_features.h"
12 #include "components/password_manager/core/common/password_manager_pref_names.h"
13 #include "components/prefs/pref_registry_simple.h"
14 #include "components/prefs/pref_service.h"
15 #include "components/prefs/testing_pref_service.h"
16 #include "components/signin/public/base/signin_pref_names.h"
17 #include "components/signin/public/identity_manager/identity_manager.h"
18 #include "components/sync/base/model_type.h"
19 #include "components/sync/driver/test_sync_service.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 
23 namespace password_bubble_experiment {
24 
25 namespace {
26 
27 enum class CustomPassphraseState { NONE, SET };
28 
29 }  // namespace
30 
31 class PasswordManagerPasswordBubbleExperimentTest : public testing::Test {
32  public:
PasswordManagerPasswordBubbleExperimentTest()33   PasswordManagerPasswordBubbleExperimentTest() {
34     RegisterPrefs(pref_service_.registry());
35     signin::IdentityManager::RegisterProfilePrefs(pref_service_.registry());
36   }
37 
prefs()38   PrefService* prefs() { return &pref_service_; }
39 
sync_service()40   syncer::TestSyncService* sync_service() { return &fake_sync_service_; }
41 
42  protected:
SetupFakeSyncServiceForTestCase(syncer::ModelType type,CustomPassphraseState passphrase_state)43   void SetupFakeSyncServiceForTestCase(syncer::ModelType type,
44                                        CustomPassphraseState passphrase_state) {
45     sync_service()->SetPreferredDataTypes({type});
46     sync_service()->SetActiveDataTypes({type});
47     sync_service()->SetIsUsingSecondaryPassphrase(passphrase_state ==
48                                                   CustomPassphraseState::SET);
49   }
50 
51  private:
52   syncer::TestSyncService fake_sync_service_;
53   TestingPrefServiceSimple pref_service_;
54 };
55 
TEST_F(PasswordManagerPasswordBubbleExperimentTest,ShouldShowChromeSignInPasswordPromo)56 TEST_F(PasswordManagerPasswordBubbleExperimentTest,
57        ShouldShowChromeSignInPasswordPromo) {
58   // By default the promo is off.
59   EXPECT_FALSE(ShouldShowChromeSignInPasswordPromo(prefs(), nullptr));
60   constexpr struct {
61     bool account_storage_enabled;
62     bool was_already_clicked;
63     bool is_sync_allowed;
64     bool is_first_setup_complete;
65     bool is_signin_allowed;
66     int current_shown_count;
67     bool result;
68   } kTestData[] = {
69       {false, false, true, false, true, 0, true},
70       {true, false, true, false, true, 0, false},
71       {false, false, true, false, true, 5, false},
72       {false, true, true, false, true, 0, false},
73       {false, true, true, false, true, 10, false},
74       {false, false, false, false, true, 0, false},
75       {false, false, true, true, true, 0, false},
76       {false, false, true, false, false, 0, false},
77   };
78   for (const auto& test_case : kTestData) {
79     SCOPED_TRACE(testing::Message("#test_case = ") << (&test_case - kTestData));
80     base::test::ScopedFeatureList account_storage_feature;
81     account_storage_feature.InitWithFeatureState(
82         password_manager::features::kEnablePasswordsAccountStorage,
83         test_case.account_storage_enabled);
84     prefs()->SetBoolean(password_manager::prefs::kWasSignInPasswordPromoClicked,
85                         test_case.was_already_clicked);
86     prefs()->SetInteger(
87         password_manager::prefs::kNumberSignInPasswordPromoShown,
88         test_case.current_shown_count);
89     sync_service()->SetDisableReasons(
90         test_case.is_sync_allowed
91             ? syncer::SyncService::DisableReasonSet()
92             : syncer::SyncService::DISABLE_REASON_PLATFORM_OVERRIDE);
93     sync_service()->SetFirstSetupComplete(test_case.is_first_setup_complete);
94     sync_service()->SetTransportState(
95         test_case.is_first_setup_complete
96             ? syncer::SyncService::TransportState::ACTIVE
97             : syncer::SyncService::TransportState::
98                   PENDING_DESIRED_CONFIGURATION);
99     prefs()->SetBoolean(prefs::kSigninAllowed, test_case.is_signin_allowed);
100 #if defined(OS_CHROMEOS)
101     EXPECT_FALSE(ShouldShowChromeSignInPasswordPromo(prefs(), sync_service()));
102 #else
103     EXPECT_EQ(test_case.result,
104               ShouldShowChromeSignInPasswordPromo(prefs(), sync_service()));
105 #endif
106   }
107 }
108 
109 #if !defined(OS_CHROMEOS)
TEST_F(PasswordManagerPasswordBubbleExperimentTest,ReviveSignInPasswordPromo)110 TEST_F(PasswordManagerPasswordBubbleExperimentTest, ReviveSignInPasswordPromo) {
111   sync_service()->SetDisableReasons(syncer::SyncService::DisableReasonSet());
112   sync_service()->SetFirstSetupComplete(false);
113   sync_service()->SetTransportState(
114       syncer::SyncService::TransportState::PENDING_DESIRED_CONFIGURATION);
115   prefs()->SetBoolean(password_manager::prefs::kWasSignInPasswordPromoClicked,
116                       true);
117   prefs()->SetInteger(password_manager::prefs::kNumberSignInPasswordPromoShown,
118                       10);
119 
120   // The state is to be reset.
121   EXPECT_TRUE(ShouldShowChromeSignInPasswordPromo(prefs(), sync_service()));
122 }
123 #endif
124 
TEST_F(PasswordManagerPasswordBubbleExperimentTest,IsSmartLockUser)125 TEST_F(PasswordManagerPasswordBubbleExperimentTest, IsSmartLockUser) {
126   constexpr struct {
127     syncer::ModelType type;
128     CustomPassphraseState passphrase_state;
129     bool expected_sync_user;
130   } kTestData[] = {
131       {syncer::ModelType::BOOKMARKS, CustomPassphraseState::NONE, false},
132       {syncer::ModelType::BOOKMARKS, CustomPassphraseState::SET, false},
133       {syncer::ModelType::PASSWORDS, CustomPassphraseState::NONE, true},
134       {syncer::ModelType::PASSWORDS, CustomPassphraseState::SET, true},
135   };
136   for (const auto& test_case : kTestData) {
137     SCOPED_TRACE(testing::Message("#test_case = ") << (&test_case - kTestData));
138     SetupFakeSyncServiceForTestCase(test_case.type, test_case.passphrase_state);
139 
140     EXPECT_EQ(test_case.expected_sync_user, IsSmartLockUser(sync_service()));
141   }
142 }
143 
144 }  // namespace password_bubble_experiment
145