michael@0: #!/usr/bin/env python michael@0: # michael@0: # This Source Code Form is subject to the terms of the Mozilla Public michael@0: # License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: # You can obtain one at http://mozilla.org/MPL/2.0/. michael@0: # michael@0: michael@0: import os michael@0: import sys michael@0: import tempfile michael@0: michael@0: from subprocess import call michael@0: from shutil import rmtree michael@0: michael@0: import logging michael@0: import unittest michael@0: michael@0: michael@0: def banner(): michael@0: """ michael@0: Display interpreter and system info for the test env michael@0: """ michael@0: print '*' * 75 michael@0: cmd = os.path.basename(__file__) michael@0: print "%s: python version is %s" % (cmd, sys.version) michael@0: print '*' * 75 michael@0: michael@0: michael@0: def myopts(vals): michael@0: """ michael@0: Storage for extra command line args passed. michael@0: michael@0: Returns: michael@0: hash - argparse::Namespace object values michael@0: """ michael@0: michael@0: if not hasattr(myopts, 'vals'): michael@0: if 'argparse' in sys.modules: michael@0: tmp = { } # key existance enables unittest module debug michael@0: else: michael@0: tmp = { 'debug': False, 'verbose': False } michael@0: michael@0: for k in dir(vals): michael@0: if k[0:1] == '_': michael@0: continue michael@0: tmp[k] = getattr(vals, k) michael@0: myopts.vals = tmp michael@0: michael@0: return myopts.vals michael@0: michael@0: michael@0: def path2posix(src): michael@0: """ michael@0: Normalize directory path syntax michael@0: michael@0: Keyword arguments: michael@0: src - path to normalize michael@0: michael@0: Returns: michael@0: scalar - a file path with drive separators and windows slashes removed michael@0: michael@0: Todo: michael@0: move to {build,config,tools,toolkit}/python for use in a library michael@0: """ michael@0: michael@0: ## (drive, tail) = os.path.splitdrive(src) michael@0: ## Support path testing on all platforms michael@0: drive = '' michael@0: winpath = src.find(':') michael@0: if -1 != winpath and 10 > winpath: michael@0: (drive, tail) = src.split(':', 1) michael@0: michael@0: if drive: michael@0: todo = [ '', drive.rstrip(':').lstrip('/').lstrip('\\') ] michael@0: todo.extend( tail.lstrip('/').lstrip('\\').split('\\') ) # c:\a => [a] michael@0: else: # os.name == 'posix' michael@0: todo = src.split('\\') michael@0: michael@0: dst = '/'.join(todo) michael@0: return dst michael@0: michael@0: michael@0: def checkMkdir(work, debug=False): michael@0: """ michael@0: Verify arg permutations for directory mutex creation. michael@0: michael@0: Keyword arguments: michael@0: None michael@0: michael@0: Returns: michael@0: Exception on error michael@0: michael@0: Note: michael@0: Exception() rather than self.assertTrue() is used in this test michael@0: function to enable scatch cleanup on test exit/failure conditions. michael@0: Not guaranteed by python closures on early exit. michael@0: """ michael@0: michael@0: logging.debug("Testing: checkMkdir") michael@0: michael@0: # On Windows, don't convert paths to POSIX michael@0: skipposix = sys.platform == "win32" michael@0: if skipposix: michael@0: path = os.path.abspath(__file__) michael@0: dirname_fun = os.path.dirname michael@0: else: michael@0: path = path2posix(os.path.abspath(__file__)) michael@0: import posixpath michael@0: dirname_fun = posixpath.dirname michael@0: michael@0: src = dirname_fun(path) michael@0: # root is 5 directories up from path michael@0: root = reduce(lambda x, _: dirname_fun(x), xrange(5), path) michael@0: michael@0: rootP = path2posix(root) michael@0: srcP = path2posix(src) michael@0: workP = path2posix(work) michael@0: michael@0: # C:\foo -vs- /c/foo michael@0: # [0] command paths use /c/foo michael@0: # [1] os.path.exists() on mingw() requires C:\ michael@0: paths = [ michael@0: "mkdir_bycall", # function generated michael@0: "mkdir_bydep", # explicit dependency michael@0: "mkdir_bygen", # by GENERATED_DIRS macro michael@0: ] michael@0: michael@0: ## Use make from the parent "make check" call when available michael@0: cmd = { 'make': 'make' } michael@0: shell0 = os.environ.get('MAKE') michael@0: if shell0: michael@0: shell = os.path.splitext(shell0)[0] # strip: .exe, .py michael@0: if -1 != shell.find('make'): michael@0: print "MAKE COMMAND FOUND: %s" % (shell0) michael@0: cmd['make'] = shell0 if skipposix else path2posix(shell0) michael@0: michael@0: args = [] michael@0: args.append('%s' % (cmd['make'])) michael@0: args.append('-C %s' % (work if skipposix else workP)) michael@0: args.append("-f %s/testor.tmpl" % (src if skipposix else srcP)) michael@0: args.append('topsrcdir=%s' % (root if skipposix else rootP)) michael@0: args.append('deps_mkdir_bycall=%s' % paths[0]) michael@0: args.append('deps_mkdir_bydep=%s' % paths[1]) michael@0: args.append('deps_mkdir_bygen=%s' % paths[2]) michael@0: args.append('checkup') # target michael@0: michael@0: # Call will fail on mingw with output redirected ?!? michael@0: if debug: michael@0: pass michael@0: if False: # if not debug: michael@0: args.append('>/dev/null') michael@0: michael@0: cmd = '%s' % (' '.join(args)) michael@0: logging.debug("Running: %s" % (cmd)) michael@0: rc = call(cmd, shell=True) michael@0: if rc: michael@0: raise Exception("make failed ($?=%s): cmd=%s" % (rc, cmd)) michael@0: michael@0: for i in paths: michael@0: path = os.path.join(work, i) michael@0: logging.debug("Did testing mkdir(%s) succeed?" % (path)) michael@0: if not os.path.exists(path): michael@0: raise Exception("Test path %s does not exist" % (path)) michael@0: michael@0: michael@0: def parseargs(): michael@0: """ michael@0: Support additional command line arguments for testing michael@0: michael@0: Returns: michael@0: hash - arguments of interested parsed from the command line michael@0: """ michael@0: michael@0: opts = None michael@0: try: michael@0: import argparse2 michael@0: parser = argparse.ArgumentParser() michael@0: parser.add_argument('--debug', michael@0: action="store_true", michael@0: default=False, michael@0: help='Enable debug mode') michael@0: # Cannot overload verbose, Verbose: False enables debugging michael@0: parser.add_argument('--verbose', michael@0: action="store_true", michael@0: default=False, michael@0: help='Enable verbose mode') michael@0: parser.add_argument('unittest_args', michael@0: nargs='*' michael@0: # help='Slurp/pass remaining args to unittest' michael@0: ) michael@0: opts = parser.parse_args() michael@0: michael@0: except ImportError: michael@0: pass michael@0: michael@0: return opts michael@0: michael@0: michael@0: class TestMakeLogic(unittest.TestCase): michael@0: """ michael@0: Test suite used to validate makefile library rules and macros michael@0: """ michael@0: michael@0: def setUp(self): michael@0: opts = myopts(None) # NameSpace object not hash michael@0: self.debug = opts['debug'] michael@0: self.verbose = opts['verbose'] michael@0: michael@0: if self.debug: michael@0: logging.basicConfig(level=logging.DEBUG) michael@0: michael@0: if self.verbose: michael@0: print michael@0: print "ENVIRONMENT DUMP:" michael@0: print '=' * 75 michael@0: for k,v in os.environ.items(): michael@0: print "env{%s} => %s" % (k, v) michael@0: print michael@0: michael@0: michael@0: def test_path2posix(self): michael@0: michael@0: todo = { michael@0: '/dev/null' : '/dev/null', michael@0: 'A:\\a\\b\\c' : '/A/a/b/c', michael@0: 'B:/x/y' : '/B/x/y', michael@0: 'C:/x\\y/z' : '/C/x/y/z', michael@0: '//FOO/bar/tans': '//FOO/bar/tans', michael@0: '//X\\a/b\\c/d' : '//X/a/b/c/d', michael@0: '\\c:mozilla\\sandbox': '/c/mozilla/sandbox', michael@0: } michael@0: michael@0: for val,exp in todo.items(): michael@0: found = path2posix(val) michael@0: tst = "posix2path(%s): %s != %s)" % (val, exp, found) michael@0: self.assertEqual(exp, found, "%s: invalid path detected" % (tst)) michael@0: michael@0: michael@0: def test_mkdir(self): michael@0: """ michael@0: Verify directory creation rules and macros michael@0: """ michael@0: michael@0: failed = True michael@0: michael@0: # Exception handling is used to cleanup scratch space on error michael@0: try: michael@0: work = tempfile.mkdtemp() michael@0: checkMkdir(work, self.debug) michael@0: failed = False michael@0: finally: michael@0: if os.path.exists(work): michael@0: rmtree(work) michael@0: michael@0: self.assertFalse(failed, "Unit test failure detected") michael@0: michael@0: michael@0: if __name__ == '__main__': michael@0: banner() michael@0: opts = parseargs() michael@0: myopts(opts) michael@0: michael@0: if opts: michael@0: if hasattr(opts, 'unittest_args'): michael@0: sys.argv[1:] = opts.unittest_args michael@0: else: michael@0: sys.argv[1:] = [] michael@0: michael@0: unittest.main()