// 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 #include #include #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 { 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* 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& enabled_features, const std::vector& 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& enabled_features, const std::vector& 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& enabled_features, const std::vector& disabled_features, std::string* result) { base::DictionaryValue test_arg; test_arg.SetString(kTestNameKey, test_name); scoped_ptr 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 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 enabled_features; enabled_features.push_back("largeCursor"); enabled_features.push_back("stickyKeys"); enabled_features.push_back("highContrast"); std::vector 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 enabled_features; enabled_features.push_back("stickyKeys"); enabled_features.push_back("autoclick"); enabled_features.push_back("virtualKeyboard"); std::vector 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 enabled_features; enabled_features.push_back("largeCursor"); enabled_features.push_back("stickyKeys"); enabled_features.push_back("highContrast"); std::vector 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