Merged revisions 2725-2865 via svnmerge from
[scons.git] / src / engine / SCons / ActionTests.py
index 4c1649c748d56eedb9ef204327bac9e83c6d92dd..f25f2321961584a204881ab440a78be3077d7111 100644 (file)
@@ -58,7 +58,8 @@ import TestCmd
 # for each test, they can just use the one.
 test = TestCmd.TestCmd(workdir = '')
 
-test.write('act.py', """import os, string, sys
+test.write('act.py', """\
+import os, string, sys
 f = open(sys.argv[1], 'w')
 f.write("act.py: '" + string.join(sys.argv[2:], "' '") + "'\\n")
 try:
@@ -81,7 +82,13 @@ if os.environ.has_key( 'ACTPY_PIPE' ):
 sys.exit(0)
 """)
 
+test.write('exit.py', """\
+import sys
+sys.exit(int(sys.argv[1]))
+""")
+
 act_py = test.workpath('act.py')
+exit_py = test.workpath('exit.py')
 
 outfile = test.workpath('outfile')
 outfile2 = test.workpath('outfile2')
@@ -128,26 +135,28 @@ class Environment:
         for k, v in kw.items():
             self.d[k] = v
     # Just use the underlying scons_subst*() utility methods.
-    def subst(self, strSubst, raw=0, target=[], source=[], dict=None):
-        return SCons.Util.scons_subst(strSubst, self, raw, target, source, dict)
+    def subst(self, strSubst, raw=0, target=[], source=[], conv=None):
+        return SCons.Subst.scons_subst(strSubst, self, raw,
+                                       target, source, self.d, conv=conv)
     subst_target_source = subst
-    def subst_list(self, strSubst, raw=0, target=[], source=[], dict=None):
-        return SCons.Util.scons_subst_list(strSubst, self, raw, target, source, dict)
+    def subst_list(self, strSubst, raw=0, target=[], source=[], conv=None):
+        return SCons.Subst.scons_subst_list(strSubst, self, raw,
+                                       target, source, self.d, conv=conv)
     def __getitem__(self, item):
         return self.d[item]
     def __setitem__(self, item, value):
         self.d[item] = value
     def has_key(self, item):
         return self.d.has_key(item)
-    def get(self, key, value):
+    def get(self, key, value=None):
         return self.d.get(key, value)
     def items(self):
         return self.d.items()
     def Dictionary(self):
         return self.d
-    def Copy(self, **kw):
+    def Clone(self, **kw):
         res = Environment()
-        res.d = SCons.Environment.our_deepcopy(self.d)
+        res.d = SCons.Util.semi_deepcopy(self.d)
         for k, v in kw.items():
             res.d[k] = v
         return res
@@ -175,6 +184,8 @@ if os.name == 'java':
 else:
     python = sys.executable
 
+_python_ = '"' + python + '"'
+
 class ActionTestCase(unittest.TestCase):
     """Test the Action() factory function"""
 
@@ -260,17 +271,19 @@ class ActionTestCase(unittest.TestCase):
         assert isinstance(a4, SCons.Action.ListAction), a4
         assert isinstance(a4.list[0], SCons.Action.CommandAction), a4.list[0]
         assert a4.list[0].cmd_list == "x", a4.list[0].cmd_list
+        assert a4.list[0].strfunction == foo, a4.list[0].strfunction
         assert isinstance(a4.list[1], SCons.Action.CommandAction), a4.list[1]
         assert a4.list[1].cmd_list == "y", a4.list[1].cmd_list
-        assert a4.strfunction == foo, a4.strfunction
+        assert a4.list[1].strfunction == foo, a4.list[1].strfunction
 
         a5 = SCons.Action.Action("x\ny", strfunction=foo)
         assert isinstance(a5, SCons.Action.ListAction), a5
         assert isinstance(a5.list[0], SCons.Action.CommandAction), a5.list[0]
         assert a5.list[0].cmd_list == "x", a5.list[0].cmd_list
+        assert a5.list[0].strfunction == foo, a5.list[0].strfunction
         assert isinstance(a5.list[1], SCons.Action.CommandAction), a5.list[1]
         assert a5.list[1].cmd_list == "y", a5.list[1].cmd_list
-        assert a5.strfunction == foo, a5.strfunction
+        assert a5.list[1].strfunction == foo, a5.list[1].strfunction
 
     def test_CommandGeneratorAction(self):
         """Test the Action() factory's creation of CommandGeneratorAction objects
@@ -279,16 +292,13 @@ class ActionTestCase(unittest.TestCase):
             pass
         def bar():
             pass
-        cg = SCons.Action.CommandGenerator(foo)
-
-        a1 = SCons.Action.Action(cg)
+        a1 = SCons.Action.Action(foo, generator=1)
         assert isinstance(a1, SCons.Action.CommandGeneratorAction), a1
         assert a1.generator is foo, a1.generator
 
-        a2 = SCons.Action.Action(cg, strfunction=bar)
+        a2 = SCons.Action.Action(foo, strfunction=bar, generator=1)
         assert isinstance(a2, SCons.Action.CommandGeneratorAction), a2
         assert a2.generator is foo, a2.generator
-        assert a2.strfunction is bar, a2.strfunction
 
     def test_LazyCmdGeneratorAction(self):
         """Test the Action() factory's creation of lazy CommandGeneratorAction objects
@@ -297,13 +307,10 @@ class ActionTestCase(unittest.TestCase):
             pass
 
         a1 = SCons.Action.Action("$FOO")
-        assert isinstance(a1, SCons.Action.CommandGeneratorAction), a1
-        assert isinstance(a1.generator, SCons.Action.LazyCmdGenerator), a1.generator
+        assert isinstance(a1, SCons.Action.LazyAction), a1
 
         a2 = SCons.Action.Action("$FOO", strfunction=foo)
-        assert isinstance(a2, SCons.Action.CommandGeneratorAction), a2
-        assert isinstance(a2.generator, SCons.Action.LazyCmdGenerator), a2.generator
-        assert a2.strfunction is foo, a2.strfunction
+        assert isinstance(a2, SCons.Action.LazyAction), a2
 
     def test_no_action(self):
         """Test when the Action() factory can't create an action object
@@ -319,26 +326,44 @@ class ActionTestCase(unittest.TestCase):
         assert a2 is a1, a2
 
 class ActionBaseTestCase(unittest.TestCase):
+    def test_get_executor(self):
+        """Test the ActionBase.get_executor() method"""
+        a = SCons.Action.Action('foo')
+        x = a.get_executor({}, {}, [], [], {})
+        assert not x is None, x
+class _ActionActionTestCase(unittest.TestCase):
 
     def test__init__(self):
-        """Test creation of ActionBase objects
+        """Test creation of _ActionAction objects
         """
 
-        def func():
+        def func1():
+            pass
+
+        def func2():
             pass
 
-        a = SCons.Action.ActionBase()
+        a = SCons.Action._ActionAction()
         assert not hasattr(a, 'strfunction')
 
-        assert SCons.Action.ActionBase(kwarg = 1)
+        assert SCons.Action._ActionAction(kwarg = 1)
         assert not hasattr(a, 'strfunction')
         assert not hasattr(a, 'kwarg')
 
-        a = SCons.Action.ActionBase(func)
-        assert a.strfunction is func, a.strfunction
+        a = SCons.Action._ActionAction(strfunction=func1)
+        assert a.strfunction is func1, a.strfunction
+
+        a = SCons.Action._ActionAction(presub=func1)
+        assert a.presub is func1, a.presub
 
-        a = SCons.Action.ActionBase(strfunction=func)
-        assert a.strfunction is func, a.strfunction
+        a = SCons.Action._ActionAction(chdir=1)
+        assert a.chdir is 1, a.chdir
+
+        a = SCons.Action._ActionAction(func1, func2, 'x')
+        assert a.strfunction is func1, a.strfunction
+        assert a.presub is func2, a.presub
+        assert a.chdir is 'x', a.chdir
 
     def test___cmp__(self):
         """Test Action comparison
@@ -350,6 +375,25 @@ class ActionBaseTestCase(unittest.TestCase):
         assert a1 != a3
         assert a2 != a3
 
+    def test_print_cmd_lines(self):
+        """Test the print_cmd_lines() method
+        """
+        save_stdout = sys.stdout
+
+        try:
+            def execfunc(target, source, env):
+                pass
+            a = SCons.Action.Action(execfunc)
+
+            sio = StringIO.StringIO()
+            sys.stdout = sio
+            a.print_cmd_line("foo bar", None, None, None)
+            s = sio.getvalue()
+            assert s == "foo bar\n", s
+
+        finally:
+            sys.stdout = save_stdout
+
     def test___call__(self):
         """Test calling an Action
         """
@@ -360,6 +404,10 @@ class ActionBaseTestCase(unittest.TestCase):
         save_execute_actions = SCons.Action.execute_actions
         #SCons.Action.print_actions = 0
 
+        test = TestCmd.TestCmd(workdir = '')
+        test.subdir('sub', 'xyz')
+        os.chdir(test.workpath())
+
         try:
             env = Environment()
 
@@ -369,13 +417,49 @@ class ActionBaseTestCase(unittest.TestCase):
                 return 7
             a = SCons.Action.Action(execfunc)
 
+            def firstfunc(target, source, env):
+                assert type(target) is type([]), type(target)
+                assert type(source) is type([]), type(source)
+                return 0
+            def lastfunc(target, source, env):
+                assert type(target) is type([]), type(target)
+                assert type(source) is type([]), type(source)
+                return 9
+            b = SCons.Action.Action([firstfunc, execfunc, lastfunc])
+            
             sio = StringIO.StringIO()
             sys.stdout = sio
             result = a("out", "in", env)
-            assert result == 7, result
+            assert result.status == 7, result
             s = sio.getvalue()
             assert s == 'execfunc(["out"], ["in"])\n', s
 
+            a.chdir = 'xyz'
+            expect = 'os.chdir(%s)\nexecfunc(["out"], ["in"])\nos.chdir(%s)\n'
+
+            sio = StringIO.StringIO()
+            sys.stdout = sio
+            result = a("out", "in", env)
+            assert result.status == 7, result.status
+            s = sio.getvalue()
+            assert s == expect % (repr('xyz'), repr(test.workpath())), s
+
+            sio = StringIO.StringIO()
+            sys.stdout = sio
+            result = a("out", "in", env, chdir='sub')
+            assert result.status == 7, result.status
+            s = sio.getvalue()
+            assert s == expect % (repr('sub'), repr(test.workpath())), s
+
+            a.chdir = None
+
+            sio = StringIO.StringIO()
+            sys.stdout = sio
+            result = b("out", "in", env)
+            assert result.status == 7, result.status
+            s = sio.getvalue()
+            assert s == 'firstfunc(["out"], ["in"])\nexecfunc(["out"], ["in"])\n', s
+
             SCons.Action.execute_actions = 0
 
             sio = StringIO.StringIO()
@@ -385,30 +469,68 @@ class ActionBaseTestCase(unittest.TestCase):
             s = sio.getvalue()
             assert s == 'execfunc(["out"], ["in"])\n', s
 
+            sio = StringIO.StringIO()
+            sys.stdout = sio
+            result = b("out", "in", env)
+            assert result == 0, result
+            s = sio.getvalue()
+            assert s == 'firstfunc(["out"], ["in"])\nexecfunc(["out"], ["in"])\nlastfunc(["out"], ["in"])\n', s
+
             SCons.Action.print_actions_presub = 1
+            SCons.Action.execute_actions = 1
 
             sio = StringIO.StringIO()
             sys.stdout = sio
             result = a("out", "in", env)
-            assert result == 0, result
+            assert result.status == 7, result.status
+            s = sio.getvalue()
+            assert s == 'Building out with action:\n  execfunc(target, source, env)\nexecfunc(["out"], ["in"])\n', s
+
+            sio = StringIO.StringIO()
+            sys.stdout = sio
+            result = a("out", "in", env, presub=0)
+            assert result.status == 7, result.status
             s = sio.getvalue()
             assert s == 'execfunc(["out"], ["in"])\n', s
 
             sio = StringIO.StringIO()
             sys.stdout = sio
             result = a("out", "in", env, presub=1)
-            assert result == 0, result
+            assert result.status == 7, result.status
+            s = sio.getvalue()
+            assert s == 'Building out with action:\n  execfunc(target, source, env)\nexecfunc(["out"], ["in"])\n', s
+
+            sio = StringIO.StringIO()
+            sys.stdout = sio
+            result = b(["out"], "in", env, presub=1)
+            assert result.status == 7, result.status
+            s = sio.getvalue()
+            assert s == 'Building out with action:\n  firstfunc(target, source, env)\nfirstfunc(["out"], ["in"])\nBuilding out with action:\n  execfunc(target, source, env)\nexecfunc(["out"], ["in"])\n', s
+
+            sio = StringIO.StringIO()
+            sys.stdout = sio
+            result = b(["out", "list"], "in", env, presub=1)
+            assert result.status == 7, result.status
             s = sio.getvalue()
-            assert s == 'Building out with action(s):\n  execfunc(env, target, source)\nexecfunc(["out"], ["in"])\n', s
+            assert s == 'Building out and list with action:\n  firstfunc(target, source, env)\nfirstfunc(["out", "list"], ["in"])\nBuilding out and list with action:\n  execfunc(target, source, env)\nexecfunc(["out", "list"], ["in"])\n', s
 
             a2 = SCons.Action.Action(execfunc)
 
             sio = StringIO.StringIO()
             sys.stdout = sio
             result = a2("out", "in", env)
-            assert result == 0, result
+            assert result.status == 7, result.status
             s = sio.getvalue()
-            assert s == 'Building out with action(s):\n  execfunc(env, target, source)\nexecfunc(["out"], ["in"])\n', s
+            assert s == 'Building out with action:\n  execfunc(target, source, env)\nexecfunc(["out"], ["in"])\n', s
+
+            sio = StringIO.StringIO()
+            sys.stdout = sio
+            result = a2("out", "in", env, presub=0)
+            assert result.status == 7, result.status
+            s = sio.getvalue()
+            assert s == 'execfunc(["out"], ["in"])\n', s
+
+            SCons.Action.execute_actions = 0
 
             sio = StringIO.StringIO()
             sys.stdout = sio
@@ -420,23 +542,34 @@ class ActionBaseTestCase(unittest.TestCase):
             sio = StringIO.StringIO()
             sys.stdout = sio
             result = a("out", "in", env, presub=0, execute=1, show=0)
-            assert result == 7, result
+            assert result.status == 7, result.status
             s = sio.getvalue()
             assert s == '', s
 
             sys.stdout = save_stdout
-            errfunc_result = []
+            exitstatfunc_result = []
 
-            def errfunc(stat, result=errfunc_result):
+            def exitstatfunc(stat, result=exitstatfunc_result):
                 result.append(stat)
+                return stat
 
-            result = a("out", "in", env, errfunc=errfunc)
+            result = a("out", "in", env, exitstatfunc=exitstatfunc)
             assert result == 0, result
-            assert errfunc_result == [], errfunc_result
+            assert exitstatfunc_result == [], exitstatfunc_result
+
+            result = a("out", "in", env, execute=1, exitstatfunc=exitstatfunc)
+            assert result.status == 7, result.status
+            assert exitstatfunc_result == [7], exitstatfunc_result
+
+            SCons.Action.execute_actions = 1
 
-            result = a("out", "in", env, execute=1, errfunc=errfunc)
-            assert result == 7, result
-            assert errfunc_result == [7], errfunc_result
+            result = []
+            def my_print_cmd_line(s, target, source, env, result=result):
+                result.append(s)
+            env['PRINT_CMD_LINE_FUNC'] = my_print_cmd_line
+            a("output", "input", env)
+            assert result == ['execfunc(["output"], ["input"])'], result
+            
 
         finally:
             sys.stdout = save_stdout
@@ -460,11 +593,11 @@ class ActionBaseTestCase(unittest.TestCase):
             pass
         a = SCons.Action.Action(func)
         s = a.presub_lines(env)
-        assert s == ["func(env, target, source)"], s
+        assert s == ["func(target, source, env)"], s
 
         def gen(target, source, env, for_signature):
             return 'generat' + env.get('GEN', 'or')
-        a = SCons.Action.Action(SCons.Action.CommandGenerator(gen))
+        a = SCons.Action.Action(gen, generator=1)
         s = a.presub_lines(env)
         assert s == ["generator"], s
         s = a.presub_lines(Environment(GEN = 'ed'))
@@ -476,13 +609,6 @@ class ActionBaseTestCase(unittest.TestCase):
         s = a.presub_lines(Environment(ACT = 'expanded action'))
         assert s == ['expanded action'], s
 
-    def test_get_actions(self):
-        """Test the get_actions() method
-        """
-        a = SCons.Action.Action("x")
-        l = a.get_actions()
-        assert l == [a], l
-
     def test_add(self):
         """Test adding Actions to stuff."""
         # Adding actions to other Actions or to stuff that can
@@ -490,7 +616,7 @@ class ActionBaseTestCase(unittest.TestCase):
         # containing all the Actions.
         def bar():
             return None
-        baz = SCons.Action.CommandGenerator(bar)
+        baz = SCons.Action.Action(bar, generator=1)
         act1 = SCons.Action.Action('foo bar')
         act2 = SCons.Action.Action([ 'foo', bar ])
 
@@ -567,6 +693,23 @@ class CommandActionTestCase(unittest.TestCase):
         """
         a = SCons.Action.CommandAction(["xyzzy"])
         assert a.cmd_list == [ "xyzzy" ], a.cmd_list
+        assert a.cmdstr is None, a.cmdstr
+
+        a = SCons.Action.CommandAction(["abra"], "cadabra")
+        assert a.cmd_list == [ "abra" ], a.cmd_list
+        assert a.cmdstr == "cadabra", a.cmdstr
+
+    def test_bad_cmdstr(self):
+        """Test handling of bad CommandAction(cmdstr) arguments
+        """
+        try:
+            a = SCons.Action.CommandAction('foo', [])
+        except SCons.Errors.UserError, e:
+            s = str(e)
+            m = 'Invalid command display variable'
+            assert string.find(s, m) != -1, 'Unexpected string:  %s' % s
+        else:
+            raise Exception, "did not catch expected UserError"
 
     def test___str__(self):
         """Test fetching the pre-substitution string for command Actions
@@ -580,7 +723,7 @@ class CommandActionTestCase(unittest.TestCase):
                                           '$TARGET', '$SOURCE',
                                           '$TARGETS', '$SOURCES'])
         s = str(act)
