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
20 namespace extensions {
21
22 namespace {
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.
27 const char kTestNameKey[] = "testName";
28 // Key for list of features enabled when the test is initialized.
29 const char kEnabledFeaturesKey[] = "enabled";
30 // Key for list fo features disabled when the test is initialized.
31 const char kDisabledFeaturesKey[] = "disabled";
32
33 // A test extension path. The extension has only |accessibilityFeatures.read|
34 // permission.
35 const char kTestExtensionPathReadPermission[] =
36 "accessibility_features/read_permission/";
37 // A test extension path. The extension has only |accessibilityFeatures.modify|
38 // permission.
39 const 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).
45 class AccessibilityFeaturesApiTest : public ExtensionApiTest,
46 public testing::WithParamInterface<bool> {
47 public:
AccessibilityFeaturesApiTest()48 AccessibilityFeaturesApiTest() {}
~AccessibilityFeaturesApiTest()49 virtual ~AccessibilityFeaturesApiTest() {}
50
51 protected:
52 // Returns pref service to be used to initialize and later verify
53 // accessibility preference values.
GetPrefs()54 PrefService* GetPrefs() { return browser()->profile()->GetPrefs(); }
55
56 // Returns the path of the extension that should be used in a parameterized
57 // test.
GetTestExtensionPath() const58 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).
ShouldModifyingFeatureSucceed() const66 bool ShouldModifyingFeatureSucceed() const { return GetParam(); }
67
68 // Returns preference path for accessibility features as defined by the API.
GetPrefForFeature(const std::string & feature)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.
InitPrefServiceForTest(PrefService * prefs,const std::vector<std::string> & enabled_features,const std::vector<std::string> & disabled_features)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.
VerifyPrefServiceState(PrefService * prefs,const std::vector<std::string> & enabled_features,const std::vector<std::string> & disabled_features)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.
GenerateTestArg(const std::string & test_name,const std::vector<std::string> & enabled_features,const std::vector<std::string> & disabled_features,std::string * result)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
164 INSTANTIATE_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.
IN_PROC_BROWSER_TEST_P(AccessibilityFeaturesApiTest,Get)170 IN_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.
IN_PROC_BROWSER_TEST_P(AccessibilityFeaturesApiTest,Set)197 IN_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.
IN_PROC_BROWSER_TEST_F(AccessibilityFeaturesApiTest,ObserveFeatures)238 IN_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