|
1 #!/usr/bin/env python |
|
2 # |
|
3 # This Source Code Form is subject to the terms of the Mozilla Public |
|
4 # License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
5 # You can obtain one at http://mozilla.org/MPL/2.0/. |
|
6 # |
|
7 |
|
8 import os |
|
9 import sys |
|
10 import tempfile |
|
11 |
|
12 from subprocess import call |
|
13 from shutil import rmtree |
|
14 |
|
15 import logging |
|
16 import unittest |
|
17 |
|
18 |
|
19 def banner(): |
|
20 """ |
|
21 Display interpreter and system info for the test env |
|
22 """ |
|
23 print '*' * 75 |
|
24 cmd = os.path.basename(__file__) |
|
25 print "%s: python version is %s" % (cmd, sys.version) |
|
26 print '*' * 75 |
|
27 |
|
28 |
|
29 def myopts(vals): |
|
30 """ |
|
31 Storage for extra command line args passed. |
|
32 |
|
33 Returns: |
|
34 hash - argparse::Namespace object values |
|
35 """ |
|
36 |
|
37 if not hasattr(myopts, 'vals'): |
|
38 if 'argparse' in sys.modules: |
|
39 tmp = { } # key existance enables unittest module debug |
|
40 else: |
|
41 tmp = { 'debug': False, 'verbose': False } |
|
42 |
|
43 for k in dir(vals): |
|
44 if k[0:1] == '_': |
|
45 continue |
|
46 tmp[k] = getattr(vals, k) |
|
47 myopts.vals = tmp |
|
48 |
|
49 return myopts.vals |
|
50 |
|
51 |
|
52 def path2posix(src): |
|
53 """ |
|
54 Normalize directory path syntax |
|
55 |
|
56 Keyword arguments: |
|
57 src - path to normalize |
|
58 |
|
59 Returns: |
|
60 scalar - a file path with drive separators and windows slashes removed |
|
61 |
|
62 Todo: |
|
63 move to {build,config,tools,toolkit}/python for use in a library |
|
64 """ |
|
65 |
|
66 ## (drive, tail) = os.path.splitdrive(src) |
|
67 ## Support path testing on all platforms |
|
68 drive = '' |
|
69 winpath = src.find(':') |
|
70 if -1 != winpath and 10 > winpath: |
|
71 (drive, tail) = src.split(':', 1) |
|
72 |
|
73 if drive: |
|
74 todo = [ '', drive.rstrip(':').lstrip('/').lstrip('\\') ] |
|
75 todo.extend( tail.lstrip('/').lstrip('\\').split('\\') ) # c:\a => [a] |
|
76 else: # os.name == 'posix' |
|
77 todo = src.split('\\') |
|
78 |
|
79 dst = '/'.join(todo) |
|
80 return dst |
|
81 |
|
82 |
|
83 def checkMkdir(work, debug=False): |
|
84 """ |
|
85 Verify arg permutations for directory mutex creation. |
|
86 |
|
87 Keyword arguments: |
|
88 None |
|
89 |
|
90 Returns: |
|
91 Exception on error |
|
92 |
|
93 Note: |
|
94 Exception() rather than self.assertTrue() is used in this test |
|
95 function to enable scatch cleanup on test exit/failure conditions. |
|
96 Not guaranteed by python closures on early exit. |
|
97 """ |
|
98 |
|
99 logging.debug("Testing: checkMkdir") |
|
100 |
|
101 # On Windows, don't convert paths to POSIX |
|
102 skipposix = sys.platform == "win32" |
|
103 if skipposix: |
|
104 path = os.path.abspath(__file__) |
|
105 dirname_fun = os.path.dirname |
|
106 else: |
|
107 path = path2posix(os.path.abspath(__file__)) |
|
108 import posixpath |
|
109 dirname_fun = posixpath.dirname |
|
110 |
|
111 src = dirname_fun(path) |
|
112 # root is 5 directories up from path |
|
113 root = reduce(lambda x, _: dirname_fun(x), xrange(5), path) |
|
114 |
|
115 rootP = path2posix(root) |
|
116 srcP = path2posix(src) |
|
117 workP = path2posix(work) |
|
118 |
|
119 # C:\foo -vs- /c/foo |
|
120 # [0] command paths use /c/foo |
|
121 # [1] os.path.exists() on mingw() requires C:\ |
|
122 paths = [ |
|
123 "mkdir_bycall", # function generated |
|
124 "mkdir_bydep", # explicit dependency |
|
125 "mkdir_bygen", # by GENERATED_DIRS macro |
|
126 ] |
|
127 |
|
128 ## Use make from the parent "make check" call when available |
|
129 cmd = { 'make': 'make' } |
|
130 shell0 = os.environ.get('MAKE') |
|
131 if shell0: |
|
132 shell = os.path.splitext(shell0)[0] # strip: .exe, .py |
|
133 if -1 != shell.find('make'): |
|
134 print "MAKE COMMAND FOUND: %s" % (shell0) |
|
135 cmd['make'] = shell0 if skipposix else path2posix(shell0) |
|
136 |
|
137 args = [] |
|
138 args.append('%s' % (cmd['make'])) |
|
139 args.append('-C %s' % (work if skipposix else workP)) |
|
140 args.append("-f %s/testor.tmpl" % (src if skipposix else srcP)) |
|
141 args.append('topsrcdir=%s' % (root if skipposix else rootP)) |
|
142 args.append('deps_mkdir_bycall=%s' % paths[0]) |
|
143 args.append('deps_mkdir_bydep=%s' % paths[1]) |
|
144 args.append('deps_mkdir_bygen=%s' % paths[2]) |
|
145 args.append('checkup') # target |
|
146 |
|
147 # Call will fail on mingw with output redirected ?!? |
|
148 if debug: |
|
149 pass |
|
150 if False: # if not debug: |
|
151 args.append('>/dev/null') |
|
152 |
|
153 cmd = '%s' % (' '.join(args)) |
|
154 logging.debug("Running: %s" % (cmd)) |
|
155 rc = call(cmd, shell=True) |
|
156 if rc: |
|
157 raise Exception("make failed ($?=%s): cmd=%s" % (rc, cmd)) |
|
158 |
|
159 for i in paths: |
|
160 path = os.path.join(work, i) |
|
161 logging.debug("Did testing mkdir(%s) succeed?" % (path)) |
|
162 if not os.path.exists(path): |
|
163 raise Exception("Test path %s does not exist" % (path)) |
|
164 |
|
165 |
|
166 def parseargs(): |
|
167 """ |
|
168 Support additional command line arguments for testing |
|
169 |
|
170 Returns: |
|
171 hash - arguments of interested parsed from the command line |
|
172 """ |
|
173 |
|
174 opts = None |
|
175 try: |
|
176 import argparse2 |
|
177 parser = argparse.ArgumentParser() |
|
178 parser.add_argument('--debug', |
|
179 action="store_true", |
|
180 default=False, |
|
181 help='Enable debug mode') |
|
182 # Cannot overload verbose, Verbose: False enables debugging |
|
183 parser.add_argument('--verbose', |
|
184 action="store_true", |
|
185 default=False, |
|
186 help='Enable verbose mode') |
|
187 parser.add_argument('unittest_args', |
|
188 nargs='*' |
|
189 # help='Slurp/pass remaining args to unittest' |
|
190 ) |
|
191 opts = parser.parse_args() |
|
192 |
|
193 except ImportError: |
|
194 pass |
|
195 |
|
196 return opts |
|
197 |
|
198 |
|
199 class TestMakeLogic(unittest.TestCase): |
|
200 """ |
|
201 Test suite used to validate makefile library rules and macros |
|
202 """ |
|
203 |
|
204 def setUp(self): |
|
205 opts = myopts(None) # NameSpace object not hash |
|
206 self.debug = opts['debug'] |
|
207 self.verbose = opts['verbose'] |
|
208 |
|
209 if self.debug: |
|
210 logging.basicConfig(level=logging.DEBUG) |
|
211 |
|
212 if self.verbose: |
|
213 print |
|
214 print "ENVIRONMENT DUMP:" |
|
215 print '=' * 75 |
|
216 for k,v in os.environ.items(): |
|
217 print "env{%s} => %s" % (k, v) |
|
218 print |
|
219 |
|
220 |
|
221 def test_path2posix(self): |
|
222 |
|
223 todo = { |
|
224 '/dev/null' : '/dev/null', |
|
225 'A:\\a\\b\\c' : '/A/a/b/c', |
|
226 'B:/x/y' : '/B/x/y', |
|
227 'C:/x\\y/z' : '/C/x/y/z', |
|
228 '//FOO/bar/tans': '//FOO/bar/tans', |
|
229 '//X\\a/b\\c/d' : '//X/a/b/c/d', |
|
230 '\\c:mozilla\\sandbox': '/c/mozilla/sandbox', |
|
231 } |
|
232 |
|
233 for val,exp in todo.items(): |
|
234 found = path2posix(val) |
|
235 tst = "posix2path(%s): %s != %s)" % (val, exp, found) |
|
236 self.assertEqual(exp, found, "%s: invalid path detected" % (tst)) |
|
237 |
|
238 |
|
239 def test_mkdir(self): |
|
240 """ |
|
241 Verify directory creation rules and macros |
|
242 """ |
|
243 |
|
244 failed = True |
|
245 |
|
246 # Exception handling is used to cleanup scratch space on error |
|
247 try: |
|
248 work = tempfile.mkdtemp() |
|
249 checkMkdir(work, self.debug) |
|
250 failed = False |
|
251 finally: |
|
252 if os.path.exists(work): |
|
253 rmtree(work) |
|
254 |
|
255 self.assertFalse(failed, "Unit test failure detected") |
|
256 |
|
257 |
|
258 if __name__ == '__main__': |
|
259 banner() |
|
260 opts = parseargs() |
|
261 myopts(opts) |
|
262 |
|
263 if opts: |
|
264 if hasattr(opts, 'unittest_args'): |
|
265 sys.argv[1:] = opts.unittest_args |
|
266 else: |
|
267 sys.argv[1:] = [] |
|
268 |
|
269 unittest.main() |