-        assert s == "['xyzzy', '$TARGET', '$SOURCE', '$TARGETS', '$SOURCES']", s
+        assert s == "xyzzy $TARGET $SOURCE $TARGETS $SOURCES", s
 
     def test_genstring(self):
         """Test the genstring() method for command Actions
@@ -612,7 +755,7 @@ class CommandActionTestCase(unittest.TestCase):
         act = SCons.Action.CommandAction(['xyzzy',
                                           '$TARGET', '$SOURCE',
                                           '$TARGETS', '$SOURCES'])
-        expect = "['xyzzy', '$TARGET', '$SOURCE', '$TARGETS', '$SOURCES']"
+        expect = "xyzzy $TARGET $SOURCE $TARGETS $SOURCES"
         s = act.genstring([], [], env)
         assert s == expect, s
         s = act.genstring([t1], [s1], env)
@@ -637,6 +780,15 @@ class CommandActionTestCase(unittest.TestCase):
         s = act.strfunction([t1, t2], [s1, s2], env)
         assert s == 'xyzzy t1 s1', s
 
+        act = SCons.Action.CommandAction('xyzzy $TARGET $SOURCE',
+                                         'cmdstr - $SOURCE - $TARGET -')
+        s = act.strfunction([], [], env)
+        assert s == 'cmdstr -  -  -', s
+        s = act.strfunction([t1], [s1], env)
+        assert s == 'cmdstr - s1 - t1 -', s
+        s = act.strfunction([t1, t2], [s1, s2], env)
+        assert s == 'cmdstr - s1 - t1 -', s
+
         act = SCons.Action.CommandAction('xyzzy $TARGETS $SOURCES')
         s = act.strfunction([], [], env)
         assert s == 'xyzzy', s
@@ -645,6 +797,15 @@ class CommandActionTestCase(unittest.TestCase):
         s = act.strfunction([t1, t2], [s1, s2], env)
         assert s == 'xyzzy t1 t2 s1 s2', s
 
+        act = SCons.Action.CommandAction('xyzzy $TARGETS $SOURCES',
+                                         'cmdstr = $SOURCES = $TARGETS =')
+        s = act.strfunction([], [], env)
+        assert s == 'cmdstr =  =  =', s
+        s = act.strfunction([t1], [s1], env)
+        assert s == 'cmdstr = s1 = t1 =', s
+        s = act.strfunction([t1, t2], [s1, s2], env)
+        assert s == 'cmdstr = s1 s2 = t1 t2 =', s
+
         act = SCons.Action.CommandAction(['xyzzy',
                                           '$TARGET', '$SOURCE',
                                           '$TARGETS', '$SOURCES'])
@@ -655,12 +816,95 @@ class CommandActionTestCase(unittest.TestCase):
         s = act.strfunction([t1, t2], [s1, s2], env)
         assert s == 'xyzzy t1 s1 t1 t2 s1 s2', s
 
+        act = SCons.Action.CommandAction('xyzzy $TARGETS $SOURCES',
+                                         'cmdstr\t$TARGETS\n$SOURCES   ')
+                    
+        s = act.strfunction([], [], env)
+        assert s == 'cmdstr\t\n   ', s
+        s = act.strfunction([t1], [s1], env)
+        assert s == 'cmdstr\tt1\ns1   ', s
+        s = act.strfunction([t1, t2], [s1, s2], env)
+        assert s == 'cmdstr\tt1 t2\ns1 s2   ', s
+
         def sf(target, source, env):
             return "sf was called"
         act = SCons.Action.CommandAction('foo', strfunction=sf)
         s = act.strfunction([], [], env)
         assert s == "sf was called", s
 
+        class actclass1:
+            def __init__(self, targets, sources, env):
+                pass
+            def __call__(self):
+                return 1
+        class actclass2:
+            def __init__(self, targets, sources, env):
+                self.strfunction = 5
+            def __call__(self):
+                return 2
+        class actclass3:
+            def __init__(self, targets, sources, env):
+                pass
+            def __call__(self):
+                return 3
+            def strfunction(self, targets, sources, env):
+                return 'actclass3 on %s to get %s'%(str(sources[0]),
+                                                    str(targets[0]))
+        class actclass4:
+            def __init__(self, targets, sources, env):
+                pass
+            def __call__(self):
+                return 4
+            strfunction = None
+
+        act1 = SCons.Action.Action(actclass1([t1], [s1], env))
+        s = act1.strfunction([t1], [s1], env)
+        assert s == 'actclass1(["t1"], ["s1"])', s
+
+        act2 = SCons.Action.Action(actclass2([t1], [s1], env))
+        s = act2.strfunction([t1], [s1], env)
+        assert s == 'actclass2(["t1"], ["s1"])', s
+
+        act3 = SCons.Action.Action(actclass3([t1], [s1], env))
+        s = act3.strfunction([t1], [s1], env)
+        assert s == 'actclass3 on s1 to get t1', s
+
+        act4 = SCons.Action.Action(actclass4([t1], [s1], env))
+        s = act4.strfunction([t1], [s1], env)
+        assert s is None, s
+
+        act = SCons.Action.CommandAction("@foo bar")
+        s = act.strfunction([], [], env)
+        assert s == "", s
+
+        act = SCons.Action.CommandAction("@-foo bar")
+        s = act.strfunction([], [], env)
+        assert s == "", s
+
+        act = SCons.Action.CommandAction("-@foo bar")
+        s = act.strfunction([], [], env)
+        assert s == "", s
+
+        act = SCons.Action.CommandAction("-foo bar")
+        s = act.strfunction([], [], env)
+        assert s == "foo bar", s
+
+        act = SCons.Action.CommandAction("@ foo bar")
+        s = act.strfunction([], [], env)
+        assert s == "", s
+
+        act = SCons.Action.CommandAction("@- foo bar")
+        s = act.strfunction([], [], env)
+        assert s == "", s
+
+        act = SCons.Action.CommandAction("-@ foo bar")
+        s = act.strfunction([], [], env)
+        assert s == "", s
+
+        act = SCons.Action.CommandAction("- foo bar")
+        s = act.strfunction([], [], env)
+        assert s == "foo bar", s
+
     def test_execute(self):
         """Test execution of command Actions
 
