X-Git-Url: http://git.tremily.us/?a=blobdiff_plain;f=src%2Fengine%2FSCons%2FEnvironmentTests.py;h=25404082a0b6311cf122018ae845e419ca39952e;hb=704f6e2480ef60718f1aa42c266f04afc9c79580;hp=bfd1262014717511efc9e1272c87e24bcb8b7c56;hpb=2eaf232880ad163415e8ec6cab22f958d0db0799;p=scons.git diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py index bfd12620..25404082 100644 --- a/src/engine/SCons/EnvironmentTests.py +++ b/src/engine/SCons/EnvironmentTests.py @@ -23,8 +23,11 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" +import SCons.compat + +import copy import os -import string +import StringIO import sys import TestCmd import unittest @@ -38,18 +41,16 @@ def diff_env(env1, env2): s2 = "env2 = {\n" d = {} for k in env1._dict.keys() + env2._dict.keys(): - d[k] = None - keys = d.keys() - keys.sort() - for k in keys: - if env1.has_key(k): - if env2.has_key(k): + d[k] = None + for k in sorted(d.keys()): + if k in env1: + if k in env2: if env1[k] != env2[k]: s1 = s1 + " " + repr(k) + " : " + repr(env1[k]) + "\n" s2 = s2 + " " + repr(k) + " : " + repr(env2[k]) + "\n" else: s1 = s1 + " " + repr(k) + " : " + repr(env1[k]) + "\n" - elif env2.has_key(k): + elif k in env2: s2 = s2 + " " + repr(k) + " : " + repr(env2[k]) + "\n" s1 = s1 + "}\n" s2 = s2 + "}\n" @@ -60,18 +61,16 @@ def diff_dict(d1, d2): s2 = "d2 = {\n" d = {} for k in d1.keys() + d2.keys(): - d[k] = None - keys = d.keys() - keys.sort() - for k in keys: - if d1.has_key(k): - if d2.has_key(k): + d[k] = None + for k in sorted(d.keys()): + if k in d1: + if k in d2: if d1[k] != d2[k]: s1 = s1 + " " + repr(k) + " : " + repr(d1[k]) + "\n" s2 = s2 + " " + repr(k) + " : " + repr(d2[k]) + "\n" else: s1 = s1 + " " + repr(k) + " : " + repr(d1[k]) + "\n" - elif env2.has_key(k): + elif k in env2: s2 = s2 + " " + repr(k) + " : " + repr(d2[k]) + "\n" s1 = s1 + "}\n" s2 = s2 + "}\n" @@ -80,7 +79,7 @@ def diff_dict(d1, d2): called_it = {} built_it = {} -class Builder: +class Builder(SCons.Builder.BuilderBase): """A dummy Builder class for testing purposes. "Building" a target is simply setting a value in the dictionary. """ @@ -129,9 +128,13 @@ class Scanner: class CLVar(UserList.UserList): def __init__(self, seq): - if type(seq) == type(''): - seq = string.split(seq) + if isinstance(seq, str): + seq = seq.split() UserList.UserList.__init__(self, seq) + def __add__(self, other): + return UserList.UserList.__add__(self, CLVar(other)) + def __radd__(self, other): + return UserList.UserList.__radd__(self, CLVar(other)) def __coerce__(self, other): return (self, CLVar(other)) @@ -147,7 +150,29 @@ class DummyNode: def get_subst_proxy(self): return self - +def test_tool( env ): + env['_F77INCFLAGS'] = '$( ${_concat(INCPREFIX, F77PATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)' + +class TestEnvironmentFixture: + def TestEnvironment(self, *args, **kw): + if not kw or 'tools' not in kw: + kw['tools'] = [test_tool] + default_keys = { 'CC' : 'cc', + 'CCFLAGS' : '-DNDEBUG', + 'ENV' : { 'TMP' : '/tmp' } } + for key, value in default_keys.items(): + if key not in kw: + kw[key] = value + if 'BUILDERS' not in kw: + static_obj = SCons.Builder.Builder(action = {}, + emitter = {}, + suffix = '.o', + single_source = 1) + kw['BUILDERS'] = {'Object' : static_obj} + static_obj.add_action('.cpp', 'fake action') + + env = Environment(*args, **kw) + return env class SubstitutionTestCase(unittest.TestCase): @@ -155,7 +180,7 @@ class SubstitutionTestCase(unittest.TestCase): """Test initializing a SubstitutionEnvironment """ env = SubstitutionEnvironment() - assert not env.has_key('__env__') + assert '__env__' not in env def test___cmp__(self): """Test comparing SubstitutionEnvironments @@ -179,13 +204,13 @@ class SubstitutionTestCase(unittest.TestCase): assert env1 == env2 def test___getitem__(self): - """Test deleting a variable from a SubstitutionEnvironment + """Test fetching a variable from a SubstitutionEnvironment """ env = SubstitutionEnvironment(XXX = 'x') assert env['XXX'] == 'x', env['XXX'] def test___setitem__(self): - """Test deleting a variable from a SubstitutionEnvironment + """Test setting a variable in a SubstitutionEnvironment """ env1 = SubstitutionEnvironment(XXX = 'x') env2 = SubstitutionEnvironment(XXX = 'x', YYY = 'y') @@ -203,8 +228,23 @@ class SubstitutionTestCase(unittest.TestCase): """Test the SubstitutionEnvironment has_key() method """ env = SubstitutionEnvironment(XXX = 'x') - assert env.has_key('XXX') - assert not env.has_key('YYY') + assert 'XXX' in env + assert 'YYY' not in env + + def test_contains(self): + """Test the SubstitutionEnvironment __contains__() method + """ + try: + 'x' in {'x':1} + except TypeError: + # TODO(1.5) + # An early version of Python that doesn't support "in" + # on dictionaries. Just pass the test. + pass + else: + env = SubstitutionEnvironment(XXX = 'x') + assert 'XXX' in env + assert not 'YYY' in env def test_items(self): """Test the SubstitutionEnvironment items() method @@ -221,7 +261,7 @@ class SubstitutionTestCase(unittest.TestCase): class X(SCons.Node.Node): pass def Factory(name, directory = None, create = 1, dict=dict, X=X): - if not dict.has_key(name): + if name not in dict: dict[name] = X() dict[name].name = name return dict[name] @@ -231,8 +271,9 @@ class SubstitutionTestCase(unittest.TestCase): assert isinstance(nodes[0], X) assert nodes[0].name == "Util.py UtilTests.py" - import types - if hasattr(types, 'UnicodeType'): + try: unicode + except NameError: pass + else: code = """if 1: nodes = env.arg2nodes(u"Util.py UtilTests.py", Factory) assert len(nodes) == 1, nodes @@ -334,6 +375,22 @@ class SubstitutionTestCase(unittest.TestCase): assert not hasattr(nodes[1], 'bbbb'), nodes[0] assert nodes[1].c == 1, nodes[1] + def test_arg2nodes_target_source(self): + """Test the arg2nodes method with target= and source= keywords + """ + targets = [DummyNode('t1'), DummyNode('t2')] + sources = [DummyNode('s1'), DummyNode('s2')] + env = SubstitutionEnvironment() + nodes = env.arg2nodes(['${TARGET}-a', + '${SOURCE}-b', + '${TARGETS[1]}-c', + '${SOURCES[1]}-d'], + DummyNode, + target=targets, + source=sources) + names = [n.name for n in nodes] + assert names == ['t1-a', 's1-b', 't2-c', 's2-d'], names + def test_gvars(self): """Test the base class gvars() method""" env = SubstitutionEnvironment() @@ -366,6 +423,16 @@ class SubstitutionTestCase(unittest.TestCase): mystr = env.subst("$AAA ${AAA}A ${AAA}B $BBB") assert mystr == "c cA cB c", mystr + # Lists: + env = SubstitutionEnvironment(AAA = ['a', 'aa', 'aaa']) + mystr = env.subst("$AAA") + assert mystr == "a aa aaa", mystr + + # Tuples: + env = SubstitutionEnvironment(AAA = ('a', 'aa', 'aaa')) + mystr = env.subst("$AAA") + assert mystr == "a aa aaa", mystr + t1 = DummyNode('t1') t2 = DummyNode('t2') s1 = DummyNode('s1') @@ -493,9 +560,13 @@ class SubstitutionTestCase(unittest.TestCase): return self.val class MyObj: - pass + def get(self): + return self - env = SubstitutionEnvironment(FOO='foo', BAR='bar', PROXY=MyProxy('my1')) + env = SubstitutionEnvironment(FOO='foo', + BAR='bar', + LIST=['one', 'two'], + PROXY=MyProxy('my1')) r = env.subst_path('$FOO') assert r == ['foo'], r @@ -503,14 +574,17 @@ class SubstitutionTestCase(unittest.TestCase): r = env.subst_path(['$FOO', 'xxx', '$BAR']) assert r == ['foo', 'xxx', 'bar'], r + r = env.subst_path(['$FOO', '$LIST', '$BAR']) + assert list(map(str, r)) == ['foo', 'one two', 'bar'], r + r = env.subst_path(['$FOO', '$TARGET', '$SOURCE', '$BAR']) assert r == ['foo', '', '', 'bar'], r r = env.subst_path(['$FOO', '$TARGET', '$BAR'], target=MyNode('ttt')) - assert map(str, r) == ['foo', 'ttt', 'bar'], r + assert list(map(str, r)) == ['foo', 'ttt', 'bar'], r r = env.subst_path(['$FOO', '$SOURCE', '$BAR'], source=MyNode('sss')) - assert map(str, r) == ['foo', 'sss', 'bar'], r + assert list(map(str, r)) == ['foo', 'sss', 'bar'], r n = MyObj() @@ -527,13 +601,13 @@ class SubstitutionTestCase(unittest.TestCase): BAR=StringableObj("bar")) r = env.subst_path([ "${FOO}/bar", "${BAR}/baz" ]) - assert r == [ "foo/bar", "bar/baz" ] + assert r == [ "foo/bar", "bar/baz" ], r r = env.subst_path([ "bar/${FOO}", "baz/${BAR}" ]) - assert r == [ "bar/foo", "baz/bar" ] + assert r == [ "bar/foo", "baz/bar" ], r r = env.subst_path([ "bar/${FOO}/bar", "baz/${BAR}/baz" ]) - assert r == [ "bar/foo/bar", "baz/bar/baz" ] + assert r == [ "bar/foo/bar", "baz/bar/baz" ], r def test_subst_target_source(self): """Test the base environment subst_target_source() method""" @@ -541,6 +615,128 @@ class SubstitutionTestCase(unittest.TestCase): mystr = env.subst_target_source("$AAA ${AAA}A $BBBB $BBB") assert mystr == "a aA b", mystr + def test_backtick(self): + """Test the backtick() method for capturing command output""" + env = SubstitutionEnvironment() + + test = TestCmd.TestCmd(workdir = '') + test.write('stdout.py', """\ +import sys +sys.stdout.write('this came from stdout.py\\n') +sys.exit(0) +""") + test.write('stderr.py', """\ +import sys +sys.stderr.write('this came from stderr.py\\n') +sys.exit(0) +""") + test.write('fail.py', """\ +import sys +sys.exit(1) +""") + test.write('echo.py', """\ +import os, sys +sys.stdout.write(os.environ['ECHO'] + '\\n') +sys.exit(0) +""") + + save_stderr = sys.stderr + + python = '"' + sys.executable + '"' + + try: + sys.stderr = StringIO.StringIO() + cmd = '%s %s' % (python, test.workpath('stdout.py')) + output = env.backtick(cmd) + errout = sys.stderr.getvalue() + assert output == 'this came from stdout.py\n', output + assert errout == '', errout + + sys.stderr = StringIO.StringIO() + cmd = '%s %s' % (python, test.workpath('stderr.py')) + output = env.backtick(cmd) + errout = sys.stderr.getvalue() + assert output == '', output + assert errout == 'this came from stderr.py\n', errout + + sys.stderr = StringIO.StringIO() + cmd = '%s %s' % (python, test.workpath('fail.py')) + try: + env.backtick(cmd) + except OSError, e: + assert str(e) == "'%s' exited 1" % cmd, str(e) + else: + self.fail("did not catch expected OSError") + + sys.stderr = StringIO.StringIO() + cmd = '%s %s' % (python, test.workpath('echo.py')) + env['ENV'] = os.environ.copy() + env['ENV']['ECHO'] = 'this came from ECHO' + output = env.backtick(cmd) + errout = sys.stderr.getvalue() + assert output == 'this came from ECHO\n', output + assert errout == '', errout + + finally: + sys.stderr = save_stderr + + def test_AddMethod(self): + """Test the AddMethod() method""" + env = SubstitutionEnvironment(FOO = 'foo') + + def func(self): + return 'func-' + self['FOO'] + + assert not hasattr(env, 'func') + env.AddMethod(func) + r = env.func() + assert r == 'func-foo', r + + assert not hasattr(env, 'bar') + env.AddMethod(func, 'bar') + r = env.bar() + assert r == 'func-foo', r + + def func2(self, arg=''): + return 'func2-' + self['FOO'] + arg + + env.AddMethod(func2) + r = env.func2() + assert r == 'func2-foo', r + r = env.func2('-xxx') + assert r == 'func2-foo-xxx', r + + env.AddMethod(func2, 'func') + r = env.func() + assert r == 'func2-foo', r + r = env.func('-yyy') + assert r == 'func2-foo-yyy', r + + # Test that clones of clones correctly re-bind added methods. + env1 = Environment(FOO = '1') + env1.AddMethod(func2) + env2 = env1.Clone(FOO = '2') + env3 = env2.Clone(FOO = '3') + env4 = env3.Clone(FOO = '4') + r = env1.func2() + assert r == 'func2-1', r + r = env2.func2() + assert r == 'func2-2', r + r = env3.func2() + assert r == 'func2-3', r + r = env4.func2() + assert r == 'func2-4', r + + # Test that clones don't re-bind an attribute that the user + env1 = Environment(FOO = '1') + env1.AddMethod(func2) + def replace_func2(): + return 'replace_func2' + env1.func2 = replace_func2 + env2 = env1.Clone(FOO = '2') + r = env2.func2() + assert r == 'replace_func2', r + def test_Override(self): "Test overriding construction variables" env = SubstitutionEnvironment(ONE=1, TWO=2, THREE=3, FOUR=4) @@ -566,9 +762,140 @@ class SubstitutionTestCase(unittest.TestCase): assert env2['ONE'] == "won", env2['ONE'] assert env['ONE'] == 1, env['ONE'] + def test_ParseFlags(self): + """Test the ParseFlags() method + """ + env = SubstitutionEnvironment() + + empty = { + 'ASFLAGS' : [], + 'CFLAGS' : [], + 'CCFLAGS' : [], + 'CPPDEFINES' : [], + 'CPPFLAGS' : [], + 'CPPPATH' : [], + 'FRAMEWORKPATH' : [], + 'FRAMEWORKS' : [], + 'LIBPATH' : [], + 'LIBS' : [], + 'LINKFLAGS' : [], + 'RPATH' : [], + } + + d = env.ParseFlags(None) + assert d == empty, d + + d = env.ParseFlags('') + assert d == empty, d + + d = env.ParseFlags([]) + assert d == empty, d + + s = "-I/usr/include/fum -I bar -X\n" + \ + '-I"C:\\Program Files\\ASCEND\\include" ' + \ + "-L/usr/fax -L foo -lxxx -l yyy " + \ + '-L"C:\\Program Files\\ASCEND" -lascend ' + \ + "-Wa,-as -Wl,-link " + \ + "-Wl,-rpath=rpath1 " + \ + "-Wl,-R,rpath2 " + \ + "-Wl,-Rrpath3 " + \ + "-Wp,-cpp " + \ + "-std=c99 " + \ + "-framework Carbon " + \ + "-frameworkdir=fwd1 " + \ + "-Ffwd2 " + \ + "-F fwd3 " + \ + "-pthread " + \ + "-mno-cygwin -mwindows " + \ + "-arch i386 -isysroot /tmp +DD64 " + \ + "-DFOO -DBAR=value -D BAZ " + + d = env.ParseFlags(s) + + assert d['ASFLAGS'] == ['-as'], d['ASFLAGS'] + assert d['CFLAGS'] == ['-std=c99'] + assert d['CCFLAGS'] == ['-X', '-Wa,-as', + '-pthread', '-mno-cygwin', + ('-arch', 'i386'), ('-isysroot', '/tmp'), + '+DD64'], d['CCFLAGS'] + assert d['CPPDEFINES'] == ['FOO', ['BAR', 'value'], 'BAZ'], d['CPPDEFINES'] + assert d['CPPFLAGS'] == ['-Wp,-cpp'], d['CPPFLAGS'] + assert d['CPPPATH'] == ['/usr/include/fum', + 'bar', + 'C:\\Program Files\\ASCEND\\include'], d['CPPPATH'] + assert d['FRAMEWORKPATH'] == ['fwd1', 'fwd2', 'fwd3'], d['FRAMEWORKPATH'] + assert d['FRAMEWORKS'] == ['Carbon'], d['FRAMEWORKS'] + assert d['LIBPATH'] == ['/usr/fax', + 'foo', + 'C:\\Program Files\\ASCEND'], d['LIBPATH'] + LIBS = list(map(str, d['LIBS'])) + assert LIBS == ['xxx', 'yyy', 'ascend'], (d['LIBS'], LIBS) + assert d['LINKFLAGS'] == ['-Wl,-link', '-pthread', + '-mno-cygwin', '-mwindows', + ('-arch', 'i386'), + ('-isysroot', '/tmp'), + '+DD64'], d['LINKFLAGS'] + assert d['RPATH'] == ['rpath1', 'rpath2', 'rpath3'], d['RPATH'] + + + def test_MergeFlags(self): + """Test the MergeFlags() method + """ + env = SubstitutionEnvironment() + env.MergeFlags('') + assert 'CCFLAGS' not in env, env['CCFLAGS'] + env.MergeFlags('-X') + assert env['CCFLAGS'] == ['-X'], env['CCFLAGS'] + env.MergeFlags('-X') + assert env['CCFLAGS'] == ['-X'], env['CCFLAGS'] + env = SubstitutionEnvironment(CCFLAGS=None) + env.MergeFlags('-Y') + assert env['CCFLAGS'] == ['-Y'], env['CCFLAGS'] -class BaseTestCase(unittest.TestCase): + env = SubstitutionEnvironment() + env.MergeFlags({'A':['aaa'], 'B':['bbb']}) + assert env['A'] == ['aaa'], env['A'] + assert env['B'] == ['bbb'], env['B'] + +# def test_MergeShellPaths(self): +# """Test the MergeShellPaths() method +# """ +# env = Environment() +# env.MergeShellPaths({}) +# assert not env['ENV'].has_key('INCLUDE'), env['INCLUDE'] +# env.MergeShellPaths({'INCLUDE': r'c:\Program Files\Stuff'}) +# assert env['ENV']['INCLUDE'] == r'c:\Program Files\Stuff', env['ENV']['INCLUDE'] +# env.MergeShellPaths({'INCLUDE': r'c:\Program Files\Stuff'}) +# assert env['ENV']['INCLUDE'] == r'c:\Program Files\Stuff', env['ENV']['INCLUDE'] +# env.MergeShellPaths({'INCLUDE': r'xyz'}) +# assert env['ENV']['INCLUDE'] == r'xyz%sc:\Program Files\Stuff'%os.pathsep, env['ENV']['INCLUDE'] + +# env = Environment() +# env['ENV']['INCLUDE'] = 'xyz' +# env.MergeShellPaths({'INCLUDE':['c:/inc1', 'c:/inc2']} ) +# assert env['ENV']['INCLUDE'] == r'c:/inc1%sc:/inc2%sxyz'%(os.pathsep, os.pathsep), env['ENV']['INCLUDE'] + +# # test prepend=0 +# env = Environment() +# env.MergeShellPaths({'INCLUDE': r'c:\Program Files\Stuff'}, prepend=0) +# assert env['ENV']['INCLUDE'] == r'c:\Program Files\Stuff', env['ENV']['INCLUDE'] +# env.MergeShellPaths({'INCLUDE': r'xyz'}, prepend=0) +# assert env['ENV']['INCLUDE'] == r'c:\Program Files\Stuff%sxyz'%os.pathsep, env['ENV']['INCLUDE'] + + +class BaseTestCase(unittest.TestCase,TestEnvironmentFixture): + + reserved_variables = [ + 'CHANGED_SOURCES', + 'CHANGED_TARGETS', + 'SOURCE', + 'SOURCES', + 'TARGET', + 'TARGETS', + 'UNCHANGED_SOURCES', + 'UNCHANGED_TARGETS', + ] def test___init__(self): """Test construction Environment creation @@ -576,16 +903,34 @@ class BaseTestCase(unittest.TestCase): Create two with identical arguments and check that they compare the same. """ - env1 = Environment(XXX = 'x', YYY = 'y') - env2 = Environment(XXX = 'x', YYY = 'y') + env1 = self.TestEnvironment(XXX = 'x', YYY = 'y') + env2 = self.TestEnvironment(XXX = 'x', YYY = 'y') assert env1 == env2, diff_env(env1, env2) - assert not env1.has_key('__env__') - assert not env2.has_key('__env__') + assert '__env__' not in env1 + assert '__env__' not in env2 + + def test_variables(self): + """Test that variables only get applied once.""" + class FakeOptions: + def __init__(self, key, val): + self.calls = 0 + self.key = key + self.val = val + def keys(self): + return [self.key] + def Update(self, env): + env[self.key] = self.val + self.calls = self.calls + 1 + + o = FakeOptions('AAA', 'fake_opt') + env = Environment(variables=o, AAA='keyword_arg') + assert o.calls == 1, o.calls + assert env['AAA'] == 'fake_opt', env['AAA'] def test_get(self): """Test the get() method.""" - env = Environment(aaa = 'AAA') + env = self.TestEnvironment(aaa = 'AAA') x = env.get('aaa') assert x == 'AAA', x @@ -609,53 +954,80 @@ class BaseTestCase(unittest.TestCase): 'builder2' : b2 }) called_it = {} env.builder1('in1') - assert called_it['target'] == None, called_it + assert called_it['target'] is None, called_it assert called_it['source'] == ['in1'], called_it called_it = {} env.builder2(source = 'in2', xyzzy = 1) - assert called_it['target'] == None, called_it + assert called_it['target'] is None, called_it assert called_it['source'] == ['in2'], called_it assert called_it['xyzzy'] == 1, called_it called_it = {} env.builder1(foo = 'bar') assert called_it['foo'] == 'bar', called_it - assert called_it['target'] == None, called_it - assert called_it['source'] == None, called_it + assert called_it['target'] is None, called_it + assert called_it['source'] is None, called_it + def test_BuilderWrapper_attributes(self): + """Test getting and setting of BuilderWrapper attributes + """ + b1 = Builder() + b2 = Builder() + e1 = Environment() + e2 = Environment() + e1.Replace(BUILDERS = {'b' : b1}) + bw = e1.b - def test_Builder_execs(self): - """Test Builder execution through different environments + assert bw.env is e1 + bw.env = e2 + assert bw.env is e2 - One environment is initialized with a single - Builder object, one with a list of a single Builder - object, and one with a list of two Builder objects. - """ - global built_it + assert bw.builder is b1 + bw.builder = b2 + assert bw.builder is b2 - b1 = Builder() - b2 = Builder() + self.assertRaises(AttributeError, getattr, bw, 'foobar') + bw.foobar = 42 + assert bw.foobar is 42 - built_it = {} + # This unit test is currently disabled because we don't think the + # underlying method it tests (Environment.BuilderWrapper.execute()) + # is necessary, but we're leaving the code here for now in case + # that's mistaken. + def _DO_NOT_test_Builder_execs(self): + """Test Builder execution through different environments + + One environment is initialized with a single + Builder object, one with a list of a single Builder + object, and one with a list of two Builder objects. + """ + global built_it + + b1 = Builder() + b2 = Builder() + + built_it = {} env3 = Environment() env3.Replace(BUILDERS = { 'builder1' : b1, 'builder2' : b2 }) - env3.builder1.execute(target = 'out1') - env3.builder2.execute(target = 'out2') - env3.builder1.execute(target = 'out3') - assert built_it['out1'] - assert built_it['out2'] - assert built_it['out3'] + env3.builder1.execute(target = 'out1') + env3.builder2.execute(target = 'out2') + env3.builder1.execute(target = 'out3') + assert built_it['out1'] + assert built_it['out2'] + assert built_it['out3'] - env4 = env3.Copy() - assert env4.builder1.env is env4, "builder1.env (%s) == env3 (%s)?" % (env4.builder1.env, env3) - assert env4.builder2.env is env4, "builder2.env (%s) == env3 (%s)?" % (env4.builder1.env, env3) + env4 = env3.Clone() + assert env4.builder1.env is env4, "builder1.env (%s) == env3 (%s)?" % ( +env4.builder1.env, env3) + assert env4.builder2.env is env4, "builder2.env (%s) == env3 (%s)?" % ( +env4.builder1.env, env3) # Now test BUILDERS as a dictionary. built_it = {} - env5 = Environment(BUILDERS={ 'foo' : b1 }) + env5 = self.TestEnvironment(BUILDERS={ 'foo' : b1 }) env5['BUILDERS']['bar'] = b2 env5.foo.execute(target='out1') env5.bar.execute(target='out2') @@ -671,6 +1043,8 @@ class BaseTestCase(unittest.TestCase): assert built_it['out1'] assert built_it['out2'] + + def test_Scanners(self): """Test setting SCANNERS in various ways @@ -683,16 +1057,17 @@ class BaseTestCase(unittest.TestCase): s1 = Scanner(name = 'scanner1', skeys = [".c", ".cc"]) s2 = Scanner(name = 'scanner2', skeys = [".m4"]) s3 = Scanner(name = 'scanner3', skeys = [".m4", ".m5"]) + s4 = Scanner(name = 'scanner4', skeys = [None]) # XXX Tests for scanner execution through different environments, # XXX if we ever want to do that some day # scanned_it = {} -# env1 = Environment(SCANNERS = s1) +# env1 = self.TestEnvironment(SCANNERS = s1) # env1.scanner1(filename = 'out1') # assert scanned_it['out1'] # # scanned_it = {} -# env2 = Environment(SCANNERS = [s1]) +# env2 = self.TestEnvironment(SCANNERS = [s1]) # env1.scanner1(filename = 'out1') # assert scanned_it['out1'] # @@ -708,64 +1083,126 @@ class BaseTestCase(unittest.TestCase): suffixes = [".c", ".cc", ".cxx", ".m4", ".m5"] - env = Environment(SCANNERS = []) - s = map(env.get_scanner, suffixes) + env = Environment() + try: del env['SCANNERS'] + except KeyError: pass + s = list(map(env.get_scanner, suffixes)) + assert s == [None, None, None, None, None], s + + env = self.TestEnvironment(SCANNERS = []) + s = list(map(env.get_scanner, suffixes)) assert s == [None, None, None, None, None], s env.Replace(SCANNERS = [s1]) - s = map(env.get_scanner, suffixes) + s = list(map(env.get_scanner, suffixes)) assert s == [s1, s1, None, None, None], s env.Append(SCANNERS = [s2]) - s = map(env.get_scanner, suffixes) + s = list(map(env.get_scanner, suffixes)) assert s == [s1, s1, None, s2, None], s env.AppendUnique(SCANNERS = [s3]) - s = map(env.get_scanner, suffixes) + s = list(map(env.get_scanner, suffixes)) assert s == [s1, s1, None, s2, s3], s - env = env.Copy(SCANNERS = [s2]) - s = map(env.get_scanner, suffixes) + env = env.Clone(SCANNERS = [s2]) + s = list(map(env.get_scanner, suffixes)) assert s == [None, None, None, s2, None], s env['SCANNERS'] = [s1] - s = map(env.get_scanner, suffixes) + s = list(map(env.get_scanner, suffixes)) assert s == [s1, s1, None, None, None], s env.PrependUnique(SCANNERS = [s2, s1]) - s = map(env.get_scanner, suffixes) + s = list(map(env.get_scanner, suffixes)) assert s == [s1, s1, None, s2, None], s env.Prepend(SCANNERS = [s3]) - s = map(env.get_scanner, suffixes) + s = list(map(env.get_scanner, suffixes)) assert s == [s1, s1, None, s3, s3], s + # Verify behavior of case-insensitive suffix matches on Windows. + uc_suffixes = [_.upper() for _ in suffixes] + + env = Environment(SCANNERS = [s1, s2, s3], + PLATFORM = 'linux') + + s = list(map(env.get_scanner, suffixes)) + assert s == [s1, s1, None, s2, s3], s + + s = list(map(env.get_scanner, uc_suffixes)) + assert s == [None, None, None, None, None], s + + env['PLATFORM'] = 'win32' + + s = list(map(env.get_scanner, uc_suffixes)) + assert s == [s1, s1, None, s2, s3], s + + # Verify behavior for a scanner returning None (on Windows + # where we might try to perform case manipulation on None). + env.Replace(SCANNERS = [s4]) + s = list(map(env.get_scanner, suffixes)) + assert s == [None, None, None, None, None], s + def test_ENV(self): - """Test setting the external ENV in Environments - """ - env = Environment() - assert env.Dictionary().has_key('ENV') + """Test setting the external ENV in Environments + """ + env = Environment() + assert 'ENV' in env.Dictionary() - env = Environment(ENV = { 'PATH' : '/foo:/bar' }) - assert env.Dictionary('ENV')['PATH'] == '/foo:/bar' + env = self.TestEnvironment(ENV = { 'PATH' : '/foo:/bar' }) + assert env.Dictionary('ENV')['PATH'] == '/foo:/bar' def test_ReservedVariables(self): - """Test generation of warnings when reserved variable names - are set in an environment.""" + """Test warning generation when reserved variable names are set""" + + reserved_variables = [ + 'CHANGED_SOURCES', + 'CHANGED_TARGETS', + 'SOURCE', + 'SOURCES', + 'TARGET', + 'TARGETS', + 'UNCHANGED_SOURCES', + 'UNCHANGED_TARGETS', + ] - SCons.Warnings.enableWarningClass(SCons.Warnings.ReservedVariableWarning) + warning = SCons.Warnings.ReservedVariableWarning + SCons.Warnings.enableWarningClass(warning) old = SCons.Warnings.warningAsException(1) try: env4 = Environment() - for kw in ['TARGET', 'TARGETS', 'SOURCE', 'SOURCES']: + for kw in self.reserved_variables: exc_caught = None try: env4[kw] = 'xyzzy' - except SCons.Warnings.ReservedVariableWarning: + except warning: exc_caught = 1 assert exc_caught, "Did not catch ReservedVariableWarning for `%s'" % kw - assert not env4.has_key(kw), "`%s' variable was incorrectly set" % kw + assert kw not in env4, "`%s' variable was incorrectly set" % kw + finally: + SCons.Warnings.warningAsException(old) + + def test_FutureReservedVariables(self): + """Test warning generation when future reserved variable names are set""" + + future_reserved_variables = [] + + warning = SCons.Warnings.FutureReservedVariableWarning + SCons.Warnings.enableWarningClass(warning) + old = SCons.Warnings.warningAsException(1) + + try: + env4 = Environment() + for kw in future_reserved_variables: + exc_caught = None + try: + env4[kw] = 'xyzzy' + except warning: + exc_caught = 1 + assert exc_caught, "Did not catch FutureReservedVariableWarning for `%s'" % kw + assert kw in env4, "`%s' variable was not set" % kw finally: SCons.Warnings.warningAsException(old) @@ -788,128 +1225,91 @@ class BaseTestCase(unittest.TestCase): def test_autogenerate(dict): """Test autogenerating variables in a dictionary.""" - def RDirs(pathlist): - return SCons.Node.FS.default_fs.Rsearchall(pathlist, - clazz=SCons.Node.FS.Dir, - must_exist=0, - cwd=SCons.Node.FS.default_fs.Dir('xx')) + drive, p = os.path.splitdrive(os.getcwd()) + def normalize_path(path, drive=drive): + if path[0] in '\\/': + path = drive + path + path = os.path.normpath(path) + drive, path = os.path.splitdrive(path) + return drive.lower() + path - env = Environment(LIBS = [ 'foo', 'bar', 'baz' ], + env = dict.TestEnvironment(LIBS = [ 'foo', 'bar', 'baz' ], LIBLINKPREFIX = 'foo', - LIBLINKSUFFIX = 'bar', - RDirs=RDirs) + LIBLINKSUFFIX = 'bar') + + def RDirs(pathlist, fs=env.fs): + return fs.Dir('xx').Rfindalldirs(pathlist) + + env['RDirs'] = RDirs flags = env.subst_list('$_LIBFLAGS', 1)[0] - assert len(flags) == 3, flags - assert flags[0] == 'foobar', \ - flags[0] - assert flags[1] == 'foobar', \ - flags[1] - assert flags[2] == 'foobazbar', \ - flags[2] - - blat = SCons.Node.FS.default_fs.Dir('blat') - - env = Environment(CPPPATH = [ 'foo', '$FOO/bar', blat ], - INCPREFIX = 'foo ', - INCSUFFIX = 'bar', - FOO = 'baz', - RDirs=RDirs) + assert flags == ['foobar', 'foobar', 'foobazbar'], flags + + blat = env.fs.Dir('blat') + + env.Replace(CPPPATH = [ 'foo', '$FOO/bar', blat ], + INCPREFIX = 'foo ', + INCSUFFIX = 'bar', + FOO = 'baz') flags = env.subst_list('$_CPPINCFLAGS', 1)[0] - assert len(flags) == 8, flags - assert flags[0] == '$(', \ - flags[0] - assert flags[1] == os.path.normpath('foo'), \ - flags[1] - assert flags[2] == os.path.normpath('xx/foobar'), \ - flags[2] - assert flags[3] == os.path.normpath('foo'), \ - flags[3] - assert flags[4] == os.path.normpath('xx/baz/bar'), \ - flags[4] - assert flags[5] == os.path.normpath('foo'), \ - flags[5] - assert flags[6] == os.path.normpath('blatbar'), \ - flags[6] - assert flags[7] == '$)', \ - flags[7] - - env = Environment(F77PATH = [ 'foo', '$FOO/bar', blat ], - INCPREFIX = 'foo ', - INCSUFFIX = 'bar', - FOO = 'baz', - RDirs=RDirs) + expect = [ '$(', + normalize_path('foo'), + normalize_path('xx/foobar'), + normalize_path('foo'), + normalize_path('xx/baz/bar'), + normalize_path('foo'), + normalize_path('blatbar'), + '$)', + ] + assert flags == expect, flags + + env.Replace(F77PATH = [ 'foo', '$FOO/bar', blat ], + INCPREFIX = 'foo ', + INCSUFFIX = 'bar', + FOO = 'baz') flags = env.subst_list('$_F77INCFLAGS', 1)[0] - assert len(flags) == 8, flags - assert flags[0] == '$(', \ - flags[0] - assert flags[1] == os.path.normpath('foo'), \ - flags[1] - assert flags[2] == os.path.normpath('xx/foobar'), \ - flags[2] - assert flags[3] == os.path.normpath('foo'), \ - flags[3] - assert flags[4] == os.path.normpath('xx/baz/bar'), \ - flags[4] - assert flags[5] == os.path.normpath('foo'), \ - flags[5] - assert flags[6] == os.path.normpath('blatbar'), \ - flags[6] - assert flags[7] == '$)', \ - flags[7] - - env = Environment(CPPPATH = '', F77PATH = '', LIBPATH = '', - RDirs=RDirs) + expect = [ '$(', + normalize_path('foo'), + normalize_path('xx/foobar'), + normalize_path('foo'), + normalize_path('xx/baz/bar'), + normalize_path('foo'), + normalize_path('blatbar'), + '$)', + ] + assert flags == expect, flags + + env.Replace(CPPPATH = '', F77PATH = '', LIBPATH = '') l = env.subst_list('$_CPPINCFLAGS') - assert len(l[0]) == 0, l[0] + assert l == [[]], l l = env.subst_list('$_F77INCFLAGS') - assert len(l[0]) == 0, l[0] + assert l == [[]], l l = env.subst_list('$_LIBDIRFLAGS') - assert len(l[0]) == 0, l[0] - - SCons.Node.FS.default_fs.Repository('/rep1') - SCons.Node.FS.default_fs.Repository('/rep2') - env = Environment(CPPPATH = [ 'foo', '/a/b', '$FOO/bar', blat], - INCPREFIX = '-I ', - INCSUFFIX = 'XXX', - FOO = 'baz', - RDirs=RDirs) + assert l == [[]], l + + env.fs.Repository('/rep1') + env.fs.Repository('/rep2') + env.Replace(CPPPATH = [ 'foo', '/a/b', '$FOO/bar', blat], + INCPREFIX = '-I ', + INCSUFFIX = 'XXX', + FOO = 'baz') flags = env.subst_list('$_CPPINCFLAGS', 1)[0] - assert flags[0] == '$(', \ - flags[0] - assert flags[1] == '-I', \ - flags[1] - assert flags[2] == os.path.normpath('xx/fooXXX'), \ - flags[2] - assert flags[3] == '-I', \ - flags[3] - assert flags[4] == os.path.normpath('/rep1/xx/fooXXX'), \ - flags[4] - assert flags[5] == '-I', \ - flags[5] - assert flags[6] == os.path.normpath('/rep2/xx/fooXXX'), \ - flags[6] - assert flags[7] == '-I', \ - flags[7] - assert flags[8] == os.path.normpath('/a/bXXX'), \ - flags[8] - assert flags[9] == '-I', \ - flags[9] - assert flags[10] == os.path.normpath('xx/baz/barXXX'), \ - flags[10] - assert flags[11] == '-I', \ - flags[11] - assert flags[12] == os.path.normpath('/rep1/xx/baz/barXXX'), \ - flags[12] - assert flags[13] == '-I', \ - flags[13] - assert flags[14] == os.path.normpath('/rep2/xx/baz/barXXX'), \ - flags[14] - assert flags[15] == '-I', \ - flags[15] - assert flags[16] == os.path.normpath('blatXXX'), \ - flags[16] - assert flags[17] == '$)', \ - flags[17] + expect = [ '$(', + '-I', normalize_path('xx/fooXXX'), + '-I', normalize_path('/rep1/xx/fooXXX'), + '-I', normalize_path('/rep2/xx/fooXXX'), + '-I', normalize_path('/a/bXXX'), + '-I', normalize_path('xx/baz/barXXX'), + '-I', normalize_path('/rep1/xx/baz/barXXX'), + '-I', normalize_path('/rep2/xx/baz/barXXX'), + '-I', normalize_path('blatXXX'), + '$)' + ] + def normalize_if_path(arg, np=normalize_path): + if arg not in ('$(','$)','-I'): + return np(str(arg)) + return arg + flags = list(map(normalize_if_path, flags)) + assert flags == expect, flags def test_platform(self): """Test specifying a platform callable when instantiating.""" @@ -921,7 +1321,7 @@ class BaseTestCase(unittest.TestCase): env['SET_TOOL'] = 'initialized' assert env['PLATFORM'] == "TestPlatform" - env = Environment(platform = platform(), tools = [tool]) + env = self.TestEnvironment(platform = platform(), tools = [tool]) assert env['XYZZY'] == 777, env assert env['PLATFORM'] == "TestPlatform" assert env['SET_TOOL'] == "initialized" @@ -943,7 +1343,7 @@ class BaseTestCase(unittest.TestCase): SCons.Defaults.ConstructionEnvironment.update({ 'PLATFORM' : platform(), }) - env = Environment(tools = [tool]) + env = self.TestEnvironment(tools = [tool]) assert env['XYZZY'] == 888, env assert env['PLATFORM'] == "DefaultTestPlatform" assert env['SET_TOOL'] == "abcde" @@ -960,7 +1360,7 @@ class BaseTestCase(unittest.TestCase): env['AAA'] = env['XYZ'] def t4(env): env['TOOL4'] = 444 - env = Environment(tools = [t1, t2, t3], XYZ = 'aaa') + env = self.TestEnvironment(tools = [t1, t2, t3], XYZ = 'aaa') assert env['TOOL1'] == 111, env['TOOL1'] assert env['TOOL2'] == 222, env assert env['AAA'] == 'aaa', env @@ -977,7 +1377,7 @@ def exists(env): return 1 """) - env = Environment(tools = [('faketool', {'a':1, 'b':2, 'c':3})], + env = self.TestEnvironment(tools = [('faketool', {'a':1, 'b':2, 'c':3})], toolpath = [test.workpath('')]) assert env['a'] == 1, env['a'] assert env['b'] == 2, env['b'] @@ -1015,20 +1415,20 @@ def exists(env): env['TOOL1'] = 111 def t2(env): env['TOOL2'] = 222 - env = Environment(tools = [t1, None, t2], XYZ = 'aaa') + env = self.TestEnvironment(tools = [t1, None, t2], XYZ = 'aaa') assert env['TOOL1'] == 111, env['TOOL1'] assert env['TOOL2'] == 222, env assert env['XYZ'] == 'aaa', env - env = Environment(tools = [None], XYZ = 'xyz') + env = self.TestEnvironment(tools = [None], XYZ = 'xyz') assert env['XYZ'] == 'xyz', env - env = Environment(tools = [t1, '', t2], XYZ = 'ddd') + env = self.TestEnvironment(tools = [t1, '', t2], XYZ = 'ddd') assert env['TOOL1'] == 111, env['TOOL1'] assert env['TOOL2'] == 222, env assert env['XYZ'] == 'ddd', env def test_concat(self): "Test _concat()" - e1 = Environment(PRE='pre', SUF='suf', STR='a b', LIST=['a', 'b']) + e1 = self.TestEnvironment(PRE='pre', SUF='suf', STR='a b', LIST=['a', 'b']) s = e1.subst x = s("${_concat('', '', '', __env__)}") assert x == '', x @@ -1043,7 +1443,7 @@ def exists(env): def test_gvars(self): """Test the Environment gvars() method""" - env = Environment(XXX = 'x', YYY = 'y', ZZZ = 'z') + env = self.TestEnvironment(XXX = 'x', YYY = 'y', ZZZ = 'z') gvars = env.gvars() assert gvars['XXX'] == 'x', gvars['XXX'] assert gvars['YYY'] == 'y', gvars['YYY'] @@ -1051,7 +1451,7 @@ def exists(env): def test__update(self): """Test the _update() method""" - env = Environment(X = 'x', Y = 'y', Z = 'z') + env = self.TestEnvironment(X = 'x', Y = 'y', Z = 'z') assert env['X'] == 'x', env['X'] assert env['Y'] == 'y', env['Y'] assert env['Z'] == 'z', env['Z'] @@ -1079,6 +1479,8 @@ def exists(env): b2 = Environment()['BUILDERS'] assert b1 == b2, diff_dict(b1, b2) + import UserDict + UD = UserDict.UserDict import UserList UL = UserList.UserList @@ -1110,6 +1512,18 @@ def exists(env): UL(['i7']), [''], UL(['i7', '']), UL(['i8']), UL(['']), UL(['i8', '']), + {'d1':1}, 'D1', {'d1':1, 'D1':None}, + {'d2':1}, ['D2'], {'d2':1, 'D2':None}, + {'d3':1}, UL(['D3']), {'d3':1, 'D3':None}, + {'d4':1}, {'D4':1}, {'d4':1, 'D4':1}, + {'d5':1}, UD({'D5':1}), UD({'d5':1, 'D5':1}), + + UD({'u1':1}), 'U1', UD({'u1':1, 'U1':None}), + UD({'u2':1}), ['U2'], UD({'u2':1, 'U2':None}), + UD({'u3':1}), UL(['U3']), UD({'u3':1, 'U3':None}), + UD({'u4':1}), {'U4':1}, UD({'u4':1, 'U4':1}), + UD({'u5':1}), UD({'U5':1}), UD({'u5':1, 'U5':1}), + '', 'M1', 'M1', '', ['M2'], ['M2'], '', UL(['M3']), UL(['M3']), @@ -1160,14 +1574,21 @@ def exists(env): failed = 0 while cases: input, append, expect = cases[:3] - env['XXX'] = input - env.Append(XXX = append) - result = env['XXX'] - if result != expect: + env['XXX'] = copy.copy(input) + try: + env.Append(XXX = append) + except Exception, e: if failed == 0: print - print " %s Append %s => %s did not match %s" % \ - (repr(input), repr(append), repr(result), repr(expect)) + print " %s Append %s exception: %s" % \ + (repr(input), repr(append), e) failed = failed + 1 + else: + result = env['XXX'] + if result != expect: + if failed == 0: print + print " %s Append %s => %s did not match %s" % \ + (repr(input), repr(append), repr(result), repr(expect)) + failed = failed + 1 del cases[:3] assert failed == 0, "%d Append() cases failed" % failed @@ -1193,80 +1614,140 @@ def exists(env): ccc = C('ccc') - env2 = Environment(CCC1 = ['c1'], CCC2 = ccc) + env2 = self.TestEnvironment(CCC1 = ['c1'], CCC2 = ccc) env2.Append(CCC1 = ccc, CCC2 = ['c2']) assert env2['CCC1'][0] == 'c1', env2['CCC1'] assert env2['CCC1'][1] is ccc, env2['CCC1'] assert env2['CCC2'][0] is ccc, env2['CCC2'] assert env2['CCC2'][1] == 'c2', env2['CCC2'] - env3 = Environment(X = {'x1' : 7}) + env3 = self.TestEnvironment(X = {'x1' : 7}) env3.Append(X = {'x1' : 8, 'x2' : 9}, Y = {'y1' : 10}) assert env3['X'] == {'x1': 8, 'x2': 9}, env3['X'] assert env3['Y'] == {'y1': 10}, env3['Y'] - env4 = Environment(BUILDERS = {'z1' : 11}) - env4.Append(BUILDERS = {'z2' : 12}) - assert env4['BUILDERS'] == {'z1' : 11, 'z2' : 12}, env4['BUILDERS'] + z1 = Builder() + z2 = Builder() + env4 = self.TestEnvironment(BUILDERS = {'z1' : z1}) + env4.Append(BUILDERS = {'z2' : z2}) + assert env4['BUILDERS'] == {'z1' : z1, 'z2' : z2}, env4['BUILDERS'] assert hasattr(env4, 'z1') assert hasattr(env4, 'z2') def test_AppendENVPath(self): """Test appending to an ENV path.""" - env1 = Environment(ENV = {'PATH': r'C:\dir\num\one;C:\dir\num\two'}, + env1 = self.TestEnvironment(ENV = {'PATH': r'C:\dir\num\one;C:\dir\num\two'}, MYENV = {'MYPATH': r'C:\mydir\num\one;C:\mydir\num\two'}) # have to include the pathsep here so that the test will work on UNIX too. env1.AppendENVPath('PATH',r'C:\dir\num\two', sep = ';') env1.AppendENVPath('PATH',r'C:\dir\num\three', sep = ';') env1.AppendENVPath('MYPATH',r'C:\mydir\num\three','MYENV', sep = ';') env1.AppendENVPath('MYPATH',r'C:\mydir\num\one','MYENV', sep = ';') + # this should do nothing since delete_existing is 0 + env1.AppendENVPath('MYPATH',r'C:\mydir\num\three','MYENV', sep = ';', delete_existing=0) assert(env1['ENV']['PATH'] == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three') assert(env1['MYENV']['MYPATH'] == r'C:\mydir\num\two;C:\mydir\num\three;C:\mydir\num\one') + test = TestCmd.TestCmd(workdir = '') + test.subdir('sub1', 'sub2') + p=env1['ENV']['PATH'] + env1.AppendENVPath('PATH','#sub1', sep = ';') + env1.AppendENVPath('PATH',env1.fs.Dir('sub2'), sep = ';') + assert env1['ENV']['PATH'] == p + ';sub1;sub2', env1['ENV']['PATH'] + def test_AppendUnique(self): """Test appending to unique values to construction variables This strips values that are already present when lists are involved.""" - env = Environment(AAA1 = 'a1', + env = self.TestEnvironment(AAA1 = 'a1', AAA2 = 'a2', AAA3 = 'a3', + AAA4 = 'a4', + AAA5 = 'a5', BBB1 = ['b1'], BBB2 = ['b2'], BBB3 = ['b3'], + BBB4 = ['b4'], + BBB5 = ['b5'], CCC1 = '', - CCC2 = '') + CCC2 = '', + DDD1 = ['a', 'b', 'c']) env.AppendUnique(AAA1 = 'a1', AAA2 = ['a2'], - AAA3 = ['a3', 'b', 'c', 'a3'], + AAA3 = ['a3', 'b', 'c', 'c', 'b', 'a3'], # ignore dups + AAA4 = 'a4.new', + AAA5 = ['a5.new'], BBB1 = 'b1', BBB2 = ['b2'], - BBB3 = ['b3', 'c', 'd', 'b3'], + BBB3 = ['b3', 'c', 'd', 'c', 'b3'], + BBB4 = 'b4.new', + BBB5 = ['b5.new'], CCC1 = 'c1', - CCC2 = ['c2']) + CCC2 = ['c2'], + DDD1 = 'b') assert env['AAA1'] == 'a1a1', env['AAA1'] assert env['AAA2'] == ['a2'], env['AAA2'] assert env['AAA3'] == ['a3', 'b', 'c'], env['AAA3'] + assert env['AAA4'] == 'a4a4.new', env['AAA4'] + assert env['AAA5'] == ['a5', 'a5.new'], env['AAA5'] assert env['BBB1'] == ['b1'], env['BBB1'] assert env['BBB2'] == ['b2'], env['BBB2'] assert env['BBB3'] == ['b3', 'c', 'd'], env['BBB3'] + assert env['BBB4'] == ['b4', 'b4.new'], env['BBB4'] + assert env['BBB5'] == ['b5', 'b5.new'], env['BBB5'] assert env['CCC1'] == 'c1', env['CCC1'] assert env['CCC2'] == ['c2'], env['CCC2'] + assert env['DDD1'] == ['a', 'b', 'c'], env['DDD1'] + + env.AppendUnique(DDD1 = 'b', delete_existing=1) + assert env['DDD1'] == ['a', 'c', 'b'], env['DDD1'] # b moves to end + env.AppendUnique(DDD1 = ['a','b'], delete_existing=1) + assert env['DDD1'] == ['c', 'a', 'b'], env['DDD1'] # a & b move to end + env.AppendUnique(DDD1 = ['e','f', 'e'], delete_existing=1) + assert env['DDD1'] == ['c', 'a', 'b', 'f', 'e'], env['DDD1'] # add last + + env['CLVar'] = CLVar([]) + env.AppendUnique(CLVar = 'bar') + result = env['CLVar'] + if sys.version[0] == '1' or sys.version[:3] == '2.0': + # Python 2.0 and before have a quirky behavior where CLVar([]) + # actually matches '' and [] due to different __coerce__() + # semantics in the UserList implementation. It isn't worth a + # lot of effort to get this corner case to work identically + # (support for Python 1.5 support will die soon anyway), + # so just treat it separately for now. + assert result == 'bar', result + else: + assert isinstance(result, CLVar), repr(result) + assert result == ['bar'], result - def test_Copy(self): - """Test construction Environment copying + env['CLVar'] = CLVar(['abc']) + env.AppendUnique(CLVar = 'bar') + result = env['CLVar'] + assert isinstance(result, CLVar), repr(result) + assert result == ['abc', 'bar'], result + + env['CLVar'] = CLVar(['bar']) + env.AppendUnique(CLVar = 'bar') + result = env['CLVar'] + assert isinstance(result, CLVar), repr(result) + assert result == ['bar'], result + + def test_Clone(self): + """Test construction environment copying Update the copy independently afterwards and check that the original remains intact (that is, no dangling references point to objects in the copied environment). - Copy the original with some construction variable + Clone the original with some construction variable updates and check that the original remains intact and the copy has the updated values. """ - env1 = Environment(XXX = 'x', YYY = 'y') - env2 = env1.Copy() - env1copy = env1.Copy() + env1 = self.TestEnvironment(XXX = 'x', YYY = 'y') + env2 = env1.Clone() + env1copy = env1.Clone() assert env1copy == env1copy assert env2 == env2 env2.Replace(YYY = 'yyy') @@ -1274,7 +1755,7 @@ def exists(env): assert env1 != env2 assert env1 == env1copy - env3 = env1.Copy(XXX = 'x3', ZZZ = 'z3') + env3 = env1.Clone(XXX = 'x3', ZZZ = 'z3') assert env3 == env3 assert env3.Dictionary('XXX') == 'x3' assert env3.Dictionary('YYY') == 'y' @@ -1285,38 +1766,38 @@ def exists(env): # deep copied, but not instances. class TestA: pass - env1 = Environment(XXX=TestA(), YYY = [ 1, 2, 3 ], + env1 = self.TestEnvironment(XXX=TestA(), YYY = [ 1, 2, 3 ], ZZZ = { 1:2, 3:4 }) - env2=env1.Copy() + env2=env1.Clone() env2.Dictionary('YYY').append(4) env2.Dictionary('ZZZ')[5] = 6 assert env1.Dictionary('XXX') is env2.Dictionary('XXX') assert 4 in env2.Dictionary('YYY') assert not 4 in env1.Dictionary('YYY') - assert env2.Dictionary('ZZZ').has_key(5) - assert not env1.Dictionary('ZZZ').has_key(5) + assert 5 in env2.Dictionary('ZZZ') + assert 5 not in env1.Dictionary('ZZZ') # - env1 = Environment(BUILDERS = {'b1' : 1}) + env1 = self.TestEnvironment(BUILDERS = {'b1' : Builder()}) assert hasattr(env1, 'b1'), "env1.b1 was not set" - assert env1.b1.env == env1, "b1.env doesn't point to env1" - env2 = env1.Copy(BUILDERS = {'b2' : 2}) + assert env1.b1.object == env1, "b1.object doesn't point to env1" + env2 = env1.Clone(BUILDERS = {'b2' : Builder()}) assert env2 is env2 assert env2 == env2 assert hasattr(env1, 'b1'), "b1 was mistakenly cleared from env1" - assert env1.b1.env == env1, "b1.env was changed" + assert env1.b1.object == env1, "b1.object was changed" assert not hasattr(env2, 'b1'), "b1 was not cleared from env2" assert hasattr(env2, 'b2'), "env2.b2 was not set" - assert env2.b2.env == env2, "b2.env doesn't point to env2" + assert env2.b2.object == env2, "b2.object doesn't point to env2" # Ensure that specifying new tools in a copied environment # works. def foo(env): env['FOO'] = 1 def bar(env): env['BAR'] = 2 def baz(env): env['BAZ'] = 3 - env1 = Environment(tools=[foo]) - env2 = env1.Copy() - env3 = env1.Copy(tools=[bar, baz]) + env1 = self.TestEnvironment(tools=[foo]) + env2 = env1.Clone() + env3 = env1.Clone(tools=[bar, baz]) assert env1.get('FOO') is 1 assert env1.get('BAR') is None @@ -1330,8 +1811,8 @@ def exists(env): # Ensure that recursive variable substitution when copying # environments works properly. - env1 = Environment(CCFLAGS = '-DFOO', XYZ = '-DXYZ') - env2 = env1.Copy(CCFLAGS = '$CCFLAGS -DBAR', + env1 = self.TestEnvironment(CCFLAGS = '-DFOO', XYZ = '-DXYZ') + env2 = env1.Clone(CCFLAGS = '$CCFLAGS -DBAR', XYZ = ['-DABC', 'x $XYZ y', '-DDEF']) x = env2.get('CCFLAGS') assert x == '-DFOO -DBAR', x @@ -1340,14 +1821,68 @@ def exists(env): # Ensure that special properties of a class don't get # lost on copying. - env1 = Environment(FLAGS = CLVar('flag1 flag2')) + env1 = self.TestEnvironment(FLAGS = CLVar('flag1 flag2')) x = env1.get('FLAGS') assert x == ['flag1', 'flag2'], x - env2 = env1.Copy() + env2 = env1.Clone() env2.Append(FLAGS = 'flag3 flag4') x = env2.get('FLAGS') assert x == ['flag1', 'flag2', 'flag3', 'flag4'], x + # Test that the environment stores the toolpath and + # re-uses it for copies. + test = TestCmd.TestCmd(workdir = '') + + test.write('xxx.py', """\ +def exists(env): + 1 +def generate(env): + env['XXX'] = 'one' +""") + + test.write('yyy.py', """\ +def exists(env): + 1 +def generate(env): + env['YYY'] = 'two' +""") + + env = self.TestEnvironment(tools=['xxx'], toolpath=[test.workpath('')]) + assert env['XXX'] == 'one', env['XXX'] + env = env.Clone(tools=['yyy']) + assert env['YYY'] == 'two', env['YYY'] + + + # Test that + real_value = [4] + + def my_tool(env, rv=real_value): + assert env['KEY_THAT_I_WANT'] == rv[0] + env['KEY_THAT_I_WANT'] = rv[0] + 1 + + env = self.TestEnvironment() + + real_value[0] = 5 + env = env.Clone(KEY_THAT_I_WANT=5, tools=[my_tool]) + assert env['KEY_THAT_I_WANT'] == real_value[0], env['KEY_THAT_I_WANT'] + + real_value[0] = 6 + env = env.Clone(KEY_THAT_I_WANT=6, tools=[my_tool]) + assert env['KEY_THAT_I_WANT'] == real_value[0], env['KEY_THAT_I_WANT'] + + + def test_Copy(self): + """Test copying using the old env.Copy() method""" + env1 = self.TestEnvironment(XXX = 'x', YYY = 'y') + env2 = env1.Copy() + env1copy = env1.Copy() + assert env1copy == env1copy + assert env2 == env2 + env2.Replace(YYY = 'yyy') + assert env2 == env2 + assert env1 != env2 + assert env1 == env1copy + def test_Detect(self): """Test Detect()ing tools""" test = TestCmd.TestCmd(workdir = '') @@ -1359,14 +1894,14 @@ def exists(env): test.write(['sub1', 'xxx'], "sub1/xxx\n") test.write(['sub2', 'xxx'], "sub2/xxx\n") - env = Environment(ENV = { 'PATH' : [sub1, sub2] }) + env = self.TestEnvironment(ENV = { 'PATH' : [sub1, sub2] }) x = env.Detect('xxx.exe') assert x is None, x test.write(['sub2', 'xxx.exe'], "sub2/xxx.exe\n") - env = Environment(ENV = { 'PATH' : [sub1, sub2] }) + env = self.TestEnvironment(ENV = { 'PATH' : [sub1, sub2] }) x = env.Detect('xxx.exe') assert x == 'xxx.exe', x @@ -1380,7 +1915,7 @@ def exists(env): test.write(['sub1', 'xxx.exe'], "sub1/xxx.exe\n") test.write(['sub2', 'xxx.exe'], "sub2/xxx.exe\n") - env = Environment(ENV = { 'PATH' : [sub1, sub2] }) + env = self.TestEnvironment(ENV = { 'PATH' : [sub1, sub2] }) x = env.Detect('xxx.exe') assert x is None, x @@ -1388,7 +1923,7 @@ def exists(env): sub2_xxx_exe = test.workpath('sub2', 'xxx.exe') os.chmod(sub2_xxx_exe, 0755) - env = Environment(ENV = { 'PATH' : [sub1, sub2] }) + env = self.TestEnvironment(ENV = { 'PATH' : [sub1, sub2] }) x = env.Detect('xxx.exe') assert x == 'xxx.exe', x @@ -1399,37 +1934,37 @@ def exists(env): x = env.Detect('xxx.exe') assert x == 'xxx.exe', x - env = Environment(ENV = { 'PATH' : [] }) + env = self.TestEnvironment(ENV = { 'PATH' : [] }) x = env.Detect('xxx.exe') assert x is None, x def test_Dictionary(self): - """Test retrieval of known construction variables - - Fetch them from the Dictionary and check for well-known - defaults that get inserted. - """ - env = Environment(XXX = 'x', YYY = 'y', ZZZ = 'z') - assert env.Dictionary('XXX') == 'x' - assert env.Dictionary('YYY') == 'y' - assert env.Dictionary('XXX', 'ZZZ') == ['x', 'z'] - xxx, zzz = env.Dictionary('XXX', 'ZZZ') - assert xxx == 'x' - assert zzz == 'z' - assert env.Dictionary().has_key('BUILDERS') - assert env.Dictionary().has_key('CC') - assert env.Dictionary().has_key('CCFLAGS') - assert env.Dictionary().has_key('ENV') - - assert env['XXX'] == 'x' - env['XXX'] = 'foo' - assert env.Dictionary('XXX') == 'foo' - del env['XXX'] - assert not env.Dictionary().has_key('XXX') + """Test retrieval of known construction variables + + Fetch them from the Dictionary and check for well-known + defaults that get inserted. + """ + env = self.TestEnvironment(XXX = 'x', YYY = 'y', ZZZ = 'z') + assert env.Dictionary('XXX') == 'x' + assert env.Dictionary('YYY') == 'y' + assert env.Dictionary('XXX', 'ZZZ') == ['x', 'z'] + xxx, zzz = env.Dictionary('XXX', 'ZZZ') + assert xxx == 'x' + assert zzz == 'z' + assert 'BUILDERS' in env.Dictionary() + assert 'CC' in env.Dictionary() + assert 'CCFLAGS' in env.Dictionary() + assert 'ENV' in env.Dictionary() + + assert env['XXX'] == 'x' + env['XXX'] = 'foo' + assert env.Dictionary('XXX') == 'foo' + del env['XXX'] + assert 'XXX' not in env.Dictionary() def test_FindIxes(self): "Test FindIxes()" - env = Environment(LIBPREFIX='lib', + env = self.TestEnvironment(LIBPREFIX='lib', LIBSUFFIX='.a', SHLIBPREFIX='lib', SHLIBSUFFIX='.so', @@ -1441,62 +1976,84 @@ def exists(env): assert paths[0] == env.FindIxes(paths, 'LIBPREFIX', 'LIBSUFFIX') assert paths[1] == env.FindIxes(paths, 'SHLIBPREFIX', 'SHLIBSUFFIX') - assert None == env.FindIxes(paths, 'PREFIX', 'POST') + assert None is env.FindIxes(paths, 'PREFIX', 'POST') paths = ['libfoo.a', 'prefoopost'] assert paths[0] == env.FindIxes(paths, 'LIBPREFIX', 'LIBSUFFIX') - assert None == env.FindIxes(paths, 'SHLIBPREFIX', 'SHLIBSUFFIX') + assert None is env.FindIxes(paths, 'SHLIBPREFIX', 'SHLIBSUFFIX') assert paths[1] == env.FindIxes(paths, 'PREFIX', 'SUFFIX') def test_ParseConfig(self): """Test the ParseConfig() method""" - env = Environment(ASFLAGS='assembler', - COMMAND='command', + env = self.TestEnvironment(COMMAND='command', + ASFLAGS='assembler', + CCFLAGS=[''], + CPPDEFINES=[], CPPFLAGS=[''], CPPPATH='string', + FRAMEWORKPATH=[], + FRAMEWORKS=[], LIBPATH=['list'], LIBS='', LINKFLAGS=[''], - CCFLAGS=['']) - orig_popen = os.popen - class my_popen: + RPATH=[]) + + orig_backtick = env.backtick + class my_backtick: def __init__(self, save_command, output): self.save_command = save_command self.output = output def __call__(self, command): self.save_command.append(command) - class fake_file: - def __init__(self, output): - self.output = output - def read(self): - return self.output - return fake_file(self.output) + return self.output + try: save_command = [] - os.popen = my_popen(save_command, + env.backtick = my_backtick(save_command, "-I/usr/include/fum -I bar -X\n" + \ "-L/usr/fax -L foo -lxxx -l yyy " + \ - "-Wa,-as -Wl,-link -Wp,-cpp abc " + \ - "-pthread -framework Carbon " + \ - "-mno-cygwin -mwindows") + "-Wa,-as -Wl,-link " + \ + "-Wl,-rpath=rpath1 " + \ + "-Wl,-R,rpath2 " + \ + "-Wl,-Rrpath3 " + \ + "-Wp,-cpp abc " + \ + "-framework Carbon " + \ + "-frameworkdir=fwd1 " + \ + "-Ffwd2 " + \ + "-F fwd3 " + \ + "-pthread " + \ + "-mno-cygwin -mwindows " + \ + "-arch i386 -isysroot /tmp +DD64 " + \ + "-DFOO -DBAR=value") env.ParseConfig("fake $COMMAND") assert save_command == ['fake command'], save_command - assert env['ASFLAGS'] == ['assembler', '-Wa,-as'], env['ASFLAGS'] - assert env['CPPPATH'] == ['string', '/usr/include/fum', 'bar'], env['CPPPATH'] + assert env['ASFLAGS'] == ['assembler', '-as'], env['ASFLAGS'] + assert env['CCFLAGS'] == ['', '-X', '-Wa,-as', + '-pthread', '-mno-cygwin', + ('-arch', 'i386'), ('-isysroot', '/tmp'), + '+DD64'], env['CCFLAGS'] + assert env['CPPDEFINES'] == ['FOO', ['BAR', 'value']], env['CPPDEFINES'] assert env['CPPFLAGS'] == ['', '-Wp,-cpp'], env['CPPFLAGS'] + assert env['CPPPATH'] == ['string', '/usr/include/fum', 'bar'], env['CPPPATH'] + assert env['FRAMEWORKPATH'] == ['fwd1', 'fwd2', 'fwd3'], env['FRAMEWORKPATH'] + assert env['FRAMEWORKS'] == ['Carbon'], env['FRAMEWORKS'] assert env['LIBPATH'] == ['list', '/usr/fax', 'foo'], env['LIBPATH'] assert env['LIBS'] == ['xxx', 'yyy', env.File('abc')], env['LIBS'] - assert env['LINKFLAGS'] == ['', '-Wl,-link', '-pthread', '-framework', 'Carbon', '-mno-cygwin', '-mwindows'], env['LINKFLAGS'] - assert env['CCFLAGS'] == ['', '-X', '-pthread', '-mno-cygwin'], env['CCFLAGS'] - - os.popen = my_popen([], "-Ibar") + assert env['LINKFLAGS'] == ['', '-Wl,-link', '-pthread', + '-mno-cygwin', '-mwindows', + ('-arch', 'i386'), + ('-isysroot', '/tmp'), + '+DD64'], env['LINKFLAGS'] + assert env['RPATH'] == ['rpath1', 'rpath2', 'rpath3'], env['RPATH'] + + env.backtick = my_backtick([], "-Ibar") env.ParseConfig("fake2") assert env['CPPPATH'] == ['string', '/usr/include/fum', 'bar'], env['CPPPATH'] env.ParseConfig("fake2", unique=0) assert env['CPPPATH'] == ['string', '/usr/include/fum', 'bar', 'bar'], env['CPPPATH'] finally: - os.popen = orig_popen + env.backtick = orig_backtick def test_ParseDepends(self): """Test the ParseDepends() method""" @@ -1523,7 +2080,7 @@ f5: \ mno \ """) - env = Environment(SINGLE = test.workpath('single')) + env = self.TestEnvironment(SINGLE = test.workpath('single')) tlist = [] dlist = [] @@ -1546,8 +2103,8 @@ f5: \ del dlist[:] env.ParseDepends('$SINGLE', only_one=1) - t = map(str, tlist) - d = map(str, dlist) + t = list(map(str, tlist)) + d = list(map(str, dlist)) assert t == ['f0'], t assert d == ['d1', 'd2', 'd3'], d @@ -1555,8 +2112,8 @@ f5: \ del dlist[:] env.ParseDepends(test.workpath('multiple')) - t = map(str, tlist) - d = map(str, dlist) + t = list(map(str, tlist)) + d = list(map(str, dlist)) assert t == ['f1', 'f2', 'f3', 'f4', 'f5'], t assert d == ['foo', 'bar', 'abc', 'def', 'ghi', 'jkl', 'mno'], d @@ -1569,7 +2126,7 @@ f5: \ def test_Platform(self): """Test the Platform() method""" - env = Environment(WIN32='win32', NONE='no-such-platform') + env = self.TestEnvironment(WIN32='win32', NONE='no-such-platform') exc_caught = None try: @@ -1594,6 +2151,8 @@ f5: \ def test_Prepend(self): """Test prepending to construction variables in an Environment """ + import UserDict + UD = UserDict.UserDict import UserList UL = UserList.UserList @@ -1625,6 +2184,18 @@ f5: \ UL(['i7']), [''], UL(['', 'i7']), UL(['i8']), UL(['']), UL(['', 'i8']), + {'d1':1}, 'D1', {'d1':1, 'D1':None}, + {'d2':1}, ['D2'], {'d2':1, 'D2':None}, + {'d3':1}, UL(['D3']), {'d3':1, 'D3':None}, + {'d4':1}, {'D4':1}, {'d4':1, 'D4':1}, + {'d5':1}, UD({'D5':1}), UD({'d5':1, 'D5':1}), + + UD({'u1':1}), 'U1', UD({'u1':1, 'U1':None}), + UD({'u2':1}), ['U2'], UD({'u2':1, 'U2':None}), + UD({'u3':1}), UL(['U3']), UD({'u3':1, 'U3':None}), + UD({'u4':1}), {'U4':1}, UD({'u4':1, 'U4':1}), + UD({'u5':1}), UD({'U5':1}), UD({'u5':1, 'U5':1}), + '', 'M1', 'M1', '', ['M2'], ['M2'], '', UL(['M3']), UL(['M3']), @@ -1675,14 +2246,21 @@ f5: \ failed = 0 while cases: input, prepend, expect = cases[:3] - env['XXX'] = input - env.Prepend(XXX = prepend) - result = env['XXX'] - if result != expect: + env['XXX'] = copy.copy(input) + try: + env.Prepend(XXX = prepend) + except Exception, e: if failed == 0: print - print " %s Prepend %s => %s did not match %s" % \ - (repr(input), repr(prepend), repr(result), repr(expect)) + print " %s Prepend %s exception: %s" % \ + (repr(input), repr(prepend), e) failed = failed + 1 + else: + result = env['XXX'] + if result != expect: + if failed == 0: print + print " %s Prepend %s => %s did not match %s" % \ + (repr(input), repr(prepend), repr(result), repr(expect)) + failed = failed + 1 del cases[:3] assert failed == 0, "%d Prepend() cases failed" % failed @@ -1698,91 +2276,142 @@ f5: \ assert isinstance(result, CLVar), repr(result) assert result == ['bar', 'foo'], result - env3 = Environment(X = {'x1' : 7}) + env3 = self.TestEnvironment(X = {'x1' : 7}) env3.Prepend(X = {'x1' : 8, 'x2' : 9}, Y = {'y1' : 10}) assert env3['X'] == {'x1': 8, 'x2' : 9}, env3['X'] assert env3['Y'] == {'y1': 10}, env3['Y'] - env4 = Environment(BUILDERS = {'z1' : 11}) - env4.Prepend(BUILDERS = {'z2' : 12}) - assert env4['BUILDERS'] == {'z1' : 11, 'z2' : 12}, env4['BUILDERS'] + z1 = Builder() + z2 = Builder() + env4 = self.TestEnvironment(BUILDERS = {'z1' : z1}) + env4.Prepend(BUILDERS = {'z2' : z2}) + assert env4['BUILDERS'] == {'z1' : z1, 'z2' : z2}, env4['BUILDERS'] assert hasattr(env4, 'z1') assert hasattr(env4, 'z2') def test_PrependENVPath(self): """Test prepending to an ENV path.""" - env1 = Environment(ENV = {'PATH': r'C:\dir\num\one;C:\dir\num\two'}, + env1 = self.TestEnvironment(ENV = {'PATH': r'C:\dir\num\one;C:\dir\num\two'}, MYENV = {'MYPATH': r'C:\mydir\num\one;C:\mydir\num\two'}) # have to include the pathsep here so that the test will work on UNIX too. env1.PrependENVPath('PATH',r'C:\dir\num\two',sep = ';') env1.PrependENVPath('PATH',r'C:\dir\num\three',sep = ';') env1.PrependENVPath('MYPATH',r'C:\mydir\num\three','MYENV',sep = ';') env1.PrependENVPath('MYPATH',r'C:\mydir\num\one','MYENV',sep = ';') + # this should do nothing since delete_existing is 0 + env1.PrependENVPath('MYPATH',r'C:\mydir\num\three','MYENV', sep = ';', delete_existing=0) assert(env1['ENV']['PATH'] == r'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one') assert(env1['MYENV']['MYPATH'] == r'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two') - def test_PrependENVPath(self): - """Test prepending to an ENV path.""" - env1 = Environment(ENV = {'PATH': r'C:\dir\num\one;C:\dir\num\two'}, - MYENV = {'MYPATH': r'C:\mydir\num\one;C:\mydir\num\two'}) - # have to include the pathsep here so that the test will work on UNIX too. - env1.PrependENVPath('PATH',r'C:\dir\num\two',sep = ';') - env1.PrependENVPath('PATH',r'C:\dir\num\three',sep = ';') - env1.PrependENVPath('MYPATH',r'C:\mydir\num\three','MYENV',sep = ';') - env1.PrependENVPath('MYPATH',r'C:\mydir\num\one','MYENV',sep = ';') - assert(env1['ENV']['PATH'] == r'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one') - assert(env1['MYENV']['MYPATH'] == r'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two') + test = TestCmd.TestCmd(workdir = '') + test.subdir('sub1', 'sub2') + p=env1['ENV']['PATH'] + env1.PrependENVPath('PATH','#sub1', sep = ';') + env1.PrependENVPath('PATH',env1.fs.Dir('sub2'), sep = ';') + assert env1['ENV']['PATH'] == 'sub2;sub1;' + p, env1['ENV']['PATH'] def test_PrependUnique(self): """Test prepending unique values to construction variables This strips values that are already present when lists are involved.""" - env = Environment(AAA1 = 'a1', + env = self.TestEnvironment(AAA1 = 'a1', AAA2 = 'a2', AAA3 = 'a3', + AAA4 = 'a4', + AAA5 = 'a5', BBB1 = ['b1'], BBB2 = ['b2'], BBB3 = ['b3'], + BBB4 = ['b4'], + BBB5 = ['b5'], CCC1 = '', - CCC2 = '') + CCC2 = '', + DDD1 = ['a', 'b', 'c']) env.PrependUnique(AAA1 = 'a1', AAA2 = ['a2'], - AAA3 = ['a3', 'b', 'c', 'a3'], + AAA3 = ['a3', 'b', 'c', 'b', 'a3'], # ignore dups + AAA4 = 'a4.new', + AAA5 = ['a5.new'], BBB1 = 'b1', BBB2 = ['b2'], BBB3 = ['b3', 'b', 'c', 'b3'], + BBB4 = 'b4.new', + BBB5 = ['b5.new'], CCC1 = 'c1', - CCC2 = ['c2']) + CCC2 = ['c2'], + DDD1 = 'b') assert env['AAA1'] == 'a1a1', env['AAA1'] assert env['AAA2'] == ['a2'], env['AAA2'] - assert env['AAA3'] == ['b', 'c', 'a3'], env['AAA3'] + assert env['AAA3'] == ['c', 'b', 'a3'], env['AAA3'] + assert env['AAA4'] == 'a4.newa4', env['AAA4'] + assert env['AAA5'] == ['a5.new', 'a5'], env['AAA5'] assert env['BBB1'] == ['b1'], env['BBB1'] assert env['BBB2'] == ['b2'], env['BBB2'] assert env['BBB3'] == ['b', 'c', 'b3'], env['BBB3'] + assert env['BBB4'] == ['b4.new', 'b4'], env['BBB4'] + assert env['BBB5'] == ['b5.new', 'b5'], env['BBB5'] assert env['CCC1'] == 'c1', env['CCC1'] assert env['CCC2'] == ['c2'], env['CCC2'] + assert env['DDD1'] == ['a', 'b', 'c'], env['DDD1'] + + env.PrependUnique(DDD1 = 'b', delete_existing=1) + assert env['DDD1'] == ['b', 'a', 'c'], env['DDD1'] # b moves to front + env.PrependUnique(DDD1 = ['a','c'], delete_existing=1) + assert env['DDD1'] == ['a', 'c', 'b'], env['DDD1'] # a & c move to front + env.PrependUnique(DDD1 = ['d','e','d'], delete_existing=1) + assert env['DDD1'] == ['d', 'e', 'a', 'c', 'b'], env['DDD1'] + + + env['CLVar'] = CLVar([]) + env.PrependUnique(CLVar = 'bar') + result = env['CLVar'] + if sys.version[0] == '1' or sys.version[:3] == '2.0': + # Python 2.0 and before have a quirky behavior where CLVar([]) + # actually matches '' and [] due to different __coerce__() + # semantics in the UserList implementation. It isn't worth a + # lot of effort to get this corner case to work identically + # (support for Python 1.5 support will die soon anyway), + # so just treat it separately for now. + assert result == 'bar', result + else: + assert isinstance(result, CLVar), repr(result) + assert result == ['bar'], result + + env['CLVar'] = CLVar(['abc']) + env.PrependUnique(CLVar = 'bar') + result = env['CLVar'] + assert isinstance(result, CLVar), repr(result) + assert result == ['bar', 'abc'], result + + env['CLVar'] = CLVar(['bar']) + env.PrependUnique(CLVar = 'bar') + result = env['CLVar'] + assert isinstance(result, CLVar), repr(result) + assert result == ['bar'], result def test_Replace(self): """Test replacing construction variables in an Environment After creation of the Environment, of course. """ - env1 = Environment(AAA = 'a', BBB = 'b') + env1 = self.TestEnvironment(AAA = 'a', BBB = 'b') env1.Replace(BBB = 'bbb', CCC = 'ccc') - env2 = Environment(AAA = 'a', BBB = 'bbb', CCC = 'ccc') + env2 = self.TestEnvironment(AAA = 'a', BBB = 'bbb', CCC = 'ccc') assert env1 == env2, diff_env(env1, env2) - env3 = Environment(BUILDERS = {'b1' : 1}) + b1 = Builder() + b2 = Builder() + env3 = self.TestEnvironment(BUILDERS = {'b1' : b1}) assert hasattr(env3, 'b1'), "b1 was not set" - env3.Replace(BUILDERS = {'b2' : 2}) + env3.Replace(BUILDERS = {'b2' : b2}) assert not hasattr(env3, 'b1'), "b1 was not cleared" assert hasattr(env3, 'b2'), "b2 was not set" def test_ReplaceIxes(self): "Test ReplaceIxes()" - env = Environment(LIBPREFIX='lib', + env = self.TestEnvironment(LIBPREFIX='lib', LIBSUFFIX='.a', SHLIBPREFIX='lib', SHLIBSUFFIX='.so', @@ -1803,7 +2432,7 @@ f5: \ def test_SetDefault(self): """Test the SetDefault method""" - env = Environment(tools = []) + env = self.TestEnvironment(tools = []) env.SetDefault(V1 = 1) env.SetDefault(V1 = 2) assert env['V1'] == 1 @@ -1813,21 +2442,21 @@ f5: \ def test_Tool(self): """Test the Tool() method""" - env = Environment(LINK='link', NONE='no-such-tool') + env = self.TestEnvironment(LINK='link', NONE='no-such-tool') exc_caught = None try: env.Tool('does_not_exist') - except SCons.Errors.UserError: + except SCons.Errors.EnvironmentError: exc_caught = 1 - assert exc_caught, "did not catch expected UserError" + assert exc_caught, "did not catch expected EnvironmentError" exc_caught = None try: env.Tool('$NONE') - except SCons.Errors.UserError: + except SCons.Errors.EnvironmentError: exc_caught = 1 - assert exc_caught, "did not catch expected UserError" + assert exc_caught, "did not catch expected EnvironmentError" # Use a non-existent toolpath directory just to make sure we # can call Tool() with the keyword argument. @@ -1837,6 +2466,29 @@ f5: \ env.Tool('$LINK') assert env['LINK'] == '$SMARTLINK', env['LINK'] + # Test that the environment stores the toolpath and + # re-uses it for later calls. + test = TestCmd.TestCmd(workdir = '') + + test.write('xxx.py', """\ +def exists(env): + 1 +def generate(env): + env['XXX'] = 'one' +""") + + test.write('yyy.py', """\ +def exists(env): + 1 +def generate(env): + env['YYY'] = 'two' +""") + + env = self.TestEnvironment(tools=['xxx'], toolpath=[test.workpath('')]) + assert env['XXX'] == 'one', env['XXX'] + env.Tool('yyy') + assert env['YYY'] == 'two', env['YYY'] + def test_WhereIs(self): """Test the WhereIs() method""" test = TestCmd.TestCmd(workdir = '') @@ -1865,21 +2517,21 @@ f5: \ test.workpath('sub2'), test.workpath('sub3'), test.workpath('sub4'), - ] + string.split(env_path, os.pathsep) + ] + env_path.split(os.pathsep) pathdirs_1243 = [ test.workpath('sub1'), test.workpath('sub2'), test.workpath('sub4'), test.workpath('sub3'), - ] + string.split(env_path, os.pathsep) + ] + env_path.split(os.pathsep) - path = string.join(pathdirs_1234, os.pathsep) - env = Environment(ENV = {'PATH' : path}) + path = os.pathsep.join(pathdirs_1234) + env = self.TestEnvironment(ENV = {'PATH' : path}) wi = env.WhereIs('xxx.exe') assert wi == test.workpath(sub3_xxx_exe), wi wi = env.WhereIs('xxx.exe', pathdirs_1243) assert wi == test.workpath(sub4_xxx_exe), wi - wi = env.WhereIs('xxx.exe', string.join(pathdirs_1243, os.pathsep)) + wi = env.WhereIs('xxx.exe', os.pathsep.join(pathdirs_1243)) assert wi == test.workpath(sub4_xxx_exe), wi wi = env.WhereIs('xxx.exe', reject = sub3_xxx_exe) @@ -1887,13 +2539,13 @@ f5: \ wi = env.WhereIs('xxx.exe', pathdirs_1243, reject = sub3_xxx_exe) assert wi == test.workpath(sub4_xxx_exe), wi - path = string.join(pathdirs_1243, os.pathsep) - env = Environment(ENV = {'PATH' : path}) + path = os.pathsep.join(pathdirs_1243) + env = self.TestEnvironment(ENV = {'PATH' : path}) wi = env.WhereIs('xxx.exe') assert wi == test.workpath(sub4_xxx_exe), wi wi = env.WhereIs('xxx.exe', pathdirs_1234) assert wi == test.workpath(sub3_xxx_exe), wi - wi = env.WhereIs('xxx.exe', string.join(pathdirs_1234, os.pathsep)) + wi = env.WhereIs('xxx.exe', os.pathsep.join(pathdirs_1234)) assert wi == test.workpath(sub3_xxx_exe), wi if sys.platform == 'win32': @@ -1904,13 +2556,13 @@ f5: \ assert wi == test.workpath(sub4_xxx_exe), wi wi = env.WhereIs('xxx', path = pathdirs_1234, pathext = '.BAT;.EXE') - assert string.lower(wi) == string.lower(test.workpath(sub3_xxx_exe)), wi + assert wi.lower() == test.workpath(sub3_xxx_exe).lower(), wi # Test that we return a normalized path even when # the path contains forward slashes. forward_slash = test.workpath('') + '/sub3' wi = env.WhereIs('xxx', path = forward_slash, pathext = '.EXE') - assert string.lower(wi) == string.lower(test.workpath(sub3_xxx_exe)), wi + assert wi.lower() == test.workpath(sub3_xxx_exe).lower(), wi @@ -1918,29 +2570,33 @@ f5: \ """Test the Action() method""" import SCons.Action - env = Environment(FOO = 'xyzzy') + env = self.TestEnvironment(FOO = 'xyzzy') a = env.Action('foo') assert a, a - assert a.__class__ is SCons.Action.CommandAction, a + assert a.__class__ is SCons.Action.CommandAction, a.__class__ a = env.Action('$FOO') assert a, a - assert a.__class__ is SCons.Action.LazyAction, a + assert a.__class__ is SCons.Action.CommandAction, a.__class__ + + a = env.Action('$$FOO') + assert a, a + assert a.__class__ is SCons.Action.LazyAction, a.__class__ a = env.Action(['$FOO', 'foo']) assert a, a - assert a.__class__ is SCons.Action.ListAction, a + assert a.__class__ is SCons.Action.ListAction, a.__class__ def func(arg): pass a = env.Action(func) assert a, a - assert a.__class__ is SCons.Action.FunctionAction, a + assert a.__class__ is SCons.Action.FunctionAction, a.__class__ def test_AddPostAction(self): """Test the AddPostAction() method""" - env = Environment(FOO='fff', BAR='bbb') + env = self.TestEnvironment(FOO='fff', BAR='bbb') n = env.AddPostAction('$FOO', lambda x: x) assert str(n[0]) == 'fff', n[0] @@ -1951,7 +2607,7 @@ f5: \ def test_AddPreAction(self): """Test the AddPreAction() method""" - env = Environment(FOO='fff', BAR='bbb') + env = self.TestEnvironment(FOO='fff', BAR='bbb') n = env.AddPreAction('$FOO', lambda x: x) assert str(n[0]) == 'fff', n[0] @@ -1962,7 +2618,7 @@ f5: \ def test_Alias(self): """Test the Alias() method""" - env = Environment(FOO='kkk', BAR='lll', EA='export_alias') + env = self.TestEnvironment(FOO='kkk', BAR='lll', EA='export_alias') tgt = env.Alias('new_alias')[0] assert str(tgt) == 'new_alias', tgt @@ -1979,37 +2635,37 @@ f5: \ tgt = env.Alias('export_alias', [ 'asrc1', '$FOO' ])[0] assert str(tgt) == 'export_alias', tgt - assert len(tgt.sources) == 2, map(str, tgt.sources) - assert str(tgt.sources[0]) == 'asrc1', map(str, tgt.sources) - assert str(tgt.sources[1]) == 'kkk', map(str, tgt.sources) + assert len(tgt.sources) == 2, list(map(str, tgt.sources)) + assert str(tgt.sources[0]) == 'asrc1', list(map(str, tgt.sources)) + assert str(tgt.sources[1]) == 'kkk', list(map(str, tgt.sources)) n = env.Alias(tgt, source = ['$BAR', 'asrc4'])[0] assert n is tgt, n - assert len(tgt.sources) == 4, map(str, tgt.sources) - assert str(tgt.sources[2]) == 'lll', map(str, tgt.sources) - assert str(tgt.sources[3]) == 'asrc4', map(str, tgt.sources) + assert len(tgt.sources) == 4, list(map(str, tgt.sources)) + assert str(tgt.sources[2]) == 'lll', list(map(str, tgt.sources)) + assert str(tgt.sources[3]) == 'asrc4', list(map(str, tgt.sources)) n = env.Alias('$EA', 'asrc5')[0] assert n is tgt, n - assert len(tgt.sources) == 5, map(str, tgt.sources) - assert str(tgt.sources[4]) == 'asrc5', map(str, tgt.sources) + assert len(tgt.sources) == 5, list(map(str, tgt.sources)) + assert str(tgt.sources[4]) == 'asrc5', list(map(str, tgt.sources)) t1, t2 = env.Alias(['t1', 't2'], ['asrc6', 'asrc7']) assert str(t1) == 't1', t1 assert str(t2) == 't2', t2 - assert len(t1.sources) == 2, map(str, t1.sources) - assert str(t1.sources[0]) == 'asrc6', map(str, t1.sources) - assert str(t1.sources[1]) == 'asrc7', map(str, t1.sources) - assert len(t2.sources) == 2, map(str, t2.sources) - assert str(t2.sources[0]) == 'asrc6', map(str, t2.sources) - assert str(t2.sources[1]) == 'asrc7', map(str, t2.sources) + assert len(t1.sources) == 2, list(map(str, t1.sources)) + assert str(t1.sources[0]) == 'asrc6', list(map(str, t1.sources)) + assert str(t1.sources[1]) == 'asrc7', list(map(str, t1.sources)) + assert len(t2.sources) == 2, list(map(str, t2.sources)) + assert str(t2.sources[0]) == 'asrc6', list(map(str, t2.sources)) + assert str(t2.sources[1]) == 'asrc7', list(map(str, t2.sources)) tgt = env.Alias('add', 's1') tgt = env.Alias('add', 's2')[0] - s = map(str, tgt.sources) + s = list(map(str, tgt.sources)) assert s == ['s1', 's2'], s tgt = env.Alias(tgt, 's3')[0] - s = map(str, tgt.sources) + s = list(map(str, tgt.sources)) assert s == ['s1', 's2', 's3'], s tgt = env.Alias('act', None, "action1")[0] @@ -2024,85 +2680,87 @@ f5: \ def test_AlwaysBuild(self): """Test the AlwaysBuild() method""" - env = Environment(FOO='fff', BAR='bbb') - t = env.AlwaysBuild('a', 'b$FOO', ['c', 'd'], '$BAR') - assert t[0].__class__.__name__ == 'File' + env = self.TestEnvironment(FOO='fff', BAR='bbb') + t = env.AlwaysBuild('a', 'b$FOO', ['c', 'd'], '$BAR', + env.fs.Dir('dir'), env.fs.File('file')) + assert t[0].__class__.__name__ == 'Entry' assert t[0].path == 'a' assert t[0].always_build - assert t[1].__class__.__name__ == 'File' + assert t[1].__class__.__name__ == 'Entry' assert t[1].path == 'bfff' assert t[1].always_build - assert t[2].__class__.__name__ == 'File' + assert t[2].__class__.__name__ == 'Entry' assert t[2].path == 'c' assert t[2].always_build - assert t[3].__class__.__name__ == 'File' + assert t[3].__class__.__name__ == 'Entry' assert t[3].path == 'd' assert t[3].always_build - assert t[4].__class__.__name__ == 'File' + assert t[4].__class__.__name__ == 'Entry' assert t[4].path == 'bbb' assert t[4].always_build - - def test_BuildDir(self): - """Test the BuildDir() method""" + assert t[5].__class__.__name__ == 'Dir' + assert t[5].path == 'dir' + assert t[5].always_build + assert t[6].__class__.__name__ == 'File' + assert t[6].path == 'file' + assert t[6].always_build + + def test_VariantDir(self): + """Test the VariantDir() method""" class MyFS: def Dir(self, name): return name - def BuildDir(self, build_dir, src_dir, duplicate): - self.build_dir = build_dir + def VariantDir(self, variant_dir, src_dir, duplicate): + self.variant_dir = variant_dir self.src_dir = src_dir self.duplicate = duplicate - env = Environment(FOO = 'fff', BAR = 'bbb') + env = self.TestEnvironment(FOO = 'fff', BAR = 'bbb') env.fs = MyFS() - env.BuildDir('build', 'src') - assert env.fs.build_dir == 'build', env.fs.build_dir + env.VariantDir('build', 'src') + assert env.fs.variant_dir == 'build', env.fs.variant_dir assert env.fs.src_dir == 'src', env.fs.src_dir assert env.fs.duplicate == 1, env.fs.duplicate - env.BuildDir('build${FOO}', '${BAR}src', 0) - assert env.fs.build_dir == 'buildfff', env.fs.build_dir + env.VariantDir('build${FOO}', '${BAR}src', 0) + assert env.fs.variant_dir == 'buildfff', env.fs.variant_dir assert env.fs.src_dir == 'bbbsrc', env.fs.src_dir assert env.fs.duplicate == 0, env.fs.duplicate def test_Builder(self): """Test the Builder() method""" - env = Environment(FOO = 'xyzzy') + env = self.TestEnvironment(FOO = 'xyzzy') b = env.Builder(action = 'foo') - assert not b is None, b + assert b is not None, b b = env.Builder(action = '$FOO') - assert not b is None, b + assert b is not None, b b = env.Builder(action = ['$FOO', 'foo']) - assert not b is None, b + assert b is not None, b def func(arg): pass b = env.Builder(action = func) - assert not b is None, b + assert b is not None, b b = env.Builder(generator = func) - assert not b is None, b + assert b is not None, b def test_CacheDir(self): """Test the CacheDir() method""" - class MyFS: - def CacheDir(self, path): - self.CD = path - - env = Environment(CD = 'CacheDir') - env.fs = MyFS() + env = self.TestEnvironment(CD = 'CacheDir') env.CacheDir('foo') - assert env.fs.CD == 'foo', env.fs.CD + assert env._CacheDir_path == 'foo', env._CacheDir_path env.CacheDir('$CD') - assert env.fs.CD == 'CacheDir', env.fs.CD + assert env._CacheDir_path == 'CacheDir', env._CacheDir_path def test_Clean(self): """Test the Clean() method""" - env = Environment(FOO = 'fff', BAR = 'bbb') + env = self.TestEnvironment(FOO = 'fff', BAR = 'bbb') CT = SCons.Environment.CleanTargets @@ -2110,20 +2768,20 @@ f5: \ fff = env.arg2nodes('fff')[0] t = env.Clean('foo', 'aaa') - l = map(str, CT[foo]) + l = list(map(str, CT[foo])) assert l == ['aaa'], l t = env.Clean(foo, ['$BAR', 'ccc']) - l = map(str, CT[foo]) + l = list(map(str, CT[foo])) assert l == ['aaa', 'bbb', 'ccc'], l eee = env.arg2nodes('eee')[0] t = env.Clean('$FOO', 'ddd') - l = map(str, CT[fff]) + l = list(map(str, CT[fff])) assert l == ['ddd'], l t = env.Clean(fff, [eee, 'fff']) - l = map(str, CT[fff]) + l = list(map(str, CT[fff])) assert l == ['ddd', 'eee', 'fff'], l def test_Command(self): @@ -2131,37 +2789,37 @@ f5: \ env = Environment() t = env.Command(target='foo.out', source=['foo1.in', 'foo2.in'], action='buildfoo $target $source')[0] - assert not t.builder is None + assert t.builder is not None assert t.builder.action.__class__.__name__ == 'CommandAction' assert t.builder.action.cmd_list == 'buildfoo $target $source' - assert 'foo1.in' in map(lambda x: x.path, t.sources) - assert 'foo2.in' in map(lambda x: x.path, t.sources) + assert 'foo1.in' in [x.path for x in t.sources] + assert 'foo2.in' in [x.path for x in t.sources] - sub = SCons.Node.FS.default_fs.Dir('sub') + sub = env.fs.Dir('sub') t = env.Command(target='bar.out', source='sub', action='buildbar $target $source')[0] - assert 'sub' in map(lambda x: x.path, t.sources) + assert 'sub' in [x.path for x in t.sources] def testFunc(env, target, source): assert str(target[0]) == 'foo.out' - assert 'foo1.in' in map(str, source) and 'foo2.in' in map(str, source), map(str, source) + assert 'foo1.in' in list(map(str, source)) and 'foo2.in' in list(map(str, source)), list(map(str, source)) return 0 t = env.Command(target='foo.out', source=['foo1.in','foo2.in'], action=testFunc)[0] - assert not t.builder is None + assert t.builder is not None assert t.builder.action.__class__.__name__ == 'FunctionAction' t.build() - assert 'foo1.in' in map(lambda x: x.path, t.sources) - assert 'foo2.in' in map(lambda x: x.path, t.sources) + assert 'foo1.in' in [x.path for x in t.sources] + assert 'foo2.in' in [x.path for x in t.sources] x = [] def test2(baz, x=x): x.append(baz) - env = Environment(TEST2 = test2) + env = self.TestEnvironment(TEST2 = test2) t = env.Command(target='baz.out', source='baz.in', action='${TEST2(XYZ)}', XYZ='magic word')[0] - assert not t.builder is None + assert t.builder is not None t.build() assert x[0] == 'magic word', x @@ -2169,9 +2827,9 @@ f5: \ action = 'foo', X = 'xxx')[0] assert str(t) == 'xxx.out', str(t) - assert 'xxx.in' in map(lambda x: x.path, t.sources) + assert 'xxx.in' in [x.path for x in t.sources] - env = Environment(source_scanner = 'should_not_find_this') + env = self.TestEnvironment(source_scanner = 'should_not_find_this') t = env.Command(target='file.out', source='file.in', action = 'foo', source_scanner = 'fake')[0] @@ -2186,17 +2844,17 @@ f5: \ try: os.chdir(test.workpath()) - env = Environment(FOO = 'xyzzy') + env = self.TestEnvironment(FOO = 'xyzzy') def func(arg): pass c = env.Configure() - assert not c is None, c + assert c is not None, c c.Finish() c = env.Configure(custom_tests = {'foo' : func, '$FOO' : func}) - assert not c is None, c + assert c is not None, c assert hasattr(c, 'foo') assert hasattr(c, 'xyzzy') c.Finish() @@ -2205,7 +2863,7 @@ f5: \ def test_Depends(self): """Test the explicit Depends method.""" - env = Environment(FOO = 'xxx', BAR='yyy') + env = self.TestEnvironment(FOO = 'xxx', BAR='yyy') env.Dir('dir1') env.Dir('dir2') env.File('xxx.py') @@ -2241,7 +2899,7 @@ f5: \ def Dir(self, name): return 'Dir(%s)' % name - env = Environment(FOO = 'foodir', BAR = 'bardir') + env = self.TestEnvironment(FOO = 'foodir', BAR = 'bardir') env.fs = MyFS() d = env.Dir('d') @@ -2253,16 +2911,45 @@ f5: \ d = env.Dir('${BAR}_$BAR') assert d == 'Dir(bardir_bardir)', d + d = env.Dir(['dir1']) + assert d == ['Dir(dir1)'], d + + d = env.Dir(['dir1', 'dir2']) + assert d == ['Dir(dir1)', 'Dir(dir2)'], d + + def test_NoClean(self): + """Test the NoClean() method""" + env = self.TestEnvironment(FOO='ggg', BAR='hhh') + env.Dir('p_hhhb') + env.File('p_d') + t = env.NoClean('p_a', 'p_${BAR}b', ['p_c', 'p_d'], 'p_$FOO') + + assert t[0].__class__.__name__ == 'Entry', t[0].__class__.__name__ + assert t[0].path == 'p_a' + assert t[0].noclean + assert t[1].__class__.__name__ == 'Dir', t[1].__class__.__name__ + assert t[1].path == 'p_hhhb' + assert t[1].noclean + assert t[2].__class__.__name__ == 'Entry', t[2].__class__.__name__ + assert t[2].path == 'p_c' + assert t[2].noclean + assert t[3].__class__.__name__ == 'File', t[3].__class__.__name__ + assert t[3].path == 'p_d' + assert t[3].noclean + assert t[4].__class__.__name__ == 'Entry', t[4].__class__.__name__ + assert t[4].path == 'p_ggg' + assert t[4].noclean + def test_Dump(self): """Test the Dump() method""" - env = Environment(FOO = 'foo') + env = self.TestEnvironment(FOO = 'foo') assert env.Dump('FOO') == "'foo'", env.Dump('FOO') assert len(env.Dump()) > 200, env.Dump() # no args version def test_Environment(self): """Test the Environment() method""" - env = Environment(FOO = 'xxx', BAR = 'yyy') + env = self.TestEnvironment(FOO = 'xxx', BAR = 'yyy') e2 = env.Environment(X = '$FOO', Y = '$BAR') assert e2['X'] == 'xxx', e2['X'] @@ -2283,13 +2970,37 @@ f5: \ result = env.Execute("foo") assert result == "foo executed", result + def test_Entry(self): + """Test the Entry() method""" + class MyFS: + def Entry(self, name): + return 'Entry(%s)' % name + + env = self.TestEnvironment(FOO = 'fooentry', BAR = 'barentry') + env.fs = MyFS() + + e = env.Entry('e') + assert e == 'Entry(e)', e + + e = env.Entry('$FOO') + assert e == 'Entry(fooentry)', e + + e = env.Entry('${BAR}_$BAR') + assert e == 'Entry(barentry_barentry)', e + + e = env.Entry(['entry1']) + assert e == ['Entry(entry1)'], e + + e = env.Entry(['entry1', 'entry2']) + assert e == ['Entry(entry1)', 'Entry(entry2)'], e + def test_File(self): """Test the File() method""" class MyFS: def File(self, name): return 'File(%s)' % name - env = Environment(FOO = 'foofile', BAR = 'barfile') + env = self.TestEnvironment(FOO = 'foofile', BAR = 'barfile') env.fs = MyFS() f = env.File('f') @@ -2301,9 +3012,15 @@ f5: \ f = env.File('${BAR}_$BAR') assert f == 'File(barfile_barfile)', f + f = env.File(['file1']) + assert f == ['File(file1)'], f + + f = env.File(['file1', 'file2']) + assert f == ['File(file1)', 'File(file2)'], f + def test_FindFile(self): """Test the FindFile() method""" - env = Environment(FOO = 'fff', BAR = 'bbb') + env = self.TestEnvironment(FOO = 'fff', BAR = 'bbb') r = env.FindFile('foo', ['no_such_directory']) assert r is None, r @@ -2320,7 +3037,7 @@ f5: \ def test_GetBuildPath(self): """Test the GetBuildPath() method.""" - env = Environment(MAGIC = 'xyzzy') + env = self.TestEnvironment(MAGIC = 'xyzzy') p = env.GetBuildPath('foo') assert p == 'foo', p @@ -2330,7 +3047,7 @@ f5: \ def test_Ignore(self): """Test the explicit Ignore method.""" - env = Environment(FOO='yyy', BAR='zzz') + env = self.TestEnvironment(FOO='yyy', BAR='zzz') env.Dir('dir1') env.Dir('dir2') env.File('yyyzzz') @@ -2360,75 +3077,9 @@ f5: \ assert i.__class__.__name__ == 'Dir', i.__class__.__name__ assert i.path == 'dir2' - def test_Install(self): - """Test the Install method""" - env = Environment(FOO='iii', BAR='jjj') - - tgt = env.Install('export', [ 'build/foo1', 'build/foo2' ]) - paths = map(str, tgt) - paths.sort() - expect = map(os.path.normpath, [ 'export/foo1', 'export/foo2' ]) - assert paths == expect, paths - for tnode in tgt: - assert tnode.builder == InstallBuilder - - tgt = env.Install('$FOO', [ 'build/${BAR}1', 'build/${BAR}2' ]) - paths = map(str, tgt) - paths.sort() - expect = map(os.path.normpath, [ 'iii/jjj1', 'iii/jjj2' ]) - assert paths == expect, paths - for tnode in tgt: - assert tnode.builder == InstallBuilder - - exc_caught = None - try: - tgt = env.Install('export', 'export') - except SCons.Errors.UserError, e: - exc_caught = 1 - assert exc_caught, "UserError should be thrown when Install() target is not a file." - match = str(e) == "Source `export' of Install() is not a file. Install() source must be one or more files." - assert match, e - - exc_caught = None - try: - tgt = env.Install('export', ['export', 'build/foo1']) - except SCons.Errors.UserError, e: - exc_caught = 1 - assert exc_caught, "UserError should be thrown when Install() target containins non-files." - match = str(e) == "Source `['export', 'build/foo1']' of Install() contains one or more non-files. Install() source must be one or more files." - assert match, e - - exc_caught = None - try: - tgt = env.Install('export/foo1', 'build/foo1') - except SCons.Errors.UserError, e: - exc_caught = 1 - assert exc_caught, "UserError should be thrown reversing the order of Install() targets." - match = str(e) == "Target `export/foo1' of Install() is a file, but should be a directory. Perhaps you have the Install() arguments backwards?" - assert match, e - - def test_InstallAs(self): - """Test the InstallAs method""" - env = Environment(FOO='iii', BAR='jjj') - - tgt = env.InstallAs(target=string.split('foo1 foo2'), - source=string.split('bar1 bar2')) - assert len(tgt) == 2, len(tgt) - paths = map(lambda x: str(x.sources[0]), tgt) - paths.sort() - expect = map(os.path.normpath, [ 'bar1', 'bar2' ]) - assert paths == expect, paths - for tnode in tgt: - assert tnode.builder == InstallBuilder - - tgt = env.InstallAs(target='${FOO}.t', source='${BAR}.s')[0] - assert tgt.path == 'iii.t' - assert tgt.sources[0].path == 'jjj.s' - assert tgt.builder == InstallBuilder - def test_Literal(self): """Test the Literal() method""" - env = Environment(FOO='fff', BAR='bbb') + env = self.TestEnvironment(FOO='fff', BAR='bbb') list = env.subst_list([env.Literal('$FOO'), '$BAR'])[0] assert list == ['$FOO', 'bbb'], list list = env.subst_list(['$FOO', env.Literal('$BAR')])[0] @@ -2436,7 +3087,7 @@ f5: \ def test_Local(self): """Test the Local() method.""" - env = Environment(FOO='lll') + env = self.TestEnvironment(FOO='lll') l = env.Local(env.fs.File('fff')) assert str(l[0]) == 'fff', l[0] @@ -2447,7 +3098,7 @@ f5: \ def test_Precious(self): """Test the Precious() method""" - env = Environment(FOO='ggg', BAR='hhh') + env = self.TestEnvironment(FOO='ggg', BAR='hhh') env.Dir('p_hhhb') env.File('p_d') t = env.Precious('p_a', 'p_${BAR}b', ['p_c', 'p_d'], 'p_$FOO') @@ -2477,7 +3128,7 @@ f5: \ self.list.extend(list(dirs)) def Dir(self, name): return name - env = Environment(FOO='rrr', BAR='sss') + env = self.TestEnvironment(FOO='rrr', BAR='sss') env.fs = MyFS() env.Repository('/tmp/foo') env.Repository('/tmp/$FOO', '/tmp/$BAR/foo') @@ -2489,20 +3140,20 @@ f5: \ def scan(node, env, target, arg): pass - env = Environment(FOO = scan) + env = self.TestEnvironment(FOO = scan) s = env.Scanner('foo') - assert not s is None, s + assert s is not None, s s = env.Scanner(function = 'foo') - assert not s is None, s + assert s is not None, s if 0: s = env.Scanner('$FOO') - assert not s is None, s + assert s is not None, s s = env.Scanner(function = '$FOO') - assert not s is None, s + assert s is not None, s def test_SConsignFile(self): """Test the SConsignFile() method""" @@ -2511,9 +3162,10 @@ f5: \ class MyFS: SConstruct_dir = os.sep + 'dir' - env = Environment(FOO = 'SConsign', + env = self.TestEnvironment(FOO = 'SConsign', BAR = os.path.join(os.sep, 'File')) env.fs = MyFS() + env.Execute = lambda action: None try: fnames = [] @@ -2526,34 +3178,42 @@ f5: \ SCons.SConsign.File = capture env.SConsignFile('foo') - assert fnames[0] == os.path.join(os.sep, 'dir', 'foo'), fnames - assert dbms[0] == None, dbms + assert fnames[-1] == os.path.join(os.sep, 'dir', 'foo'), fnames + assert dbms[-1] is None, dbms env.SConsignFile('$FOO') - assert fnames[1] == os.path.join(os.sep, 'dir', 'SConsign'), fnames - assert dbms[1] == None, dbms + assert fnames[-1] == os.path.join(os.sep, 'dir', 'SConsign'), fnames + assert dbms[-1] is None, dbms env.SConsignFile('/$FOO') - assert fnames[2] == '/SConsign', fnames - assert dbms[2] == None, dbms + assert fnames[-1] == os.sep + 'SConsign', fnames + assert dbms[-1] is None, dbms + + env.SConsignFile(os.sep + '$FOO') + assert fnames[-1] == os.sep + 'SConsign', fnames + assert dbms[-1] is None, dbms env.SConsignFile('$BAR', 'x') - assert fnames[3] == os.path.join(os.sep, 'File'), fnames - assert dbms[3] == 'x', dbms + assert fnames[-1] == os.path.join(os.sep, 'File'), fnames + assert dbms[-1] == 'x', dbms env.SConsignFile('__$BAR', 7) - assert fnames[4] == os.path.join(os.sep, 'dir', '__', 'File'), fnames - assert dbms[4] == 7, dbms + assert fnames[-1] == os.path.join(os.sep, 'dir', '__', 'File'), fnames + assert dbms[-1] == 7, dbms env.SConsignFile() - assert fnames[5] == os.path.join(os.sep, 'dir', '.sconsign'), fnames - assert dbms[5] == None, dbms + assert fnames[-1] == os.path.join(os.sep, 'dir', '.sconsign'), fnames + assert dbms[-1] is None, dbms + + env.SConsignFile(None) + assert fnames[-1] is None, fnames + assert dbms[-1] is None, dbms finally: SCons.SConsign.File = save_SConsign_File def test_SideEffect(self): """Test the SideEffect() method""" - env = Environment(LIB='lll', FOO='fff', BAR='bbb') + env = self.TestEnvironment(LIB='lll', FOO='fff', BAR='bbb') env.File('mylll.pdb') env.Dir('mymmm.pdb') @@ -2565,8 +3225,6 @@ f5: \ assert s.side_effect assert foo.side_effects == [s] assert bar.side_effects == [s] - assert s.depends_on([bar]) - assert s.depends_on([foo]) fff = env.Object('fff.obj', 'fff.cpp')[0] bbb = env.Object('bbb.obj', 'bbb.cpp')[0] @@ -2576,8 +3234,6 @@ f5: \ assert s.side_effect assert fff.side_effects == [s], fff.side_effects assert bbb.side_effects == [s], bbb.side_effects - assert s.depends_on([bbb]) - assert s.depends_on([fff]) ggg = env.Object('ggg.obj', 'ggg.cpp')[0] ccc = env.Object('ccc.obj', 'ccc.cpp')[0] @@ -2587,12 +3243,10 @@ f5: \ assert s.side_effect assert ggg.side_effects == [s], ggg.side_effects assert ccc.side_effects == [s], ccc.side_effects - assert s.depends_on([ccc]) - assert s.depends_on([ggg]) def test_SourceCode(self): """Test the SourceCode() method.""" - env = Environment(FOO='mmm', BAR='nnn') + env = self.TestEnvironment(FOO='mmm', BAR='nnn') e = env.SourceCode('foo', None)[0] assert e.path == 'foo' s = e.src_builder() @@ -2611,7 +3265,9 @@ f5: \ def test_SourceSignatures(type): """Test the SourceSignatures() method""" - env = Environment(M = 'MD5', T = 'timestamp') + import SCons.Errors + + env = type.TestEnvironment(M = 'MD5', T = 'timestamp') exc_caught = None try: @@ -2619,23 +3275,35 @@ f5: \ except SCons.Errors.UserError: exc_caught = 1 assert exc_caught, "did not catch expected UserError" - assert not hasattr(env, '_calc_module') env.SourceSignatures('MD5') - m = env._calc_module + assert env.src_sig_type == 'MD5', env.src_sig_type env.SourceSignatures('$M') - assert env._calc_module is m + assert env.src_sig_type == 'MD5', env.src_sig_type env.SourceSignatures('timestamp') - t = env._calc_module + assert env.src_sig_type == 'timestamp', env.src_sig_type env.SourceSignatures('$T') - assert env._calc_module is t + assert env.src_sig_type == 'timestamp', env.src_sig_type + + try: + import SCons.Util + save_md5 = SCons.Util.md5 + SCons.Util.md5 = None + try: + env.SourceSignatures('MD5') + except SCons.Errors.UserError: + pass + else: + self.fail('Did not catch expected UserError') + finally: + SCons.Util.md5 = save_md5 def test_Split(self): """Test the Split() method""" - env = Environment(FOO='fff', BAR='bbb') + env = self.TestEnvironment(FOO='fff', BAR='bbb') s = env.Split("foo bar") assert s == ["foo", "bar"], s s = env.Split("$FOO bar") @@ -2651,7 +3319,9 @@ f5: \ def test_TargetSignatures(type): """Test the TargetSignatures() method""" - env = Environment(B = 'build', C = 'content') + import SCons.Errors + + env = type.TestEnvironment(B = 'build', C = 'content') exc_caught = None try: @@ -2662,16 +3332,41 @@ f5: \ assert not hasattr(env, '_build_signature') env.TargetSignatures('build') - assert env._build_signature == 1, env._build_signature - - env.TargetSignatures('content') - assert env._build_signature == 0, env._build_signature + assert env.tgt_sig_type == 'build', env.tgt_sig_type env.TargetSignatures('$B') - assert env._build_signature == 1, env._build_signature + assert env.tgt_sig_type == 'build', env.tgt_sig_type + + env.TargetSignatures('content') + assert env.tgt_sig_type == 'content', env.tgt_sig_type env.TargetSignatures('$C') - assert env._build_signature == 0, env._build_signature + assert env.tgt_sig_type == 'content', env.tgt_sig_type + + env.TargetSignatures('MD5') + assert env.tgt_sig_type == 'MD5', env.tgt_sig_type + + env.TargetSignatures('timestamp') + assert env.tgt_sig_type == 'timestamp', env.tgt_sig_type + + try: + import SCons.Util + save_md5 = SCons.Util.md5 + SCons.Util.md5 = None + try: + env.TargetSignatures('MD5') + except SCons.Errors.UserError: + pass + else: + self.fail('Did not catch expected UserError') + try: + env.TargetSignatures('content') + except SCons.Errors.UserError: + pass + else: + self.fail('Did not catch expected UserError') + finally: + SCons.Util.md5 = save_md5 def test_Value(self): """Test creating a Value() object @@ -2688,6 +3383,9 @@ f5: \ assert not v1 is v2 assert v1.value == v2.value + v3 = env.Value('c', 'build-c') + assert v3.value == 'c', v3.value + def test_Environment_global_variable(type): @@ -2706,114 +3404,182 @@ f5: \ f = env.xxx('$FOO') assert f == 'foo', f - def test_bad_keywords(type): + def test_bad_keywords(self): """Test trying to use reserved keywords in an Environment""" - reserved = ['TARGETS','SOURCES', 'SOURCE','TARGET'] added = [] - env = SCons.Environment.Environment(TARGETS = 'targets', - SOURCES = 'sources', - SOURCE = 'source', - TARGET = 'target', - INIT = 'init') + env = self.TestEnvironment(TARGETS = 'targets', + SOURCES = 'sources', + SOURCE = 'source', + TARGET = 'target', + CHANGED_SOURCES = 'changed_sources', + CHANGED_TARGETS = 'changed_targets', + UNCHANGED_SOURCES = 'unchanged_sources', + UNCHANGED_TARGETS = 'unchanged_targets', + INIT = 'init') + bad_msg = '%s is not reserved, but got omitted; see Environment.construction_var_name_ok' added.append('INIT') - for x in reserved: - assert not env.has_key(x), env[x] + for x in self.reserved_variables: + assert x not in env, env[x] for x in added: - assert env.has_key(x), \ - '%s is not reserved, but got omitted; see Environment.construction_var_name_ok'%x + assert x in env, bad_msg % x env.Append(TARGETS = 'targets', SOURCES = 'sources', SOURCE = 'source', TARGET = 'target', + CHANGED_SOURCES = 'changed_sources', + CHANGED_TARGETS = 'changed_targets', + UNCHANGED_SOURCES = 'unchanged_sources', + UNCHANGED_TARGETS = 'unchanged_targets', APPEND = 'append') added.append('APPEND') - for x in reserved: - assert not env.has_key(x), env[x] + for x in self.reserved_variables: + assert x not in env, env[x] for x in added: - assert env.has_key(x), \ - '%s is not reserved, but got omitted; see Environment.construction_var_name_ok'%x + assert x in env, bad_msg % x env.AppendUnique(TARGETS = 'targets', SOURCES = 'sources', SOURCE = 'source', TARGET = 'target', + CHANGED_SOURCES = 'changed_sources', + CHANGED_TARGETS = 'changed_targets', + UNCHANGED_SOURCES = 'unchanged_sources', + UNCHANGED_TARGETS = 'unchanged_targets', APPENDUNIQUE = 'appendunique') added.append('APPENDUNIQUE') - for x in reserved: - assert not env.has_key(x), env[x] + for x in self.reserved_variables: + assert x not in env, env[x] for x in added: - assert env.has_key(x), \ - '%s is not reserved, but got omitted; see Environment.construction_var_name_ok'%x + assert x in env, bad_msg % x env.Prepend(TARGETS = 'targets', SOURCES = 'sources', SOURCE = 'source', TARGET = 'target', + CHANGED_SOURCES = 'changed_sources', + CHANGED_TARGETS = 'changed_targets', + UNCHANGED_SOURCES = 'unchanged_sources', + UNCHANGED_TARGETS = 'unchanged_targets', PREPEND = 'prepend') added.append('PREPEND') - for x in reserved: - assert not env.has_key(x), env[x] + for x in self.reserved_variables: + assert x not in env, env[x] for x in added: - assert env.has_key(x), \ - '%s is not reserved, but got omitted; see Environment.construction_var_name_ok'%x + assert x in env, bad_msg % x env.Prepend(TARGETS = 'targets', SOURCES = 'sources', SOURCE = 'source', TARGET = 'target', + CHANGED_SOURCES = 'changed_sources', + CHANGED_TARGETS = 'changed_targets', + UNCHANGED_SOURCES = 'unchanged_sources', + UNCHANGED_TARGETS = 'unchanged_targets', PREPENDUNIQUE = 'prependunique') added.append('PREPENDUNIQUE') - for x in reserved: - assert not env.has_key(x), env[x] + for x in self.reserved_variables: + assert x not in env, env[x] for x in added: - assert env.has_key(x), \ - '%s is not reserved, but got omitted; see Environment.construction_var_name_ok'%x + assert x in env, bad_msg % x env.Replace(TARGETS = 'targets', SOURCES = 'sources', SOURCE = 'source', TARGET = 'target', + CHANGED_SOURCES = 'changed_sources', + CHANGED_TARGETS = 'changed_targets', + UNCHANGED_SOURCES = 'unchanged_sources', + UNCHANGED_TARGETS = 'unchanged_targets', REPLACE = 'replace') added.append('REPLACE') - for x in reserved: - assert not env.has_key(x), env[x] + for x in self.reserved_variables: + assert x not in env, env[x] for x in added: - assert env.has_key(x), \ - '%s is not reserved, but got omitted; see Environment.construction_var_name_ok'%x - - copy = env.Copy(TARGETS = 'targets', - SOURCES = 'sources', - SOURCE = 'source', - TARGET = 'target', - COPY = 'copy') - for x in reserved: - assert not copy.has_key(x), env[x] + assert x in env, bad_msg % x + + copy = env.Clone(TARGETS = 'targets', + SOURCES = 'sources', + SOURCE = 'source', + TARGET = 'target', + CHANGED_SOURCES = 'changed_sources', + CHANGED_TARGETS = 'changed_targets', + UNCHANGED_SOURCES = 'unchanged_sources', + UNCHANGED_TARGETS = 'unchanged_targets', + COPY = 'copy') + for x in self.reserved_variables: + assert x not in copy, env[x] for x in added + ['COPY']: - assert copy.has_key(x), \ - '%s is not reserved, but got omitted; see Environment.construction_var_name_ok'%x + assert x in copy, bad_msg % x over = env.Override({'TARGETS' : 'targets', 'SOURCES' : 'sources', 'SOURCE' : 'source', 'TARGET' : 'target', + 'CHANGED_SOURCES' : 'changed_sources', + 'CHANGED_TARGETS' : 'changed_targets', + 'UNCHANGED_SOURCES' : 'unchanged_sources', + 'UNCHANGED_TARGETS' : 'unchanged_targets', 'OVERRIDE' : 'override'}) - for x in reserved: - assert not over.has_key(x), over[x] + for x in self.reserved_variables: + assert x not in over, over[x] for x in added + ['OVERRIDE']: - assert over.has_key(x), \ - '%s is not reserved, but got omitted; see Environment.construction_var_name_ok'%x + assert x in over, bad_msg % x + + def test_parse_flags(self): + '''Test the Base class parse_flags argument''' + # all we have to show is that it gets to MergeFlags internally + env = Environment(tools=[], parse_flags = '-X') + assert env['CCFLAGS'] == ['-X'], env['CCFLAGS'] + + env = Environment(tools=[], CCFLAGS=None, parse_flags = '-Y') + assert env['CCFLAGS'] == ['-Y'], env['CCFLAGS'] + + env = Environment(tools=[], CPPDEFINES = 'FOO', parse_flags = '-std=c99 -X -DBAR') + assert env['CFLAGS'] == ['-std=c99'], env['CFLAGS'] + assert env['CCFLAGS'] == ['-X'], env['CCFLAGS'] + assert env['CPPDEFINES'] == ['FOO', 'BAR'], env['CPPDEFINES'] + + def test_clone_parse_flags(self): + '''Test the env.Clone() parse_flags argument''' + # all we have to show is that it gets to MergeFlags internally + env = Environment(tools = []) + env2 = env.Clone(parse_flags = '-X') + assert 'CCFLAGS' not in env + assert env2['CCFLAGS'] == ['-X'], env2['CCFLAGS'] + + env = Environment(tools = [], CCFLAGS=None) + env2 = env.Clone(parse_flags = '-Y') + assert env['CCFLAGS'] is None, env['CCFLAGS'] + assert env2['CCFLAGS'] == ['-Y'], env2['CCFLAGS'] + env = Environment(tools = [], CPPDEFINES = 'FOO') + env2 = env.Clone(parse_flags = '-std=c99 -X -DBAR') + assert 'CFLAGS' not in env + assert env2['CFLAGS'] == ['-std=c99'], env2['CFLAGS'] + assert 'CCFLAGS' not in env + assert env2['CCFLAGS'] == ['-X'], env2['CCFLAGS'] + assert env['CPPDEFINES'] == 'FOO', env['CPPDEFINES'] + assert env2['CPPDEFINES'] == ['FOO','BAR'], env2['CPPDEFINES'] -class OverrideEnvironmentTestCase(unittest.TestCase): + +class OverrideEnvironmentTestCase(unittest.TestCase,TestEnvironmentFixture): + + def setUp(self): + env = Environment() + env._dict = {'XXX' : 'x', 'YYY' : 'y'} + env2 = OverrideEnvironment(env, {'XXX' : 'x2'}) + env3 = OverrideEnvironment(env2, {'XXX' : 'x3', 'YYY' : 'y3', 'ZZZ' : 'z3'}) + self.envs = [ env, env2, env3 ] + + def checkpath(self, node, expect): + return str(node) == os.path.normpath(expect) def test___init__(self): """Test OverrideEnvironment initialization""" - env = Environment(XXX = 'x', YYY = 'y') - env2 = OverrideEnvironment(env, {'XXX' : 'x2'}) - env3 = OverrideEnvironment(env2, {'XXX' : 'x3', 'YYY' : 'y3'}) + env, env2, env3 = self.envs assert env['XXX'] == 'x', env['XXX'] assert env2['XXX'] == 'x2', env2['XXX'] assert env3['XXX'] == 'x3', env3['XXX'] @@ -2821,77 +3587,115 @@ class OverrideEnvironmentTestCase(unittest.TestCase): assert env2['YYY'] == 'y', env2['YYY'] assert env3['YYY'] == 'y3', env3['YYY'] + def test___delitem__(self): + """Test deleting variables from an OverrideEnvironment""" + env, env2, env3 = self.envs + + del env3['XXX'] + assert 'XXX' not in env, "env has XXX?" + assert 'XXX' not in env2, "env2 has XXX?" + assert 'XXX' not in env3, "env3 has XXX?" + + del env3['YYY'] + assert 'YYY' not in env, "env has YYY?" + assert 'YYY' not in env2, "env2 has YYY?" + assert 'YYY' not in env3, "env3 has YYY?" + + del env3['ZZZ'] + assert 'ZZZ' not in env, "env has ZZZ?" + assert 'ZZZ' not in env2, "env2 has ZZZ?" + assert 'ZZZ' not in env3, "env3 has ZZZ?" + def test_get(self): """Test the OverrideEnvironment get() method""" - env = Environment(XXX = 'x', YYY = 'y') - env2 = OverrideEnvironment(env, {'XXX' : 'x2'}) - env3 = OverrideEnvironment(env2, {'XXX' : 'x3', 'YYY' : 'y3', 'ZZZ' : 'z3'}) + env, env2, env3 = self.envs assert env.get('XXX') == 'x', env.get('XXX') assert env2.get('XXX') == 'x2', env2.get('XXX') assert env3.get('XXX') == 'x3', env3.get('XXX') assert env.get('YYY') == 'y', env.get('YYY') assert env2.get('YYY') == 'y', env2.get('YYY') assert env3.get('YYY') == 'y3', env3.get('YYY') - assert env.get('ZZZ') == None, env.get('ZZZ') - assert env2.get('ZZZ') == None, env2.get('ZZZ') + assert env.get('ZZZ') is None, env.get('ZZZ') + assert env2.get('ZZZ') is None, env2.get('ZZZ') assert env3.get('ZZZ') == 'z3', env3.get('ZZZ') def test_has_key(self): """Test the OverrideEnvironment has_key() method""" - env = Environment(XXX = 'x', YYY = 'y') - env2 = OverrideEnvironment(env, {'XXX' : 'x2'}) - env3 = OverrideEnvironment(env2, {'XXX' : 'x3', 'YYY' : 'y3', 'ZZZ' : 'z3'}) - assert env.has_key('XXX'), env.has_key('XXX') - assert env2.has_key('XXX'), env2.has_key('XXX') - assert env3.has_key('XXX'), env3.has_key('XXX') - assert env.has_key('YYY'), env.has_key('YYY') - assert env2.has_key('YYY'), env2.has_key('YYY') - assert env3.has_key('YYY'), env3.has_key('YYY') - assert not env.has_key('ZZZ'), env.has_key('ZZZ') - assert not env2.has_key('ZZZ'), env2.has_key('ZZZ') - assert env3.has_key('ZZZ'), env3.has_key('ZZZ') + env, env2, env3 = self.envs + assert 'XXX' in env, 'XXX' in env + assert 'XXX' in env2, 'XXX' in env2 + assert 'XXX' in env3, 'XXX' in env3 + assert 'YYY' in env, 'YYY' in env + assert 'YYY' in env2, 'YYY' in env2 + assert 'YYY' in env3, 'YYY' in env3 + assert 'ZZZ' not in env, 'ZZZ' in env + assert 'ZZZ' not in env2, 'ZZZ' in env2 + assert 'ZZZ' in env3, 'ZZZ' in env3 + + def test_contains(self): + """Test the OverrideEnvironment __contains__() method""" + try: + 'x' in {'x':1} + except TypeError: + # TODO(1.5) + # An early version of Python that doesn't support "in" + # on dictionaries. Just pass the test. + pass + else: + env, env2, env3 = self.envs + assert 'XXX' in env + assert 'XXX' in env2 + assert 'XXX' in env3 + assert 'YYY' in env + assert 'YYY' in env2 + assert 'YYY' in env3 + assert not 'ZZZ' in env + assert not 'ZZZ' in env2 + assert 'ZZZ' in env3 + + def test_items(self): + """Test the OverrideEnvironment Dictionary() method""" + env, env2, env3 = self.envs + items = env.Dictionary() + assert items == {'XXX' : 'x', 'YYY' : 'y'}, items + items = env2.Dictionary() + assert items == {'XXX' : 'x2', 'YYY' : 'y'}, items + items = env3.Dictionary() + assert items == {'XXX' : 'x3', 'YYY' : 'y3', 'ZZZ' : 'z3'}, items def test_items(self): """Test the OverrideEnvironment items() method""" - env = Environment(WWW = 'w', XXX = 'x', YYY = 'y') - env2 = OverrideEnvironment(env, {'XXX' : 'x2'}) - env3 = OverrideEnvironment(env2, {'XXX' : 'x3', 'YYY' : 'y3', 'ZZZ' : 'z3'}) - items = env.items() - assert items == {'WWW' : 'w', 'XXX' : 'x', 'YYY' : 'y'}, items - items = env2.items() - assert items == {'WWW' : 'w', 'XXX' : 'x2', 'YYY' : 'y'}, items - items = env3.items() - assert items == {'WWW' : 'w', 'XXX' : 'x3', 'YYY' : 'y3', 'ZZZ' : 'z3'}, items + env, env2, env3 = self.envs + items = sorted(env.items()) + assert items == [('XXX', 'x'), ('YYY', 'y')], items + items = sorted(env2.items()) + assert items == [('XXX', 'x2'), ('YYY', 'y')], items + items = sorted(env3.items()) + assert items == [('XXX', 'x3'), ('YYY', 'y3'), ('ZZZ', 'z3')], items def test_gvars(self): """Test the OverrideEnvironment gvars() method""" - env = Environment(XXX = 'x', YYY = 'y') - env2 = OverrideEnvironment(env, {'xxx' : 'x2'}) - env3 = OverrideEnvironment(env2, {'XXX' : 'x3', 'YYY' : 'y3'}) + env, env2, env3 = self.envs gvars = env.gvars() assert gvars == {'XXX' : 'x', 'YYY' : 'y'}, gvars gvars = env2.gvars() - assert gvars == {'XXX' : 'x2', 'YYY' : 'y'}, gvars + assert gvars == {'XXX' : 'x', 'YYY' : 'y'}, gvars gvars = env3.gvars() - assert gvars == {'XXX' : 'x3', 'YYY' : 'y3'}, gvars + assert gvars == {'XXX' : 'x', 'YYY' : 'y'}, gvars def test_lvars(self): """Test the OverrideEnvironment lvars() method""" - env = Environment(XXX = 'x', YYY = 'y') - env2 = OverrideEnvironment(env, {'xxx' : 'x2'}) - env3 = OverrideEnvironment(env2, {'xxx' : 'x3', 'YYY' : 'y3'}) + env, env2, env3 = self.envs lvars = env.lvars() assert lvars == {}, lvars lvars = env2.lvars() - assert lvars == {'XXX' : 'x2', 'YYY' : 'y'}, lvars + assert lvars == {'XXX' : 'x2'}, lvars lvars = env3.lvars() - assert lvars == {'XXX' : 'x3', 'YYY' : 'y3'}, lvars + assert lvars == {'XXX' : 'x3', 'YYY' : 'y3', 'ZZZ' : 'z3'}, lvars def test_Replace(self): """Test the OverrideEnvironment Replace() method""" - env = Environment(XXX = 'x', YYY = 'y') - env2 = OverrideEnvironment(env, {'xxx' : 'x2'}) - env3 = OverrideEnvironment(env2, {'xxx' : 'x3', 'YYY' : 'y3'}) + env, env2, env3 = self.envs assert env['XXX'] == 'x', env['XXX'] assert env2['XXX'] == 'x2', env2['XXX'] assert env3['XXX'] == 'x3', env3['XXX'] @@ -2908,14 +3712,132 @@ class OverrideEnvironmentTestCase(unittest.TestCase): assert env2['YYY'] == 'y4', env2['YYY'] assert env3['YYY'] == 'y3', env3['YYY'] + # Tests a number of Base methods through an OverrideEnvironment to + # make sure they handle overridden constructionv variables properly. + # + # The following Base methods also call self.subst(), and so could + # theoretically be subject to problems with evaluating overridden + # variables, but they're never really called that way in the rest + # of our code, so we won't worry about them (at least for now): + # + # ParseConfig() + # ParseDepends() + # Platform() + # Tool() + # + # Action() + # Alias() + # Builder() + # CacheDir() + # Configure() + # Environment() + # FindFile() + # Scanner() + # SourceSignatures() + # TargetSignatures() + + # It's unlikely Clone() will ever be called this way, so let the + # other methods test that handling overridden values works. + #def test_Clone(self): + # """Test the OverrideEnvironment Clone() method""" + # pass + def test_FindIxes(self): + """Test the OverrideEnvironment FindIxes() method""" + env, env2, env3 = self.envs + x = env.FindIxes(['xaaay'], 'XXX', 'YYY') + assert x == 'xaaay', x + x = env2.FindIxes(['x2aaay'], 'XXX', 'YYY') + assert x == 'x2aaay', x + x = env3.FindIxes(['x3aaay3'], 'XXX', 'YYY') + assert x == 'x3aaay3', x + def test_ReplaceIxes(self): + """Test the OverrideEnvironment ReplaceIxes() method""" + env, env2, env3 = self.envs + x = env.ReplaceIxes('xaaay', 'XXX', 'YYY', 'YYY', 'XXX') + assert x == 'yaaax', x + x = env2.ReplaceIxes('x2aaay', 'XXX', 'YYY', 'YYY', 'XXX') + assert x == 'yaaax2', x + x = env3.ReplaceIxes('x3aaay3', 'XXX', 'YYY', 'YYY', 'XXX') + assert x == 'y3aaax3', x + + # It's unlikely WhereIs() will ever be called this way, so let the + # other methods test that handling overridden values works. + #def test_WhereIs(self): + # """Test the OverrideEnvironment WhereIs() method""" + # pass -class NoSubstitutionProxyTestCase(unittest.TestCase): + def test_Dir(self): + """Test the OverrideEnvironment Dir() method""" + env, env2, env3 = self.envs + x = env.Dir('ddir/$XXX') + assert self.checkpath(x, 'ddir/x'), str(x) + x = env2.Dir('ddir/$XXX') + assert self.checkpath(x, 'ddir/x2'), str(x) + x = env3.Dir('ddir/$XXX') + assert self.checkpath(x, 'ddir/x3'), str(x) + + def test_Entry(self): + """Test the OverrideEnvironment Entry() method""" + env, env2, env3 = self.envs + x = env.Entry('edir/$XXX') + assert self.checkpath(x, 'edir/x'), str(x) + x = env2.Entry('edir/$XXX') + assert self.checkpath(x, 'edir/x2'), str(x) + x = env3.Entry('edir/$XXX') + assert self.checkpath(x, 'edir/x3'), str(x) + + def test_File(self): + """Test the OverrideEnvironment File() method""" + env, env2, env3 = self.envs + x = env.File('fdir/$XXX') + assert self.checkpath(x, 'fdir/x'), str(x) + x = env2.File('fdir/$XXX') + assert self.checkpath(x, 'fdir/x2'), str(x) + x = env3.File('fdir/$XXX') + assert self.checkpath(x, 'fdir/x3'), str(x) + + def test_Split(self): + """Test the OverrideEnvironment Split() method""" + env, env2, env3 = self.envs + env['AAA'] = '$XXX $YYY $ZZZ' + x = env.Split('$AAA') + assert x == ['x', 'y'], x + x = env2.Split('$AAA') + assert x == ['x2', 'y'], x + x = env3.Split('$AAA') + assert x == ['x3', 'y3', 'z3'], x + + def test_parse_flags(self): + '''Test the OverrideEnvironment parse_flags argument''' + # all we have to show is that it gets to MergeFlags internally + env = SubstitutionEnvironment() + env2 = env.Override({'parse_flags' : '-X'}) + assert 'CCFLAGS' not in env + assert env2['CCFLAGS'] == ['-X'], env2['CCFLAGS'] + + env = SubstitutionEnvironment(CCFLAGS=None) + env2 = env.Override({'parse_flags' : '-Y'}) + assert env['CCFLAGS'] is None, env['CCFLAGS'] + assert env2['CCFLAGS'] == ['-Y'], env2['CCFLAGS'] + + env = SubstitutionEnvironment(CPPDEFINES = 'FOO') + env2 = env.Override({'parse_flags' : '-std=c99 -X -DBAR'}) + assert 'CFLAGS' not in env + assert env2['CFLAGS'] == ['-std=c99'], env2['CFLAGS'] + assert 'CCFLAGS' not in env + assert env2['CCFLAGS'] == ['-X'], env2['CCFLAGS'] + assert env['CPPDEFINES'] == 'FOO', env['CPPDEFINES'] + assert env2['CPPDEFINES'] == ['FOO','BAR'], env2['CPPDEFINES'] + + + +class NoSubstitutionProxyTestCase(unittest.TestCase,TestEnvironmentFixture): def test___init__(self): """Test NoSubstitutionProxy initialization""" - env = Environment(XXX = 'x', YYY = 'y') + env = self.TestEnvironment(XXX = 'x', YYY = 'y') assert env['XXX'] == 'x', env['XXX'] assert env['YYY'] == 'y', env['YYY'] @@ -2943,7 +3865,7 @@ class NoSubstitutionProxyTestCase(unittest.TestCase): def test_subst(self): """Test the NoSubstitutionProxy.subst() method""" - env = Environment(XXX = 'x', YYY = 'y') + env = self.TestEnvironment(XXX = 'x', YYY = 'y') assert env['XXX'] == 'x', env['XXX'] assert env['YYY'] == 'y', env['YYY'] @@ -2963,7 +3885,7 @@ class NoSubstitutionProxyTestCase(unittest.TestCase): def test_subst_kw(self): """Test the NoSubstitutionProxy.subst_kw() method""" - env = Environment(XXX = 'x', YYY = 'y') + env = self.TestEnvironment(XXX = 'x', YYY = 'y') assert env['XXX'] == 'x', env['XXX'] assert env['YYY'] == 'y', env['YYY'] @@ -2978,7 +3900,7 @@ class NoSubstitutionProxyTestCase(unittest.TestCase): def test_subst_list(self): """Test the NoSubstitutionProxy.subst_list() method""" - env = Environment(XXX = 'x', YYY = 'y') + env = self.TestEnvironment(XXX = 'x', YYY = 'y') assert env['XXX'] == 'x', env['XXX'] assert env['YYY'] == 'y', env['YYY'] @@ -2996,7 +3918,7 @@ class NoSubstitutionProxyTestCase(unittest.TestCase): def test_subst_target_source(self): """Test the NoSubstitutionProxy.subst_target_source() method""" - env = Environment(XXX = 'x', YYY = 'y') + env = self.TestEnvironment(XXX = 'x', YYY = 'y') assert env['XXX'] == 'x', env['XXX'] assert env['YYY'] == 'y', env['YYY'] @@ -3006,20 +3928,61 @@ class NoSubstitutionProxyTestCase(unittest.TestCase): args = ('$XXX $TARGET $SOURCE $YYY',) kw = {'target' : DummyNode('ttt'), 'source' : DummyNode('sss')} - x = apply(env.subst_target_source, args, kw) + x = env.subst_target_source(*args, **kw) assert x == 'x ttt sss y', x - x = apply(proxy.subst_target_source, args, kw) + x = proxy.subst_target_source(*args, **kw) assert x == ' ttt sss ', x +class EnvironmentVariableTestCase(unittest.TestCase): + + def test_is_valid_construction_var(self): + """Testing is_valid_construction_var()""" + r = is_valid_construction_var("_a") + assert r is not None, r + r = is_valid_construction_var("z_") + assert r is not None, r + r = is_valid_construction_var("X_") + assert r is not None, r + r = is_valid_construction_var("2a") + assert r is None, r + r = is_valid_construction_var("a2_") + assert r is not None, r + r = is_valid_construction_var("/") + assert r is None, r + r = is_valid_construction_var("_/") + assert r is None, r + r = is_valid_construction_var("a/") + assert r is None, r + r = is_valid_construction_var(".b") + assert r is None, r + r = is_valid_construction_var("_.b") + assert r is None, r + r = is_valid_construction_var("b1._") + assert r is None, r + r = is_valid_construction_var("-b") + assert r is None, r + r = is_valid_construction_var("_-b") + assert r is None, r + r = is_valid_construction_var("b1-_") + assert r is None, r + if __name__ == "__main__": suite = unittest.TestSuite() tclasses = [ SubstitutionTestCase, BaseTestCase, - NoSubstitutionProxyTestCase ] + OverrideEnvironmentTestCase, + NoSubstitutionProxyTestCase, + EnvironmentVariableTestCase ] for tclass in tclasses: names = unittest.getTestCaseNames(tclass, 'test_') - suite.addTests(map(tclass, names)) + suite.addTests(list(map(tclass, names))) if not unittest.TextTestRunner().run(suite).wasSuccessful(): sys.exit(1) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: