OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # Copyright (c) 2013 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2013 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 """Provides test coverage for individual recipes. | 6 """Provides test coverage for individual recipes. |
7 | 7 |
8 Recipe tests are located in ../recipes_test/*.py. | 8 Recipe tests are located in ../recipes_test/*.py. |
9 | 9 |
10 Each py file's splitext'd name is expected to match a recipe in ../recipes/*.py. | 10 Each py file's splitext'd name is expected to match a recipe in ../recipes/*.py. |
(...skipping 23 matching lines...) Expand all Loading... |
34 | 34 |
35 Additionally, this test cannot pass unless every recipe in ../recipes has 100% | 35 Additionally, this test cannot pass unless every recipe in ../recipes has 100% |
36 code coverage when executed via the tests in ../recipes_test. | 36 code coverage when executed via the tests in ../recipes_test. |
37 """ | 37 """ |
38 | 38 |
39 import collections | 39 import collections |
40 import contextlib | 40 import contextlib |
41 import json | 41 import json |
42 import os | 42 import os |
43 import sys | 43 import sys |
44 import unittest | |
45 | 44 |
46 from glob import glob | 45 from glob import glob |
47 | 46 |
48 import test_env # pylint: disable=W0611 | 47 import test_env # pylint: disable=W0611 |
49 | 48 |
50 import coverage | 49 import coverage |
51 | 50 |
| 51 import common.python26_polyfill # pylint: disable=W0611 |
| 52 import unittest |
| 53 |
52 from common import annotator | 54 from common import annotator |
53 | 55 |
54 SCRIPT_PATH = os.path.abspath(os.path.dirname(__file__)) | 56 SCRIPT_PATH = os.path.abspath(os.path.dirname(__file__)) |
55 ROOT_PATH = os.path.abspath(os.path.join(SCRIPT_PATH, os.pardir, os.pardir, | 57 ROOT_PATH = os.path.abspath(os.path.join(SCRIPT_PATH, os.pardir, os.pardir, |
56 os.pardir)) | 58 os.pardir)) |
57 SLAVE_DIR = os.path.join(ROOT_PATH, 'slave', 'fake_slave', 'build') | 59 SLAVE_DIR = os.path.join(ROOT_PATH, 'slave', 'fake_slave', 'build') |
58 INTERNAL_DIR = os.path.join(ROOT_PATH, os.pardir, 'build_internal') | 60 INTERNAL_DIR = os.path.join(ROOT_PATH, os.pardir, 'build_internal') |
59 BASE_DIRS = { | 61 BASE_DIRS = { |
60 'Public': os.path.dirname(SCRIPT_PATH), | 62 'Public': os.path.dirname(SCRIPT_PATH), |
61 'Internal': os.path.join(INTERNAL_DIR, 'scripts', 'slave'), | 63 'Internal': os.path.join(INTERNAL_DIR, 'scripts', 'slave'), |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
191 | 193 |
192 | 194 |
193 def train_from_tests(recipe_path): | 195 def train_from_tests(recipe_path): |
194 for path in glob(expected_for(recipe_path, '*')): | 196 for path in glob(expected_for(recipe_path, '*')): |
195 os.unlink(path) | 197 os.unlink(path) |
196 | 198 |
197 for name, test_data in exec_test_file(recipe_path): | 199 for name, test_data in exec_test_file(recipe_path): |
198 steps = execute_test_case(test_data, recipe_path) | 200 steps = execute_test_case(test_data, recipe_path) |
199 expected_path = expected_for(recipe_path, name) | 201 expected_path = expected_for(recipe_path, name) |
200 print 'Writing', expected_path | 202 print 'Writing', expected_path |
201 with open(expected_path, 'w') as f: | 203 with open(expected_path, 'wb') as f: |
202 f.write('[') | 204 f.write('[') |
203 first = True | 205 first = True |
204 for step in steps: | 206 for step in steps: |
205 f.write(('' if first else '\n },')+'\n {') | 207 f.write(('' if first else '\n },')+'\n {') |
206 first_dict_item = True | 208 first_dict_item = True |
207 for key, value in sorted(step.items(), key=lambda x: x[0]): | 209 for key, value in sorted(step.items(), key=lambda x: x[0]): |
208 f.write(('' if first_dict_item else ',')+'\n ') | 210 f.write(('' if first_dict_item else ',')+'\n ') |
209 f.write('"%s": ' % key) | 211 f.write('"%s": ' % key) |
210 json.dump(value, f, sort_keys=True) | 212 json.dump(value, f, sort_keys=True) |
211 first_dict_item = False | 213 first_dict_item = False |
212 first = False | 214 first = False |
213 f.write('\n }\n]') | 215 f.write('\n }\n]') |
214 | 216 |
215 return True | 217 return True |
216 | 218 |
217 | 219 |
218 def load_tests(loader, _standard_tests, _pattern): | 220 def load_tests(loader, _standard_tests, _pattern): |
219 """This method is invoked by unittest.main's automatic testloader.""" | 221 """This method is invoked by unittest.main's automatic testloader.""" |
220 def create_test_class(recipe_path): | 222 def create_test_class(recipe_path): |
221 class RecipeTest(unittest.TestCase): | 223 class RecipeTest(unittest.TestCase): |
222 @classmethod | 224 @classmethod |
223 def add_test_methods(cls): | 225 def add_test_methods(cls): |
224 for name, test_data in exec_test_file(recipe_path): | 226 for name, test_data in exec_test_file(recipe_path): |
225 expected_path = expected_for(recipe_path, name) | 227 expected_path = expected_for(recipe_path, name) |
226 def add_test(test_data, expected_path): | 228 def add_test(test_data, expected_path): |
227 def test_(self): | 229 def test_(self): |
228 steps = execute_test_case(test_data, recipe_path) | 230 steps = execute_test_case(test_data, recipe_path) |
229 # Roundtrip json to get same string encoding as load | 231 # Roundtrip json to get same string encoding as load |
230 steps = json.loads(json.dumps(steps)) | 232 steps = json.loads(json.dumps(steps)) |
231 with open(expected_path, 'r') as f: | 233 with open(expected_path, 'rb') as f: |
232 expected = json.load(f) | 234 expected = json.load(f) |
233 self.assertEqual(steps, expected) | 235 self.assertEqual(steps, expected) |
234 test_.__name__ += name | 236 test_.__name__ += name |
235 setattr(cls, test_.__name__, test_) | 237 setattr(cls, test_.__name__, test_) |
236 add_test(test_data, expected_path) | 238 add_test(test_data, expected_path) |
237 | 239 |
238 RecipeTest.add_test_methods() | 240 RecipeTest.add_test_methods() |
239 | 241 |
240 RecipeTest.__name__ += '_for_%s' % ( | 242 RecipeTest.__name__ += '_for_%s' % ( |
241 os.path.splitext(os.path.basename(recipe_path))[0]) | 243 os.path.splitext(os.path.basename(recipe_path))[0]) |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
294 total_covered = COVERAGE.report() | 296 total_covered = COVERAGE.report() |
295 if total_covered != 100.0: | 297 if total_covered != 100.0: |
296 print 'FATAL: Recipes are not at 100% coverage.' | 298 print 'FATAL: Recipes are not at 100% coverage.' |
297 retcode = retcode or 2 | 299 retcode = retcode or 2 |
298 | 300 |
299 return retcode | 301 return retcode |
300 | 302 |
301 | 303 |
302 if __name__ == '__main__': | 304 if __name__ == '__main__': |
303 sys.exit(main(sys.argv)) | 305 sys.exit(main(sys.argv)) |
OLD | NEW |