@@ -670,49 +914,49 @@ class CommandActionTestCase(unittest.TestCase):
         except AttributeError:
             env = Environment()
 
-        cmd1 = r'%s %s %s xyzzy' % (python, act_py, outfile)
+        cmd1 = r'%s %s %s xyzzy' % (_python_, act_py, outfile)
 
         act = SCons.Action.CommandAction(cmd1)
-        r = act([], [], env.Copy())
+        r = act([], [], env.Clone())
         assert r == 0
         c = test.read(outfile, 'r')
         assert c == "act.py: 'xyzzy'\n", c
 
-        cmd2 = r'%s %s %s $TARGET' % (python, act_py, outfile)
+        cmd2 = r'%s %s %s $TARGET' % (_python_, act_py, outfile)
 
         act = SCons.Action.CommandAction(cmd2)
-        r = act(DummyNode('foo'), [], env.Copy())
+        r = act(DummyNode('foo'), [], env.Clone())
         assert r == 0
         c = test.read(outfile, 'r')
         assert c == "act.py: 'foo'\n", c
 
-        cmd3 = r'%s %s %s ${TARGETS}' % (python, act_py, outfile)
+        cmd3 = r'%s %s %s ${TARGETS}' % (_python_, act_py, outfile)
 
         act = SCons.Action.CommandAction(cmd3)
