| OLD | NEW | 
|    1 #!/usr/bin/env python |    1 #!/usr/bin/env python | 
|    2 # Copyright 2015 The Chromium Authors. All rights reserved. |    2 # Copyright 2015 The Chromium Authors. All rights reserved. | 
|    3 # Use of this source code is governed by a BSD-style license that can be |    3 # Use of this source code is governed by a BSD-style license that can be | 
|    4 # found in the LICENSE file. |    4 # found in the LICENSE file. | 
|    5  |    5  | 
 |    6 import copy | 
|    6 import feature_compiler |    7 import feature_compiler | 
|    7 import unittest |    8 import unittest | 
|    8  |    9  | 
|    9 class FeatureCompilerTest(unittest.TestCase): |   10 class FeatureCompilerTest(unittest.TestCase): | 
|   10   """Test the FeatureCompiler. Note that we test that the expected features are |   11   """Test the FeatureCompiler. Note that we test that the expected features are | 
|   11   generated more thoroughly in features_generation_unittest.cc. And, of course, |   12   generated more thoroughly in features_generation_unittest.cc. And, of course, | 
|   12   this is most exhaustively tested through Chrome's compilation process (if a |   13   this is most exhaustively tested through Chrome's compilation process (if a | 
|   13   feature fails to parse, the compile fails). |   14   feature fails to parse, the compile fails). | 
|   14   These tests primarily focus on catching errors during parsing. |   15   These tests primarily focus on catching errors during parsing. | 
|   15   """ |   16   """ | 
|   16   def _parseFeature(self, value): |   17   def _parseFeature(self, value): | 
|   17     """Parses a feature from the given value and returns the result.""" |   18     """Parses a feature from the given value and returns the result.""" | 
|   18     f = feature_compiler.Feature('alpha') |   19     f = feature_compiler.Feature('alpha') | 
|   19     f.Parse(value) |   20     f.Parse(value, {}) | 
|   20     return f |   21     return f | 
|   21  |   22  | 
 |   23   def _createTestFeatureCompiler(self, feature_class): | 
 |   24     return feature_compiler.FeatureCompiler('chrome_root', [], feature_class, | 
 |   25         'provider_class', 'out_root', 'out_base_filename') | 
 |   26  | 
|   22   def _hasError(self, f, error): |   27   def _hasError(self, f, error): | 
|   23     """Asserts that |error| is present somewhere in the given feature's |   28     """Asserts that |error| is present somewhere in the given feature's | 
|   24     errors.""" |   29     errors.""" | 
|   25     self.assertTrue(f.errors) |   30     errors = f.GetErrors() | 
|   26     self.assertNotEqual(-1, str(f.errors).find(error), str(f.errors)) |   31     self.assertTrue(errors) | 
 |   32     self.assertNotEqual(-1, str(errors).find(error), str(errors)) | 
