Merge lp:~madteam/mg5amcnlo/test-framework-dev into lp:~madteam/mg5amcnlo/framework-dev

Proposed by Olivier Mattelaer
Status: Merged
Approved by: Michel Herquet
Approved revision: 30
Merged at revision: not available
Proposed branch: lp:~madteam/mg5amcnlo/test-framework-dev
Merge into: lp:~madteam/mg5amcnlo/framework-dev
Diff against target: 682 lines
2 files modified
bin/test_manager.py (+314/-0)
tests/unit_tests/bin/test_test_manager.py (+357/-0)
To merge this branch: bzr merge lp:~madteam/mg5amcnlo/test-framework-dev
Reviewer Review Type Date Requested Status
Michel Herquet (community) full Approve
Review via email: mp+12875@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Olivier Mattelaer (olivier-mattelaer) wrote :

Add the test manager to launch test automaticaly

Revision history for this message
Michel Herquet (herquet) wrote :

Perfect! Ok for merging

review: Approve (full)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'bin/test_manager.py'
--- bin/test_manager.py 1970-01-01 00:00:00 +0000
+++ bin/test_manager.py 2009-10-05 15:15:19 +0000
@@ -0,0 +1,314 @@
1#!/usr/bin/env python
2##############################################################################
3#
4# Copyright (c) 2009 The MadGraph Development team and Contributors
5#
6# This file is a part of the MadGraph 5 project, an application which
7# automatically generates Feynman diagrams and matrix elements for arbitrary
8# high-energy processes in the Standard Model and beyond.
9#
10# It is subject to the MadGraph license which should accompany this
11# distribution.
12#
13# For more information, please visit: http://madgraph.phys.ucl.ac.be
14#
15##############################################################################
16""" Manager for running the test library
17
18 This library offer a simple way to launch test.
19
20 To run a test/class of test/test file/module of test/...
21 you just have to launch
22 test_manager.run(NAME)
23 or
24 test_manager.run(LIST_OF_NAME)
25
26 the NAME can contain regular expression (in python re standard format)
27"""
28
29import unittest
30import re
31import os
32import inspect
33import sys
34sys.path+=['.','..']
35
36##############################################################################
37def run(expression='', re_opt=0, package='./tests/'):
38 """ running the test associated to expression. By default, this launch all
39 test derivated from TestCase. expression can be the name of directory,
40 module, class, function or event standard regular expression (in re format)
41 """
42
43 #init a test suite
44 testsuite = unittest.TestSuite()
45 collect = unittest.TestLoader()
46 for test_fct in Test_in_module(package=package, expression=expression, \
47 re_opt=re_opt):
48 data=collect.loadTestsFromName(test_fct)
49 testsuite.addTest(data)
50 unittest.TextTestRunner(verbosity=1).run(testsuite)
51
52
53##############################################################################
54class Test_in_module(list):
55 """ class introspecting the test module to find the available test.
56
57 The strategy is the following:
58 The routine collect_dir looks in all module/file to find the different
59 functions in different test class. This produce a list, on wich external
60 routines can loop on.
61
62 In order to authorize definition and loop on this object on the same time,
63 i.e: for test in Test_in_module([opt])-. At each time a loop is started,
64 we check if a collect_dir runned before, and run it if neccessary. And
65 that without any problem with future add-on on this class.
66 """
67
68 search_class=unittest.TestCase
69 class ERRORTestManager(Exception): pass
70
71 ##########################################################################
72 def __init__(self, package='./tests/', expression='', re_opt=0):
73 """ initialize global variable for the test """
74
75 list.__init__(self)
76
77 self.package = package
78 if self.package[-1] != '/': self.package+='/'
79 self.restrict_to(expression, re_opt)
80
81 ##########################################################################
82 def _check_if_obj_build(self):
83 """ Check if a collect is already done
84 Uses to have smart __iter__ and __contain__ functions
85 """
86 if len(self) == 0:
87 self.collect_dir(self.package, checking=True)
88
89 ##########################################################################
90 def __iter__(self):
91 """ Check that a collect was performed (do it if needed) """
92 self._check_if_obj_build()
93 return list.__iter__(self)
94
95 ##########################################################################
96 def __contains__(self,value):
97 """ Check that a collect was performed (do it if needed) """
98 self._check_if_obj_build()
99 return list.__contains__(self,value)
100
101 ##########################################################################
102 def collect_dir(self, directory, checking=True):
103 """ Find the file and the subpackage in this package """
104
105 for name in os.listdir(directory):
106 local_check = checking
107
108 status = self.status_file(directory + '/' + name)
109 if status is None:
110 continue
111
112 if checking:
113 if self.check_valid(directory + '/' + name):
114 local_check = False #since now perform all the test
115
116 if status == 'file':
117 self.collect_file(directory + '/' + name, local_check)
118 elif status == "module":
119 self.collect_dir(directory + '/' + name, local_check)
120
121 ##########################################################################
122 def collect_file(self, file, checking=True):
123 """ Find the different class instance derivated of TestCase """
124
125 pyname=self.passin_pyformat(file)
126 exec('import '+pyname+' as obj')
127
128 #look at class
129 for name in dir(obj):
130 exec('class_=obj.'+name)
131 if inspect.isclass(class_) and issubclass(class_,unittest.TestCase):
132 if checking:
133 if self.check_valid(name):
134 check_inside=False
135 else:
136 check_inside=True
137 else:
138 check_inside=False
139
140
141 self.collect_function(class_, checking=check_inside, \
142 base=pyname)
143
144 ##########################################################################
145 def collect_function(self, class_, checking=True, base=''):
146 """
147 Find the different test function in this class
148 test functions should start with test
149 """
150
151 if not inspect.isclass(class_):
152 raise self.ERRORTestManager, 'wrong input class_'
153 if not issubclass(class_,unittest.TestCase):
154 raise self.ERRORTestManager, 'wrong input class_'
155
156 #devellop the name
157 if base:
158 base+='.'+class_.__name__
159 else:
160 base=class_.__name__
161
162 candidate=[base+'.'+name for name in dir(class_) if \
163 name.startswith('test')\
164 and inspect.ismethod(eval('class_.'+name))]
165
166 if not checking:
167 self+=candidate
168 else:
169 self+=[name for name in candidate if self.check_valid(name)]
170
171 ##########################################################################
172 def restrict_to(self, expression, re_opt=0):
173 """ store in global the expression to fill in order to be a valid test """
174
175 if isinstance(expression,list):
176 pass
177 elif isinstance(expression,basestring):
178 if expression=='':
179 expression=['.*'] #made an re authorizing all regular name
180 else:
181 expression = [expression]
182 else:
183 raise self.ERRORTestManager, 'obj should be list or string'
184
185 self.rule=[]
186 for expr in expression:
187 if not expr.startswith('^'): expr='^'+expr #fix the begin of the re
188 if not expr.endswith('$'): expr=expr+'$' #fix the end of the re
189 self.rule.append( re.compile(expr, re_opt) )
190
191 ##########################################################################
192 def check_valid(self, name):
193 """ check if the name correspond to the rule """
194
195 if not isinstance(name,basestring):
196 raise self.ERRORTestManager, 'check valid take a string argument'
197
198 for specific_format in self.format_possibility(name):
199 for expr in self.rule:
200 if expr.search(specific_format):
201 return True
202 return False
203
204 ##########################################################################
205 @staticmethod
206 def status_file(name):
207 """ check if a name is a module/a python file and return the status """
208 if os.path.isfile(name):
209 if name.endswith('.py') and '__init__' not in name:
210 return 'file'
211 elif os.path.isdir(name):
212 if os.path.isfile(name+'/__init__.py'):
213 return 'module'
214
215 ##########################################################################
216 @classmethod
217 def passin_pyformat(cls,name):
218 """ transform a relative position in a python import format """
219
220 if not isinstance(name,basestring):
221 raise cls.ERRORTestManager, 'collect_file takes a file position'
222
223 name=name.replace('//','/') #sanity
224 #deal with begin/end
225 if name.startswith('./'):
226 name=name[2:]
227 if not name.endswith('.py'):
228 raise cls.ERRORTestManager,'Python files should have .py extension'
229 else:
230 name=name[:-3]
231
232 if name.startswith('/'):
233 raise cls.ERRORTestManager, 'path must be relative'
234 if '..' in name:
235 raise cls.ERRORTestManager,'relative position with \'..\' is' + \
236 ' not supported for the moment'
237
238 #replace '/' by points -> Python format
239 name=name.replace('/','.')
240
241 #position
242 return name
243
244 ##########################################################################
245 def format_possibility(self,name):
246 """ return the different string derivates from name in order to
247 scan all the different format authorizes for a restrict_to
248 format authorizes:
249 1) full file position
250 2) name of the file (with extension)
251 3) full file position whithour extension
252 4) name of the file (whithout extension)
253 5) name of the file (but suppose name in python format)
254 6) if name is a python file, try with a './' and with package pos
255 """
256
257 def add_to_possibility(possibility,val):
258 """ add if not exist """
259 if val not in possibility:
260 possibility.append(val)
261 #end local def
262
263 #print name
264 #sanity
265 if name.startswith('./'): name = name[2:]
266 name=name.replace('//','/')
267 # init with solution #
268 out=[name]
269
270 # add solution 2
271 new_pos=name.split('/')[-1]
272 add_to_possibility(out,new_pos)
273
274 #remove extension and add solution3 and 6
275 if name.endswith('.py'):
276 add_to_possibility(out,'./'+name)
277 add_to_possibility(out,self.package+name)
278 name = name[:-3]
279 add_to_possibility(out,name)
280
281 #add solution 4
282 new_pos=name.split('/')[-1]
283 add_to_possibility(out,new_pos)
284
285 #add solution 5
286 new_pos=name.split('.')[-1]
287 add_to_possibility(out,new_pos)
288
289
290
291
292 return out
293
294##############################################################################
295if __name__ == "__main__":
296
297 opt=sys.argv
298 if len(opt)==1:
299 run()
300 elif len(opt)==2:
301 run(opt[1])
302 else:
303 run(opt[1],re_opt=opt[2])
304
305#some example
306# run('iolibs')
307# run('test_test_manager.py')
308# run('./tests/unit_tests/bin/test_test_manager.py')
309# run('IOLibsMiscTest')
310# run('Unittest_on_TestinModule')
311# run('test_check_valid_on_file')
312# run('test_collect_dir.*') # '.*' stands for all possible char (re format)
313
314
0315
=== added directory 'tests/unit_tests/bin'
=== added file 'tests/unit_tests/bin/__init__.py'
=== added file 'tests/unit_tests/bin/test_test_manager.py'
--- tests/unit_tests/bin/test_test_manager.py 1970-01-01 00:00:00 +0000
+++ tests/unit_tests/bin/test_test_manager.py 2009-10-05 15:15:19 +0000
@@ -0,0 +1,357 @@
1##############################################################################
2#
3# Copyright (c) 2009 The MadGraph Development team and Contributors
4#
5# This file is a part of the MadGraph 5 project, an application which
6# automatically generates Feynman diagrams and matrix elements for arbitrary
7# high-energy processes in the Standard Model and beyond.
8#
9# It is subject to the MadGraph license which should accompany this
10# distribution.
11#
12# For more information, please visit: http://madgraph.phys.ucl.ac.be
13#
14##############################################################################
15
16"""Unit test library for the Misc routine library in the I/O package"""
17
18import sys
19sys.path+=['../../../bin','.','./bin']
20
21import unittest
22import test_manager
23import inspect
24
25class Unittest_on_TestinModule(unittest.TestCase):
26 #This class test to find it's own property so it need some shortcut
27 test_path='./tests/unit_tests/bin/'
28 name='test.manager.Unittest_on_TestinModule'
29
30 def setUp(self):
31 """ basic building of the class to test """
32 self.testmodule=test_manager.Test_in_module(package=self.test_path)
33
34 def tearDown(self):
35 pass
36
37 def test_buiding_in_iter(self):
38 """ Test_in_module.__iter__ is able to build the list """
39
40 for i in self.testmodule:
41 break
42 self.assert_(len(self.testmodule)>1)
43
44 def test_collect_dir(self):
45 """ Test_in_module.collect_dir should detect subdirectory and file """
46
47 self.testmodule=test_manager.Test_in_module(package= \
48 './tests/unit_tests')
49 self.assert_('tests.unit_tests.bin.test_test_manager.Unittest_on_TestinModule.test_collect_dir' in self.testmodule)
50
51 def test_collect_dir_with_restriction_file(self):
52 """ Test_in_module.collect_dir pass corectly restriction rule on file"""
53 self.testmodule.restrict_to('test_test_manager.py')
54# self.testmodule.collect_dir('./tests/unit_tests/bin')
55 self.assert_('tests.unit_tests.bin.test_test_manager.Unittest_on_TestinModule.test_collect_dir' in self.testmodule)
56
57 def test_collect_dir_with_restriction_file2(self):
58 """ Test_in_module.collect_dir pass corectly restriction rule on file"""
59 self.testmodule.restrict_to('./tests/unit_tests/bin/test_test_manager.py')
60# self.testmodule.collect_dir('./tests/unit_tests/bin')
61# print self.testmodule
62 self.assert_('tests.unit_tests.bin.test_test_manager.Unittest_on_TestinModule.test_collect_dir' in self.testmodule)
63
64 def test_collect_dir_with_restriction_class(self):
65 """ Test_in_module.collect_dir pass corectly restriction rule on class"""
66
67 self.testmodule.restrict_to('Unittest_on_TestinModule')
68# self.testmodule.collect_dir('./tests/unit_tests/bin')
69 self.assert_('tests.unit_tests.bin.test_test_manager.Unittest_on_TestinModule.test_collect_dir' in self.testmodule)
70
71 def test_collect_dir_with_restriction_fct(self):
72 """ Test_in_module.collect_dir pass corectly restriction rule on fct"""
73
74 self.testmodule.restrict_to('test_check_valid.*')
75 self.assert_('tests.unit_tests.bin.test_test_manager.Unittest_on_TestinModule.test_collect_dir' not in self.testmodule)
76 self.assert_('tests.unit_tests.bin.test_test_manager.Unittest_on_TestinModule.test_check_valid_on_file' in self.testmodule)
77
78
79 def test_collect_file_wrong_arg(self):
80 """ Test_in_module.collect_file fails on wrong argument"""
81
82 for input in [1,{1:2},[1],str,int,list,'alpha']:
83 self.assertRaises(test_manager.Test_in_module.ERRORTestManager, \
84 self.testmodule.collect_file, input)
85
86 def test_collect_file(self):
87 """ Test_in_module.collect_file find the different class in a file """
88
89 self.testmodule.collect_file('./tests/unit_tests/bin/test_test_manager.py')
90 self.assert_('tests.unit_tests.bin.test_test_manager.Unittest_on_TestinModule.test_collect_file' in \
91 self.testmodule)
92
93 def test_collect_function_wrong_arg(self):
94 """ Test_in_module.collect_function fails on wrong argument """
95
96 for input in [1,{1:2},[1],'alpha',str,int,list]:
97 self.assertRaises(test_manager.Test_in_module.ERRORTestManager, \
98 self.testmodule.collect_function, input)
99
100
101 def test_collect_function(self):
102 """ Test_in_module.collect_function find the test function """
103
104 self.testmodule.collect_function(Unittest_on_TestinModule)
105 self.assert_('Unittest_on_TestinModule.test_collect_function' in \
106 self.testmodule)
107
108 for name in self.testmodule:
109 name=name.split('.')[-1]
110 self.assertTrue(name.startswith('test'))
111
112 def test_output_are_function(self):
113 """ Test_in_module.collect_function returns test funcions only """
114 self.testmodule.collect_function(Unittest_on_TestinModule)
115 mytest = unittest.TestSuite()
116 collect = unittest.TestLoader()
117 for test_fct in self.testmodule:
118 try:
119 collect.loadTestsFromName( \
120 'tests.unit_tests.bin.test_test_manager.'+test_fct)
121 except:
122 self.fail('non callable object are returned')
123
124
125 def test_restrict_to_inputcheck(self):
126 """ Test_in_module.restrict_to fail on non string/list input """
127
128 input1={}
129 self.assertRaises(test_manager.Test_in_module.ERRORTestManager, \
130 self.testmodule.restrict_to, input1)
131 input1=1
132 self.assertRaises(test_manager.Test_in_module.ERRORTestManager, \
133 self.testmodule.restrict_to, input1)
134 import re
135
136 input1=re.compile('''1''')
137 self.assertRaises(test_manager.Test_in_module.ERRORTestManager, \
138 self.testmodule.restrict_to, input1)
139
140 def test_check_valid_wrong_arg(self):
141 """ Test_in_module.check_valid raise error if not str in input """
142
143 for input in [1,{1:2},[1]]:
144 self.assertRaises(test_manager.Test_in_module.ERRORTestManager, \
145 self.testmodule.check_valid, input)
146
147 def test_check_valid_on_module(self):
148 """ Test_in_module.check_valid recognizes module """
149
150 expression = 'bin'
151 self.testmodule.restrict_to(expression)
152 pos = './bin'
153 self.assertTrue(self.testmodule.check_valid(pos))
154 pos = './bin2'
155 self.assertFalse(self.testmodule.check_valid(pos))
156 pos = 'bin'
157 self.assertTrue(self.testmodule.check_valid(pos))
158 pos = '../test/bin'
159 self.assertTrue(self.testmodule.check_valid(pos))
160
161 def test_check_valid_on_file(self):
162 """ Test_in_module.check_valid recognizes file """
163
164 expression = 'test'
165 self.testmodule.restrict_to(expression)
166 pos = 'test.py'
167 self.assertTrue(self.testmodule.check_valid(pos))
168 pos = './test.py'
169 self.assertTrue(self.testmodule.check_valid(pos))
170 pos = '../test/test.py'
171 self.assertTrue(self.testmodule.check_valid(pos))
172 pos = 'test.pyc'
173 self.assertFalse(self.testmodule.check_valid(pos))
174 pos = 'onetest.py'
175 self.assertFalse(self.testmodule.check_valid(pos))
176 pos = 'test/file.py'
177 self.assertFalse(self.testmodule.check_valid(pos))
178
179 expression = 'test.py'
180 self.testmodule.restrict_to(expression)
181 pos = 'test.py'
182 self.assertTrue(self.testmodule.check_valid(pos))
183 pos = './test.py'
184 self.assertTrue(self.testmodule.check_valid(pos))
185 pos = '../test/test.py'
186 self.assertTrue(self.testmodule.check_valid(pos))
187 pos = 'test.pyc'
188 self.assertFalse(self.testmodule.check_valid(pos))
189 pos = 'onetest.py'
190 self.assertFalse(self.testmodule.check_valid(pos))
191 pos = 'test/file.py'
192 self.assertFalse(self.testmodule.check_valid(pos))
193
194 expression = 'test.test.py'
195 self.testmodule.restrict_to(expression)
196 pos = 'test/test.py'
197 self.assertTrue(self.testmodule.check_valid(pos))
198 pos = './test.py'
199 self.assertFalse(self.testmodule.check_valid(pos))
200 pos = 'bin/test/test.py'
201 self.assertFalse(self.testmodule.check_valid(pos))
202 pos = 'test.pyc'
203 self.assertFalse(self.testmodule.check_valid(pos))
204 pos = 'onetest.py'
205 self.assertFalse(self.testmodule.check_valid(pos))
206 pos = 'test/file.py'
207 self.assertFalse(self.testmodule.check_valid(pos))
208
209 expression = './test/test.py'
210 self.testmodule.restrict_to(expression)
211 pos = 'test/test.py'
212 self.assertTrue(self.testmodule.check_valid(pos))
213 pos = './test.py'
214 self.assertFalse(self.testmodule.check_valid(pos))
215 pos = 'bin/test/test.py'
216 self.assertFalse(self.testmodule.check_valid(pos))
217 pos = 'test.pyc'
218 self.assertFalse(self.testmodule.check_valid(pos))
219 pos = 'onetest.py'
220 self.assertFalse(self.testmodule.check_valid(pos))
221 pos = 'test/file.py'
222 self.assertFalse(self.testmodule.check_valid(pos))
223
224
225 def test_check_valid_on_class(self):
226 """ Test_in_module.check_valid recognizes class of test """
227
228 expression = 'Unittest_on_TestinModule'
229 self.testmodule.restrict_to(expression)
230 name = 'Unittest_on_TestinModule'
231 self.assertTrue(self.testmodule.check_valid(name))
232 name = 'test.Unittest_on_TestinModule'
233 self.assertTrue(self.testmodule.check_valid(name))
234 name = 'I.am.Your.Father'
235 self.assertFalse(self.testmodule.check_valid(name))
236
237 def test_check_valid_on_function(self):
238 """ Test_in_module.check_valid recognizes functions """
239
240 expression='test_search'
241 self.testmodule.restrict_to(expression)
242 name='test_search'
243 self.assertTrue(self.testmodule.check_valid(name))
244 name='test.test_search'
245 self.assertTrue(self.testmodule.check_valid(name))
246 name='It.is.impossible'
247 self.assertFalse(self.testmodule.check_valid(name))
248
249 expression='test_check_valid.*'
250 self.testmodule.restrict_to(expression)
251 name='module.test_check_valid_on_function'
252 self.assertTrue(self.testmodule.check_valid(name))
253
254 def test_check_valid_with_re(self):
255 """ Test_in_module.check_valid should work with re """
256
257 expression = 'test.*'
258 self.testmodule.restrict_to(expression,)
259 name = 'test_search'
260 self.assertTrue(self.testmodule.check_valid(name))
261 name = 'valid.test_search'
262 self.assertTrue(self.testmodule.check_valid(name))
263 name = 'one_test'
264 self.assertFalse(self.testmodule.check_valid(name))
265
266 expression = 'test'
267 import re
268 re_opt = re.I
269 self.testmodule.restrict_to(expression,re_opt)
270 name = 'test'
271 self.assertTrue(self.testmodule.check_valid(name))
272 name = 'TEST'
273 self.assertTrue(self.testmodule.check_valid(name))
274 name = 'one_test'
275 self.assertFalse(self.testmodule.check_valid(name))
276
277 def test_check_valid_with_list_restriction(self):
278 """ Test_in_module.check_valid should work with list in restrict """
279
280 expression = ['test.*','iolibs']
281 self.testmodule.restrict_to(expression)
282 name = 'test_search'
283 self.assertTrue(self.testmodule.check_valid(name))
284 name = 'iolibs'
285 self.assertTrue(self.testmodule.check_valid(name))
286 name = 'data'
287 self.assertFalse(self.testmodule.check_valid(name))
288
289 def test_status_file_on_file(self):
290 """ Test_in_module.status_file recognizes file """
291
292 status=self.testmodule.status_file(self.test_path+\
293 'test_test_manager.py')
294 self.assertEqual(status,'file')
295 status=self.testmodule.status_file(self.test_path+\
296 '../../../README')
297 self.assertFalse(status)
298 status=self.testmodule.status_file(self.test_path+\
299 '__init__.py')
300 self.assertFalse(status)
301 status=self.testmodule.status_file(self.test_path+\
302 '__init__.pyc')
303 self.assertFalse(status)
304
305
306 def test_status_file_on_dir(self):
307 """ Test_in_module.status_file doesn't detect non module dir """
308
309 status=self.testmodule.status_file(self.test_path+\
310 '../bin')
311 self.assertEqual(status,'module')
312
313 status=self.testmodule.status_file(self.test_path+\
314 '../../../apidoc')
315 self.assertFalse(status)
316
317
318 def test_passin_pyformat(self):
319 """ convert from linux position format to python include """
320
321 input={'test.py':'test', 'Source/test.py':'Source.test', \
322 'Source//test.py':'Source.test', './test.py':'test'}
323 for key,value in input.items():
324 self.assertEqual( \
325 self.testmodule.passin_pyformat(key),
326 value)
327
328 input=['test','../Source.py','/home/data.py',1,str]
329 for data in input:
330 self.assertRaises(test_manager.Test_in_module.ERRORTestManager
331 ,self.testmodule.passin_pyformat, data)
332
333
334 def test_add_to_possibility(self):
335 """ convert name in different matching possibility """
336 # the sanity of the output is checked by check_valid test,
337 # this test the format of the output
338
339 output=self.testmodule.format_possibility('./bin/test.py')
340 for name in output:
341 self.assertEqual(output.count(name),1)
342 self.assert_(len(output)>3)
343
344 output=self.testmodule.format_possibility('bin.test')
345 for name in output:
346 self.assertEqual(output.count(name),1)
347 self.assert_(len(output)>1)
348
349if __name__ == "__main__":
350 mytest = unittest.TestSuite()
351 suite = unittest.TestLoader()
352 suite=suite.loadTestsFromTestCase(Unittest_on_TestinModule)
353 mytest.addTest(suite)
354 unittest.TextTestRunner(verbosity=2).run(mytest)
355
356
357# unittest.main()

Subscribers

People subscribed via source and target branches