-        r = act(map(DummyNode, ['aaa', 'bbb']), [], env.Copy())
+        r = act(map(DummyNode, ['aaa', 'bbb']), [], env.Clone())
         assert r == 0
         c = test.read(outfile, 'r')
         assert c == "act.py: 'aaa' 'bbb'\n", c
 
-        cmd4 = r'%s %s %s $SOURCES' % (python, act_py, outfile)
+        cmd4 = r'%s %s %s $SOURCES' % (_python_, act_py, outfile)
 
         act = SCons.Action.CommandAction(cmd4)
-        r = act([], [DummyNode('one'), DummyNode('two')], env.Copy())
+        r = act([], [DummyNode('one'), DummyNode('two')], env.Clone())
         assert r == 0
         c = test.read(outfile, 'r')
         assert c == "act.py: 'one' 'two'\n", c
 
-        cmd4 = r'%s %s %s ${SOURCES[:2]}' % (python, act_py, outfile)
+        cmd4 = r'%s %s %s ${SOURCES[:2]}' % (_python_, act_py, outfile)
 
         act = SCons.Action.CommandAction(cmd4)
         sources = [DummyNode('three'), DummyNode('four'), DummyNode('five')]
-        env2 = env.Copy()
+        env2 = env.Clone()
         r = act([], source = sources, env = env2)
         assert r == 0
         c = test.read(outfile, 'r')
         assert c == "act.py: 'three' 'four'\n", c
 
-        cmd5 = r'%s %s %s $TARGET XYZZY' % (python, act_py, outfile)
+        cmd5 = r'%s %s %s $TARGET XYZZY' % (_python_, act_py, outfile)
 
         act = SCons.Action.CommandAction(cmd5)
         env5 = Environment()
