blob: 8245a9e4a1e9dfe6e81895b47c32113fb95eaf4d [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <string>
#include <vector>
#include "base/json/json_writer.h"
#include "base/prefs/pref_service.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/common/pref_names.h"
#include "extensions/test/result_catcher.h"
// API tests for chrome.accessibilityFeatures API.
// Note that the API is implemented using preference API infrastructure.
// See preference_api.cc for the list of accessibility features exposed by the
// API and the related preferences.
namespace extensions {
namespace {
// Keys for data in the test config argument that will be set for the test app
// to use.
// The test that the app should run.
const char kTestNameKey[] = "testName";
// Key for list of features enabled when the test is initialized.
const char kEnabledFeaturesKey[] = "enabled";
// Key for list fo features disabled when the test is initialized.
const char kDisabledFeaturesKey[] = "disabled";
// A test extension path. The extension has only |accessibilityFeatures.read|
// permission.
const char kTestExtensionPathReadPermission[] =
"accessibility_features/read_permission/";
// A test extension path. The extension has only |accessibilityFeatures.modify|
// permission.
const char kTestExtensionPathMofifyPermission[] =
"accessibility_features/modify_permission/";
// Accessibility features API test.
// Tests are parameterized by whether the test extension is write-only (the
// parameter value is true) or read-only (the parameter value is false).
class AccessibilityFeaturesApiTest : public ExtensionApiTest,
public testing::WithParamInterface<bool> {
public:
AccessibilityFeaturesApiTest() {}
virtual ~AccessibilityFeaturesApiTest() {}
protected:
// Returns pref service to be used to initialize and later verify
// accessibility preference values.
PrefService* GetPrefs() { return browser()->profile()->GetPrefs(); }
// Returns the path of the extension that should be used in a parameterized
// test.
std::string GetTestExtensionPath() const {
if (GetParam())
return kTestExtensionPathMofifyPermission;
return kTestExtensionPathReadPermission;
}
// Whether a parameterized test should have been able to modify accessibility
// preferences (i.e. whether the test extension had modify permission).
bool ShouldModifyingFeatureSucceed() const { return GetParam(); }
// Returns preference path for accessibility features as defined by the API.
const char* const GetPrefForFeature(const std::string& feature) {
if (feature == "spokenFeedback")
return prefs::kAccessibilitySpokenFeedbackEnabled;
if (feature == "largeCursor")
return prefs::kAccessibilityLargeCursorEnabled;
if (feature == "stickyKeys")
return prefs::kAccessibilityStickyKeysEnabled;
if (feature == "highContrast")
return prefs::kAccessibilityHighContrastEnabled;
if (feature == "screenMagnifier")
return prefs::kAccessibilityScreenMagnifierEnabled;
if (feature == "autoclick")
return prefs::kAccessibilityAutoclickEnabled;
if (feature == "virtualKeyboard")
return prefs::kAccessibilityVirtualKeyboardEnabled;
return NULL;
}
// Initializes preferences before running the test extension.
// |prefs| Pref service which should be initializzed.
// |enabled_features| List of boolean preference whose value should be set to
// true.
// |disabled_features| List of boolean preferences whose value should be set
// to false.
bool InitPrefServiceForTest(
PrefService* prefs,
const std::vector<std::string>& enabled_features,
const std::vector<std::string>& disabled_features) {
for (size_t i = 0; i < enabled_features.size(); ++i) {
const char* const pref_name = GetPrefForFeature(enabled_features[i]);
EXPECT_TRUE(pref_name) << "Invalid feature " << enabled_features[i];
if (!pref_name)
return false;
prefs->SetBoolean(pref_name, true);
}
for (size_t i = 0; i < disabled_features.size(); ++i) {
const char* const pref_name = GetPrefForFeature(disabled_features[i]);
EXPECT_TRUE(pref_name) << "Invalid feature " << disabled_features[i];
if (!pref_name)
return false;
prefs->SetBoolean(pref_name, false);
}
return true;
}
// Verifies that preferences have the expected value.
// |prefs| The pref service to be verified.
// |enabled_features| The list of boolean preferences whose value should be
// true.
// |disabled_features| The list of boolean preferences whose value should be
// false.
void VerifyPrefServiceState(
PrefService* prefs,
const std::vector<std::string>& enabled_features,
const std::vector<std::string>& disabled_features) {
for (size_t i = 0; i < enabled_features.size(); ++i) {
const char* const pref_name = GetPrefForFeature(enabled_features[i]);
ASSERT_TRUE(pref_name) << "Invalid feature " << enabled_features[i];
ASSERT_TRUE(prefs->GetBoolean(pref_name));
}
for (size_t i = 0; i < disabled_features.size(); ++i) {
const char* const pref_name = GetPrefForFeature(disabled_features[i]);
ASSERT_TRUE(pref_name) << "Invalid feature " << disabled_features[i];
ASSERT_FALSE(prefs->GetBoolean(pref_name));
}
}
// Given the test name and list of enabled and disabled features, generates
// and sets the JSON string that should be given to the test extension as
// test configuration.
// The result is saved to |result|. The return value is whether the test
// argument was successfully generated.
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::DictionaryValue test_arg;
test_arg.SetString(kTestNameKey, test_name);
scoped_ptr<base::ListValue> enabled_list(new base::ListValue);
for (size_t i = 0; i < enabled_features.size(); ++i)
enabled_list->AppendString(enabled_features[i]);
test_arg.Set(kEnabledFeaturesKey, enabled_list.release());
scoped_ptr<base::ListValue> disabled_list(new base::ListValue);
for (size_t i = 0; i < disabled_features.size(); ++i)
disabled_list->AppendString(disabled_features[i]);
test_arg.Set(kDisabledFeaturesKey, disabled_list.release());
return base::JSONWriter::Write(&test_arg, result);
}
};
INSTANTIATE_TEST_CASE_P(AccessibilityFeatureaApiTestInstantiatePermission,
AccessibilityFeaturesApiTest,
testing::Bool());
// Tests that an extension with read permission can read accessibility features
// state, while an extension that doesn't have the permission cannot.
IN_PROC_BROWSER_TEST_P(AccessibilityFeaturesApiTest, Get) {
// WARNING: Make sure that spoken feedback is not among enabled_features
// (see |Set| test for the reason).
std::vector<std::string> enabled_features;
enabled_features.push_back("largeCursor");
enabled_features.push_back("stickyKeys");
enabled_features.push_back("highContrast");
std::vector<std::string> disabled_features;
disabled_features.push_back("spokenFeedback");
disabled_features.push_back("screenMagnifier");
disabled_features.push_back("autoclick");
disabled_features.push_back("virtualKeyboard");
ASSERT_TRUE(
InitPrefServiceForTest(GetPrefs(), enabled_features, disabled_features));
std::string test_arg;
ASSERT_TRUE(GenerateTestArg(
"getterTest", enabled_features, disabled_features, &test_arg));
EXPECT_TRUE(
RunPlatformAppTestWithArg(GetTestExtensionPath(), test_arg.c_str()))
<< message_;
}
// Tests that an extension with modify permission can modify accessibility
// features, while an extension that doesn't have the permission can't.
IN_PROC_BROWSER_TEST_P(AccessibilityFeaturesApiTest, Set) {
// WARNING: Make sure that spoken feedback does not get enabled at this point
// (before the test app is loaded), as that may break the test:
// |RunPlatformAppTestWithArg| waits for the test extension to load by
// waiting for EXTENSION_LOADED notification to be observed. It also assumes
// that there is only one extension being loaded during this time (it finishes
// when the first notification is seen). Enabling spoken feedback here would
// break this assumption as it would induce loading of ChromeVox extension.
std::vector<std::string> enabled_features;
enabled_features.push_back("stickyKeys");
enabled_features.push_back("autoclick");
enabled_features.push_back("virtualKeyboard");
std::vector<std::string> disabled_features;
disabled_features.push_back("spokenFeedback");
disabled_features.push_back("largeCursor");
disabled_features.push_back("highContrast");
disabled_features.push_back("screenMagnifier");
ASSERT_TRUE(
InitPrefServiceForTest(GetPrefs(), enabled_features, disabled_features));
std::string test_arg;
ASSERT_TRUE(GenerateTestArg(
"setterTest", enabled_features, disabled_features, &test_arg));
// The test extension attempts to flip all feature values.
ASSERT_TRUE(
RunPlatformAppTestWithArg(GetTestExtensionPath(), test_arg.c_str()))
<< message_;
// The test tries to flip the feature states.
if (ShouldModifyingFeatureSucceed()) {
VerifyPrefServiceState(GetPrefs(), disabled_features, enabled_features);
} else {
VerifyPrefServiceState(GetPrefs(), enabled_features, disabled_features);
}
}
// Tests that an extension with read permission is notified when accessibility
// features change.
IN_PROC_BROWSER_TEST_F(AccessibilityFeaturesApiTest, ObserveFeatures) {
// WARNING: Make sure that spoken feedback is not among enabled_features
// (see |Set| test for the reason).
std::vector<std::string> enabled_features;
enabled_features.push_back("largeCursor");
enabled_features.push_back("stickyKeys");
enabled_features.push_back("highContrast");
std::vector<std::string> disabled_features;
disabled_features.push_back("screenMagnifier");
ASSERT_TRUE(
InitPrefServiceForTest(GetPrefs(), enabled_features, disabled_features));
std::string test_arg;
ASSERT_TRUE(GenerateTestArg(
"observerTest", enabled_features, disabled_features, &test_arg));
// The test extension is supposed to report result twice when runnign this
// test. First time when in initializes it's feature listeners, and second
// time, when gets all expected events. This is done so the extension is
// running when the accessibility features are flipped; oterwise, the
// extension may not see events.
ASSERT_TRUE(RunPlatformAppTestWithArg(kTestExtensionPathReadPermission,
test_arg.c_str()))
<< message_;
// This should flip all features.
ASSERT_TRUE(
InitPrefServiceForTest(GetPrefs(), disabled_features, enabled_features));
// Catch the second result notification sent by the test extension.
ResultCatcher result_catcher;
ASSERT_TRUE(result_catcher.GetNextResult()) << result_catcher.message();
}
} // namespace
} // namespace extensions