##// END OF EJS Templates
Add test utility for parsing test output from stdout/stderr
Fernando Perez -
Show More
@@ -1,52 +1,61 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 Tests for testing.tools
4 Tests for testing.tools
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2009 The IPython Development Team
8 # Copyright (C) 2008-2009 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 import os
18 import os
19 import sys
19 import sys
20
20
21 import nose.tools as nt
21 import nose.tools as nt
22
22
23 from IPython.testing import decorators as dec
23 from IPython.testing import decorators as dec
24 from IPython.testing.tools import full_path
24 from IPython.testing.tools import full_path, parse_test_output
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Tests
27 # Tests
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30
31 @dec.skip_win32
30 @dec.skip_win32
32 def test_full_path_posix():
31 def test_full_path_posix():
33 spath = '/foo/bar.py'
32 spath = '/foo/bar.py'
34 result = full_path(spath,['a.txt','b.txt'])
33 result = full_path(spath,['a.txt','b.txt'])
35 nt.assert_equal(result, ['/foo/a.txt', '/foo/b.txt'])
34 nt.assert_equal(result, ['/foo/a.txt', '/foo/b.txt'])
36 spath = '/foo'
35 spath = '/foo'
37 result = full_path(spath,['a.txt','b.txt'])
36 result = full_path(spath,['a.txt','b.txt'])
38 nt.assert_equal(result, ['/a.txt', '/b.txt'])
37 nt.assert_equal(result, ['/a.txt', '/b.txt'])
39 result = full_path(spath,'a.txt')
38 result = full_path(spath,'a.txt')
40 nt.assert_equal(result, ['/a.txt'])
39 nt.assert_equal(result, ['/a.txt'])
41
40
42
41
43 @dec.skip_if_not_win32
42 @dec.skip_if_not_win32
44 def test_full_path_win32():
43 def test_full_path_win32():
45 spath = 'c:\\foo\\bar.py'
44 spath = 'c:\\foo\\bar.py'
46 result = full_path(spath,['a.txt','b.txt'])
45 result = full_path(spath,['a.txt','b.txt'])
47 nt.assert_equal(result, ['c:\\foo\\a.txt', 'c:\\foo\\b.txt'])
46 nt.assert_equal(result, ['c:\\foo\\a.txt', 'c:\\foo\\b.txt'])
48 spath = 'c:\\foo'
47 spath = 'c:\\foo'
49 result = full_path(spath,['a.txt','b.txt'])
48 result = full_path(spath,['a.txt','b.txt'])
50 nt.assert_equal(result, ['c:\\a.txt', 'c:\\b.txt'])
49 nt.assert_equal(result, ['c:\\a.txt', 'c:\\b.txt'])
51 result = full_path(spath,'a.txt')
50 result = full_path(spath,'a.txt')
52 nt.assert_equal(result, ['c:\\a.txt'])
51 nt.assert_equal(result, ['c:\\a.txt'])
52
53
54 def test_parser():
55 err = ("FAILED (errors=1)", 1, 0)
56 fail = ("FAILED (failures=1)", 0, 1)
57 both = ("FAILED (errors=1, failures=1)", 1, 1)
58 for txt, nerr, nfail in [err, fail, both]:
59 nerr1, nfail1 = parse_test_output(txt)
60 yield (nt.assert_equal, nerr, nerr1)
61 yield (nt.assert_equal, nfail, nfail1)
@@ -1,89 +1,133 b''
1 """Generic testing tools that do NOT depend on Twisted.
1 """Generic testing tools that do NOT depend on Twisted.
2
2
3 In particular, this module exposes a set of top-level assert* functions that
3 In particular, this module exposes a set of top-level assert* functions that
4 can be used in place of nose.tools.assert* in method generators (the ones in
4 can be used in place of nose.tools.assert* in method generators (the ones in
5 nose can not, at least as of nose 0.10.4).
5 nose can not, at least as of nose 0.10.4).
6
6
7 Note: our testing package contains testing.util, which does depend on Twisted
7 Note: our testing package contains testing.util, which does depend on Twisted
8 and provides utilities for tests that manage Deferreds. All testing support
8 and provides utilities for tests that manage Deferreds. All testing support
9 tools that only depend on nose, IPython or the standard library should go here
9 tools that only depend on nose, IPython or the standard library should go here
10 instead.
10 instead.
11
11
12
12
13 Authors
13 Authors
14 -------
14 -------
15 - Fernando Perez <Fernando.Perez@berkeley.edu>
15 - Fernando Perez <Fernando.Perez@berkeley.edu>
16 """
16 """
17
17
18 #*****************************************************************************
18 #*****************************************************************************
19 # Copyright (C) 2009 The IPython Development Team
19 # Copyright (C) 2009 The IPython Development Team
20 #
20 #
21 # Distributed under the terms of the BSD License. The full license is in
21 # Distributed under the terms of the BSD License. The full license is in
22 # the file COPYING, distributed as part of this software.
22 # the file COPYING, distributed as part of this software.
23 #*****************************************************************************
23 #*****************************************************************************
24
24
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26 # Required modules and packages
26 # Required modules and packages
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28
28
29 import os
29 import os
30 import re
30 import sys
31 import sys
31
32
32 import nose.tools as nt
33 import nose.tools as nt
33
34
34 from IPython.tools import utils
35 from IPython.tools import utils
35 from IPython.testing import decorators as dec
36 from IPython.testing import decorators as dec
36
37
37 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
38 # Globals
39 # Globals
39 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
40
41
41 # Make a bunch of nose.tools assert wrappers that can be used in test
42 # Make a bunch of nose.tools assert wrappers that can be used in test
42 # generators. This will expose an assert* function for each one in nose.tools.
43 # generators. This will expose an assert* function for each one in nose.tools.
43
44
44 _tpl = """
45 _tpl = """
45 def %(name)s(*a,**kw):
46 def %(name)s(*a,**kw):
46 return nt.%(name)s(*a,**kw)
47 return nt.%(name)s(*a,**kw)
47 """
48 """
48
49
49 for _x in [a for a in dir(nt) if a.startswith('assert')]:
50 for _x in [a for a in dir(nt) if a.startswith('assert')]:
50 exec _tpl % dict(name=_x)
51 exec _tpl % dict(name=_x)
51
52
52 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
53 # Functions and classes
54 # Functions and classes
54 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
55
56
56
57
57 def full_path(startPath,files):
58 def full_path(startPath,files):
58 """Make full paths for all the listed files, based on startPath.
59 """Make full paths for all the listed files, based on startPath.
59
60
60 Only the base part of startPath is kept, since this routine is typically
61 Only the base part of startPath is kept, since this routine is typically
61 used with a script's __file__ variable as startPath. The base of startPath
62 used with a script's __file__ variable as startPath. The base of startPath
62 is then prepended to all the listed files, forming the output list.
63 is then prepended to all the listed files, forming the output list.
63
64
64 Parameters
65 Parameters
65 ----------
66 ----------
66 startPath : string
67 startPath : string
67 Initial path to use as the base for the results. This path is split
68 Initial path to use as the base for the results. This path is split
68 using os.path.split() and only its first component is kept.
69 using os.path.split() and only its first component is kept.
69
70
70 files : string or list
71 files : string or list
71 One or more files.
72 One or more files.
72
73
73 Examples
74 Examples
74 --------
75 --------
75
76
76 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
77 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
77 ['/foo/a.txt', '/foo/b.txt']
78 ['/foo/a.txt', '/foo/b.txt']
78
79
79 >>> full_path('/foo',['a.txt','b.txt'])
80 >>> full_path('/foo',['a.txt','b.txt'])
80 ['/a.txt', '/b.txt']
81 ['/a.txt', '/b.txt']
81
82
82 If a single file is given, the output is still a list:
83 If a single file is given, the output is still a list:
83 >>> full_path('/foo','a.txt')
84 >>> full_path('/foo','a.txt')
84 ['/a.txt']
85 ['/a.txt']
85 """
86 """
86
87
87 files = utils.list_strings(files)
88 files = utils.list_strings(files)
88 base = os.path.split(startPath)[0]
89 base = os.path.split(startPath)[0]
89 return [ os.path.join(base,f) for f in files ]
90 return [ os.path.join(base,f) for f in files ]
91
92
93 def parse_test_output(txt):
94 """Parse the output of a test run and return errors, failures.
95
96 Parameters
97 ----------
98 txt : str
99 Text output of a test run, assumed to contain a line of one of the
100 following forms::
101 'FAILED (errors=1)'
102 'FAILED (failures=1)'
103 'FAILED (errors=1, failures=1)'
104
105 Returns
106 -------
107 nerr, nfail: number of errors and failures.
108 """
109
110 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
111 if err_m:
112 nerr = int(err_m.group(1))
113 nfail = 0
114 return nerr, nfail
115
116 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
117 if fail_m:
118 nerr = 0
119 nfail = int(fail_m.group(1))
120 return nerr, nfail
121
122 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
123 re.MULTILINE)
124 if both_m:
125 nerr = int(both_m.group(1))
126 nfail = int(both_m.group(2))
127 return nerr, nfail
128
129 # If the input didn't match any of these forms, assume no error/failures
130 return 0, 0
131
132 # So nose doesn't think this is a test
133 parse_test_output.__test__ = False
General Comments 0
You need to be logged in to leave comments. Login now