From efdf3fdbcd2f7654cb8d1209a8b040914437bacd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Tue, 23 Jul 2019 16:54:06 +0200 Subject: New upstream version 3.1.0 --- testing/framework/README.txt | 2 +- testing/framework/SConscript | 13 +- testing/framework/TestCmd.py | 165 ++++++--- testing/framework/TestCmdTests.py | 543 ++++++++++++++--------------- testing/framework/TestRuntest.py | 4 +- testing/framework/TestSCons.py | 130 ++++--- testing/framework/TestSConsMSVS.py | 678 ++++++++---------------------------- testing/framework/TestSCons_time.py | 5 +- testing/framework/TestSConsign.py | 2 +- 9 files changed, 641 insertions(+), 901 deletions(-) (limited to 'testing/framework') diff --git a/testing/framework/README.txt b/testing/framework/README.txt index 0e0f2bb..817cb3f 100644 --- a/testing/framework/README.txt +++ b/testing/framework/README.txt @@ -47,4 +47,4 @@ the pieces here are local to SCons. Test infrastructure for the sconsign.py script. Copyright (c) 2001 - 2019 The SCons Foundation -testing/framework/README.txt 103260fce95bf5db1c35fb2371983087d85dd611 2019-07-13 18:25:30 bdbaddog +testing/framework/README.txt e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan diff --git a/testing/framework/SConscript b/testing/framework/SConscript index 535f187..f79a254 100644 --- a/testing/framework/SConscript +++ b/testing/framework/SConscript @@ -41,12 +41,13 @@ files = [ def copy(target, source, env): t = str(target[0]) s = str(source[0]) - c = open(s, 'r').read() - # Note: We construct the __ VERSION __ substitution string at - # run-time so it doesn't get replaced when this file gets copied - # into the tree for packaging. - c = c.replace('__' + 'VERSION' + '__', env['VERSION']) - open(t, 'w').write(c) + with open(s, 'r') as i, open(t, 'w') as o: + c = i.read() + # Note: We construct the __ VERSION __ substitution string at + # run-time so it doesn't get replaced when this file gets copied + # into the tree for packaging. + c = c.replace('__' + 'VERSION' + '__', env['VERSION']) + o.write(c) for file in files: # Guarantee that real copies of these files always exist in diff --git a/testing/framework/TestCmd.py b/testing/framework/TestCmd.py index a6a8045..81e03f3 100644 --- a/testing/framework/TestCmd.py +++ b/testing/framework/TestCmd.py @@ -366,13 +366,11 @@ else: def is_String(e): return isinstance(e, (str, unicode, UserString)) -tempfile.template = 'testcmd.' +testprefix = 'testcmd.' if os.name in ('posix', 'nt'): - tempfile.template = 'testcmd.' + str(os.getpid()) + '.' -else: - tempfile.template = 'testcmd.' + testprefix += "%s." % str(os.getpid()) -re_space = re.compile('\s') +re_space = re.compile(r'\s') def _caller(tblist, skip): @@ -470,6 +468,14 @@ def pass_test(self=None, condition=1, function=None): def match_exact(lines=None, matches=None, newline=os.sep): """ + Match function using exact match. + + :param lines: data lines + :type lines: str or list[str] + :param matches: expected lines to match + :type matches: str or list[str] + :param newline: line separator + :returns: an object (1) on match, else None, like re.match """ if isinstance(lines, bytes) or bytes is str: @@ -480,30 +486,51 @@ def match_exact(lines=None, matches=None, newline=os.sep): if not is_List(matches): matches = matches.split(newline) if len(lines) != len(matches): - return - for i in range(len(lines)): - if lines[i] != matches[i]: - return + return None + for line, match in zip(lines, matches): + if line != match: + return None return 1 def match_caseinsensitive(lines=None, matches=None): """ + Match function using case-insensitive matching. + + Only a simplistic comparison is done, based on lowercasing the + strings. This has plenty of holes for unicode data using + non-English languages. + + TODO: casefold() is better than lower() if we don't need Py2 support. + + :param lines: data lines + :type lines: str or list[str] + :param matches: expected lines to match + :type matches: str or list[str] + :returns: True or False + :returns: an object (1) on match, else None, like re.match """ if not is_List(lines): lines = lines.split("\n") if not is_List(matches): matches = matches.split("\n") if len(lines) != len(matches): - return - for i in range(len(lines)): - if lines[i].lower() != matches[i].lower(): - return + return None + for line, match in zip(lines, matches): + if line.lower() != match.lower(): + return None return 1 def match_re(lines=None, res=None): """ + Match function using line-by-line regular expression match. + + :param lines: data lines + :type lines: str or list[str] + :param res: regular expression(s) for matching + :type res: str or list[str] + :returns: an object (1) on match, else None, like re.match """ if not is_List(lines): # CRs mess up matching (Windows) so split carefully @@ -512,29 +539,39 @@ def match_re(lines=None, res=None): res = res.split("\n") if len(lines) != len(res): print("match_re: expected %d lines, found %d" % (len(res), len(lines))) - return - for i in range(len(lines)): - s = "^" + res[i] + "$" + return None + for i, (line, regex) in enumerate(zip(lines, res)): + s = r"^{}$".format(regex) try: expr = re.compile(s) except re.error as e: msg = "Regular expression error in %s: %s" raise re.error(msg % (repr(s), e.args[0])) - if not expr.search(lines[i]): - print("match_re: mismatch at line %d:\n search re='%s'\n line='%s'" % ( - i, s, lines[i])) - return + if not expr.search(line): + miss_tmpl = "match_re: mismatch at line {}:\n search re='{}'\n line='{}'" + print(miss_tmpl.format(i, s, line)) + return None return 1 def match_re_dotall(lines=None, res=None): """ + Match function using regular expression match. + + Unlike match_re, the arguments are converted to strings (if necessary) + and must match exactly. + + :param lines: data lines + :type lines: str or list[str] + :param res: regular expression(s) for matching + :type res: str or list[str] + :returns: a match object, or None as for re.match """ if not isinstance(lines, str): lines = "\n".join(lines) if not isinstance(res, str): res = "\n".join(res) - s = "^" + res + "$" + s = r"^{}$".format(res) try: expr = re.compile(s, re.DOTALL) except re.error as e: @@ -544,11 +581,32 @@ def match_re_dotall(lines=None, res=None): def simple_diff(a, b, fromfile='', tofile='', - fromfiledate='', tofiledate='', n=3, lineterm='\n'): - """ - A function with the same calling signature as difflib.context_diff - (diff -c) and difflib.unified_diff (diff -u) but which prints - output like the simple, unadorned 'diff" command. + fromfiledate='', tofiledate='', n=0, lineterm=''): + r""" + Compare two sequences of lines; generate the delta as a simple diff. + + Similar to difflib.context_diff and difflib.unified_diff but + output is like from the 'diff" command without arguments. The function + keeps the same signature as the difflib ones so they will be + interchangeable, but except for lineterm, the arguments beyond the + two sequences are ignored in this version. By default, the + diff is not created with trailing newlines, set the lineterm + argument to '\n' to do so. + + :raises re.error: if a regex fails to compile + + Example: + + >>> print(''.join(simple_diff('one\ntwo\nthree\nfour\n'.splitlines(True), + ... 'zero\none\ntree\nfour\n'.splitlines(True), lineterm='\n'))) + 0a1 + > zero + 2,3c3 + < two + < three + --- + > tree + """ a = [to_str(q) for q in a] b = [to_str(q) for q in b] @@ -556,25 +614,30 @@ def simple_diff(a, b, fromfile='', tofile='', def comma(x1, x2): return x1 + 1 == x2 and str(x2) or '%s,%s' % (x1 + 1, x2) - result = [] + for op, a1, a2, b1, b2 in sm.get_opcodes(): if op == 'delete': - result.append("%sd%d" % (comma(a1, a2), b1)) - result.extend(['< ' + l for l in a[a1:a2]]) + yield "{}d{}{}".format(comma(a1, a2), b1, lineterm) + for l in a[a1:a2]: + yield '< ' + l elif op == 'insert': - result.append("%da%s" % (a1, comma(b1, b2))) - result.extend(['> ' + l for l in b[b1:b2]]) + yield "{}a{}{}".format(a1, comma(b1, b2), lineterm) + for l in b[b1:b2]: + yield '> ' + l elif op == 'replace': - result.append("%sc%s" % (comma(a1, a2), comma(b1, b2))) - result.extend(['< ' + l for l in a[a1:a2]]) - result.append('---') - result.extend(['> ' + l for l in b[b1:b2]]) - return result + yield "{}c{}{}".format(comma(a1, a2), comma(b1, b2), lineterm) + for l in a[a1:a2]: + yield '< ' + l + yield '---{}'.format(lineterm) + for l in b[b1:b2]: + yield '> ' + l def diff_re(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n'): """ + Compare a and b (lists of strings) where a are regexes. + A simple "diff" of two sets of lines when the expected lines are regular expressions. This is a really dumb thing that just compares each line in turn, so it doesn't look for @@ -587,9 +650,8 @@ def diff_re(a, b, fromfile='', tofile='', a = a + [''] * (-diff) elif diff > 0: b = b + [''] * diff - i = 0 - for aline, bline in zip(a, b): - s = "^" + aline + "$" + for i, (aline, bline) in enumerate(zip(a, b)): + s = r"^{}$".format(aline) try: expr = re.compile(s) except re.error as e: @@ -600,7 +662,6 @@ def diff_re(a, b, fromfile='', tofile='', result.append('< ' + repr(a[i])) result.append('---') result.append('> ' + repr(b[i])) - i = i + 1 return result @@ -974,6 +1035,12 @@ class TestCmd(object): self.subdir(subdir) self.fixture_dirs = [] + try: + self.fixture_dirs = (os.environ['FIXTURE_DIRS']).split(os.pathsep) + except KeyError: + pass + + def __del__(self): self.cleanup() @@ -1026,7 +1093,7 @@ class TestCmd(object): condition = self.condition if self._preserve[condition]: for dir in self._dirlist: - print(u"Preserved directory " + dir + "\n") + print(u"Preserved directory " + dir) else: list = self._dirlist[:] list.reverse() @@ -1242,6 +1309,7 @@ class TestCmd(object): def read(self, file, mode='rb', newline=None): """Reads and returns the contents of the specified file name. + The file name may be a list, in which case the elements are concatenated with the os.path.join() method. The file is assumed to be under the temporary working directory unless it @@ -1261,6 +1329,7 @@ class TestCmd(object): def rmdir(self, dir): """Removes the specified dir name. + The dir name may be a list, in which case the elements are concatenated with the os.path.join() method. The dir is assumed to be under the temporary working directory unless it @@ -1302,6 +1371,7 @@ class TestCmd(object): """Copies the contents of the specified folder srcdir from the directory of the called script, to the current working directory. + The srcdir name may be a list, in which case the elements are concatenated with the os.path.join() method. The dstdir is assumed to be under the temporary working directory, it gets @@ -1343,6 +1413,7 @@ class TestCmd(object): def file_fixture(self, srcfile, dstfile=None): """Copies the file srcfile from the directory of the called script, to the current working directory. + The dstfile is assumed to be under the temporary working directory unless it is an absolute path name. If dstfile is specified its target directory gets created @@ -1439,6 +1510,7 @@ class TestCmd(object): def fix_binary_stream(stream): """ Handle stdout/stderr from popen when we specify universal_newlines = False. + This will read from the pipes in binary mode, not decode the output, and not convert line endings to \n. We do this because in py3 (3.5) with universal_newlines=True, it will @@ -1455,7 +1527,7 @@ class TestCmd(object): return stream # TODO: Run full tests on both platforms and see if this fixes failures # It seems that py3.6 still sets text mode if you set encoding. - elif sys.version_info[0] == 3:# TODO and sys.version_info[1] < 6: + elif sys.version_info[0] == 3: # TODO and sys.version_info[1] < 6: stream = stream.decode('utf-8') stream = stream.replace('\r\n', '\n') elif sys.version_info[0] == 2: @@ -1629,7 +1701,7 @@ class TestCmd(object): try: os.mkdir(new) except OSError as e: - print("Got error :%s"%e) + print("Got error creating dir: %s :%s" % (sub, e)) pass else: count = count + 1 @@ -1662,10 +1734,11 @@ class TestCmd(object): """ if path is None: try: - path = tempfile.mktemp(prefix=tempfile.template) + path = tempfile.mkdtemp(prefix=testprefix) except TypeError: - path = tempfile.mktemp() - os.mkdir(path) + path = tempfile.mkdtemp() + else: + os.mkdir(path) # Symlinks in the path will report things # differently from os.getcwd(), so chdir there diff --git a/testing/framework/TestCmdTests.py b/testing/framework/TestCmdTests.py index b9226fd..ef76228 100644 --- a/testing/framework/TestCmdTests.py +++ b/testing/framework/TestCmdTests.py @@ -26,13 +26,22 @@ import os import shutil import signal import stat -from StringIO import StringIO +try: + from cStringIO import StringIO +except ImportError: + from io import StringIO +from contextlib import closing import sys import tempfile import time import types import unittest -from UserList import UserList +try: + from collections import UserList +except ImportError: + from UserList import UserList + +from SCons.Util import to_bytes, to_str # Strip the current directory so we get the right TestCmd.py module. @@ -55,7 +64,7 @@ def _is_executable(path): def _clear_dict(dict, *keys): for key in keys: try: - dict[key] = '' # del dict[key] + del dict[key] except KeyError: pass @@ -156,9 +165,9 @@ class TestCmdTestCase(unittest.TestCase): stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE) - stdout, stderr = p.communicate(input) - stdout = self.translate_newlines(stdout) - stderr = self.translate_newlines(stderr) + stdout, stderr = p.communicate(to_bytes(input)) + stdout = self.translate_newlines(to_str(stdout)) + stderr = self.translate_newlines(to_str(stderr)) return stdout, stderr, p.returncode def popen_python(self, input, status=0, stdout="", stderr="", python=None): @@ -181,7 +190,7 @@ class TestCmdTestCase(unittest.TestCase): def run_match(self, content, *args): expect = "%s: %s: %s: %s\n" % args - content = self.translate_newlines(content) + content = self.translate_newlines(to_str(content)) assert content == expect, \ "Expected %s ==========\n" % args[1] + expect + \ "Actual %s ============\n" % args[1] + content @@ -257,6 +266,7 @@ result = TestCmd.TestCmd(workdir = '') sys.exit(0) """ % self.orig_cwd, stdout='my_exitfunc()\n') + @unittest.skipIf(TestCmd.IS_PY3, "No sys.exitfunc in Python 3") def test_exitfunc(self): """Test cleanup() when sys.exitfunc is set""" self.popen_python("""from __future__ import print_function @@ -271,7 +281,6 @@ sys.exit(0) """ % self.orig_cwd, stdout='my_exitfunc()\n') - class chmod_TestCase(TestCmdTestCase): def test_chmod(self): """Test chmod()""" @@ -280,8 +289,10 @@ class chmod_TestCase(TestCmdTestCase): wdir_file1 = os.path.join(test.workdir, 'file1') wdir_sub_file2 = os.path.join(test.workdir, 'sub', 'file2') - open(wdir_file1, 'w').write("") - open(wdir_sub_file2, 'w').write("") + with open(wdir_file1, 'w') as f: + f.write("") + with open(wdir_sub_file2, 'w') as f: + f.write("") if sys.platform == 'win32': @@ -349,11 +360,8 @@ sys.stderr.write("run2 STDERR third line\\n") test = TestCmd.TestCmd(interpreter = 'python', workdir = '', combine = 1) - try: - output = test.stdout() - except IndexError: - pass - else: + output = test.stdout() + if output is not None: raise IndexError("got unexpected output:\n\t`%s'\n" % output) # The underlying system subprocess implementations can combine @@ -422,10 +430,13 @@ class diff_TestCase(TestCmdTestCase): def test_diff_re(self): """Test diff_re()""" result = TestCmd.diff_re(["abcde"], ["abcde"]) + result = list(result) assert result == [], result result = TestCmd.diff_re(["a.*e"], ["abcde"]) + result = list(result) assert result == [], result result = TestCmd.diff_re(["a.*e"], ["xxx"]) + result = list(result) assert result == ['1c1', "< 'a.*e'", '---', "> 'xxx'"], result def test_diff_custom_function(self): @@ -475,13 +486,13 @@ STDOUT========================================================================== script_input = """import sys sys.path = ['%s'] + sys.path import TestCmd -assert TestCmd.diff_re(["a.*(e"], ["abcde"]) +assert TestCmd.diff_re([r"a.*(e"], ["abcde"]) sys.exit(0) """ % self.orig_cwd stdout, stderr, status = self.call_python(script_input) assert status == 1, status - expect1 = "Regular expression error in '^a.*(e$': missing )\n" - expect2 = "Regular expression error in '^a.*(e$': unbalanced parenthesis\n" + expect1 = "Regular expression error in '^a.*(e$': missing )" + expect2 = "Regular expression error in '^a.*(e$': unbalanced parenthesis" assert (stderr.find(expect1) != -1 or stderr.find(expect2) != -1), repr(stderr) @@ -492,6 +503,7 @@ sys.path = ['%s'] + sys.path import TestCmd result = TestCmd.TestCmd.simple_diff(['a', 'b', 'c', 'e', 'f1'], ['a', 'c', 'd', 'e', 'f2']) +result = list(result) expect = ['2d1', '< b', '3a3', '> d', '5c5', '< f1', '---', '> f2'] assert result == expect, result sys.exit(0) @@ -557,6 +569,7 @@ sys.path = ['%s'] + sys.path import TestCmd result = TestCmd.TestCmd.diff_re(['a', 'b', 'c', '.', 'f1'], ['a', 'c', 'd', 'e', 'f2']) +result = list(result) expect = [ '2c2', "< 'b'", @@ -844,22 +857,22 @@ test.%s() _test_it(cwd, 'dir04', 'pass_test', 1) _test_it(cwd, 'dir05', 'fail_test', 1) _test_it(cwd, 'dir06', 'no_result', 1) - os.environ['PRESERVE'] = '' # del os.environ['PRESERVE'] + del os.environ['PRESERVE'] os.environ['PRESERVE_PASS'] = '1' _test_it(cwd, 'dir07', 'pass_test', 1) _test_it(cwd, 'dir08', 'fail_test', 0) _test_it(cwd, 'dir09', 'no_result', 0) - os.environ['PRESERVE_PASS'] = '' # del os.environ['PRESERVE_PASS'] + del os.environ['PRESERVE_PASS'] os.environ['PRESERVE_FAIL'] = '1' _test_it(cwd, 'dir10', 'pass_test', 0) _test_it(cwd, 'dir11', 'fail_test', 1) _test_it(cwd, 'dir12', 'no_result', 0) - os.environ['PRESERVE_FAIL'] = '' # del os.environ['PRESERVE_FAIL'] + del os.environ['PRESERVE_FAIL'] os.environ['PRESERVE_NO_RESULT'] = '1' _test_it(cwd, 'dir13', 'pass_test', 0) _test_it(cwd, 'dir14', 'fail_test', 0) _test_it(cwd, 'dir15', 'no_result', 1) - os.environ['PRESERVE_NO_RESULT'] = '' # del os.environ['PRESERVE_NO_RESULT'] + del os.environ['PRESERVE_NO_RESULT'] finally: _clear_dict(os.environ, 'PRESERVE', 'PRESERVE_PASS', 'PRESERVE_FAIL', 'PRESERVE_NO_RESULT') @@ -980,10 +993,10 @@ class match_TestCase(TestCmdTestCase): test = TestCmd.TestCmd(match = TestCmd.match_exact) assert not test.match("abcde\n", "a.*e\n") assert test.match("abcde\n", "abcde\n") - assert not test.match("12345\nabcde\n", "1\d+5\na.*e\n") + assert not test.match("12345\nabcde\n", "1\\d+5\na.*e\n") assert test.match("12345\nabcde\n", "12345\nabcde\n") lines = ["vwxyz\n", "67890\n"] - regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"] + regexes = [r"v[^a-u]*z\n", r"6[^ ]+0\n"] assert not test.match(lines, regexes) assert test.match(lines, lines) @@ -992,10 +1005,10 @@ class match_TestCase(TestCmdTestCase): test = TestCmd.TestCmd(match=TestCmd.TestCmd.match_exact) assert not test.match("abcde\n", "a.*e\n") assert test.match("abcde\n", "abcde\n") - assert not test.match("12345\nabcde\n", "1\d+5\na.*e\n") + assert not test.match("12345\nabcde\n", "1\\d+5\na.*e\n") assert test.match("12345\nabcde\n", "12345\nabcde\n") lines = ["vwxyz\n", "67890\n"] - regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"] + regexes = [r"v[^a-u]*z\n", r"6[^ ]+0\n"] assert not test.match(lines, regexes) assert test.match(lines, lines) @@ -1004,10 +1017,10 @@ class match_TestCase(TestCmdTestCase): test = TestCmd.TestCmd(match='match_exact') assert not test.match("abcde\n", "a.*e\n") assert test.match("abcde\n", "abcde\n") - assert not test.match("12345\nabcde\n", "1\d+5\na.*e\n") + assert not test.match("12345\nabcde\n", "1\\d+5\na.*e\n") assert test.match("12345\nabcde\n", "12345\nabcde\n") lines = ["vwxyz\n", "67890\n"] - regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"] + regexes = [r"v[^a-u]*z\n", r"6[^ ]+0\n"] assert not test.match(lines, regexes) assert test.match(lines, lines) @@ -1057,16 +1070,16 @@ class match_exact_TestCase(TestCmdTestCase): class match_re_dotall_TestCase(TestCmdTestCase): def test_match_re_dotall_function(self): """Test calling the TestCmd.match_re_dotall() function""" - assert TestCmd.match_re_dotall("abcde\nfghij\n", "a.*j\n") + assert TestCmd.match_re_dotall("abcde\nfghij\n", r"a.*j\n") def test_match_re_dotall_instance_method(self): """Test calling the TestCmd.TestCmd().match_re_dotall() instance method""" test = TestCmd.TestCmd() - test.match_re_dotall("abcde\\nfghij\\n", "a.*j\\n") + test.match_re_dotall("abcde\\nfghij\\n", r"a.*j\\n") def test_match_re_dotall_static_method(self): """Test calling the TestCmd.TestCmd.match_re_dotall() static method""" - assert TestCmd.TestCmd.match_re_dotall("abcde\nfghij\n", "a.*j\n") + assert TestCmd.TestCmd.match_re_dotall("abcde\nfghij\n", r"a.*j\n") def test_error(self): """Test handling a compilation error in TestCmd.match_re_dotall()""" @@ -1079,13 +1092,13 @@ class match_re_dotall_TestCase(TestCmdTestCase): script_input = """import sys sys.path = ['%s'] + sys.path import TestCmd -assert TestCmd.match_re_dotall("abcde", "a.*(e") +assert TestCmd.match_re_dotall("abcde", r"a.*(e") sys.exit(0) """ % cwd stdout, stderr, status = self.call_python(script_input) assert status == 1, status - expect1 = "Regular expression error in '^a.*(e$': missing )\n" - expect2 = "Regular expression error in '^a.*(e$': unbalanced parenthesis\n" + expect1 = "Regular expression error in '^a.*(e$': missing )" + expect2 = "Regular expression error in '^a.*(e$': unbalanced parenthesis" assert (stderr.find(expect1) != -1 or stderr.find(expect2) != -1), repr(stderr) finally: @@ -1094,44 +1107,34 @@ sys.exit(0) def test_evaluation(self): """Test match_re_dotall() evaluation""" test = TestCmd.TestCmd() - assert test.match_re_dotall("abcde\nfghij\n", "a.*e\nf.*j\n") - assert test.match_re_dotall("abcde\nfghij\n", "a[^j]*j\n") - assert test.match_re_dotall("abcde\nfghij\n", "abcde\nfghij\n") + assert test.match_re_dotall("abcde\nfghij\n", r"a.*e\nf.*j\n") + assert test.match_re_dotall("abcde\nfghij\n", r"a[^j]*j\n") + assert test.match_re_dotall("abcde\nfghij\n", r"abcde\nfghij\n") assert test.match_re_dotall(["12345\n", "abcde\n", "fghij\n"], - ["1[0-9]*5\n", "a.*e\n", "f.*j\n"]) + [r"1[0-9]*5\n", r"a.*e\n", r"f.*j\n"]) assert test.match_re_dotall(["12345\n", "abcde\n", "fghij\n"], - ["1.*j\n"]) + [r"1.*j\n"]) assert test.match_re_dotall(["12345\n", "abcde\n", "fghij\n"], - ["12345\n", "abcde\n", "fghij\n"]) - assert test.match_re_dotall(UserList(["12345\n", - "abcde\n", - "fghij\n"]), - ["1[0-9]*5\n", "a.*e\n", "f.*j\n"]) - assert test.match_re_dotall(UserList(["12345\n", - "abcde\n", - "fghij\n"]), - ["1.*j\n"]) - assert test.match_re_dotall(UserList(["12345\n", - "abcde\n", - "fghij\n"]), - ["12345\n", "abcde\n", "fghij\n"]) + [r"12345\n", r"abcde\n", r"fghij\n"]) + assert test.match_re_dotall(UserList(["12345\n", "abcde\n", "fghij\n"]), + [r"1[0-9]*5\n", r"a.*e\n", r"f.*j\n"]) + assert test.match_re_dotall(UserList(["12345\n", "abcde\n", "fghij\n"]), + [r"1.*j\n"]) + assert test.match_re_dotall(UserList(["12345\n", "abcde\n", "fghij\n"]), + [r"12345\n", r"abcde\n", r"fghij\n"]) assert test.match_re_dotall(["12345\n", "abcde\n", "fghij\n"], - UserList(["1[0-9]*5\n", - "a.*e\n", - "f.*j\n"])) + UserList([r"1[0-9]*5\n", r"a.*e\n", r"f.*j\n"])) assert test.match_re_dotall(["12345\n", "abcde\n", "fghij\n"], - UserList(["1.*j\n"])) + UserList([r"1.*j\n"])) assert test.match_re_dotall(["12345\n", "abcde\n", "fghij\n"], - UserList(["12345\n", - "abcde\n", - "fghij\n"])) + UserList([r"12345\n", r"abcde\n", r"fghij\n"])) assert test.match_re_dotall("12345\nabcde\nfghij\n", - "1[0-9]*5\na.*e\nf.*j\n") - assert test.match_re_dotall("12345\nabcde\nfghij\n", "1.*j\n") + r"1[0-9]*5\na.*e\nf.*j\n") + assert test.match_re_dotall("12345\nabcde\nfghij\n", r"1.*j\n") assert test.match_re_dotall("12345\nabcde\nfghij\n", - "12345\nabcde\nfghij\n") + r"12345\nabcde\nfghij\n") lines = ["vwxyz\n", "67890\n"] - regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"] + regexes = [r"v[^a-u]*z\n", r"6[^ ]+0\n"] assert test.match_re_dotall(lines, regexes) assert test.match_re_dotall(lines, lines) @@ -1167,8 +1170,8 @@ sys.exit(0) """ % cwd stdout, stderr, status = self.call_python(script_input) assert status == 1, status - expect1 = "Regular expression error in '^a.*(e$': missing )\n" - expect2 = "Regular expression error in '^a.*(e$': unbalanced parenthesis\n" + expect1 = "Regular expression error in '^a.*(e$': missing )" + expect2 = "Regular expression error in '^a.*(e$': unbalanced parenthesis" assert (stderr.find(expect1) != -1 or stderr.find(expect2) != -1), repr(stderr) finally: @@ -1192,7 +1195,7 @@ sys.exit(0) assert test.match_re("12345\nabcde\n", "1[0-9]*5\na.*e\n") assert test.match_re("12345\nabcde\n", "12345\nabcde\n") lines = ["vwxyz\n", "67890\n"] - regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"] + regexes = [r"v[^a-u]*z\n", r"6[^ ]+0\n"] assert test.match_re(lines, regexes) assert test.match_re(lines, lines) @@ -1205,7 +1208,7 @@ class match_stderr_TestCase(TestCmdTestCase): assert test.match_stderr("abcde\n", "a.*e\n") assert test.match_stderr("12345\nabcde\n", "1\\d+5\na.*e\n") lines = ["vwxyz\n", "67890\n"] - regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"] + regexes = [r"v[^a-u]*z\n", r"6[^ ]+0\n"] assert test.match_stderr(lines, regexes) def test_match_stderr_not_affecting_match_stdout(self): @@ -1217,14 +1220,14 @@ class match_stderr_TestCase(TestCmdTestCase): assert not test.match_stderr("12345\nabcde\n", "1\\d+5\na.*e\n") assert test.match_stderr("12345\nabcde\n", "12345\nabcde\n") lines = ["vwxyz\n", "67890\n"] - regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"] + regexes = [r"v[^a-u]*z\n", r"6[^ ]+0\n"] assert not test.match_stderr(lines, regexes) assert test.match_stderr(lines, lines) assert test.match_stdout("abcde\n", "a.*e\n") assert test.match_stdout("12345\nabcde\n", "1\\d+5\na.*e\n") lines = ["vwxyz\n", "67890\n"] - regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"] + regexes = [r"v[^a-u]*z\n", r"6[^ ]+0\n"] assert test.match_stdout(lines, regexes) def test_match_stderr_custom_function(self): @@ -1237,7 +1240,7 @@ class match_stderr_TestCase(TestCmdTestCase): assert not test.match_stderr("123\n123\n", "1\n1\n") assert test.match_stderr("123\n123\n", "111\n111\n") lines = ["123\n", "123\n"] - regexes = ["1\n", "1\n"] + regexes = [r"1\n", r"1\n"] assert test.match_stderr(lines, regexes) # equal numbers of lines def test_match_stderr_TestCmd_function(self): @@ -1245,10 +1248,10 @@ class match_stderr_TestCase(TestCmdTestCase): test = TestCmd.TestCmd(match_stderr = TestCmd.match_exact) assert not test.match_stderr("abcde\n", "a.*e\n") assert test.match_stderr("abcde\n", "abcde\n") - assert not test.match_stderr("12345\nabcde\n", "1\d+5\na.*e\n") + assert not test.match_stderr("12345\nabcde\n", "1\\d+5\na.*e\n") assert test.match_stderr("12345\nabcde\n", "12345\nabcde\n") lines = ["vwxyz\n", "67890\n"] - regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"] + regexes = [r"v[^a-u]*z\n", r"6[^ ]+0\n"] assert not test.match_stderr(lines, regexes) assert test.match_stderr(lines, lines) @@ -1257,10 +1260,10 @@ class match_stderr_TestCase(TestCmdTestCase): test = TestCmd.TestCmd(match_stderr=TestCmd.TestCmd.match_exact) assert not test.match_stderr("abcde\n", "a.*e\n") assert test.match_stderr("abcde\n", "abcde\n") - assert not test.match_stderr("12345\nabcde\n", "1\d+5\na.*e\n") + assert not test.match_stderr("12345\nabcde\n", "1\\d+5\na.*e\n") assert test.match_stderr("12345\nabcde\n", "12345\nabcde\n") lines = ["vwxyz\n", "67890\n"] - regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"] + regexes = [r"v[^a-u]*z\n", r"6[^ ]+0\n"] assert not test.match_stderr(lines, regexes) assert test.match_stderr(lines, lines) @@ -1269,10 +1272,10 @@ class match_stderr_TestCase(TestCmdTestCase): test = TestCmd.TestCmd(match_stderr='match_exact') assert not test.match_stderr("abcde\n", "a.*e\n") assert test.match_stderr("abcde\n", "abcde\n") - assert not test.match_stderr("12345\nabcde\n", "1\d+5\na.*e\n") + assert not test.match_stderr("12345\nabcde\n", "1\\d+5\na.*e\n") assert test.match_stderr("12345\nabcde\n", "12345\nabcde\n") lines = ["vwxyz\n", "67890\n"] - regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"] + regexes = [r"v[^a-u]*z\n", r"6[^ ]+0\n"] assert not test.match_stderr(lines, regexes) assert test.match_stderr(lines, lines) @@ -1285,7 +1288,7 @@ class match_stdout_TestCase(TestCmdTestCase): assert test.match_stdout("abcde\n", "a.*e\n") assert test.match_stdout("12345\nabcde\n", "1\\d+5\na.*e\n") lines = ["vwxyz\n", "67890\n"] - regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"] + regexes = [r"v[^a-u]*z\n", r"6[^ ]+0\n"] assert test.match_stdout(lines, regexes) def test_match_stdout_not_affecting_match_stderr(self): @@ -1297,14 +1300,14 @@ class match_stdout_TestCase(TestCmdTestCase): assert not test.match_stdout("12345\nabcde\n", "1\\d+5\na.*e\n") assert test.match_stdout("12345\nabcde\n", "12345\nabcde\n") lines = ["vwxyz\n", "67890\n"] - regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"] + regexes = [r"v[^a-u]*z\n", r"6[^ ]+0\n"] assert not test.match_stdout(lines, regexes) assert test.match_stdout(lines, lines) assert test.match_stderr("abcde\n", "a.*e\n") assert test.match_stderr("12345\nabcde\n", "1\\d+5\na.*e\n") lines = ["vwxyz\n", "67890\n"] - regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"] + regexes = [r"v[^a-u]*z\n", r"6[^ ]+0\n"] assert test.match_stderr(lines, regexes) def test_match_stdout_custom_function(self): @@ -1317,7 +1320,7 @@ class match_stdout_TestCase(TestCmdTestCase): assert not test.match_stdout("123\n123\n", "1\n1\n") assert test.match_stdout("123\n123\n", "111\n111\n") lines = ["123\n", "123\n"] - regexes = ["1\n", "1\n"] + regexes = [r"1\n", r"1\n"] assert test.match_stdout(lines, regexes) # equal numbers of lines def test_match_stdout_TestCmd_function(self): @@ -1325,10 +1328,10 @@ class match_stdout_TestCase(TestCmdTestCase): test = TestCmd.TestCmd(match_stdout = TestCmd.match_exact) assert not test.match_stdout("abcde\n", "a.*e\n") assert test.match_stdout("abcde\n", "abcde\n") - assert not test.match_stdout("12345\nabcde\n", "1\d+5\na.*e\n") + assert not test.match_stdout("12345\nabcde\n", "1\\d+5\na.*e\n") assert test.match_stdout("12345\nabcde\n", "12345\nabcde\n") lines = ["vwxyz\n", "67890\n"] - regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"] + regexes = [r"v[^a-u]*z\n", r"6[^ ]+0\n"] assert not test.match_stdout(lines, regexes) assert test.match_stdout(lines, lines) @@ -1337,10 +1340,10 @@ class match_stdout_TestCase(TestCmdTestCase): test = TestCmd.TestCmd(match_stdout=TestCmd.TestCmd.match_exact) assert not test.match_stdout("abcde\n", "a.*e\n") assert test.match_stdout("abcde\n", "abcde\n") - assert not test.match_stdout("12345\nabcde\n", "1\d+5\na.*e\n") + assert not test.match_stdout("12345\nabcde\n", "1\\d+5\na.*e\n") assert test.match_stdout("12345\nabcde\n", "12345\nabcde\n") lines = ["vwxyz\n", "67890\n"] - regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"] + regexes = [r"v[^a-u]*z\n", r"6[^ ]+0\n"] assert not test.match_stdout(lines, regexes) assert test.match_stdout(lines, lines) @@ -1349,10 +1352,10 @@ class match_stdout_TestCase(TestCmdTestCase): test = TestCmd.TestCmd(match_stdout='match_exact') assert not test.match_stdout("abcde\n", "a.*e\n") assert test.match_stdout("abcde\n", "abcde\n") - assert not test.match_stdout("12345\nabcde\n", "1\d+5\na.*e\n") + assert not test.match_stdout("12345\nabcde\n", "1\\d+5\na.*e\n") assert test.match_stdout("12345\nabcde\n", "12345\nabcde\n") lines = ["vwxyz\n", "67890\n"] - regexes = ["v[^a-u]*z\n", "6[^ ]+0\n"] + regexes = [r"v[^a-u]*z\n", r"6[^ ]+0\n"] assert not test.match_stdout(lines, regexes) assert test.match_stdout(lines, lines) @@ -1468,20 +1471,20 @@ class preserve_TestCase(TestCmdTestCase): def test_preserve(self): """Test preserve()""" def cleanup_test(test, cond=None, stdout=""): - io = StringIO() save = sys.stdout - sys.stdout = io - try: - if cond: - test.cleanup(cond) - else: - test.cleanup() - o = io.getvalue() - assert o == stdout, "o = `%s', stdout = `%s'" % (o, stdout) - finally: - sys.stdout = save - - test = TestCmd.TestCmd(workdir = '') + with closing(StringIO()) as io: + sys.stdout = io + try: + if cond: + test.cleanup(cond) + else: + test.cleanup() + o = io.getvalue() + assert o == stdout, "o = `%s', stdout = `%s'" % (o, stdout) + finally: + sys.stdout = save + + test = TestCmd.TestCmd(workdir='') wdir = test.workdir try: test.write('file1', "Test file #1\n") @@ -1490,10 +1493,10 @@ class preserve_TestCase(TestCmdTestCase): assert not os.path.exists(wdir) finally: if os.path.exists(wdir): - shutil.rmtree(wdir, ignore_errors = 1) + shutil.rmtree(wdir, ignore_errors=1) test._dirlist.remove(wdir) - test = TestCmd.TestCmd(workdir = '') + test = TestCmd.TestCmd(workdir='') wdir = test.workdir try: test.write('file2', "Test file #2\n") @@ -1576,11 +1579,16 @@ class read_TestCase(TestCmdTestCase): wdir_file4 = os.path.join(test.workdir, 'file4') wdir_file5 = os.path.join(test.workdir, 'file5') - open(wdir_file1, 'wb').write("") - open(wdir_file2, 'wb').write("Test\nfile\n#2.\n") - open(wdir_foo_file3, 'wb').write("Test\nfile\n#3.\n") - open(wdir_file4, 'wb').write("Test\nfile\n#4.\n") - open(wdir_file5, 'wb').write("Test\r\nfile\r\n#5.\r\n") + with open(wdir_file1, 'wb') as f: + f.write(to_bytes("")) + with open(wdir_file2, 'wb') as f: + f.write(to_bytes("Test\nfile\n#2.\n")) + with open(wdir_foo_file3, 'wb') as f: + f.write(to_bytes("Test\nfile\n#3.\n")) + with open(wdir_file4, 'wb') as f: + f.write(to_bytes("Test\nfile\n#4.\n")) + with open(wdir_file5, 'wb') as f: + f.write(to_bytes("Test\r\nfile\r\n#5.\r\n")) try: contents = test.read('no_file') @@ -1597,6 +1605,7 @@ class read_TestCase(TestCmdTestCase): raise def _file_matches(file, contents, expected): + contents = to_str(contents) assert contents == expected, \ "Expected contents of " + str(file) + "==========\n" + \ expected + \ @@ -1627,7 +1636,7 @@ class rmdir_TestCase(TestCmdTestCase): except EnvironmentError: pass else: - raise Exception("did not catch expected EnvironmentError") + raise Exception("did not catch expected SConsEnvironmentError") test.subdir(['sub'], ['sub', 'dir'], @@ -1642,7 +1651,7 @@ class rmdir_TestCase(TestCmdTestCase): except EnvironmentError: pass else: - raise Exception("did not catch expected EnvironmentError") + raise Exception("did not catch expected SConsEnvironmentError") assert os.path.isdir(s_d_o), "%s is gone?" % s_d_o @@ -1651,7 +1660,7 @@ class rmdir_TestCase(TestCmdTestCase): except EnvironmentError: pass else: - raise Exception("did not catch expected EnvironmentError") + raise Exception("did not catch expected SConsEnvironmentError") assert os.path.isdir(s_d_o), "%s is gone?" % s_d_o @@ -1867,29 +1876,25 @@ class run_verbose_TestCase(TestCmdTestCase): workdir = '', verbose = 1) - sys.stdout = StringIO() - sys.stderr = StringIO() - - test.run(arguments = ['arg1 arg2']) - o = sys.stdout.getvalue() - assert o == '', o - e = sys.stderr.getvalue() - expect = 'python "%s" "arg1 arg2"\n' % t.script_path - assert expect == e, (expect, e) + with closing(StringIO()) as sys.stdout, closing(StringIO()) as sys.stderr: + test.run(arguments = ['arg1 arg2']) + o = sys.stdout.getvalue() + assert o == '', o + e = sys.stderr.getvalue() + expect = 'python "%s" "arg1 arg2"\n' % t.script_path + assert expect == e, (expect, e) testx = TestCmd.TestCmd(program = t.scriptx, workdir = '', verbose = 1) - sys.stdout = StringIO() - sys.stderr = StringIO() - - testx.run(arguments = ['arg1 arg2']) - expect = '"%s" "arg1 arg2"\n' % t.scriptx_path - o = sys.stdout.getvalue() - assert o == '', o - e = sys.stderr.getvalue() - assert expect == e, (expect, e) + with closing(StringIO()) as sys.stdout, closing(StringIO()) as sys.stderr: + testx.run(arguments = ['arg1 arg2']) + expect = '"%s" "arg1 arg2"\n' % t.scriptx_path + o = sys.stdout.getvalue() + assert o == '', o + e = sys.stderr.getvalue() + assert expect == e, (expect, e) # Test calling TestCmd() with an explicit verbose = 2. @@ -1918,43 +1923,39 @@ class run_verbose_TestCase(TestCmdTestCase): workdir = '', verbose = 2) - sys.stdout = StringIO() - sys.stderr = StringIO() + with closing(StringIO()) as sys.stdout, closing(StringIO()) as sys.stderr: + test.run(arguments = ['arg1 arg2']) - test.run(arguments = ['arg1 arg2']) + line_fmt = "script: %s: %s: ['arg1 arg2']\n" + stdout_line = line_fmt % ('STDOUT', t.sub_dir) + stderr_line = line_fmt % ('STDERR', t.sub_dir) + expect = outerr_fmt % (len(stdout_line), stdout_line, + len(stderr_line), stderr_line) + o = sys.stdout.getvalue() + assert expect == o, (expect, o) - line_fmt = "script: %s: %s: ['arg1 arg2']\n" - stdout_line = line_fmt % ('STDOUT', t.sub_dir) - stderr_line = line_fmt % ('STDERR', t.sub_dir) - expect = outerr_fmt % (len(stdout_line), stdout_line, - len(stderr_line), stderr_line) - o = sys.stdout.getvalue() - assert expect == o, (expect, o) - - expect = 'python "%s" "arg1 arg2"\n' % t.script_path - e = sys.stderr.getvalue() - assert e == expect, (e, expect) + expect = 'python "%s" "arg1 arg2"\n' % t.script_path + e = sys.stderr.getvalue() + assert e == expect, (e, expect) testx = TestCmd.TestCmd(program = t.scriptx, workdir = '', verbose = 2) - sys.stdout = StringIO() - sys.stderr = StringIO() - - testx.run(arguments = ['arg1 arg2']) + with closing(StringIO()) as sys.stdout, closing(StringIO()) as sys.stderr: + testx.run(arguments = ['arg1 arg2']) - line_fmt = "scriptx.bat: %s: %s: ['arg1 arg2']\n" - stdout_line = line_fmt % ('STDOUT', t.sub_dir) - stderr_line = line_fmt % ('STDERR', t.sub_dir) - expect = outerr_fmt % (len(stdout_line), stdout_line, - len(stderr_line), stderr_line) - o = sys.stdout.getvalue() - assert expect == o, (expect, o) + line_fmt = "scriptx.bat: %s: %s: ['arg1 arg2']\n" + stdout_line = line_fmt % ('STDOUT', t.sub_dir) + stderr_line = line_fmt % ('STDERR', t.sub_dir) + expect = outerr_fmt % (len(stdout_line), stdout_line, + len(stderr_line), stderr_line) + o = sys.stdout.getvalue() + assert expect == o, (expect, o) - expect = '"%s" "arg1 arg2"\n' % t.scriptx_path - e = sys.stderr.getvalue() - assert e == expect, (e, expect) + expect = '"%s" "arg1 arg2"\n' % t.scriptx_path + e = sys.stderr.getvalue() + assert e == expect, (e, expect) # Test calling TestCmd() with an explicit verbose = 3. @@ -1963,41 +1964,37 @@ class run_verbose_TestCase(TestCmdTestCase): workdir = '', verbose = 2) - sys.stdout = StringIO() - sys.stderr = StringIO() + with closing(StringIO()) as sys.stdout, closing(StringIO()) as sys.stderr: + test.run(arguments = ['arg1 arg2']) - test.run(arguments = ['arg1 arg2']) + line_fmt = "scriptout: %s: %s: ['arg1 arg2']\n" + stdout_line = line_fmt % ('STDOUT', t.sub_dir) + expect = out_fmt % (len(stdout_line), stdout_line) + o = sys.stdout.getvalue() + assert expect == o, (expect, o) - line_fmt = "scriptout: %s: %s: ['arg1 arg2']\n" - stdout_line = line_fmt % ('STDOUT', t.sub_dir) - expect = out_fmt % (len(stdout_line), stdout_line) - o = sys.stdout.getvalue() - assert expect == o, (expect, o) - - e = sys.stderr.getvalue() - expect = 'python "%s" "arg1 arg2"\n' % (t.scriptout_path) - assert e == expect, (e, expect) + e = sys.stderr.getvalue() + expect = 'python "%s" "arg1 arg2"\n' % (t.scriptout_path) + assert e == expect, (e, expect) test = TestCmd.TestCmd(program = t.scriptout, interpreter = 'python', workdir = '', verbose = 3) - sys.stdout = StringIO() - sys.stderr = StringIO() - - test.run(arguments = ['arg1 arg2']) + with closing(StringIO()) as sys.stdout, closing(StringIO()) as sys.stderr: + test.run(arguments = ['arg1 arg2']) - line_fmt = "scriptout: %s: %s: ['arg1 arg2']\n" - stdout_line = line_fmt % ('STDOUT', t.sub_dir) - expect = outerr_fmt % (len(stdout_line), stdout_line, - '0', '') - o = sys.stdout.getvalue() - assert expect == o, (expect, o) + line_fmt = "scriptout: %s: %s: ['arg1 arg2']\n" + stdout_line = line_fmt % ('STDOUT', t.sub_dir) + expect = outerr_fmt % (len(stdout_line), stdout_line, + '0', '') + o = sys.stdout.getvalue() + assert expect == o, (expect, o) - e = sys.stderr.getvalue() - expect = 'python "%s" "arg1 arg2"\n' % (t.scriptout_path) - assert e == expect, (e, expect) + e = sys.stderr.getvalue() + expect = 'python "%s" "arg1 arg2"\n' % (t.scriptout_path) + assert e == expect, (e, expect) # Test letting TestCmd() pick up verbose = 2 from the environment. @@ -2007,42 +2004,38 @@ class run_verbose_TestCase(TestCmdTestCase): interpreter = 'python', workdir = '') - sys.stdout = StringIO() - sys.stderr = StringIO() + with closing(StringIO()) as sys.stdout, closing(StringIO()) as sys.stderr: + test.run(arguments = ['arg1 arg2']) - test.run(arguments = ['arg1 arg2']) + line_fmt = "script: %s: %s: ['arg1 arg2']\n" + stdout_line = line_fmt % ('STDOUT', t.sub_dir) + stderr_line = line_fmt % ('STDERR', t.sub_dir) + expect = outerr_fmt % (len(stdout_line), stdout_line, + len(stderr_line), stderr_line) + o = sys.stdout.getvalue() + assert expect == o, (expect, o) - line_fmt = "script: %s: %s: ['arg1 arg2']\n" - stdout_line = line_fmt % ('STDOUT', t.sub_dir) - stderr_line = line_fmt % ('STDERR', t.sub_dir) - expect = outerr_fmt % (len(stdout_line), stdout_line, - len(stderr_line), stderr_line) - o = sys.stdout.getvalue() - assert expect == o, (expect, o) - - expect = 'python "%s" "arg1 arg2"\n' % t.script_path - e = sys.stderr.getvalue() - assert e == expect, (e, expect) + expect = 'python "%s" "arg1 arg2"\n' % t.script_path + e = sys.stderr.getvalue() + assert e == expect, (e, expect) testx = TestCmd.TestCmd(program = t.scriptx, workdir = '') - sys.stdout = StringIO() - sys.stderr = StringIO() - - testx.run(arguments = ['arg1 arg2']) + with closing(StringIO()) as sys.stdout, closing(StringIO()) as sys.stderr: + testx.run(arguments = ['arg1 arg2']) - line_fmt = "scriptx.bat: %s: %s: ['arg1 arg2']\n" - stdout_line = line_fmt % ('STDOUT', t.sub_dir) - stderr_line = line_fmt % ('STDERR', t.sub_dir) - expect = outerr_fmt % (len(stdout_line), stdout_line, - len(stderr_line), stderr_line) - o = sys.stdout.getvalue() - assert expect == o, (expect, o) + line_fmt = "scriptx.bat: %s: %s: ['arg1 arg2']\n" + stdout_line = line_fmt % ('STDOUT', t.sub_dir) + stderr_line = line_fmt % ('STDERR', t.sub_dir) + expect = outerr_fmt % (len(stdout_line), stdout_line, + len(stderr_line), stderr_line) + o = sys.stdout.getvalue() + assert expect == o, (expect, o) - expect = '"%s" "arg1 arg2"\n' % t.scriptx_path - e = sys.stderr.getvalue() - assert e == expect, (e, expect) + expect = '"%s" "arg1 arg2"\n' % t.scriptx_path + e = sys.stderr.getvalue() + assert e == expect, (e, expect) # Test letting TestCmd() pick up verbose = 1 from the environment. @@ -2053,29 +2046,25 @@ class run_verbose_TestCase(TestCmdTestCase): workdir = '', verbose = 1) - sys.stdout = StringIO() - sys.stderr = StringIO() - - test.run(arguments = ['arg1 arg2']) - o = sys.stdout.getvalue() - assert o == '', o - e = sys.stderr.getvalue() - expect = 'python "%s" "arg1 arg2"\n' % t.script_path - assert expect == e, (expect, e) + with closing(StringIO()) as sys.stdout, closing(StringIO()) as sys.stderr: + test.run(arguments = ['arg1 arg2']) + o = sys.stdout.getvalue() + assert o == '', o + e = sys.stderr.getvalue() + expect = 'python "%s" "arg1 arg2"\n' % t.script_path + assert expect == e, (expect, e) testx = TestCmd.TestCmd(program = t.scriptx, workdir = '', verbose = 1) - sys.stdout = StringIO() - sys.stderr = StringIO() - - testx.run(arguments = ['arg1 arg2']) - expect = '"%s" "arg1 arg2"\n' % t.scriptx_path - o = sys.stdout.getvalue() - assert o == '', o - e = sys.stderr.getvalue() - assert expect == e, (expect, e) + with closing(StringIO()) as sys.stdout, closing(StringIO()) as sys.stderr: + testx.run(arguments = ['arg1 arg2']) + expect = '"%s" "arg1 arg2"\n' % t.scriptx_path + o = sys.stdout.getvalue() + assert o == '', o + e = sys.stderr.getvalue() + assert expect == e, (expect, e) finally: sys.stdout = save_stdout @@ -2343,16 +2332,15 @@ sys.stderr = Unbuffered(sys.stderr) sys.stdout.write('script_recv: STDOUT\\n') sys.stderr.write('script_recv: STDERR\\n') -logfp = open(r'%s', 'wb') -while 1: - line = sys.stdin.readline() - if not line: - break - logfp.write('script_recv: ' + line) - sys.stdout.write('script_recv: STDOUT: ' + line) - sys.stderr.write('script_recv: STDERR: ' + line) -logfp.close() - """ % t.recv_out_path +with open(r'%s', 'wb') as logfp: + while 1: + line = sys.stdin.readline() + if not line: + break + logfp.write('script_recv: ' + line) + sys.stdout.write('script_recv: STDOUT: ' + line) + sys.stderr.write('script_recv: STDERR: ' + line) +""" % t.recv_out_path t.run_env.write(t.recv_script_path, text) os.chmod(t.recv_script_path, 0o644) # XXX UNIX-specific return t @@ -2618,10 +2606,11 @@ script_recv: STDERR: input p = test.start(stdin=1) input = 'stdin.write() input to the receive script\n' - p.stdin.write(input) + p.stdin.write(to_bytes(input)) p.stdin.close() p.wait() - result = open(t.recv_out_path, 'rb').read() + with open(t.recv_out_path, 'rb') as f: + result = to_str(f.read()) expect = 'script_recv: ' + input assert result == expect, repr(result) @@ -2630,7 +2619,8 @@ script_recv: STDERR: input p.send(input) p.stdin.close() p.wait() - result = open(t.recv_out_path, 'rb').read() + with open(t.recv_out_path, 'rb') as f: + result = to_str(f.read()) expect = 'script_recv: ' + input assert result == expect, repr(result) @@ -2689,7 +2679,8 @@ script_recv: STDERR: input to the receive script """ assert stdout == expect_stdout, stdout assert stderr == expect_stderr, stderr - result = open(t.recv_out_path, 'rb').read() + with open(t.recv_out_path, 'rb') as f: + result = f.read() expect = ('script_recv: ' + input) * 2 assert result == expect, (result, stdout, stderr) @@ -2745,11 +2736,8 @@ sys.stderr.write("run2 STDERR second line\\n") # Everything before this prepared our "source directory." # Now do the real test. test = TestCmd.TestCmd(interpreter = 'python', workdir = '') - try: - output = test.stdout() - except IndexError: - pass - else: + output = test.stdout() + if output is not None: raise IndexError("got unexpected output:\n\t`%s'\n" % output) test.program_set('run1') test.run(arguments = 'foo bar') @@ -2807,15 +2795,18 @@ class symlink_TestCase(TestCmdTestCase): test.symlink('target1', 'file1') assert os.path.islink(wdir_file1) assert not os.path.exists(wdir_file1) - open(wdir_target1, 'w').write("") + with open(wdir_target1, 'w') as f: + f.write("") assert os.path.exists(wdir_file1) test.symlink('target2', ['foo', 'file2']) assert os.path.islink(wdir_foo_file2) assert not os.path.exists(wdir_foo_file2) - open(wdir_target2, 'w').write("") + with open(wdir_target2, 'w') as f: + f.write("") assert not os.path.exists(wdir_foo_file2) - open(wdir_foo_target2, 'w').write("") + with open(wdir_foo_target2, 'w') as f: + f.write("") assert os.path.exists(wdir_foo_file2) @@ -2947,12 +2938,18 @@ class unlink_TestCase(TestCmdTestCase): wdir_foo_file4 = os.path.join(test.workdir, 'foo', 'file4') wdir_file5 = os.path.join(test.workdir, 'file5') - open(wdir_file1, 'w').write("") - open(wdir_file2, 'w').write("") - open(wdir_foo_file3a, 'w').write("") - open(wdir_foo_file3b, 'w').write("") - open(wdir_foo_file4, 'w').write("") - open(wdir_file5, 'w').write("") + with open(wdir_file1, 'w') as f: + f.write("") + with open(wdir_file2, 'w') as f: + f.write("") + with open(wdir_foo_file3a, 'w') as f: + f.write("") + with open(wdir_foo_file3b, 'w') as f: + f.write("") + with open(wdir_foo_file4, 'w') as f: + f.write("") + with open(wdir_file5, 'w') as f: + f.write("") try: contents = test.unlink('no_file') @@ -2981,20 +2978,17 @@ class unlink_TestCase(TestCmdTestCase): # For Windows, open the file. os.chmod(test.workdir, 0o500) os.chmod(wdir_file5, 0o400) - f = open(wdir_file5, 'r') - - try: + with open(wdir_file5, 'r'): try: - test.unlink('file5') - except OSError: # expect "Permission denied" - pass - except: - raise - finally: - os.chmod(test.workdir, 0o700) - os.chmod(wdir_file5, 0o600) - f.close() - + try: + test.unlink('file5') + except OSError: # expect "Permission denied" + pass + except: + raise + finally: + os.chmod(test.workdir, 0o700) + os.chmod(wdir_file5, 0o600) class touch_TestCase(TestCmdTestCase): @@ -3005,8 +2999,10 @@ class touch_TestCase(TestCmdTestCase): wdir_file1 = os.path.join(test.workdir, 'file1') wdir_sub_file2 = os.path.join(test.workdir, 'sub', 'file2') - open(wdir_file1, 'w').write("") - open(wdir_sub_file2, 'w').write("") + with open(wdir_file1, 'w') as f: + f.write("") + with open(wdir_sub_file2, 'w') as f: + f.write("") file1_old_time = os.path.getmtime(wdir_file1) file2_old_time = os.path.getmtime(wdir_sub_file2) @@ -3312,9 +3308,12 @@ class write_TestCase(TestCmdTestCase): if os.name != "nt": assert not os.path.exists(test.workpath('file10')) - assert open(test.workpath('file8'), 'r').read() == "Test file #8.\n" - assert open(test.workpath('file9'), 'rb').read() == "Test file #9.\r\n" - + with open(test.workpath('file8'), 'r') as f: + res = f.read() + assert res == "Test file #8.\n", res + with open(test.workpath('file9'), 'rb') as f: + res = to_str(f.read()) + assert res == "Test file #9.\r\n", res class variables_TestCase(TestCmdTestCase): diff --git a/testing/framework/TestRuntest.py b/testing/framework/TestRuntest.py index 64dcf17..e9ca524 100644 --- a/testing/framework/TestRuntest.py +++ b/testing/framework/TestRuntest.py @@ -14,7 +14,7 @@ attributes defined in this subclass. # Copyright (c) 2001 - 2019 The SCons Foundation -__revision__ = "testing/framework/TestRuntest.py 103260fce95bf5db1c35fb2371983087d85dd611 2019-07-13 18:25:30 bdbaddog" +__revision__ = "testing/framework/TestRuntest.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan" import os import os.path @@ -30,7 +30,7 @@ __all__.extend([ 'TestRuntest', 'pythonflags', ]) -if re.search('\s', python): +if re.search(r'\s', python): pythonstring = _python_ else: pythonstring = python diff --git a/testing/framework/TestSCons.py b/testing/framework/TestSCons.py index e415291..2228423 100644 --- a/testing/framework/TestSCons.py +++ b/testing/framework/TestSCons.py @@ -15,7 +15,7 @@ attributes defined in this subclass. # Copyright (c) 2001 - 2019 The SCons Foundation from __future__ import division, print_function -__revision__ = "testing/framework/TestSCons.py 103260fce95bf5db1c35fb2371983087d85dd611 2019-07-13 18:25:30 bdbaddog" +__revision__ = "testing/framework/TestSCons.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan" import os import re @@ -35,7 +35,7 @@ from TestCmd import PIPE # here provides some independent verification that what we packaged # conforms to what we expect. -default_version = '3.0.5' +default_version = '3.1.0' python_version_unsupported = (2, 6, 0) python_version_deprecated = (2, 7, 0) @@ -44,7 +44,7 @@ python_version_deprecated = (2, 7, 0) # line must remain "__ VERSION __" (without the spaces) so the built # version in build/testing/framework/TestSCons.py contains the actual version # string of the packages that have been built. -SConsVersion = '3.0.5' +SConsVersion = '3.1.0' if SConsVersion == '__' + 'VERSION' + '__': SConsVersion = default_version @@ -682,6 +682,9 @@ class TestSCons(TestCommon): """ Initialize with a default external environment that uses a local Java SDK in preference to whatever's found in the default PATH. + + :param version: if set, match only that version + :return: the new env. """ if not self.external: try: @@ -698,11 +701,11 @@ class TestSCons(TestCommon): if version: if sys.platform == 'win32': patterns = [ - 'C:/Program Files*/Java/jdk%s*/bin'%version, + 'C:/Program Files*/Java/jdk*%s*/bin' % version, ] else: patterns = [ - '/usr/java/jdk%s*/bin' % version, + '/usr/java/jdk%s*/bin' % version, '/usr/lib/jvm/*-%s*/bin' % version, '/usr/local/j2sdk%s*/bin' % version, ] @@ -727,7 +730,10 @@ class TestSCons(TestCommon): def java_where_includes(self,version=None): """ - Return java include paths compiling java jni code + Find include path needed for compiling java jni code. + + :param version: if set, match only that version + :return: path to java headers """ import sys @@ -761,6 +767,14 @@ class TestSCons(TestCommon): return result def java_where_java_home(self, version=None): + """ + Find path to what would be JAVA_HOME. + + SCons does not read JAVA_HOME from the environment, so deduce it. + + :param version: if set, match only that version + :return: path where JDK components live + """ if sys.platform[:6] == 'darwin': # osx 10.11, 10.12 home_tool = '/usr/libexec/java_home' @@ -807,6 +821,12 @@ class TestSCons(TestCommon): self.skip_test("Could not find Java " + java_bin_name + ", skipping test(s).\n") def java_where_jar(self, version=None): + """ + Find java archiver jar. + + :param version: if set, match only that version + :return: path to jar + """ ENV = self.java_ENV(version) if self.detect_tool('jar', ENV=ENV): where_jar = self.detect('JAR', 'jar', ENV=ENV) @@ -821,7 +841,10 @@ class TestSCons(TestCommon): def java_where_java(self, version=None): """ - Return a path to the java executable. + Find java executable. + + :param version: if set, match only that version + :return: path to the java rutime """ ENV = self.java_ENV(version) where_java = self.where_is('java', ENV['PATH']) @@ -835,7 +858,10 @@ class TestSCons(TestCommon): def java_where_javac(self, version=None): """ - Return a path to the javac compiler. + Find java compiler. + + :param version: if set, match only that version + :return: path to javac """ ENV = self.java_ENV(version) if self.detect_tool('javac'): @@ -851,15 +877,17 @@ class TestSCons(TestCommon): arguments = '-version', stderr=None, status=None) + # Note recent versions output version info to stdout instead of stderr if version: - if self.stderr().find('javac %s' % version) == -1: + verf = 'javac %s' % version + if self.stderr().find(verf) == -1 and self.stdout().find(verf) == -1: fmt = "Could not find javac for Java version %s, skipping test(s).\n" self.skip_test(fmt % version) else: - m = re.search(r'javac (\d\.*\d)', self.stderr()) - # Java 11 outputs this to stdout + version_re = r'javac (\d*\.*\d)' + m = re.search(version_re, self.stderr()) if not m: - m = re.search(r'javac (\d\.*\d)', self.stdout()) + m = re.search(version_re, self.stdout()) if m: version = m.group(1) @@ -873,6 +901,16 @@ class TestSCons(TestCommon): return where_javac, version def java_where_javah(self, version=None): + """ + Find java header generation tool. + + TODO issue #3347 since JDK10, there is no separate javah command, + 'javac -h' is used. We should not return a javah from a different + installed JDK - how to detect and what to return in this case? + + :param version: if set, match only that version + :return: path to javah + """ ENV = self.java_ENV(version) if self.detect_tool('javah'): where_javah = self.detect('JAVAH', 'javah', ENV=ENV) @@ -883,6 +921,12 @@ class TestSCons(TestCommon): return where_javah def java_where_rmic(self, version=None): + """ + Find java rmic tool. + + :param version: if set, match only that version + :return: path to rmic + """ ENV = self.java_ENV(version) if self.detect_tool('rmic'): where_rmic = self.detect('RMIC', 'rmic', ENV=ENV) @@ -905,7 +949,7 @@ class TestSCons(TestCommon): def Qt_dummy_installation(self, dir='qt'): # create a dummy qt installation - self.subdir( dir, [dir, 'bin'], [dir, 'include'], [dir, 'lib'] ) + self.subdir(dir, [dir, 'bin'], [dir, 'include'], [dir, 'lib']) self.write([dir, 'bin', 'mymoc.py'], """\ import getopt @@ -913,23 +957,23 @@ import sys import re # -w and -z are fake options used in test/QT/QTFLAGS.py cmd_opts, args = getopt.getopt(sys.argv[1:], 'io:wz', []) -output = None impl = 0 opt_string = '' for opt, arg in cmd_opts: - if opt == '-o': output = open(arg, 'w') + if opt == '-o': outfile = arg elif opt == '-i': impl = 1 else: opt_string = opt_string + ' ' + opt -output.write("/* mymoc.py%s */\\n" % opt_string) -for a in args: - with open(a, 'r') as f: - contents = f.read() - a = a.replace('\\\\', '\\\\\\\\') - subst = r'{ my_qt_symbol( "' + a + '\\\\n" ); }' - if impl: - contents = re.sub( r'#include.*', '', contents ) - output.write(contents.replace('Q_OBJECT', subst)) -output.close() + +with open(outfile, 'w') as ofp: + ofp.write("/* mymoc.py%s */\\n" % opt_string) + for a in args: + with open(a, 'r') as ifp: + contents = ifp.read() + a = a.replace('\\\\', '\\\\\\\\') + subst = r'{ my_qt_symbol( "' + a + '\\\\n" ); }' + if impl: + contents = re.sub(r'#include.*', '', contents) + ofp.write(contents.replace('Q_OBJECT', subst)) sys.exit(0) """) @@ -944,7 +988,7 @@ source = None opt_string = '' for arg in sys.argv[1:]: if output_arg: - output = open(arg, 'w') + outfile = arg output_arg = 0 elif impl_arg: impl = arg @@ -958,19 +1002,19 @@ for arg in sys.argv[1:]: else: if source: sys.exit(1) - source = open(arg, 'r') - sourceFile = arg -output.write("/* myuic.py%s */\\n" % opt_string) -if impl: - output.write( '#include "' + impl + '"\\n' ) - includes = re.findall('(.*?)', source.read()) - for incFile in includes: - # this is valid for ui.h files, at least - if os.path.exists(incFile): - output.write('#include "' + incFile + '"\\n') -else: - output.write( '#include "my_qobject.h"\\n' + source.read() + " Q_OBJECT \\n" ) -output.close() + source = sourceFile = arg + +with open(outfile, 'w') as ofp, open(source, 'r') as ifp: + ofp.write("/* myuic.py%s */\\n" % opt_string) + if impl: + ofp.write('#include "' + impl + '"\\n') + includes = re.findall('(.*?)', ifp.read()) + for incFile in includes: + # this is valid for ui.h files, at least + if os.path.exists(incFile): + ofp.write('#include "' + incFile + '"\\n') + else: + ofp.write('#include "my_qobject.h"\\n' + ifp.read() + " Q_OBJECT \\n") sys.exit(0) """ ) @@ -983,7 +1027,7 @@ void my_qt_symbol(const char *arg); #include "../include/my_qobject.h" #include void my_qt_symbol(const char *arg) { - fputs( arg, stdout ); + fputs(arg, stdout); } """) @@ -991,9 +1035,9 @@ void my_qt_symbol(const char *arg) { env = Environment() import sys if sys.platform == 'win32': - env.StaticLibrary( 'myqt', 'my_qobject.cpp' ) + env.StaticLibrary('myqt', 'my_qobject.cpp') else: - env.SharedLibrary( 'myqt', 'my_qobject.cpp' ) + env.SharedLibrary('myqt', 'my_qobject.cpp') """) self.run(chdir = self.workpath(dir, 'lib'), @@ -1036,7 +1080,7 @@ if ARGUMENTS.get('variant_dir', 0): else: sconscript = File('SConscript') Export("env dup") -SConscript( sconscript ) +SConscript(sconscript) """ % (self.QT, self.QT_LIB, self.QT_MOC, self.QT_UIC)) diff --git a/testing/framework/TestSConsMSVS.py b/testing/framework/TestSConsMSVS.py index 09cb5ee..86935fd 100644 --- a/testing/framework/TestSConsMSVS.py +++ b/testing/framework/TestSConsMSVS.py @@ -15,7 +15,7 @@ in this subclass. # Copyright (c) 2001 - 2019 The SCons Foundation -__revision__ = "testing/framework/TestSConsMSVS.py 103260fce95bf5db1c35fb2371983087d85dd611 2019-07-13 18:25:30 bdbaddog" +__revision__ = "testing/framework/TestSConsMSVS.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan" import os import sys @@ -23,6 +23,7 @@ import platform import traceback from xml.etree import ElementTree +import SCons.Errors from TestSCons import * from TestSCons import __all__ @@ -38,18 +39,18 @@ expected_dspfile_6_0 = '''\ CFG=Test - Win32 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run -!MESSAGE +!MESSAGE !MESSAGE NMAKE /f "Test.mak". -!MESSAGE +!MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE +!MESSAGE !MESSAGE NMAKE /f "Test.mak" CFG="Test - Win32 Release" -!MESSAGE +!MESSAGE !MESSAGE Possible choices for configuration are: -!MESSAGE +!MESSAGE !MESSAGE "Test - Win32 Release" (based on "Win32 (x86) External Target") -!MESSAGE +!MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 @@ -85,7 +86,7 @@ CFG=Test - Win32 Release !IF "$(CFG)" == "Test - Win32 Release" -!ENDIF +!ENDIF # Begin Group "Header Files" @@ -435,31 +436,10 @@ env.MSVSProject(target = 'Test.vcproj', """ - -expected_slnfile_8_0 = """\ -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Test", "Test.vcproj", "" -EndProject -Global - -\tGlobalSection(SolutionConfigurationPlatforms) = preSolution -\t\tRelease|Win32 = Release|Win32 -\tEndGlobalSection -\tGlobalSection(ProjectConfigurationPlatforms) = postSolution -\t\t.Release|Win32.ActiveCfg = Release|Win32 -\t\t.Release|Win32.Build.0 = Release|Win32 -\tEndGlobalSection -\tGlobalSection(SolutionProperties) = preSolution -\t\tHideSolutionNode = FALSE -\tEndGlobalSection -EndGlobal -""" - -expected_slnfile_9_0 = """\ -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Test", "Test.vcproj", "" +expected_slnfile_fmt = """\ +Microsoft Visual Studio Solution File, Format Version %(FORMAT_VERSION)s +# Visual Studio %(VS_NUMBER)s +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "%(PROJECT_NAME)s", "%(PROJECT_FILE)s", "" EndProject Global @@ -476,91 +456,11 @@ Global EndGlobal """ -expected_slnfile_10_0 = """\ -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Test.vcxproj", "Test.vcxproj", "{39A97E1F-1A52-8954-A0B1-A10A8487545E}" -EndProject -Global - -\tGlobalSection(SolutionConfigurationPlatforms) = preSolution -\t\tRelease|Win32 = Release|Win32 -\tEndGlobalSection -\tGlobalSection(ProjectConfigurationPlatforms) = postSolution -\t\t{39A97E1F-1A52-8954-A0B1-A10A8487545E}.Release|Win32.ActiveCfg = Release|Win32 -\t\t{39A97E1F-1A52-8954-A0B1-A10A8487545E}.Release|Win32.Build.0 = Release|Win32 -\tEndGlobalSection -\tGlobalSection(SolutionProperties) = preSolution -\t\tHideSolutionNode = FALSE -\tEndGlobalSection -EndGlobal -""" - -expected_slnfile_11_0 = """\ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 11 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Test.vcxproj", "Test.vcxproj", "{39A97E1F-1A52-8954-A0B1-A10A8487545E}" -EndProject -Global - -\tGlobalSection(SolutionConfigurationPlatforms) = preSolution -\t\tRelease|Win32 = Release|Win32 -\tEndGlobalSection -\tGlobalSection(ProjectConfigurationPlatforms) = postSolution -\t\t{39A97E1F-1A52-8954-A0B1-A10A8487545E}.Release|Win32.ActiveCfg = Release|Win32 -\t\t{39A97E1F-1A52-8954-A0B1-A10A8487545E}.Release|Win32.Build.0 = Release|Win32 -\tEndGlobalSection -\tGlobalSection(SolutionProperties) = preSolution -\t\tHideSolutionNode = FALSE -\tEndGlobalSection -EndGlobal -""" - -expected_slnfile_14_0 = """\ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Test.vcxproj", "Test.vcxproj", "{39A97E1F-1A52-8954-A0B1-A10A8487545E}" -EndProject -Global - -\tGlobalSection(SolutionConfigurationPlatforms) = preSolution -\t\tRelease|Win32 = Release|Win32 -\tEndGlobalSection -\tGlobalSection(ProjectConfigurationPlatforms) = postSolution -\t\t{39A97E1F-1A52-8954-A0B1-A10A8487545E}.Release|Win32.ActiveCfg = Release|Win32 -\t\t{39A97E1F-1A52-8954-A0B1-A10A8487545E}.Release|Win32.Build.0 = Release|Win32 -\tEndGlobalSection -\tGlobalSection(SolutionProperties) = preSolution -\t\tHideSolutionNode = FALSE -\tEndGlobalSection -EndGlobal -""" - -expected_slnfile_14_1 = """\ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Test.vcxproj", "Test.vcxproj", "{39A97E1F-1A52-8954-A0B1-A10A8487545E}" -EndProject -Global - -\tGlobalSection(SolutionConfigurationPlatforms) = preSolution -\t\tRelease|Win32 = Release|Win32 -\tEndGlobalSection -\tGlobalSection(ProjectConfigurationPlatforms) = postSolution -\t\t{39A97E1F-1A52-8954-A0B1-A10A8487545E}.Release|Win32.ActiveCfg = Release|Win32 -\t\t{39A97E1F-1A52-8954-A0B1-A10A8487545E}.Release|Win32.Build.0 = Release|Win32 -\tEndGlobalSection -\tGlobalSection(SolutionProperties) = preSolution -\t\tHideSolutionNode = FALSE -\tEndGlobalSection -EndGlobal -""" - -expected_vcprojfile_8_0 = """\ +expected_vcprojfile_fmt = """\ \t\t\t +\t\t\t\tRelativePath="sdk_dir\\sdk.h"> \t\t\t \t\t \t\t """ -expected_vcprojfile_9_0 = """\ - - -\tKeyword="MakeFileProj"> -\t -\t\t -\t -\t -\t -\t -\t\t -\t\t\t -\t\t -\t -\t -\t -\t -\t\t -\t\t\t -\t\t\t -\t\t -\t\t -\t\t\t -\t\t\t -\t\t -\t\t -\t\t\t -\t\t\t -\t\t -\t\t -\t\t\t -\t\t\t -\t\t -\t\t -\t\t\t -\t\t\t -\t\t\t -\t\t\t -\t\t -\t\t -\t\t -\t -\t -\t - -""" - -expected_vcprojfile_10_0 = """\ +expected_vcxprojfile_fmt = """\ - + \t \t\t \t\t\tRelease @@ -746,6 +558,7 @@ expected_vcprojfile_10_0 = """\ \t\tTest \t\tMakeFileProj +\t\tNoUpgrade \t \t \t @@ -767,13 +580,13 @@ expected_vcprojfile_10_0 = """\ \t\techo Starting SCons && "" -c "" -C "" -f SConstruct -c "Test.exe" \t\tTest.exe \t\tDEF1;DEF2;DEF3=1234 -\t\tinc1;inc2 +\t\t%(INCLUDE_DIRS)s \t\t$(NMakeForcedIncludes) \t\t$(NMakeAssemblySearchPath) \t\t$(NMakeForcedUsingAssemblies) \t \t -\t\t +\t\t \t \t \t\t @@ -797,237 +610,19 @@ expected_vcprojfile_10_0 = """\ """ -expected_vcprojfile_11_0 = """\ - - -\t -\t\t -\t\t\tRelease -\t\t\tWin32 -\t\t -\t -\t -\t\t{39A97E1F-1A52-8954-A0B1-A10A8487545E} - -\t\tTest -\t\tMakeFileProj -\t -\t -\t -\t\tMakefile -\t\tfalse -\t\tv110 -\t -\t -\t -\t -\t -\t\t -\t -\t -\t -\t<_ProjectFileVersion>10.0.30319.1 -\t\techo Starting SCons && "" -c "" -C "" -f SConstruct "Test.exe" -\t\techo Starting SCons && "" -c "" -C "" -f SConstruct "Test.exe" -\t\techo Starting SCons && "" -c "" -C "" -f SConstruct -c "Test.exe" -\t\tTest.exe -\t\tDEF1;DEF2;DEF3=1234 -\t\tinc1;inc2 -\t\t$(NMakeForcedIncludes) -\t\t$(NMakeAssemblySearchPath) -\t\t$(NMakeForcedUsingAssemblies) -\t -\t -\t\t -\t -\t -\t\t -\t -\t -\t\t -\t -\t -\t\t -\t -\t -\t\t -\t\t -\t -\t -\t\t -\t -\t -\t -\t - -""" - -expected_vcprojfile_14_0 = """\ - - -\t -\t\t -\t\t\tRelease -\t\t\tWin32 -\t\t -\t -\t -\t\t{39A97E1F-1A52-8954-A0B1-A10A8487545E} - -\t\tTest -\t\tMakeFileProj -\t -\t -\t -\t\tMakefile -\t\tfalse -\t\tv140 -\t -\t -\t -\t -\t -\t\t -\t -\t -\t -\t<_ProjectFileVersion>10.0.30319.1 -\t\techo Starting SCons && "" -c "" -C "" -f SConstruct "Test.exe" -\t\techo Starting SCons && "" -c "" -C "" -f SConstruct "Test.exe" -\t\techo Starting SCons && "" -c "" -C "" -f SConstruct -c "Test.exe" -\t\tTest.exe -\t\tDEF1;DEF2;DEF3=1234 -\t\tinc1;inc2 -\t\t$(NMakeForcedIncludes) -\t\t$(NMakeAssemblySearchPath) -\t\t$(NMakeForcedUsingAssemblies) -\t -\t -\t\t -\t -\t -\t\t -\t -\t -\t\t -\t -\t -\t\t -\t -\t -\t\t -\t\t -\t -\t -\t\t -\t -\t -\t -\t - -""" - -expected_vcprojfile_14_1 = """\ - - -\t -\t\t -\t\t\tRelease -\t\t\tWin32 -\t\t -\t -\t -\t\t{39A97E1F-1A52-8954-A0B1-A10A8487545E} - -\t\tTest -\t\tMakeFileProj -\t -\t -\t -\t\tMakefile -\t\tfalse -\t\tv141 -\t -\t -\t -\t -\t -\t\t -\t -\t -\t -\t<_ProjectFileVersion>10.0.30319.1 -\t\techo Starting SCons && "" -c "" -C "" -f SConstruct "Test.exe" -\t\techo Starting SCons && "" -c "" -C "" -f SConstruct "Test.exe" -\t\techo Starting SCons && "" -c "" -C "" -f SConstruct -c "Test.exe" -\t\tTest.exe -\t\tDEF1;DEF2;DEF3=1234 -\t\tinc1;inc2 -\t\t$(NMakeForcedIncludes) -\t\t$(NMakeAssemblySearchPath) -\t\t$(NMakeForcedUsingAssemblies) -\t -\t -\t\t -\t -\t -\t\t -\t -\t -\t\t -\t -\t -\t\t -\t -\t -\t\t -\t\t -\t -\t -\t\t -\t -\t -\t -\t - -""" - -SConscript_contents_8_0 = """\ -env=Environment(platform='win32', tools=['msvs'], MSVS_VERSION='8.0', - CPPDEFINES=['DEF1', 'DEF2',('DEF3','1234')], - CPPPATH=['inc1', 'inc2'], - HOST_ARCH='%(HOST_ARCH)s') - -testsrc = ['test1.cpp', 'test2.cpp'] -testincs = ['sdk.h'] -testlocalincs = ['test.h'] -testresources = ['test.rc'] -testmisc = ['readme.txt'] - -env.MSVSProject(target = 'Test.vcproj', - slnguid = '{SLNGUID}', - srcs = testsrc, - incs = testincs, - localincs = testlocalincs, - resources = testresources, - misc = testmisc, - buildtarget = 'Test.exe', - variant = 'Release') -""" - -SConscript_contents_9_0 = """\ -env=Environment(platform='win32', tools=['msvs'], MSVS_VERSION='9.0', +SConscript_contents_fmt = """\ +env=Environment(platform='win32', tools=['msvs'], MSVS_VERSION='%(MSVS_VERSION)s', CPPDEFINES=['DEF1', 'DEF2',('DEF3','1234')], CPPPATH=['inc1', 'inc2'], HOST_ARCH='%(HOST_ARCH)s') testsrc = ['test1.cpp', 'test2.cpp'] -testincs = ['sdk.h'] +testincs = [r'sdk_dir\\sdk.h'] testlocalincs = ['test.h'] testresources = ['test.rc'] testmisc = ['readme.txt'] -env.MSVSProject(target = 'Test.vcproj', +env.MSVSProject(target = '%(PROJECT_FILE)s', slnguid = '{SLNGUID}', srcs = testsrc, incs = testincs, @@ -1038,97 +633,13 @@ env.MSVSProject(target = 'Test.vcproj', variant = 'Release') """ -SConscript_contents_10_0 = """\ -env=Environment(platform='win32', tools=['msvs'], MSVS_VERSION='10.0', - CPPDEFINES=['DEF1', 'DEF2',('DEF3','1234')], - CPPPATH=['inc1', 'inc2'], - HOST_ARCH='%(HOST_ARCH)s') -testsrc = ['test1.cpp', 'test2.cpp'] -testincs = ['sdk_dir\sdk.h'] -testlocalincs = ['test.h'] -testresources = ['test.rc'] -testmisc = ['readme.txt'] +def get_tested_proj_file_vc_versions(): + """ + Returns all MSVC versions that we want to test project file creation for. + """ + return ['8.0', '9.0', '10.0', '11.0', '12.0', '14.0', '14.1', '14.2'] -env.MSVSProject(target = 'Test.vcxproj', - slnguid = '{SLNGUID}', - srcs = testsrc, - incs = testincs, - localincs = testlocalincs, - resources = testresources, - misc = testmisc, - buildtarget = 'Test.exe', - variant = 'Release') -""" - -SConscript_contents_11_0 = """\ -env=Environment(platform='win32', tools=['msvs'], MSVS_VERSION='11.0', - CPPDEFINES=['DEF1', 'DEF2',('DEF3','1234')], - CPPPATH=['inc1', 'inc2'], - HOST_ARCH='%(HOST_ARCH)s') - -testsrc = ['test1.cpp', 'test2.cpp'] -testincs = ['sdk_dir\sdk.h'] -testlocalincs = ['test.h'] -testresources = ['test.rc'] -testmisc = ['readme.txt'] - -env.MSVSProject(target = 'Test.vcxproj', - slnguid = '{SLNGUID}', - srcs = testsrc, - incs = testincs, - localincs = testlocalincs, - resources = testresources, - misc = testmisc, - buildtarget = 'Test.exe', - variant = 'Release') -""" - -SConscript_contents_14_0 = """\ -env=Environment(platform='win32', tools=['msvs'], MSVS_VERSION='14.0', - CPPDEFINES=['DEF1', 'DEF2',('DEF3','1234')], - CPPPATH=['inc1', 'inc2'], - HOST_ARCH='%(HOST_ARCH)s') - -testsrc = ['test1.cpp', 'test2.cpp'] -testincs = ['sdk_dir\sdk.h'] -testlocalincs = ['test.h'] -testresources = ['test.rc'] -testmisc = ['readme.txt'] - -env.MSVSProject(target = 'Test.vcxproj', - slnguid = '{SLNGUID}', - srcs = testsrc, - incs = testincs, - localincs = testlocalincs, - resources = testresources, - misc = testmisc, - buildtarget = 'Test.exe', - variant = 'Release') -""" - -SConscript_contents_14_1 = """\ -env=Environment(platform='win32', tools=['msvs'], MSVS_VERSION='14.1', - CPPDEFINES=['DEF1', 'DEF2',('DEF3','1234')], - CPPPATH=['inc1', 'inc2'], - HOST_ARCH='%(HOST_ARCH)s') - -testsrc = ['test1.cpp', 'test2.cpp'] -testincs = ['sdk_dir\sdk.h'] -testlocalincs = ['test.h'] -testresources = ['test.rc'] -testmisc = ['readme.txt'] - -env.MSVSProject(target = 'Test.vcxproj', - slnguid = '{SLNGUID}', - srcs = testsrc, - incs = testincs, - localincs = testlocalincs, - resources = testresources, - misc = testmisc, - buildtarget = 'Test.exe', - variant = 'Release') -""" class TestSConsMSVS(TestSCons): """Subclass for testing MSVS-specific portions of SCons.""" @@ -1150,7 +661,7 @@ import SCons.Tool.MSCommon print("self.scons_version =%%s"%%repr(SCons.__%s__)) print("self._msvs_versions =%%s"%%str(SCons.Tool.MSCommon.query_versions())) """ % 'version' - + self.run(arguments = '-n -q -Q -f -', stdin = input) exec(self.stdout()) @@ -1233,11 +744,11 @@ print("self._msvs_versions =%%s"%%str(SCons.Tool.MSCommon.query_versions())) finally: os.environ['SCONSFLAGS'] = save_sconsflags or '' return result - + def get_vs_host_arch(self): """ Get an MSVS, SDK , and/or MSVS acceptable platform arch """ - + # Dict to 'canonalize' the arch _ARCH_TO_CANONICAL = { "x86": "x86", @@ -1255,21 +766,19 @@ print("self._msvs_versions =%%s"%%str(SCons.Tool.MSCommon.query_versions())) # PROCESSOR_ARCHITECTURE. if not host_platform: host_platform = os.environ.get('PROCESSOR_ARCHITECTURE', '') - - + try: host = _ARCH_TO_CANONICAL[host_platform] except KeyError as e: # Default to x86 for all other platforms host = 'x86' - - + return host def validate_msvs_file(self, file): try: x = ElementTree.parse(file) - except: + except: print("--------------------------------------------------------------") print("--------------------------------------------------------------") print(traceback.format_exc()) @@ -1278,6 +787,119 @@ print("self._msvs_versions =%%s"%%str(SCons.Tool.MSCommon.query_versions())) print("--------------------------------------------------------------") print("--------------------------------------------------------------") self.fail_test() + + def parse_vc_version(self, vc_version): + """ + Parses the string vc_version to determine the major and minor version + included. + """ + components = vc_version.split('.') + major = int(components[0]) + minor = 0 if len(components) < 2 else int(components[1]) + return major, minor + + def _get_solution_file_format_version(self, vc_version): + """ + Returns the Visual Studio format version expected in the .sln file. + """ + major, _ = self.parse_vc_version(vc_version) + if major == 8: + return '9.00' + elif major == 9: + return '10.00' + elif major == 10: + return '11.00' + elif major > 10: + return '12.00' + else: + raise SCons.Errors.UserError('Received unexpected VC version %s' % vc_version) + + def _get_solution_file_vs_number(self, vc_version): + """ + Returns the Visual Studio number expected in the .sln file. + """ + major, minor = self.parse_vc_version(vc_version) + if major == 8: + return '2005' + elif major == 9: + return '2008' + if major == 10: + return '2010' + elif major == 11: + return '11' + elif major == 12: + return '14' + elif major == 14 and (minor == 0 or minor == 1): + # Visual Studio 2015 and 2017 both use 15 in this entry. + return '15' + elif major == 14 and minor == 2: + return '16' + else: + raise SCons.Errors.UserError('Received unexpected VC version %s' % vc_version) + + def _get_vcxproj_file_tools_version(self, vc_version): + """ + Returns the version entry expected in the project file. + For .vcxproj files, this goes is ToolsVersion. + For .vcproj files, this goes in Version. + """ + major, minor = self.parse_vc_version(vc_version) + if major == 8: + # Version="8.00" + return '8.00' + elif major == 9: + # Version="9.00" + return '9.00' + elif major < 14: + # ToolsVersion='4.0' + return '4.0' + elif major == 14 and minor == 0: + # ToolsVersion='14.0' + return '14.0' + elif major == 14 and minor == 1: + # ToolsVersion='15.0' + return '15.0' + elif vc_version == '14.2': + # ToolsVersion='16' + return '16.0' + else: + raise SCons.Errors.UserError('Received unexpected VC version %s' % vc_version) + + def _get_vcxproj_file_cpp_path(self, dirs): + """Returns the include paths expected in the .vcxproj file""" + return ';'.join([self.workpath(dir) for dir in dirs]) + + def get_expected_sln_file_contents(self, vc_version, project_file): + """ + Returns the expected .sln file contents. + Currently this function only supports the newer VC versions that use + the .vcxproj file format. + """ + return expected_slnfile_fmt % { + 'FORMAT_VERSION': self._get_solution_file_format_version(vc_version), + 'VS_NUMBER': self._get_solution_file_vs_number(vc_version), + 'PROJECT_NAME': project_file.split('.')[0], + 'PROJECT_FILE': project_file, + } + + def get_expected_proj_file_contents(self, vc_version, dirs, project_file): + """Returns the expected .vcxproj file contents""" + if project_file.endswith('.vcxproj'): + fmt = expected_vcxprojfile_fmt + else: + fmt = expected_vcprojfile_fmt + return fmt % { + 'TOOLS_VERSION': self._get_vcxproj_file_tools_version(vc_version), + 'INCLUDE_DIRS': self._get_vcxproj_file_cpp_path(dirs), + } + + def get_expected_sconscript_file_contents(self, vc_version, project_file): + return SConscript_contents_fmt % { + 'HOST_ARCH': self.get_vs_host_arch(), + 'MSVS_VERSION': vc_version, + 'PROJECT_FILE': project_file, + } + # Local Variables: # tab-width:4 # indent-tabs-mode:nil diff --git a/testing/framework/TestSCons_time.py b/testing/framework/TestSCons_time.py index 624eb4c..547e264 100644 --- a/testing/framework/TestSCons_time.py +++ b/testing/framework/TestSCons_time.py @@ -13,7 +13,7 @@ attributes defined in this subclass. # Copyright (c) 2001 - 2019 The SCons Foundation -__revision__ = "testing/framework/TestSCons_time.py 103260fce95bf5db1c35fb2371983087d85dd611 2019-07-13 18:25:30 bdbaddog" +__revision__ = "testing/framework/TestSCons_time.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan" import os import os.path @@ -272,7 +272,8 @@ class TestSCons_time(TestCommon): d, f = os.path.split(path) if not os.path.isdir(d): os.makedirs(d) - open(path, 'w').write(content) + with open(path, 'w') as f: + f.write(content) return dir def write_sample_tarfile(self, archive, dir, files): diff --git a/testing/framework/TestSConsign.py b/testing/framework/TestSConsign.py index fc72aa4..8f992ef 100644 --- a/testing/framework/TestSConsign.py +++ b/testing/framework/TestSConsign.py @@ -1,7 +1,7 @@ # Copyright (c) 2001 - 2019 The SCons Foundation from __future__ import print_function -__revision__ = "testing/framework/TestSConsign.py 103260fce95bf5db1c35fb2371983087d85dd611 2019-07-13 18:25:30 bdbaddog" +__revision__ = "testing/framework/TestSConsign.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan" __doc__ = """ TestSConsign.py: a testing framework for the "sconsign" script -- cgit v1.2.3