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