blob: 014251c0c4a714cfc82e67a7f0bf3c0ca0e1c30b [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/content_settings/generated_javascript_optimizer_pref.h"
#include "base/run_loop.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/download/download_item_warning_data.h"
#include "chrome/browser/extensions/api/settings_private/generated_pref.h"
#include "chrome/common/extensions/api/settings_private.h"
#include "chrome/test/base/testing_profile.h"
#include "components/content_settings/core/browser/content_settings_registry.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/content_settings/core/common/features.h"
#include "components/content_settings/core/common/pref_names.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "content/public/common/content_features.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace settings_private_api = extensions::api::settings_private;
using extensions::settings_private::GeneratedPref;
using extensions::settings_private::SetPrefResult;
using settings_private_api::PrefObject;
namespace content_settings {
namespace {
int GetPrefValue(const PrefObject& pref_object) {
if (pref_object.type != settings_private_api::PrefType::kNumber ||
!pref_object.value->is_int()) {
return -1;
}
return pref_object.value->GetInt();
}
int GetGeneratedPrefValue(Profile* profile) {
PrefObject pref_object =
GeneratedJavascriptOptimizerPref(profile).GetPrefObject();
return GetPrefValue(pref_object);
}
extensions::settings_private::SetPrefResult SetPref(
GeneratedJavascriptOptimizerPref& pref,
const base::Value& value) {
return pref.SetPref(&value);
}
// GeneratedPref::Observer which exposes method for waiting till generated pref
// has changed.
class TestObserver : public GeneratedPref::Observer {
public:
TestObserver() {
base::RunLoop run_loop;
quit_closure_ = run_loop.QuitClosure();
}
~TestObserver() override = default;
void WaitForGeneratedPrefChange() {
if (was_pref_changed_) {
return;
}
base::RunLoop run_loop;
quit_closure_ = run_loop.QuitClosure();
run_loop.Run();
}
void OnGeneratedPrefChanged(const std::string&) override {
was_pref_changed_ = true;
if (quit_closure_) {
std::move(quit_closure_).Run();
}
}
private:
bool was_pref_changed_ = false;
base::OnceClosure quit_closure_;
};
} // anonymous namespace
class GeneratedJavascriptOptimizerPrefTest : public testing::Test {
public:
GeneratedJavascriptOptimizerPrefTest() = default;
void SetUp() override {
testing::Test::SetUp();
profile_ = std::make_unique<TestingProfile>();
host_content_settings_map_ =
HostContentSettingsMapFactory::GetForProfile(profile_.get());
}
TestingProfile* profile() { return profile_.get(); }
PrefService* prefs() { return profile()->GetPrefs(); }
HostContentSettingsMap* host_content_settings_map() {
return host_content_settings_map_.get();
}
private:
content::BrowserTaskEnvironment task_environment_;
std::unique_ptr<TestingProfile> profile_;
scoped_refptr<HostContentSettingsMap> host_content_settings_map_;
};
void EnableFeature(base::test::ScopedFeatureList* feature_list) {
feature_list
->InitWithFeatures(/*enabled_features=*/
{content_settings::features::
kBlockV8OptimizerOnUnfamiliarSitesSetting,
::features::kProcessSelectionDeferringConditions},
/*disabled_features=*/{});
}
TEST_F(GeneratedJavascriptOptimizerPrefTest, GetPrefObject_FeatureEnabled) {
base::test::ScopedFeatureList scoped_feature_list;
EnableFeature(&scoped_feature_list);
const struct TestCase {
ContentSetting content_setting;
bool pref_blocked_for_unfamiliar_sites;
JavascriptOptimizerSetting expected_setting;
} kTestCases[] = {
{ContentSetting::CONTENT_SETTING_ALLOW, false,
JavascriptOptimizerSetting::kAllowed},
{ContentSetting::CONTENT_SETTING_ALLOW, true,
JavascriptOptimizerSetting::kBlockedForUnfamiliarSites},
{ContentSetting::CONTENT_SETTING_BLOCK, false,
JavascriptOptimizerSetting::kBlocked},
{ContentSetting::CONTENT_SETTING_BLOCK, true,
JavascriptOptimizerSetting::kBlocked},
};
for (const auto& test_case : kTestCases) {
host_content_settings_map()->SetDefaultContentSetting(
ContentSettingsType::JAVASCRIPT_OPTIMIZER, test_case.content_setting);
prefs()->SetBoolean(prefs::kJavascriptOptimizerBlockedForUnfamiliarSites,
test_case.pref_blocked_for_unfamiliar_sites);
EXPECT_EQ(static_cast<int>(test_case.expected_setting),
GetGeneratedPrefValue(profile()));
}
}
TEST_F(GeneratedJavascriptOptimizerPrefTest, GetPrefObject_FeatureDisabled) {
host_content_settings_map()->SetDefaultContentSetting(
ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_ALLOW);
prefs()->SetBoolean(prefs::kJavascriptOptimizerBlockedForUnfamiliarSites,
true);
std::vector<base::test::FeatureRef> test_cases = {
content_settings::features::kBlockV8OptimizerOnUnfamiliarSitesSetting,
::features::kProcessSelectionDeferringConditions};
for (const base::test::FeatureRef& feature : test_cases) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndDisableFeature(*feature);
EXPECT_EQ(static_cast<int>(JavascriptOptimizerSetting::kAllowed),
GetGeneratedPrefValue(profile()));
}
}
// Test potential future scenario where
// kJavascriptOptimizerBlockedForUnfamiliarSites is updated by
// non generated-pref code.
TEST_F(GeneratedJavascriptOptimizerPrefTest,
GetPrefObject_PrefChangedExternally) {
base::test::ScopedFeatureList scoped_feature_list;
EnableFeature(&scoped_feature_list);
prefs()->SetBoolean(prefs::kJavascriptOptimizerBlockedForUnfamiliarSites,
false);
EXPECT_EQ(static_cast<int>(JavascriptOptimizerSetting::kAllowed),
GetGeneratedPrefValue(profile()));
GeneratedJavascriptOptimizerPref pref(profile());
TestObserver observer;
pref.AddObserver(&observer);
prefs()->SetBoolean(prefs::kJavascriptOptimizerBlockedForUnfamiliarSites,
true);
observer.WaitForGeneratedPrefChange();
EXPECT_EQ(
static_cast<int>(JavascriptOptimizerSetting::kBlockedForUnfamiliarSites),
GetGeneratedPrefValue(profile()));
}
TEST_F(GeneratedJavascriptOptimizerPrefTest, GetPrefObject_SafeBrowsingOff) {
profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnabled, false);
PrefObject pref_object =
GeneratedJavascriptOptimizerPref(profile()).GetPrefObject();
EXPECT_EQ(static_cast<int>(JavascriptOptimizerSetting::kAllowed),
GetPrefValue(pref_object));
EXPECT_EQ(settings_private_api::Enforcement::kEnforced,
pref_object.enforcement);
EXPECT_EQ(settings_private_api::ControlledBy::kSafeBrowsingOff,
pref_object.controlled_by);
}
TEST_F(GeneratedJavascriptOptimizerPrefTest,
GetPrefObject_DisableForUnfamiliar_ThenSafeBrowsingOff) {
base::test::ScopedFeatureList scoped_feature_list;
EnableFeature(&scoped_feature_list);
prefs()->SetBoolean(prefs::kJavascriptOptimizerBlockedForUnfamiliarSites,
true);
EXPECT_EQ(
static_cast<int>(JavascriptOptimizerSetting::kBlockedForUnfamiliarSites),
GetGeneratedPrefValue(profile()));
// Disable safe browsing after user has disabled v8-optimizers for unfamiliar
// sites.
profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnabled, false);
PrefObject pref_object =
GeneratedJavascriptOptimizerPref(profile()).GetPrefObject();
EXPECT_EQ(static_cast<int>(JavascriptOptimizerSetting::kAllowed),
GetPrefValue(pref_object));
EXPECT_EQ(settings_private_api::Enforcement::kEnforced,
pref_object.enforcement);
EXPECT_EQ(settings_private_api::ControlledBy::kSafeBrowsingOff,
pref_object.controlled_by);
}
TEST_F(GeneratedJavascriptOptimizerPrefTest, GetPrefObject_SafeBrowsingOn) {
profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnabled, true);
PrefObject pref_object =
GeneratedJavascriptOptimizerPref(profile()).GetPrefObject();
EXPECT_EQ(settings_private_api::Enforcement::kNone, pref_object.enforcement);
}
TEST_F(GeneratedJavascriptOptimizerPrefTest, GetPrefObject_Policy) {
ContentSettingsRegistry::GetInstance();
profile()->GetTestingPrefService()->SetManagedPref(
prefs::kManagedDefaultJavaScriptOptimizerSetting,
base::Value(ContentSetting::CONTENT_SETTING_BLOCK));
PrefObject pref_object =
GeneratedJavascriptOptimizerPref(profile()).GetPrefObject();
EXPECT_EQ(settings_private_api::Enforcement::kEnforced,
pref_object.enforcement);
EXPECT_EQ(settings_private_api::ControlledBy::kDevicePolicy,
pref_object.controlled_by);
}
TEST_F(GeneratedJavascriptOptimizerPrefTest,
GetPrefObject_PolicyDisablesFeature) {
base::test::ScopedFeatureList scoped_feature_list;
EnableFeature(&scoped_feature_list);
// Could be set by the user via chrome://settings prior to policy being set by
// administrator.
prefs()->SetBoolean(prefs::kJavascriptOptimizerBlockedForUnfamiliarSites,
true);
ContentSettingsRegistry::GetInstance();
profile()->GetTestingPrefService()->SetManagedPref(
prefs::kManagedDefaultJavaScriptOptimizerSetting,
base::Value(ContentSetting::CONTENT_SETTING_ALLOW));
EXPECT_EQ(static_cast<int>(JavascriptOptimizerSetting::kAllowed),
GetGeneratedPrefValue(profile()));
}
TEST_F(GeneratedJavascriptOptimizerPrefTest, SetPrefResult) {
const struct TestCase {
JavascriptOptimizerSetting setting;
ContentSetting expected_content_setting;
bool expected_pref_blocked_for_unfamiliar_sites;
} kTestCases[] = {
{JavascriptOptimizerSetting::kAllowed,
ContentSetting::CONTENT_SETTING_ALLOW, false},
{JavascriptOptimizerSetting::kBlockedForUnfamiliarSites,
ContentSetting::CONTENT_SETTING_ALLOW, true},
{JavascriptOptimizerSetting::kBlocked,
ContentSetting::CONTENT_SETTING_BLOCK, false},
};
for (const auto& test_case : kTestCases) {
GeneratedJavascriptOptimizerPref pref(profile());
SetPrefResult result =
SetPref(pref, base::Value(static_cast<int>(test_case.setting)));
EXPECT_EQ(result, SetPrefResult::SUCCESS);
EXPECT_EQ(host_content_settings_map()->GetDefaultContentSetting(
ContentSettingsType::JAVASCRIPT_OPTIMIZER),
test_case.expected_content_setting);
EXPECT_EQ(prefs()->GetBoolean(
prefs::kJavascriptOptimizerBlockedForUnfamiliarSites),
test_case.expected_pref_blocked_for_unfamiliar_sites);
}
}
TEST_F(GeneratedJavascriptOptimizerPrefTest, SetPref_NotInt) {
GeneratedJavascriptOptimizerPref pref(profile());
SetPrefResult result = SetPref(pref, base::Value("not an int"));
EXPECT_EQ(result, SetPrefResult::PREF_TYPE_MISMATCH);
}
TEST_F(GeneratedJavascriptOptimizerPrefTest, SetPref_OutOfRange) {
GeneratedJavascriptOptimizerPref pref(profile());
SetPrefResult result = SetPref(pref, base::Value(100));
EXPECT_EQ(result, SetPrefResult::PREF_TYPE_MISMATCH);
}
} // namespace content_settings