blob: 17dec2b0391f262ec944d4d0862ac7b954b9e015 [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/user_education/webui/whats_new_registry.h"
#include <memory>
#include "base/containers/contains.h"
#include "base/feature_list.h"
#include "base/test/scoped_feature_list.h"
#include "components/user_education/webui/mock_whats_new_storage_service.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/interaction/expect_call_in_scope.h"
using testing::Return;
using whats_new::WhatsNewEdition;
using whats_new::WhatsNewModule;
using whats_new::WhatsNewRegistry;
using whats_new::WhatsNewStorageService;
namespace user_education {
namespace {
using BrowserCommand = browser_command::mojom::Command;
// Modules
// Enabled through feature list.
BASE_FEATURE(kTestModuleEnabled,
"TestModuleEnabled",
base::FEATURE_DISABLED_BY_DEFAULT);
// Disabled through feature list.
BASE_FEATURE(kTestModuleDisabled,
"TestModuleDisabled",
base::FEATURE_DISABLED_BY_DEFAULT);
// Enabled by default.
BASE_FEATURE(kTestModuleEnabledByDefault,
"TestModuleEnabledByDefault",
base::FEATURE_ENABLED_BY_DEFAULT);
// Disabled by default.
BASE_FEATURE(kTestModuleDisabledByDefault,
"TestModuleDisabledByDefault",
base::FEATURE_DISABLED_BY_DEFAULT);
// Editions
// Enabled through feature list.
BASE_FEATURE(kTestEditionEnabled1,
"TestEditionEnabled1",
base::FEATURE_DISABLED_BY_DEFAULT);
// Enabled through feature list.
BASE_FEATURE(kTestEditionEnabled2,
"TestEditionEnabled2",
base::FEATURE_DISABLED_BY_DEFAULT);
// Enabled by default.
BASE_FEATURE(kTestEditionEnabledByDefault,
"TestEditionEnabledByDefault",
base::FEATURE_ENABLED_BY_DEFAULT);
// Disabled by default.
BASE_FEATURE(kTestEditionDisabled,
"TestEditionDisabled",
base::FEATURE_DISABLED_BY_DEFAULT);
// Previously used edition, enabled by default, unregistered.
BASE_FEATURE(kTestOldUnregisteredEdition,
"TestOldUnregisteredEdition",
base::FEATURE_ENABLED_BY_DEFAULT);
} // namespace
class WhatsNewRegistryTest : public testing::Test {
public:
WhatsNewRegistryTest() = default;
~WhatsNewRegistryTest() override = default;
void SetUp() override {
testing::Test::SetUp();
feature_list_.InitWithFeatures(
{kTestModuleEnabled, kTestEditionEnabled1, kTestEditionEnabled2},
{kTestModuleDisabled});
}
void CreateRegistry(
std::unique_ptr<MockWhatsNewStorageService> mock_storage_service) {
// One Enabled module
EXPECT_CALL(*mock_storage_service, SetModuleEnabled(testing::_)).Times(2);
// Create list of enabled modules in the same order as they are
// registered below.
stored_enabled_modules_.Append(kTestModuleEnabled.name);
stored_enabled_modules_.Append(kTestModuleEnabledByDefault.name);
// Create list of used editions.
stored_used_editions_.Set(kTestOldUnregisteredEdition.name, 100);
whats_new_registry_ =
std::make_unique<WhatsNewRegistry>(std::move(mock_storage_service));
}
void RegisterModules(
std::unique_ptr<MockWhatsNewStorageService> mock_storage_service) {
CreateRegistry(std::move(mock_storage_service));
// Modules
whats_new_registry_->RegisterModule(
WhatsNewModule(kTestModuleEnabled, "", BrowserCommand::kNoOpCommand));
whats_new_registry_->RegisterModule(
WhatsNewModule(kTestModuleDisabled, "", BrowserCommand::kMinValue));
whats_new_registry_->RegisterModule(
WhatsNewModule(kTestModuleEnabledByDefault, ""));
whats_new_registry_->RegisterModule(
WhatsNewModule(kTestModuleDisabledByDefault, ""));
whats_new_registry_->RegisterModule(
WhatsNewModule("", "", BrowserCommand::kUnknownCommand));
}
void RegisterModulesAndEditions(
std::unique_ptr<MockWhatsNewStorageService> mock_storage_service) {
RegisterModules(std::move(mock_storage_service));
// Editions
whats_new_registry_->RegisterEdition(WhatsNewEdition(
kTestEditionEnabled1, "",
{BrowserCommand::kOpenAISettings, BrowserCommand::kOpenSafetyCheck}));
whats_new_registry_->RegisterEdition(
WhatsNewEdition(kTestEditionEnabled2, ""));
whats_new_registry_->RegisterEdition(
WhatsNewEdition(kTestEditionEnabledByDefault, ""));
whats_new_registry_->RegisterEdition(
WhatsNewEdition(kTestEditionDisabled, ""));
}
void TearDown() override {
stored_enabled_modules_.clear();
stored_used_editions_.clear();
whats_new_registry_.reset();
testing::Test::TearDown();
}
protected:
base::Value::List stored_enabled_modules_;
base::Value::Dict stored_used_editions_;
std::unique_ptr<WhatsNewRegistry> whats_new_registry_;
base::test::ScopedFeatureList feature_list_;
};
TEST_F(WhatsNewRegistryTest, CommandsAreActiveForEnabledFeatures) {
auto mock_storage_service = std::make_unique<MockWhatsNewStorageService>();
RegisterModules(std::move(mock_storage_service));
auto active_commands = whats_new_registry_->GetActiveCommands();
EXPECT_EQ(static_cast<size_t>(2), active_commands.size());
EXPECT_TRUE(base::Contains(active_commands, BrowserCommand::kNoOpCommand));
EXPECT_TRUE(base::Contains(active_commands, BrowserCommand::kUnknownCommand));
}
TEST_F(WhatsNewRegistryTest, CommandsAreActiveForEnabledModulesAndEditions) {
auto mock_storage_service = std::make_unique<MockWhatsNewStorageService>();
RegisterModulesAndEditions(std::move(mock_storage_service));
auto active_commands = whats_new_registry_->GetActiveCommands();
EXPECT_EQ(static_cast<size_t>(4), active_commands.size());
EXPECT_TRUE(base::Contains(active_commands, BrowserCommand::kNoOpCommand));
EXPECT_TRUE(base::Contains(active_commands, BrowserCommand::kUnknownCommand));
// Note: If you are removing one of these commands, you may change
// these to any available command to match the above Edition
// registratrion.
EXPECT_TRUE(base::Contains(active_commands, BrowserCommand::kOpenAISettings));
EXPECT_TRUE(
base::Contains(active_commands, BrowserCommand::kOpenSafetyCheck));
}
TEST_F(WhatsNewRegistryTest, FindModulesForActiveFeatures) {
auto mock_storage_service = std::make_unique<MockWhatsNewStorageService>();
EXPECT_CALL(*mock_storage_service, FindEditionForCurrentVersion())
.WillOnce(Return(std::nullopt));
EXPECT_CALL(*mock_storage_service, ReadModuleData())
.WillOnce(testing::ReturnRef(stored_enabled_modules_));
EXPECT_CALL(*mock_storage_service, WasVersionPageUsedForCurrentMilestone)
.WillRepeatedly(Return(false));
RegisterModules(std::move(mock_storage_service));
auto active_features = whats_new_registry_->GetActiveFeatureNames();
EXPECT_EQ(static_cast<size_t>(1), active_features.size());
EXPECT_EQ("TestModuleEnabled", active_features.at(0));
}
TEST_F(WhatsNewRegistryTest, FindModulesForActiveFeaturesWithEditions) {
auto mock_storage_service = std::make_unique<MockWhatsNewStorageService>();
// No used edition.
EXPECT_CALL(*mock_storage_service, FindEditionForCurrentVersion())
.WillOnce(Return(std::nullopt));
EXPECT_CALL(*mock_storage_service, ReadModuleData())
.WillOnce(testing::ReturnRef(stored_enabled_modules_));
EXPECT_CALL(*mock_storage_service, IsUsedEdition(testing::_))
.WillRepeatedly(Return(false));
EXPECT_CALL(*mock_storage_service, WasVersionPageUsedForCurrentMilestone)
.WillRepeatedly(Return(false));
RegisterModulesAndEditions(std::move(mock_storage_service));
auto active_features = whats_new_registry_->GetActiveFeatureNames();
EXPECT_EQ(static_cast<size_t>(4), active_features.size());
// Editions appear first, in register order.
EXPECT_EQ("TestEditionEnabled1", active_features.at(0));
EXPECT_EQ("TestEditionEnabled2", active_features.at(1));
EXPECT_EQ("TestEditionEnabledByDefault", active_features.at(2));
// Modules appear last.
EXPECT_EQ("TestModuleEnabled", active_features.at(3));
}
TEST_F(WhatsNewRegistryTest, IgnoresEditionsWhenVersionWasUsed) {
auto mock_storage_service = std::make_unique<MockWhatsNewStorageService>();
// No used edition.
EXPECT_CALL(*mock_storage_service, FindEditionForCurrentVersion())
.WillOnce(Return(std::nullopt));
EXPECT_CALL(*mock_storage_service, ReadModuleData())
.WillOnce(testing::ReturnRef(stored_enabled_modules_));
EXPECT_CALL(*mock_storage_service, IsUsedEdition(testing::_))
.WillRepeatedly(Return(false));
// Version page is marked as used for this milestone.
EXPECT_CALL(*mock_storage_service, WasVersionPageUsedForCurrentMilestone)
.WillRepeatedly(Return(true));
RegisterModulesAndEditions(std::move(mock_storage_service));
auto active_features = whats_new_registry_->GetActiveFeatureNames();
EXPECT_EQ(static_cast<size_t>(1), active_features.size());
// Only modules appear.
EXPECT_EQ("TestModuleEnabled", active_features.at(0));
}
TEST_F(WhatsNewRegistryTest, FindModulesForActiveFeaturesWithUsedEdition) {
auto mock_storage_service = std::make_unique<MockWhatsNewStorageService>();
// Used for current version.
EXPECT_CALL(*mock_storage_service, FindEditionForCurrentVersion())
.WillOnce(Return(std::optional(kTestEditionEnabled1.name)));
EXPECT_CALL(*mock_storage_service, ReadModuleData())
.WillOnce(testing::ReturnRef(stored_enabled_modules_));
RegisterModulesAndEditions(std::move(mock_storage_service));
auto active_features = whats_new_registry_->GetActiveFeatureNames();
EXPECT_EQ(static_cast<size_t>(2), active_features.size());
// Used edition appears first.
EXPECT_EQ("TestEditionEnabled1", active_features.at(0));
// No other editions are added.
// Modules appear last.
EXPECT_EQ("TestModuleEnabled", active_features.at(1));
}
TEST_F(WhatsNewRegistryTest, FindModulesForRolledFeatures) {
auto mock_storage_service = std::make_unique<MockWhatsNewStorageService>();
EXPECT_CALL(*mock_storage_service, ReadModuleData())
.WillOnce(testing::ReturnRef(stored_enabled_modules_));
RegisterModules(std::move(mock_storage_service));
auto rolled_features = whats_new_registry_->GetRolledFeatureNames();
EXPECT_EQ(static_cast<size_t>(1), rolled_features.size());
EXPECT_EQ("TestModuleEnabledByDefault", rolled_features.at(0));
}
TEST_F(WhatsNewRegistryTest, SetEditionUsed) {
auto mock_storage_service = std::make_unique<MockWhatsNewStorageService>();
EXPECT_CALL(*mock_storage_service, SetEditionUsed("TestEditionEnabled1"));
RegisterModulesAndEditions(std::move(mock_storage_service));
whats_new_registry_->SetEditionUsed(kTestEditionEnabled1.name);
}
TEST_F(WhatsNewRegistryTest, ClearUnregisteredModules) {
auto mock_storage_service = std::make_unique<MockWhatsNewStorageService>();
// Add unregistered module to stored data.
stored_enabled_modules_.Append("TestModuleDoesNotExist");
EXPECT_CALL(*mock_storage_service, ReadModuleData())
.WillOnce(testing::ReturnRef(stored_enabled_modules_));
EXPECT_CALL(
*mock_storage_service,
ClearModules(std::set<std::string_view>({"TestModuleDoesNotExist"})));
RegisterModules(std::move(mock_storage_service));
whats_new_registry_->ClearUnregisteredModules();
}
TEST_F(WhatsNewRegistryTest, ClearUnregisteredEditions) {
auto mock_storage_service = std::make_unique<MockWhatsNewStorageService>();
EXPECT_CALL(*mock_storage_service, ReadEditionData())
.WillOnce(testing::ReturnRef(stored_used_editions_));
EXPECT_CALL(*mock_storage_service, ClearEditions(std::set<std::string_view>(
{"TestOldUnregisteredEdition"})));
RegisterModules(std::move(mock_storage_service));
whats_new_registry_->ClearUnregisteredEditions();
}
TEST_F(WhatsNewRegistryTest, ResetStorageService) {
auto mock_storage_service = std::make_unique<MockWhatsNewStorageService>();
EXPECT_CALL(*mock_storage_service, Reset());
RegisterModules(std::move(mock_storage_service));
whats_new_registry_->ResetData();
}
} // namespace user_education