#include <stddef.h>
#include <string>
#include <vector>
#include "ash/constants/ash_pref_names.h"
#include "base/json/json_writer.h"
#include "base/values.h"
#include "chrome/browser/ash/accessibility/accessibility_test_utils.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "components/prefs/pref_service.h"
#include "content/public/test/browser_test.h"
#include "extensions/test/result_catcher.h"
namespace extensions {
namespace {
const char kTestNameKey[] = "testName";
const char kEnabledFeaturesKey[] = "enabled";
const char kDisabledFeaturesKey[] = "disabled";
const char kTestExtensionPathReadPermission[] =
"accessibility_features/read_permission/";
const char kTestExtensionPathReadPermissionV3[] =
"accessibility_features/mv3/read_permission/";
const char kTestExtensionPathModifyPermission[] =
"accessibility_features/modify_permission/";
const char kTestExtensionPathModifyPermissionV3[] =
"accessibility_features/mv3/modify_permission/";
using ManifestVersion = ash::ManifestVersion;
enum class Permission { kWriteOnly, kReadOnly };
struct TestConfig {
Permission permission;
ManifestVersion version;
};
class AccessibilityFeaturesApiTest
: public ExtensionApiTest,
public testing::WithParamInterface<TestConfig> {
public:
AccessibilityFeaturesApiTest() = default;
virtual ~AccessibilityFeaturesApiTest() = default;
protected:
PrefService* GetPrefs() { return browser()->profile()->GetPrefs(); }
const char* GetTestExtensionPath() const {
Permission permission = GetParam().permission;
ManifestVersion version = GetParam().version;
if (version == ManifestVersion::kTwo &&
permission == Permission::kWriteOnly) {
return kTestExtensionPathModifyPermission;
} else if (version == ManifestVersion::kTwo &&
permission == Permission::kReadOnly) {
return kTestExtensionPathReadPermission;
} else if (version == ManifestVersion::kThree &&
permission == Permission::kWriteOnly) {
return kTestExtensionPathModifyPermissionV3;
} else if (version == ManifestVersion::kThree &&
permission == Permission::kReadOnly) {
return kTestExtensionPathReadPermissionV3;
}
NOTREACHED();
}
bool ShouldModifyingFeatureSucceed() const {
return GetParam().permission == Permission::kWriteOnly;
}
const char* GetPrefForFeature(const std::string& feature) {
if (feature == "spokenFeedback")
return ash::prefs::kAccessibilitySpokenFeedbackEnabled;
if (feature == "largeCursor")
return ash::prefs::kAccessibilityLargeCursorEnabled;
if (feature == "stickyKeys")
return ash::prefs::kAccessibilityStickyKeysEnabled;
if (feature == "highContrast")
return ash::prefs::kAccessibilityHighContrastEnabled;
if (feature == "screenMagnifier")
return ash::prefs::kAccessibilityScreenMagnifierEnabled;
if (feature == "autoclick")
return ash::prefs::kAccessibilityAutoclickEnabled;
if (feature == "virtualKeyboard")
return ash::prefs::kAccessibilityVirtualKeyboardEnabled;
if (feature == "caretHighlight")
return ash::prefs::kAccessibilityCaretHighlightEnabled;
if (feature == "cursorHighlight")
return ash::prefs::kAccessibilityCursorHighlightEnabled;
if (feature == "focusHighlight")
return ash::prefs::kAccessibilityFocusHighlightEnabled;
if (feature == "selectToSpeak")
return ash::prefs::kAccessibilitySelectToSpeakEnabled;
if (feature == "switchAccess")
return ash::prefs::kAccessibilitySwitchAccessEnabled;
if (feature == "cursorColor")
return ash::prefs::kAccessibilityCursorColorEnabled;
if (feature == "dockedMagnifier")
return ash::prefs::kDockedMagnifierEnabled;
if (feature == "dictation")
return ash::prefs::kAccessibilityDictationEnabled;
return nullptr;
}
bool InitPrefServiceForTest(
PrefService* prefs,
const std::vector<std::string>& enabled_features,
const std::vector<std::string>& disabled_features) {
for (const auto& feature : enabled_features) {
const char* const pref_name = GetPrefForFeature(feature);
EXPECT_TRUE(pref_name) << "Invalid feature " << feature;
if (!pref_name)
return false;
prefs->SetBoolean(pref_name, true);
}
for (const auto& feature : disabled_features) {
const char* const pref_name = GetPrefForFeature(feature);
EXPECT_TRUE(pref_name) << "Invalid feature " << feature;
if (!pref_name)
return false;
prefs->SetBoolean(pref_name, false);
}
return true;
}
void VerifyPrefServiceState(
PrefService* prefs,
const std::vector<std::string>& enabled_features,
const std::vector<std::string>& disabled_features) {
for (const auto& feature : enabled_features) {
const char* const pref_name = GetPrefForFeature(feature);
ASSERT_TRUE(pref_name) << "Invalid feature " << feature;
ASSERT_TRUE(prefs->GetBoolean(pref_name));
}
for (const auto& feature : disabled_features) {
const char* const pref_name = GetPrefForFeature(feature);
ASSERT_TRUE(pref_name) << "Invalid feature " << feature;
ASSERT_FALSE(prefs->GetBoolean(pref_name));
}
}
bool GenerateTestArg(const std::string& test_name,
const std::vector<std::string>& enabled_features,
const std::vector<std::string>& disabled_features,
std::string* result) {
base::Value::Dict test_arg;
test_arg.Set(kTestNameKey, test_name);
base::Value::List enabled_list;
for (const auto& feature : enabled_features)
enabled_list.Append(feature);
test_arg.Set(kEnabledFeaturesKey, std::move(enabled_list));
base::Value::List disabled_list;
for (const auto& feature : disabled_features)
disabled_list.Append(feature);
test_arg.Set(kDisabledFeaturesKey, std::move(disabled_list));
return base::JSONWriter::Write(test_arg, result);
}
};
INSTANTIATE_TEST_SUITE_P(AccessibilityFeaturesApiTestWritePermission,
AccessibilityFeaturesApiTest,
::testing::Values(TestConfig{Permission::kWriteOnly,
ManifestVersion::kTwo}));
INSTANTIATE_TEST_SUITE_P(AccessibilityFeaturesApiTestReadPermission,
AccessibilityFeaturesApiTest,
::testing::Values(TestConfig{Permission::kReadOnly,
ManifestVersion::kTwo}));
INSTANTIATE_TEST_SUITE_P(AccessibilityFeaturesApiTestWritePermissionV3,
AccessibilityFeaturesApiTest,
::testing::Values(TestConfig{
Permission::kWriteOnly, ManifestVersion::kThree}));
INSTANTIATE_TEST_SUITE_P(AccessibilityFeaturesApiTestReadPermissionV3,
AccessibilityFeaturesApiTest,
::testing::Values(TestConfig{
Permission::kReadOnly, ManifestVersion::kThree}));
IN_PROC_BROWSER_TEST_P(AccessibilityFeaturesApiTest, Get) {
std::vector<std::string> enabled_features = {
"cursorColor", "cursorHighlight", "highContrast",
"largeCursor", "stickyKeys",
};
std::vector<std::string> disabled_features = {
"autoclick",
"caretHighlight",
"dockedMagnifier",
"focusHighlight",
"screenMagnifier",
"selectToSpeak",
"spokenFeedback",
"switchAccess",
"virtualKeyboard",
};
ASSERT_TRUE(
InitPrefServiceForTest(GetPrefs(), enabled_features, disabled_features));
std::string test_arg;
ASSERT_TRUE(GenerateTestArg("getterTest", enabled_features, disabled_features,
&test_arg));
bool is_mv2 = GetParam().version == ManifestVersion::kTwo;
EXPECT_TRUE(RunExtensionTest(
GetTestExtensionPath(),
{.custom_arg = test_arg.c_str(), .launch_as_platform_app = is_mv2}))
<< message_;
}
IN_PROC_BROWSER_TEST_P(AccessibilityFeaturesApiTest, PRE_Get_ComponentApp) {
bool is_mv2 = GetParam().version == ManifestVersion::kTwo;
EXPECT_FALSE(
RunExtensionTest(GetTestExtensionPath(),
{.custom_arg = "{}", .launch_as_platform_app = is_mv2},
{.load_as_component = is_mv2}))
<< message_;
}
IN_PROC_BROWSER_TEST_P(AccessibilityFeaturesApiTest, Get_ComponentApp) {
std::vector<std::string> enabled_features = {
"cursorHighlight",
"dockedMagnifier",
"highContrast",
"largeCursor",
"stickyKeys",
};
std::vector<std::string> disabled_features = {
"autoclick", "caretHighlight", "cursorColor",
"focusHighlight", "screenMagnifier", "selectToSpeak",
"spokenFeedback", "switchAccess", "virtualKeyboard",
};
ASSERT_TRUE(
InitPrefServiceForTest(GetPrefs(), enabled_features, disabled_features));
std::string test_arg;
ASSERT_TRUE(GenerateTestArg("getterTest", enabled_features, disabled_features,
&test_arg));
bool is_mv2 = GetParam().version == ManifestVersion::kTwo;
EXPECT_TRUE(RunExtensionTest(
GetTestExtensionPath(),
{.custom_arg = test_arg.c_str(), .launch_as_platform_app = is_mv2},
{.load_as_component = is_mv2}))
<< message_;
}
IN_PROC_BROWSER_TEST_P(AccessibilityFeaturesApiTest, Set) {
std::vector<std::string> enabled_features = {
"caretHighlight",
"cursorColor",
"focusHighlight",
"stickyKeys",
};
std::vector<std::string> disabled_features = {
"autoclick",
"cursorHighlight",
"dockedMagnifier",
"highContrast",
"largeCursor",
"screenMagnifier",
"selectToSpeak",
"spokenFeedback",
"switchAccess",
"virtualKeyboard",
};
ASSERT_TRUE(
InitPrefServiceForTest(GetPrefs(), enabled_features, disabled_features));
std::string test_arg;
ASSERT_TRUE(GenerateTestArg("setterTest", enabled_features, disabled_features,
&test_arg));
bool is_mv2 = GetParam().version == ManifestVersion::kTwo;
ASSERT_TRUE(RunExtensionTest(
GetTestExtensionPath(),
{.custom_arg = test_arg.c_str(), .launch_as_platform_app = is_mv2}))
<< message_;
if (ShouldModifyingFeatureSucceed()) {
VerifyPrefServiceState(GetPrefs(), disabled_features, enabled_features);
} else {
VerifyPrefServiceState(GetPrefs(), enabled_features, disabled_features);
}
}
IN_PROC_BROWSER_TEST_P(AccessibilityFeaturesApiTest, ObserveFeatures) {
std::vector<std::string> enabled_features = {
"caretHighlight",
"cursorColor",
"focusHighlight",
"stickyKeys",
};
std::vector<std::string> disabled_features = {
"autoclick",
"cursorHighlight",
"dockedMagnifier",
"highContrast",
"largeCursor",
"screenMagnifier",
"selectToSpeak",
"spokenFeedback",
"switchAccess",
"virtualKeyboard",
};
ASSERT_TRUE(
InitPrefServiceForTest(GetPrefs(), enabled_features, disabled_features));
std::string test_arg;
ASSERT_TRUE(GenerateTestArg("observerTest", enabled_features,
disabled_features, &test_arg));
bool is_mv2 = GetParam().version == ManifestVersion::kTwo;
const char* extension_path = is_mv2 ? kTestExtensionPathReadPermission
: kTestExtensionPathReadPermissionV3;
ASSERT_TRUE(RunExtensionTest(
extension_path,
{.custom_arg = test_arg.c_str(), .launch_as_platform_app = is_mv2}))
<< message_;
ASSERT_TRUE(
InitPrefServiceForTest(GetPrefs(), disabled_features, enabled_features));
ResultCatcher result_catcher;
ASSERT_TRUE(result_catcher.GetNextResult()) << result_catcher.message();
}
}
}