Merge lp:~vila/selenium-simple-test/test-loader into lp:selenium-simple-test
- test-loader
- Merge into trunk
Proposed by
Vincent Ladeuil
Status: | Merged |
---|---|
Approved by: | Vincent Ladeuil |
Approved revision: | 463 |
Merged at revision: | 418 |
Proposed branch: | lp:~vila/selenium-simple-test/test-loader |
Merge into: | lp:selenium-simple-test |
Diff against target: |
1483 lines (+470/-754) 9 files modified
src/sst/filters.py (+3/-3) src/sst/loader.py (+131/-286) src/sst/result.py (+0/-3) src/sst/runtests.py (+10/-17) src/sst/selftests/shared/__init__.py (+3/-0) src/sst/tests/test_filters.py (+1/-2) src/sst/tests/test_loader.py (+272/-413) src/sst/tests/test_runtests.py (+50/-1) test-loader.TODO (+0/-29) |
To merge this branch: | bzr merge lp:~vila/selenium-simple-test/test-loader |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Corey Goldberg (community) | Approve | ||
Leo Arias (community) | code review | Approve | |
Review via email: mp+167562@code.launchpad.net |
Commit message
Simplify test loader implementation.
Description of the change
This simplify the new loader implementation, splitting between the part that may be upstreamed and the sst specific parts.
All existing tests have been migrated and some more added.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'src/sst/filters.py' |
2 | --- src/sst/filters.py 2013-05-23 10:41:04 +0000 |
3 | +++ src/sst/filters.py 2013-06-05 15:07:32 +0000 |
4 | @@ -46,7 +46,7 @@ |
5 | return filtered_suite |
6 | |
7 | |
8 | -def filter_by_regexps(regexps, suite): |
9 | +def include_regexps(regexps, suite): |
10 | """Returns the tests that match one of ``regexps``. |
11 | |
12 | :param regexps: A list of test id regexps (strings, will be compiled |
13 | @@ -58,13 +58,13 @@ |
14 | if not regexps: |
15 | return suite |
16 | |
17 | - def filter_test_regexps(test): |
18 | + def matches_one_of(test): |
19 | tid = test.id() |
20 | for reg in regexps: |
21 | if re.search(reg, tid) is not None: |
22 | return True |
23 | return False |
24 | - return filter_suite(filter_test_regexps, suite) |
25 | + return filter_suite(matches_one_of, suite) |
26 | |
27 | |
28 | def exclude_regexps(regexps, suite): |
29 | |
30 | === modified file 'src/sst/loader.py' |
31 | --- src/sst/loader.py 2013-05-31 11:17:32 +0000 |
32 | +++ src/sst/loader.py 2013-06-05 15:07:32 +0000 |
33 | @@ -28,273 +28,71 @@ |
34 | from sst import cases |
35 | |
36 | |
37 | -def matches_for_regexp(regexp): |
38 | - match_re = re.compile(regexp) |
39 | - |
40 | - def matches(path): |
41 | - return bool(match_re.match(path)) |
42 | - return matches |
43 | - |
44 | - |
45 | -def matches_for_glob(pattern): |
46 | - match_re = fnmatch.translate(pattern) |
47 | - return matches_for_regexp(match_re) |
48 | - |
49 | - |
50 | class NameMatcher(object): |
51 | + """Defines rules to select names. |
52 | + |
53 | + The rules are defined by two lists of regular expressions: |
54 | + - includes: matching succeeds if one of the regular expression match. |
55 | + - excludes: matching fails if one of the regular expression match. |
56 | + |
57 | + Matching fails if no rules are given. |
58 | + """ |
59 | |
60 | def __init__(self, includes=None, excludes=None): |
61 | + self.includes = [] |
62 | if includes is not None: |
63 | - self.includes = includes |
64 | + for inc in includes: |
65 | + self.includes.append(re.compile(inc)) |
66 | + self.excludes = [] |
67 | if excludes is not None: |
68 | - self.excludes = excludes |
69 | - |
70 | - def includes(self, path): |
71 | - return True |
72 | - |
73 | - def excludes(self, path): |
74 | + for exc in excludes: |
75 | + self.excludes.append(re.compile(exc)) |
76 | + |
77 | + def matches(self, name): |
78 | + for exc in self.excludes: |
79 | + if exc.search(name): |
80 | + return False |
81 | + for inc in self.includes: |
82 | + if inc.search(name): |
83 | + return True |
84 | + # Not explicitely included |
85 | return False |
86 | |
87 | - def matches(self, name): |
88 | - return self.includes(name) and not self.excludes(name) |
89 | - |
90 | - |
91 | -class FileLoader(object): |
92 | - """Load tests from a file. |
93 | - |
94 | - This is an abstract class allowing daughter classes to enforce constraints |
95 | - including the ability to load tests from files that cannot be imported. |
96 | - """ |
97 | - |
98 | - def __init__(self, test_loader, matcher=None): |
99 | - """Load tests from a file.""" |
100 | - super(FileLoader, self).__init__() |
101 | - if matcher is None: |
102 | - self.matches = lambda name: True |
103 | - else: |
104 | - self.matches = matcher.matches |
105 | - self.test_loader = test_loader |
106 | - |
107 | - def discover(self, directory, name): |
108 | - """Return None to represent an empty test suite. |
109 | - |
110 | - This is mostly for documentation purposes, if a file contains material |
111 | - that can produce tests, a specific file loader should be defined to |
112 | - build tests from the file content. |
113 | - """ |
114 | - return None |
115 | - |
116 | - |
117 | -class ModuleLoader(FileLoader): |
118 | - """Load tests from a python module. |
119 | - |
120 | - This handles base name matching and loading tests defined in an importable |
121 | - python module. |
122 | - """ |
123 | - |
124 | - def __init__(self, test_loader, matcher=None): |
125 | - if matcher is None: |
126 | - # Default to python source files, excluding private ones |
127 | - matcher = NameMatcher(includes=matches_for_regexp('.*\.py$'), |
128 | - excludes=matches_for_regexp('^_')) |
129 | - super(ModuleLoader, self).__init__(test_loader, matcher=matcher) |
130 | - |
131 | - def discover(self, directory, name): |
132 | - if not self.matches(name): |
133 | - return None |
134 | - module = self.test_loader.importFromPath(os.path.join(directory, name)) |
135 | - return self.test_loader.loadTestsFromModule(module) |
136 | - |
137 | - |
138 | -class ScriptLoader(FileLoader): |
139 | - """Load tests from an sst script. |
140 | - |
141 | - This handles base name matching and loading tests defined in an sst script. |
142 | - """ |
143 | - |
144 | - def __init__(self, test_loader, matcher=None): |
145 | - if matcher is None: |
146 | - # Default to python source files, excluding private ones |
147 | - matcher = NameMatcher(includes=matches_for_regexp('.*\.py$'), |
148 | - excludes=matches_for_regexp('^_')) |
149 | - super(ScriptLoader, self).__init__(test_loader, matcher=matcher) |
150 | - |
151 | - def discover(self, directory, name): |
152 | - if not self.matches(name): |
153 | - return None |
154 | - return self.test_loader.loadTestsFromScript(directory, name) |
155 | - |
156 | - |
157 | -class DirLoader(object): |
158 | - """Load tests from a tree. |
159 | - |
160 | - This is an abstract class allowing daughter classes to enforce constraints |
161 | - including the ability to load tests from files and directories that cannot |
162 | - be imported. |
163 | - """ |
164 | - |
165 | - def __init__(self, test_loader, matcher=None): |
166 | - """Load tests from a directory.""" |
167 | - super(DirLoader, self).__init__() |
168 | - if matcher is None: |
169 | - # Accept everything |
170 | - self.matches = lambda name: True |
171 | - else: |
172 | - self.matches = matcher.matches |
173 | - self.test_loader = test_loader |
174 | - |
175 | - def discover(self, directory, name): |
176 | - if not self.matches(name): |
177 | - return None |
178 | - path = os.path.join(directory, name) |
179 | - names = os.listdir(path) |
180 | - names = self.test_loader.sortNames(names) |
181 | - return self.discover_names(path, names) |
182 | - |
183 | - def discover_names(self, directory, names): |
184 | - suite = self.test_loader.suiteClass() |
185 | - for name in names: |
186 | - tests = self.discover_path(directory, name) |
187 | - if tests is not None: |
188 | - suite.addTests(tests) |
189 | - return suite |
190 | - |
191 | - def discover_path(self, directory, name): |
192 | - loader = None |
193 | - path = os.path.join(directory, name) |
194 | - if os.path.isfile(path): |
195 | - loader = self.test_loader.fileLoaderClass(self.test_loader) |
196 | - elif os.path.isdir(path): |
197 | - loader = self.test_loader.dirLoaderClass(self.test_loader) |
198 | - if loader is not None: |
199 | - return loader.discover(directory, name) |
200 | - return None |
201 | - |
202 | - |
203 | -class ScriptDirLoader(DirLoader): |
204 | - """Load tests for a tree containing scripts. |
205 | - |
206 | - Scripts can be organized in a tree where directories are not python |
207 | - packages. Since scripts are not imported, they don't require the |
208 | - directories containing them to be packages. |
209 | - """ |
210 | - |
211 | - def __init__(self, test_loader, matcher=None): |
212 | - if matcher is None: |
213 | - # Excludes the 'shared' directory and the "private" directories |
214 | - regexp = '^shared$|^_' |
215 | - matcher = NameMatcher(excludes=matches_for_regexp(regexp)) |
216 | - super(ScriptDirLoader, self).__init__(test_loader, matcher=matcher) |
217 | - |
218 | - def discover_path(self, directory, name): |
219 | - # MISSINGTEST: The behavior is unclear when a module cannot be imported |
220 | - # because sys.path is incomplete. This makes it hard for the user to |
221 | - # understand it should update sys.path -- vila 2013-05-05 |
222 | - path = os.path.join(directory, name) |
223 | - if (os.path.isdir(path) and os.path.isfile( |
224 | - os.path.join(path, '__init__.py'))): |
225 | - # Hold on, we need to respect users wishes here (if it has some) |
226 | - loader = PackageLoader(self.test_loader) |
227 | - try: |
228 | - return loader.discover(directory, name) |
229 | - except ImportError: |
230 | - # FIXME: Nah, didn't work, should we report it to the user ? |
231 | - # (yes see MISSINGTEST above) How ? (By re-raising with a |
232 | - # proper message: if there is an __init__.py file here, it |
233 | - # should be importable, that's what we should explain to the |
234 | - # user) vila 2013-05-04 |
235 | - pass |
236 | - return super(ScriptDirLoader, self).discover_path(directory, name) |
237 | - |
238 | - |
239 | -class PackageLoader(DirLoader): |
240 | - """Load tests for a package. |
241 | - |
242 | - A package provides a way for the user to specify how tests are loaded. |
243 | - """ |
244 | - |
245 | - def discover(self, directory, name): |
246 | - if not self.matches(name): |
247 | - return None |
248 | - path = os.path.join(directory, name) |
249 | - try: |
250 | - package = self.test_loader.importFromPath(path) |
251 | - except ImportError: |
252 | - # Explicitly raise the full exception with its backtrace. This |
253 | - # could be overwritten by daughter classes to handle them |
254 | - # differently (swallowing included ;) |
255 | - raise |
256 | - # Can we delegate to the package ? |
257 | - discover = getattr(package, 'discover', None) |
258 | - if discover is not None: |
259 | - # Since the user defined it, the package knows better |
260 | - return discover(self.test_loader, package, |
261 | - os.path.join(directory, name)) |
262 | - # Can we use the load_tests protocol ? |
263 | - load_tests = getattr(package, 'load_tests', None) |
264 | - if load_tests is not None: |
265 | - # FIXME: This swallows exceptions raised the by the user defined |
266 | - # 'load_test'. We may want to give a way to expose them instead |
267 | - # (with or without stopping the test loading) -- vila 2013-04-27 |
268 | - return self.test_loader.loadTestsFromModule(package) |
269 | - # Anything else with that ? |
270 | - # Nothing for now, thanks |
271 | - |
272 | - names = os.listdir(path) |
273 | - names.remove('__init__.py') |
274 | - names = self.test_loader.sortNames(names) |
275 | - return self.discover_names(path, names) |
276 | - |
277 | |
278 | @contextlib.contextmanager |
279 | -def Loaders(test_loader, file_loader_class, dir_loader_class): |
280 | +def NameMatchers(test_loader, file_matcher=None, dir_matcher=None): |
281 | """A context manager for loading tests from a tree. |
282 | |
283 | - This is mainly used when walking a tree a requiring a different set of |
284 | - loaders for a subtree. |
285 | + This is mainly used when walking a tree and requiring a different set of |
286 | + name matchers for a subtree. |
287 | """ |
288 | - if file_loader_class is None: |
289 | - file_loader_class = test_loader.fileLoaderClass |
290 | - if dir_loader_class is None: |
291 | - dir_loader_class = test_loader.dirLoaderClass |
292 | - orig = (test_loader.fileLoaderClass, test_loader.dirLoaderClass) |
293 | + if file_matcher is None: |
294 | + file_matcher = test_loader.file_matcher |
295 | + if dir_matcher is None: |
296 | + dir_matcher = test_loader.dir_matcher |
297 | + orig = (test_loader.file_matcher, test_loader.dir_matcher) |
298 | try: |
299 | - test_loader.fileLoaderClass = file_loader_class |
300 | - test_loader.dirLoaderClass = dir_loader_class |
301 | - # 'test_loader' will now use the specified file/dir loader classes |
302 | - yield |
303 | + test_loader.file_matcher = file_matcher |
304 | + test_loader.dir_matcher = dir_matcher |
305 | + # 'test_loader' will now use the specified file/dir matchers |
306 | + yield test_loader |
307 | finally: |
308 | - (test_loader.fileLoaderClass, test_loader.dirLoaderClass) = orig |
309 | + (test_loader.file_matcher, test_loader.dir_matcher) = orig |
310 | |
311 | |
312 | class TestLoader(unittest.TestLoader): |
313 | - """Load tests from an sst tree. |
314 | - |
315 | - This loader is able to load sst scripts and create test cases with the |
316 | - right sst specific attributes (browser, error handling, reporting). |
317 | - |
318 | - This also allows test case based modules to be loaded when appropriate. |
319 | - |
320 | - This also provides ways for packages to define the test loading as they see |
321 | - fit. |
322 | + """Load tests from an arbitrary tree. |
323 | + |
324 | + This also provides ways for packages to define the test discovery and |
325 | + loading as they see fit. |
326 | |
327 | Sorting happens on base names inside a directory while walking the tree and |
328 | on test classes and test method names when loading a module. Those sortings |
329 | combined provide a test suite where test ids are sorted. |
330 | """ |
331 | |
332 | - dirLoaderClass = PackageLoader |
333 | - fileLoaderClass = ModuleLoader |
334 | - |
335 | - def __init__(self, results_directory=None, browser_factory=None, |
336 | - screenshots_on=False, debug_post_mortem=False, |
337 | - extended_report=False): |
338 | - super(TestLoader, self).__init__() |
339 | - self.results_directory = results_directory |
340 | - self.browser_factory = browser_factory |
341 | - self.screenshots_on = screenshots_on |
342 | - self.debug_post_mortem = debug_post_mortem |
343 | - self.extended_report = extended_report |
344 | + file_matcher = NameMatcher(includes=[r'^test.*\.py$']) |
345 | + dir_matcher = NameMatcher(includes=[r'.*']) |
346 | |
347 | def discover(self, start_dir, pattern='test*.py', top_level_dir=None): |
348 | if top_level_dir: |
349 | @@ -303,33 +101,48 @@ |
350 | # setup properly |
351 | sys.path.insert(0, top_level_dir) |
352 | |
353 | - class ModuleLoaderFromPattern(ModuleLoader): |
354 | - |
355 | - def __init__(self, test_loader): |
356 | - matcher = NameMatcher(includes=matches_for_glob(pattern)) |
357 | - super(ModuleLoaderFromPattern, self).__init__( |
358 | - test_loader, matcher=matcher) |
359 | - |
360 | - return self.discoverTests(start_dir, |
361 | - file_loader_class=ModuleLoaderFromPattern) |
362 | - |
363 | - def discoverTests(self, start_dir, file_loader_class=None, |
364 | - dir_loader_class=None): |
365 | - with Loaders(self, file_loader_class, dir_loader_class): |
366 | - dir_loader = self.dirLoaderClass(self) |
367 | - return dir_loader.discover(*os.path.split(start_dir)) |
368 | - |
369 | - def discoverTestsFromPackage(self, package, path, file_loader_class=None, |
370 | - dir_loader_class=None): |
371 | - suite = self.suiteClass() |
372 | - suite.addTests(self.loadTestsFromModule(package)) |
373 | - names = os.listdir(path) |
374 | - names.remove('__init__.py') |
375 | - names = self.sortNames(names) |
376 | - with Loaders(self, file_loader_class, dir_loader_class): |
377 | - dir_loader = self.dirLoaderClass(self) |
378 | - suite.addTests(dir_loader.discover_names(path, names)) |
379 | - return suite |
380 | + translated = NameMatcher(includes=['^' + fnmatch.translate(pattern)]) |
381 | + with NameMatchers(self, file_matcher=translated) as tl: |
382 | + return tl.discoverTestsFromTree(start_dir) |
383 | + |
384 | + def discoverTestsFromTree(self, dir_path, package=None): |
385 | + suite = self.suiteClass() |
386 | + names = os.listdir(dir_path) |
387 | + if package is None: |
388 | + if os.path.isfile(os.path.join(dir_path, '__init__.py')): |
389 | + package = self.importFromPath(dir_path) |
390 | + names.remove('__init__.py') |
391 | + if package is not None: |
392 | + # Can we delegate to the package ? |
393 | + discover = getattr(package, 'discover', None) |
394 | + if discover is not None: |
395 | + # Since the user defined it, the package knows better |
396 | + suite.addTests(discover(self, package, dir_path, names)) |
397 | + return suite |
398 | + load_tests = getattr(package, 'load_tests', None) |
399 | + if load_tests is not None: |
400 | + # let unittest handle the 'load_tests' protocol |
401 | + suite.addTests(self.loadTestsFromModule(package)) |
402 | + return suite |
403 | + # If tests are defined in the package, load them |
404 | + suite.addTests(self.loadTestsFromModule(package)) |
405 | + suite.addTests(self.discoverTestsFromNames(dir_path, names)) |
406 | + return suite |
407 | + |
408 | + def discoverTestsFromNames(self, dir_path, names): |
409 | + # Walk the tree to discover the tests |
410 | + suite = self.suiteClass() |
411 | + for name in self.sortNames(names): |
412 | + path = os.path.join(dir_path, name) |
413 | + if os.path.isfile(path) and self.file_matcher.matches(name): |
414 | + suite.addTests(self.discoverTestsFromFile(path)) |
415 | + elif os.path.isdir(path) and self.dir_matcher.matches(name): |
416 | + suite.addTests(self.discoverTestsFromTree(path)) |
417 | + return suite |
418 | + |
419 | + def discoverTestsFromFile(self, path): |
420 | + module = self.importFromPath(path) |
421 | + return self.loadTestsFromModule(module) |
422 | |
423 | def sortNames(self, names): |
424 | """Return 'names' sorted as defined by sortTestMethodsUsing. |
425 | @@ -349,9 +162,45 @@ |
426 | __import__(mod_name) |
427 | return sys.modules[mod_name] |
428 | |
429 | - def loadTestsFromScript(self, dir_name, script_name): |
430 | + |
431 | +class SSTestLoader(TestLoader): |
432 | + """Load tests from an sst tree. |
433 | + |
434 | + This loader is able to load sst scripts and create test cases with the |
435 | + right sst specific attributes (browser, error handling, reporting). |
436 | + |
437 | + This also allows test case based modules to be loaded when appropriate. |
438 | + |
439 | + The main differences with unittest test loader are around different rules |
440 | + for file names that can contain tests and importing rules (a script *should |
441 | + not* be imported at load time). |
442 | + |
443 | + Scripts can be organized in a tree where directories are not python |
444 | + packages. Since scripts are not imported, they don't require the |
445 | + directories containing them to be packages. Although as soon a test suite |
446 | + becomes complex enough to be organized as a tree, it generally requires the |
447 | + packages to be importable. |
448 | + """ |
449 | + |
450 | + file_matcher = NameMatcher(includes=[r'.*\.py$'], excludes=[r'^_']) |
451 | + dir_matcher = NameMatcher(includes=[r'.*'], excludes=[r'^_', '^shared$']) |
452 | + |
453 | + def __init__(self, results_directory=None, browser_factory=None, |
454 | + screenshots_on=False, debug_post_mortem=False, |
455 | + extended_report=False): |
456 | + super(SSTestLoader, self).__init__() |
457 | + self.results_directory = results_directory |
458 | + self.browser_factory = browser_factory |
459 | + self.screenshots_on = screenshots_on |
460 | + self.debug_post_mortem = debug_post_mortem |
461 | + self.extended_report = extended_report |
462 | + |
463 | + def discoverTestsFromFile(self, path): |
464 | + return self.loadTestsFromScript(path) |
465 | + |
466 | + def loadTestsFromScript(self, path): |
467 | suite = self.suiteClass() |
468 | - path = os.path.join(dir_name, script_name) |
469 | + dir_name, script_name = os.path.split(path) |
470 | if not os.path.isfile(path): |
471 | return suite |
472 | # script specific test parametrization |
473 | @@ -382,27 +231,23 @@ |
474 | return test |
475 | |
476 | |
477 | -def discoverTestScripts(test_loader, package, directory): |
478 | +def discoverTestScripts(test_loader, package, directory, names): |
479 | """``discover`` helper to load sst scripts. |
480 | |
481 | This can be used in a __init__.py file while walking a regular tests tree. |
482 | """ |
483 | - return test_loader.discoverTestsFromPackage( |
484 | - package, directory, |
485 | - file_loader_class=ScriptLoader, dir_loader_class=ScriptDirLoader) |
486 | - |
487 | - |
488 | -def discoverRegularTests(test_loader, package, directory): |
489 | + return SSTestLoader().discoverTestsFromNames(directory, names) |
490 | + |
491 | + |
492 | +def discoverRegularTests(test_loader, package, directory, names): |
493 | """``discover`` helper to load regular python files defining tests. |
494 | |
495 | This can be used in a __init__.py file while walking an sst tests tree. |
496 | """ |
497 | - return test_loader.discoverTestsFromPackage( |
498 | - package, directory, |
499 | - file_loader_class=ModuleLoader, dir_loader_class=PackageLoader) |
500 | - |
501 | - |
502 | -def discoverNoTests(test_loader, *args, **kwargs): |
503 | + return TestLoader().discoverTestsFromNames(directory, names) |
504 | + |
505 | + |
506 | +def discoverNoTests(test_loader, package, directory, names): |
507 | """Returns an empty test suite. |
508 | |
509 | This can be used in a __init__.py file to prune the test loading for a |
510 | |
511 | === modified file 'src/sst/result.py' |
512 | --- src/sst/result.py 2013-05-10 16:10:51 +0000 |
513 | +++ src/sst/result.py 2013-06-05 15:07:32 +0000 |
514 | @@ -33,9 +33,6 @@ |
515 | self.timer = timer |
516 | self.verbose = verbosity > 1 |
517 | |
518 | - def startTestRun(self): |
519 | - super(TextTestResult, self).startTestRun() |
520 | - |
521 | def startTest(self, test): |
522 | if self.verbose: |
523 | self.stream.write(str(test)) |
524 | |
525 | === modified file 'src/sst/runtests.py' |
526 | --- src/sst/runtests.py 2013-06-04 15:56:58 +0000 |
527 | +++ src/sst/runtests.py 2013-06-05 15:07:32 +0000 |
528 | @@ -63,29 +63,22 @@ |
529 | extended=False, |
530 | includes=None, |
531 | excludes=None): |
532 | - |
533 | if not os.path.isdir(test_dir): |
534 | raise RuntimeError('Specified directory %r does not exist' |
535 | % (test_dir,)) |
536 | + if browser_factory is None and collect_only is False: |
537 | + raise RuntimeError('A browser must be specified') |
538 | shared_directory = find_shared_directory(test_dir, shared_directory) |
539 | config.shared_directory = shared_directory |
540 | - sys.path.append(shared_directory) |
541 | - |
542 | - if browser_factory is None: |
543 | - # TODO: We could raise an error instead as providing a default value |
544 | - # makes little sense here -- vila 2013-04-11 |
545 | - browser_factory = browsers.FirefoxFactory() |
546 | - |
547 | - test_loader = loader.TestLoader(results_directory, |
548 | - browser_factory, screenshots_on, |
549 | - debug, extended) |
550 | + if shared_directory is not None: |
551 | + sys.path.append(shared_directory) |
552 | + |
553 | + test_loader = loader.SSTestLoader(results_directory, |
554 | + browser_factory, screenshots_on, |
555 | + debug, extended) |
556 | alltests = test_loader.suiteClass() |
557 | - alltests.addTests( |
558 | - test_loader.discoverTests(test_dir, |
559 | - file_loader_class=loader.ScriptLoader, |
560 | - dir_loader_class=loader.ScriptDirLoader)) |
561 | - |
562 | - alltests = filters.filter_by_regexps(test_regexps, alltests) |
563 | + alltests.addTests(test_loader.discoverTestsFromTree(test_dir)) |
564 | + alltests = filters.include_regexps(test_regexps, alltests) |
565 | alltests = filters.exclude_regexps(excludes, alltests) |
566 | |
567 | if not alltests.countTestCases(): |
568 | |
569 | === added file 'src/sst/selftests/shared/__init__.py' |
570 | --- src/sst/selftests/shared/__init__.py 1970-01-01 00:00:00 +0000 |
571 | +++ src/sst/selftests/shared/__init__.py 2013-06-05 15:07:32 +0000 |
572 | @@ -0,0 +1,3 @@ |
573 | +from sst import loader |
574 | + |
575 | +discover = loader.discoverNoTests |
576 | |
577 | === modified file 'src/sst/tests/test_filters.py' |
578 | --- src/sst/tests/test_filters.py 2013-05-23 10:41:04 +0000 |
579 | +++ src/sst/tests/test_filters.py 2013-06-05 15:07:32 +0000 |
580 | @@ -83,8 +83,7 @@ |
581 | |
582 | def assertFiltered(self, expected, regexps, ids): |
583 | """Check that ``regexps`` filters tests created from ``ids``.""" |
584 | - filtered = filters.filter_by_regexps(regexps, |
585 | - create_tests_from_ids(ids)) |
586 | + filtered = filters.include_regexps(regexps, create_tests_from_ids(ids)) |
587 | self.assertEqual(expected, |
588 | [t.id() for t in testtools.iterate_tests(filtered)]) |
589 | |
590 | |
591 | === modified file 'src/sst/tests/test_loader.py' |
592 | --- src/sst/tests/test_loader.py 2013-05-14 08:48:15 +0000 |
593 | +++ src/sst/tests/test_loader.py 2013-06-05 15:07:32 +0000 |
594 | @@ -46,136 +46,75 @@ |
595 | ) |
596 | |
597 | |
598 | -class TestMatchesForRegexp(testtools.TestCase): |
599 | - |
600 | - def test_matches(self): |
601 | - matches = loader.matches_for_regexp('foo.*') |
602 | - # All assertions should succeed, if one of them fails, we have a bigger |
603 | - # problem than having one test for each assertion |
604 | - self.assertTrue(matches('foo')) |
605 | - self.assertFalse(matches('bar')) |
606 | - self.assertTrue(matches('foobar')) |
607 | - self.assertFalse(matches('barfoo')) |
608 | - |
609 | - |
610 | -class TestMatchesForGlob(testtools.TestCase): |
611 | - |
612 | - def test_matches(self): |
613 | - matches = loader.matches_for_glob('foo*') |
614 | - # All assertions should succeed, if one of them fails, we have a bigger |
615 | - # problem than having one test for each assertion |
616 | - self.assertTrue(matches('foo')) |
617 | - self.assertFalse(matches('fo')) |
618 | - self.assertFalse(matches('bar')) |
619 | - self.assertTrue(matches('foobar')) |
620 | - self.assertFalse(matches('barfoo')) |
621 | - |
622 | - |
623 | class TestNameMatcher(testtools.TestCase): |
624 | |
625 | - def test_default_includes(self): |
626 | - name_matcher = loader.NameMatcher() |
627 | - self.assertTrue(name_matcher.includes('foo')) |
628 | - self.assertTrue(name_matcher.matches('foo')) |
629 | - |
630 | - def test_default_exclude(self): |
631 | - name_matcher = loader.NameMatcher() |
632 | - self.assertFalse(name_matcher.excludes('foo')) |
633 | - self.assertTrue(name_matcher.matches('foo')) |
634 | - |
635 | - def test_provided_includes(self): |
636 | - name_matcher = loader.NameMatcher( |
637 | - includes=loader.matches_for_regexp('^.*foo$')) |
638 | - self.assertTrue(name_matcher.includes('foo')) |
639 | - self.assertTrue(name_matcher.includes('barfoo')) |
640 | - self.assertFalse(name_matcher.includes('bar')) |
641 | - self.assertFalse(name_matcher.includes('foobar')) |
642 | - |
643 | - def test_provided_excludes(self): |
644 | - name_matcher = loader.NameMatcher( |
645 | - excludes=loader.matches_for_regexp('^bar.*foo$')) |
646 | - self.assertTrue(name_matcher.excludes('barfoo')) |
647 | - self.assertFalse(name_matcher.excludes('foo')) |
648 | - |
649 | - |
650 | -class TestFileLoader(testtools.TestCase): |
651 | - |
652 | - def get_test_loader(self): |
653 | - return loader.TestLoader() |
654 | - |
655 | - def test_discover_nothing(self): |
656 | - tests.set_cwd_to_tmp(self) |
657 | - with open('foo', 'w') as f: |
658 | - f.write('bar\n') |
659 | - file_loader = loader.FileLoader(self.get_test_loader()) |
660 | - suite = file_loader.discover('.', 'foo') |
661 | - self.assertIs(None, suite) |
662 | - |
663 | - |
664 | -class TestModuleLoader(tests.ImportingLocalFilesTest): |
665 | - |
666 | - def get_test_loader(self): |
667 | - return loader.TestLoader() |
668 | - |
669 | - def test_default_includes(self): |
670 | - mod_loader = loader.ModuleLoader(self.get_test_loader()) |
671 | - self.assertTrue(mod_loader.matches('foo.py')) |
672 | - # But we won't try to import a random file |
673 | - self.assertFalse(mod_loader.matches('foopy')) |
674 | - |
675 | - def test_discover_empty_file(self): |
676 | - with open('foo.py', 'w') as f: |
677 | + def test_defaults(self): |
678 | + nm = loader.NameMatcher() |
679 | + self.assertFalse(nm.matches('')) |
680 | + self.assertFalse(nm.matches('foo')) |
681 | + |
682 | + def test_simple_include(self): |
683 | + nm = loader.NameMatcher(includes=['foo']) |
684 | + self.assertTrue(nm.matches('foo')) |
685 | + self.assertTrue(nm.matches('XXXfooXXX')) |
686 | + |
687 | + def test_multiple_includes(self): |
688 | + nm = loader.NameMatcher(includes=['foo', '^bar']) |
689 | + self.assertTrue(nm.matches('foo')) |
690 | + self.assertTrue(nm.matches('bar')) |
691 | + self.assertTrue(nm.matches('barfoo')) |
692 | + self.assertTrue(nm.matches('foobar')) |
693 | + self.assertFalse(nm.matches('bazbar')) |
694 | + |
695 | + def test_simple_excludes(self): |
696 | + nm = loader.NameMatcher(includes=['.*'], excludes=['foo']) |
697 | + self.assertTrue(nm.matches('bar')) |
698 | + self.assertFalse(nm.matches('foo')) |
699 | + self.assertFalse(nm.matches('foobar')) |
700 | + |
701 | + def test_multiple_excludes(self): |
702 | + nm = loader.NameMatcher(includes=['.*'], excludes=['foo$', '^bar']) |
703 | + self.assertTrue(nm.matches('baz')) |
704 | + self.assertTrue(nm.matches('footix')) |
705 | + self.assertFalse(nm.matches('foo')) |
706 | + self.assertFalse(nm.matches('barista')) |
707 | + |
708 | + |
709 | +class TestTestLoader(tests.ImportingLocalFilesTest): |
710 | + |
711 | + def make_test_loader(self): |
712 | + return loader.TestLoader() |
713 | + |
714 | + def test_ignored_file(self): |
715 | + with open('empty.py', 'w') as f: |
716 | f.write('') |
717 | - mod_loader = loader.ModuleLoader(self.get_test_loader()) |
718 | - suite = mod_loader.discover('.', 'foo.py') |
719 | + test_loader = self.make_test_loader() |
720 | + suite = test_loader.discoverTestsFromTree('.') |
721 | self.assertEqual(0, suite.countTestCases()) |
722 | |
723 | - def test_discover_invalid_file(self): |
724 | - with open('foo.py', 'w') as f: |
725 | + def test_invalid_file(self): |
726 | + with open('test_foo.py', 'w') as f: |
727 | f.write("I'm no python code") |
728 | - mod_loader = loader.ModuleLoader(self.get_test_loader()) |
729 | - self.assertRaises(SyntaxError, mod_loader.discover, '.', 'foo.py') |
730 | - |
731 | - def test_discover_valid_file(self): |
732 | - with open('foo.py', 'w') as f: |
733 | - f.write(''' |
734 | -import unittest |
735 | - |
736 | -class Test(unittest.TestCase): |
737 | - |
738 | - def test_it(self): |
739 | - self.assertTrue(True) |
740 | -''') |
741 | - mod_loader = loader.ModuleLoader(self.get_test_loader()) |
742 | - suite = mod_loader.discover('.', 'foo.py') |
743 | - self.assertEqual(1, suite.countTestCases()) |
744 | - |
745 | - |
746 | -class TestDirLoaderDiscoverPath(tests.ImportingLocalFilesTest): |
747 | - |
748 | - def get_test_loader(self): |
749 | - test_loader = loader.TestLoader() |
750 | - # We don't use the default PackageLoader for unit testing DirLoader |
751 | - # behavior. But we still leave ModuleLoader for the file loader. |
752 | - test_loader.dirLoaderClass = loader.DirLoader |
753 | - return test_loader |
754 | - |
755 | - def test_discover_path_for_file_without_package(self): |
756 | + test_loader = self.make_test_loader() |
757 | + self.assertRaises(SyntaxError, test_loader.discoverTestsFromTree, '.') |
758 | + |
759 | + def test_invalid_file_in_a_dir(self): |
760 | tests.write_tree_from_desc('''dir: t |
761 | -file: t/foo.py |
762 | +file: t/test_foo.py |
763 | I'm not even python code |
764 | ''') |
765 | - # Since 'foo' can't be imported, discover_path should not be invoked, |
766 | - # ensure we still get some meaningful error message. |
767 | - dir_loader = loader.DirLoader(self.get_test_loader()) |
768 | + # Since 'foo' can't be imported, discoverTestsFromTree should not be |
769 | + # invoked, ensure we still get some meaningful error message. |
770 | + test_loader = self.make_test_loader() |
771 | e = self.assertRaises(ImportError, |
772 | - dir_loader.discover_path, 't', 'foo.py') |
773 | - self.assertEqual('No module named t.foo', e.message) |
774 | + test_loader.discoverTestsFromTree, 't') |
775 | + self.assertEqual('No module named t.test_foo', e.args[0]) |
776 | |
777 | - def test_discover_path_for_valid_file(self): |
778 | + def test_invalid_init_file(self): |
779 | tests.write_tree_from_desc('''dir: t |
780 | file: t/__init__.py |
781 | -file: t/foo.py |
782 | +I'm not even python code |
783 | +file: t/test_foo.py |
784 | import unittest |
785 | |
786 | class Test(unittest.TestCase): |
787 | @@ -183,15 +122,35 @@ |
788 | def test_it(self): |
789 | self.assertTrue(True) |
790 | ''') |
791 | - dir_loader = loader.DirLoader(self.get_test_loader()) |
792 | - suite = dir_loader.discover_path('t', 'foo.py') |
793 | - self.assertEqual(1, suite.countTestCases()) |
794 | - |
795 | - def test_discover_path_for_dir(self): |
796 | + test_loader = self.make_test_loader() |
797 | + e = self.assertRaises(SyntaxError, |
798 | + test_loader.discoverTestsFromTree, 't') |
799 | + self.assertEqual('EOL while scanning string literal', e.args[0]) |
800 | + |
801 | + def test_symlink_is_ignored(self): |
802 | + tests.write_tree_from_desc('''dir: t |
803 | +file: t/foo |
804 | +tagada |
805 | +link: t/foo t/test_bar.py |
806 | +''') |
807 | + test_loader = self.make_test_loader() |
808 | + suite = test_loader.discoverTestsFromTree('.') |
809 | + # Despite a matching name, symlink is ignored |
810 | + self.assertEqual(0, suite.countTestCases()) |
811 | + |
812 | + def test_broken_symlink_is_ignored(self): |
813 | + tests.write_tree_from_desc('''dir: t |
814 | +link: t/test_bar.py t/test_qux.py |
815 | +''') |
816 | + test_loader = self.make_test_loader() |
817 | + suite = test_loader.discoverTestsFromTree('.') |
818 | + self.assertEqual(0, suite.countTestCases()) |
819 | + |
820 | + def test_file_in_a_dir(self): |
821 | tests.write_tree_from_desc('''dir: t |
822 | file: t/__init__.py |
823 | dir: t/dir |
824 | -file: t/dir/foo.py |
825 | +file: t/dir/test_foo.py |
826 | import unittest |
827 | |
828 | class Test(unittest.TestCase): |
829 | @@ -199,228 +158,214 @@ |
830 | def test_it(self): |
831 | self.assertTrue(True) |
832 | ''') |
833 | - dir_loader = loader.DirLoader(self.get_test_loader()) |
834 | + test_loader = self.make_test_loader() |
835 | e = self.assertRaises(ImportError, |
836 | - dir_loader.discover_path, 't', 'dir') |
837 | - # 't' is a module but 'dir' is not, hence, 'dir.foo' is not either, |
838 | - # blame python for the approximate message ;-/ |
839 | - self.assertEqual('No module named dir.foo', e.message) |
840 | - |
841 | - def test_discover_path_for_not_matching_symlink(self): |
842 | - tests.write_tree_from_desc('''dir: t |
843 | -file: t/foo |
844 | -tagada |
845 | -link: t/foo t/bar.py |
846 | -''') |
847 | - dir_loader = loader.DirLoader(self.get_test_loader()) |
848 | - suite = dir_loader.discover_path('t', 'bar.py') |
849 | - self.assertIs(None, suite) |
850 | - |
851 | - def test_discover_path_for_broken_symlink(self): |
852 | - tests.write_tree_from_desc('''dir: t |
853 | -file: t/foo |
854 | -tagada |
855 | -link: bar t/qux |
856 | -''') |
857 | - dir_loader = loader.DirLoader(self.get_test_loader()) |
858 | - suite = dir_loader.discover_path('t', 'qux') |
859 | - self.assertIs(None, suite) |
860 | - |
861 | - def test_discover_simple_file_in_dir(self): |
862 | - tests.write_tree_from_desc('''dir: t |
863 | -file: t/__init__.py |
864 | -file: t/foo.py |
865 | -import unittest |
866 | - |
867 | -class Test(unittest.TestCase): |
868 | - |
869 | - def test_it(self): |
870 | - self.assertTrue(True) |
871 | -''') |
872 | - dir_loader = loader.DirLoader(self.get_test_loader()) |
873 | - suite = dir_loader.discover('.', 't') |
874 | - # Despite using DirLoader, python triggers the 't' import so we are |
875 | - # able to import foo.py and all is well |
876 | - self.assertEqual(1, suite.countTestCases()) |
877 | - |
878 | - |
879 | -class TestPackageLoader(tests.ImportingLocalFilesTest): |
880 | - |
881 | - def get_test_loader(self): |
882 | - test_loader = loader.TestLoader() |
883 | - return test_loader |
884 | - |
885 | - def test_discover_package_with_invalid_file(self): |
886 | - tests.write_tree_from_desc('''dir: dir |
887 | -file: dir/__init__.py |
888 | -file: dir/foo.py |
889 | -I'm not even python code |
890 | -''') |
891 | - pkg_loader = loader.PackageLoader(self.get_test_loader()) |
892 | - e = self.assertRaises(SyntaxError, pkg_loader.discover, '.', 'dir') |
893 | - self.assertEqual('EOL while scanning string literal', e.args[0]) |
894 | - |
895 | - def test_discover_simple_file_in_dir(self): |
896 | - tests.write_tree_from_desc('''dir: t |
897 | -file: t/__init__.py |
898 | -file: t/foo.py |
899 | -import unittest |
900 | - |
901 | -class Test(unittest.TestCase): |
902 | - |
903 | - def test_it(self): |
904 | - self.assertTrue(True) |
905 | -''') |
906 | - dir_loader = loader.DirLoader(self.get_test_loader()) |
907 | - suite = dir_loader.discover('.', 't') |
908 | - self.assertEqual(1, suite.countTestCases()) |
909 | - |
910 | - |
911 | -class TestLoadScript(testtools.TestCase): |
912 | + test_loader.discoverTestsFromTree, 't/dir') |
913 | + # 't' is a package but 'dir' is not, hence, 'dir.test_foo' is not |
914 | + # either, blame python for the approximate message ;-/ |
915 | + self.assertEqual('No module named dir.test_foo', e.args[0]) |
916 | + |
917 | + def test_simple_file_in_a_package(self): |
918 | + tests.write_tree_from_desc('''dir: t |
919 | +file: t/__init__.py |
920 | +file: t/test_foo.py |
921 | +import unittest |
922 | + |
923 | +class Test(unittest.TestCase): |
924 | + |
925 | + def test_me(self): |
926 | + self.assertTrue(True) |
927 | +''') |
928 | + test_loader = self.make_test_loader() |
929 | + suite = test_loader.discoverTestsFromTree('t') |
930 | + self.assertEqual(1, suite.countTestCases()) |
931 | + |
932 | + def test_discover_changing_file_matcher(self): |
933 | + tests.write_tree_from_desc('''dir: t |
934 | +file: t/__init__.py |
935 | +file: t/test_foo.py |
936 | +import unittest |
937 | + |
938 | +class Test(unittest.TestCase): |
939 | + |
940 | + def test_me(self): |
941 | + self.assertTrue(True) |
942 | +dir: t/other |
943 | +file: t/other/__init__.py |
944 | +import unittest |
945 | +from sst import loader |
946 | + |
947 | +def discover(test_loader, package, directory_path, names): |
948 | + suite = test_loader.loadTestsFromModule(package) |
949 | + # Change the test.*\.py rule |
950 | + fmatcher = loader.NameMatcher(includes=['.*']) |
951 | + with loader.NameMatchers(test_loader, fmatcher) as tl: |
952 | + suite.addTests(tl.discoverTestsFromNames(directory_path, names)) |
953 | + return suite |
954 | + |
955 | +class Test(unittest.TestCase): |
956 | + |
957 | + def test_in_init(self): |
958 | + self.assertTrue(True) |
959 | +file: t/other/not_starting_with_test.py |
960 | +import unittest |
961 | + |
962 | +class Test(unittest.TestCase): |
963 | + |
964 | + def test_me(self): |
965 | + self.assertTrue(True) |
966 | +''') |
967 | + test_loader = self.make_test_loader() |
968 | + suite = test_loader.discoverTestsFromTree('t') |
969 | + self.assertEqual(3, suite.countTestCases()) |
970 | + self.assertEqual(['t.other.Test.test_in_init', |
971 | + 't.other.not_starting_with_test.Test.test_me', |
972 | + 't.test_foo.Test.test_me'], |
973 | + [t.id() for t in testtools.iterate_tests(suite)]) |
974 | + |
975 | + def test_load_tests(self): |
976 | + tests.write_tree_from_desc('''dir: t |
977 | +file: t/__init__.py |
978 | +import unittest |
979 | + |
980 | +def load_tests(test_loader, tests, ignore): |
981 | + # A simple way to reveal the side effect is to add more tests |
982 | + class TestLoadTest(unittest.TestCase): |
983 | + def test_in_load_test(self): |
984 | + self.assertTrue(True) |
985 | + tests.addTests(test_loader.loadTestsFromTestCase(TestLoadTest)) |
986 | + return tests |
987 | + |
988 | +class TestInit(unittest.TestCase): |
989 | + |
990 | + def test_in_init(self): |
991 | + self.assertTrue(True) |
992 | + |
993 | +file: t/test_not_discovered.py |
994 | +import unittest |
995 | + |
996 | +class Test(unittest.TestCase): |
997 | + |
998 | + def test_me(self): |
999 | + self.assertTrue(True) |
1000 | +''') |
1001 | + test_loader = self.make_test_loader() |
1002 | + suite = test_loader.discoverTestsFromTree('t') |
1003 | + self.assertEqual(2, suite.countTestCases()) |
1004 | + self.assertEqual(['t.TestInit.test_in_init', |
1005 | + 't.TestLoadTest.test_in_load_test'], |
1006 | + [t.id() for t in testtools.iterate_tests(suite)]) |
1007 | + |
1008 | + |
1009 | +class TestTestLoaderPattern(tests.ImportingLocalFilesTest): |
1010 | + |
1011 | + def make_test_loader(self): |
1012 | + return loader.TestLoader() |
1013 | + |
1014 | + def test_default_pattern(self): |
1015 | + tests.write_tree_from_desc('''dir: t |
1016 | +file: t/__init__.py |
1017 | +file: t/foo.py |
1018 | +Don't look at me ! |
1019 | +file: t/test_foo.py |
1020 | +import unittest |
1021 | + |
1022 | +class Test(unittest.TestCase): |
1023 | + |
1024 | + def test_me(self): |
1025 | + self.assertTrue(True) |
1026 | +''') |
1027 | + test_loader = self.make_test_loader() |
1028 | + suite = test_loader.discover('t') |
1029 | + self.assertEqual(1, suite.countTestCases()) |
1030 | + |
1031 | + def test_pattern(self): |
1032 | + tests.write_tree_from_desc('''dir: t |
1033 | +file: t/__init__.py |
1034 | +file: t/foo_foo.py |
1035 | +import unittest |
1036 | + |
1037 | +class Test(unittest.TestCase): |
1038 | + |
1039 | + def test_me(self): |
1040 | + self.assertTrue(True) |
1041 | +file: t/test_foo.py |
1042 | +Don't look at me ! |
1043 | +''') |
1044 | + test_loader = self.make_test_loader() |
1045 | + suite = test_loader.discover('t', pattern='foo*.py') |
1046 | + self.assertEqual(1, suite.countTestCases()) |
1047 | + |
1048 | + |
1049 | +class TestTestLoaderTopLevelDir(testtools.TestCase): |
1050 | |
1051 | def setUp(self): |
1052 | - super(TestLoadScript, self).setUp() |
1053 | + super(TestTestLoaderTopLevelDir, self).setUp() |
1054 | + # We build trees rooted in test_base_dir from which we will import |
1055 | tests.set_cwd_to_tmp(self) |
1056 | - |
1057 | - def create_script(self, path, content): |
1058 | - with open(path, 'w') as f: |
1059 | - f.write(content) |
1060 | - |
1061 | - def test_load_simple_script(self): |
1062 | + tests.protect_imports(self) |
1063 | + tests.write_tree_from_desc('''dir: t |
1064 | +file: t/__init__.py |
1065 | +file: t/foo.py |
1066 | +import unittest |
1067 | + |
1068 | +class Test(unittest.TestCase): |
1069 | + |
1070 | + def test_me(self): |
1071 | + self.assertTrue(True) |
1072 | +''') |
1073 | + self.loader = loader.TestLoader() |
1074 | + |
1075 | + def test_simple_file_in_a_dir(self): |
1076 | + suite = self.loader.discover('t', '*.py', self.test_base_dir) |
1077 | + self.assertEqual(1, suite.countTestCases()) |
1078 | + |
1079 | + def test_simple_file_in_a_dir_no_sys_path(self): |
1080 | + e = self.assertRaises(ImportError, |
1081 | + self.loader.discover, 't', '*.py') |
1082 | + self.assertEqual('No module named t', e.args[0]) |
1083 | + |
1084 | + |
1085 | +class TestSSTestLoaderDiscoverTestsFromTree(tests.ImportingLocalFilesTest): |
1086 | + |
1087 | + def discover(self, start_dir): |
1088 | + test_loader = loader.SSTestLoader() |
1089 | + return test_loader.discoverTestsFromTree(start_dir) |
1090 | + |
1091 | + def test_simple_script(self): |
1092 | # A simple do nothing script with no imports |
1093 | - self.create_script('foo.py', 'pass') |
1094 | - suite = loader.TestLoader().loadTestsFromScript('.', 'foo.py') |
1095 | + tests.write_tree_from_desc('''file: foo.py |
1096 | +pass |
1097 | +''') |
1098 | + suite = self.discover('.') |
1099 | self.assertEqual(1, suite.countTestCases()) |
1100 | |
1101 | - def test_load_simple_script_with_csv(self): |
1102 | - self.create_script('foo.py', "pass") |
1103 | - with open('foo.csv', 'w') as f: |
1104 | - f.write('''\ |
1105 | + def test_simple_script_with_csv(self): |
1106 | + tests.write_tree_from_desc('''file: foo.py |
1107 | +pass |
1108 | +file: foo.csv |
1109 | 'foo'^'bar' |
1110 | 1^baz |
1111 | 2^qux |
1112 | ''') |
1113 | - suite = loader.TestLoader().loadTestsFromScript('.', 'foo.py') |
1114 | + suite = self.discover('.') |
1115 | self.assertEqual(2, suite.countTestCases()) |
1116 | |
1117 | - def test_load_non_existing_script(self): |
1118 | - suite = loader.TestLoader().loadTestsFromScript('.', 'foo.py') |
1119 | - self.assertEqual(0, suite.countTestCases()) |
1120 | - |
1121 | - |
1122 | -class TestScriptLoader(tests.ImportingLocalFilesTest): |
1123 | - |
1124 | - def get_test_loader(self): |
1125 | - return loader.TestLoader() |
1126 | - |
1127 | - def test_simple_script(self): |
1128 | + def test_simple_script_in_a_dir(self): |
1129 | tests.write_tree_from_desc('''dir: t |
1130 | # no t/__init__.py required, we don't need to import the scripts |
1131 | -file: t/foo.py |
1132 | -from sst.actions import * |
1133 | - |
1134 | +file: t/script.py |
1135 | raise AssertionError('Loading only, executing fails') |
1136 | ''') |
1137 | - script_loader = loader.ScriptLoader(self.get_test_loader()) |
1138 | - suite = script_loader.discover('t', 'foo.py') |
1139 | + suite = self.discover('t') |
1140 | self.assertEqual(1, suite.countTestCases()) |
1141 | |
1142 | def test_ignore_privates(self): |
1143 | tests.write_tree_from_desc('''dir: t |
1144 | file: t/_private.py |
1145 | ''') |
1146 | - script_loader = loader.ScriptLoader(self.get_test_loader()) |
1147 | - suite = script_loader.discover('t', '_private.py') |
1148 | - self.assertIs(None, suite) |
1149 | - |
1150 | - |
1151 | -class TesScriptDirLoader(tests.ImportingLocalFilesTest): |
1152 | - |
1153 | - def test_shared(self): |
1154 | - tests.write_tree_from_desc('''dir: t |
1155 | -# no t/__init__.py required, we don't need to import the scripts |
1156 | -file: t/foo.py |
1157 | -from sst.actions import * |
1158 | - |
1159 | -raise AssertionError('Loading only, executing fails') |
1160 | -dir: t/shared |
1161 | -file: t/shared/amodule.py |
1162 | -Don't look at me ! |
1163 | -''') |
1164 | - script_dir_loader = loader.ScriptDirLoader(loader.TestLoader()) |
1165 | - suite = script_dir_loader.discover('t', 'shared') |
1166 | - self.assertIs(None, suite) |
1167 | - |
1168 | - def test_regular(self): |
1169 | - tests.write_tree_from_desc('''dir: t |
1170 | -# no t/__init__.py required, we don't need to import the scripts |
1171 | -dir: t/subdir |
1172 | -file: t/subdir/foo.py |
1173 | -raise AssertionError('Loading only, executing fails') |
1174 | -dir: t/shared |
1175 | -file: t/shared/amodule.py |
1176 | -Don't look at me ! |
1177 | -''') |
1178 | - test_loader = loader.TestLoader() |
1179 | - suite = test_loader.discoverTests( |
1180 | - '.', file_loader_class=loader.ScriptLoader, |
1181 | - dir_loader_class=loader.ScriptDirLoader) |
1182 | - self.assertEqual(1, suite.countTestCases()) |
1183 | - |
1184 | - |
1185 | -class TestTestLoader(tests.ImportingLocalFilesTest): |
1186 | - |
1187 | - def test_simple_file_in_a_dir(self): |
1188 | - tests.write_tree_from_desc('''dir: t |
1189 | -file: t/__init__.py |
1190 | -file: t/foo.py |
1191 | -import unittest |
1192 | - |
1193 | -class Test(unittest.TestCase): |
1194 | - |
1195 | - def test_me(self): |
1196 | - self.assertTrue(True) |
1197 | -''') |
1198 | - test_loader = loader.TestLoader() |
1199 | - suite = test_loader.discoverTests('t') |
1200 | - self.assertEqual(1, suite.countTestCases()) |
1201 | - |
1202 | - def test_broken_file_in_a_dir(self): |
1203 | - tests.write_tree_from_desc('''dir: t |
1204 | -file: t/__init__.py |
1205 | -file: t/foo.py |
1206 | -I'm not even python code |
1207 | -''') |
1208 | - test_loader = loader.TestLoader() |
1209 | - e = self.assertRaises(SyntaxError, test_loader.discoverTests, 't') |
1210 | - self.assertEqual('EOL while scanning string literal', e.args[0]) |
1211 | - |
1212 | - def test_scripts_below_regular(self): |
1213 | - tests.write_tree_from_desc('''dir: t |
1214 | -file: t/__init__.py |
1215 | -file: t/foo.py |
1216 | -import unittest |
1217 | - |
1218 | -class Test(unittest.TestCase): |
1219 | - |
1220 | - def test_me(self): |
1221 | - self.assertTrue(True) |
1222 | -dir: t/scripts |
1223 | -file: t/scripts/__init__.py |
1224 | -from sst import loader |
1225 | - |
1226 | -discover = loader.discoverTestScripts |
1227 | -file: t/scripts/script.py |
1228 | -raise AssertionError('Loading only, executing fails') |
1229 | -''') |
1230 | - test_loader = loader.TestLoader() |
1231 | - suite = test_loader.discoverTests('t') |
1232 | - self.assertEqual(2, suite.countTestCases()) |
1233 | - # Check which kind of tests have been discovered or we may miss regular |
1234 | - # test cases seen as scripts. |
1235 | - self.assertEqual(['t.foo.Test.test_me', |
1236 | - 't.scripts.script'], |
1237 | - [t.id() for t in testtools.iterate_tests(suite)]) |
1238 | + suite = self.discover('t') |
1239 | + self.assertEqual(0, suite.countTestCases()) |
1240 | |
1241 | def test_regular_below_scripts(self): |
1242 | tests.write_tree_from_desc('''dir: t |
1243 | @@ -428,15 +373,10 @@ |
1244 | dir: t/regular |
1245 | file: t/regular/__init__.py |
1246 | from sst import loader |
1247 | -import unittest |
1248 | |
1249 | discover = loader.discoverRegularTests |
1250 | |
1251 | -class Test(unittest.TestCase): |
1252 | - |
1253 | - def test_in_init(self): |
1254 | - self.assertTrue(True) |
1255 | -file: t/regular/foo.py |
1256 | +file: t/regular/test_foo.py |
1257 | import unittest |
1258 | |
1259 | class Test(unittest.TestCase): |
1260 | @@ -446,15 +386,10 @@ |
1261 | file: t/script.py |
1262 | raise AssertionError('Loading only, executing fails') |
1263 | ''') |
1264 | - test_loader = loader.TestLoader() |
1265 | - suite = test_loader.discoverTests( |
1266 | - 't', |
1267 | - file_loader_class=loader.ScriptLoader, |
1268 | - dir_loader_class=loader.ScriptDirLoader) |
1269 | + suite = self.discover('t') |
1270 | # Check which kind of tests have been discovered or we may miss regular |
1271 | # test cases seen as scripts. |
1272 | - self.assertEqual(['t.regular.Test.test_in_init', |
1273 | - 't.regular.foo.Test.test_me', |
1274 | + self.assertEqual(['t.regular.test_foo.Test.test_me', |
1275 | 't.script'], |
1276 | [t.id() for t in testtools.iterate_tests(suite)]) |
1277 | |
1278 | @@ -489,89 +424,13 @@ |
1279 | file: script1.py |
1280 | file: script2.py |
1281 | file: not_a_test |
1282 | -# '.p' is intentional, not a typoed '.py' |
1283 | -file: test_not_a_test.p |
1284 | +file: test_not_a_test.potato |
1285 | _hidden_too.py |
1286 | ''') |
1287 | - test_loader = loader.TestLoader() |
1288 | - suite = test_loader.discoverTests( |
1289 | - '.', |
1290 | - file_loader_class=loader.ScriptLoader, |
1291 | - dir_loader_class=loader.ScriptDirLoader) |
1292 | + suite = self.discover('.') |
1293 | self.assertEqual(['script1', |
1294 | 'script2', |
1295 | 'tests.test_real.Test_test_real.test_test_real', |
1296 | 'tests.test_real1.Test_test_real1.test_test_real1', |
1297 | 'tests.test_real2.Test_test_real2.test_test_real2'], |
1298 | [t.id() for t in testtools.iterate_tests(suite)]) |
1299 | - |
1300 | - |
1301 | -class TestTestLoaderPattern(tests.ImportingLocalFilesTest): |
1302 | - |
1303 | - def test_default_pattern(self): |
1304 | - tests.write_tree_from_desc('''dir: t |
1305 | -file: t/__init__.py |
1306 | -file: t/foo.py |
1307 | -Don't look at me ! |
1308 | -file: t/test_foo.py |
1309 | -import unittest |
1310 | - |
1311 | -class Test(unittest.TestCase): |
1312 | - |
1313 | - def test_me(self): |
1314 | - self.assertTrue(True) |
1315 | -''') |
1316 | - test_loader = loader.TestLoader() |
1317 | - suite = test_loader.discover('t') |
1318 | - self.assertEqual(1, suite.countTestCases()) |
1319 | - |
1320 | - def test_pattern(self): |
1321 | - tests.write_tree_from_desc('''dir: t |
1322 | -file: t/__init__.py |
1323 | -file: t/foo_foo.py |
1324 | -import unittest |
1325 | - |
1326 | -class Test(unittest.TestCase): |
1327 | - |
1328 | - def test_me(self): |
1329 | - self.assertTrue(True) |
1330 | -file: t/test_foo.py |
1331 | -Don't look at me ! |
1332 | -''') |
1333 | - test_loader = loader.TestLoader() |
1334 | - suite = test_loader.discover('t', pattern='foo*.py') |
1335 | - self.assertEqual(1, suite.countTestCases()) |
1336 | - |
1337 | - |
1338 | -class TestTestLoaderTopLevelDir(testtools.TestCase): |
1339 | - |
1340 | - def setUp(self): |
1341 | - super(TestTestLoaderTopLevelDir, self).setUp() |
1342 | - # We build trees rooted in test_base_dir from which we will import |
1343 | - tests.set_cwd_to_tmp(self) |
1344 | - tests.protect_imports(self) |
1345 | - |
1346 | - def _create_foo_in_tests(self): |
1347 | - tests.write_tree_from_desc('''dir: t |
1348 | -file: t/__init__.py |
1349 | -file: t/foo.py |
1350 | -import unittest |
1351 | - |
1352 | -class Test(unittest.TestCase): |
1353 | - |
1354 | - def test_me(self): |
1355 | - self.assertTrue(True) |
1356 | -''') |
1357 | - |
1358 | - def test_simple_file_in_a_dir(self): |
1359 | - self._create_foo_in_tests() |
1360 | - test_loader = loader.TestLoader() |
1361 | - suite = test_loader.discover('t', '*.py', self.test_base_dir) |
1362 | - self.assertEqual(1, suite.countTestCases()) |
1363 | - |
1364 | - def test_simple_file_in_a_dir_no_sys_path(self): |
1365 | - self._create_foo_in_tests() |
1366 | - test_loader = loader.TestLoader() |
1367 | - e = self.assertRaises(ImportError, |
1368 | - test_loader.discover, 't', '*.py') |
1369 | - self.assertEqual(e.message, 'No module named t') |
1370 | |
1371 | === modified file 'src/sst/tests/test_runtests.py' |
1372 | --- src/sst/tests/test_runtests.py 2013-06-04 15:56:58 +0000 |
1373 | +++ src/sst/tests/test_runtests.py 2013-06-05 15:07:32 +0000 |
1374 | @@ -19,7 +19,10 @@ |
1375 | |
1376 | from cStringIO import StringIO |
1377 | |
1378 | +import testtools |
1379 | + |
1380 | from sst import ( |
1381 | + browsers, |
1382 | runtests, |
1383 | tests, |
1384 | ) |
1385 | @@ -76,6 +79,51 @@ |
1386 | self.run_tests(['t.t'], excludes=['to'])) |
1387 | |
1388 | |
1389 | +class TestRunBrowserFactory(testtools.TestCase): |
1390 | + |
1391 | + def test_browser_factory_is_mandatory(self): |
1392 | + self.assertRaises(RuntimeError, runtests.runtests, |
1393 | + None, 'no results directory used', None, |
1394 | + browser_factory=None) |
1395 | + |
1396 | + |
1397 | +class TestRunTestsShared(tests.ImportingLocalFilesTest): |
1398 | + |
1399 | + def run_tests(self, test_dir, shared_dir=None): |
1400 | + out = StringIO() |
1401 | + runtests.runtests(None, 'no results directory used', out, |
1402 | + test_dir=test_dir, shared_directory=shared_dir, |
1403 | + collect_only=True) |
1404 | + return out.getvalue().splitlines() |
1405 | + |
1406 | + def test_shared_in_top(self): |
1407 | + tests.write_tree_from_desc('''dir: t |
1408 | +# no t/__init__.py required, we don't need to import the scripts |
1409 | +file: t/foo.py |
1410 | +from sst.actions import * |
1411 | + |
1412 | +raise AssertionError('Loading only, executing fails') |
1413 | +dir: t/shared |
1414 | +file: t/shared/amodule.py |
1415 | +Don't look at me ! |
1416 | +''') |
1417 | + test_names = self.run_tests('t', 't/shared') |
1418 | + self.assertEqual(['t.foo'], test_names) |
1419 | + |
1420 | + def test_shared_in_dir(self): |
1421 | + tests.write_tree_from_desc('''dir: t |
1422 | +# no t/__init__.py required, we don't need to import the scripts |
1423 | +dir: t/subdir |
1424 | +file: t/subdir/foo.py |
1425 | +raise AssertionError('Loading only, executing fails') |
1426 | +dir: t/shared |
1427 | +file: t/shared/amodule.py |
1428 | +Don't look at me ! |
1429 | +''') |
1430 | + test_names = self.run_tests('.', 't/shared') |
1431 | + self.assertEqual(['t.subdir.foo'], test_names) |
1432 | + |
1433 | + |
1434 | class SSTRunExitCodeTestCase(tests.ImportingLocalFilesTest): |
1435 | |
1436 | def setUp(self): |
1437 | @@ -108,7 +156,8 @@ |
1438 | |
1439 | def run_tests(self, args): |
1440 | out = StringIO() |
1441 | - failures = runtests.runtests(args, 'no results directory used', out) |
1442 | + failures = runtests.runtests(args, 'no results directory used', out, |
1443 | + browser_factory=browsers.FirefoxFactory()) |
1444 | return bool(failures) |
1445 | |
1446 | def test_pass(self): |
1447 | |
1448 | === modified file 'test-loader.TODO' |
1449 | --- test-loader.TODO 2013-05-30 13:31:51 +0000 |
1450 | +++ test-loader.TODO 2013-06-05 15:07:32 +0000 |
1451 | @@ -9,32 +9,3 @@ |
1452 | * run unit tests |
1453 | |
1454 | sst-test -e tests.acceptance |
1455 | - |
1456 | -* some test_loader tests are too big, this screams for better helpers so |
1457 | - they can be simplified. |
1458 | - |
1459 | -* fix the remaining grey areas in the design |
1460 | - |
1461 | -There are a few points that smell funny in the current implementation |
1462 | -including: |
1463 | - |
1464 | -- abusing sortTestMethodsUsing |
1465 | - |
1466 | -- having to call sortNames in several places |
1467 | - |
1468 | -This is probably caused by some less than ideal split of responsability |
1469 | -between TestLoader and the {File|Dir}Loader classes. |
1470 | - |
1471 | -The key points that need to be handled are: |
1472 | - |
1473 | -- whether directories are packages or not and as such require to be imported |
1474 | - |
1475 | -- if they are imported, respect user overriding |
1476 | - |
1477 | -- allowing the user to specify some matching on the base names encountered |
1478 | - while walking the tree (or a sub tree). This should remain separate for |
1479 | - files and directories (the rules are different). |
1480 | - => addressed with '^test_name' |
1481 | - |
1482 | -- how the sub tree is iterated |
1483 | - |
I can't find any errors. But this is huge, I've asked for another pair of eyes to double check :)