Chromium Code Reviews| 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({ |
| 41 'alias': 'feature', | |
| 35 'blacklist': ['aaa', 'bbb'], | 42 'blacklist': ['aaa', 'bbb'], |
| 36 'channel': 'stable', | 43 'channel': 'stable', |
| 37 'command_line_switch': 'switch', | 44 'command_line_switch': 'switch', |
| 38 'component_extensions_auto_granted': False, | 45 'component_extensions_auto_granted': False, |
| 39 'contexts': ['blessed_extension', 'blessed_web_page'], | 46 'contexts': ['blessed_extension', 'blessed_web_page'], |
| 40 'default_parent': True, | 47 'default_parent': True, |
| 41 'dependencies': ['dependency1', 'dependency2'], | 48 'dependencies': ['dependency1', 'dependency2'], |
| 42 'extension_types': ['extension'], | 49 'extension_types': ['extension'], |
| 43 'location': 'component', | 50 'location': 'component', |
| 44 'internal': True, | 51 'internal': True, |
| 45 'matches': ['*://*/*'], | 52 'matches': ['*://*/*'], |
| 46 'max_manifest_version': 1, | 53 'max_manifest_version': 1, |
| 47 'noparent': True, | 54 'noparent': True, |
| 48 'platforms': ['mac', 'win'], | 55 'platforms': ['mac', 'win'], |
| 49 'session_types': ['kiosk', 'regular'], | 56 'session_types': ['kiosk', 'regular'], |
| 57 'source': 'feature', | |
|
Devlin
2016/11/23 15:56:14
It doesn't make sense to have both an alias and a
tbarzic
2016/11/23 20:16:41
I wouldn't say it necessarily doesn't make sense,
| |
| 50 'whitelist': ['zzz', 'yyy'] | 58 'whitelist': ['zzz', 'yyy'] |
| 51 }) | 59 }) |
| 52 self.assertFalse(f.errors) | 60 self.assertFalse(f.GetErrors()) |
| 53 | 61 |
| 54 def testInvalidAll(self): | 62 def testInvalidAll(self): |
| 55 f = self._parseFeature({ | 63 f = self._parseFeature({ |
| 56 'channel': 'stable', | 64 'channel': 'stable', |
| 57 'dependencies': 'all', | 65 'dependencies': 'all', |
| 58 }) | 66 }) |
| 59 self._hasError(f, 'Illegal value: "all"') | 67 self._hasError(f, 'Illegal value: "all"') |
| 60 | 68 |
| 61 def testUnknownKeyError(self): | 69 def testUnknownKeyError(self): |
| 62 f = self._parseFeature({ | 70 f = self._parseFeature({ |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 129 permission_feature.Validate('PermissionFeature') | 137 permission_feature.Validate('PermissionFeature') |
| 130 self._hasError(permission_feature, | 138 self._hasError(permission_feature, |
| 131 'Features must specify either a channel or dependencies') | 139 'Features must specify either a channel or dependencies') |
| 132 manifest_feature = self._parseFeature({'extension_types': ['extension']}) | 140 manifest_feature = self._parseFeature({'extension_types': ['extension']}) |
| 133 manifest_feature.Validate('ManifestFeature') | 141 manifest_feature.Validate('ManifestFeature') |
| 134 self._hasError(manifest_feature, | 142 self._hasError(manifest_feature, |
| 135 'Features must specify either a channel or dependencies') | 143 'Features must specify either a channel or dependencies') |
| 136 channel_feature = self._parseFeature({'contexts': ['blessed_extension'], | 144 channel_feature = self._parseFeature({'contexts': ['blessed_extension'], |
| 137 'channel': 'trunk'}) | 145 'channel': 'trunk'}) |
| 138 channel_feature.Validate('APIFeature') | 146 channel_feature.Validate('APIFeature') |
| 139 self.assertFalse(channel_feature.errors) | 147 self.assertFalse(channel_feature.GetErrors()) |
| 140 dependency_feature = self._parseFeature( | 148 dependency_feature = self._parseFeature( |
| 141 {'contexts': ['blessed_extension'], | 149 {'contexts': ['blessed_extension'], |
| 142 'dependencies': ['alpha']}) | 150 'dependencies': ['alpha']}) |
| 143 dependency_feature.Validate('APIFeature') | 151 dependency_feature.Validate('APIFeature') |
| 144 self.assertFalse(dependency_feature.errors) | 152 self.assertFalse(dependency_feature.GetErrors()) |
| 145 | 153 |
| 154 def testAliasFeature(self): | |
| 155 compiler = self._createTestFeatureCompiler('APIFeature') | |
| 156 compiler._json = { | |
| 157 'feature_alpha': { | |
| 158 'channel': 'beta', | |
| 159 'contexts': ['blessed_extension'], | |
| 160 'alias': 'feature_beta' | |
| 161 }, | |
| 162 'feature_beta': { | |
| 163 'channel': 'beta', | |
| 164 'contexts': ['blessed_extension'], | |
| 165 'source': 'feature_alpha' | |
| 166 } | |
| 167 }; | |
| 168 compiler.Compile() | |
| 169 | |
| 170 feature = compiler._features.get('feature_alpha') | |
| 171 self.assertTrue(feature) | |
| 172 self.assertFalse(feature.GetErrors()) | |
| 173 | |
| 174 feature = compiler._features.get('feature_beta') | |
| 175 self.assertTrue(feature) | |
| 176 self.assertFalse(feature.GetErrors()) | |
| 177 | |
| 178 def testMultipleAliasesInComplexFeature(self): | |
| 179 compiler = self._createTestFeatureCompiler('APIFeature') | |
| 180 compiler._json = { | |
| 181 'feature_alpha': [{ | |
| 182 'channel': 'beta', | |
| 183 'contexts': ['blessed_extension'], | |
| 184 'alias': 'feature_beta' | |
| 185 }, { | |
| 186 'contexts': ['blessed_extension'], | |
|
Devlin
2016/11/23 15:56:13
indentation
tbarzic
2016/11/23 20:16:41
Done
| |
| 187 'channel': 'beta', | |
| 188 'alias': 'feature_beta' | |
| 189 }] | |
| 190 }; | |
| 191 compiler.Compile() | |
| 192 | |
| 193 feature = compiler._features.get('feature_alpha') | |
| 194 self.assertTrue(feature) | |
| 195 self._hasError(feature, 'Error parsing feature "feature_alpha" at key ' + | |
| 196 '"alias": Key can be set at most once per feature.') | |
| 197 | |
| 198 def testAliasReferenceInComplexFeature(self): | |
| 199 compiler = self._createTestFeatureCompiler('APIFeature') | |
| 200 compiler._json = { | |
| 201 'feature_alpha': [{ | |
| 202 'channel': 'beta', | |
| 203 'contexts': ['blessed_extension'], | |
| 204 'alias': 'feature_beta' | |
| 205 }, { | |
| 206 'contexts': ['blessed_extension'], | |
| 207 'channel': 'beta', | |
| 208 }], | |
| 209 'feature_beta': { | |
| 210 'channel': 'beta', | |
| 211 'contexts': ['blessed_extension'], | |
| 212 'source': 'feature_alpha' | |
| 213 } | |
| 214 }; | |
| 215 compiler.Compile() | |
| 216 | |
| 217 feature = compiler._features.get('feature_alpha') | |
| 218 self.assertTrue(feature) | |
| 219 self.assertFalse(feature.GetErrors()) | |
| 220 | |
| 221 feature = compiler._features.get('feature_beta') | |
| 222 self.assertTrue(feature) | |
| 223 self.assertFalse(feature.GetErrors()) | |
| 224 | |
| 225 def testSourceMissingReference(self): | |
| 226 compiler = self._createTestFeatureCompiler('APIFeature') | |
| 227 compiler._json = { | |
| 228 'feature_alpha': { | |
| 229 'channel': 'beta', | |
| 230 'contexts': ['blessed_extension'], | |
| 231 'alias': 'feature_beta' | |
| 232 }, | |
| 233 'feature_beta': { | |
| 234 'contexts': ['blessed_extension'], | |
| 235 'channel': 'beta', | |
| 236 'source': 'does_not_exist' | |
| 237 } | |
| 238 }; | |
| 239 compiler.Compile() | |
| 240 | |
| 241 feature = compiler._features.get('feature_beta') | |
| 242 self.assertTrue(feature) | |
| 243 self._hasError(feature, 'A feature source property should reference a ' + | |
| 244 'feature whose alias property references it back.') | |
| 245 | |
| 246 | |
| 247 def testAliasMissingReferenceInComplexFeature(self): | |
| 248 compiler = self._createTestFeatureCompiler('APIFeature') | |
| 249 compiler._json = { | |
| 250 'feature_alpha': [{ | |
| 251 'channel': 'beta', | |
| 252 'contexts': ['blessed_extension'], | |
| 253 'alias': 'feature_beta' | |
| 254 }, { | |
| 255 'contexts': ['blessed_extension'], | |
|
Devlin
2016/11/23 15:56:14
indentation
tbarzic
2016/11/23 20:16:41
Done
| |
| 256 'channel': 'beta' | |
| 257 }] | |
| 258 }; | |
| 259 compiler.Compile() | |
| 260 | |
| 261 feature = compiler._features.get('feature_alpha') | |
| 262 self.assertTrue(feature) | |
| 263 self._hasError(feature, 'A feature alias property should reference a ' + | |
| 264 'feature whose source property references it back.') | |
| 265 | |
| 266 def testAliasReferenceMissingSourceInComplexFeature(self): | |
| 267 compiler = self._createTestFeatureCompiler('APIFeature') | |
| 268 compiler._json = { | |
| 269 'feature_alpha': { | |
| 270 'contexts': ['blessed_extension'], | |
| 271 'channel': 'beta', | |
| 272 }, | |
| 273 'feature_beta': { | |
| 274 'channel': 'beta', | |
| 275 'contexts': ['blessed_extension'], | |
| 276 'alias': 'feature_alpha' | |
| 277 } | |
| 278 }; | |
| 279 compiler.Compile() | |
| 280 | |
| 281 feature = compiler._features.get('feature_alpha') | |
| 282 self.assertTrue(feature) | |
| 283 self.assertFalse(feature.GetErrors()) | |
| 284 | |
| 285 feature = compiler._features.get('feature_beta') | |
| 286 self.assertTrue(feature) | |
| 287 self._hasError(feature, 'A feature alias property should reference a ' + | |
| 288 'feature whose source property references it back.') | |
| 146 | 289 |
| 147 if __name__ == '__main__': | 290 if __name__ == '__main__': |
| 148 unittest.main() | 291 unittest.main() |
| OLD | NEW |