blob: 9194bb273e22b43f447095023d1dac5692872019 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/promos_manager/promos_manager_unittest.h"
#import <Foundation/Foundation.h>
#import <set>
#import <vector>
#import "base/test/scoped_feature_list.h"
#import "base/values.h"
#import "components/prefs/pref_registry_simple.h"
#import "components/prefs/testing_pref_service.h"
#import "ios/chrome/browser/prefs/pref_names.h"
#import "ios/chrome/browser/promos_manager/constants.h"
#import "ios/chrome/browser/promos_manager/features.h"
#import "ios/chrome/browser/promos_manager/impression_limit.h"
#import "ios/chrome/browser/promos_manager/promo.h"
#import "ios/chrome/browser/promos_manager/promos_manager.h"
#import "testing/platform_test.h"
#import "third_party/abseil-cpp/absl/types/optional.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// The number of days since the Unix epoch; one day, in this context, runs
// from UTC midnight to UTC midnight.
int TodaysDay() {
return (base::Time::Now() - base::Time::UnixEpoch()).InDays();
}
} // namespace
PromosManagerTest::PromosManagerTest() {
scoped_feature_list_.InitWithFeatures({kFullscreenPromosManager}, {});
}
PromosManagerTest::~PromosManagerTest() {}
NSArray<ImpressionLimit*>* PromosManagerTest::TestImpressionLimits() {
static NSArray<ImpressionLimit*>* limits;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
ImpressionLimit* oncePerWeek = [[ImpressionLimit alloc] initWithLimit:1
forNumDays:7];
ImpressionLimit* twicePerMonth = [[ImpressionLimit alloc] initWithLimit:2
forNumDays:31];
limits = @[ oncePerWeek, twicePerMonth ];
});
return limits;
}
Promo* PromosManagerTest::TestPromo() {
return [[Promo alloc] initWithIdentifier:promos_manager::Promo::Test];
}
Promo* PromosManagerTest::TestPromoWithImpressionLimits() {
return [[Promo alloc] initWithIdentifier:promos_manager::Promo::Test
andImpressionLimits:TestImpressionLimits()];
}
void PromosManagerTest::CreatePromosManager() {
CreatePrefs();
promos_manager_ = std::make_unique<PromosManager>(local_state_.get());
promos_manager_->Init();
}
// Create pref registry for tests.
void PromosManagerTest::CreatePrefs() {
local_state_ = std::make_unique<TestingPrefServiceSimple>();
local_state_->registry()->RegisterListPref(
prefs::kIosPromosManagerImpressions);
local_state_->registry()->RegisterListPref(
prefs::kIosPromosManagerActivePromos);
local_state_->registry()->RegisterListPref(
prefs::kIosPromosManagerSingleDisplayActivePromos);
}
// Tests the initializer correctly creates a PromosManager* with the
// specified Pref service.
TEST_F(PromosManagerTest, InitWithPrefService) {
CreatePromosManager();
EXPECT_NE(local_state_->FindPreference(prefs::kIosPromosManagerImpressions),
nullptr);
EXPECT_NE(local_state_->FindPreference(prefs::kIosPromosManagerActivePromos),
nullptr);
EXPECT_NE(local_state_->FindPreference(
prefs::kIosPromosManagerSingleDisplayActivePromos),
nullptr);
EXPECT_FALSE(local_state_->HasPrefPath(prefs::kIosPromosManagerImpressions));
EXPECT_FALSE(local_state_->HasPrefPath(prefs::kIosPromosManagerActivePromos));
EXPECT_FALSE(local_state_->HasPrefPath(
prefs::kIosPromosManagerSingleDisplayActivePromos));
}
// Tests promos_manager::NameForPromo correctly returns the string
// representation of a given promo.
TEST_F(PromosManagerTest, ReturnsNameForTestPromo) {
EXPECT_EQ(promos_manager::NameForPromo(promos_manager::Promo::Test),
"promos_manager::Promo::Test");
}
// Tests promos_manager::PromoForName correctly returns the
// promos_manager::Promo given its string name.
TEST_F(PromosManagerTest, ReturnsTestPromoForName) {
EXPECT_EQ(promos_manager::PromoForName("promos_manager::Promo::Test"),
promos_manager::Promo::Test);
}
// Tests promos_manager::PromoForName correctly returns absl::nullopt for bad
// input.
TEST_F(PromosManagerTest, ReturnsNulloptForBadName) {
EXPECT_FALSE(promos_manager::PromoForName("promos_manager::Promo::FOOBAR")
.has_value());
}
// Tests PromosManagerTest::TestPromo() correctly creates one mock promo.
TEST_F(PromosManagerTest, CreatesPromo) {
Promo* promo = TestPromo();
EXPECT_NE(promo, nil);
EXPECT_EQ((int)promo.impressionLimits.count, 0);
}
// Tests PromosManagerTest::TestPromoWithImpressionLimits() correctly creates
// one mock promo with mock impression limits.
TEST_F(PromosManagerTest, CreatesPromoWithImpressionLimits) {
Promo* promoWithImpressionLimits = TestPromoWithImpressionLimits();
EXPECT_NE(promoWithImpressionLimits, nil);
EXPECT_EQ((int)promoWithImpressionLimits.impressionLimits.count, 2);
}
// Tests PromosManagerTest::TestImpressionLimits() correctly creates two mock
// impression limits.
TEST_F(PromosManagerTest, CreatesImpressionLimits) {
NSArray<ImpressionLimit*>* impressionLimits = TestImpressionLimits();
EXPECT_NE(impressionLimits, nil);
EXPECT_EQ(impressionLimits[0].numImpressions, 1);
EXPECT_EQ(impressionLimits[0].numDays, 7);
EXPECT_EQ(impressionLimits[1].numImpressions, 2);
EXPECT_EQ(impressionLimits[1].numDays, 31);
}
// Tests PromosManager::ImpressionCounts() correctly returns a counts list from
// an impression counts map.
TEST_F(PromosManagerTest, ReturnsImpressionCounts) {
std::map<promos_manager::Promo, int> promo_impression_counts = {
{promos_manager::Promo::Test, 3},
{promos_manager::Promo::AppStoreRating, 1},
{promos_manager::Promo::CredentialProviderExtension, 6},
{promos_manager::Promo::DefaultBrowser, 5},
};
std::vector<int> counts = {3, 5, 1, 6};
EXPECT_EQ(promos_manager_->ImpressionCounts(promo_impression_counts), counts);
}
// Tests PromosManager::ImpressionCounts() correctly returns an empty counts
// list for an empty impression counts map.
TEST_F(PromosManagerTest, ReturnsEmptyImpressionCounts) {
std::map<promos_manager::Promo, int> promo_impression_counts;
std::vector<int> counts;
EXPECT_EQ(promos_manager_->ImpressionCounts(promo_impression_counts), counts);
}
// Tests PromosManager::TotalImpressionCount() correctly adds the counts of
// different promos from an impression counts map.
TEST_F(PromosManagerTest, ReturnsTotalImpressionCount) {
std::map<promos_manager::Promo, int> promo_impression_counts = {
{promos_manager::Promo::Test, 3},
{promos_manager::Promo::AppStoreRating, 1},
{promos_manager::Promo::CredentialProviderExtension, 6},
{promos_manager::Promo::DefaultBrowser, 5},
};
EXPECT_EQ(promos_manager_->TotalImpressionCount(promo_impression_counts), 15);
}
// Tests PromosManager::TotalImpressionCount() returns zero for an empty
// impression counts map.
TEST_F(PromosManagerTest, ReturnsZeroForTotalImpressionCount) {
std::map<promos_manager::Promo, int> promo_impression_counts;
EXPECT_EQ(promos_manager_->TotalImpressionCount(promo_impression_counts), 0);
}
// Tests PromosManager::MaxImpressionCount() correctly returns the max
// impression count from an impression counts map.
TEST_F(PromosManagerTest, ReturnsMaxImpressionCount) {
std::map<promos_manager::Promo, int> promo_impression_counts = {
{promos_manager::Promo::Test, 3},
{promos_manager::Promo::AppStoreRating, 1},
{promos_manager::Promo::CredentialProviderExtension, 6},
{promos_manager::Promo::DefaultBrowser, 5},
};
EXPECT_EQ(promos_manager_->MaxImpressionCount(promo_impression_counts), 6);
}
// Tests PromosManager::MaxImpressionCount() correctly returns zero for an empty
// impression counts map.
TEST_F(PromosManagerTest, ReturnsZeroForMaxImpressionCount) {
std::map<promos_manager::Promo, int> promo_impression_counts;
EXPECT_EQ(promos_manager_->MaxImpressionCount(promo_impression_counts), 0);
}
// Tests PromosManager::AnyImpressionLimitTriggered() correctly detects an
// impression limit is triggered.
TEST_F(PromosManagerTest, DetectsSingleImpressionLimitTriggered) {
ImpressionLimit* thricePerWeek = [[ImpressionLimit alloc] initWithLimit:3
forNumDays:7];
NSArray<ImpressionLimit*>* limits = @[
thricePerWeek,
];
EXPECT_EQ(promos_manager_->AnyImpressionLimitTriggered(3, 1, limits), true);
EXPECT_EQ(promos_manager_->AnyImpressionLimitTriggered(4, 5, limits), true);
EXPECT_EQ(promos_manager_->AnyImpressionLimitTriggered(4, 6, limits), true);
// This is technically the 8th day, so it's the start of a new week, and
// doesn't hit the limit.
EXPECT_EQ(promos_manager_->AnyImpressionLimitTriggered(3, 7, limits), false);
}
// Tests PromosManager::AnyImpressionLimitTriggered() correctly detects an
// impression limit is triggered over multiple impression limits.
TEST_F(PromosManagerTest, DetectsOneOfMultipleImpressionLimitsTriggered) {
ImpressionLimit* onceEveryTwoDays = [[ImpressionLimit alloc] initWithLimit:1
forNumDays:2];
ImpressionLimit* thricePerWeek = [[ImpressionLimit alloc] initWithLimit:3
forNumDays:7];
NSArray<ImpressionLimit*>* limits = @[
thricePerWeek,
onceEveryTwoDays,
];
EXPECT_EQ(promos_manager_->AnyImpressionLimitTriggered(1, 1, limits), true);
EXPECT_EQ(promos_manager_->AnyImpressionLimitTriggered(1, 2, limits), false);
EXPECT_EQ(promos_manager_->AnyImpressionLimitTriggered(2, 2, limits), false);
EXPECT_EQ(promos_manager_->AnyImpressionLimitTriggered(2, 4, limits), false);
}
// Tests PromosManager::AnyImpressionLimitTriggered() correctly detects no
// impression limits are triggered.
TEST_F(PromosManagerTest, DetectsNoImpressionLimitTriggered) {
ImpressionLimit* onceEveryTwoDays = [[ImpressionLimit alloc] initWithLimit:1
forNumDays:2];
ImpressionLimit* thricePerWeek = [[ImpressionLimit alloc] initWithLimit:3
forNumDays:7];
NSArray<ImpressionLimit*>* limits = @[ onceEveryTwoDays, thricePerWeek ];
EXPECT_EQ(promos_manager_->AnyImpressionLimitTriggered(1, 1, nil), false);
EXPECT_EQ(promos_manager_->AnyImpressionLimitTriggered(0, 3, limits), false);
EXPECT_EQ(promos_manager_->AnyImpressionLimitTriggered(1, 5, limits), false);
EXPECT_EQ(promos_manager_->AnyImpressionLimitTriggered(2, 5, limits), false);
}
// Tests PromosManager::CanShowPromo() correctly allows a promo to be shown
// because it hasn't met any impression limits.
TEST_F(PromosManagerTest, DecidesCanShowPromo) {
CreatePromosManager();
const std::vector<promos_manager::Impression> zeroImpressions = {};
EXPECT_EQ(promos_manager_->CanShowPromo(promos_manager::Promo::Test,
zeroImpressions),
true);
}
// Tests PromosManager::CanShowPromo() correctly denies promos from being shown
// as they've triggered impression limits.
TEST_F(PromosManagerTest, DecidesCannotShowPromo) {
CreatePromosManager();
int today = TodaysDay();
const std::vector<promos_manager::Impression> impressions = {
promos_manager::Impression(promos_manager::Promo::Test, today),
promos_manager::Impression(promos_manager::Promo::DefaultBrowser,
today - 7),
promos_manager::Impression(promos_manager::Promo::AppStoreRating,
today - 14),
promos_manager::Impression(
promos_manager::Promo::CredentialProviderExtension, today - 180),
};
// False because triggers no more than 1 impression per month global
// impression limit.
EXPECT_EQ(
promos_manager_->CanShowPromo(promos_manager::Promo::Test, impressions),
false);
EXPECT_EQ(promos_manager_->CanShowPromo(promos_manager::Promo::DefaultBrowser,
impressions),
false);
EXPECT_EQ(promos_manager_->CanShowPromo(promos_manager::Promo::AppStoreRating,
impressions),
false);
// False because an impression has already been shown this month, even though
// it's not the CredentialProviderExtension promo.
EXPECT_EQ(
promos_manager_->CanShowPromo(
promos_manager::Promo::CredentialProviderExtension, impressions),
false);
}
// Tests PromosManager::LeastRecentlyShown() correctly returns a list of active
// promos sorted by least recently shown.
TEST_F(PromosManagerTest, ReturnsLeastRecentlyShown) {
const std::set<promos_manager::Promo> active_promos = {
promos_manager::Promo::Test,
promos_manager::Promo::CredentialProviderExtension,
promos_manager::Promo::AppStoreRating,
promos_manager::Promo::DefaultBrowser,
};
int today = TodaysDay();
const std::vector<promos_manager::Impression> impressions = {
promos_manager::Impression(promos_manager::Promo::Test, today),
promos_manager::Impression(promos_manager::Promo::DefaultBrowser,
today - 7),
promos_manager::Impression(promos_manager::Promo::AppStoreRating,
today - 14),
promos_manager::Impression(
promos_manager::Promo::CredentialProviderExtension, today - 180),
};
std::vector<promos_manager::Promo> expected = {
promos_manager::Promo::CredentialProviderExtension,
promos_manager::Promo::AppStoreRating,
promos_manager::Promo::DefaultBrowser,
promos_manager::Promo::Test,
};
EXPECT_EQ(promos_manager_->LeastRecentlyShown(active_promos, impressions),
expected);
}
// Tests PromosManager::LeastRecentlyShown() correctly returns a list of
// active / promos sorted by least recently shown (with some impressions /
// belonging to inactive promo campaigns).
TEST_F(PromosManagerTest, ReturnsLeastRecentlyShownWithSomeInactivePromos) {
const std::set<promos_manager::Promo> active_promos = {
promos_manager::Promo::Test,
promos_manager::Promo::AppStoreRating,
};
int today = TodaysDay();
const std::vector<promos_manager::Impression> impressions = {
promos_manager::Impression(promos_manager::Promo::Test, today),
promos_manager::Impression(promos_manager::Promo::DefaultBrowser,
today - 7),
promos_manager::Impression(promos_manager::Promo::AppStoreRating,
today - 14),
promos_manager::Impression(
promos_manager::Promo::CredentialProviderExtension, today - 180),
};
const std::vector<promos_manager::Promo> expected = {
promos_manager::Promo::AppStoreRating,
promos_manager::Promo::Test,
};
EXPECT_EQ(promos_manager_->LeastRecentlyShown(active_promos, impressions),
expected);
}
// Tests PromosManager::LeastRecentlyShown() gracefully returns a list of
// active / promos when multiple promos are tied for least recently shown.
TEST_F(PromosManagerTest, ReturnsLeastRecentlyShownBreakingTies) {
const std::set<promos_manager::Promo> active_promos = {
promos_manager::Promo::Test,
promos_manager::Promo::CredentialProviderExtension,
promos_manager::Promo::AppStoreRating,
promos_manager::Promo::DefaultBrowser,
};
int today = TodaysDay();
const std::vector<promos_manager::Impression> impressions = {
promos_manager::Impression(promos_manager::Promo::Test, today),
promos_manager::Impression(promos_manager::Promo::DefaultBrowser, today),
promos_manager::Impression(promos_manager::Promo::AppStoreRating, today),
promos_manager::Impression(
promos_manager::Promo::CredentialProviderExtension, today),
};
const std::vector<promos_manager::Promo> expected = {
promos_manager::Promo::CredentialProviderExtension,
promos_manager::Promo::AppStoreRating,
promos_manager::Promo::DefaultBrowser,
promos_manager::Promo::Test,
};
EXPECT_EQ(promos_manager_->LeastRecentlyShown(active_promos, impressions),
expected);
}
// Tests PromosManager::LeastRecentlyShown() gracefully returns a single promo
// in a list when the impression history contains only one active promo
// campaign.
TEST_F(PromosManagerTest, ReturnsLeastRecentlyShownWithOnlyOnePromoActive) {
const std::set<promos_manager::Promo> active_promos = {
promos_manager::Promo::Test,
};
int today = TodaysDay();
const std::vector<promos_manager::Impression> impressions = {
promos_manager::Impression(promos_manager::Promo::Test, today),
promos_manager::Impression(promos_manager::Promo::DefaultBrowser,
today - 7),
promos_manager::Impression(promos_manager::Promo::AppStoreRating,
today - 14),
promos_manager::Impression(
promos_manager::Promo::CredentialProviderExtension, today - 180),
};
const std::vector<promos_manager::Promo> expected = {
promos_manager::Promo::Test,
};
EXPECT_EQ(promos_manager_->LeastRecentlyShown(active_promos, impressions),
expected);
}
// Tests PromosManager::LeastRecentlyShown() gracefully returns an empty array
// when there are no active promo campaigns.
TEST_F(PromosManagerTest,
ReturnsEmptyListWhenLeastRecentlyShownHasNoActivePromoCampaigns) {
const std::set<promos_manager::Promo> active_promos;
int today = TodaysDay();
const std::vector<promos_manager::Impression> impressions = {
promos_manager::Impression(promos_manager::Promo::Test, today),
promos_manager::Impression(promos_manager::Promo::DefaultBrowser,
today - 7),
promos_manager::Impression(promos_manager::Promo::AppStoreRating,
today - 14),
promos_manager::Impression(
promos_manager::Promo::CredentialProviderExtension, today - 180),
};
const std::vector<promos_manager::Promo> expected;
EXPECT_EQ(promos_manager_->LeastRecentlyShown(active_promos, impressions),
expected);
}
// Tests PromosManager::LeastRecentlyShown() gracefully returns an empty array
// when no impression history exists (i.e. there's no 'least recently
// shown' promo because empty impression history means no promo has ever been
// shown.)
TEST_F(PromosManagerTest,
ReturnsEmptyListWhenLeastRecentlyShownHasNoImpressionHistory) {
const std::set<promos_manager::Promo> active_promos = {
promos_manager::Promo::CredentialProviderExtension,
};
const std::vector<promos_manager::Impression> impressions;
const std::vector<promos_manager::Promo> expected;
EXPECT_EQ(promos_manager_->LeastRecentlyShown(active_promos, impressions),
expected);
}
// Tests PromosManager::LeastRecentlyShown() sorts unshown promos before shown
// promos.
TEST_F(PromosManagerTest,
SortsUnshownPromosBeforeShownPromosForLeastRecentlyShown) {
const std::set<promos_manager::Promo> active_promos = {
promos_manager::Promo::Test,
promos_manager::Promo::CredentialProviderExtension,
promos_manager::Promo::AppStoreRating,
promos_manager::Promo::DefaultBrowser,
};
int today = TodaysDay();
const std::vector<promos_manager::Impression> impressions = {
promos_manager::Impression(promos_manager::Promo::Test, today),
promos_manager::Impression(promos_manager::Promo::DefaultBrowser,
today - 7),
};
const std::vector<promos_manager::Promo> expected = {
promos_manager::Promo::CredentialProviderExtension,
promos_manager::Promo::AppStoreRating,
promos_manager::Promo::DefaultBrowser,
promos_manager::Promo::Test,
};
EXPECT_EQ(promos_manager_->LeastRecentlyShown(active_promos, impressions),
expected);
}
// Tests PromosManager::ImpressionHistory() correctly ingests impression history
// (base::Value::List) and returns corresponding
// std::vector<promos_manager::Impression>.
TEST_F(PromosManagerTest, ReturnsImpressionHistory) {
int today = TodaysDay();
base::Value::Dict first_impression;
first_impression.Set(
promos_manager::kImpressionPromoKey,
promos_manager::NameForPromo(promos_manager::Promo::DefaultBrowser));
first_impression.Set(promos_manager::kImpressionDayKey, today);
base::Value::Dict second_impression;
second_impression.Set(
promos_manager::kImpressionPromoKey,
promos_manager::NameForPromo(promos_manager::Promo::AppStoreRating));
second_impression.Set(promos_manager::kImpressionDayKey, today - 7);
base::Value::List impressions;
impressions.Append(first_impression.Clone());
impressions.Append(second_impression.Clone());
std::vector<promos_manager::Impression> expected = {
promos_manager::Impression(promos_manager::Promo::DefaultBrowser, today),
promos_manager::Impression(promos_manager::Promo::AppStoreRating,
today - 7),
};
std::vector<promos_manager::Impression> result =
promos_manager_->ImpressionHistory(impressions);
EXPECT_EQ(expected.size(), result.size());
EXPECT_EQ(expected[0].promo, result[0].promo);
EXPECT_EQ(expected[0].day, result[0].day);
EXPECT_EQ(expected[1].promo, result[1].promo);
EXPECT_EQ(expected[1].day, result[1].day);
}
// Tests PromosManager::ImpressionHistory() correctly ingests empty impression
// history (base::Value::List) and returns empty
// std::vector<promos_manager::Impression>.
TEST_F(PromosManagerTest, ReturnsBlankImpressionHistoryForBlankPrefs) {
base::Value::List impressions;
std::vector<promos_manager::Impression> result =
promos_manager_->ImpressionHistory(impressions);
EXPECT_TRUE(result.empty());
}
// Tests PromosManager::ImpressionHistory() correctly ingests impression history
// with malformed data (base::Value::List) and returns corresponding
// std::vector<promos_manager::Impression> without malformed entries.
TEST_F(PromosManagerTest, ReturnsImpressionHistoryBySkippingMalformedEntries) {
int today = TodaysDay();
base::Value::Dict first_impression;
first_impression.Set(
promos_manager::kImpressionPromoKey,
promos_manager::NameForPromo(promos_manager::Promo::DefaultBrowser));
first_impression.Set(promos_manager::kImpressionDayKey, today);
base::Value::Dict second_impression;
second_impression.Set("foobar", promos_manager::NameForPromo(
promos_manager::Promo::AppStoreRating));
second_impression.Set(promos_manager::kImpressionDayKey, today - 7);
base::Value::List impressions;
impressions.Append(first_impression.Clone());
impressions.Append(second_impression.Clone());
std::vector<promos_manager::Impression> expected = {
promos_manager::Impression(promos_manager::Promo::DefaultBrowser, today),
};
std::vector<promos_manager::Impression> result =
promos_manager_->ImpressionHistory(impressions);
EXPECT_EQ(expected.size(), result.size());
EXPECT_EQ(expected[0].promo, result[0].promo);
EXPECT_EQ(expected[0].day, result[0].day);
}
// Tests PromosManager::ActivePromos() correctly ingests active promos
// (base::Value::List) and returns corresponding
// std::vector<promos_manager::Promo>.
TEST_F(PromosManagerTest, ReturnsActivePromos) {
base::Value::List promos;
promos.Append("promos_manager::Promo::DefaultBrowser");
promos.Append("promos_manager::Promo::AppStoreRating");
promos.Append("promos_manager::Promo::CredentialProviderExtension");
std::set<promos_manager::Promo> expected = {
promos_manager::Promo::DefaultBrowser,
promos_manager::Promo::AppStoreRating,
promos_manager::Promo::CredentialProviderExtension,
};
std::set<promos_manager::Promo> result =
promos_manager_->ActivePromos(promos);
EXPECT_EQ(expected, promos_manager_->ActivePromos(promos));
}
// Tests PromosManager::ActivePromos() correctly ingests empty active promos
// (base::Value::List) and returns empty std::set<promos_manager::Promo>.
TEST_F(PromosManagerTest, ReturnsBlankActivePromosForBlankPrefs) {
base::Value::List promos;
std::set<promos_manager::Promo> result =
promos_manager_->ActivePromos(promos);
EXPECT_TRUE(result.empty());
}
// Tests PromosManager::ActivePromos() correctly ingests active promos with
// malformed data (base::Value::List) and returns corresponding
// std::vector<promos_manager::Promo> with malformed entries pruned.
TEST_F(PromosManagerTest, ReturnsActivePromosAndSkipsMalformedData) {
base::Value::List promos;
promos.Append("promos_manager::Promo::DefaultBrowser");
promos.Append("promos_manager::Promo::AppStoreRating");
promos.Append("promos_manager::Promo::FOOBAR");
std::set<promos_manager::Promo> expected = {
promos_manager::Promo::DefaultBrowser,
promos_manager::Promo::AppStoreRating,
};
std::set<promos_manager::Promo> result =
promos_manager_->ActivePromos(promos);
EXPECT_EQ(expected, promos_manager_->ActivePromos(promos));
}
// Tests PromosManager::RegisterPromoForContinuousDisplay() correctly registers
// a promo for continuous display by writing the promo's name to the pref
// `kIosPromosManagerActivePromos`.
TEST_F(PromosManagerTest, RegistersPromoForContinuousDisplay) {
CreatePromosManager();
EXPECT_TRUE(
local_state_->GetList(prefs::kIosPromosManagerActivePromos).empty());
// Initial active promos state.
promos_manager_->RegisterPromoForContinuousDisplay(
promos_manager::Promo::CredentialProviderExtension);
promos_manager_->RegisterPromoForContinuousDisplay(
promos_manager::Promo::AppStoreRating);
EXPECT_EQ(local_state_->GetList(prefs::kIosPromosManagerActivePromos).size(),
(size_t)2);
// Register new promo.
promos_manager_->RegisterPromoForContinuousDisplay(
promos_manager::Promo::DefaultBrowser);
EXPECT_EQ(local_state_->GetList(prefs::kIosPromosManagerActivePromos).size(),
(size_t)3);
EXPECT_EQ(local_state_->GetList(prefs::kIosPromosManagerActivePromos)[0],
promos_manager::NameForPromo(
promos_manager::Promo::CredentialProviderExtension));
EXPECT_EQ(
local_state_->GetList(prefs::kIosPromosManagerActivePromos)[1],
promos_manager::NameForPromo(promos_manager::Promo::AppStoreRating));
EXPECT_EQ(
local_state_->GetList(prefs::kIosPromosManagerActivePromos)[2],
promos_manager::NameForPromo(promos_manager::Promo::DefaultBrowser));
}
// Tests PromosManager::RegisterPromoForContinuousDisplay() correctly registers
// a promo—for the very first time—for continuous display by writing the
// promo's name to the pref `kIosPromosManagerActivePromos`.
TEST_F(PromosManagerTest,
RegistersPromoForContinuousDisplayForEmptyActivePromos) {
CreatePromosManager();
EXPECT_TRUE(
local_state_->GetList(prefs::kIosPromosManagerActivePromos).empty());
promos_manager_->RegisterPromoForContinuousDisplay(
promos_manager::Promo::DefaultBrowser);
EXPECT_EQ(local_state_->GetList(prefs::kIosPromosManagerActivePromos).size(),
(size_t)1);
EXPECT_EQ(
local_state_->GetList(prefs::kIosPromosManagerActivePromos)[0],
promos_manager::NameForPromo(promos_manager::Promo::DefaultBrowser));
}
// Tests PromosManager::RegisterPromoForContinuousDisplay() correctly registers
// an already-registered promo for continuous display by first erasing, and then
// re-writing, the promo's name to the pref `kIosPromosManagerActivePromos`;
// tests no duplicate entries are created.
TEST_F(PromosManagerTest, RegistersAlreadyRegisteredPromoForContinuousDisplay) {
CreatePromosManager();
EXPECT_TRUE(
local_state_->GetList(prefs::kIosPromosManagerActivePromos).empty());
// Initial active promos state.
promos_manager_->RegisterPromoForContinuousDisplay(
promos_manager::Promo::CredentialProviderExtension);
promos_manager_->RegisterPromoForContinuousDisplay(
promos_manager::Promo::AppStoreRating);
EXPECT_EQ(local_state_->GetList(prefs::kIosPromosManagerActivePromos).size(),
(size_t)2);
// Register existing promo.
promos_manager_->RegisterPromoForContinuousDisplay(
promos_manager::Promo::CredentialProviderExtension);
EXPECT_EQ(local_state_->GetList(prefs::kIosPromosManagerActivePromos).size(),
(size_t)2);
EXPECT_EQ(
local_state_->GetList(prefs::kIosPromosManagerActivePromos)[0],
promos_manager::NameForPromo(promos_manager::Promo::AppStoreRating));
EXPECT_EQ(local_state_->GetList(prefs::kIosPromosManagerActivePromos)[1],
promos_manager::NameForPromo(
promos_manager::Promo::CredentialProviderExtension));
}
// Tests PromosManager::RegisterPromoForContinuousDisplay() correctly registers
// an already-registered promo for continuous display—for the very first time—by
// first erasing, and then re-writing, the promo's name to the pref
// `kIosPromosManagerActivePromos`; tests no duplicate entries are created.
TEST_F(
PromosManagerTest,
RegistersAlreadyRegisteredPromoForContinuousDisplayForEmptyActivePromos) {
CreatePromosManager();
EXPECT_TRUE(
local_state_->GetList(prefs::kIosPromosManagerActivePromos).empty());
// Initial active promos state.
promos_manager_->RegisterPromoForContinuousDisplay(
promos_manager::Promo::CredentialProviderExtension);
// Register existing promo.
promos_manager_->RegisterPromoForContinuousDisplay(
promos_manager::Promo::CredentialProviderExtension);
EXPECT_EQ(local_state_->GetList(prefs::kIosPromosManagerActivePromos).size(),
(size_t)1);
EXPECT_EQ(local_state_->GetList(prefs::kIosPromosManagerActivePromos)[0],
promos_manager::NameForPromo(
promos_manager::Promo::CredentialProviderExtension));
}
// Tests PromosManager::RegisterPromoForSingleDisplay() correctly registers
// a promo for single display by writing the promo's name to the pref
// `kIosPromosManagerSingleDisplayActivePromos`.
TEST_F(PromosManagerTest, RegistersPromoForSingleDisplay) {
CreatePromosManager();
EXPECT_TRUE(
local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos)
.empty());
// Initial active promos state.
promos_manager_->RegisterPromoForSingleDisplay(
promos_manager::Promo::CredentialProviderExtension);
promos_manager_->RegisterPromoForSingleDisplay(
promos_manager::Promo::AppStoreRating);
EXPECT_EQ(
local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos)
.size(),
(size_t)2);
// Register new promo.
promos_manager_->RegisterPromoForSingleDisplay(
promos_manager::Promo::DefaultBrowser);
EXPECT_EQ(
local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos)
.size(),
(size_t)3);
EXPECT_EQ(local_state_->GetList(
prefs::kIosPromosManagerSingleDisplayActivePromos)[0],
promos_manager::NameForPromo(
promos_manager::Promo::CredentialProviderExtension));
EXPECT_EQ(
local_state_->GetList(
prefs::kIosPromosManagerSingleDisplayActivePromos)[1],
promos_manager::NameForPromo(promos_manager::Promo::AppStoreRating));
EXPECT_EQ(
local_state_->GetList(
prefs::kIosPromosManagerSingleDisplayActivePromos)[2],
promos_manager::NameForPromo(promos_manager::Promo::DefaultBrowser));
}
// Tests PromosManager::RegisterPromoForSingleDisplay() correctly registers
// a promo for single display—for the very first time—by writing the promo's
// name to the pref `kIosPromosManagerSingleDisplayActivePromos`.
TEST_F(PromosManagerTest, RegistersPromoForSingleDisplayForEmptyActivePromos) {
CreatePromosManager();
EXPECT_TRUE(
local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos)
.empty());
promos_manager_->RegisterPromoForSingleDisplay(
promos_manager::Promo::DefaultBrowser);
EXPECT_EQ(
local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos)
.size(),
(size_t)1);
EXPECT_EQ(
local_state_->GetList(
prefs::kIosPromosManagerSingleDisplayActivePromos)[0],
promos_manager::NameForPromo(promos_manager::Promo::DefaultBrowser));
}
// Tests PromosManager::RegisterPromoForSingleDisplay() correctly registers
// an already-registered promo for single display by first erasing, and then
// re-writing, the promo's name to the pref
// `kIosPromosManagerSingleDisplayActivePromos`; tests no duplicate entries are
// created.
TEST_F(PromosManagerTest, RegistersAlreadyRegisteredPromoForSingleDisplay) {
CreatePromosManager();
EXPECT_TRUE(
local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos)
.empty());
// Initial active promos state.
promos_manager_->RegisterPromoForSingleDisplay(
promos_manager::Promo::CredentialProviderExtension);
promos_manager_->RegisterPromoForSingleDisplay(
promos_manager::Promo::AppStoreRating);
EXPECT_EQ(
local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos)
.size(),
(size_t)2);
// Register existing promo.
promos_manager_->RegisterPromoForSingleDisplay(
promos_manager::Promo::CredentialProviderExtension);
EXPECT_EQ(
local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos)
.size(),
(size_t)2);
EXPECT_EQ(
local_state_->GetList(
prefs::kIosPromosManagerSingleDisplayActivePromos)[0],
promos_manager::NameForPromo(promos_manager::Promo::AppStoreRating));
EXPECT_EQ(local_state_->GetList(
prefs::kIosPromosManagerSingleDisplayActivePromos)[1],
promos_manager::NameForPromo(
promos_manager::Promo::CredentialProviderExtension));
}
// Tests PromosManager::RegisterPromoForSingleDisplay() correctly registers
// an already-registered promo for single display—for the very first time—by
// first erasing, and then re-writing, the promo's name to the pref
// `kIosPromosManagerSingleDisplayActivePromos`; tests no duplicate entries are
// created.
TEST_F(PromosManagerTest,
RegistersAlreadyRegisteredPromoForSingleDisplayForEmptyActivePromos) {
CreatePromosManager();
EXPECT_TRUE(
local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos)
.empty());
// Initial active promos state.
promos_manager_->RegisterPromoForSingleDisplay(
promos_manager::Promo::CredentialProviderExtension);
// Register existing promo.
promos_manager_->RegisterPromoForSingleDisplay(
promos_manager::Promo::CredentialProviderExtension);
EXPECT_EQ(
local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos)
.size(),
(size_t)1);
EXPECT_EQ(local_state_->GetList(
prefs::kIosPromosManagerSingleDisplayActivePromos)[0],
promos_manager::NameForPromo(
promos_manager::Promo::CredentialProviderExtension));
}
// Tests PromosManager::InitializePromoImpressionLimits() correctly registers
// promo-specific impression limits.
TEST_F(PromosManagerTest, RegistersPromoSpecificImpressionLimits) {
CreatePromosManager();
ImpressionLimit* onceEveryTwoDays = [[ImpressionLimit alloc] initWithLimit:1
forNumDays:2];
ImpressionLimit* thricePerWeek = [[ImpressionLimit alloc] initWithLimit:3
forNumDays:7];
NSArray<ImpressionLimit*>* defaultBrowserLimits = @[
onceEveryTwoDays,
];
NSArray<ImpressionLimit*>* credentialProviderLimits = @[
thricePerWeek,
];
base::small_map<std::map<promos_manager::Promo, NSArray<ImpressionLimit*>*>>
promoImpressionLimits;
promoImpressionLimits[promos_manager::Promo::DefaultBrowser] =
defaultBrowserLimits;
promoImpressionLimits[promos_manager::Promo::CredentialProviderExtension] =
credentialProviderLimits;
promos_manager_->InitializePromoImpressionLimits(
std::move(promoImpressionLimits));
EXPECT_EQ(promos_manager_->PromoImpressionLimits(
promos_manager::Promo::DefaultBrowser),
defaultBrowserLimits);
EXPECT_EQ(promos_manager_->PromoImpressionLimits(
promos_manager::Promo::CredentialProviderExtension),
credentialProviderLimits);
}
// Tests PromosManager::RecordImpression() correctly records a new impression.
TEST_F(PromosManagerTest, RecordsImpression) {
CreatePromosManager();
promos_manager_->RecordImpression(promos_manager::Promo::DefaultBrowser);
EXPECT_EQ(local_state_->GetList(prefs::kIosPromosManagerImpressions).size(),
(size_t)1);
promos_manager_->RecordImpression(
promos_manager::Promo::CredentialProviderExtension);
const auto& impression_history =
local_state_->GetList(prefs::kIosPromosManagerImpressions);
const base::Value::Dict& first_impression = impression_history[0].GetDict();
const base::Value::Dict& second_impression = impression_history[1].GetDict();
EXPECT_EQ(impression_history.size(), (size_t)2);
EXPECT_EQ(*first_impression.FindString(promos_manager::kImpressionPromoKey),
"promos_manager::Promo::DefaultBrowser");
EXPECT_TRUE(
first_impression.FindInt(promos_manager::kImpressionDayKey).has_value());
EXPECT_EQ(first_impression.FindInt(promos_manager::kImpressionDayKey).value(),
TodaysDay());
EXPECT_EQ(*second_impression.FindString(promos_manager::kImpressionPromoKey),
"promos_manager::Promo::CredentialProviderExtension");
EXPECT_TRUE(
second_impression.FindInt(promos_manager::kImpressionDayKey).has_value());
EXPECT_EQ(
second_impression.FindInt(promos_manager::kImpressionDayKey).value(),
TodaysDay());
}
// Tests PromosManager::DeregisterPromo() correctly deregisters a currently
// active promo campaign.
TEST_F(PromosManagerTest, DeregistersActivePromo) {
CreatePromosManager();
EXPECT_EQ(local_state_->GetList(prefs::kIosPromosManagerActivePromos).size(),
(size_t)0);
EXPECT_EQ(
local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos)
.size(),
(size_t)0);
promos_manager_->RegisterPromoForContinuousDisplay(
promos_manager::Promo::CredentialProviderExtension);
EXPECT_EQ(local_state_->GetList(prefs::kIosPromosManagerActivePromos).size(),
(size_t)1);
EXPECT_EQ(
local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos)
.size(),
(size_t)0);
promos_manager_->RegisterPromoForSingleDisplay(
promos_manager::Promo::CredentialProviderExtension);
EXPECT_EQ(local_state_->GetList(prefs::kIosPromosManagerActivePromos).size(),
(size_t)1);
EXPECT_EQ(
local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos)
.size(),
(size_t)1);
promos_manager_->DeregisterPromo(
promos_manager::Promo::CredentialProviderExtension);
EXPECT_EQ(local_state_->GetList(prefs::kIosPromosManagerActivePromos).size(),
(size_t)0);
EXPECT_EQ(
local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos)
.size(),
(size_t)0);
}
// Tests PromosManager::DeregisterPromo() gracefully handles deregistration if
// the promo doesn't exist in a given active promos list.
TEST_F(PromosManagerTest, DeregistersNonExistentPromo) {
CreatePromosManager();
EXPECT_EQ(local_state_->GetList(prefs::kIosPromosManagerActivePromos).size(),
(size_t)0);
EXPECT_EQ(
local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos)
.size(),
(size_t)0);
promos_manager_->RegisterPromoForContinuousDisplay(
promos_manager::Promo::CredentialProviderExtension);
EXPECT_EQ(local_state_->GetList(prefs::kIosPromosManagerActivePromos).size(),
(size_t)1);
EXPECT_EQ(
local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos)
.size(),
(size_t)0);
promos_manager_->DeregisterPromo(
promos_manager::Promo::CredentialProviderExtension);
EXPECT_EQ(local_state_->GetList(prefs::kIosPromosManagerActivePromos).size(),
(size_t)0);
EXPECT_EQ(
local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos)
.size(),
(size_t)0);
}