| // 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 |