@@ -729,7 +973,7 @@ class CommandActionTestCase(unittest.TestCase):
         act = SCons.Action.CommandAction(cmd5)
         r = act(target = DummyNode('out5'),
                 source = [],
-                env = env.Copy(ENV = {'XYZZY' : 'xyzzy5',
+                env = env.Clone(ENV = {'XYZZY' : 'xyzzy5',
                                       'PATH' : PATH}))
         assert r == 0
         c = test.read(outfile, 'r')
@@ -745,12 +989,12 @@ class CommandActionTestCase(unittest.TestCase):
             def get_subst_proxy(self):
                 return self
 
-        cmd6 = r'%s %s %s ${TARGETS[1]} $TARGET ${SOURCES[:2]}' % (python, act_py, outfile)
+        cmd6 = r'%s %s %s ${TARGETS[1]} $TARGET ${SOURCES[:2]}' % (_python_, act_py, outfile)
 
         act = SCons.Action.CommandAction(cmd6)
         r = act(target = [Obj('111'), Obj('222')],
                         source = [Obj('333'), Obj('444'), Obj('555')],
-                        env = env.Copy())
+                        env = env.Clone())
         assert r == 0
         c = test.read(outfile, 'r')
         assert c == "act.py: '222' '111' '333' '444'\n", c
@@ -762,29 +1006,67 @@ class CommandActionTestCase(unittest.TestCase):
             expect_nonexecutable = 1
         elif sys.platform == 'cygwin':
             expect_nonexistent = 127
-            expect_nonexecutable = 127
+            # Newer cygwin seems to return 126 for following
+            expect_nonexecutable_file = 126
+            expect_nonexecutable_dir  = 127
         else:
             expect_nonexistent = 127
-            expect_nonexecutable = 126
+            expect_nonexecutable_file = 126
+            expect_nonexecutable_dir  = 126
 
         # Test that a nonexistent command returns 127
         act = SCons.Action.CommandAction(python + "_no_such_command_")
-        r = act([], [], env.Copy(out = outfile))
-        assert r == expect_nonexistent, "r == %d" % r
+        r = act([], [], env.Clone(out = outfile))
+        assert r.status == expect_nonexistent, r.status
 
         # Test that trying to execute a directory returns 126
         dir, tail = os.path.split(python)
         act = SCons.Action.CommandAction(dir)
-        r = act([], [], env.Copy(out = outfile))
-        assert r == expect_nonexecutable, "r == %d" % r
+        r = act([], [], env.Clone(out = outfile))
+        assert r.status == expect_nonexecutable_file, r.status
 
         # Test that trying to execute a non-executable file returns 126
         act = SCons.Action.CommandAction(outfile)
-        r = act([], [], env.Copy(out = outfile))
-        assert r == expect_nonexecutable, "r == %d" % r
+        r = act([], [], env.Clone(out = outfile))
+        assert r.status == expect_nonexecutable_dir, r.status
+
+        act = SCons.Action.CommandAction('%s %s 1' % (_python_, exit_py))
+        r = act([], [], env)
+        assert r.status == 1, r.status
+
+        act = SCons.Action.CommandAction('@%s %s 1' % (_python_, exit_py))
+        r = act([], [], env)
+        assert r.status == 1, r.status
+
+        act = SCons.Action.CommandAction('@-%s %s 1' % (_python_, exit_py))
+        r = act([], [], env)
+        assert r == 0, r
+
+        act = SCons.Action.CommandAction('-%s %s 1' % (_python_, exit_py))
+        r = act([], [], env)
+        assert r == 0, r
+
+        act = SCons.Action.CommandAction('@ %s %s 1' % (_python_, exit_py))
+        r = act([], [], env)
+        assert r.status == 1, r.status
 
-    def test_pipe_execute(self):
+        act = SCons.Action.CommandAction('@- %s %s 1' % (_python_, exit_py))
+        r = act([], [], env)
+        assert r == 0, r
+
+        act = SCons.Action.CommandAction('- %s %s 1' % (_python_, exit_py))
+        r = act([], [], env)
+        assert r == 0, r
+
+    def _DO_NOT_EXECUTE_test_pipe_execute(self):
         """Test capturing piped output from an action
+
+        We used to have PIPE_BUILD support built right into
+        Action.execute() for the benefit of the SConf subsystem, but we've
+        moved that logic back into SConf itself.  We'll leave this code
+        here, just in case we ever want to resurrect this functionality
+        in the future, but change the name of the test so it doesn't
+        get executed as part of the normal test suite.
         """
         pipe = open( pipe_file, "w" )
         self.env = Environment(ENV = {'ACTPY_PIPE' : '1'}, PIPE_BUILD = 1,
@@ -806,11 +1088,11 @@ class CommandActionTestCase(unittest.TestCase):
 
         # test redirection operators
         def test_redirect(self, redir, stdout_msg, stderr_msg):
-            cmd = r'%s %s %s xyzzy %s' % (python, act_py, outfile, redir)
-            # Write the output and error messages to files because Win32
-            # can't handle strings that are too big in its external
-            # environment (os.spawnve() returns EINVAL, "Invalid
-            # argument").
+            cmd = r'%s %s %s xyzzy %s' % (_python_, act_py, outfile, redir)
+            # Write the output and error messages to files because
+            # Windows can't handle strings that are too big in its
+            # external environment (os.spawnve() returns EINVAL,
+            # "Invalid argument").
             stdout_file = test.workpath('stdout_msg')
             stderr_file = test.workpath('stderr_msg')
             open(stdout_file, 'w').write(stdout_msg)
@@ -880,6 +1162,11 @@ class CommandActionTestCase(unittest.TestCase):
         a([], [], e)
         assert t.executed == [ 'xyzzy' ], t.executed
 
+        a = SCons.Action.CommandAction(["xyzzy"])
+        e = Environment(SPAWN = '$FUNC', FUNC = func)
+        a([], [], e)
+        assert t.executed == [ 'xyzzy' ], t.executed
+
         a = SCons.Action.CommandAction(["xyzzy"])
         e = Environment(SPAWN = func, SHELL = 'fake shell')
         a([], [], e)
@@ -910,7 +1197,7 @@ class CommandActionTestCase(unittest.TestCase):
         # Make sure that CommandActions use an Environment's
         # subst_target_source() method for substitution.
         class SpecialEnvironment(Environment):
-            def subst_target_source(self, strSubst, raw=0, target=[], source=[], dict=None):
+            def subst_target_source(self, strSubst, raw=0, target=[], source=[]):
                 return 'subst_target_source: ' + strSubst
 
         c = a.get_contents(target=DummyNode('ttt'), source = DummyNode('sss'),
@@ -934,14 +1221,10 @@ class CommandActionTestCase(unittest.TestCase):
         a = SCons.Action.CommandAction(["$TARGET"])
         c = a.get_contents(target=t, source=s, env=env)
         assert c == "t1", c
-        c = a.get_contents(target=t, source=s, env=env, dict={})
-        assert c == "", c
 
         a = SCons.Action.CommandAction(["$TARGETS"])
         c = a.get_contents(target=t, source=s, env=env)
         assert c == "t1 t2 t3 t4 t5 t6", c
-        c = a.get_contents(target=t, source=s, env=env, dict={})
-        assert c == "", c
 
         a = SCons.Action.CommandAction(["${TARGETS[2]}"])
         c = a.get_contents(target=t, source=s, env=env)
@@ -954,14 +1237,10 @@ class CommandActionTestCase(unittest.TestCase):
         a = SCons.Action.CommandAction(["$SOURCE"])
         c = a.get_contents(target=t, source=s, env=env)
         assert c == "s1", c
-        c = a.get_contents(target=t, source=s, env=env, dict={})
-        assert c == "", c
 
         a = SCons.Action.CommandAction(["$SOURCES"])
         c = a.get_contents(target=t, source=s, env=env)
         assert c == "s1 s2 s3 s4 s5 s6", c
-        c = a.get_contents(target=t, source=s, env=env, dict={})
-        assert c == "", c
 
         a = SCons.Action.CommandAction(["${SOURCES[2]}"])
         c = a.get_contents(target=t, source=s, env=env)
@@ -985,6 +1264,14 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
         """Test the pre-substitution strings for command generator Actions
         """
         def f(target, source, env, for_signature, self=self):
+
+            # See if "env" is really a construction environment (or
+            # looks like one) by accessing the FindIxes attribute.
+            # (The Tool/mingw.py module has a generator that uses this,
+            # and the __str__() method used to cause problems by passing
+            # us a regular dictionary as a fallback.)
+
+            env.FindIxes
             return "FOO"
         a = SCons.Action.CommandGeneratorAction(f)
         s = str(a)
@@ -1003,32 +1290,6 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
         assert self.dummy == 1, self.dummy
         assert s == "$FOO $TARGET $SOURCE $TARGETS $SOURCES", s
 
-    def test_strfunction(self):
-        """Test the command generator Action string function
-        """
-        def f(target, source, env, for_signature, self=self):
-            dummy = env['dummy']
-            self.dummy = dummy
-            return "$FOO"
-        a = SCons.Action.CommandGeneratorAction(f)
-        self.dummy = 0
-        s = a.strfunction([], [], env=Environment(FOO='xyzzy', dummy=1))
-        assert self.dummy == 1, self.dummy
-        assert s == 'xyzzy', s
-
-        def sf(target, source, env):
-            return "sf was called"
-        a = SCons.Action.CommandGeneratorAction(f, strfunction=sf)
-        s = a.strfunction([], [], env=Environment())
-        assert s == "sf was called", s
-
-        def f(target, source, env, for_signature, self=self):
-            def null(target, source, env):
-                pass
-            return SCons.Action.Action(null, strfunction=None)
-        a = SCons.Action.CommandGeneratorAction(f)
-        s = a.strfunction([], [], env=Environment())
-
     def test_execute(self):
         """Test executing a command generator Action
         """
@@ -1101,8 +1362,6 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
         a = SCons.Action.CommandGeneratorAction(f)
         c = a.get_contents(target=[], source=[], env=env)
         assert c == "guux FFF BBB test", c
-        c = a.get_contents(target=[], source=[], env=env, dict={})
-        assert c == "guux FFF BBB test", c
 
 
 class FunctionActionTestCase(unittest.TestCase):
@@ -1127,6 +1386,20 @@ class FunctionActionTestCase(unittest.TestCase):
         assert a.execfunction == func2, a.execfunction
         assert a.strfunction == func3, a.strfunction
 
+    def test_cmdstr_bad(self):
+        """Test handling of bad FunctionAction(cmdstr) arguments
+        """
+        def func():
+            pass
+        try:
+            a = SCons.Action.FunctionAction(func, [])
+        except SCons.Errors.UserError, e:
+            s = str(e)
+            m = 'Invalid function display variable'
+            assert string.find(s, m) != -1, 'Unexpected string:  %s' % s
+        else:
+            raise "did not catch expected UserError"
+
     def test___str__(self):
         """Test the __str__() method for function Actions
         """
@@ -1134,14 +1407,14 @@ class FunctionActionTestCase(unittest.TestCase):
             pass
         a = SCons.Action.FunctionAction(func1)
         s = str(a)
-        assert s == "func1(env, target, source)", s
+        assert s == "func1(target, source, env)", s
 
         class class1:
             def __call__(self):
                 pass
         a = SCons.Action.FunctionAction(class1())
         s = str(a)
-        assert s == "class1(env, target, source)", s
+        assert s == "class1(target, source, env)", s
 
     def test_execute(self):
         """Test executing a function Action
@@ -1171,13 +1444,10 @@ class FunctionActionTestCase(unittest.TestCase):
             return 1
 
         act = SCons.Action.FunctionAction(function1)
-        r = None
-        try:
-            r = act(target = [outfile, outfile2], source=[], env=Environment())
-        except SCons.Errors.BuildError:
-            pass
-        assert r == 1
-        assert count == 1
+        r = act(target = [outfile, outfile2], source=[], env=Environment())
+        assert r.status == 1, r.status
+
+        assert count == 1, count
         c = test.read(outfile, 'r')
         assert c == "function1\n", c
         c = test.read(outfile2, 'r')
@@ -1189,7 +1459,7 @@ class FunctionActionTestCase(unittest.TestCase):
 
         act = SCons.Action.FunctionAction(class1a)
         r = act([], [], Environment(out = outfile))
-        assert r.__class__ == class1a
+        assert isinstance(r.status, class1a), r.status
         c = test.read(outfile, 'r')
         assert c == "class1a\n", c
 
@@ -1200,7 +1470,7 @@ class FunctionActionTestCase(unittest.TestCase):
 
         act = SCons.Action.FunctionAction(class1b())
         r = act([], [], Environment(out = outfile))
-        assert r == 2
+        assert r.status == 2, r.status
         c = test.read(outfile, 'r')
         assert c == "class1b\n", c
 
@@ -1220,34 +1490,69 @@ class FunctionActionTestCase(unittest.TestCase):
         """Test fetching the contents of a function Action
         """
 
-        a = SCons.Action.FunctionAction(GlobalFunc)
+        def LocalFunc():
+            pass
 
-        matches = [
-            "\177\036\000\177\037\000d\000\000S",
-            "d\x00\x00S",
+        func_matches = [
+            "0,0,0,0,(),(),(d\000\000S),(),()",
+            "0,0,0,0,(),(),(d\x00\x00S),(),()",
+            ]
+        
+        meth_matches = [
+            "1,1,0,0,(),(),(d\000\000S),(),()",
+            "1,1,0,0,(),(),(d\x00\x00S),(),()",
         ]
 
+        a = SCons.Action.FunctionAction(GlobalFunc)
         c = a.get_contents(target=[], source=[], env=Environment())
-        assert c in matches, repr(c)
-        c = a.get_contents(target=[], source=[], env=Environment(), dict={})
-        assert c in matches, repr(c)
+        assert c in func_matches, repr(c)
+
+        a = SCons.Action.FunctionAction(LocalFunc)
+        c = a.get_contents(target=[], source=[], env=Environment())
+        assert c in func_matches, repr(c)
 
         a = SCons.Action.FunctionAction(GlobalFunc, varlist=['XYZ'])
 
-        matches_foo = map(lambda x: x + "foo", matches)
+        matches_foo = map(lambda x: x + "foo", func_matches)
 
         c = a.get_contents(target=[], source=[], env=Environment())
-        assert c in matches, repr(c)
+        assert c in func_matches, repr(c)
         c = a.get_contents(target=[], source=[], env=Environment(XYZ = 'foo'))
         assert c in matches_foo, repr(c)
 
         class Foo:
-            def get_contents(self, target, source, env, dict=None):
+            def get_contents(self, target, source, env):
                 return 'xyzzy'
         a = SCons.Action.FunctionAction(Foo())
         c = a.get_contents(target=[], source=[], env=Environment())
         assert c == 'xyzzy', repr(c)
 
+        class LocalClass:
+            def LocalMethod(self):
+                pass
+        lc = LocalClass()
+        a = SCons.Action.FunctionAction(lc.LocalMethod)
+        c = a.get_contents(target=[], source=[], env=Environment())
+        assert c in meth_matches, repr(c)
+
+    def test_strfunction(self):
+        """Test the FunctionAction.strfunction() method
+        """
+        def func():
+            pass
+
+        a = SCons.Action.FunctionAction(func)
+        s = a.strfunction(target=[], source=[], env=Environment())
+        assert s == 'func([], [])', s
+
+        a = SCons.Action.FunctionAction(func, None)
+        s = a.strfunction(target=[], source=[], env=Environment())
+        assert s is None, s
+
+        a = SCons.Action.FunctionAction(func, 'function')
+        s = a.strfunction(target=[], source=[], env=Environment())
+        assert s == 'function', s
+
 class ListActionTestCase(unittest.TestCase):
 
     def test___init__(self):
@@ -1261,19 +1566,6 @@ class ListActionTestCase(unittest.TestCase):
         assert isinstance(a.list[2], SCons.Action.ListAction)
         assert a.list[2].list[0].cmd_list == 'y'
 
-    def test_get_actions(self):
-        """Test the get_actions() method for ListActions
-        """
-        a = SCons.Action.ListAction(["x", "y"])
-        l = a.get_actions()
-        assert len(l) == 2, l
-        assert isinstance(l[0], SCons.Action.CommandAction), l[0]
-        g = l[0].get_actions()
-        assert g == [l[0]], g
-        assert isinstance(l[1], SCons.Action.CommandAction), l[1]
-        g = l[1].get_actions()
-        assert g == [l[1]], g
-
     def test___str__(self):
         """Test the __str__() method for a list of subsidiary Actions
         """
@@ -1283,35 +1575,19 @@ class ListActionTestCase(unittest.TestCase):
             pass
         a = SCons.Action.ListAction([f, g, "XXX", f])
         s = str(a)
-        assert s == "f(env, target, source)\ng(env, target, source)\nXXX\nf(env, target, source)", s
+        assert s == "f(target, source, env)\ng(target, source, env)\nXXX\nf(target, source, env)", s
 
     def test_genstring(self):
         """Test the genstring() method for a list of subsidiary Actions
         """
         def f(target,source,env):
             pass
-        def g(target,source,env):
-            pass
+        def g(target,source,env,for_signature):
+            return 'generated %s %s' % (target[0], source[0])
+        g = SCons.Action.Action(g, generator=1)
         a = SCons.Action.ListAction([f, g, "XXX", f])
-        s = a.genstring([], [], Environment())
-        assert s == "f(env, target, source)\ng(env, target, source)\nXXX\nf(env, target, source)", s
-
-    def test_strfunction(self):
-        """Test the string function for a list of subsidiary Actions
-        """
-        def f(target,source,env):
-            pass
-        def g(target,source,env):
-            pass
-        a = SCons.Action.ListAction([f, g, "XXX", f])
-        s = a.strfunction([], [], Environment())
-        assert s == "f([], [])\ng([], [])\nXXX\nf([], [])", s
-
-        def sf(target, source, env):
-            return "sf was called"
-        act = SCons.Action.ListAction([f, g, "XXX", f], strfunction=sf)
-        s = act.strfunction([], [], Environment())
-        assert s == "sf was called", s
+        s = a.genstring(['foo.x'], ['bar.y'], Environment())
+        assert s == "f(target, source, env)\ngenerated foo.x bar.y\nXXX\nf(target, source, env)", s
 
     def test_execute(self):
         """Test executing a list of subsidiary Actions
@@ -1324,7 +1600,7 @@ class ListActionTestCase(unittest.TestCase):
         a([], [], Environment(s = self))
         assert self.inc == 3, self.inc
 
-        cmd2 = r'%s %s %s syzygy' % (python, act_py, outfile)
+        cmd2 = r'%s %s %s syzygy' % (_python_, act_py, outfile)
 
         def function2(target, source, env):
             open(env['out'], 'a').write("function2\n")
@@ -1340,7 +1616,7 @@ class ListActionTestCase(unittest.TestCase):
                 open(env['out'], 'a').write("class2b\n")
         act = SCons.Action.ListAction([cmd2, function2, class2a(), class2b])
         r = act([], [], Environment(out = outfile))
-        assert r.__class__ == class2b
+        assert isinstance(r.status, class2b), r.status
         c = test.read(outfile, 'r')
         assert c == "act.py: 'syzygy'\nfunction2\nclass2a\nclass2b\n", c
 
@@ -1353,38 +1629,26 @@ class ListActionTestCase(unittest.TestCase):
             s.foo=1
             return "y"
         a = SCons.Action.ListAction(["x",
-                                     SCons.Action.CommandGenerator(gen),
+                                     SCons.Action.Action(gen, generator=1),
                                      "z"])
         c = a.get_contents(target=[], source=[], env=Environment(s = self))
         assert self.foo==1, self.foo
         assert c == "xyz", c
-        c = a.get_contents(target=[], source=[], env=Environment(s = self), dict={})
-        assert self.foo==1, self.foo
-        assert c == "xyz", c
 
 class LazyActionTestCase(unittest.TestCase):
     def test___init__(self):
         """Test creation of a lazy-evaluation Action
         """
-        # Environment variable references should create a special
-        # type of CommandGeneratorAction that lazily evaluates the
-        # variable.
+        # Environment variable references should create a special type
+        # of LazyAction that lazily evaluates the variable for whether
+        # it's a string or something else before doing anything.
         a9 = SCons.Action.Action('$FOO')
-        assert isinstance(a9, SCons.Action.CommandGeneratorAction), a9
-        assert a9.generator.var == 'FOO', a9.generator.var
+        assert isinstance(a9, SCons.Action.LazyAction), a9
+        assert a9.var == 'FOO', a9.var
 
         a10 = SCons.Action.Action('${FOO}')
-        assert isinstance(a9, SCons.Action.CommandGeneratorAction), a10
-        assert a10.generator.var == 'FOO', a10.generator.var
-
-    def test_strfunction(self):
-        """Test the lazy-evaluation Action string function
-        """
-        def f(target, source, env):
-            pass
-        a = SCons.Action.Action('$BAR')
-        s = a.strfunction([], [], env=Environment(BAR=f, s=self))
-        assert s == "f([], [])", s
+        assert isinstance(a10, SCons.Action.LazyAction), a10
+        assert a10.var == 'FOO', a10.var
 
     def test_genstring(self):
         """Test the lazy-evaluation Action genstring() method
@@ -1392,8 +1656,12 @@ class LazyActionTestCase(unittest.TestCase):
         def f(target, source, env):
             pass
         a = SCons.Action.Action('$BAR')
-        s = a.genstring([], [], env=Environment(BAR=f, s=self))
-        assert s == "f(env, target, source)", s
+        env1 = Environment(BAR=f, s=self)
+        env2 = Environment(BAR='xxx', s=self)
+        s = a.genstring([], [], env=env1)
+        assert s == "f(target, source, env)", s
+        s = a.genstring([], [], env=env2)
+        assert s == 'xxx', s
 
     def test_execute(self):
         """Test executing a lazy-evaluation Action
@@ -1405,6 +1673,10 @@ class LazyActionTestCase(unittest.TestCase):
         a = SCons.Action.Action('$BAR')
         a([], [], env=Environment(BAR = f, s = self))
         assert self.test == 1, self.test
+        cmd = r'%s %s %s lazy' % (_python_, act_py, outfile)
+        a([], [], env=Environment(BAR = cmd, s = self))
+        c = test.read(outfile, 'r')
+        assert c == "act.py: 'lazy'\n", c
 
     def test_get_contents(self):
         """Test fetching the contents of a lazy-evaluation Action
@@ -1413,8 +1685,6 @@ class LazyActionTestCase(unittest.TestCase):
         env = Environment(FOO = [["This", "is", "a", "test"]])
         c = a.get_contents(target=[], source=[], env=env)
         assert c == "This is a test", c
-        c = a.get_contents(target=[], source=[], env=env, dict={})
-        assert c == "This is a test", c
 
 class ActionCallerTestCase(unittest.TestCase):
     def test___init__(self):
@@ -1429,8 +1699,11 @@ class ActionCallerTestCase(unittest.TestCase):
         def strfunc():
             pass
 
+        def LocalFunc():
+            pass
+
         matches = [
-            "\177\036\000\177\037\000d\000\000S",
+            "d\000\000S",
             "d\x00\x00S"
         ]
 
@@ -1439,16 +1712,30 @@ class ActionCallerTestCase(unittest.TestCase):
         c = ac.get_contents([], [], Environment())
         assert c in matches, repr(c)
 
+        af = SCons.Action.ActionFactory(LocalFunc, strfunc)
+        ac = SCons.Action.ActionCaller(af, [], {})
+        c = ac.get_contents([], [], Environment())
+        assert c in matches, repr(c)
+
         matches = [
-            '\177"\000\177#\000d\000\000S',
+            'd\000\000S',
             "d\x00\x00S"
         ]
 
+        class LocalActFunc:
+            def __call__(self):
+                pass
+
         af = SCons.Action.ActionFactory(GlobalActFunc(), strfunc)
         ac = SCons.Action.ActionCaller(af, [], {})
         c = ac.get_contents([], [], Environment())
         assert c in matches, repr(c)
 
+        af = SCons.Action.ActionFactory(LocalActFunc(), strfunc)
+        ac = SCons.Action.ActionCaller(af, [], {})
+        c = ac.get_contents([], [], Environment())
+        assert c in matches, repr(c)
+
         matches = [
             "<built-in function str>",
             "<type 'str'>",
@@ -1468,33 +1755,41 @@ class ActionCallerTestCase(unittest.TestCase):
         def strfunc(a1, a2, a3):
             pass
 
+        e = Environment(FOO = 2, BAR = 5)
+
         af = SCons.Action.ActionFactory(actfunc, strfunc)
-        ac = SCons.Action.ActionCaller(af, [1, '$FOO', 3], {})
-        ac([], [], Environment(FOO = 2))
-        assert actfunc_args == [1, '2', 3], actfunc_args
+        ac = SCons.Action.ActionCaller(af, ['$__env__', '$FOO', 3], {})
+        ac([], [], e)
+        assert actfunc_args[0] is e, actfunc_args
+        assert actfunc_args[1] == '2', actfunc_args
+        assert actfunc_args[2] == 3, actfunc_args
+        del actfunc_args[:]
 
+        ac = SCons.Action.ActionCaller(af, [], {'a3' : '$__env__', 'a2' : '$BAR', 'a1' : 4})
+        ac([], [], e)
+        assert actfunc_args[0] == 4, actfunc_args
+        assert actfunc_args[1] == '5', actfunc_args
+        assert actfunc_args[2] is e, actfunc_args
         del actfunc_args[:]
-        ac = SCons.Action.ActionCaller(af, [], {'a3' : 6, 'a2' : '$BAR', 'a1' : 4})
-        ac([], [], Environment(BAR = 5))
-        assert actfunc_args == [4, '5', 6], actfunc_args
 
     def test_strfunction(self):
         """Test calling the ActionCaller strfunction() method"""
         strfunc_args = []
-        def actfunc(a1, a2, a3):
+        def actfunc(a1, a2, a3, a4):
             pass
-        def strfunc(a1, a2, a3, args=strfunc_args):
-            args.extend([a1, a2, a3])
+        def strfunc(a1, a2, a3, a4, args=strfunc_args):
+            args.extend([a1, a2, a3, a4])
 
         af = SCons.Action.ActionFactory(actfunc, strfunc)
-        ac = SCons.Action.ActionCaller(af, [1, '$FOO', 3], {})
-        ac.strfunction([], [], Environment(FOO = 2))
-        assert strfunc_args == [1, '2', 3], strfunc_args
+        ac = SCons.Action.ActionCaller(af, [1, '$FOO', 3, '$WS'], {})
+        ac.strfunction([], [], Environment(FOO = 2, WS='white   space'))
+        assert strfunc_args == [1, '2', 3, 'white   space'], strfunc_args
 
         del strfunc_args[:]
-        ac = SCons.Action.ActionCaller(af, [], {'a3' : 6, 'a2' : '$BAR', 'a1' : 4})
-        ac.strfunction([], [], Environment(BAR = 5))
-        assert strfunc_args == [4, '5', 6], strfunc_args
+        d = {'a3' : 6, 'a2' : '$BAR', 'a1' : 4, 'a4' : '$WS'}
+        ac = SCons.Action.ActionCaller(af, [], d)
+        ac.strfunction([], [], Environment(BAR = 5, WS='w   s'))
+        assert strfunc_args == [4, '5', 6, 'w   s'], strfunc_args
 
 class ActionFactoryTestCase(unittest.TestCase):
     def test___init__(self):
@@ -1521,17 +1816,69 @@ class ActionFactoryTestCase(unittest.TestCase):
         assert strfunc_args == [3, 6, 9], strfunc_args
 
 
+class ActionCompareTestCase(unittest.TestCase):
+
+    def test_1_solo_name(self):
+        """Test Lazy Cmd Generator Action get_name alone.
+
+        Basically ensures we can locate the builder, comparing it to
+        itself along the way."""
+        bar = SCons.Builder.Builder(action = {})
+        env = Environment( BUILDERS = {'BAR' : bar} )
+        name = bar.get_name(env)
+        assert name == 'BAR', name
+
+    def test_2_multi_name(self):
+        """Test LazyCmdGenerator Action get_name multi builders.
+
+        Ensure that we can compare builders (and thereby actions) to
+        each other safely."""
+        foo = SCons.Builder.Builder(action = '$FOO', suffix = '.foo')
+        bar = SCons.Builder.Builder(action = {})
+        assert foo != bar
+        assert foo.action != bar.action
+        env = Environment( BUILDERS = {'FOO' : foo,
+                                       'BAR' : bar} )
+        name = foo.get_name(env)
+        assert name == 'FOO', name
+        name = bar.get_name(env)
+        assert name == 'BAR', name
+
+    def test_3_dict_names(self):
+        """Test Action/Suffix dicts with get_name.
+
+        Verifies that Action/Suffix dictionaries work correctly,
+        especially two builders that can generate the same suffix,
+        where one of the builders has a suffix dictionary with a None
+        key."""
+        
+        foo = SCons.Builder.Builder(action = '$FOO', suffix = '.foo')
+        bar = SCons.Builder.Builder(action = {}, suffix={None:'.bar'})
+        bar.add_action('.cow', "$MOO")
+        dog = SCons.Builder.Builder(suffix = '.bar')
+        
+        env = Environment( BUILDERS = {'FOO' : foo,
+                                       'BAR' : bar,
+                                       'DOG' : dog} )
+        
+        assert foo.get_name(env) == 'FOO', foo.get_name(env)
+        assert bar.get_name(env) == 'BAR', bar.get_name(env)
+        assert dog.get_name(env) == 'DOG', dog.get_name(env)
+
+
 if __name__ == "__main__":
     suite = unittest.TestSuite()
     tclasses = [ ActionTestCase,
                  ActionBaseTestCase,
+                 _ActionActionTestCase,
                  CommandActionTestCase,
                  CommandGeneratorActionTestCase,
                  FunctionActionTestCase,
                  ListActionTestCase,
                  LazyActionTestCase,
                  ActionCallerTestCase,
-                 ActionFactoryTestCase ]
+                 ActionFactoryTestCase,
+                 ActionCompareTestCase ]
     for tclass in tclasses:
         names = unittest.getTestCaseNames(tclass, 'test_')
         suite.addTests(map(tclass, names))