Home | History | Annotate | Download | only in extensions
      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