Merged revisions 2725-2865 via svnmerge from
[scons.git] / src / engine / SCons / ActionTests.py
1 #
2 # __COPYRIGHT__
3 #
4 # Permission is hereby granted, free of charge, to any person obtaining
5 # a copy of this software and associated documentation files (the
6 # "Software"), to deal in the Software without restriction, including
7 # without limitation the rights to use, copy, modify, merge, publish,
8 # distribute, sublicense, and/or sell copies of the Software, and to
9 # permit persons to whom the Software is furnished to do so, subject to
10 # the following conditions:
11 #
12 # The above copyright notice and this permission notice shall be included
13 # in all copies or substantial portions of the Software.
14 #
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
16 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
17 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 #
23
24 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
25
26 # Define a null function and a null class for use as builder actions.
27 # Where these are defined in the file seems to affect their byte-code
28 # contents, so try to minimize changes by defining them here, before we
29 # even import anything.
30 def GlobalFunc():
31     pass
32
33 class GlobalActFunc:
34     def __call__(self):
35         pass
36
37 import os
38 import re
39 import StringIO
40 import string
41 import sys
42 import types
43 import unittest
44 import UserDict
45
46 import SCons.Action
47 import SCons.Environment
48 import SCons.Errors
49
50 import TestCmd
51
52 # Initial setup of the common environment for all tests,
53 # a temporary working directory containing a
54 # script for writing arguments to an output file.
55 #
56 # We don't do this as a setUp() method because it's
57 # unnecessary to create a separate directory and script
58 # for each test, they can just use the one.
59 test = TestCmd.TestCmd(workdir = '')
60
61 test.write('act.py', """\
62 import os, string, sys
63 f = open(sys.argv[1], 'w')
64 f.write("act.py: '" + string.join(sys.argv[2:], "' '") + "'\\n")
65 try:
66     if sys.argv[3]:
67         f.write("act.py: '" + os.environ[sys.argv[3]] + "'\\n")
68 except:
69     pass
70 f.close()
71 if os.environ.has_key( 'ACTPY_PIPE' ):
72     if os.environ.has_key( 'PIPE_STDOUT_FILE' ):
73          stdout_msg = open(os.environ['PIPE_STDOUT_FILE'], 'r').read()
74     else:
75          stdout_msg = "act.py: stdout: executed act.py %s\\n" % string.join(sys.argv[1:])
76     sys.stdout.write( stdout_msg )
77     if os.environ.has_key( 'PIPE_STDERR_FILE' ):
78          stderr_msg = open(os.environ['PIPE_STDERR_FILE'], 'r').read()
79     else:
80          stderr_msg = "act.py: stderr: executed act.py %s\\n" % string.join(sys.argv[1:])
81     sys.stderr.write( stderr_msg )
82 sys.exit(0)
83 """)
84
85 test.write('exit.py', """\
86 import sys
87 sys.exit(int(sys.argv[1]))
88 """)
89
90 act_py = test.workpath('act.py')
91 exit_py = test.workpath('exit.py')
92
93 outfile = test.workpath('outfile')
94 outfile2 = test.workpath('outfile2')
95 pipe_file = test.workpath('pipe.out')
96
97 scons_env = SCons.Environment.Environment()
98
99 # Capture all the stuff the Actions will print,
100 # so it doesn't clutter the output.
101 sys.stdout = StringIO.StringIO()
102
103 class CmdStringHolder:
104     def __init__(self, cmd, literal=None):
105         self.data = str(cmd)
106         self.literal = literal
107
108     def is_literal(self):
109         return self.literal
110
111     def escape(self, escape_func):
112         """Escape the string with the supplied function.  The
113         function is expected to take an arbitrary string, then
114         return it with all special characters escaped and ready
115         for passing to the command interpreter.
116
117         After calling this function, the next call to str() will
118         return the escaped string.
119         """
120
121         if self.is_literal():
122             return escape_func(self.data)
123         elif ' ' in self.data or '\t' in self.data:
124             return '"%s"' % self.data
125         else:
126             return self.data
127
128 class Environment:
129     def __init__(self, **kw):
130         self.d = {}
131         self.d['SHELL'] = scons_env['SHELL']
132         self.d['SPAWN'] = scons_env['SPAWN']
133         self.d['PSPAWN'] = scons_env['PSPAWN']
134         self.d['ESCAPE'] = scons_env['ESCAPE']
135         for k, v in kw.items():
136             self.d[k] = v
137     # Just use the underlying scons_subst*() utility methods.
138     def subst(self, strSubst, raw=0, target=[], source=[], conv=None):
139         return SCons.Subst.scons_subst(strSubst, self, raw,
140                                        target, source, self.d, conv=conv)
141     subst_target_source = subst
142     def subst_list(self, strSubst, raw=0, target=[], source=[], conv=None):
143         return SCons.Subst.scons_subst_list(strSubst, self, raw,
144                                        target, source, self.d, conv=conv)
145     def __getitem__(self, item):
146         return self.d[item]
147     def __setitem__(self, item, value):
148         self.d[item] = value
149     def has_key(self, item):
150         return self.d.has_key(item)
151     def get(self, key, value=None):
152         return self.d.get(key, value)
153     def items(self):
154         return self.d.items()
155     def Dictionary(self):
156         return self.d
157     def Clone(self, **kw):
158         res = Environment()
159         res.d = SCons.Util.semi_deepcopy(self.d)
160         for k, v in kw.items():
161             res.d[k] = v
162         return res
163     def sig_dict(self):
164         d = {}
165         for k,v in self.items(): d[k] = v
166         d['TARGETS'] = ['__t1__', '__t2__', '__t3__', '__t4__', '__t5__', '__t6__']
167         d['TARGET'] = d['TARGETS'][0]
168         d['SOURCES'] = ['__s1__', '__s2__', '__s3__', '__s4__', '__s5__', '__s6__']
169         d['SOURCE'] = d['SOURCES'][0]
170         return d
171
172 class DummyNode:
173     def __init__(self, name):
174         self.name = name
175     def __str__(self):
176         return self.name
177     def rfile(self):
178         return self
179     def get_subst_proxy(self):
180         return self
181
182 if os.name == 'java':
183     python = os.path.join(sys.prefix, 'jython')
184 else:
185     python = sys.executable
186
187 _python_ = '"' + python + '"'
188
189 class ActionTestCase(unittest.TestCase):
190     """Test the Action() factory function"""
191
192     def test_FunctionAction(self):
193         """Test the Action() factory's creation of FunctionAction objects
194         """
195         def foo():
196             pass
197         def bar():
198             pass
199         a1 = SCons.Action.Action(foo)
200         assert isinstance(a1, SCons.Action.FunctionAction), a1
201         assert a1.execfunction == foo, a1.execfunction
202
203         a11 = SCons.Action.Action(foo, strfunction=bar)
204         assert isinstance(a11, SCons.Action.FunctionAction), a11
205         assert a11.execfunction == foo, a11.execfunction
206         assert a11.strfunction == bar, a11.strfunction
207
208     def test_CommandAction(self):
209         """Test the Action() factory's creation of CommandAction objects
210         """
211         a1 = SCons.Action.Action("string")
212         assert isinstance(a1, SCons.Action.CommandAction), a1
213         assert a1.cmd_list == "string", a1.cmd_list
214
215         if hasattr(types, 'UnicodeType'):
216             exec "a2 = SCons.Action.Action(u'string')"
217             exec "assert isinstance(a2, SCons.Action.CommandAction), a2"
218
219         a3 = SCons.Action.Action(["a3"])
220         assert isinstance(a3, SCons.Action.CommandAction), a3
221         assert a3.cmd_list == "a3", a3.cmd_list
222
223         a4 = SCons.Action.Action([[ "explicit", "command", "line" ]])
224         assert isinstance(a4, SCons.Action.CommandAction), a4
225         assert a4.cmd_list == [ "explicit", "command", "line" ], a4.cmd_list
226
227         def foo():
228             pass
229
230         a5 = SCons.Action.Action("string", strfunction=foo)
231         assert isinstance(a5, SCons.Action.CommandAction), a5
232         assert a5.cmd_list == "string", a5.cmd_list
233         assert a5.strfunction == foo, a5.strfunction
234
235     def test_ListAction(self):
236         """Test the Action() factory's creation of ListAction objects
237         """
238         a1 = SCons.Action.Action(["x", "y", "z", [ "a", "b", "c"]])
239         assert isinstance(a1, SCons.Action.ListAction), a1
240         assert isinstance(a1.list[0], SCons.Action.CommandAction), a1.list[0]
241         assert a1.list[0].cmd_list == "x", a1.list[0].cmd_list
242         assert isinstance(a1.list[1], SCons.Action.CommandAction), a1.list[1]
243         assert a1.list[1].cmd_list == "y", a1.list[1].cmd_list
244         assert isinstance(a1.list[2], SCons.Action.CommandAction), a1.list[2]
245         assert a1.list[2].cmd_list == "z", a1.list[2].cmd_list
246         assert isinstance(a1.list[3], SCons.Action.CommandAction), a1.list[3]
247         assert a1.list[3].cmd_list == [ "a", "b", "c" ], a1.list[3].cmd_list
248
249         a2 = SCons.Action.Action("x\ny\nz")
250         assert isinstance(a2, SCons.Action.ListAction), a2
251         assert isinstance(a2.list[0], SCons.Action.CommandAction), a2.list[0]
252         assert a2.list[0].cmd_list == "x", a2.list[0].cmd_list
253         assert isinstance(a2.list[1], SCons.Action.CommandAction), a2.list[1]
254         assert a2.list[1].cmd_list == "y", a2.list[1].cmd_list
255         assert isinstance(a2.list[2], SCons.Action.CommandAction), a2.list[2]
256         assert a2.list[2].cmd_list == "z", a2.list[2].cmd_list
257
258         def foo():
259             pass
260
261         a3 = SCons.Action.Action(["x", foo, "z"])
262         assert isinstance(a3, SCons.Action.ListAction), a3
263         assert isinstance(a3.list[0], SCons.Action.CommandAction), a3.list[0]
264         assert a3.list[0].cmd_list == "x", a3.list[0].cmd_list
265         assert isinstance(a3.list[1], SCons.Action.FunctionAction), a3.list[1]
266         assert a3.list[1].execfunction == foo, a3.list[1].execfunction
267         assert isinstance(a3.list[2], SCons.Action.CommandAction), a3.list[2]
268         assert a3.list[2].cmd_list == "z", a3.list[2].cmd_list
269
270         a4 = SCons.Action.Action(["x", "y"], strfunction=foo)
271         assert isinstance(a4, SCons.Action.ListAction), a4
272         assert isinstance(a4.list[0], SCons.Action.CommandAction), a4.list[0]
273         assert a4.list[0].cmd_list == "x", a4.list[0].cmd_list
274         assert a4.list[0].strfunction == foo, a4.list[0].strfunction
275         assert isinstance(a4.list[1], SCons.Action.CommandAction), a4.list[1]
276         assert a4.list[1].cmd_list == "y", a4.list[1].cmd_list
277         assert a4.list[1].strfunction == foo, a4.list[1].strfunction
278
279         a5 = SCons.Action.Action("x\ny", strfunction=foo)
280         assert isinstance(a5, SCons.Action.ListAction), a5
281         assert isinstance(a5.list[0], SCons.Action.CommandAction), a5.list[0]
282         assert a5.list[0].cmd_list == "x", a5.list[0].cmd_list
283         assert a5.list[0].strfunction == foo, a5.list[0].strfunction
284         assert isinstance(a5.list[1], SCons.Action.CommandAction), a5.list[1]
285         assert a5.list[1].cmd_list == "y", a5.list[1].cmd_list
286         assert a5.list[1].strfunction == foo, a5.list[1].strfunction
287
288     def test_CommandGeneratorAction(self):
289         """Test the Action() factory's creation of CommandGeneratorAction objects
290         """
291         def foo():
292             pass
293         def bar():
294             pass
295         a1 = SCons.Action.Action(foo, generator=1)
296         assert isinstance(a1, SCons.Action.CommandGeneratorAction), a1
297         assert a1.generator is foo, a1.generator
298
299         a2 = SCons.Action.Action(foo, strfunction=bar, generator=1)
300         assert isinstance(a2, SCons.Action.CommandGeneratorAction), a2
301         assert a2.generator is foo, a2.generator
302
303     def test_LazyCmdGeneratorAction(self):
304         """Test the Action() factory's creation of lazy CommandGeneratorAction objects
305         """
306         def foo():
307             pass
308
309         a1 = SCons.Action.Action("$FOO")
310         assert isinstance(a1, SCons.Action.LazyAction), a1
311
312         a2 = SCons.Action.Action("$FOO", strfunction=foo)
313         assert isinstance(a2, SCons.Action.LazyAction), a2
314
315     def test_no_action(self):
316         """Test when the Action() factory can't create an action object
317         """
318         a5 = SCons.Action.Action(1)
319         assert a5 is None, a5
320
321     def test_reentrance(self):
322         """Test the Action() factory when the action is already an Action object
323         """
324         a1 = SCons.Action.Action("foo")
325         a2 = SCons.Action.Action(a1)
326         assert a2 is a1, a2
327
328 class ActionBaseTestCase(unittest.TestCase):
329     def test_get_executor(self):
330         """Test the ActionBase.get_executor() method"""
331         a = SCons.Action.Action('foo')
332         x = a.get_executor({}, {}, [], [], {})
333         assert not x is None, x
334  
335 class _ActionActionTestCase(unittest.TestCase):
336
337     def test__init__(self):
338         """Test creation of _ActionAction objects
339         """
340
341         def func1():
342             pass
343
344         def func2():
345             pass
346
347         a = SCons.Action._ActionAction()
348         assert not hasattr(a, 'strfunction')
349
350         assert SCons.Action._ActionAction(kwarg = 1)
351         assert not hasattr(a, 'strfunction')
352         assert not hasattr(a, 'kwarg')
353
354         a = SCons.Action._ActionAction(strfunction=func1)
355         assert a.strfunction is func1, a.strfunction
356
357         a = SCons.Action._ActionAction(presub=func1)
358         assert a.presub is func1, a.presub
359
360         a = SCons.Action._ActionAction(chdir=1)
361         assert a.chdir is 1, a.chdir
362
363         a = SCons.Action._ActionAction(func1, func2, 'x')
364         assert a.strfunction is func1, a.strfunction
365         assert a.presub is func2, a.presub
366         assert a.chdir is 'x', a.chdir
367
368     def test___cmp__(self):
369         """Test Action comparison
370         """
371         a1 = SCons.Action.Action("x")
372         a2 = SCons.Action.Action("x")
373         assert a1 == a2
374         a3 = SCons.Action.Action("y")
375         assert a1 != a3
376         assert a2 != a3
377
378     def test_print_cmd_lines(self):
379         """Test the print_cmd_lines() method
380         """
381         save_stdout = sys.stdout
382
383         try:
384             def execfunc(target, source, env):
385                 pass
386             a = SCons.Action.Action(execfunc)
387
388             sio = StringIO.StringIO()
389             sys.stdout = sio
390             a.print_cmd_line("foo bar", None, None, None)
391             s = sio.getvalue()
392             assert s == "foo bar\n", s
393
394         finally:
395             sys.stdout = save_stdout
396
397     def test___call__(self):
398         """Test calling an Action
399         """
400         save_stdout = sys.stdout
401
402         save_print_actions = SCons.Action.print_actions
403         save_print_actions_presub = SCons.Action.print_actions_presub
404         save_execute_actions = SCons.Action.execute_actions
405         #SCons.Action.print_actions = 0
406
407         test = TestCmd.TestCmd(workdir = '')
408         test.subdir('sub', 'xyz')
409         os.chdir(test.workpath())
410
411         try:
412             env = Environment()
413
414             def execfunc(target, source, env):
415                 assert type(target) is type([]), type(target)
416                 assert type(source) is type([]), type(source)
417                 return 7
418             a = SCons.Action.Action(execfunc)
419
420             def firstfunc(target, source, env):
421                 assert type(target) is type([]), type(target)
422                 assert type(source) is type([]), type(source)
423                 return 0
424             def lastfunc(target, source, env):
425                 assert type(target) is type([]), type(target)
426                 assert type(source) is type([]), type(source)
427                 return 9
428             b = SCons.Action.Action([firstfunc, execfunc, lastfunc])
429             
430             sio = StringIO.StringIO()
431             sys.stdout = sio
432             result = a("out", "in", env)
433             assert result.status == 7, result
434             s = sio.getvalue()
435             assert s == 'execfunc(["out"], ["in"])\n', s
436
437             a.chdir = 'xyz'
438             expect = 'os.chdir(%s)\nexecfunc(["out"], ["in"])\nos.chdir(%s)\n'
439
440             sio = StringIO.StringIO()
441             sys.stdout = sio
442             result = a("out", "in", env)
443             assert result.status == 7, result.status
444             s = sio.getvalue()
445             assert s == expect % (repr('xyz'), repr(test.workpath())), s
446
447             sio = StringIO.StringIO()
448             sys.stdout = sio
449             result = a("out", "in", env, chdir='sub')
450             assert result.status == 7, result.status
451             s = sio.getvalue()
452             assert s == expect % (repr('sub'), repr(test.workpath())), s
453
454             a.chdir = None
455
456             sio = StringIO.StringIO()
457             sys.stdout = sio
458             result = b("out", "in", env)
459             assert result.status == 7, result.status
460             s = sio.getvalue()
461             assert s == 'firstfunc(["out"], ["in"])\nexecfunc(["out"], ["in"])\n', s
462
463             SCons.Action.execute_actions = 0
464
465             sio = StringIO.StringIO()
466             sys.stdout = sio
467             result = a("out", "in", env)
468             assert result == 0, result
469             s = sio.getvalue()
470             assert s == 'execfunc(["out"], ["in"])\n', s
471
472             sio = StringIO.StringIO()
473             sys.stdout = sio
474             result = b("out", "in", env)
475             assert result == 0, result
476             s = sio.getvalue()
477             assert s == 'firstfunc(["out"], ["in"])\nexecfunc(["out"], ["in"])\nlastfunc(["out"], ["in"])\n', s
478
479             SCons.Action.print_actions_presub = 1
480             SCons.Action.execute_actions = 1
481
482             sio = StringIO.StringIO()
483             sys.stdout = sio
484             result = a("out", "in", env)
485             assert result.status == 7, result.status
486             s = sio.getvalue()
487             assert s == 'Building out with action:\n  execfunc(target, source, env)\nexecfunc(["out"], ["in"])\n', s
488
489             sio = StringIO.StringIO()
490             sys.stdout = sio
491             result = a("out", "in", env, presub=0)
492             assert result.status == 7, result.status
493             s = sio.getvalue()
494             assert s == 'execfunc(["out"], ["in"])\n', s
495
496             sio = StringIO.StringIO()
497             sys.stdout = sio
498             result = a("out", "in", env, presub=1)
499             assert result.status == 7, result.status
500             s = sio.getvalue()
501             assert s == 'Building out with action:\n  execfunc(target, source, env)\nexecfunc(["out"], ["in"])\n', s
502
503             sio = StringIO.StringIO()
504             sys.stdout = sio
505             result = b(["out"], "in", env, presub=1)
506             assert result.status == 7, result.status
507             s = sio.getvalue()
508             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
509
510             sio = StringIO.StringIO()
511             sys.stdout = sio
512             result = b(["out", "list"], "in", env, presub=1)
513             assert result.status == 7, result.status
514             s = sio.getvalue()
515             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
516
517             a2 = SCons.Action.Action(execfunc)
518
519             sio = StringIO.StringIO()
520             sys.stdout = sio
521             result = a2("out", "in", env)
522             assert result.status == 7, result.status
523             s = sio.getvalue()
524             assert s == 'Building out with action:\n  execfunc(target, source, env)\nexecfunc(["out"], ["in"])\n', s
525
526             sio = StringIO.StringIO()
527             sys.stdout = sio
528             result = a2("out", "in", env, presub=0)
529             assert result.status == 7, result.status
530             s = sio.getvalue()
531             assert s == 'execfunc(["out"], ["in"])\n', s
532
533             SCons.Action.execute_actions = 0
534
535             sio = StringIO.StringIO()
536             sys.stdout = sio
537             result = a2("out", "in", env, presub=0)
538             assert result == 0, result
539             s = sio.getvalue()
540             assert s == 'execfunc(["out"], ["in"])\n', s
541
542             sio = StringIO.StringIO()
543             sys.stdout = sio
544             result = a("out", "in", env, presub=0, execute=1, show=0)
545             assert result.status == 7, result.status
546             s = sio.getvalue()
547             assert s == '', s
548
549             sys.stdout = save_stdout
550             exitstatfunc_result = []
551
552             def exitstatfunc(stat, result=exitstatfunc_result):
553                 result.append(stat)
554                 return stat
555
556             result = a("out", "in", env, exitstatfunc=exitstatfunc)
557             assert result == 0, result
558             assert exitstatfunc_result == [], exitstatfunc_result
559
560             result = a("out", "in", env, execute=1, exitstatfunc=exitstatfunc)
561             assert result.status == 7, result.status
562             assert exitstatfunc_result == [7], exitstatfunc_result
563
564             SCons.Action.execute_actions = 1
565
566             result = []
567             def my_print_cmd_line(s, target, source, env, result=result):
568                 result.append(s)
569             env['PRINT_CMD_LINE_FUNC'] = my_print_cmd_line
570             a("output", "input", env)
571             assert result == ['execfunc(["output"], ["input"])'], result
572             
573
574         finally:
575             sys.stdout = save_stdout
576             SCons.Action.print_actions = save_print_actions
577             SCons.Action.print_actions_presub = save_print_actions_presub
578             SCons.Action.execute_actions = save_execute_actions
579
580     def test_presub_lines(self):
581         """Test the presub_lines() method
582         """
583         env = Environment()
584         a = SCons.Action.Action("x")
585         s = a.presub_lines(env)
586         assert s == ['x'], s
587
588         a = SCons.Action.Action(["y", "z"])
589         s = a.presub_lines(env)
590         assert s == ['y', 'z'], s
591
592         def func():
593             pass
594         a = SCons.Action.Action(func)
595         s = a.presub_lines(env)
596         assert s == ["func(target, source, env)"], s
597
598         def gen(target, source, env, for_signature):
599             return 'generat' + env.get('GEN', 'or')
600         a = SCons.Action.Action(gen, generator=1)
601         s = a.presub_lines(env)
602         assert s == ["generator"], s
603         s = a.presub_lines(Environment(GEN = 'ed'))
604         assert s == ["generated"], s
605
606         a = SCons.Action.Action("$ACT")
607         s = a.presub_lines(env)
608         assert s == [''], s
609         s = a.presub_lines(Environment(ACT = 'expanded action'))
610         assert s == ['expanded action'], s
611
612     def test_add(self):
613         """Test adding Actions to stuff."""
614         # Adding actions to other Actions or to stuff that can
615         # be converted into an Action should produce a ListAction
616         # containing all the Actions.
617         def bar():
618             return None
619         baz = SCons.Action.Action(bar, generator=1)
620         act1 = SCons.Action.Action('foo bar')
621         act2 = SCons.Action.Action([ 'foo', bar ])
622
623         sum = act1 + act2
624         assert isinstance(sum, SCons.Action.ListAction), str(sum)
625         assert len(sum.list) == 3, len(sum.list)
626         assert map(lambda x: isinstance(x, SCons.Action.ActionBase),
627                    sum.list) == [ 1, 1, 1 ]
628
629         sum = act1 + act1
630         assert isinstance(sum, SCons.Action.ListAction), str(sum)
631         assert len(sum.list) == 2, len(sum.list)
632
633         sum = act2 + act2
634         assert isinstance(sum, SCons.Action.ListAction), str(sum)
635         assert len(sum.list) == 4, len(sum.list)
636
637         # Should also be able to add command generators to each other
638         # or to actions
639         sum = baz + baz
640         assert isinstance(sum, SCons.Action.ListAction), str(sum)
641         assert len(sum.list) == 2, len(sum.list)
642
643         sum = baz + act1
644         assert isinstance(sum, SCons.Action.ListAction), str(sum)
645         assert len(sum.list) == 2, len(sum.list)
646
647         sum = act2 + baz
648         assert isinstance(sum, SCons.Action.ListAction), str(sum)
649         assert len(sum.list) == 3, len(sum.list)
650
651         # Also should be able to add Actions to anything that can
652         # be converted into an action.
653         sum = act1 + bar
654         assert isinstance(sum, SCons.Action.ListAction), str(sum)
655         assert len(sum.list) == 2, len(sum.list)
656         assert isinstance(sum.list[1], SCons.Action.FunctionAction)
657
658         sum = 'foo bar' + act2
659         assert isinstance(sum, SCons.Action.ListAction), str(sum)
660         assert len(sum.list) == 3, len(sum.list)
661         assert isinstance(sum.list[0], SCons.Action.CommandAction)
662
663         sum = [ 'foo', 'bar' ] + act1
664         assert isinstance(sum, SCons.Action.ListAction), str(sum)
665         assert len(sum.list) == 3, sum.list
666         assert isinstance(sum.list[0], SCons.Action.CommandAction)
667         assert isinstance(sum.list[1], SCons.Action.CommandAction)
668
669         sum = act2 + [ baz, bar ]
670         assert isinstance(sum, SCons.Action.ListAction), str(sum)
671         assert len(sum.list) == 4, len(sum.list)
672         assert isinstance(sum.list[2], SCons.Action.CommandGeneratorAction)
673         assert isinstance(sum.list[3], SCons.Action.FunctionAction)
674
675         try:
676             sum = act2 + 1
677         except TypeError:
678             pass
679         else:
680             assert 0, "Should have thrown a TypeError adding to an int."
681
682         try:
683             sum = 1 + act2
684         except TypeError:
685             pass
686         else:
687             assert 0, "Should have thrown a TypeError adding to an int."
688
689 class CommandActionTestCase(unittest.TestCase):
690
691     def test___init__(self):
692         """Test creation of a command Action
693         """
694         a = SCons.Action.CommandAction(["xyzzy"])
695         assert a.cmd_list == [ "xyzzy" ], a.cmd_list
696         assert a.cmdstr is None, a.cmdstr
697
698         a = SCons.Action.CommandAction(["abra"], "cadabra")
699         assert a.cmd_list == [ "abra" ], a.cmd_list
700         assert a.cmdstr == "cadabra", a.cmdstr
701
702     def test_bad_cmdstr(self):
703         """Test handling of bad CommandAction(cmdstr) arguments
704         """
705         try:
706             a = SCons.Action.CommandAction('foo', [])
707         except SCons.Errors.UserError, e:
708             s = str(e)
709             m = 'Invalid command display variable'
710             assert string.find(s, m) != -1, 'Unexpected string:  %s' % s
711         else:
712             raise Exception, "did not catch expected UserError"
713
714     def test___str__(self):
715         """Test fetching the pre-substitution string for command Actions
716         """
717         env = Environment()
718         act = SCons.Action.CommandAction('xyzzy $TARGET $SOURCE')
719         s = str(act)
720         assert s == 'xyzzy $TARGET $SOURCE', s
721
722         act = SCons.Action.CommandAction(['xyzzy',
723                                           '$TARGET', '$SOURCE',
724                                           '$TARGETS', '$SOURCES'])
725         s = str(act)
726         assert s == "xyzzy $TARGET $SOURCE $TARGETS $SOURCES", s
727
728     def test_genstring(self):
729         """Test the genstring() method for command Actions
730         """
731
732         env = Environment()
733         t1 = DummyNode('t1')
734         t2 = DummyNode('t2')
735         s1 = DummyNode('s1')
736         s2 = DummyNode('s2')
737         act = SCons.Action.CommandAction('xyzzy $TARGET $SOURCE')
738         expect = 'xyzzy $TARGET $SOURCE'
739         s = act.genstring([], [], env)
740         assert s == expect, s
741         s = act.genstring([t1], [s1], env)
742         assert s == expect, s
743         s = act.genstring([t1, t2], [s1, s2], env)
744         assert s == expect, s
745
746         act = SCons.Action.CommandAction('xyzzy $TARGETS $SOURCES')
747         expect = 'xyzzy $TARGETS $SOURCES'
748         s = act.genstring([], [], env)
749         assert s == expect, s
750         s = act.genstring([t1], [s1], env)
751         assert s == expect, s
752         s = act.genstring([t1, t2], [s1, s2], env)
753         assert s == expect, s
754
755         act = SCons.Action.CommandAction(['xyzzy',
756                                           '$TARGET', '$SOURCE',
757                                           '$TARGETS', '$SOURCES'])
758         expect = "xyzzy $TARGET $SOURCE $TARGETS $SOURCES"
759         s = act.genstring([], [], env)
760         assert s == expect, s
761         s = act.genstring([t1], [s1], env)
762         assert s == expect, s
763         s = act.genstring([t1, t2], [s1, s2], env)
764         assert s == expect, s
765
766     def test_strfunction(self):
767         """Test fetching the string representation of command Actions
768         """
769
770         env = Environment()
771         t1 = DummyNode('t1')
772         t2 = DummyNode('t2')
773         s1 = DummyNode('s1')
774         s2 = DummyNode('s2')
775         act = SCons.Action.CommandAction('xyzzy $TARGET $SOURCE')
776         s = act.strfunction([], [], env)
777         assert s == 'xyzzy', s
778         s = act.strfunction([t1], [s1], env)
779         assert s == 'xyzzy t1 s1', s
780         s = act.strfunction([t1, t2], [s1, s2], env)
781         assert s == 'xyzzy t1 s1', s
782
783         act = SCons.Action.CommandAction('xyzzy $TARGET $SOURCE',
784                                          'cmdstr - $SOURCE - $TARGET -')
785         s = act.strfunction([], [], env)
786         assert s == 'cmdstr -  -  -', s
787         s = act.strfunction([t1], [s1], env)
788         assert s == 'cmdstr - s1 - t1 -', s
789         s = act.strfunction([t1, t2], [s1, s2], env)
790         assert s == 'cmdstr - s1 - t1 -', s
791
792         act = SCons.Action.CommandAction('xyzzy $TARGETS $SOURCES')
793         s = act.strfunction([], [], env)
794         assert s == 'xyzzy', s
795         s = act.strfunction([t1], [s1], env)
796         assert s == 'xyzzy t1 s1', s
797         s = act.strfunction([t1, t2], [s1, s2], env)
798         assert s == 'xyzzy t1 t2 s1 s2', s
799
800         act = SCons.Action.CommandAction('xyzzy $TARGETS $SOURCES',
801                                          'cmdstr = $SOURCES = $TARGETS =')
802         s = act.strfunction([], [], env)
803         assert s == 'cmdstr =  =  =', s
804         s = act.strfunction([t1], [s1], env)
805         assert s == 'cmdstr = s1 = t1 =', s
806         s = act.strfunction([t1, t2], [s1, s2], env)
807         assert s == 'cmdstr = s1 s2 = t1 t2 =', s
808
809         act = SCons.Action.CommandAction(['xyzzy',
810                                           '$TARGET', '$SOURCE',
811                                           '$TARGETS', '$SOURCES'])
812         s = act.strfunction([], [], env)
813         assert s == 'xyzzy', s
814         s = act.strfunction([t1], [s1], env)
815         assert s == 'xyzzy t1 s1 t1 s1', s
816         s = act.strfunction([t1, t2], [s1, s2], env)
817         assert s == 'xyzzy t1 s1 t1 t2 s1 s2', s
818
819         act = SCons.Action.CommandAction('xyzzy $TARGETS $SOURCES',
820                                          'cmdstr\t$TARGETS\n$SOURCES   ')
821                     
822         s = act.strfunction([], [], env)
823         assert s == 'cmdstr\t\n   ', s
824         s = act.strfunction([t1], [s1], env)
825         assert s == 'cmdstr\tt1\ns1   ', s
826         s = act.strfunction([t1, t2], [s1, s2], env)
827         assert s == 'cmdstr\tt1 t2\ns1 s2   ', s
828
829         def sf(target, source, env):
830             return "sf was called"
831         act = SCons.Action.CommandAction('foo', strfunction=sf)
832         s = act.strfunction([], [], env)
833         assert s == "sf was called", s
834
835         class actclass1:
836             def __init__(self, targets, sources, env):
837                 pass
838             def __call__(self):
839                 return 1
840         class actclass2:
841             def __init__(self, targets, sources, env):
842                 self.strfunction = 5
843             def __call__(self):
844                 return 2
845         class actclass3:
846             def __init__(self, targets, sources, env):
847                 pass
848             def __call__(self):
849                 return 3
850             def strfunction(self, targets, sources, env):
851                 return 'actclass3 on %s to get %s'%(str(sources[0]),
852                                                     str(targets[0]))
853         class actclass4:
854             def __init__(self, targets, sources, env):
855                 pass
856             def __call__(self):
857                 return 4
858             strfunction = None
859
860         act1 = SCons.Action.Action(actclass1([t1], [s1], env))
861         s = act1.strfunction([t1], [s1], env)
862         assert s == 'actclass1(["t1"], ["s1"])', s
863
864         act2 = SCons.Action.Action(actclass2([t1], [s1], env))
865         s = act2.strfunction([t1], [s1], env)
866         assert s == 'actclass2(["t1"], ["s1"])', s
867
868         act3 = SCons.Action.Action(actclass3([t1], [s1], env))
869         s = act3.strfunction([t1], [s1], env)
870         assert s == 'actclass3 on s1 to get t1', s
871
872         act4 = SCons.Action.Action(actclass4([t1], [s1], env))
873         s = act4.strfunction([t1], [s1], env)
874         assert s is None, s
875
876         act = SCons.Action.CommandAction("@foo bar")
877         s = act.strfunction([], [], env)
878         assert s == "", s
879
880         act = SCons.Action.CommandAction("@-foo bar")
881         s = act.strfunction([], [], env)
882         assert s == "", s
883
884         act = SCons.Action.CommandAction("-@foo bar")
885         s = act.strfunction([], [], env)
886         assert s == "", s
887
888         act = SCons.Action.CommandAction("-foo bar")
889         s = act.strfunction([], [], env)
890         assert s == "foo bar", s
891
892         act = SCons.Action.CommandAction("@ foo bar")
893         s = act.strfunction([], [], env)
894         assert s == "", s
895
896         act = SCons.Action.CommandAction("@- foo bar")
897         s = act.strfunction([], [], env)
898         assert s == "", s
899
900         act = SCons.Action.CommandAction("-@ foo bar")
901         s = act.strfunction([], [], env)
902         assert s == "", s
903
904         act = SCons.Action.CommandAction("- foo bar")
905         s = act.strfunction([], [], env)
906         assert s == "foo bar", s
907
908     def test_execute(self):
909         """Test execution of command Actions
910
911         """
912         try:
913             env = self.env
914         except AttributeError:
915             env = Environment()
916
917         cmd1 = r'%s %s %s xyzzy' % (_python_, act_py, outfile)
918
919         act = SCons.Action.CommandAction(cmd1)
920         r = act([], [], env.Clone())
921         assert r == 0
922         c = test.read(outfile, 'r')
923         assert c == "act.py: 'xyzzy'\n", c
924
925         cmd2 = r'%s %s %s $TARGET' % (_python_, act_py, outfile)
926
927         act = SCons.Action.CommandAction(cmd2)
928         r = act(DummyNode('foo'), [], env.Clone())
929         assert r == 0
930         c = test.read(outfile, 'r')
931         assert c == "act.py: 'foo'\n", c
932
933         cmd3 = r'%s %s %s ${TARGETS}' % (_python_, act_py, outfile)
934
935         act = SCons.Action.CommandAction(cmd3)
936         r = act(map(DummyNode, ['aaa', 'bbb']), [], env.Clone())
937         assert r == 0
938         c = test.read(outfile, 'r')
939         assert c == "act.py: 'aaa' 'bbb'\n", c
940
941         cmd4 = r'%s %s %s $SOURCES' % (_python_, act_py, outfile)
942
943         act = SCons.Action.CommandAction(cmd4)
944         r = act([], [DummyNode('one'), DummyNode('two')], env.Clone())
945         assert r == 0
946         c = test.read(outfile, 'r')
947         assert c == "act.py: 'one' 'two'\n", c
948
949         cmd4 = r'%s %s %s ${SOURCES[:2]}' % (_python_, act_py, outfile)
950
951         act = SCons.Action.CommandAction(cmd4)
952         sources = [DummyNode('three'), DummyNode('four'), DummyNode('five')]
953         env2 = env.Clone()
954         r = act([], source = sources, env = env2)
955         assert r == 0
956         c = test.read(outfile, 'r')
957         assert c == "act.py: 'three' 'four'\n", c
958
959         cmd5 = r'%s %s %s $TARGET XYZZY' % (_python_, act_py, outfile)
960
961         act = SCons.Action.CommandAction(cmd5)
962         env5 = Environment()
963         if scons_env.has_key('ENV'):
964             env5['ENV'] = scons_env['ENV']
965             PATH = scons_env['ENV'].get('PATH', '')
966         else:
967             env5['ENV'] = {}
968             PATH = ''
969
970         env5['ENV']['XYZZY'] = 'xyzzy'
971         r = act(target = DummyNode('out5'), source = [], env = env5)
972
973         act = SCons.Action.CommandAction(cmd5)
974         r = act(target = DummyNode('out5'),
975                 source = [],
976                 env = env.Clone(ENV = {'XYZZY' : 'xyzzy5',
977                                       'PATH' : PATH}))
978         assert r == 0
979         c = test.read(outfile, 'r')
980         assert c == "act.py: 'out5' 'XYZZY'\nact.py: 'xyzzy5'\n", c
981
982         class Obj:
983             def __init__(self, str):
984                 self._str = str
985             def __str__(self):
986                 return self._str
987             def rfile(self):
988                 return self
989             def get_subst_proxy(self):
990                 return self
991
992         cmd6 = r'%s %s %s ${TARGETS[1]} $TARGET ${SOURCES[:2]}' % (_python_, act_py, outfile)
993
994         act = SCons.Action.CommandAction(cmd6)
995         r = act(target = [Obj('111'), Obj('222')],
996                         source = [Obj('333'), Obj('444'), Obj('555')],
997                         env = env.Clone())
998         assert r == 0
999         c = test.read(outfile, 'r')
1000         assert c == "act.py: '222' '111' '333' '444'\n", c
1001
1002         if os.name == 'nt':
1003             # NT treats execs of directories and non-executable files
1004             # as "file not found" errors
1005             expect_nonexistent = 1
1006             expect_nonexecutable = 1
1007         elif sys.platform == 'cygwin':
1008             expect_nonexistent = 127
1009             # Newer cygwin seems to return 126 for following
1010             expect_nonexecutable_file = 126
1011             expect_nonexecutable_dir  = 127
1012         else:
1013             expect_nonexistent = 127
1014             expect_nonexecutable_file = 126
1015             expect_nonexecutable_dir  = 126
1016
1017         # Test that a nonexistent command returns 127
1018         act = SCons.Action.CommandAction(python + "_no_such_command_")
1019         r = act([], [], env.Clone(out = outfile))
1020         assert r.status == expect_nonexistent, r.status
1021
1022         # Test that trying to execute a directory returns 126
1023         dir, tail = os.path.split(python)
1024         act = SCons.Action.CommandAction(dir)
1025         r = act([], [], env.Clone(out = outfile))
1026         assert r.status == expect_nonexecutable_file, r.status
1027
1028         # Test that trying to execute a non-executable file returns 126
1029         act = SCons.Action.CommandAction(outfile)
1030         r = act([], [], env.Clone(out = outfile))
1031         assert r.status == expect_nonexecutable_dir, r.status
1032
1033         act = SCons.Action.CommandAction('%s %s 1' % (_python_, exit_py))
1034         r = act([], [], env)
1035         assert r.status == 1, r.status
1036
1037         act = SCons.Action.CommandAction('@%s %s 1' % (_python_, exit_py))
1038         r = act([], [], env)
1039         assert r.status == 1, r.status
1040
1041         act = SCons.Action.CommandAction('@-%s %s 1' % (_python_, exit_py))
1042         r = act([], [], env)
1043         assert r == 0, r
1044
1045         act = SCons.Action.CommandAction('-%s %s 1' % (_python_, exit_py))
1046         r = act([], [], env)
1047         assert r == 0, r
1048
1049         act = SCons.Action.CommandAction('@ %s %s 1' % (_python_, exit_py))
1050         r = act([], [], env)
1051         assert r.status == 1, r.status
1052
1053         act = SCons.Action.CommandAction('@- %s %s 1' % (_python_, exit_py))
1054         r = act([], [], env)
1055         assert r == 0, r
1056
1057         act = SCons.Action.CommandAction('- %s %s 1' % (_python_, exit_py))
1058         r = act([], [], env)
1059         assert r == 0, r
1060
1061     def _DO_NOT_EXECUTE_test_pipe_execute(self):
1062         """Test capturing piped output from an action
1063
1064         We used to have PIPE_BUILD support built right into
1065         Action.execute() for the benefit of the SConf subsystem, but we've
1066         moved that logic back into SConf itself.  We'll leave this code
1067         here, just in case we ever want to resurrect this functionality
1068         in the future, but change the name of the test so it doesn't
1069         get executed as part of the normal test suite.
1070         """
1071         pipe = open( pipe_file, "w" )
1072         self.env = Environment(ENV = {'ACTPY_PIPE' : '1'}, PIPE_BUILD = 1,
1073                                PSTDOUT = pipe, PSTDERR = pipe)
1074         # everything should also work when piping output
1075         self.test_execute()
1076         self.env['PSTDOUT'].close()
1077         pipe_out = test.read( pipe_file )
1078
1079         act_out = "act.py: stdout: executed act.py"
1080         act_err = "act.py: stderr: executed act.py"
1081
1082         # Since we are now using select(), stdout and stderr can be
1083         # intermixed, so count the lines separately.
1084         outlines = re.findall(act_out, pipe_out)
1085         errlines = re.findall(act_err, pipe_out)
1086         assert len(outlines) == 6, pipe_out + repr(outlines)
1087         assert len(errlines) == 6, pipe_out + repr(errlines)
1088
1089         # test redirection operators
1090         def test_redirect(self, redir, stdout_msg, stderr_msg):
1091             cmd = r'%s %s %s xyzzy %s' % (_python_, act_py, outfile, redir)
1092             # Write the output and error messages to files because
1093             # Windows can't handle strings that are too big in its
1094             # external environment (os.spawnve() returns EINVAL,
1095             # "Invalid argument").
1096             stdout_file = test.workpath('stdout_msg')
1097             stderr_file = test.workpath('stderr_msg')
1098             open(stdout_file, 'w').write(stdout_msg)
1099             open(stderr_file, 'w').write(stderr_msg)
1100             pipe = open( pipe_file, "w" )
1101             act = SCons.Action.CommandAction(cmd)
1102             env = Environment( ENV = {'ACTPY_PIPE' : '1',
1103                                       'PIPE_STDOUT_FILE' : stdout_file,
1104                                       'PIPE_STDERR_FILE' : stderr_file},
1105                                PIPE_BUILD = 1,
1106                                PSTDOUT = pipe, PSTDERR = pipe )
1107             r = act([], [], env)
1108             pipe.close()
1109             assert r == 0
1110             return (test.read(outfile2, 'r'), test.read(pipe_file, 'r'))
1111
1112         (redirected, pipe_out) = test_redirect(self,'> %s' % outfile2,
1113                                                act_out, act_err)
1114         assert redirected == act_out
1115         assert pipe_out == act_err
1116
1117         (redirected, pipe_out) = test_redirect(self,'2> %s' % outfile2,
1118                                                act_out, act_err)
1119         assert redirected == act_err
1120         assert pipe_out == act_out
1121
1122         (redirected, pipe_out) = test_redirect(self,'> %s 2>&1' % outfile2,
1123                                                act_out, act_err)
1124         assert (redirected == act_out + act_err or
1125                 redirected == act_err + act_out)
1126         assert pipe_out == ""
1127
1128         act_err = "Long Command Output\n"*3000
1129         # the size of the string should exceed the system's default block size
1130         act_out = ""
1131         (redirected, pipe_out) = test_redirect(self,'> %s' % outfile2,
1132                                                act_out, act_err)
1133         assert (redirected == act_out)
1134         assert (pipe_out == act_err)
1135
1136     def test_set_handler(self):
1137         """Test setting the command handler...
1138         """
1139         class Test:
1140             def __init__(self):
1141                 self.executed = 0
1142         t=Test()
1143         def func(sh, escape, cmd, args, env, test=t):
1144             test.executed = args
1145             test.shell = sh
1146             return 0
1147         def escape_func(cmd):
1148             return '**' + cmd + '**'
1149
1150         class LiteralStr:
1151             def __init__(self, x):
1152                 self.data = x
1153             def __str__(self):
1154                 return self.data
1155             def escape(self, escape_func):
1156                 return escape_func(self.data)
1157             def is_literal(self):
1158                 return 1
1159
1160         a = SCons.Action.CommandAction(["xyzzy"])
1161         e = Environment(SPAWN = func)
1162         a([], [], e)
1163         assert t.executed == [ 'xyzzy' ], t.executed
1164
1165         a = SCons.Action.CommandAction(["xyzzy"])
1166         e = Environment(SPAWN = '$FUNC', FUNC = func)
1167         a([], [], e)
1168         assert t.executed == [ 'xyzzy' ], t.executed
1169
1170         a = SCons.Action.CommandAction(["xyzzy"])
1171         e = Environment(SPAWN = func, SHELL = 'fake shell')
1172         a([], [], e)
1173         assert t.executed == [ 'xyzzy' ], t.executed
1174         assert t.shell == 'fake shell', t.shell
1175
1176         a = SCons.Action.CommandAction([ LiteralStr("xyzzy") ])
1177         e = Environment(SPAWN = func, ESCAPE = escape_func)
1178         a([], [], e)
1179         assert t.executed == [ '**xyzzy**' ], t.executed
1180
1181     def test_get_contents(self):
1182         """Test fetching the contents of a command Action
1183         """
1184         def CmdGen(target, source, env, for_signature):
1185             assert for_signature
1186             return "%s %s" % \
1187                    (env["foo"], env["bar"])
1188
1189         # The number 1 is there to make sure all args get converted to strings.
1190         a = SCons.Action.CommandAction(["|", "$(", "$foo", "|", "$bar",
1191                                         "$)", "|", "$baz", 1])
1192         c = a.get_contents(target=[], source=[],
1193                            env=Environment(foo = 'FFF', bar = 'BBB',
1194                                            baz = CmdGen))
1195         assert c == "| | FFF BBB 1", c
1196
1197         # Make sure that CommandActions use an Environment's
1198         # subst_target_source() method for substitution.
1199         class SpecialEnvironment(Environment):
1200             def subst_target_source(self, strSubst, raw=0, target=[], source=[]):
1201                 return 'subst_target_source: ' + strSubst
1202
1203         c = a.get_contents(target=DummyNode('ttt'), source = DummyNode('sss'),
1204                            env=SpecialEnvironment(foo = 'GGG', bar = 'CCC',
1205                                                   baz = 'ZZZ'))
1206         assert c == 'subst_target_source: | $( $foo | $bar $) | $baz 1', c
1207
1208         # We've discussed using the real target and source names in a
1209         # CommandAction's signature contents.  This would have have the
1210         # advantage of recompiling when a file's name changes (keeping
1211         # debug info current), but it would currently break repository
1212         # logic that will change the file name based on whether the
1213         # files come from a repository or locally.  If we ever move to
1214         # that scheme, then all of the '__t1__' and '__s6__' file names
1215         # in the asserts below would change to 't1' and 's6' and the
1216         # like.
1217         t = map(DummyNode, ['t1', 't2', 't3', 't4', 't5', 't6'])
1218         s = map(DummyNode, ['s1', 's2', 's3', 's4', 's5', 's6'])
1219         env = Environment()
1220
1221         a = SCons.Action.CommandAction(["$TARGET"])
1222         c = a.get_contents(target=t, source=s, env=env)
1223         assert c == "t1", c
1224
1225         a = SCons.Action.CommandAction(["$TARGETS"])
1226         c = a.get_contents(target=t, source=s, env=env)
1227         assert c == "t1 t2 t3 t4 t5 t6", c
1228
1229         a = SCons.Action.CommandAction(["${TARGETS[2]}"])
1230         c = a.get_contents(target=t, source=s, env=env)
1231         assert c == "t3", c
1232
1233         a = SCons.Action.CommandAction(["${TARGETS[3:5]}"])
1234         c = a.get_contents(target=t, source=s, env=env)
1235         assert c == "t4 t5", c
1236
1237         a = SCons.Action.CommandAction(["$SOURCE"])
1238         c = a.get_contents(target=t, source=s, env=env)
1239         assert c == "s1", c
1240
1241         a = SCons.Action.CommandAction(["$SOURCES"])
1242         c = a.get_contents(target=t, source=s, env=env)
1243         assert c == "s1 s2 s3 s4 s5 s6", c
1244
1245         a = SCons.Action.CommandAction(["${SOURCES[2]}"])
1246         c = a.get_contents(target=t, source=s, env=env)
1247         assert c == "s3", c
1248
1249         a = SCons.Action.CommandAction(["${SOURCES[3:5]}"])
1250         c = a.get_contents(target=t, source=s, env=env)
1251         assert c == "s4 s5", c
1252
1253 class CommandGeneratorActionTestCase(unittest.TestCase):
1254
1255     def test___init__(self):
1256         """Test creation of a command generator Action
1257         """
1258         def f(target, source, env):
1259             pass
1260         a = SCons.Action.CommandGeneratorAction(f)
1261         assert a.generator == f
1262
1263     def test___str__(self):
1264         """Test the pre-substitution strings for command generator Actions
1265         """
1266         def f(target, source, env, for_signature, self=self):
1267
1268             # See if "env" is really a construction environment (or
1269             # looks like one) by accessing the FindIxes attribute.
1270             # (The Tool/mingw.py module has a generator that uses this,
1271             # and the __str__() method used to cause problems by passing
1272             # us a regular dictionary as a fallback.)
1273
1274             env.FindIxes
1275             return "FOO"
1276         a = SCons.Action.CommandGeneratorAction(f)
1277         s = str(a)
1278         assert s == 'FOO', s
1279
1280     def test_genstring(self):
1281         """Test the command generator Action genstring() method
1282         """
1283         def f(target, source, env, for_signature, self=self):
1284             dummy = env['dummy']
1285             self.dummy = dummy
1286             return "$FOO $TARGET $SOURCE $TARGETS $SOURCES"
1287         a = SCons.Action.CommandGeneratorAction(f)
1288         self.dummy = 0
1289         s = a.genstring([], [], env=Environment(FOO='xyzzy', dummy=1))
1290         assert self.dummy == 1, self.dummy
1291         assert s == "$FOO $TARGET $SOURCE $TARGETS $SOURCES", s
1292
1293     def test_execute(self):
1294         """Test executing a command generator Action
1295         """
1296
1297         def f(target, source, env, for_signature, self=self):
1298             dummy = env['dummy']
1299             self.dummy = dummy
1300             s = env.subst("$FOO")
1301             assert s == 'foo baz\nbar ack', s
1302             return "$FOO"
1303         def func_action(target, source, env, self=self):
1304             dummy=env['dummy']
1305             s = env.subst('$foo')
1306             assert s == 'bar', s
1307             self.dummy=dummy
1308         def f2(target, source, env, for_signature, f=func_action):
1309             return f
1310         def ch(sh, escape, cmd, args, env, self=self):
1311             self.cmd.append(cmd)
1312             self.args.append(args)
1313
1314         a = SCons.Action.CommandGeneratorAction(f)
1315         self.dummy = 0
1316         self.cmd = []
1317         self.args = []
1318         a([], [], env=Environment(FOO = 'foo baz\nbar ack',
1319                                           dummy = 1,
1320                                           SPAWN = ch))
1321         assert self.dummy == 1, self.dummy
1322         assert self.cmd == ['foo', 'bar'], self.cmd
1323         assert self.args == [[ 'foo', 'baz' ], [ 'bar', 'ack' ]], self.args
1324
1325         b = SCons.Action.CommandGeneratorAction(f2)
1326         self.dummy = 0
1327         b(target=[], source=[], env=Environment(foo =  'bar',
1328                                                         dummy =  2 ))
1329         assert self.dummy==2, self.dummy
1330         del self.dummy
1331
1332         class DummyFile:
1333             def __init__(self, t):
1334                 self.t = t
1335             def rfile(self):
1336                 self.t.rfile_called = 1
1337                 return self
1338             def get_subst_proxy(self):
1339                 return self
1340         def f3(target, source, env, for_signature):
1341             return ''
1342         c = SCons.Action.CommandGeneratorAction(f3)
1343         c(target=[], source=DummyFile(self), env=Environment())
1344         assert self.rfile_called
1345
1346     def test_get_contents(self):
1347         """Test fetching the contents of a command generator Action
1348         """
1349         def f(target, source, env, for_signature):
1350             foo = env['foo']
1351             bar = env['bar']
1352             assert for_signature, for_signature
1353             return [["guux", foo, "$(", "$ignore", "$)", bar,
1354                      '${test("$( foo $bar $)")}' ]]
1355
1356         def test(mystr):
1357             assert mystr == "$( foo $bar $)", mystr
1358             return "test"
1359
1360         env = Environment(foo = 'FFF', bar =  'BBB',
1361                           ignore = 'foo', test=test)
1362         a = SCons.Action.CommandGeneratorAction(f)
1363         c = a.get_contents(target=[], source=[], env=env)
1364         assert c == "guux FFF BBB test", c
1365
1366
1367 class FunctionActionTestCase(unittest.TestCase):
1368
1369     def test___init__(self):
1370         """Test creation of a function Action
1371         """
1372         def func1():
1373             pass
1374         def func2():
1375             pass
1376         def func3():
1377             pass
1378         def func4():
1379             pass
1380
1381         a = SCons.Action.FunctionAction(func1)
1382         assert a.execfunction == func1, a.execfunction
1383         assert isinstance(a.strfunction, types.MethodType), type(a.strfunction)
1384
1385         a = SCons.Action.FunctionAction(func2, strfunction=func3)
1386         assert a.execfunction == func2, a.execfunction
1387         assert a.strfunction == func3, a.strfunction
1388
1389     def test_cmdstr_bad(self):
1390         """Test handling of bad FunctionAction(cmdstr) arguments
1391         """
1392         def func():
1393             pass
1394         try:
1395             a = SCons.Action.FunctionAction(func, [])
1396         except SCons.Errors.UserError, e:
1397             s = str(e)
1398             m = 'Invalid function display variable'
1399             assert string.find(s, m) != -1, 'Unexpected string:  %s' % s
1400         else:
1401             raise "did not catch expected UserError"
1402
1403     def test___str__(self):
1404         """Test the __str__() method for function Actions
1405         """
1406         def func1():
1407             pass
1408         a = SCons.Action.FunctionAction(func1)
1409         s = str(a)
1410         assert s == "func1(target, source, env)", s
1411
1412         class class1:
1413             def __call__(self):
1414                 pass
1415         a = SCons.Action.FunctionAction(class1())
1416         s = str(a)
1417         assert s == "class1(target, source, env)", s
1418
1419     def test_execute(self):
1420         """Test executing a function Action
1421         """
1422         self.inc = 0
1423         def f(target, source, env):
1424             s = env['s']
1425             s.inc = s.inc + 1
1426             s.target = target
1427             s.source=source
1428             assert env.subst("$BAR") == 'foo bar', env.subst("$BAR")
1429             return 0
1430         a = SCons.Action.FunctionAction(f)
1431         a(target=1, source=2, env=Environment(BAR = 'foo bar',
1432                                                       s = self))
1433         assert self.inc == 1, self.inc
1434         assert self.source == [2], self.source
1435         assert self.target == [1], self.target
1436
1437         global count
1438         count = 0
1439         def function1(target, source, env):
1440             global count
1441             count = count + 1
1442             for t in target:
1443                 open(t, 'w').write("function1\n")
1444             return 1
1445
1446         act = SCons.Action.FunctionAction(function1)
1447         r = act(target = [outfile, outfile2], source=[], env=Environment())
1448         assert r.status == 1, r.status
1449
1450         assert count == 1, count
1451         c = test.read(outfile, 'r')
1452         assert c == "function1\n", c
1453         c = test.read(outfile2, 'r')
1454         assert c == "function1\n", c
1455
1456         class class1a:
1457             def __init__(self, target, source, env):
1458                 open(env['out'], 'w').write("class1a\n")
1459
1460         act = SCons.Action.FunctionAction(class1a)
1461         r = act([], [], Environment(out = outfile))
1462         assert isinstance(r.status, class1a), r.status
1463         c = test.read(outfile, 'r')
1464         assert c == "class1a\n", c
1465
1466         class class1b:
1467             def __call__(self, target, source, env):
1468                 open(env['out'], 'w').write("class1b\n")
1469                 return 2
1470
1471         act = SCons.Action.FunctionAction(class1b())
1472         r = act([], [], Environment(out = outfile))
1473         assert r.status == 2, r.status
1474         c = test.read(outfile, 'r')
1475         assert c == "class1b\n", c
1476
1477         def build_it(target, source, env, self=self):
1478             self.build_it = 1
1479             return 0
1480         def string_it(target, source, env, self=self):
1481             self.string_it = 1
1482             return None
1483         act = SCons.Action.FunctionAction(build_it, strfunction=string_it)
1484         r = act([], [], Environment())
1485         assert r == 0, r
1486         assert self.build_it
1487         assert self.string_it
1488
1489     def test_get_contents(self):
1490         """Test fetching the contents of a function Action
1491         """
1492
1493         def LocalFunc():
1494             pass
1495
1496         func_matches = [
1497             "0,0,0,0,(),(),(d\000\000S),(),()",
1498             "0,0,0,0,(),(),(d\x00\x00S),(),()",
1499             ]
1500         
1501         meth_matches = [
1502             "1,1,0,0,(),(),(d\000\000S),(),()",
1503             "1,1,0,0,(),(),(d\x00\x00S),(),()",
1504         ]
1505
1506         a = SCons.Action.FunctionAction(GlobalFunc)
1507         c = a.get_contents(target=[], source=[], env=Environment())
1508         assert c in func_matches, repr(c)
1509
1510         a = SCons.Action.FunctionAction(LocalFunc)
1511         c = a.get_contents(target=[], source=[], env=Environment())
1512         assert c in func_matches, repr(c)
1513
1514         a = SCons.Action.FunctionAction(GlobalFunc, varlist=['XYZ'])
1515
1516         matches_foo = map(lambda x: x + "foo", func_matches)
1517
1518         c = a.get_contents(target=[], source=[], env=Environment())
1519         assert c in func_matches, repr(c)
1520         c = a.get_contents(target=[], source=[], env=Environment(XYZ = 'foo'))
1521         assert c in matches_foo, repr(c)
1522
1523         class Foo:
1524             def get_contents(self, target, source, env):
1525                 return 'xyzzy'
1526         a = SCons.Action.FunctionAction(Foo())
1527         c = a.get_contents(target=[], source=[], env=Environment())
1528         assert c == 'xyzzy', repr(c)
1529
1530         class LocalClass:
1531             def LocalMethod(self):
1532                 pass
1533         lc = LocalClass()
1534         a = SCons.Action.FunctionAction(lc.LocalMethod)
1535         c = a.get_contents(target=[], source=[], env=Environment())
1536         assert c in meth_matches, repr(c)
1537
1538     def test_strfunction(self):
1539         """Test the FunctionAction.strfunction() method
1540         """
1541         def func():
1542             pass
1543
1544         a = SCons.Action.FunctionAction(func)
1545         s = a.strfunction(target=[], source=[], env=Environment())
1546         assert s == 'func([], [])', s
1547
1548         a = SCons.Action.FunctionAction(func, None)
1549         s = a.strfunction(target=[], source=[], env=Environment())
1550         assert s is None, s
1551
1552         a = SCons.Action.FunctionAction(func, 'function')
1553         s = a.strfunction(target=[], source=[], env=Environment())
1554         assert s == 'function', s
1555
1556 class ListActionTestCase(unittest.TestCase):
1557
1558     def test___init__(self):
1559         """Test creation of a list of subsidiary Actions
1560         """
1561         def func():
1562             pass
1563         a = SCons.Action.ListAction(["x", func, ["y", "z"]])
1564         assert isinstance(a.list[0], SCons.Action.CommandAction)
1565         assert isinstance(a.list[1], SCons.Action.FunctionAction)
1566         assert isinstance(a.list[2], SCons.Action.ListAction)
1567         assert a.list[2].list[0].cmd_list == 'y'
1568
1569     def test___str__(self):
1570         """Test the __str__() method for a list of subsidiary Actions
1571         """
1572         def f(target,source,env):
1573             pass
1574         def g(target,source,env):
1575             pass
1576         a = SCons.Action.ListAction([f, g, "XXX", f])
1577         s = str(a)
1578         assert s == "f(target, source, env)\ng(target, source, env)\nXXX\nf(target, source, env)", s
1579
1580     def test_genstring(self):
1581         """Test the genstring() method for a list of subsidiary Actions
1582         """
1583         def f(target,source,env):
1584             pass
1585         def g(target,source,env,for_signature):
1586             return 'generated %s %s' % (target[0], source[0])
1587         g = SCons.Action.Action(g, generator=1)
1588         a = SCons.Action.ListAction([f, g, "XXX", f])
1589         s = a.genstring(['foo.x'], ['bar.y'], Environment())
1590         assert s == "f(target, source, env)\ngenerated foo.x bar.y\nXXX\nf(target, source, env)", s
1591
1592     def test_execute(self):
1593         """Test executing a list of subsidiary Actions
1594         """
1595         self.inc = 0
1596         def f(target,source,env):
1597             s = env['s']
1598             s.inc = s.inc + 1
1599         a = SCons.Action.ListAction([f, f, f])
1600         a([], [], Environment(s = self))
1601         assert self.inc == 3, self.inc
1602
1603         cmd2 = r'%s %s %s syzygy' % (_python_, act_py, outfile)
1604
1605         def function2(target, source, env):
1606             open(env['out'], 'a').write("function2\n")
1607             return 0
1608
1609         class class2a:
1610             def __call__(self, target, source, env):
1611                 open(env['out'], 'a').write("class2a\n")
1612                 return 0
1613
1614         class class2b:
1615             def __init__(self, target, source, env):
1616                 open(env['out'], 'a').write("class2b\n")
1617         act = SCons.Action.ListAction([cmd2, function2, class2a(), class2b])
1618         r = act([], [], Environment(out = outfile))
1619         assert isinstance(r.status, class2b), r.status
1620         c = test.read(outfile, 'r')
1621         assert c == "act.py: 'syzygy'\nfunction2\nclass2a\nclass2b\n", c
1622
1623     def test_get_contents(self):
1624         """Test fetching the contents of a list of subsidiary Actions
1625         """
1626         self.foo=0
1627         def gen(target, source, env, for_signature):
1628             s = env['s']
1629             s.foo=1
1630             return "y"
1631         a = SCons.Action.ListAction(["x",
1632                                      SCons.Action.Action(gen, generator=1),
1633                                      "z"])
1634         c = a.get_contents(target=[], source=[], env=Environment(s = self))
1635         assert self.foo==1, self.foo
1636         assert c == "xyz", c
1637
1638 class LazyActionTestCase(unittest.TestCase):
1639     def test___init__(self):
1640         """Test creation of a lazy-evaluation Action
1641         """
1642         # Environment variable references should create a special type
1643         # of LazyAction that lazily evaluates the variable for whether
1644         # it's a string or something else before doing anything.
1645         a9 = SCons.Action.Action('$FOO')
1646         assert isinstance(a9, SCons.Action.LazyAction), a9
1647         assert a9.var == 'FOO', a9.var
1648
1649         a10 = SCons.Action.Action('${FOO}')
1650         assert isinstance(a10, SCons.Action.LazyAction), a10
1651         assert a10.var == 'FOO', a10.var
1652
1653     def test_genstring(self):
1654         """Test the lazy-evaluation Action genstring() method
1655         """
1656         def f(target, source, env):
1657             pass
1658         a = SCons.Action.Action('$BAR')
1659         env1 = Environment(BAR=f, s=self)
1660         env2 = Environment(BAR='xxx', s=self)
1661         s = a.genstring([], [], env=env1)
1662         assert s == "f(target, source, env)", s
1663         s = a.genstring([], [], env=env2)
1664         assert s == 'xxx', s
1665
1666     def test_execute(self):
1667         """Test executing a lazy-evaluation Action
1668         """
1669         def f(target, source, env):
1670             s = env['s']
1671             s.test=1
1672             return 0
1673         a = SCons.Action.Action('$BAR')
1674         a([], [], env=Environment(BAR = f, s = self))
1675         assert self.test == 1, self.test
1676         cmd = r'%s %s %s lazy' % (_python_, act_py, outfile)
1677         a([], [], env=Environment(BAR = cmd, s = self))
1678         c = test.read(outfile, 'r')
1679         assert c == "act.py: 'lazy'\n", c
1680
1681     def test_get_contents(self):
1682         """Test fetching the contents of a lazy-evaluation Action
1683         """
1684         a = SCons.Action.Action("${FOO}")
1685         env = Environment(FOO = [["This", "is", "a", "test"]])
1686         c = a.get_contents(target=[], source=[], env=env)
1687         assert c == "This is a test", c
1688
1689 class ActionCallerTestCase(unittest.TestCase):
1690     def test___init__(self):
1691         """Test creation of an ActionCaller"""
1692         ac = SCons.Action.ActionCaller(1, [2, 3], {'FOO' : 4, 'BAR' : 5})
1693         assert ac.parent == 1, ac.parent
1694         assert ac.args == [2, 3], ac.args
1695         assert ac.kw == {'FOO' : 4, 'BAR' : 5}, ac.kw
1696
1697     def test_get_contents(self):
1698         """Test fetching the contents of an ActionCaller"""
1699         def strfunc():
1700             pass
1701
1702         def LocalFunc():
1703             pass
1704
1705         matches = [
1706             "d\000\000S",
1707             "d\x00\x00S"
1708         ]
1709
1710         af = SCons.Action.ActionFactory(GlobalFunc, strfunc)
1711         ac = SCons.Action.ActionCaller(af, [], {})
1712         c = ac.get_contents([], [], Environment())
1713         assert c in matches, repr(c)
1714
1715         af = SCons.Action.ActionFactory(LocalFunc, strfunc)
1716         ac = SCons.Action.ActionCaller(af, [], {})
1717         c = ac.get_contents([], [], Environment())
1718         assert c in matches, repr(c)
1719
1720         matches = [
1721             'd\000\000S',
1722             "d\x00\x00S"
1723         ]
1724
1725         class LocalActFunc:
1726             def __call__(self):
1727                 pass
1728
1729         af = SCons.Action.ActionFactory(GlobalActFunc(), strfunc)
1730         ac = SCons.Action.ActionCaller(af, [], {})
1731         c = ac.get_contents([], [], Environment())
1732         assert c in matches, repr(c)
1733
1734         af = SCons.Action.ActionFactory(LocalActFunc(), strfunc)
1735         ac = SCons.Action.ActionCaller(af, [], {})
1736         c = ac.get_contents([], [], Environment())
1737         assert c in matches, repr(c)
1738
1739         matches = [
1740             "<built-in function str>",
1741             "<type 'str'>",
1742         ]
1743
1744         af = SCons.Action.ActionFactory(str, strfunc)
1745         ac = SCons.Action.ActionCaller(af, [], {})
1746         c = ac.get_contents([], [], Environment())
1747         assert c == "<built-in function str>" or \
1748                c == "<type 'str'>", repr(c)
1749
1750     def test___call__(self):
1751         """Test calling an ActionCaller"""
1752         actfunc_args = []
1753         def actfunc(a1, a2, a3, args=actfunc_args):
1754             args.extend([a1, a2, a3])
1755         def strfunc(a1, a2, a3):
1756             pass
1757
1758         e = Environment(FOO = 2, BAR = 5)
1759
1760         af = SCons.Action.ActionFactory(actfunc, strfunc)
1761         ac = SCons.Action.ActionCaller(af, ['$__env__', '$FOO', 3], {})
1762         ac([], [], e)
1763         assert actfunc_args[0] is e, actfunc_args
1764         assert actfunc_args[1] == '2', actfunc_args
1765         assert actfunc_args[2] == 3, actfunc_args
1766         del actfunc_args[:]
1767
1768         ac = SCons.Action.ActionCaller(af, [], {'a3' : '$__env__', 'a2' : '$BAR', 'a1' : 4})
1769         ac([], [], e)
1770         assert actfunc_args[0] == 4, actfunc_args
1771         assert actfunc_args[1] == '5', actfunc_args
1772         assert actfunc_args[2] is e, actfunc_args
1773         del actfunc_args[:]
1774
1775     def test_strfunction(self):
1776         """Test calling the ActionCaller strfunction() method"""
1777         strfunc_args = []
1778         def actfunc(a1, a2, a3, a4):
1779             pass
1780         def strfunc(a1, a2, a3, a4, args=strfunc_args):
1781             args.extend([a1, a2, a3, a4])
1782
1783         af = SCons.Action.ActionFactory(actfunc, strfunc)
1784         ac = SCons.Action.ActionCaller(af, [1, '$FOO', 3, '$WS'], {})
1785         ac.strfunction([], [], Environment(FOO = 2, WS='white   space'))
1786         assert strfunc_args == [1, '2', 3, 'white   space'], strfunc_args
1787
1788         del strfunc_args[:]
1789         d = {'a3' : 6, 'a2' : '$BAR', 'a1' : 4, 'a4' : '$WS'}
1790         ac = SCons.Action.ActionCaller(af, [], d)
1791         ac.strfunction([], [], Environment(BAR = 5, WS='w   s'))
1792         assert strfunc_args == [4, '5', 6, 'w   s'], strfunc_args
1793
1794 class ActionFactoryTestCase(unittest.TestCase):
1795     def test___init__(self):
1796         """Test creation of an ActionFactory"""
1797         def actfunc():
1798             pass
1799         def strfunc():
1800             pass
1801         ac = SCons.Action.ActionFactory(actfunc, strfunc)
1802         assert ac.actfunc is actfunc, ac.actfunc
1803         assert ac.strfunc is strfunc, ac.strfunc
1804
1805     def test___call__(self):
1806         """Test calling whatever's returned from an ActionFactory"""
1807         actfunc_args = []
1808         strfunc_args = []
1809         def actfunc(a1, a2, a3, args=actfunc_args):
1810             args.extend([a1, a2, a3])
1811         def strfunc(a1, a2, a3, args=strfunc_args):
1812             args.extend([a1, a2, a3])
1813         af = SCons.Action.ActionFactory(actfunc, strfunc)
1814         af(3, 6, 9)([], [], Environment())
1815         assert actfunc_args == [3, 6, 9], actfunc_args
1816         assert strfunc_args == [3, 6, 9], strfunc_args
1817
1818
1819 class ActionCompareTestCase(unittest.TestCase):
1820
1821     def test_1_solo_name(self):
1822         """Test Lazy Cmd Generator Action get_name alone.
1823
1824         Basically ensures we can locate the builder, comparing it to
1825         itself along the way."""
1826         bar = SCons.Builder.Builder(action = {})
1827         env = Environment( BUILDERS = {'BAR' : bar} )
1828         name = bar.get_name(env)
1829         assert name == 'BAR', name
1830
1831     def test_2_multi_name(self):
1832         """Test LazyCmdGenerator Action get_name multi builders.
1833
1834         Ensure that we can compare builders (and thereby actions) to
1835         each other safely."""
1836         foo = SCons.Builder.Builder(action = '$FOO', suffix = '.foo')
1837         bar = SCons.Builder.Builder(action = {})
1838         assert foo != bar
1839         assert foo.action != bar.action
1840         env = Environment( BUILDERS = {'FOO' : foo,
1841                                        'BAR' : bar} )
1842         name = foo.get_name(env)
1843         assert name == 'FOO', name
1844         name = bar.get_name(env)
1845         assert name == 'BAR', name
1846
1847     def test_3_dict_names(self):
1848         """Test Action/Suffix dicts with get_name.
1849
1850         Verifies that Action/Suffix dictionaries work correctly,
1851         especially two builders that can generate the same suffix,
1852         where one of the builders has a suffix dictionary with a None
1853         key."""
1854         
1855         foo = SCons.Builder.Builder(action = '$FOO', suffix = '.foo')
1856         bar = SCons.Builder.Builder(action = {}, suffix={None:'.bar'})
1857         bar.add_action('.cow', "$MOO")
1858         dog = SCons.Builder.Builder(suffix = '.bar')
1859         
1860         env = Environment( BUILDERS = {'FOO' : foo,
1861                                        'BAR' : bar,
1862                                        'DOG' : dog} )
1863         
1864         assert foo.get_name(env) == 'FOO', foo.get_name(env)
1865         assert bar.get_name(env) == 'BAR', bar.get_name(env)
1866         assert dog.get_name(env) == 'DOG', dog.get_name(env)
1867
1868
1869 if __name__ == "__main__":
1870     suite = unittest.TestSuite()
1871     tclasses = [ ActionTestCase,
1872                  ActionBaseTestCase,
1873                  _ActionActionTestCase,
1874                  CommandActionTestCase,
1875                  CommandGeneratorActionTestCase,
1876                  FunctionActionTestCase,
1877                  ListActionTestCase,
1878                  LazyActionTestCase,
1879                  ActionCallerTestCase,
1880                  ActionFactoryTestCase,
1881                  ActionCompareTestCase ]
1882     for tclass in tclasses:
1883         names = unittest.getTestCaseNames(tclass, 'test_')
1884         suite.addTests(map(tclass, names))
1885     if not unittest.TextTestRunner().run(suite).wasSuccessful():
1886         sys.exit(1)