1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <string> 6#include <vector> 7 8#include "base/json/json_writer.h" 9#include "base/prefs/pref_service.h" 10#include "base/strings/stringprintf.h" 11#include "base/values.h" 12#include "chrome/browser/extensions/extension_apitest.h" 13#include "chrome/common/pref_names.h" 14 15// API tests for chrome.accessibilityFeatures API. 16// Note that the API is implemented using preference API infrastructure. 17// See preference_api.cc for the list of accessibility features exposed by the 18// API and the related preferences. 19 20namespace extensions { 21 22namespace { 23 24// Keys for data in the test config argument that will be set for the test app 25// to use. 26// The test that the app should run. 27const char kTestNameKey[] = "testName"; 28// Key for list of features enabled when the test is initialized. 29const char kEnabledFeaturesKey[] = "enabled"; 30// Key for list fo features disabled when the test is initialized. 31const char kDisabledFeaturesKey[] = "disabled"; 32 33// A test extension path. The extension has only |accessibilityFeatures.read| 34// permission. 35const char kTestExtensionPathReadPermission[] = 36 "accessibility_features/read_permission/"; 37// A test extension path. The extension has only |accessibilityFeatures.modify| 38// permission. 39const char kTestExtensionPathMofifyPermission[] = 40 "accessibility_features/modify_permission/"; 41 42// Accessibility features API test. 43// Tests are parameterized by whether the test extension is write-only (the 44// parameter value is true) or read-only (the parameter value is false). 45class AccessibilityFeaturesApiTest : public ExtensionApiTest, 46 public testing::WithParamInterface<bool> { 47 public: 48 AccessibilityFeaturesApiTest() {} 49 virtual ~AccessibilityFeaturesApiTest() {} 50 51 protected: 52 // Returns pref service to be used to initialize and later verify 53 // accessibility preference values. 54 PrefService* GetPrefs() { return browser()->profile()->GetPrefs(); } 55 56 // Returns the path of the extension that should be used in a parameterized 57 // test. 58 std::string GetTestExtensionPath() const { 59 if (GetParam()) 60 return kTestExtensionPathMofifyPermission; 61 return kTestExtensionPathReadPermission; 62 } 63 64 // Whether a parameterized test should have been able to modify accessibility 65 // preferences (i.e. whether the test extension had modify permission). 66 bool ShouldModifyingFeatureSucceed() const { return GetParam(); } 67 68 // Returns preference path for accessibility features as defined by the API. 69 const char* const GetPrefForFeature(const std::string& feature) { 70 if (feature == "spokenFeedback") 71 return prefs::kAccessibilitySpokenFeedbackEnabled; 72 if (feature == "largeCursor") 73 return prefs::kAccessibilityLargeCursorEnabled; 74 if (feature == "stickyKeys") 75 return prefs::kAccessibilityStickyKeysEnabled; 76 if (feature == "highContrast") 77 return prefs::kAccessibilityHighContrastEnabled; 78 if (feature == "screenMagnifier") 79 return prefs::kAccessibilityScreenMagnifierEnabled; 80 if (feature == "autoclick") 81 return prefs::kAccessibilityAutoclickEnabled; 82 if (feature == "virtualKeyboard") 83 return prefs::kAccessibilityVirtualKeyboardEnabled; 84 return NULL; 85 } 86 87 // Initializes preferences before running the test extension. 88 // |prefs| Pref service which should be initializzed. 89 // |enabled_features| List of boolean preference whose value should be set to 90 // true. 91 // |disabled_features| List of boolean preferences whose value should be set 92 // to false. 93 bool InitPrefServiceForTest( 94 PrefService* prefs, 95 const std::vector<std::string>& enabled_features, 96 const std::vector<std::string>& disabled_features) { 97 for (size_t i = 0; i < enabled_features.size(); ++i) { 98 const char* const pref_name = GetPrefForFeature(enabled_features[i]); 99 EXPECT_TRUE(pref_name) << "Invalid feature " << enabled_features[i]; 100 if (!pref_name) 101 return false; 102 prefs->SetBoolean(pref_name, true); 103 } 104 105 for (size_t i = 0; i < disabled_features.size(); ++i) { 106 const char* const pref_name = GetPrefForFeature(disabled_features[i]); 107 EXPECT_TRUE(pref_name) << "Invalid feature " << disabled_features[i]; 108 if (!pref_name) 109 return false; 110 prefs->SetBoolean(pref_name, false); 111 } 112 return true; 113 } 114 115 // Verifies that preferences have the expected value. 116 // |prefs| The pref service to be verified. 117 // |enabled_features| The list of boolean preferences whose value should be 118 // true. 119 // |disabled_features| The list of boolean preferences whose value should be 120 // false. 121 void VerifyPrefServiceState( 122 PrefService* prefs, 123 const std::vector<std::string>& enabled_features, 124 const std::vector<std::string>& disabled_features) { 125 for (size_t i = 0; i < enabled_features.size(); ++i) { 126 const char* const pref_name = GetPrefForFeature(enabled_features[i]); 127 ASSERT_TRUE(pref_name) << "Invalid feature " << enabled_features[i]; 128 ASSERT_TRUE(prefs->GetBoolean(pref_name)); 129 } 130 131 for (size_t i = 0; i < disabled_features.size(); ++i) { 132 const char* const pref_name = GetPrefForFeature(disabled_features[i]); 133 ASSERT_TRUE(pref_name) << "Invalid feature " << disabled_features[i]; 134 ASSERT_FALSE(prefs->GetBoolean(pref_name)); 135 } 136 } 137 138 // Given the test name and list of enabled and disabled features, generates 139 // and sets the JSON string that should be given to the test extension as 140 // test configuration. 141 // The result is saved to |result|. The return value is whether the test 142 // argument was successfully generated. 143 bool GenerateTestArg(const std::string& test_name, 144 const std::vector<std::string>& enabled_features, 145 const std::vector<std::string>& disabled_features, 146 std::string* result) { 147 base::DictionaryValue test_arg; 148 test_arg.SetString(kTestNameKey, test_name); 149 150 scoped_ptr<base::ListValue> enabled_list(new base::ListValue); 151 for (size_t i = 0; i < enabled_features.size(); ++i) 152 enabled_list->AppendString(enabled_features[i]); 153 test_arg.Set(kEnabledFeaturesKey, enabled_list.release()); 154 155 scoped_ptr<base::ListValue> disabled_list(new base::ListValue); 156 for (size_t i = 0; i < disabled_features.size(); ++i) 157 disabled_list->AppendString(disabled_features[i]); 158 test_arg.Set(kDisabledFeaturesKey, disabled_list.release()); 159 160 return base::JSONWriter::Write(&test_arg, result); 161 } 162}; 163 164INSTANTIATE_TEST_CASE_P(AccessibilityFeatureaApiTestInstantiatePermission, 165 AccessibilityFeaturesApiTest, 166 testing::Bool()); 167 168// Tests that an extension with read permission can read accessibility features 169// state, while an extension that doesn't have the permission cannot. 170IN_PROC_BROWSER_TEST_P(AccessibilityFeaturesApiTest, Get) { 171 // WARNING: Make sure that spoken feedback is not among enabled_features 172 // (see |Set| test for the reason). 173 std::vector<std::string> enabled_features; 174 enabled_features.push_back("largeCursor"); 175 enabled_features.push_back("stickyKeys"); 176 enabled_features.push_back("highContrast"); 177 178 std::vector<std::string> disabled_features; 179 disabled_features.push_back("spokenFeedback"); 180 disabled_features.push_back("screenMagnifier"); 181 disabled_features.push_back("autoclick"); 182 disabled_features.push_back("virtualKeyboard"); 183 184 ASSERT_TRUE( 185 InitPrefServiceForTest(GetPrefs(), enabled_features, disabled_features)); 186 187 std::string test_arg; 188 ASSERT_TRUE(GenerateTestArg( 189 "getterTest", enabled_features, disabled_features, &test_arg)); 190 EXPECT_TRUE( 191 RunPlatformAppTestWithArg(GetTestExtensionPath(), test_arg.c_str())) 192 << message_; 193} 194 195// Tests that an extension with modify permission can modify accessibility 196// features, while an extension that doesn't have the permission can't. 197IN_PROC_BROWSER_TEST_P(AccessibilityFeaturesApiTest, Set) { 198 // WARNING: Make sure that spoken feedback does not get enabled at this point 199 // (before the test app is loaded), as that may break the test: 200 // |RunPlatformAppTestWithArg| waits for the test extension to load by 201 // waiting for EXTENSION_LOADED notification to be observed. It also assumes 202 // that there is only one extension being loaded during this time (it finishes 203 // when the first notification is seen). Enabling spoken feedback here would 204 // break this assumption as it would induce loading of ChromeVox extension. 205 std::vector<std::string> enabled_features; 206 enabled_features.push_back("stickyKeys"); 207 enabled_features.push_back("autoclick"); 208 enabled_features.push_back("virtualKeyboard"); 209 210 std::vector<std::string> disabled_features; 211 disabled_features.push_back("spokenFeedback"); 212 disabled_features.push_back("largeCursor"); 213 disabled_features.push_back("highContrast"); 214 disabled_features.push_back("screenMagnifier"); 215 216 ASSERT_TRUE( 217 InitPrefServiceForTest(GetPrefs(), enabled_features, disabled_features)); 218 219 std::string test_arg; 220 ASSERT_TRUE(GenerateTestArg( 221 "setterTest", enabled_features, disabled_features, &test_arg)); 222 223 // The test extension attempts to flip all feature values. 224 ASSERT_TRUE( 225 RunPlatformAppTestWithArg(GetTestExtensionPath(), test_arg.c_str())) 226 << message_; 227 228 // The test tries to flip the feature states. 229 if (ShouldModifyingFeatureSucceed()) { 230 VerifyPrefServiceState(GetPrefs(), disabled_features, enabled_features); 231 } else { 232 VerifyPrefServiceState(GetPrefs(), enabled_features, disabled_features); 233 } 234} 235 236// Tests that an extension with read permission is notified when accessibility 237// features change. 238IN_PROC_BROWSER_TEST_F(AccessibilityFeaturesApiTest, ObserveFeatures) { 239 // WARNING: Make sure that spoken feedback is not among enabled_features 240 // (see |Set| test for the reason). 241 std::vector<std::string> enabled_features; 242 enabled_features.push_back("largeCursor"); 243 enabled_features.push_back("stickyKeys"); 244 enabled_features.push_back("highContrast"); 245 246 std::vector<std::string> disabled_features; 247 disabled_features.push_back("screenMagnifier"); 248 249 ASSERT_TRUE( 250 InitPrefServiceForTest(GetPrefs(), enabled_features, disabled_features)); 251 252 std::string test_arg; 253 ASSERT_TRUE(GenerateTestArg( 254 "observerTest", enabled_features, disabled_features, &test_arg)); 255 256 // The test extension is supposed to report result twice when runnign this 257 // test. First time when in initializes it's feature listeners, and second 258 // time, when gets all expected events. This is done so the extension is 259 // running when the accessibility features are flipped; oterwise, the 260 // extension may not see events. 261 ASSERT_TRUE(RunPlatformAppTestWithArg(kTestExtensionPathReadPermission, 262 test_arg.c_str())) 263 << message_; 264 265 // This should flip all features. 266 ASSERT_TRUE( 267 InitPrefServiceForTest(GetPrefs(), disabled_features, enabled_features)); 268 269 // Catch the second result notification sent by the test extension. 270 ResultCatcher result_catcher; 271 ASSERT_TRUE(result_catcher.GetNextResult()) << result_catcher.message(); 272} 273 274} // namespace 275 276} // namespace extensions 277