| 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 |