From: stevenknight Date: Sun, 7 Sep 2003 04:14:49 +0000 (+0000) Subject: Rearrange the Environment methods and tests. X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=e00e0613dccf4e5427d05e9b9a5699121a4944e9;p=scons.git Rearrange the Environment methods and tests. git-svn-id: http://scons.tigris.org/svn/scons/trunk@789 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py index f72bc953..e7407ee6 100644 --- a/src/engine/SCons/Environment.py +++ b/src/engine/SCons/Environment.py @@ -59,6 +59,8 @@ class _Null: _null = _Null +DefaultTargets = None + def installFunc(target, source, env): """Install a source file into a target using the function specified as the INSTALL construction variable.""" @@ -169,6 +171,20 @@ class Environment: Environment. """ + ####################################################################### + # This is THE class for interacting with the SCons build engine, + # and it contains a lot of stuff, so we're going to try to keep this + # a little organized by grouping the methods. + ####################################################################### + + ####################################################################### + # Methods that make an Environment act like a dictionary. These have + # the expected standard names for Python mapping objects. Note that + # we don't actually make an Environment a subclass of UserDict for + # performance reasons. Note also that we only supply methods for + # dictionary functionality that we actually need and use. + ####################################################################### + def __init__(self, platform=None, tools=None, @@ -217,6 +233,46 @@ class Environment: def __cmp__(self, other): return cmp(self._dict, other._dict) + def __getitem__(self, key): + return self._dict[key] + + def __setitem__(self, key, value): + if key in ['TARGET', 'TARGETS', 'SOURCE', 'SOURCES']: + SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning, + "Ignoring attempt to set reserved variable `%s'" % key) + elif key == 'BUILDERS': + try: + bd = self._dict[key] + for k in bd.keys(): + del bd[k] + except KeyError: + self._dict[key] = BuilderDict(kwbd, self) + self._dict[key].update(value) + else: + if not SCons.Util.is_valid_construction_var(key): + raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key + self._dict[key] = value + + def __delitem__(self, key): + del self._dict[key] + + def items(self): + "Emulates the items() method of dictionaries.""" + return self._dict.items() + + def has_key(self, key): + return self._dict.has_key(key) + + def get(self, key, default=None): + "Emulates the get() method of dictionaries.""" + return self._dict.get(key, default) + + ####################################################################### + # Utility methods that are primarily for internal use by SCons. + # These begin with lower-case letters. Note that the subst() method + # is actually already out of the closet and used by people. + ####################################################################### + def arg2nodes(self, args, node_factory=_null, lookup_list=_null): if node_factory is _null: node_factory = self.fs.File @@ -251,8 +307,99 @@ class Environment: return nodes - def Builders(self): - pass # XXX + def get_builder(self, name): + """Fetch the builder with the specified name from the environment. + """ + try: + return self._dict['BUILDERS'][name] + except KeyError: + return None + + def get_scanner(self, skey): + """Find the appropriate scanner given a key (usually a file suffix). + Does a linear search. Could be sped up by creating a dictionary if + this proves too slow. + """ + if self._dict['SCANNERS']: + for scanner in self._dict['SCANNERS']: + if skey in scanner.skeys: + return scanner + return None + + def subst(self, string, raw=0, target=None, source=None): + """Recursively interpolates construction variables from the + Environment into the specified string, returning the expanded + result. Construction variables are specified by a $ prefix + in the string and begin with an initial underscore or + alphabetic character followed by any number of underscores + or alphanumeric characters. The construction variable names + may be surrounded by curly braces to separate the name from + trailing characters. + """ + if raw: + mode = SCons.Util.SUBST_RAW + else: + mode = SCons.Util.SUBST_CMD + return SCons.Util.scons_subst(string, self, mode, + target, source) + + def subst_list(self, string, raw=0, target=None, source=None): + """Calls through to SCons.Util.scons_subst_list(). See + the documentation for that function.""" + if raw: + mode = SCons.Util.SUBST_RAW + else: + mode = SCons.Util.SUBST_CMD + return SCons.Util.scons_subst_list(string, self, mode, + target, source) + + ####################################################################### + # Public methods for manipulating an Environment. These begin with + # upper-case letters. The essential characteristic of methods in + # this section is that they do *not* have corresponding same-named + # global functions. For example, a stand-alone Append() function + # makes no sense, because Append() is all about appending values to + # an Environment's construction variables. + ####################################################################### + + def Append(self, **kw): + """Append values to existing construction variables + in an Environment. + """ + kw = our_deepcopy(kw) + for key in kw.keys(): + if not self._dict.has_key(key): + self._dict[key] = kw[key] + elif SCons.Util.is_List(self._dict[key]) and not \ + SCons.Util.is_List(kw[key]): + self._dict[key] = self._dict[key] + [ kw[key] ] + elif SCons.Util.is_List(kw[key]) and not \ + SCons.Util.is_List(self._dict[key]): + self._dict[key] = [ self._dict[key] ] + kw[key] + elif SCons.Util.is_Dict(self._dict[key]) and \ + SCons.Util.is_Dict(kw[key]): + self._dict[key].update(kw[key]) + else: + self._dict[key] = self._dict[key] + kw[key] + + def AppendENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep): + """Append path elements to the path 'name' in the 'ENV' + dictionary for this environment. Will only add any particular + path once, and will normpath and normcase all paths to help + assure this. This can also handle the case where the env + variable is a list instead of a string. + """ + + orig = '' + if self._dict.has_key(envname) and self._dict[envname].has_key(name): + orig = self._dict[envname][name] + + nv = SCons.Util.AppendPath(orig, newpath, sep) + + if not self._dict.has_key(envname): + self._dict[envname] = {} + + self._dict[envname][name] = nv def Copy(self, tools=None, **kw): """Return a copy of a construction Environment. The @@ -276,40 +423,62 @@ class Environment: apply(clone.Replace, (), kw) return clone - def Scanners(self): - pass # XXX + def Detect(self, progs): + """Return the first available program in progs. + """ + if not SCons.Util.is_List(progs): + progs = [ progs ] + for prog in progs: + path = self.WhereIs(prog) + if path: return prog + return None + + def Dictionary(self, *args): + if not args: + return self._dict + dlist = map(lambda x, s=self: s._dict[x], args) + if len(dlist) == 1: + dlist = dlist[0] + return dlist - def Replace(self, **kw): - """Replace existing construction variables in an Environment - with new construction variables and/or values. + def FindIxes(self, paths, prefix, suffix): """ - try: - kwbd = our_deepcopy(kw['BUILDERS']) - del kw['BUILDERS'] - self.__setitem__('BUILDERS', kwbd) - except KeyError: - pass - self._dict.update(our_deepcopy(kw)) + Search a list of paths for something that matches the prefix and suffix. - def Append(self, **kw): - """Append values to existing construction variables - in an Environment. + paths - the list of paths or nodes. + prefix - construction variable for the prefix. + suffix - construction variable for the suffix. """ - kw = our_deepcopy(kw) - for key in kw.keys(): - if not self._dict.has_key(key): - self._dict[key] = kw[key] - elif SCons.Util.is_List(self._dict[key]) and not \ - SCons.Util.is_List(kw[key]): - self._dict[key] = self._dict[key] + [ kw[key] ] - elif SCons.Util.is_List(kw[key]) and not \ - SCons.Util.is_List(self._dict[key]): - self._dict[key] = [ self._dict[key] ] + kw[key] - elif SCons.Util.is_Dict(self._dict[key]) and \ - SCons.Util.is_Dict(kw[key]): - self._dict[key].update(kw[key]) - else: - self._dict[key] = self._dict[key] + kw[key] + + suffix = self.subst('$%s'%suffix) + prefix = self.subst('$%s'%prefix) + + for path in paths: + dir,name = os.path.split(str(path)) + if name[:len(prefix)] == prefix and name[-len(suffix):] == suffix: + return path + + def Override(self, overrides): + """ + Produce a modified environment whose variables + are overriden by the overrides dictionaries. + + overrides - a dictionary that will override + the variables of this environment. + + This function is much more efficient than Copy() + or creating a new Environment because it doesn't do + a deep copy of the dictionary, and doesn't do a copy + at all if there are no overrides. + """ + + if overrides: + env = copy.copy(self) + env._dict = copy.copy(self._dict) + env._dict.update(overrides) + return env + else: + return self def Prepend(self, **kw): """Prepend values to existing construction variables @@ -350,47 +519,63 @@ class Environment: self._dict[envname][name] = nv - def AppendENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep): - """Append path elements to the path 'name' in the 'ENV' - dictionary for this environment. Will only add any particular - path once, and will normpath and normcase all paths to help - assure this. This can also handle the case where the env - variable is a list instead of a string. + def Replace(self, **kw): + """Replace existing construction variables in an Environment + with new construction variables and/or values. """ + try: + kwbd = our_deepcopy(kw['BUILDERS']) + del kw['BUILDERS'] + self.__setitem__('BUILDERS', kwbd) + except KeyError: + pass + self._dict.update(our_deepcopy(kw)) - orig = '' - if self._dict.has_key(envname) and self._dict[envname].has_key(name): - orig = self._dict[envname][name] - - nv = SCons.Util.AppendPath(orig, newpath, sep) - - if not self._dict.has_key(envname): - self._dict[envname] = {} + def ReplaceIxes(self, path, old_prefix, old_suffix, new_prefix, new_suffix): + """ + Replace old_prefix with new_prefix and old_suffix with new_suffix. - self._dict[envname][name] = nv + env - Environment used to interpolate variables. + path - the path that will be modified. + old_prefix - construction variable for the old prefix. + old_suffix - construction variable for the old suffix. + new_prefix - construction variable for the new prefix. + new_suffix - construction variable for the new suffix. + """ + old_prefix = self.subst('$%s'%old_prefix) + old_suffix = self.subst('$%s'%old_suffix) + new_prefix = self.subst('$%s'%new_prefix) + new_suffix = self.subst('$%s'%new_suffix) - def Depends(self, target, dependency): - """Explicity specify that 'target's depend on 'dependency'.""" - tlist = self.arg2nodes(target, self.fs.File) - dlist = self.arg2nodes(dependency, self.fs.File) - for t in tlist: - t.add_dependency(dlist) + dir,name = os.path.split(str(path)) + if name[:len(old_prefix)] == old_prefix: + name = name[len(old_prefix):] + if name[-len(old_suffix):] == old_suffix: + name = name[:-len(old_suffix)] + return os.path.join(dir, new_prefix+name+new_suffix) - if len(tlist) == 1: - tlist = tlist[0] - return tlist - - def Ignore(self, target, dependency): - """Ignore a dependency.""" - tlist = self.arg2nodes(target, self.fs.File) - dlist = self.arg2nodes(dependency, self.fs.File) - for t in tlist: - t.add_ignore(dlist) + def WhereIs(self, prog): + """Find prog in the path. + """ + path = None + pathext = None + if self.has_key('ENV'): + if self['ENV'].has_key('PATH'): + path = self['ENV']['PATH'] + if self['ENV'].has_key('PATHEXT'): + pathext = self['ENV']['PATHEXT'] + path = SCons.Util.WhereIs(prog, path, pathext) + if path: return path + return None - if len(tlist) == 1: - tlist = tlist[0] - return tlist + ####################################################################### + # Public methods for doing real "SCons stuff" (manipulating + # dependencies, setting attributes on targets, etc.). These begin + # with upper-case letters. The essential characteristic of methods + # in this section is that they all *should* have corresponding + # same-named global functions. + ####################################################################### def AlwaysBuild(self, *targets): tlist = [] @@ -404,52 +589,6 @@ class Environment: tlist = tlist[0] return tlist - def Precious(self, *targets): - tlist = [] - for t in targets: - tlist.extend(self.arg2nodes(t, self.fs.File)) - - for t in tlist: - t.set_precious() - - if len(tlist) == 1: - tlist = tlist[0] - return tlist - - def Dictionary(self, *args): - if not args: - return self._dict - dlist = map(lambda x, s=self: s._dict[x], args) - if len(dlist) == 1: - dlist = dlist[0] - return dlist - - def __setitem__(self, key, value): - if key in ['TARGET', 'TARGETS', 'SOURCE', 'SOURCES']: - SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning, - "Ignoring attempt to set reserved variable `%s'" % key) - elif key == 'BUILDERS': - try: - bd = self._dict[key] - for k in bd.keys(): - del bd[k] - except KeyError: - self._dict[key] = BuilderDict(kwbd, self) - self._dict[key].update(value) - else: - if not SCons.Util.is_valid_construction_var(key): - raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key - self._dict[key] = value - - def __getitem__(self, key): - return self._dict[key] - - def __delitem__(self, key): - del self._dict[key] - - def has_key(self, key): - return self._dict.has_key(key) - def Command(self, target, source, action): """Builds the supplied target files from the supplied source files using the supplied action. Action may @@ -459,6 +598,28 @@ class Environment: source_factory=SCons.Node.FS.default_fs.Entry) return bld(self, target, source) + def Depends(self, target, dependency): + """Explicity specify that 'target's depend on 'dependency'.""" + tlist = self.arg2nodes(target, self.fs.File) + dlist = self.arg2nodes(dependency, self.fs.File) + for t in tlist: + t.add_dependency(dlist) + + if len(tlist) == 1: + tlist = tlist[0] + return tlist + + def Ignore(self, target, dependency): + """Ignore a dependency.""" + tlist = self.arg2nodes(target, self.fs.File) + dlist = self.arg2nodes(dependency, self.fs.File) + for t in tlist: + t.add_ignore(dlist) + + if len(tlist) == 1: + tlist = tlist[0] + return tlist + def Install(self, dir, source): """Install specified files in the given directory.""" try: @@ -492,14 +653,17 @@ class Environment: ret = ret[0] return ret - def SourceCode(self, entry, builder): - """Arrange for a source code builder for (part of) a tree.""" - entries = self.arg2nodes(entry, self.fs.Entry) - for entry in entries: - entry.set_src_builder(builder) - if len(entries) == 1: - return entries[0] - return entries + def Precious(self, *targets): + tlist = [] + for t in targets: + tlist.extend(self.arg2nodes(t, self.fs.File)) + + for t in tlist: + t.set_precious() + + if len(tlist) == 1: + tlist = tlist[0] + return tlist def SideEffect(self, side_effect, target): """Tell scons that side_effects are built as side @@ -523,143 +687,11 @@ class Environment: else: return side_effects - def subst(self, string, raw=0, target=None, source=None): - """Recursively interpolates construction variables from the - Environment into the specified string, returning the expanded - result. Construction variables are specified by a $ prefix - in the string and begin with an initial underscore or - alphabetic character followed by any number of underscores - or alphanumeric characters. The construction variable names - may be surrounded by curly braces to separate the name from - trailing characters. - """ - if raw: - mode = SCons.Util.SUBST_RAW - else: - mode = SCons.Util.SUBST_CMD - return SCons.Util.scons_subst(string, self, mode, - target, source) - - def subst_list(self, string, raw=0, target=None, source=None): - """Calls through to SCons.Util.scons_subst_list(). See - the documentation for that function.""" - if raw: - mode = SCons.Util.SUBST_RAW - else: - mode = SCons.Util.SUBST_CMD - return SCons.Util.scons_subst_list(string, self, mode, - target, source) - - def get_scanner(self, skey): - """Find the appropriate scanner given a key (usually a file suffix). - Does a linear search. Could be sped up by creating a dictionary if - this proves too slow. - """ - if self._dict['SCANNERS']: - for scanner in self._dict['SCANNERS']: - if skey in scanner.skeys: - return scanner - return None - - def get_builder(self, name): - """Fetch the builder with the specified name from the environment. - """ - try: - return self._dict['BUILDERS'][name] - except KeyError: - return None - - def Detect(self, progs): - """Return the first available program in progs. - """ - if not SCons.Util.is_List(progs): - progs = [ progs ] - for prog in progs: - path = self.WhereIs(prog) - if path: return prog - return None - - def WhereIs(self, prog): - """Find prog in the path. - """ - path = None - pathext = None - if self.has_key('ENV'): - if self['ENV'].has_key('PATH'): - path = self['ENV']['PATH'] - if self['ENV'].has_key('PATHEXT'): - pathext = self['ENV']['PATHEXT'] - path = SCons.Util.WhereIs(prog, path, pathext) - if path: return path - return None - - def Override(self, overrides): - """ - Produce a modified environment whose variables - are overriden by the overrides dictionaries. - - overrides - a dictionary that will override - the variables of this environment. - - This function is much more efficient than Copy() - or creating a new Environment because it doesn't do - a deep copy of the dictionary, and doesn't do a copy - at all if there are no overrides. - """ - - if overrides: - env = copy.copy(self) - env._dict = copy.copy(self._dict) - env._dict.update(overrides) - return env - else: - return self - - def get(self, key, default=None): - "Emulates the get() method of dictionaries.""" - return self._dict.get(key, default) - - def items(self): - "Emulates the items() method of dictionaries.""" - return self._dict.items() - - def FindIxes(self, paths, prefix, suffix): - """ - Search a list of paths for something that matches the prefix and suffix. - - paths - the list of paths or nodes. - prefix - construction variable for the prefix. - suffix - construction variable for the suffix. - """ - - suffix = self.subst('$%s'%suffix) - prefix = self.subst('$%s'%prefix) - - for path in paths: - dir,name = os.path.split(str(path)) - if name[:len(prefix)] == prefix and name[-len(suffix):] == suffix: - return path - - def ReplaceIxes(self, path, old_prefix, old_suffix, new_prefix, new_suffix): - """ - Replace old_prefix with new_prefix and old_suffix with new_suffix. - - env - Environment used to interpolate variables. - path - the path that will be modified. - old_prefix - construction variable for the old prefix. - old_suffix - construction variable for the old suffix. - new_prefix - construction variable for the new prefix. - new_suffix - construction variable for the new suffix. - """ - old_prefix = self.subst('$%s'%old_prefix) - old_suffix = self.subst('$%s'%old_suffix) - - new_prefix = self.subst('$%s'%new_prefix) - new_suffix = self.subst('$%s'%new_suffix) - - dir,name = os.path.split(str(path)) - if name[:len(old_prefix)] == old_prefix: - name = name[len(old_prefix):] - if name[-len(old_suffix):] == old_suffix: - name = name[:-len(old_suffix)] - return os.path.join(dir, new_prefix+name+new_suffix) + def SourceCode(self, entry, builder): + """Arrange for a source code builder for (part of) a tree.""" + entries = self.arg2nodes(entry, self.fs.Entry) + for entry in entries: + entry.set_src_builder(builder) + if len(entries) == 1: + return entries[0] + return entries diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py index 12766ecb..d3807f50 100644 --- a/src/engine/SCons/EnvironmentTests.py +++ b/src/engine/SCons/EnvironmentTests.py @@ -116,18 +116,28 @@ class Scanner: class EnvironmentTestCase(unittest.TestCase): - def test_Override(self): - "Test overriding construction variables" - env = Environment(ONE=1, TWO=2) - assert env['ONE'] == 1 - assert env['TWO'] == 2 - env2 = env.Override({'TWO':'10'}) - assert env2['ONE'] == 1 - assert env2['TWO'] == '10' - assert env['TWO'] == 2 - env2.Replace(ONE = "won") - assert env2['ONE'] == "won" - assert env['ONE'] == 1 + def test___init__(self): + """Test construction Environments creation + + Create two with identical arguments and check that + they compare the same. + """ + env1 = Environment(XXX = 'x', YYY = 'y') + env2 = Environment(XXX = 'x', YYY = 'y') + assert env1 == env2, diff_env(env1, env2) + + def test_get(self): + """Test the get() method.""" + env = Environment(aaa = 'AAA') + + x = env.get('aaa') + assert x == 'AAA', x + x = env.get('aaa', 'XXX') + assert x == 'AAA', x + x = env.get('bbb') + assert x is None, x + x = env.get('bbb', 'XXX') + assert x == 'XXX', x def test_arg2nodes(self): """Test the arg2nodes method @@ -250,6 +260,54 @@ class EnvironmentTestCase(unittest.TestCase): assert not hasattr(nodes[1], 'bbbb'), nodes[0] assert nodes[1].c == 1, nodes[1] + def test_subst(self): + """Test substituting construction variables within strings + + Check various combinations, including recursive expansion + of variables into other variables. + """ + env = Environment(AAA = 'a', BBB = 'b') + mystr = env.subst("$AAA ${AAA}A $BBBB $BBB") + assert mystr == "a aA b", str + + # Changed the tests below to reflect a bug fix in + # subst() + env = Environment(AAA = '$BBB', BBB = 'b', BBBA = 'foo') + mystr = env.subst("$AAA ${AAA}A ${AAA}B $BBB") + assert mystr == "b bA bB b", str + env = Environment(AAA = '$BBB', BBB = '$CCC', CCC = 'c') + mystr = env.subst("$AAA ${AAA}A ${AAA}B $BBB") + assert mystr == "c cA cB c", str + + env = Environment(AAA = '$BBB', BBB = '$CCC', CCC = [ 'a', 'b\nc' ]) + lst = env.subst_list([ "$AAA", "B $CCC" ]) + assert lst == [ [ "a", "b" ], [ "c", "B a", "b" ], [ "c" ] ], lst + + class DummyNode: + def __init__(self, name): + self.name = name + def __str__(self): + return self.name + def rfile(self): + return self + def get_subst_proxy(self): + return self + + # Test callables in the Environment + def foo(target, source, env, for_signature): + assert str(target) == 't', target + assert str(source) == 's', source + return env["FOO"] + + env = Environment(BAR=foo, FOO='baz') + + subst = env.subst('test $BAR', target=DummyNode('t'), source=DummyNode('s')) + assert subst == 'test baz', subst + + lst = env.subst_list('test $BAR', target=DummyNode('t'), source=DummyNode('s')) + assert lst[0][0] == 'test', lst[0][0] + assert lst[0][1] == 'baz', lst[0][1] + def test_Builder_calls(self): """Test Builder calls through different environments """ @@ -278,6 +336,8 @@ class EnvironmentTestCase(unittest.TestCase): assert not called_it.has_key('target') assert not called_it.has_key('source') + + def test_Builder_execs(self): """Test Builder execution through different environments @@ -362,98 +422,6 @@ class EnvironmentTestCase(unittest.TestCase): # s = env3.get_scanner(".cxx") # assert s == None, s - def test_Copy(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 - 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() - env2.Replace(YYY = 'yyy') - assert env1 != env2 - assert env1 == env1copy - - env3 = env1.Copy(XXX = 'x3', ZZZ = 'z3') - assert env3.Dictionary('XXX') == 'x3' - assert env3.Dictionary('YYY') == 'y' - assert env3.Dictionary('ZZZ') == 'z3' - assert env1 == env1copy - - # Ensure that lists and dictionaries are - # deep copied, but not instances. - class TestA: - pass - env1 = Environment(XXX=TestA(), YYY = [ 1, 2, 3 ], - ZZZ = { 1:2, 3:4 }) - env2=env1.Copy() - 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) - - # - env1 = Environment(BUILDERS = {'b1' : 1}) - 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 hasattr(env1, 'b1'), "b1 was mistakenly cleared from env1" - assert env1.b1.env == env1, "b1.env 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" - - # 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]) - - assert env1.get('FOO') is 1 - assert env1.get('BAR') is None - assert env1.get('BAZ') is None - assert env2.get('FOO') is 1 - assert env2.get('BAR') is None - assert env2.get('BAZ') is None - assert env3.get('FOO') is 1 - assert env3.get('BAR') is 2 - assert env3.get('BAZ') is 3 - - 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') - def test_ENV(self): """Test setting the external ENV in Environments """ @@ -463,78 +431,6 @@ class EnvironmentTestCase(unittest.TestCase): env = Environment(ENV = { 'PATH' : '/foo:/bar' }) assert env.Dictionary('ENV')['PATH'] == '/foo:/bar' - def test_Environment(self): - """Test construction Environments creation - - Create two with identical arguments and check that - they compare the same. - """ - env1 = Environment(XXX = 'x', YYY = 'y') - env2 = Environment(XXX = 'x', YYY = 'y') - assert env1 == env2, diff_env(env1, env2) - - def test_Install(self): - """Test Install and InstallAs methods""" - 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 - - 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') - assert tgt.path == 'iii.t' - assert tgt.sources[0].path == 'jjj.s' - assert tgt.builder == InstallBuilder - def test_ReservedVariables(self): """Test generation of warnings when reserved variable names are set in an environment.""" @@ -571,22 +467,222 @@ class EnvironmentTestCase(unittest.TestCase): test_it('foo.bar') test_it('foo-bar') - 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.Replace(BBB = 'bbb', CCC = 'ccc') + 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')) + + env = Environment(LIBS = [ 'foo', 'bar', 'baz' ], + LIBLINKPREFIX = 'foo', + LIBLINKSUFFIX = 'bar', + RDirs=RDirs) + flags = env.subst_list('$_LIBFLAGS', 1)[0] + assert len(flags) == 3, flags + assert flags[0] == 'foofoobar', \ + flags[0] + assert flags[1] == 'foobarbar', \ + 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) + 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/barbar'), \ + 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) + 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/barbar'), \ + 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) + assert len(env.subst_list('$_CPPINCFLAGS')[0]) == 0 + assert len(env.subst_list('$_F77INCFLAGS')[0]) == 0 + assert len(env.subst_list('$_LIBDIRFLAGS')[0]) == 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) + 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] + + def test_platform(self): + """Test specifying a platform callable when instantiating.""" + class platform: + def __str__(self): return "TestPlatform" + def __call__(self, env): env['XYZZY'] = 777 + + def tool(env): + env['SET_TOOL'] = 'initialized' + assert env['PLATFORM'] == "TestPlatform" + + env = Environment(platform = platform(), tools = [tool]) + assert env['XYZZY'] == 777, env + assert env['PLATFORM'] == "TestPlatform" + assert env['SET_TOOL'] == "initialized" + + def test_Default_PLATFORM(self): + """Test overriding the default PLATFORM variable""" + class platform: + def __str__(self): return "DefaultTestPlatform" + def __call__(self, env): env['XYZZY'] = 888 + + def tool(env): + env['SET_TOOL'] = 'abcde' + assert env['PLATFORM'] == "DefaultTestPlatform" + + import SCons.Defaults + save = SCons.Defaults.ConstructionEnvironment.copy() + try: + import SCons.Defaults + SCons.Defaults.ConstructionEnvironment.update({ + 'PLATFORM' : platform(), + }) + env = Environment(tools = [tool]) + assert env['XYZZY'] == 888, env + assert env['PLATFORM'] == "DefaultTestPlatform" + assert env['SET_TOOL'] == "abcde" + finally: + SCons.Defaults.ConstructionEnvironment = save + + def test_tools(self): + """Test specifying a tool callable when instantiating.""" + def t1(env): + env['TOOL1'] = 111 + def t2(env): + env['TOOL2'] = 222 + def t3(env): + env['AAA'] = env['XYZ'] + def t4(env): + env['TOOL4'] = 444 + env = Environment(tools = [t1, t2, t3], XYZ = 'aaa') + assert env['TOOL1'] == 111, env['TOOL1'] + assert env['TOOL2'] == 222, env + assert env['AAA'] == 'aaa', env + t4(env) + assert env['TOOL4'] == 444, env + + def test_Default_TOOLS(self): + """Test overriding the default TOOLS variable""" + def t5(env): + env['TOOL5'] = 555 + def t6(env): + env['TOOL6'] = 666 + def t7(env): + env['BBB'] = env['XYZ'] + def t8(env): + env['TOOL8'] = 888 + + import SCons.Defaults + save = SCons.Defaults.ConstructionEnvironment.copy() + try: + SCons.Defaults.ConstructionEnvironment.update({ + 'TOOLS' : [t5, t6, t7], + }) + env = Environment(XYZ = 'bbb') + assert env['TOOL5'] == 555, env['TOOL5'] + assert env['TOOL6'] == 666, env + assert env['BBB'] == 'bbb', env + t8(env) + assert env['TOOL8'] == 888, env + finally: + SCons.Defaults.ConstructionEnvironment = save + + def test_concat(self): + "Test _concat()" + e1 = Environment(PRE='pre', SUF='suf', STR='a b', LIST=['a', 'b']) + s = e1.subst + assert s("${_concat('', '', '', __env__)}") == '' + assert s("${_concat('', [], '', __env__)}") == '' + assert s("${_concat(PRE, '', SUF, __env__)}") == '' + assert s("${_concat(PRE, STR, SUF, __env__)}") == 'prea bsuf' + assert s("${_concat(PRE, LIST, SUF, __env__)}") == 'preasuf prebsuf' - env2 = Environment(AAA = 'a', BBB = 'bbb', CCC = 'ccc') - assert env1 == env2, diff_env(env1, env2) - env3 = Environment(BUILDERS = {'b1' : 1}) - assert hasattr(env3, 'b1'), "b1 was not set" - env3.Replace(BUILDERS = {'b2' : 2}) - assert not hasattr(env3, 'b1'), "b1 was not cleared" - assert hasattr(env3, 'b2'), "b2 was not set" def test_Append(self): """Test appending to construction variables in an Environment @@ -624,75 +720,8 @@ class EnvironmentTestCase(unittest.TestCase): assert hasattr(env4, 'z1') assert hasattr(env4, 'z2') - def test_Prepend(self): - """Test prepending to construction variables in an Environment - """ - import UserList - UL = UserList.UserList - env1 = Environment(AAA = 'a', BBB = 'b', CCC = 'c', DDD = 'd', - EEE = ['e'], FFF = ['f'], GGG = ['g'], HHH = ['h'], - III = UL(['i']), JJJ = UL(['j']), - KKK = UL(['k']), LLL = UL(['l'])) - env1.Prepend(BBB = 'B', CCC = ['C'], DDD = UL(['D']), - FFF = 'F', GGG = ['G'], HHH = UL(['H']), - JJJ = 'J', KKK = ['K'], LLL = UL(['L'])) - env2 = Environment(AAA = 'a', BBB = 'Bb', - CCC = ['C', 'c'], DDD = UL(['D', 'd']), - EEE = ['e'], FFF = ['F', 'f'], - GGG = ['G', 'g'], HHH = UL(['H', 'h']), - III = UL(['i']), JJJ = UL(['J', 'j']), - KKK = UL(['K', 'k']), LLL = UL(['L', 'l'])) - assert env1 == env2, diff_env(env1, env2) - - env3 = Environment(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'] - 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'}, - 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') - - def test_AppendENVPath(self): - """Test appending 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.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 = ';') - 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') - - def test_AppendENVPath(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') - - def test_AppendENVPath(self): - """Test appending to an ENV path.""" + def test_AppendENVPath(self): + """Test appending 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. @@ -703,324 +732,73 @@ class EnvironmentTestCase(unittest.TestCase): 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') - def test_Depends(self): - """Test the explicit Depends method.""" - env = Environment(FOO = 'xxx', BAR='yyy') - t = env.Depends(target='EnvironmentTest.py', dependency='Environment.py') - assert t.__class__.__name__ == 'File' - assert t.path == 'EnvironmentTest.py' - assert len(t.depends) == 1 - d = t.depends[0] - assert d.__class__.__name__ == 'File' - assert d.path == 'Environment.py' - - t = env.Depends(target='${FOO}.py', dependency='${BAR}.py') - assert t.__class__.__name__ == 'File' - assert t.path == 'xxx.py' - assert len(t.depends) == 1 - d = t.depends[0] - assert d.__class__.__name__ == 'File' - assert d.path == 'yyy.py' - - def test_Ignore(self): - """Test the explicit Ignore method.""" - env = Environment(FOO='yyy', BAR='zzz') - t = env.Ignore(target='targ.py', dependency='dep.py') - assert t.__class__.__name__ == 'File' - assert t.path == 'targ.py' - assert len(t.ignore) == 1 - i = t.ignore[0] - assert i.__class__.__name__ == 'File' - assert i.path == 'dep.py' - t = env.Ignore(target='$FOO$BAR', dependency='$BAR$FOO') - assert t.__class__.__name__ == 'File' - assert t.path == 'yyyzzz' - assert len(t.ignore) == 1 - i = t.ignore[0] - assert i.__class__.__name__ == 'File' - assert i.path == 'zzzyyy' - - 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' - assert t[0].path == 'a' - assert t[0].always_build - assert t[1].__class__.__name__ == 'File' - assert t[1].path == 'bfff' - assert t[1].always_build - assert t[2].__class__.__name__ == 'File' - assert t[2].path == 'c' - assert t[2].always_build - assert t[3].__class__.__name__ == 'File' - assert t[3].path == 'd' - assert t[3].always_build - assert t[4].__class__.__name__ == 'File' - assert t[4].path == 'bbb' - assert t[4].always_build - - def test_Precious(self): - """Test the Precious() method.""" - env = Environment(FOO='ggg', BAR='hhh') - t = env.Precious('a', '${BAR}b', ['c', 'd'], '$FOO') - assert t[0].__class__.__name__ == 'File' - assert t[0].path == 'a' - assert t[0].precious - assert t[1].__class__.__name__ == 'File' - assert t[1].path == 'hhhb' - assert t[1].precious - assert t[2].__class__.__name__ == 'File' - assert t[2].path == 'c' - assert t[2].precious - assert t[3].__class__.__name__ == 'File' - assert t[3].path == 'd' - assert t[3].precious - assert t[4].__class__.__name__ == 'File' - assert t[4].path == 'ggg' - assert t[4].precious - - def test_Command(self): - """Test the Command() method.""" - env = Environment() - t = env.Command(target='foo.out', source=['foo1.in', 'foo2.in'], - action='buildfoo $target $source') - assert not t.builder is 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) - - sub = SCons.Node.FS.default_fs.Dir('sub') - t = env.Command(target='bar.out', source='sub', - action='buildbar $target $source') - assert 'sub' in map(lambda x: x.path, 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) - return 0 - t = env.Command(target='foo.out', source=['foo1.in','foo2.in'], - action=testFunc) - assert not t.builder is 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) - - def test_SourceCode(self): - """Test the SourceCode() method.""" - env = Environment(FOO='mmm', BAR='nnn') - e = env.SourceCode('foo', None) - assert e.path == 'foo' - s = e.src_builder() - assert s is None, s - - b = Builder() - e = env.SourceCode(e, b) - assert e.path == 'foo' - s = e.src_builder() - assert s is b, s - - e = env.SourceCode('$BAR$FOO', None) - assert e.path == 'nnnmmm' - s = e.src_builder() - assert s is None, s - - def test_SideEffect(self): - """Test the SideEffect() method""" - env = Environment(LIB='lll', FOO='fff', BAR='bbb') - - foo = env.Object('foo.obj', 'foo.cpp') - bar = env.Object('bar.obj', 'bar.cpp') - s = env.SideEffect('mylib.pdb', ['foo.obj', 'bar.obj']) - assert s.path == 'mylib.pdb' - 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') - bbb = env.Object('bbb.obj', 'bbb.cpp') - s = env.SideEffect('my${LIB}.pdb', ['${FOO}.obj', '${BAR}.obj']) - assert s.path == 'mylll.pdb' - 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]) + def test_Copy(self): + """Test construction Environment copying - def test_subst(self): - """Test substituting construction variables within strings - - Check various combinations, including recursive expansion - of variables into other variables. + 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 + updates and check that the original remains intact + and the copy has the updated values. """ - env = Environment(AAA = 'a', BBB = 'b') - mystr = env.subst("$AAA ${AAA}A $BBBB $BBB") - assert mystr == "a aA b", str - - # Changed the tests below to reflect a bug fix in - # subst() - env = Environment(AAA = '$BBB', BBB = 'b', BBBA = 'foo') - mystr = env.subst("$AAA ${AAA}A ${AAA}B $BBB") - assert mystr == "b bA bB b", str - env = Environment(AAA = '$BBB', BBB = '$CCC', CCC = 'c') - mystr = env.subst("$AAA ${AAA}A ${AAA}B $BBB") - assert mystr == "c cA cB c", str - - env = Environment(AAA = '$BBB', BBB = '$CCC', CCC = [ 'a', 'b\nc' ]) - lst = env.subst_list([ "$AAA", "B $CCC" ]) - assert lst == [ [ "a", "b" ], [ "c", "B a", "b" ], [ "c" ] ], lst - - class DummyNode: - def __init__(self, name): - self.name = name - def __str__(self): - return self.name - def rfile(self): - return self - def get_subst_proxy(self): - return self - - # Test callables in the Environment - def foo(target, source, env, for_signature): - assert str(target) == 't', target - assert str(source) == 's', source - return env["FOO"] - - env = Environment(BAR=foo, FOO='baz') - - subst = env.subst('test $BAR', target=DummyNode('t'), source=DummyNode('s')) - assert subst == 'test baz', subst - - lst = env.subst_list('test $BAR', target=DummyNode('t'), source=DummyNode('s')) - assert lst[0][0] == 'test', lst[0][0] - assert lst[0][1] == 'baz', lst[0][1] - - 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')) - - env = Environment(LIBS = [ 'foo', 'bar', 'baz' ], - LIBLINKPREFIX = 'foo', - LIBLINKSUFFIX = 'bar', - RDirs=RDirs) - flags = env.subst_list('$_LIBFLAGS', 1)[0] - assert len(flags) == 3, flags - assert flags[0] == 'foofoobar', \ - flags[0] - assert flags[1] == 'foobarbar', \ - flags[1] - assert flags[2] == 'foobazbar', \ - flags[2] - - blat = SCons.Node.FS.default_fs.Dir('blat') + env1 = Environment(XXX = 'x', YYY = 'y') + env2 = env1.Copy() + env1copy = env1.Copy() + env2.Replace(YYY = 'yyy') + assert env1 != env2 + assert env1 == env1copy - env = Environment(CPPPATH = [ 'foo', '$FOO/bar', blat ], - INCPREFIX = 'foo ', - INCSUFFIX = 'bar', - FOO = 'baz', - RDirs=RDirs) - 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/barbar'), \ - 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] + env3 = env1.Copy(XXX = 'x3', ZZZ = 'z3') + assert env3.Dictionary('XXX') == 'x3' + assert env3.Dictionary('YYY') == 'y' + assert env3.Dictionary('ZZZ') == 'z3' + assert env1 == env1copy - env = Environment(F77PATH = [ 'foo', '$FOO/bar', blat ], - INCPREFIX = 'foo ', - INCSUFFIX = 'bar', - FOO = 'baz', - RDirs=RDirs) - 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/barbar'), \ - 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] + # Ensure that lists and dictionaries are + # deep copied, but not instances. + class TestA: + pass + env1 = Environment(XXX=TestA(), YYY = [ 1, 2, 3 ], + ZZZ = { 1:2, 3:4 }) + env2=env1.Copy() + 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) - env = Environment(CPPPATH = '', F77PATH = '', LIBPATH = '', - RDirs=RDirs) - assert len(env.subst_list('$_CPPINCFLAGS')[0]) == 0 - assert len(env.subst_list('$_F77INCFLAGS')[0]) == 0 - assert len(env.subst_list('$_LIBDIRFLAGS')[0]) == 0 + # + env1 = Environment(BUILDERS = {'b1' : 1}) + 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 hasattr(env1, 'b1'), "b1 was mistakenly cleared from env1" + assert env1.b1.env == env1, "b1.env 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" - 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) - 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] + # 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]) + + assert env1.get('FOO') is 1 + assert env1.get('BAR') is None + assert env1.get('BAZ') is None + assert env2.get('FOO') is 1 + assert env2.get('BAR') is None + assert env2.get('BAZ') is None + assert env3.get('FOO') is 1 + assert env3.get('BAR') is 2 + assert env3.get('BAZ') is 3 def test_Detect(self): """Test Detect()ing tools""" @@ -1077,132 +855,124 @@ class EnvironmentTestCase(unittest.TestCase): x = env.Detect('xxx.exe') assert x is None, x - def test_platform(self): - """Test specifying a platform callable when instantiating.""" - class platform: - def __str__(self): return "TestPlatform" - def __call__(self, env): env['XYZZY'] = 777 + def test_Dictionary(self): + """Test retrieval of known construction variables - def tool(env): - env['SET_TOOL'] = 'initialized' - assert env['PLATFORM'] == "TestPlatform" + 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') - env = Environment(platform = platform(), tools = [tool]) - assert env['XYZZY'] == 777, env - assert env['PLATFORM'] == "TestPlatform" - assert env['SET_TOOL'] == "initialized" + assert env['XXX'] == 'x' + env['XXX'] = 'foo' + assert env.Dictionary('XXX') == 'foo' + del env['XXX'] + assert not env.Dictionary().has_key('XXX') - def test_Default_PLATFORM(self): - """Test overriding the default PLATFORM variable""" - class platform: - def __str__(self): return "DefaultTestPlatform" - def __call__(self, env): env['XYZZY'] = 888 + def test_FindIxes(self): + "Test FindIxes()" + env = Environment(LIBPREFIX='lib', + LIBSUFFIX='.a', + SHLIBPREFIX='lib', + SHLIBSUFFIX='.so', + PREFIX='pre', + SUFFIX='post') - def tool(env): - env['SET_TOOL'] = 'abcde' - assert env['PLATFORM'] == "DefaultTestPlatform" + paths = [os.path.join('dir', 'libfoo.a'), + os.path.join('dir', 'libfoo.so')] - import SCons.Defaults - save = SCons.Defaults.ConstructionEnvironment.copy() - try: - import SCons.Defaults - SCons.Defaults.ConstructionEnvironment.update({ - 'PLATFORM' : platform(), - }) - env = Environment(tools = [tool]) - assert env['XYZZY'] == 888, env - assert env['PLATFORM'] == "DefaultTestPlatform" - assert env['SET_TOOL'] == "abcde" - finally: - SCons.Defaults.ConstructionEnvironment = save + assert paths[0] == env.FindIxes(paths, 'LIBPREFIX', 'LIBSUFFIX') + assert paths[1] == env.FindIxes(paths, 'SHLIBPREFIX', 'SHLIBSUFFIX') + assert None == env.FindIxes(paths, 'PREFIX', 'POST') - def test_tools(self): - """Test specifying a tool callable when instantiating.""" - def t1(env): - env['TOOL1'] = 111 - def t2(env): - env['TOOL2'] = 222 - def t3(env): - env['AAA'] = env['XYZ'] - def t4(env): - env['TOOL4'] = 444 - env = Environment(tools = [t1, t2, t3], XYZ = 'aaa') - assert env['TOOL1'] == 111, env['TOOL1'] - assert env['TOOL2'] == 222, env - assert env['AAA'] == 'aaa', env - t4(env) - assert env['TOOL4'] == 444, env - - def test_Default_TOOLS(self): - """Test overriding the default TOOLS variable""" - def t5(env): - env['TOOL5'] = 555 - def t6(env): - env['TOOL6'] = 666 - def t7(env): - env['BBB'] = env['XYZ'] - def t8(env): - env['TOOL8'] = 888 + paths = ['libfoo.a', 'prefoopost'] - import SCons.Defaults - save = SCons.Defaults.ConstructionEnvironment.copy() - try: - SCons.Defaults.ConstructionEnvironment.update({ - 'TOOLS' : [t5, t6, t7], - }) - env = Environment(XYZ = 'bbb') - assert env['TOOL5'] == 555, env['TOOL5'] - assert env['TOOL6'] == 666, env - assert env['BBB'] == 'bbb', env - t8(env) - assert env['TOOL8'] == 888, env - finally: - SCons.Defaults.ConstructionEnvironment = save + assert paths[0] == env.FindIxes(paths, 'LIBPREFIX', 'LIBSUFFIX') + assert None == env.FindIxes(paths, 'SHLIBPREFIX', 'SHLIBSUFFIX') + assert paths[1] == env.FindIxes(paths, 'PREFIX', 'SUFFIX') - def test_get(self): - """Test the get() method.""" - env = Environment(aaa = 'AAA') + def test_Override(self): + "Test overriding construction variables" + env = Environment(ONE=1, TWO=2) + assert env['ONE'] == 1 + assert env['TWO'] == 2 + env2 = env.Override({'TWO':'10'}) + assert env2['ONE'] == 1 + assert env2['TWO'] == '10' + assert env['TWO'] == 2 + env2.Replace(ONE = "won") + assert env2['ONE'] == "won" + assert env['ONE'] == 1 - x = env.get('aaa') - assert x == 'AAA', x - x = env.get('aaa', 'XXX') - assert x == 'AAA', x - x = env.get('bbb') - assert x is None, x - x = env.get('bbb', 'XXX') - assert x == 'XXX', x + def test_Prepend(self): + """Test prepending to construction variables in an Environment + """ + import UserList + UL = UserList.UserList + env1 = Environment(AAA = 'a', BBB = 'b', CCC = 'c', DDD = 'd', + EEE = ['e'], FFF = ['f'], GGG = ['g'], HHH = ['h'], + III = UL(['i']), JJJ = UL(['j']), + KKK = UL(['k']), LLL = UL(['l'])) + env1.Prepend(BBB = 'B', CCC = ['C'], DDD = UL(['D']), + FFF = 'F', GGG = ['G'], HHH = UL(['H']), + JJJ = 'J', KKK = ['K'], LLL = UL(['L'])) + env2 = Environment(AAA = 'a', BBB = 'Bb', + CCC = ['C', 'c'], DDD = UL(['D', 'd']), + EEE = ['e'], FFF = ['F', 'f'], + GGG = ['G', 'g'], HHH = UL(['H', 'h']), + III = UL(['i']), JJJ = UL(['J', 'j']), + KKK = UL(['K', 'k']), LLL = UL(['L', 'l'])) + assert env1 == env2, diff_env(env1, env2) - def test_concat(self): - "Test _concat()" - e1 = Environment(PRE='pre', SUF='suf', STR='a b', LIST=['a', 'b']) - s = e1.subst - assert s("${_concat('', '', '', __env__)}") == '' - assert s("${_concat('', [], '', __env__)}") == '' - assert s("${_concat(PRE, '', SUF, __env__)}") == '' - assert s("${_concat(PRE, STR, SUF, __env__)}") == 'prea bsuf' - assert s("${_concat(PRE, LIST, SUF, __env__)}") == 'preasuf prebsuf' + env3 = Environment(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'] + assert hasattr(env4, 'z1') + assert hasattr(env4, 'z2') - def test_FindIxes(self): - "Test FindIxes()" - env = Environment(LIBPREFIX='lib', - LIBSUFFIX='.a', - SHLIBPREFIX='lib', - SHLIBSUFFIX='.so', - PREFIX='pre', - SUFFIX='post') + 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') - paths = [os.path.join('dir', 'libfoo.a'), - os.path.join('dir', 'libfoo.so')] + def test_Replace(self): + """Test replacing construction variables in an Environment - assert paths[0] == env.FindIxes(paths, 'LIBPREFIX', 'LIBSUFFIX') - assert paths[1] == env.FindIxes(paths, 'SHLIBPREFIX', 'SHLIBSUFFIX') - assert None == env.FindIxes(paths, 'PREFIX', 'POST') + After creation of the Environment, of course. + """ + env1 = Environment(AAA = 'a', BBB = 'b') + env1.Replace(BBB = 'bbb', CCC = 'ccc') - paths = ['libfoo.a', 'prefoopost'] + env2 = Environment(AAA = 'a', BBB = 'bbb', CCC = 'ccc') + assert env1 == env2, diff_env(env1, env2) - assert paths[0] == env.FindIxes(paths, 'LIBPREFIX', 'LIBSUFFIX') - assert None == env.FindIxes(paths, 'SHLIBPREFIX', 'SHLIBSUFFIX') - assert paths[1] == env.FindIxes(paths, 'PREFIX', 'SUFFIX') + env3 = Environment(BUILDERS = {'b1' : 1}) + assert hasattr(env3, 'b1'), "b1 was not set" + env3.Replace(BUILDERS = {'b2' : 2}) + assert not hasattr(env3, 'b1'), "b1 was not cleared" + assert hasattr(env3, 'b2'), "b2 was not set" def test_ReplaceIxes(self): "Test ReplaceIxes()" @@ -1225,6 +995,218 @@ class EnvironmentTestCase(unittest.TestCase): 'PREFIX', 'SUFFIX', 'LIBPREFIX', 'LIBSUFFIX') + + + 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' + assert t[0].path == 'a' + assert t[0].always_build + assert t[1].__class__.__name__ == 'File' + assert t[1].path == 'bfff' + assert t[1].always_build + assert t[2].__class__.__name__ == 'File' + assert t[2].path == 'c' + assert t[2].always_build + assert t[3].__class__.__name__ == 'File' + assert t[3].path == 'd' + assert t[3].always_build + assert t[4].__class__.__name__ == 'File' + assert t[4].path == 'bbb' + assert t[4].always_build + + def test_Command(self): + """Test the Command() method.""" + env = Environment() + t = env.Command(target='foo.out', source=['foo1.in', 'foo2.in'], + action='buildfoo $target $source') + assert not t.builder is 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) + + sub = SCons.Node.FS.default_fs.Dir('sub') + t = env.Command(target='bar.out', source='sub', + action='buildbar $target $source') + assert 'sub' in map(lambda x: x.path, 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) + return 0 + t = env.Command(target='foo.out', source=['foo1.in','foo2.in'], + action=testFunc) + assert not t.builder is 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) + + def test_Depends(self): + """Test the explicit Depends method.""" + env = Environment(FOO = 'xxx', BAR='yyy') + t = env.Depends(target='EnvironmentTest.py', dependency='Environment.py') + assert t.__class__.__name__ == 'File' + assert t.path == 'EnvironmentTest.py' + assert len(t.depends) == 1 + d = t.depends[0] + assert d.__class__.__name__ == 'File' + assert d.path == 'Environment.py' + + t = env.Depends(target='${FOO}.py', dependency='${BAR}.py') + assert t.__class__.__name__ == 'File' + assert t.path == 'xxx.py' + assert len(t.depends) == 1 + d = t.depends[0] + assert d.__class__.__name__ == 'File' + assert d.path == 'yyy.py' + + def test_Ignore(self): + """Test the explicit Ignore method.""" + env = Environment(FOO='yyy', BAR='zzz') + t = env.Ignore(target='targ.py', dependency='dep.py') + assert t.__class__.__name__ == 'File' + assert t.path == 'targ.py' + assert len(t.ignore) == 1 + i = t.ignore[0] + assert i.__class__.__name__ == 'File' + assert i.path == 'dep.py' + t = env.Ignore(target='$FOO$BAR', dependency='$BAR$FOO') + assert t.__class__.__name__ == 'File' + assert t.path == 'yyyzzz' + assert len(t.ignore) == 1 + i = t.ignore[0] + assert i.__class__.__name__ == 'File' + assert i.path == 'zzzyyy' + + def test_Install(self): + """Test Install and InstallAs methods""" + 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 + + 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') + assert tgt.path == 'iii.t' + assert tgt.sources[0].path == 'jjj.s' + assert tgt.builder == InstallBuilder + + def test_Precious(self): + """Test the Precious() method.""" + env = Environment(FOO='ggg', BAR='hhh') + t = env.Precious('a', '${BAR}b', ['c', 'd'], '$FOO') + assert t[0].__class__.__name__ == 'File' + assert t[0].path == 'a' + assert t[0].precious + assert t[1].__class__.__name__ == 'File' + assert t[1].path == 'hhhb' + assert t[1].precious + assert t[2].__class__.__name__ == 'File' + assert t[2].path == 'c' + assert t[2].precious + assert t[3].__class__.__name__ == 'File' + assert t[3].path == 'd' + assert t[3].precious + assert t[4].__class__.__name__ == 'File' + assert t[4].path == 'ggg' + assert t[4].precious + + def test_SideEffect(self): + """Test the SideEffect() method""" + env = Environment(LIB='lll', FOO='fff', BAR='bbb') + + foo = env.Object('foo.obj', 'foo.cpp') + bar = env.Object('bar.obj', 'bar.cpp') + s = env.SideEffect('mylib.pdb', ['foo.obj', 'bar.obj']) + assert s.path == 'mylib.pdb' + 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') + bbb = env.Object('bbb.obj', 'bbb.cpp') + s = env.SideEffect('my${LIB}.pdb', ['${FOO}.obj', '${BAR}.obj']) + assert s.path == 'mylll.pdb' + 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]) + + def test_SourceCode(self): + """Test the SourceCode() method.""" + env = Environment(FOO='mmm', BAR='nnn') + e = env.SourceCode('foo', None) + assert e.path == 'foo' + s = e.src_builder() + assert s is None, s + + b = Builder() + e = env.SourceCode(e, b) + assert e.path == 'foo' + s = e.src_builder() + assert s is b, s + + e = env.SourceCode('$BAR$FOO', None) + assert e.path == 'nnnmmm' + s = e.src_builder() + assert s is None, s + if __name__ == "__main__": suite = unittest.makeSuite(EnvironmentTestCase, 'test_')