Merge lp:~vila/selenium-simple-test/test-loader into lp:selenium-simple-test

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
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.
Revision history for this message
Leo Arias (elopio) wrote :

I can't find any errors. But this is huge, I've asked for another pair of eyes to double check :)

review: Approve (code review)
Revision history for this message
Corey Goldberg (coreygoldberg) wrote :

lgtm too

review: Approve

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-

Subscribers

People subscribed via source and target branches