diff options
author | Steven Knight <knight@baldmt.com> | 2003-09-07 04:14:49 (GMT) |
---|---|---|
committer | Steven Knight <knight@baldmt.com> | 2003-09-07 04:14:49 (GMT) |
commit | 61d018dfceac6cb9717caeeea7125d7a55b4b0eb (patch) | |
tree | a5d6529470d3797256f03ba197dedc1cac1feded /src/engine | |
parent | bf221d4e593f803116af76ec3bc16514b666c9f1 (diff) | |
download | SCons-61d018dfceac6cb9717caeeea7125d7a55b4b0eb.zip SCons-61d018dfceac6cb9717caeeea7125d7a55b4b0eb.tar.gz SCons-61d018dfceac6cb9717caeeea7125d7a55b4b0eb.tar.bz2 |
Rearrange the Environment methods and tests.
Diffstat (limited to 'src/engine')
-rw-r--r-- | src/engine/SCons/Environment.py | 552 | ||||
-rw-r--r-- | src/engine/SCons/EnvironmentTests.py | 1126 |
2 files changed, 846 insertions, 832 deletions
diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py index f72bc95..e7407ee 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] = {} - - self._dict[envname][name] = nv + 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) - 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) + new_prefix = self.subst('$%s'%new_prefix) + new_suffix = self.subst('$%s'%new_suffix) - if len(tlist) == 1: - tlist = tlist[0] - return tlist + 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 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 12766ec..d3807f5 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,334 +467,6 @@ 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') - - 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 - """ - - b1 = Environment()['BUILDERS'] - b2 = Environment()['BUILDERS'] - assert b1 == b2, diff_dict(b1, b2) - - 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.Append(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.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'] - 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.""" - 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_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_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_autogenerate(dict): """Test autogenerating variables in a dictionary.""" @@ -1022,61 +590,6 @@ class EnvironmentTestCase(unittest.TestCase): assert flags[17] == '$)', \ flags[17] - def test_Detect(self): - """Test Detect()ing tools""" - test = TestCmd.TestCmd(workdir = '') - test.subdir('sub1', 'sub2') - sub1 = test.workpath('sub1') - sub2 = test.workpath('sub2') - - if sys.platform == 'win32': - test.write(['sub1', 'xxx'], "sub1/xxx\n") - test.write(['sub2', 'xxx'], "sub2/xxx\n") - - env = Environment(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] }) - - x = env.Detect('xxx.exe') - assert x == 'xxx.exe', x - - test.write(['sub1', 'xxx.exe'], "sub1/xxx.exe\n") - - x = env.Detect('xxx.exe') - assert x == 'xxx.exe', x - - else: - test.write(['sub1', 'xxx.exe'], "sub1/xxx.exe\n") - test.write(['sub2', 'xxx.exe'], "sub2/xxx.exe\n") - - env = Environment(ENV = { 'PATH' : [sub1, sub2] }) - - x = env.Detect('xxx.exe') - assert x is None, x - - sub2_xxx_exe = test.workpath('sub2', 'xxx.exe') - os.chmod(sub2_xxx_exe, 0755) - - env = Environment(ENV = { 'PATH' : [sub1, sub2] }) - - x = env.Detect('xxx.exe') - assert x == 'xxx.exe', x - - sub1_xxx_exe = test.workpath('sub1', 'xxx.exe') - os.chmod(sub1_xxx_exe, 0755) - - x = env.Detect('xxx.exe') - assert x == 'xxx.exe', x - - env = Environment(ENV = { 'PATH' : [] }) - x = env.Detect('xxx.exe') - assert x is None, x - def test_platform(self): """Test specifying a platform callable when instantiating.""" class platform: @@ -1159,19 +672,6 @@ class EnvironmentTestCase(unittest.TestCase): finally: SCons.Defaults.ConstructionEnvironment = save - 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_concat(self): "Test _concat()" e1 = Environment(PRE='pre', SUF='suf', STR='a b', LIST=['a', 'b']) @@ -1182,6 +682,203 @@ class EnvironmentTestCase(unittest.TestCase): assert s("${_concat(PRE, STR, SUF, __env__)}") == 'prea bsuf' assert s("${_concat(PRE, LIST, SUF, __env__)}") == 'preasuf prebsuf' + + + def test_Append(self): + """Test appending to construction variables in an Environment + """ + + b1 = Environment()['BUILDERS'] + b2 = Environment()['BUILDERS'] + assert b1 == b2, diff_dict(b1, b2) + + 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.Append(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.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'] + 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'}, + 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_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_Detect(self): + """Test Detect()ing tools""" + test = TestCmd.TestCmd(workdir = '') + test.subdir('sub1', 'sub2') + sub1 = test.workpath('sub1') + sub2 = test.workpath('sub2') + + if sys.platform == 'win32': + test.write(['sub1', 'xxx'], "sub1/xxx\n") + test.write(['sub2', 'xxx'], "sub2/xxx\n") + + env = Environment(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] }) + + x = env.Detect('xxx.exe') + assert x == 'xxx.exe', x + + test.write(['sub1', 'xxx.exe'], "sub1/xxx.exe\n") + + x = env.Detect('xxx.exe') + assert x == 'xxx.exe', x + + else: + test.write(['sub1', 'xxx.exe'], "sub1/xxx.exe\n") + test.write(['sub2', 'xxx.exe'], "sub2/xxx.exe\n") + + env = Environment(ENV = { 'PATH' : [sub1, sub2] }) + + x = env.Detect('xxx.exe') + assert x is None, x + + sub2_xxx_exe = test.workpath('sub2', 'xxx.exe') + os.chmod(sub2_xxx_exe, 0755) + + env = Environment(ENV = { 'PATH' : [sub1, sub2] }) + + x = env.Detect('xxx.exe') + assert x == 'xxx.exe', x + + sub1_xxx_exe = test.workpath('sub1', 'xxx.exe') + os.chmod(sub1_xxx_exe, 0755) + + x = env.Detect('xxx.exe') + assert x == 'xxx.exe', x + + env = Environment(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') + def test_FindIxes(self): "Test FindIxes()" env = Environment(LIBPREFIX='lib', @@ -1204,6 +901,79 @@ class EnvironmentTestCase(unittest.TestCase): assert None == env.FindIxes(paths, 'SHLIBPREFIX', 'SHLIBSUFFIX') assert paths[1] == env.FindIxes(paths, 'PREFIX', 'SUFFIX') + 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_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_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') + + 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_ReplaceIxes(self): "Test ReplaceIxes()" env = Environment(LIBPREFIX='lib', @@ -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_') |