-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsetup_tests.py
161 lines (153 loc) · 6.9 KB
/
setup_tests.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#*****************************************************************************
#
# Copyright (c) 2000 - 2012, Lawrence Livermore National Security, LLC
# Produced at the Lawrence Livermore National Laboratory
# LLNL-CODE-442911
# All rights reserved.
#
# This file is part of VisIt. For details, see https://visit.llnl.gov/. The
# full copyright notice is contained in the file COPYRIGHT located at the root
# of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# - Redistributions of source code must retain the above copyright notice,
# this list of conditions and the disclaimer below.
# - Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the disclaimer (as noted below) in the
# documentation and/or other materials provided with the distribution.
# - Neither the name of the LLNS/LLNL nor the names of its contributors may
# be used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL SECURITY,
# LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
# DAMAGE.
#*****************************************************************************
"""
file: setup_tests.py
author: Cyrus Harrison <[email protected]>
created: 10/14/2010
description:
Provides 'ExecuteTests' a distutils command class that automatically
collects and launches unittest test cases from scripts in the 'tests'
subdir.
I created this simple one file module b/c nose & setuptools are not always
available/installable on all of the systems I develop python modules on.
To use this class in a distutils setup project:
A) Create test scripts in the subdir 'tests'
B) In your setup.py:
#import the test module
import setup_tests
# Add the custom command to the 'cmdclass' dictonary in your setup call:
setup( ...
cmdclass = { 'test': setup_tests.ExecuteTests})
C) Invoke 'python setup.py test' to run tests
"""
import os
import glob
import sys
from distutils.core import Command
from unittest import TextTestRunner, TestLoader, TestSuite, TestCase
class ExecuteTests(Command):
description = "locate and execute scripts containing unit tests."
user_options = [ ('verbose', None, "Verbose output"),
('tests-dir=', None, "Directory containg tests"),
('filter=',None,"Filter used to select which tests to execute")]
boolean_options = ['verbose']
negative_opt = {'quiet' : 'verbose'}
def initialize_options(self):
self.verbose = 1
self.tests_dir = "tests"
self.filter = None
def finalize_options(self):
self.tests_dir = os.path.join(os.getcwd(),self.tests_dir)
def run(self):
"""
Finds and executes unit tests in the 'tests' subdir.
Because TestLoader imports the tests as a module this method
automatically creates/updates the 'tests/__init__.py' to
import all python scripts in the 'tests' subdir.
"""
self.run_command('build')
sys.path.insert(0,os.path.join(os.getcwd(),"build","lib"))
self.tests = []
# make sure the 'tests' subdir actually exists.
if not os.path.isdir(self.tests_dir):
print "ExecuteTests: <Error> 'tests' subdir not found!"
else:
self.find_tests()
self.gen_tests_init()
# create a test suite.
tests = TestLoader().loadTestsFromNames([t[0] for t in self.tests])
if not self.filter is None:
tests = self.filter_tests(tests)
# run the test suite if it actually contains test cases.
run_verbosity = 2
if self.verbose == 0:
run_verbosity = 0
if tests.countTestCases() > 0:
runner = TextTestRunner(verbosity=run_verbosity)
runner.run(tests)
else:
print "ExecuteTests: <Warning> No test cases found!"
sys.path.pop(0)
def find_tests(self):
"""
Helper called by 'run' to find python scripts in the 'tests' subdir.
"""
for f in glob.glob(os.path.join(self.tests_dir,"*.py")):
if not f.endswith('__init__.py'):
test = os.path.splitext(os.path.basename(f))[0]
test = '.'.join(['tests',test])
self.tests.append( (test,f))
if len(self.tests) > 0 and self.verbose:
print "Detected Test Scripts:"
for t in self.tests:
print " %s @ %s)" % (t[0],t[1])
def filter_tests(self,tests):
"""
Filters detected tests according to pattern passed to
the "--filter=" argument.
"""
return self.__filter_test_suite(tests,self.filter)
def __filter_test_suite(self,ts,filter):
"""
Recursively filters tests from a test suite object according
to the passed filter.
"""
res = TestSuite()
for t in ts:
if isinstance(t,TestSuite):
res.addTest(self.__filter_test_suite(t,filter))
elif issubclass(type(t),TestCase):
if t.id().count(filter) !=0:
res.addTest(t)
return res
def gen_tests_init(self):
"""
Helper called by 'run' to update the 'tests/__init__.py' file.
Note: If no python scripts exist in the 'tests' subdir
'tests/__init__.py' will be removed.
"""
tests_init = os.path.join(self.tests_dir,"__init__.py")
if len(self.tests) > 0:
f = open(tests_init,"w")
f.write("# module header auto generated by "
"setup_tests.ExecuteTests\n")
# import each test script as part of the 'tests' module.
for t in self.tests:
f.write("import %s\n" % t[0])
elif os.path.exists(tests_init):
# remove the module init file if no test scripts are found.
os.remove(tests_init)