|   27  |   33  | 
|   28   def setUp(self): |   34   def setUp(self): | 
|   29     feature_compiler.ENABLE_ASSERTIONS = False |   35     feature_compiler.ENABLE_ASSERTIONS = False | 
|   30     feature_compiler.STRINGS_TO_UNICODE = True |   36     feature_compiler.STRINGS_TO_UNICODE = True | 
|   31  |   37  | 
|   32   def testFeature(self): |   38   def testFeature(self): | 
|   33     # Test some basic feature parsing for a sanity check. |   39     # Test some basic feature parsing for a sanity check. | 
|   34     f = self._parseFeature({ |   40     f = self._parseFeature({ | 
|   35       'blacklist': ['aaa', 'bbb'], |   41       'blacklist': ['aaa', 'bbb'], | 
|   36       'channel': 'stable', |   42       'channel': 'stable', | 
|   37       'command_line_switch': 'switch', |   43       'command_line_switch': 'switch', | 
|   38       'component_extensions_auto_granted': False, |   44       'component_extensions_auto_granted': False, | 
|   39       'contexts': ['blessed_extension', 'blessed_web_page'], |   45       'contexts': ['blessed_extension', 'blessed_web_page'], | 
|   40       'default_parent': True, |   46       'default_parent': True, | 
|   41       'dependencies': ['dependency1', 'dependency2'], |   47       'dependencies': ['dependency1', 'dependency2'], | 
|   42       'extension_types': ['extension'], |   48       'extension_types': ['extension'], | 
|   43       'location': 'component', |   49       'location': 'component', | 
|   44       'internal': True, |   50       'internal': True, | 
|   45       'matches': ['*://*/*'], |   51       'matches': ['*://*/*'], | 
|   46       'max_manifest_version': 1, |   52       'max_manifest_version': 1, | 
|   47       'noparent': True, |   53       'noparent': True, | 
|   48       'platforms': ['mac', 'win'], |   54       'platforms': ['mac', 'win'], | 
|   49       'session_types': ['kiosk', 'regular'], |   55       'session_types': ['kiosk', 'regular'], | 
|   50       'whitelist': ['zzz', 'yyy'] |   56       'whitelist': ['zzz', 'yyy'] | 
|   51     }) |   57     }) | 
|   52     self.assertFalse(f.errors) |   58     self.assertFalse(f.GetErrors()) | 
|   53  |   59  | 
|   54   def testInvalidAll(self): |   60   def testInvalidAll(self): | 
|   55     f = self._parseFeature({ |   61     f = self._parseFeature({ | 
|   56       'channel': 'stable', |   62       'channel': 'stable', | 
|   57       'dependencies': 'all', |   63       'dependencies': 'all', | 
|   58     }) |   64     }) | 
|   59     self._hasError(f, 'Illegal value: "all"') |   65     self._hasError(f, 'Illegal value: "all"') | 
|   60  |   66  | 
|   61   def testUnknownKeyError(self): |   67   def testUnknownKeyError(self): | 
|   62     f = self._parseFeature({ |   68     f = self._parseFeature({ | 
| (...skipping 19 matching lines...) Expand all  Loading... | 
|   82     self._hasError(f, 'Illegal value: "1"') |   88     self._hasError(f, 'Illegal value: "1"') | 
|   83  |   89  | 
|   84   def testImproperValue(self): |   90   def testImproperValue(self): | 
|   85     f = self._parseFeature({'noparent': False}) |   91     f = self._parseFeature({'noparent': False}) | 
|   86     self._hasError(f, 'Illegal value: "False"') |   92     self._hasError(f, 'Illegal value: "False"') | 
|   87  |   93  | 
|   88   def testApiFeaturesNeedContexts(self): |   94   def testApiFeaturesNeedContexts(self): | 
|   89     f = self._parseFeature({'dependencies': 'alpha', |   95     f = self._parseFeature({'dependencies': 'alpha', | 
|   90                             'extension_types': ['extension'], |   96                             'extension_types': ['extension'], | 
|   91                             'channel': 'trunk'}) |   97                             'channel': 'trunk'}) | 
|   92     f.Validate('APIFeature') |   98     f.Validate('APIFeature', {}) | 
|   93     self._hasError(f, 'APIFeatures must specify at least one context') |   99     self._hasError(f, 'APIFeatures must specify at least one context') | 
|   94  |  100  | 
|   95   def testManifestFeaturesNeedExtensionTypes(self): |  101   def testManifestFeaturesNeedExtensionTypes(self): | 
|   96     f = self._parseFeature({'dependencies': 'alpha', 'channel': 'beta'}) |  102     f = self._parseFeature({'dependencies': 'alpha', 'channel': 'beta'}) | 
|   97     f.Validate('ManifestFeature') |  103     f.Validate('ManifestFeature', {}) | 
|   98     self._hasError(f, |  104     self._hasError(f, | 
|   99                    'ManifestFeatures must specify at least one extension type') |  105                    'ManifestFeatures must specify at least one extension type') | 
|  100  |  106  | 
|  101   def testManifestFeaturesCantHaveContexts(self): |  107   def testManifestFeaturesCantHaveContexts(self): | 
|  102     f = self._parseFeature({'dependencies': 'alpha', |  108     f = self._parseFeature({'dependencies': 'alpha', | 
|  103                             'channel': 'beta', |  109                             'channel': 'beta', | 
|  104                             'extension_types': ['extension'], |  110                             'extension_types': ['extension'], | 
|  105                             'contexts': ['blessed_extension']}) |  111                             'contexts': ['blessed_extension']}) | 
|  106     f.Validate('ManifestFeature') |  112     f.Validate('ManifestFeature', {}) | 
|  107     self._hasError(f, 'ManifestFeatures do not support contexts') |  113     self._hasError(f, 'ManifestFeatures do not support contexts') | 
|  108  |  114  | 
|  109   def testPermissionFeaturesNeedExtensionTypes(self): |  115   def testPermissionFeaturesNeedExtensionTypes(self): | 
|  110     f = self._parseFeature({'dependencies': 'alpha', 'channel': 'beta'}) |  116     f = self._parseFeature({'dependencies': 'alpha', 'channel': 'beta'}) | 
|  111     f.Validate('PermissionFeature') |  117     f.Validate('PermissionFeature', {}) | 
|  112     self._hasError( |  118     self._hasError( | 
|  113         f, 'PermissionFeatures must specify at least one extension type') |  119         f, 'PermissionFeatures must specify at least one extension type') | 
|  114  |  120  | 
|  115   def testPermissionFeaturesCantHaveContexts(self): |  121   def testPermissionFeaturesCantHaveContexts(self): | 
|  116     f = self._parseFeature({'dependencies': 'alpha', |  122     f = self._parseFeature({'dependencies': 'alpha', | 
|  117                             'channel': 'beta', |  123                             'channel': 'beta', | 
|  118                             'extension_types': ['extension'], |  124                             'extension_types': ['extension'], | 
|  119                             'contexts': ['blessed_extension']}) |  125                             'contexts': ['blessed_extension']}) | 
|  120     f.Validate('PermissionFeature') |  126     f.Validate('PermissionFeature', {}) | 
|  121     self._hasError(f, 'PermissionFeatures do not support contexts') |  127     self._hasError(f, 'PermissionFeatures do not support contexts') | 
|  122  |  128  | 
|  123   def testAllPermissionsNeedChannelOrDependencies(self): |  129   def testAllPermissionsNeedChannelOrDependencies(self): | 
|  124     api_feature = self._parseFeature({'contexts': ['blessed_extension']}) |  130     api_feature = self._parseFeature({'contexts': ['blessed_extension']}) | 
|  125     api_feature.Validate('APIFeature') |  131     api_feature.Validate('APIFeature', {}) | 
|  126     self._hasError( |  132     self._hasError( | 
|  127         api_feature, 'Features must specify either a channel or dependencies') |  133         api_feature, 'Features must specify either a channel or dependencies') | 
|  128     permission_feature = self._parseFeature({'extension_types': ['extension']}) |  134     permission_feature = self._parseFeature({'extension_types': ['extension']}) | 
|  129     permission_feature.Validate('PermissionFeature') |  135     permission_feature.Validate('PermissionFeature', {}) | 
|  130     self._hasError(permission_feature, |  136     self._hasError(permission_feature, | 
|  131                    'Features must specify either a channel or dependencies') |  137                    'Features must specify either a channel or dependencies') | 
|  132     manifest_feature = self._parseFeature({'extension_types': ['extension']}) |  138     manifest_feature = self._parseFeature({'extension_types': ['extension']}) | 
|  133     manifest_feature.Validate('ManifestFeature') |  139     manifest_feature.Validate('ManifestFeature', {}) | 
|  134     self._hasError(manifest_feature, |  140     self._hasError(manifest_feature, | 
|  135                    'Features must specify either a channel or dependencies') |  141                    'Features must specify either a channel or dependencies') | 
|  136     channel_feature = self._parseFeature({'contexts': ['blessed_extension'], |  142     channel_feature = self._parseFeature({'contexts': ['blessed_extension'], | 
|  137                                           'channel': 'trunk'}) |  143                                           'channel': 'trunk'}) | 
|  138     channel_feature.Validate('APIFeature') |  144     channel_feature.Validate('APIFeature', {}) | 
|  139     self.assertFalse(channel_feature.errors) |  145     self.assertFalse(channel_feature.GetErrors()) | 
|  140     dependency_feature = self._parseFeature( |  146     dependency_feature = self._parseFeature( | 
|  141                              {'contexts': ['blessed_extension'], |  147                              {'contexts': ['blessed_extension'], | 
|  142                               'dependencies': ['alpha']}) |  148                               'dependencies': ['alpha']}) | 
|  143     dependency_feature.Validate('APIFeature') |  149     dependency_feature.Validate('APIFeature', {}) | 
|  144     self.assertFalse(dependency_feature.errors) |  150     self.assertFalse(dependency_feature.GetErrors()) | 
|  145  |  151  | 
 |  152   def testBothAliasAndSource(self): | 
 |  153     compiler = self._createTestFeatureCompiler('APIFeature') | 
 |  154     compiler._json = { | 
 |  155       'feature_alpha': { | 
 |  156         'channel': 'beta', | 
 |  157         'contexts': ['blessed_extension'], | 
 |  158         'alias': 'feature_alpha', | 
 |  159         'source': 'feature_alpha' | 
 |  160       } | 
 |  161     } | 
 |  162     compiler.Compile() | 
 |  163  | 
 |  164     feature = compiler._features.get('feature_alpha') | 
 |  165     self.assertTrue(feature) | 
 |  166     self._hasError(feature, 'Features cannot specify both alias and source.') | 
 |  167  | 
 |  168   def testAliasOnNonApiFeature(self): | 
 |  169     compiler = self._createTestFeatureCompiler('PermissionFeature') | 
 |  170     compiler._json = { | 
 |  171       'feature_alpha': { | 
 |  172         'channel': 'beta', | 
 |  173         'contexts': ['blessed_extension'], | 
 |  174         'alias': 'feature_beta' | 
 |  175       }, | 
 |  176       'feature_beta': [{ | 
 |  177         'channel': 'beta', | 
 |  178         'contexts': ['blessed_extension'], | 
 |  179         'source': 'feature_alpha' | 
 |  180       },{ | 
 |  181         'channel': 'dev', | 
 |  182         'context': ['blessed_extension'] | 
 |  183       }] | 
 |  184     }; | 
 |  185     compiler.Compile() | 
 |  186  | 
 |  187     feature = compiler._features.get('feature_alpha') | 
 |  188     self.assertTrue(feature) | 
 |  189     self._hasError(feature, 'PermissionFeatures do not support alias.') | 
 |  190  | 
 |  191     feature = compiler._features.get('feature_beta') | 
 |  192     self.assertTrue(feature) | 
 |  193     self._hasError(feature, 'PermissionFeatures do not support source.') | 
 |  194  | 
 |  195   def testAliasFeature(self): | 
 |  196     compiler = self._createTestFeatureCompiler('APIFeature') | 
 |  197     compiler._json = { | 
 |  198       'feature_alpha': { | 
 |  199         'channel': 'beta', | 
 |  200         'contexts': ['blessed_extension'], | 
 |  201         'alias': 'feature_beta' | 
 |  202       }, | 
 |  203       'feature_beta': { | 
 |  204         'channel': 'beta', | 
 |  205         'contexts': ['blessed_extension'], | 
 |  206         'source': 'feature_alpha' | 
 |  207       } | 
 |  208     }; | 
 |  209     compiler.Compile() | 
 |  210  | 
 |  211     feature = compiler._features.get('feature_alpha') | 
 |  212     self.assertTrue(feature) | 
 |  213     self.assertFalse(feature.GetErrors()) | 
 |  214  | 
 |  215     feature = compiler._features.get('feature_beta') | 
 |  216     self.assertTrue(feature) | 
 |  217     self.assertFalse(feature.GetErrors()) | 
 |  218  | 
 |  219   def testMultipleAliasesInComplexFeature(self): | 
 |  220     compiler = self._createTestFeatureCompiler('APIFeature') | 
 |  221     compiler._json = { | 
 |  222       'feature_alpha': [{ | 
 |  223         'channel': 'beta', | 
 |  224         'contexts': ['blessed_extension'], | 
 |  225         'alias': 'feature_beta' | 
 |  226       }, { | 
 |  227         'contexts': ['blessed_extension'], | 
 |  228         'channel': 'beta', | 
 |  229         'alias': 'feature_beta' | 
 |  230       }] | 
 |  231     }; | 
 |  232     compiler.Compile() | 
 |  233  | 
 |  234     feature = compiler._features.get('feature_alpha') | 
 |  235     self.assertTrue(feature) | 
 |  236     self._hasError(feature, 'Error parsing feature "feature_alpha" at key ' + | 
 |  237                             '"alias": Key can be set at most once per feature.') | 
 |  238  | 
 |  239   def testAliasReferenceInComplexFeature(self): | 
 |  240     compiler = self._createTestFeatureCompiler('APIFeature') | 
 |  241     compiler._json = { | 
 |  242       'feature_alpha': [{ | 
 |  243         'channel': 'beta', | 
 |  244         'contexts': ['blessed_extension'], | 
 |  245         'alias': 'feature_beta' | 
 |  246       }, { | 
 |  247         'contexts': ['blessed_extension'], | 
 |  248         'channel': 'beta', | 
 |  249       }], | 
 |  250       'feature_beta': { | 
 |  251         'channel': 'beta', | 
 |  252         'contexts': ['blessed_extension'], | 
 |  253         'source': 'feature_alpha' | 
 |  254       } | 
 |  255     }; | 
 |  256     compiler.Compile() | 
 |  257  | 
 |  258     feature = compiler._features.get('feature_alpha') | 
 |  259     self.assertTrue(feature) | 
 |  260     self.assertFalse(feature.GetErrors()) | 
 |  261  | 
 |  262     feature = compiler._features.get('feature_beta') | 
 |  263     self.assertTrue(feature) | 
 |  264     self.assertFalse(feature.GetErrors()) | 
 |  265  | 
 |  266   def testSourceMissingReference(self): | 
 |  267     compiler = self._createTestFeatureCompiler('APIFeature') | 
 |  268     compiler._json = { | 
 |  269       'feature_alpha': { | 
 |  270         'channel': 'beta', | 
 |  271         'contexts': ['blessed_extension'], | 
 |  272         'alias': 'feature_beta' | 
 |  273       }, | 
 |  274       'feature_beta': { | 
 |  275         'contexts': ['blessed_extension'], | 
 |  276         'channel': 'beta', | 
 |  277         'source': 'does_not_exist' | 
 |  278       } | 
 |  279     }; | 
 |  280     compiler.Compile() | 
 |  281  | 
 |  282     feature = compiler._features.get('feature_beta') | 
 |  283     self.assertTrue(feature) | 
 |  284     self._hasError(feature, 'A feature source property should reference a ' + | 
 |  285                             'feature whose alias property references it back.') | 
 |  286  | 
 |  287  | 
 |  288   def testAliasMissingReferenceInComplexFeature(self): | 
 |  289     compiler = self._createTestFeatureCompiler('APIFeature') | 
 |  290     compiler._json = { | 
 |  291       'feature_alpha': [{ | 
 |  292         'channel': 'beta', | 
 |  293         'contexts': ['blessed_extension'], | 
 |  294         'alias': 'feature_beta' | 
 |  295       }, { | 
 |  296         'contexts': ['blessed_extension'], | 
 |  297         'channel': 'beta' | 
 |  298       }] | 
 |  299     }; | 
 |  300     compiler.Compile() | 
 |  301  | 
 |  302     feature = compiler._features.get('feature_alpha') | 
 |  303     self.assertTrue(feature) | 
 |  304     self._hasError(feature, 'A feature alias property should reference a ' + | 
 |  305                             'feature whose source property references it back.') | 
 |  306  | 
 |  307   def testAliasReferenceMissingSourceInComplexFeature(self): | 
 |  308     compiler = self._createTestFeatureCompiler('APIFeature') | 
 |  309     compiler._json = { | 
 |  310       'feature_alpha': { | 
 |  311         'contexts': ['blessed_extension'], | 
 |  312         'channel': 'beta', | 
 |  313       }, | 
 |  314       'feature_beta': { | 
 |  315         'channel': 'beta', | 
 |  316         'contexts': ['blessed_extension'], | 
 |  317         'alias': 'feature_alpha' | 
 |  318       } | 
 |  319     }; | 
 |  320     compiler.Compile() | 
 |  321  | 
 |  322     feature = compiler._features.get('feature_alpha') | 
 |  323     self.assertTrue(feature) | 
 |  324     self.assertFalse(feature.GetErrors()) | 
 |  325  | 
 |  326     feature = compiler._features.get('feature_beta') | 
 |  327     self.assertTrue(feature) | 
 |  328     self._hasError(feature, 'A feature alias property should reference a ' + | 
 |  329                             'feature whose source property references it back.') | 
|  146  |  330  | 
|  147 if __name__ == '__main__': |  331 if __name__ == '__main__': | 
|  148   unittest.main() |  332   unittest.main() | 
| OLD | NEW |