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:
12 # The above copyright notice and this permission notice shall be included
13 # in all copies or substantial portions of the Software.
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.
24 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
28 # Define a null function and a null class for use as builder actions.
29 # Where these are defined in the file seems to affect their byte-code
30 # contents, so try to minimize changes by defining them here, before we
31 # even import anything.
48 import SCons.Environment
53 # Initial setup of the common environment for all tests,
54 # a temporary working directory containing a
55 # script for writing arguments to an output file.
57 # We don't do this as a setUp() method because it's
58 # unnecessary to create a separate directory and script
59 # for each test, they can just use the one.
60 test = TestCmd.TestCmd(workdir = '')
62 test.write('act.py', """\
63 import os, string, sys
64 f = open(sys.argv[1], 'w')
65 f.write("act.py: '" + string.join(sys.argv[2:], "' '") + "'\\n")
68 f.write("act.py: '" + os.environ[sys.argv[3]] + "'\\n")
72 if 'ACTPY_PIPE' in os.environ:
73 if 'PIPE_STDOUT_FILE' in os.environ:
74 stdout_msg = open(os.environ['PIPE_STDOUT_FILE'], 'r').read()
76 stdout_msg = "act.py: stdout: executed act.py %s\\n" % ' '.join(sys.argv[1:])
77 sys.stdout.write( stdout_msg )
78 if 'PIPE_STDERR_FILE' in os.environ:
79 stderr_msg = open(os.environ['PIPE_STDERR_FILE'], 'r').read()
81 stderr_msg = "act.py: stderr: executed act.py %s\\n" % ' '.join(sys.argv[1:])
82 sys.stderr.write( stderr_msg )
86 test.write('exit.py', """\
88 sys.exit(int(sys.argv[1]))
91 act_py = test.workpath('act.py')
92 exit_py = test.workpath('exit.py')
94 outfile = test.workpath('outfile')
95 outfile2 = test.workpath('outfile2')
96 pipe_file = test.workpath('pipe.out')
98 scons_env = SCons.Environment.Environment()
100 # Capture all the stuff the Actions will print,
101 # so it doesn't clutter the output.
102 sys.stdout = io.StringIO()
104 class CmdStringHolder:
105 def __init__(self, cmd, literal=None):
107 self.literal = literal
109 def is_literal(self):
112 def escape(self, escape_func):
113 """Escape the string with the supplied function. The
114 function is expected to take an arbitrary string, then
115 return it with all special characters escaped and ready
116 for passing to the command interpreter.
118 After calling this function, the next call to str() will
119 return the escaped string.
122 if self.is_literal():
123 return escape_func(self.data)
124 elif ' ' in self.data or '\t' in self.data:
125 return '"%s"' % self.data
130 def __init__(self, **kw):
132 self.d['SHELL'] = scons_env['SHELL']
133 self.d['SPAWN'] = scons_env['SPAWN']
134 self.d['PSPAWN'] = scons_env['PSPAWN']
135 self.d['ESCAPE'] = scons_env['ESCAPE']
136 for k, v in kw.items():
138 # Just use the underlying scons_subst*() utility methods.
139 def subst(self, strSubst, raw=0, target=[], source=[], conv=None):
140 return SCons.Subst.scons_subst(strSubst, self, raw,
141 target, source, self.d, conv=conv)
142 subst_target_source = subst
143 def subst_list(self, strSubst, raw=0, target=[], source=[], conv=None):
144 return SCons.Subst.scons_subst_list(strSubst, self, raw,
145 target, source, self.d, conv=conv)
146 def __getitem__(self, item):
148 def __setitem__(self, item, value):
150 def has_key(self, item):
151 return item in self.d
152 def get(self, key, value=None):
153 return self.d.get(key, value)
155 return self.d.items()
156 def Dictionary(self):
158 def Clone(self, **kw):
160 res.d = SCons.Util.semi_deepcopy(self.d)
161 for k, v in kw.items():
166 for k,v in self.items(): d[k] = v
167 d['TARGETS'] = ['__t1__', '__t2__', '__t3__', '__t4__', '__t5__', '__t6__']
168 d['TARGET'] = d['TARGETS'][0]
169 d['SOURCES'] = ['__s1__', '__s2__', '__s3__', '__s4__', '__s5__', '__s6__']
170 d['SOURCE'] = d['SOURCES'][0]
174 def __init__(self, name):
176 def str_for_display(self):
177 return '"' + self.name + '"'
182 def get_subst_proxy(self):
185 if os.name == 'java':
186 python = os.path.join(sys.prefix, 'jython')
188 python = sys.executable
190 _python_ = '"' + python + '"'
192 _null = SCons.Action._null
194 def test_varlist(pos_call, str_call, cmd, cmdstrfunc, **kw):
195 def call_action(a, pos_call=pos_call, str_call=str_call, kw=kw):
196 a = SCons.Action.Action(*a, **kw)
197 # returned object must provide these entry points
198 assert hasattr(a, '__call__')
199 assert hasattr(a, 'get_contents')
200 assert hasattr(a, 'genstring')
205 a = call_action((cmd, cmdstrfunc))
206 assert a.varlist == (), a.varlist
208 a = call_action((cmd, cmdstrfunc, 'foo'))
209 assert a.varlist == ('foo',), a.varlist
211 a = call_action((cmd, cmdstrfunc, 'a', 'b', 'c'))
212 assert a.varlist == ('a', 'b', 'c'), a.varlist
214 kw['varlist'] = 'foo'
215 a = call_action((cmd, cmdstrfunc))
216 assert a.varlist == ('foo',), a.varlist
218 kw['varlist'] = ['x', 'y', 'z']
219 a = call_action((cmd, cmdstrfunc))
220 assert a.varlist == ('x', 'y', 'z'), a.varlist
222 a = call_action((cmd, cmdstrfunc, 'foo'))
223 assert a.varlist == ('foo', 'x', 'y', 'z'), a.varlist
225 a = call_action((cmd, cmdstrfunc, 'a', 'b', 'c'))
226 assert a.varlist == ('a', 'b', 'c', 'x', 'y', 'z'), a.varlist
228 def test_positional_args(pos_callback, cmd, **kw):
229 """Test that Action() returns the expected type and that positional args work.
231 #FUTURE act = SCons.Action.Action(cmd, **kw)
232 act = SCons.Action.Action(cmd, **kw)
234 assert act.varlist is (), act.varlist
236 if not isinstance(act, SCons.Action._ActionAction):
237 # only valid cmdstrfunc is None
239 #FUTURE test_varlist(pos_callback, none, cmd, None, **kw)
240 test_varlist(pos_callback, none, cmd, None, **kw)
242 # _ActionAction should have set these
243 assert hasattr(act, 'strfunction')
244 assert act.cmdstr is _null, act.cmdstr
245 assert act.presub is _null, act.presub
246 assert act.chdir is None, act.chdir
247 assert act.exitstatfunc is SCons.Action.default_exitstatfunc, \
251 assert hasattr(a, 'strfunction')
252 assert a.cmdstr == 'cmdstr', a.cmdstr
253 #FUTURE test_varlist(pos_callback, cmdstr, cmd, 'cmdstr', **kw)
254 test_varlist(pos_callback, cmdstr, cmd, 'cmdstr', **kw)
257 def strfun(a, fun=fun):
258 assert a.strfunction is fun, a.strfunction
259 assert a.cmdstr == _null, a.cmdstr
260 #FUTURE test_varlist(pos_callback, strfun, cmd, fun, **kw)
261 test_varlist(pos_callback, strfun, cmd, fun, **kw)
264 assert hasattr(a, 'strfunction')
265 assert a.cmdstr is None, a.cmdstr
266 #FUTURE test_varlist(pos_callback, none, cmd, None, **kw)
267 test_varlist(pos_callback, none, cmd, None, **kw)
269 """Test handling of bad cmdstrfunc arguments """
271 #FUTURE a = SCons.Action.Action(cmd, [], **kw)
272 a = SCons.Action.Action(cmd, [], **kw)
273 except SCons.Errors.UserError, e:
275 m = 'Invalid command display variable'
276 assert s.find(m) != -1, 'Unexpected string: %s' % s
278 raise Exception("did not catch expected UserError")
282 class ActionTestCase(unittest.TestCase):
283 """Test the Action() factory function"""
285 def test_FunctionAction(self):
286 """Test the Action() factory's creation of FunctionAction objects
291 def func_action(a, foo=foo):
292 assert isinstance(a, SCons.Action.FunctionAction), a
293 assert a.execfunction == foo, a.execfunction
294 test_positional_args(func_action, foo)
295 # a singleton list returns the contained action
296 test_positional_args(func_action, [foo])
298 def test_CommandAction(self):
299 """Test the Action() factory's creation of CommandAction objects
302 assert isinstance(a, SCons.Action.CommandAction), a
303 assert a.cmd_list == "string", a.cmd_list
304 test_positional_args(cmd_action, "string")
305 # a singleton list returns the contained action
306 test_positional_args(cmd_action, ["string"])
309 except NameError: pass
311 a2 = eval("SCons.Action.Action(u'string')")
312 assert isinstance(a2, SCons.Action.CommandAction), a2
315 assert isinstance(a, SCons.Action.CommandAction), a
316 assert a.cmd_list == [ "explicit", "command", "line" ], a.cmd_list
317 test_positional_args(line_action, [[ "explicit", "command", "line" ]])
319 def test_ListAction(self):
320 """Test the Action() factory's creation of ListAction objects
322 a1 = SCons.Action.Action(["x", "y", "z", [ "a", "b", "c"]])
323 assert isinstance(a1, SCons.Action.ListAction), a1
324 assert a1.varlist is (), a1.varlist
325 assert isinstance(a1.list[0], SCons.Action.CommandAction), a1.list[0]
326 assert a1.list[0].cmd_list == "x", a1.list[0].cmd_list
327 assert isinstance(a1.list[1], SCons.Action.CommandAction), a1.list[1]
328 assert a1.list[1].cmd_list == "y", a1.list[1].cmd_list
329 assert isinstance(a1.list[2], SCons.Action.CommandAction), a1.list[2]
330 assert a1.list[2].cmd_list == "z", a1.list[2].cmd_list
331 assert isinstance(a1.list[3], SCons.Action.CommandAction), a1.list[3]
332 assert a1.list[3].cmd_list == [ "a", "b", "c" ], a1.list[3].cmd_list
334 a2 = SCons.Action.Action("x\ny\nz")
335 assert isinstance(a2, SCons.Action.ListAction), a2
336 assert a2.varlist is (), a2.varlist
337 assert isinstance(a2.list[0], SCons.Action.CommandAction), a2.list[0]
338 assert a2.list[0].cmd_list == "x", a2.list[0].cmd_list
339 assert isinstance(a2.list[1], SCons.Action.CommandAction), a2.list[1]
340 assert a2.list[1].cmd_list == "y", a2.list[1].cmd_list
341 assert isinstance(a2.list[2], SCons.Action.CommandAction), a2.list[2]
342 assert a2.list[2].cmd_list == "z", a2.list[2].cmd_list
347 a3 = SCons.Action.Action(["x", foo, "z"])
348 assert isinstance(a3, SCons.Action.ListAction), a3
349 assert a3.varlist is (), a3.varlist
350 assert isinstance(a3.list[0], SCons.Action.CommandAction), a3.list[0]
351 assert a3.list[0].cmd_list == "x", a3.list[0].cmd_list
352 assert isinstance(a3.list[1], SCons.Action.FunctionAction), a3.list[1]
353 assert a3.list[1].execfunction == foo, a3.list[1].execfunction
354 assert isinstance(a3.list[2], SCons.Action.CommandAction), a3.list[2]
355 assert a3.list[2].cmd_list == "z", a3.list[2].cmd_list
357 a4 = SCons.Action.Action(["x", "y"], strfunction=foo)
358 assert isinstance(a4, SCons.Action.ListAction), a4
359 assert a4.varlist is (), a4.varlist
360 assert isinstance(a4.list[0], SCons.Action.CommandAction), a4.list[0]
361 assert a4.list[0].cmd_list == "x", a4.list[0].cmd_list
362 assert a4.list[0].strfunction == foo, a4.list[0].strfunction
363 assert isinstance(a4.list[1], SCons.Action.CommandAction), a4.list[1]
364 assert a4.list[1].cmd_list == "y", a4.list[1].cmd_list
365 assert a4.list[1].strfunction == foo, a4.list[1].strfunction
367 a5 = SCons.Action.Action("x\ny", strfunction=foo)
368 assert isinstance(a5, SCons.Action.ListAction), a5
369 assert a5.varlist is (), a5.varlist
370 assert isinstance(a5.list[0], SCons.Action.CommandAction), a5.list[0]
371 assert a5.list[0].cmd_list == "x", a5.list[0].cmd_list
372 assert a5.list[0].strfunction == foo, a5.list[0].strfunction
373 assert isinstance(a5.list[1], SCons.Action.CommandAction), a5.list[1]
374 assert a5.list[1].cmd_list == "y", a5.list[1].cmd_list
375 assert a5.list[1].strfunction == foo, a5.list[1].strfunction
377 def test_CommandGeneratorAction(self):
378 """Test the Action() factory's creation of CommandGeneratorAction objects
382 def gen_action(a, foo=foo):
383 assert isinstance(a, SCons.Action.CommandGeneratorAction), a
384 assert a.generator is foo, a.generator
385 test_positional_args(gen_action, foo, generator=1)
387 def test_LazyCmdGeneratorAction(self):
388 """Test the Action() factory's creation of lazy CommandGeneratorAction objects
391 assert isinstance(a, SCons.Action.LazyAction), a
392 assert a.var == "FOO", a.var
393 assert a.cmd_list == "${FOO}", a.cmd_list
394 test_positional_args(lazy_action, "$FOO")
395 test_positional_args(lazy_action, "${FOO}")
397 def test_no_action(self):
398 """Test when the Action() factory can't create an action object
400 a5 = SCons.Action.Action(1)
401 assert a5 is None, a5
403 def test_reentrance(self):
404 """Test the Action() factory when the action is already an Action object
406 a1 = SCons.Action.Action("foo")
407 a2 = SCons.Action.Action(a1)
410 class _ActionActionTestCase(unittest.TestCase):
412 def test__init__(self):
413 """Test creation of _ActionAction objects
425 a = SCons.Action._ActionAction()
426 assert not hasattr(a, 'strfunction')
427 assert a.cmdstr is _null, a.cmdstr
428 assert a.varlist == (), a.varlist
429 assert a.presub is _null, a.presub
430 assert a.chdir is None, a.chdir
431 assert a.exitstatfunc is SCons.Action.default_exitstatfunc, a.exitstatfunc
433 assert SCons.Action._ActionAction(kwarg = 1)
434 assert not hasattr(a, 'kwarg')
435 assert not hasattr(a, 'strfunction')
436 assert a.cmdstr is _null, a.cmdstr
437 assert a.varlist == (), a.varlist
438 assert a.presub is _null, a.presub
439 assert a.chdir is None, a.chdir
440 assert a.exitstatfunc is SCons.Action.default_exitstatfunc, a.exitstatfunc
442 a = SCons.Action._ActionAction(strfunction=func1)
443 assert a.strfunction is func1, a.strfunction
445 a = SCons.Action._ActionAction(strfunction=None)
446 assert not hasattr(a, 'strfunction')
447 assert a.cmdstr is None, a.cmdstr
449 a = SCons.Action._ActionAction(cmdstr='cmdstr')
450 assert not hasattr(a, 'strfunction')
451 assert a.cmdstr is 'cmdstr', a.cmdstr
453 a = SCons.Action._ActionAction(cmdstr=None)
454 assert not hasattr(a, 'strfunction')
455 assert a.cmdstr is None, a.cmdstr
458 a = SCons.Action._ActionAction(varlist=t)
459 assert a.varlist == t, a.varlist
461 a = SCons.Action._ActionAction(presub=func1)
462 assert a.presub is func1, a.presub
464 a = SCons.Action._ActionAction(chdir=1)
465 assert a.chdir is 1, a.chdir
467 a = SCons.Action._ActionAction(exitstatfunc=func1)
468 assert a.exitstatfunc is func1, a.exitstatfunc
470 a = SCons.Action._ActionAction(
471 # alphabetical order ...
479 assert a.chdir is 'x', a.chdir
480 assert a.cmdstr is 'cmdstr', a.cmdstr
481 assert a.exitstatfunc is func3, a.exitstatfunc
482 assert a.presub is func2, a.presub
483 assert a.strfunction is func1, a.strfunction
484 assert a.varlist is t, a.varlist
486 def test_dup_keywords(self):
487 """Test handling of both cmdstr and strfunction arguments
491 a = SCons.Action.Action('foo', cmdstr='string', strfunction=func)
492 except SCons.Errors.UserError, e:
494 m = 'Cannot have both strfunction and cmdstr args to Action()'
495 assert s.find(m) != -1, 'Unexpected string: %s' % s
497 raise Exception("did not catch expected UserError")
499 def test___cmp__(self):
500 """Test Action comparison
502 a1 = SCons.Action.Action("x")
503 a2 = SCons.Action.Action("x")
505 a3 = SCons.Action.Action("y")
509 def test_print_cmd_lines(self):
510 """Test the print_cmd_lines() method
512 save_stdout = sys.stdout
515 def execfunc(target, source, env):
517 a = SCons.Action.Action(execfunc)
521 a.print_cmd_line("foo bar", None, None, None)
523 assert s == "foo bar\n", s
526 sys.stdout = save_stdout
528 def test___call__(self):
529 """Test calling an Action
531 save_stdout = sys.stdout
533 save_print_actions = SCons.Action.print_actions
534 save_print_actions_presub = SCons.Action.print_actions_presub
535 save_execute_actions = SCons.Action.execute_actions
536 #SCons.Action.print_actions = 0
538 test = TestCmd.TestCmd(workdir = '')
539 test.subdir('sub', 'xyz')
540 os.chdir(test.workpath())
545 def execfunc(target, source, env):
546 assert isinstance(target, list), type(target)
547 assert isinstance(source, list), type(source)
549 a = SCons.Action.Action(execfunc)
551 def firstfunc(target, source, env):
552 assert isinstance(target, list), type(target)
553 assert isinstance(source, list), type(source)
555 def lastfunc(target, source, env):
556 assert isinstance(target, list), type(target)
557 assert isinstance(source, list), type(source)
559 b = SCons.Action.Action([firstfunc, execfunc, lastfunc])
563 result = a("out", "in", env)
564 assert result.status == 7, result
566 assert s == "execfunc(['out'], ['in'])\n", s
569 expect = "os.chdir(%s)\nexecfunc(['out'], ['in'])\nos.chdir(%s)\n"
573 result = a("out", "in", env)
574 assert result.status == 7, result.status
576 assert s == expect % (repr('xyz'), repr(test.workpath())), s
580 result = a("out", "in", env, chdir='sub')
581 assert result.status == 7, result.status
583 assert s == expect % (repr('sub'), repr(test.workpath())), s
589 result = b("out", "in", env)
590 assert result.status == 7, result.status
592 assert s == "firstfunc(['out'], ['in'])\nexecfunc(['out'], ['in'])\n", s
594 SCons.Action.execute_actions = 0
598 result = a("out", "in", env)
599 assert result == 0, result
601 assert s == "execfunc(['out'], ['in'])\n", s
605 result = b("out", "in", env)
606 assert result == 0, result
608 assert s == "firstfunc(['out'], ['in'])\nexecfunc(['out'], ['in'])\nlastfunc(['out'], ['in'])\n", s
610 SCons.Action.print_actions_presub = 1
611 SCons.Action.execute_actions = 1
615 result = a("out", "in", env)
616 assert result.status == 7, result.status
618 assert s == "Building out with action:\n execfunc(target, source, env)\nexecfunc(['out'], ['in'])\n", s
622 result = a("out", "in", env, presub=0)
623 assert result.status == 7, result.status
625 assert s == "execfunc(['out'], ['in'])\n", s
629 result = a("out", "in", env, presub=1)
630 assert result.status == 7, result.status
632 assert s == "Building out with action:\n execfunc(target, source, env)\nexecfunc(['out'], ['in'])\n", s
636 result = b(["out"], "in", env, presub=1)
637 assert result.status == 7, result.status
639 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
643 result = b(["out", "list"], "in", env, presub=1)
644 assert result.status == 7, result.status
646 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
648 a2 = SCons.Action.Action(execfunc)
652 result = a2("out", "in", env)
653 assert result.status == 7, result.status
655 assert s == "Building out with action:\n execfunc(target, source, env)\nexecfunc(['out'], ['in'])\n", s
659 result = a2("out", "in", env, presub=0)
660 assert result.status == 7, result.status
662 assert s == "execfunc(['out'], ['in'])\n", s
664 SCons.Action.execute_actions = 0
668 result = a2("out", "in", env, presub=0)
669 assert result == 0, result
671 assert s == "execfunc(['out'], ['in'])\n", s
675 result = a("out", "in", env, presub=0, execute=1, show=0)
676 assert result.status == 7, result.status
680 sys.stdout = save_stdout
681 exitstatfunc_result = []
683 def exitstatfunc(stat, result=exitstatfunc_result):
687 result = a("out", "in", env, exitstatfunc=exitstatfunc)
688 assert result == 0, result
689 assert exitstatfunc_result == [], exitstatfunc_result
691 result = a("out", "in", env, execute=1, exitstatfunc=exitstatfunc)
692 assert result.status == 7, result.status
693 assert exitstatfunc_result == [7], exitstatfunc_result
695 SCons.Action.execute_actions = 1
698 def my_print_cmd_line(s, target, source, env, result=result):
700 env['PRINT_CMD_LINE_FUNC'] = my_print_cmd_line
701 a("output", "input", env)
702 assert result == ["execfunc(['output'], ['input'])"], result
706 sys.stdout = save_stdout
707 SCons.Action.print_actions = save_print_actions
708 SCons.Action.print_actions_presub = save_print_actions_presub
709 SCons.Action.execute_actions = save_execute_actions
711 def test_presub_lines(self):
712 """Test the presub_lines() method
715 a = SCons.Action.Action("x")
716 s = a.presub_lines(env)
719 a = SCons.Action.Action(["y", "z"])
720 s = a.presub_lines(env)
721 assert s == ['y', 'z'], s
725 a = SCons.Action.Action(func)
726 s = a.presub_lines(env)
727 assert s == ["func(target, source, env)"], s
729 def gen(target, source, env, for_signature):
730 return 'generat' + env.get('GEN', 'or')
731 a = SCons.Action.Action(gen, generator=1)
732 s = a.presub_lines(env)
733 assert s == ["generator"], s
734 s = a.presub_lines(Environment(GEN = 'ed'))
735 assert s == ["generated"], s
737 a = SCons.Action.Action("$ACT")
738 s = a.presub_lines(env)
740 s = a.presub_lines(Environment(ACT = 'expanded action'))
741 assert s == ['expanded action'], s
744 """Test adding Actions to stuff."""
745 # Adding actions to other Actions or to stuff that can
746 # be converted into an Action should produce a ListAction
747 # containing all the Actions.
750 baz = SCons.Action.Action(bar, generator=1)
751 act1 = SCons.Action.Action('foo bar')
752 act2 = SCons.Action.Action([ 'foo', bar ])
755 assert isinstance(sum, SCons.Action.ListAction), str(sum)
756 assert len(sum.list) == 3, len(sum.list)
757 assert [isinstance(x, SCons.Action.ActionBase) for x in sum.list] == [ 1, 1, 1 ]
760 assert isinstance(sum, SCons.Action.ListAction), str(sum)
761 assert len(sum.list) == 2, len(sum.list)
764 assert isinstance(sum, SCons.Action.ListAction), str(sum)
765 assert len(sum.list) == 4, len(sum.list)
767 # Should also be able to add command generators to each other
770 assert isinstance(sum, SCons.Action.ListAction), str(sum)
771 assert len(sum.list) == 2, len(sum.list)
774 assert isinstance(sum, SCons.Action.ListAction), str(sum)
775 assert len(sum.list) == 2, len(sum.list)
778 assert isinstance(sum, SCons.Action.ListAction), str(sum)
779 assert len(sum.list) == 3, len(sum.list)
781 # Also should be able to add Actions to anything that can
782 # be converted into an action.
784 assert isinstance(sum, SCons.Action.ListAction), str(sum)
785 assert len(sum.list) == 2, len(sum.list)
786 assert isinstance(sum.list[1], SCons.Action.FunctionAction)
788 sum = 'foo bar' + act2
789 assert isinstance(sum, SCons.Action.ListAction), str(sum)
790 assert len(sum.list) == 3, len(sum.list)
791 assert isinstance(sum.list[0], SCons.Action.CommandAction)
793 sum = [ 'foo', 'bar' ] + act1
794 assert isinstance(sum, SCons.Action.ListAction), str(sum)
795 assert len(sum.list) == 3, sum.list
796 assert isinstance(sum.list[0], SCons.Action.CommandAction)
797 assert isinstance(sum.list[1], SCons.Action.CommandAction)
799 sum = act2 + [ baz, bar ]
800 assert isinstance(sum, SCons.Action.ListAction), str(sum)
801 assert len(sum.list) == 4, len(sum.list)
802 assert isinstance(sum.list[2], SCons.Action.CommandGeneratorAction)
803 assert isinstance(sum.list[3], SCons.Action.FunctionAction)
810 assert 0, "Should have thrown a TypeError adding to an int."
817 assert 0, "Should have thrown a TypeError adding to an int."
819 class CommandActionTestCase(unittest.TestCase):
821 def test___init__(self):
822 """Test creation of a command Action
824 a = SCons.Action.CommandAction(["xyzzy"])
825 assert a.cmd_list == [ "xyzzy" ], a.cmd_list
826 assert a.cmdstr is _null, a.cmdstr
828 a = SCons.Action.CommandAction(["abra"], cmdstr="cadabra")
829 assert a.cmd_list == [ "abra" ], a.cmd_list
830 assert a.cmdstr == "cadabra", a.cmdstr
832 def test___str__(self):
833 """Test fetching the pre-substitution string for command Actions
836 act = SCons.Action.CommandAction('xyzzy $TARGET $SOURCE')
838 assert s == 'xyzzy $TARGET $SOURCE', s
840 act = SCons.Action.CommandAction(['xyzzy',
841 '$TARGET', '$SOURCE',
842 '$TARGETS', '$SOURCES'])
844 assert s == "xyzzy $TARGET $SOURCE $TARGETS $SOURCES", s
846 def test_genstring(self):
847 """Test the genstring() method for command Actions
855 act = SCons.Action.CommandAction('xyzzy $TARGET $SOURCE')
856 expect = 'xyzzy $TARGET $SOURCE'
857 s = act.genstring([], [], env)
858 assert s == expect, s
859 s = act.genstring([t1], [s1], env)
860 assert s == expect, s
861 s = act.genstring([t1, t2], [s1, s2], env)
862 assert s == expect, s
864 act = SCons.Action.CommandAction('xyzzy $TARGETS $SOURCES')
865 expect = 'xyzzy $TARGETS $SOURCES'
866 s = act.genstring([], [], env)
867 assert s == expect, s
868 s = act.genstring([t1], [s1], env)
869 assert s == expect, s
870 s = act.genstring([t1, t2], [s1, s2], env)
871 assert s == expect, s
873 act = SCons.Action.CommandAction(['xyzzy',
874 '$TARGET', '$SOURCE',
875 '$TARGETS', '$SOURCES'])
876 expect = "xyzzy $TARGET $SOURCE $TARGETS $SOURCES"
877 s = act.genstring([], [], env)
878 assert s == expect, s
879 s = act.genstring([t1], [s1], env)
880 assert s == expect, s
881 s = act.genstring([t1, t2], [s1, s2], env)
882 assert s == expect, s
884 def test_strfunction(self):
885 """Test fetching the string representation of command Actions
893 act = SCons.Action.CommandAction('xyzzy $TARGET $SOURCE')
894 s = act.strfunction([], [], env)
895 assert s == 'xyzzy', s
896 s = act.strfunction([t1], [s1], env)
897 assert s == 'xyzzy t1 s1', s
898 s = act.strfunction([t1, t2], [s1, s2], env)
899 assert s == 'xyzzy t1 s1', s
901 act = SCons.Action.CommandAction('xyzzy $TARGET $SOURCE',
902 cmdstr='cmdstr - $SOURCE - $TARGET -')
903 s = act.strfunction([], [], env)
904 assert s == 'cmdstr - - -', s
905 s = act.strfunction([t1], [s1], env)
906 assert s == 'cmdstr - s1 - t1 -', s
907 s = act.strfunction([t1, t2], [s1, s2], env)
908 assert s == 'cmdstr - s1 - t1 -', s
910 act = SCons.Action.CommandAction('xyzzy $TARGETS $SOURCES')
911 s = act.strfunction([], [], env)
912 assert s == 'xyzzy', s
913 s = act.strfunction([t1], [s1], env)
914 assert s == 'xyzzy t1 s1', s
915 s = act.strfunction([t1, t2], [s1, s2], env)
916 assert s == 'xyzzy t1 t2 s1 s2', s
918 act = SCons.Action.CommandAction('xyzzy $TARGETS $SOURCES',
919 cmdstr='cmdstr = $SOURCES = $TARGETS =')
920 s = act.strfunction([], [], env)
921 assert s == 'cmdstr = = =', s
922 s = act.strfunction([t1], [s1], env)
923 assert s == 'cmdstr = s1 = t1 =', s
924 s = act.strfunction([t1, t2], [s1, s2], env)
925 assert s == 'cmdstr = s1 s2 = t1 t2 =', s
927 act = SCons.Action.CommandAction(['xyzzy',
928 '$TARGET', '$SOURCE',
929 '$TARGETS', '$SOURCES'])
930 s = act.strfunction([], [], env)
931 assert s == 'xyzzy', s
932 s = act.strfunction([t1], [s1], env)
933 assert s == 'xyzzy t1 s1 t1 s1', s
934 s = act.strfunction([t1, t2], [s1, s2], env)
935 assert s == 'xyzzy t1 s1 t1 t2 s1 s2', s
937 act = SCons.Action.CommandAction('xyzzy $TARGETS $SOURCES',
938 cmdstr='cmdstr\t$TARGETS\n$SOURCES ')
940 s = act.strfunction([], [], env)
941 assert s == 'cmdstr\t\n ', s
942 s = act.strfunction([t1], [s1], env)
943 assert s == 'cmdstr\tt1\ns1 ', s
944 s = act.strfunction([t1, t2], [s1, s2], env)
945 assert s == 'cmdstr\tt1 t2\ns1 s2 ', s
947 def sf(target, source, env):
948 return "sf was called"
949 act = SCons.Action.CommandAction('foo', strfunction=sf)
950 s = act.strfunction([], [], env)
951 assert s == "sf was called", s
954 def __init__(self, targets, sources, env):
959 def __init__(self, targets, sources, env):
964 def __init__(self, targets, sources, env):
968 def strfunction(self, targets, sources, env):
969 return 'actclass3 on %s to get %s'%(str(sources[0]),
972 def __init__(self, targets, sources, env):
978 act1 = SCons.Action.Action(actclass1([t1], [s1], env))
979 s = act1.strfunction([t1], [s1], env)
980 assert s == 'actclass1(["t1"], ["s1"])', s
982 act2 = SCons.Action.Action(actclass2([t1], [s1], env))
983 s = act2.strfunction([t1], [s1], env)
984 assert s == 'actclass2(["t1"], ["s1"])', s
986 act3 = SCons.Action.Action(actclass3([t1], [s1], env))
987 s = act3.strfunction([t1], [s1], env)
988 assert s == 'actclass3 on s1 to get t1', s
990 act4 = SCons.Action.Action(actclass4([t1], [s1], env))
991 s = act4.strfunction([t1], [s1], env)
994 act = SCons.Action.CommandAction("@foo bar")
995 s = act.strfunction([], [], env)
998 act = SCons.Action.CommandAction("@-foo bar")
999 s = act.strfunction([], [], env)
1002 act = SCons.Action.CommandAction("-@foo bar")
1003 s = act.strfunction([], [], env)
1006 act = SCons.Action.CommandAction("-foo bar")
1007 s = act.strfunction([], [], env)
1008 assert s == "foo bar", s
1010 act = SCons.Action.CommandAction("@ foo bar")
1011 s = act.strfunction([], [], env)
1014 act = SCons.Action.CommandAction("@- foo bar")
1015 s = act.strfunction([], [], env)
1018 act = SCons.Action.CommandAction("-@ foo bar")
1019 s = act.strfunction([], [], env)
1022 act = SCons.Action.CommandAction("- foo bar")
1023 s = act.strfunction([], [], env)
1024 assert s == "foo bar", s
1026 def test_execute(self):
1027 """Test execution of command Actions
1032 except AttributeError:
1035 cmd1 = r'%s %s %s xyzzy' % (_python_, act_py, outfile)
1037 act = SCons.Action.CommandAction(cmd1)
1038 r = act([], [], env.Clone())
1040 c = test.read(outfile, 'r')
1041 assert c == "act.py: 'xyzzy'\n", c
1043 cmd2 = r'%s %s %s $TARGET' % (_python_, act_py, outfile)
1045 act = SCons.Action.CommandAction(cmd2)
1046 r = act(DummyNode('foo'), [], env.Clone())
1048 c = test.read(outfile, 'r')
1049 assert c == "act.py: 'foo'\n", c
1051 cmd3 = r'%s %s %s ${TARGETS}' % (_python_, act_py, outfile)
1053 act = SCons.Action.CommandAction(cmd3)
1054 r = act(list(map(DummyNode, ['aaa', 'bbb'])), [], env.Clone())
1056 c = test.read(outfile, 'r')
1057 assert c == "act.py: 'aaa' 'bbb'\n", c
1059 cmd4 = r'%s %s %s $SOURCES' % (_python_, act_py, outfile)
1061 act = SCons.Action.CommandAction(cmd4)
1062 r = act([], [DummyNode('one'), DummyNode('two')], env.Clone())
1064 c = test.read(outfile, 'r')
1065 assert c == "act.py: 'one' 'two'\n", c
1067 cmd4 = r'%s %s %s ${SOURCES[:2]}' % (_python_, act_py, outfile)
1069 act = SCons.Action.CommandAction(cmd4)
1070 sources = [DummyNode('three'), DummyNode('four'), DummyNode('five')]
1072 r = act([], source = sources, env = env2)
1074 c = test.read(outfile, 'r')
1075 assert c == "act.py: 'three' 'four'\n", c
1077 cmd5 = r'%s %s %s $TARGET XYZZY' % (_python_, act_py, outfile)
1079 act = SCons.Action.CommandAction(cmd5)
1080 env5 = Environment()
1081 if 'ENV' in scons_env:
1082 env5['ENV'] = scons_env['ENV']
1083 PATH = scons_env['ENV'].get('PATH', '')
1088 env5['ENV']['XYZZY'] = 'xyzzy'
1089 r = act(target = DummyNode('out5'), source = [], env = env5)
1091 act = SCons.Action.CommandAction(cmd5)
1092 r = act(target = DummyNode('out5'),
1094 env = env.Clone(ENV = {'XYZZY' : 'xyzzy5',
1097 c = test.read(outfile, 'r')
1098 assert c == "act.py: 'out5' 'XYZZY'\nact.py: 'xyzzy5'\n", c
1101 def __init__(self, str):
1107 def get_subst_proxy(self):
1110 cmd6 = r'%s %s %s ${TARGETS[1]} $TARGET ${SOURCES[:2]}' % (_python_, act_py, outfile)
1112 act = SCons.Action.CommandAction(cmd6)
1113 r = act(target = [Obj('111'), Obj('222')],
1114 source = [Obj('333'), Obj('444'), Obj('555')],
1117 c = test.read(outfile, 'r')
1118 assert c == "act.py: '222' '111' '333' '444'\n", c
1121 # NT treats execs of directories and non-executable files
1122 # as "file not found" errors
1123 expect_nonexistent = 1
1124 expect_nonexecutable_file = 1
1125 expect_nonexecutable_dir = 1
1126 elif sys.platform == 'cygwin':
1127 expect_nonexistent = 127
1128 # Newer cygwin seems to return 126 for following
1129 expect_nonexecutable_file = 126
1130 expect_nonexecutable_dir = 127
1132 expect_nonexistent = 127
1133 expect_nonexecutable_file = 126
1134 expect_nonexecutable_dir = 126
1136 # Test that a nonexistent command returns 127
1137 act = SCons.Action.CommandAction(python + "_no_such_command_")
1138 r = act([], [], env.Clone(out = outfile))
1139 assert r.status == expect_nonexistent, r.status
1141 # Test that trying to execute a directory returns 126
1142 dir, tail = os.path.split(python)
1143 act = SCons.Action.CommandAction(dir)
1144 r = act([], [], env.Clone(out = outfile))
1145 assert r.status == expect_nonexecutable_file, r.status
1147 # Test that trying to execute a non-executable file returns 126
1148 act = SCons.Action.CommandAction(outfile)
1149 r = act([], [], env.Clone(out = outfile))
1150 assert r.status == expect_nonexecutable_dir, r.status
1152 act = SCons.Action.CommandAction('%s %s 1' % (_python_, exit_py))
1153 r = act([], [], env)
1154 assert r.status == 1, r.status
1156 act = SCons.Action.CommandAction('@%s %s 1' % (_python_, exit_py))
1157 r = act([], [], env)
1158 assert r.status == 1, r.status
1160 act = SCons.Action.CommandAction('@-%s %s 1' % (_python_, exit_py))
1161 r = act([], [], env)
1164 act = SCons.Action.CommandAction('-%s %s 1' % (_python_, exit_py))
1165 r = act([], [], env)
1168 act = SCons.Action.CommandAction('@ %s %s 1' % (_python_, exit_py))
1169 r = act([], [], env)
1170 assert r.status == 1, r.status
1172 act = SCons.Action.CommandAction('@- %s %s 1' % (_python_, exit_py))
1173 r = act([], [], env)
1176 act = SCons.Action.CommandAction('- %s %s 1' % (_python_, exit_py))
1177 r = act([], [], env)
1180 def _DO_NOT_EXECUTE_test_pipe_execute(self):
1181 """Test capturing piped output from an action
1183 We used to have PIPE_BUILD support built right into
1184 Action.execute() for the benefit of the SConf subsystem, but we've
1185 moved that logic back into SConf itself. We'll leave this code
1186 here, just in case we ever want to resurrect this functionality
1187 in the future, but change the name of the test so it doesn't
1188 get executed as part of the normal test suite.
1190 pipe = open( pipe_file, "w" )
1191 self.env = Environment(ENV = {'ACTPY_PIPE' : '1'}, PIPE_BUILD = 1,
1192 PSTDOUT = pipe, PSTDERR = pipe)
1193 # everything should also work when piping output
1195 self.env['PSTDOUT'].close()
1196 pipe_out = test.read( pipe_file )
1198 act_out = "act.py: stdout: executed act.py"
1199 act_err = "act.py: stderr: executed act.py"
1201 # Since we are now using select(), stdout and stderr can be
1202 # intermixed, so count the lines separately.
1203 outlines = re.findall(act_out, pipe_out)
1204 errlines = re.findall(act_err, pipe_out)
1205 assert len(outlines) == 6, pipe_out + repr(outlines)
1206 assert len(errlines) == 6, pipe_out + repr(errlines)
1208 # test redirection operators
1209 def test_redirect(self, redir, stdout_msg, stderr_msg):
1210 cmd = r'%s %s %s xyzzy %s' % (_python_, act_py, outfile, redir)
1211 # Write the output and error messages to files because
1212 # Windows can't handle strings that are too big in its
1213 # external environment (os.spawnve() returns EINVAL,
1214 # "Invalid argument").
1215 stdout_file = test.workpath('stdout_msg')
1216 stderr_file = test.workpath('stderr_msg')
1217 open(stdout_file, 'w').write(stdout_msg)
1218 open(stderr_file, 'w').write(stderr_msg)
1219 pipe = open( pipe_file, "w" )
1220 act = SCons.Action.CommandAction(cmd)
1221 env = Environment( ENV = {'ACTPY_PIPE' : '1',
1222 'PIPE_STDOUT_FILE' : stdout_file,
1223 'PIPE_STDERR_FILE' : stderr_file},
1225 PSTDOUT = pipe, PSTDERR = pipe )
1226 r = act([], [], env)
1229 return (test.read(outfile2, 'r'), test.read(pipe_file, 'r'))
1231 (redirected, pipe_out) = test_redirect(self,'> %s' % outfile2,
1233 assert redirected == act_out
1234 assert pipe_out == act_err
1236 (redirected, pipe_out) = test_redirect(self,'2> %s' % outfile2,
1238 assert redirected == act_err
1239 assert pipe_out == act_out
1241 (redirected, pipe_out) = test_redirect(self,'> %s 2>&1' % outfile2,
1243 assert (redirected == act_out + act_err or
1244 redirected == act_err + act_out)
1245 assert pipe_out == ""
1247 act_err = "Long Command Output\n"*3000
1248 # the size of the string should exceed the system's default block size
1250 (redirected, pipe_out) = test_redirect(self,'> %s' % outfile2,
1252 assert (redirected == act_out)
1253 assert (pipe_out == act_err)
1255 def test_set_handler(self):
1256 """Test setting the command handler...
1262 def func(sh, escape, cmd, args, env, test=t):
1263 test.executed = args
1266 def escape_func(cmd):
1267 return '**' + cmd + '**'
1270 def __init__(self, x):
1274 def escape(self, escape_func):
1275 return escape_func(self.data)
1276 def is_literal(self):
1279 a = SCons.Action.CommandAction(["xyzzy"])
1280 e = Environment(SPAWN = func)
1282 assert t.executed == [ 'xyzzy' ], t.executed
1284 a = SCons.Action.CommandAction(["xyzzy"])
1285 e = Environment(SPAWN = '$FUNC', FUNC = func)
1287 assert t.executed == [ 'xyzzy' ], t.executed
1289 a = SCons.Action.CommandAction(["xyzzy"])
1290 e = Environment(SPAWN = func, SHELL = 'fake shell')
1292 assert t.executed == [ 'xyzzy' ], t.executed
1293 assert t.shell == 'fake shell', t.shell
1295 a = SCons.Action.CommandAction([ LiteralStr("xyzzy") ])
1296 e = Environment(SPAWN = func, ESCAPE = escape_func)
1298 assert t.executed == [ '**xyzzy**' ], t.executed
1300 def test_get_contents(self):
1301 """Test fetching the contents of a command Action
1303 def CmdGen(target, source, env, for_signature):
1304 assert for_signature
1306 (env["foo"], env["bar"])
1308 # The number 1 is there to make sure all args get converted to strings.
1309 a = SCons.Action.CommandAction(["|", "$(", "$foo", "|", "$bar",
1310 "$)", "|", "$baz", 1])
1311 c = a.get_contents(target=[], source=[],
1312 env=Environment(foo = 'FFF', bar = 'BBB',
1314 assert c == "| | FFF BBB 1", c
1316 # Make sure that CommandActions use an Environment's
1317 # subst_target_source() method for substitution.
1318 class SpecialEnvironment(Environment):
1319 def subst_target_source(self, strSubst, raw=0, target=[], source=[]):
1320 return 'subst_target_source: ' + strSubst
1322 c = a.get_contents(target=DummyNode('ttt'), source = DummyNode('sss'),
1323 env=SpecialEnvironment(foo = 'GGG', bar = 'CCC',
1325 assert c == 'subst_target_source: | $( $foo | $bar $) | $baz 1', c
1327 # We've discussed using the real target and source names in a
1328 # CommandAction's signature contents. This would have have the
1329 # advantage of recompiling when a file's name changes (keeping
1330 # debug info current), but it would currently break repository
1331 # logic that will change the file name based on whether the
1332 # files come from a repository or locally. If we ever move to
1333 # that scheme, then all of the '__t1__' and '__s6__' file names
1334 # in the asserts below would change to 't1' and 's6' and the
1336 t = list(map(DummyNode, ['t1', 't2', 't3', 't4', 't5', 't6']))
1337 s = list(map(DummyNode, ['s1', 's2', 's3', 's4', 's5', 's6']))
1340 a = SCons.Action.CommandAction(["$TARGET"])
1341 c = a.get_contents(target=t, source=s, env=env)
1344 a = SCons.Action.CommandAction(["$TARGETS"])
1345 c = a.get_contents(target=t, source=s, env=env)
1346 assert c == "t1 t2 t3 t4 t5 t6", c
1348 a = SCons.Action.CommandAction(["${TARGETS[2]}"])
1349 c = a.get_contents(target=t, source=s, env=env)
1352 a = SCons.Action.CommandAction(["${TARGETS[3:5]}"])
1353 c = a.get_contents(target=t, source=s, env=env)
1354 assert c == "t4 t5", c
1356 a = SCons.Action.CommandAction(["$SOURCE"])
1357 c = a.get_contents(target=t, source=s, env=env)
1360 a = SCons.Action.CommandAction(["$SOURCES"])
1361 c = a.get_contents(target=t, source=s, env=env)
1362 assert c == "s1 s2 s3 s4 s5 s6", c
1364 a = SCons.Action.CommandAction(["${SOURCES[2]}"])
1365 c = a.get_contents(target=t, source=s, env=env)
1368 a = SCons.Action.CommandAction(["${SOURCES[3:5]}"])
1369 c = a.get_contents(target=t, source=s, env=env)
1370 assert c == "s4 s5", c
1372 class CommandGeneratorActionTestCase(unittest.TestCase):
1374 def factory(self, act, **kw):
1375 """Pass any keywords as a dict"""
1376 return SCons.Action.CommandGeneratorAction(act, kw)
1378 def test___init__(self):
1379 """Test creation of a command generator Action
1381 def f(target, source, env):
1384 assert a.generator == f
1386 def test___str__(self):
1387 """Test the pre-substitution strings for command generator Actions
1389 def f(target, source, env, for_signature, self=self):
1391 # See if "env" is really a construction environment (or
1392 # looks like one) by accessing the FindIxes attribute.
1393 # (The Tool/mingw.py module has a generator that uses this,
1394 # and the __str__() method used to cause problems by passing
1395 # us a regular dictionary as a fallback.)
1401 assert s == 'FOO', s
1403 def test_genstring(self):
1404 """Test the command generator Action genstring() method
1406 def f(target, source, env, for_signature, self=self):
1407 dummy = env['dummy']
1409 return "$FOO $TARGET $SOURCE $TARGETS $SOURCES"
1412 s = a.genstring([], [], env=Environment(FOO='xyzzy', dummy=1))
1413 assert self.dummy == 1, self.dummy
1414 assert s == "$FOO $TARGET $SOURCE $TARGETS $SOURCES", s
1416 def test_execute(self):
1417 """Test executing a command generator Action
1420 def f(target, source, env, for_signature, self=self):
1421 dummy = env['dummy']
1423 s = env.subst("$FOO")
1424 assert s == 'foo baz\nbar ack', s
1426 def func_action(target, source, env, self=self):
1428 s = env.subst('$foo')
1429 assert s == 'bar', s
1431 def f2(target, source, env, for_signature, f=func_action):
1433 def ch(sh, escape, cmd, args, env, self=self):
1434 self.cmd.append(cmd)
1435 self.args.append(args)
1441 a([], [], env=Environment(FOO = 'foo baz\nbar ack',
1444 assert self.dummy == 1, self.dummy
1445 assert self.cmd == ['foo', 'bar'], self.cmd
1446 assert self.args == [[ 'foo', 'baz' ], [ 'bar', 'ack' ]], self.args
1448 b = self.factory(f2)
1450 b(target=[], source=[], env=Environment(foo = 'bar',
1452 assert self.dummy==2, self.dummy
1456 def __init__(self, t):
1459 self.t.rfile_called = 1
1461 def get_subst_proxy(self):
1463 def f3(target, source, env, for_signature):
1465 c = self.factory(f3)
1466 c(target=[], source=DummyFile(self), env=Environment())
1467 assert self.rfile_called
1469 def test_get_contents(self):
1470 """Test fetching the contents of a command generator Action
1472 def f(target, source, env, for_signature):
1475 assert for_signature, for_signature
1476 return [["guux", foo, "$(", "$ignore", "$)", bar,
1477 '${test("$( foo $bar $)")}' ]]
1480 assert mystr == "$( foo $bar $)", mystr
1483 env = Environment(foo = 'FFF', bar = 'BBB',
1484 ignore = 'foo', test=test)
1486 c = a.get_contents(target=[], source=[], env=env)
1487 assert c == "guux FFF BBB test", c
1489 def test_get_contents_of_function_action(self):
1490 """Test contents of a CommandGeneratorAction-generated FunctionAction
1497 "0,0,0,0,(),(),(d\000\000S),(),()",
1498 "0,0,0,0,(),(),(d\x00\x00S),(),()",
1502 "1,1,0,0,(),(),(d\000\000S),(),()",
1503 "1,1,0,0,(),(),(d\x00\x00S),(),()",
1506 def f_global(target, source, env, for_signature):
1507 return SCons.Action.Action(GlobalFunc)
1510 #def f_local(target, source, env, for_signature):
1511 def f_local(target, source, env, for_signature, LocalFunc=LocalFunc):
1512 return SCons.Action.Action(LocalFunc)
1514 env = Environment(XYZ = 'foo')
1516 a = self.factory(f_global)
1517 c = a.get_contents(target=[], source=[], env=env)
1518 assert c in func_matches, repr(c)
1520 a = self.factory(f_local)
1521 c = a.get_contents(target=[], source=[], env=env)
1522 assert c in func_matches, repr(c)
1524 def f_global(target, source, env, for_signature):
1525 return SCons.Action.Action(GlobalFunc, varlist=['XYZ'])
1528 #def f_local(target, source, env, for_signature):
1529 def f_local(target, source, env, for_signature, LocalFunc=LocalFunc):
1530 return SCons.Action.Action(LocalFunc, varlist=['XYZ'])
1532 matches_foo = [x + "foo" for x in func_matches]
1534 a = self.factory(f_global)
1535 c = a.get_contents(target=[], source=[], env=env)
1536 assert c in matches_foo, repr(c)
1538 a = self.factory(f_local)
1539 c = a.get_contents(target=[], source=[], env=env)
1540 assert c in matches_foo, repr(c)
1543 class FunctionActionTestCase(unittest.TestCase):
1545 def test___init__(self):
1546 """Test creation of a function Action
1557 a = SCons.Action.FunctionAction(func1, {})
1558 assert a.execfunction == func1, a.execfunction
1559 assert isinstance(a.strfunction, types.MethodType), type(a.strfunction)
1561 a = SCons.Action.FunctionAction(func2, { 'strfunction' : func3 })
1562 assert a.execfunction == func2, a.execfunction
1563 assert a.strfunction == func3, a.strfunction
1565 def test___str__(self):
1566 """Test the __str__() method for function Actions
1570 a = SCons.Action.FunctionAction(func1, {})
1572 assert s == "func1(target, source, env)", s
1577 a = SCons.Action.FunctionAction(class1(), {})
1579 assert s == "class1(target, source, env)", s
1581 def test_execute(self):
1582 """Test executing a function Action
1585 def f(target, source, env):
1590 assert env.subst("$BAR") == 'foo bar', env.subst("$BAR")
1592 a = SCons.Action.FunctionAction(f, {})
1593 a(target=1, source=2, env=Environment(BAR = 'foo bar',
1595 assert self.inc == 1, self.inc
1596 assert self.source == [2], self.source
1597 assert self.target == [1], self.target
1601 def function1(target, source, env):
1605 open(t, 'w').write("function1\n")
1608 act = SCons.Action.FunctionAction(function1, {})
1609 r = act(target = [outfile, outfile2], source=[], env=Environment())
1610 assert r.status == 1, r.status
1612 assert count == 1, count
1613 c = test.read(outfile, 'r')
1614 assert c == "function1\n", c
1615 c = test.read(outfile2, 'r')
1616 assert c == "function1\n", c
1619 def __init__(self, target, source, env):
1620 open(env['out'], 'w').write("class1a\n")
1622 act = SCons.Action.FunctionAction(class1a, {})
1623 r = act([], [], Environment(out = outfile))
1624 assert isinstance(r.status, class1a), r.status
1625 c = test.read(outfile, 'r')
1626 assert c == "class1a\n", c
1629 def __call__(self, target, source, env):
1630 open(env['out'], 'w').write("class1b\n")
1633 act = SCons.Action.FunctionAction(class1b(), {})
1634 r = act([], [], Environment(out = outfile))
1635 assert r.status == 2, r.status
1636 c = test.read(outfile, 'r')
1637 assert c == "class1b\n", c
1639 def build_it(target, source, env, executor=None, self=self):
1642 def string_it(target, source, env, executor=None, self=self):
1645 act = SCons.Action.FunctionAction(build_it,
1646 { 'strfunction' : string_it })
1647 r = act([], [], Environment())
1649 assert self.build_it
1650 assert self.string_it
1652 def test_get_contents(self):
1653 """Test fetching the contents of a function Action
1660 "0,0,0,0,(),(),(d\000\000S),(),()",
1661 "0,0,0,0,(),(),(d\x00\x00S),(),()",
1665 "1,1,0,0,(),(),(d\000\000S),(),()",
1666 "1,1,0,0,(),(),(d\x00\x00S),(),()",
1669 def factory(act, **kw):
1670 return SCons.Action.FunctionAction(act, kw)
1672 a = factory(GlobalFunc)
1673 c = a.get_contents(target=[], source=[], env=Environment())
1674 assert c in func_matches, repr(c)
1676 a = factory(LocalFunc)
1677 c = a.get_contents(target=[], source=[], env=Environment())
1678 assert c in func_matches, repr(c)
1680 matches_foo = [x + "foo" for x in func_matches]
1682 a = factory(GlobalFunc, varlist=['XYZ'])
1683 c = a.get_contents(target=[], source=[], env=Environment())
1684 assert c in func_matches, repr(c)
1685 c = a.get_contents(target=[], source=[], env=Environment(XYZ='foo'))
1686 assert c in matches_foo, repr(c)
1688 ##TODO: is this set of tests still needed?
1689 # Make sure a bare string varlist works
1690 a = factory(GlobalFunc, varlist='XYZ')
1691 c = a.get_contents(target=[], source=[], env=Environment())
1692 assert c in func_matches, repr(c)
1693 c = a.get_contents(target=[], source=[], env=Environment(XYZ='foo'))
1694 assert c in matches_foo, repr(c)
1697 def get_contents(self, target, source, env):
1700 c = a.get_contents(target=[], source=[], env=Environment())
1701 assert c == 'xyzzy', repr(c)
1704 def LocalMethod(self):
1707 a = factory(lc.LocalMethod)
1708 c = a.get_contents(target=[], source=[], env=Environment())
1709 assert c in meth_matches, repr(c)
1711 def test_strfunction(self):
1712 """Test the FunctionAction.strfunction() method
1717 def factory(act, **kw):
1718 return SCons.Action.FunctionAction(act, kw)
1721 s = a.strfunction(target=[], source=[], env=Environment())
1722 assert s == 'func([], [])', s
1724 a = factory(func, strfunction=None)
1725 s = a.strfunction(target=[], source=[], env=Environment())
1728 a = factory(func, cmdstr='function')
1729 s = a.strfunction(target=[], source=[], env=Environment())
1730 assert s == 'function', s
1732 class ListActionTestCase(unittest.TestCase):
1734 def test___init__(self):
1735 """Test creation of a list of subsidiary Actions
1739 a = SCons.Action.ListAction(["x", func, ["y", "z"]])
1740 assert isinstance(a.list[0], SCons.Action.CommandAction)
1741 assert isinstance(a.list[1], SCons.Action.FunctionAction)
1742 assert isinstance(a.list[2], SCons.Action.ListAction)
1743 assert a.list[2].list[0].cmd_list == 'y'
1745 def test___str__(self):
1746 """Test the __str__() method for a list of subsidiary Actions
1748 def f(target,source,env):
1750 def g(target,source,env):
1752 a = SCons.Action.ListAction([f, g, "XXX", f])
1754 assert s == "f(target, source, env)\ng(target, source, env)\nXXX\nf(target, source, env)", s
1756 def test_genstring(self):
1757 """Test the genstring() method for a list of subsidiary Actions
1759 def f(target,source,env):
1761 def g(target,source,env,for_signature):
1762 return 'generated %s %s' % (target[0], source[0])
1763 g = SCons.Action.Action(g, generator=1)
1764 a = SCons.Action.ListAction([f, g, "XXX", f])
1765 s = a.genstring(['foo.x'], ['bar.y'], Environment())
1766 assert s == "f(target, source, env)\ngenerated foo.x bar.y\nXXX\nf(target, source, env)", s
1768 def test_execute(self):
1769 """Test executing a list of subsidiary Actions
1772 def f(target,source,env):
1775 a = SCons.Action.ListAction([f, f, f])
1776 a([], [], Environment(s = self))
1777 assert self.inc == 3, self.inc
1779 cmd2 = r'%s %s %s syzygy' % (_python_, act_py, outfile)
1781 def function2(target, source, env):
1782 open(env['out'], 'a').write("function2\n")
1786 def __call__(self, target, source, env):
1787 open(env['out'], 'a').write("class2a\n")
1791 def __init__(self, target, source, env):
1792 open(env['out'], 'a').write("class2b\n")
1793 act = SCons.Action.ListAction([cmd2, function2, class2a(), class2b])
1794 r = act([], [], Environment(out = outfile))
1795 assert isinstance(r.status, class2b), r.status
1796 c = test.read(outfile, 'r')
1797 assert c == "act.py: 'syzygy'\nfunction2\nclass2a\nclass2b\n", c
1799 def test_get_contents(self):
1800 """Test fetching the contents of a list of subsidiary Actions
1803 def gen(target, source, env, for_signature):
1807 a = SCons.Action.ListAction(["x",
1808 SCons.Action.Action(gen, generator=1),
1810 c = a.get_contents(target=[], source=[], env=Environment(s = self))
1811 assert self.foo==1, self.foo
1812 assert c == "xyz", c
1814 class LazyActionTestCase(unittest.TestCase):
1815 def test___init__(self):
1816 """Test creation of a lazy-evaluation Action
1818 # Environment variable references should create a special type
1819 # of LazyAction that lazily evaluates the variable for whether
1820 # it's a string or something else before doing anything.
1821 a9 = SCons.Action.Action('$FOO')
1822 assert isinstance(a9, SCons.Action.LazyAction), a9
1823 assert a9.var == 'FOO', a9.var
1825 a10 = SCons.Action.Action('${FOO}')
1826 assert isinstance(a10, SCons.Action.LazyAction), a10
1827 assert a10.var == 'FOO', a10.var
1829 def test_genstring(self):
1830 """Test the lazy-evaluation Action genstring() method
1832 def f(target, source, env):
1834 a = SCons.Action.Action('$BAR')
1835 env1 = Environment(BAR=f, s=self)
1836 env2 = Environment(BAR='xxx', s=self)
1837 s = a.genstring([], [], env=env1)
1838 assert s == "f(target, source, env)", s
1839 s = a.genstring([], [], env=env2)
1840 assert s == 'xxx', s
1842 def test_execute(self):
1843 """Test executing a lazy-evaluation Action
1845 def f(target, source, env):
1849 a = SCons.Action.Action('$BAR')
1850 a([], [], env=Environment(BAR = f, s = self))
1851 assert self.test == 1, self.test
1852 cmd = r'%s %s %s lazy' % (_python_, act_py, outfile)
1853 a([], [], env=Environment(BAR = cmd, s = self))
1854 c = test.read(outfile, 'r')
1855 assert c == "act.py: 'lazy'\n", c
1857 def test_get_contents(self):
1858 """Test fetching the contents of a lazy-evaluation Action
1860 a = SCons.Action.Action("${FOO}")
1861 env = Environment(FOO = [["This", "is", "a", "test"]])
1862 c = a.get_contents(target=[], source=[], env=env)
1863 assert c == "This is a test", c
1865 def test_get_contents_of_function_action(self):
1866 """Test fetching the contents of a lazy-evaluation FunctionAction
1873 "0,0,0,0,(),(),(d\000\000S),(),()",
1874 "0,0,0,0,(),(),(d\x00\x00S),(),()",
1878 "1,1,0,0,(),(),(d\000\000S),(),()",
1879 "1,1,0,0,(),(),(d\x00\x00S),(),()",
1882 def factory(act, **kw):
1883 return SCons.Action.FunctionAction(act, kw)
1886 a = SCons.Action.Action("${FOO}")
1888 env = Environment(FOO = factory(GlobalFunc))
1889 c = a.get_contents(target=[], source=[], env=env)
1890 assert c in func_matches, repr(c)
1892 env = Environment(FOO = factory(LocalFunc))
1893 c = a.get_contents(target=[], source=[], env=env)
1894 assert c in func_matches, repr(c)
1896 matches_foo = [x + "foo" for x in func_matches]
1898 env = Environment(FOO = factory(GlobalFunc, varlist=['XYZ']))
1899 c = a.get_contents(target=[], source=[], env=env)
1900 assert c in func_matches, repr(c)
1903 c = a.get_contents(target=[], source=[], env=env)
1904 assert c in matches_foo, repr(c)
1906 class ActionCallerTestCase(unittest.TestCase):
1907 def test___init__(self):
1908 """Test creation of an ActionCaller"""
1909 ac = SCons.Action.ActionCaller(1, [2, 3], {'FOO' : 4, 'BAR' : 5})
1910 assert ac.parent == 1, ac.parent
1911 assert ac.args == [2, 3], ac.args
1912 assert ac.kw == {'FOO' : 4, 'BAR' : 5}, ac.kw
1914 def test_get_contents(self):
1915 """Test fetching the contents of an ActionCaller"""
1927 af = SCons.Action.ActionFactory(GlobalFunc, strfunc)
1928 ac = SCons.Action.ActionCaller(af, [], {})
1929 c = ac.get_contents([], [], Environment())
1930 assert c in matches, repr(c)
1932 af = SCons.Action.ActionFactory(LocalFunc, strfunc)
1933 ac = SCons.Action.ActionCaller(af, [], {})
1934 c = ac.get_contents([], [], Environment())
1935 assert c in matches, repr(c)
1946 af = SCons.Action.ActionFactory(GlobalActFunc(), strfunc)
1947 ac = SCons.Action.ActionCaller(af, [], {})
1948 c = ac.get_contents([], [], Environment())
1949 assert c in matches, repr(c)
1951 af = SCons.Action.ActionFactory(LocalActFunc(), strfunc)
1952 ac = SCons.Action.ActionCaller(af, [], {})
1953 c = ac.get_contents([], [], Environment())
1954 assert c in matches, repr(c)
1957 "<built-in function str>",
1961 af = SCons.Action.ActionFactory(str, strfunc)
1962 ac = SCons.Action.ActionCaller(af, [], {})
1963 c = ac.get_contents([], [], Environment())
1964 assert c == "<built-in function str>" or \
1965 c == "<type 'str'>", repr(c)
1967 def test___call__(self):
1968 """Test calling an ActionCaller"""
1970 def actfunc(a1, a2, a3, args=actfunc_args):
1971 args.extend([a1, a2, a3])
1972 def strfunc(a1, a2, a3):
1975 e = Environment(FOO = 2, BAR = 5)
1977 af = SCons.Action.ActionFactory(actfunc, strfunc)
1978 ac = SCons.Action.ActionCaller(af, ['$__env__', '$FOO', 3], {})
1980 assert actfunc_args[0] is e, actfunc_args
1981 assert actfunc_args[1] == '2', actfunc_args
1982 assert actfunc_args[2] == 3, actfunc_args
1985 ac = SCons.Action.ActionCaller(af, [], {'a3' : '$__env__', 'a2' : '$BAR', 'a1' : 4})
1987 assert actfunc_args[0] == 4, actfunc_args
1988 assert actfunc_args[1] == '5', actfunc_args
1989 assert actfunc_args[2] is e, actfunc_args
1992 def test_strfunction(self):
1993 """Test calling the ActionCaller strfunction() method"""
1995 def actfunc(a1, a2, a3, a4):
1997 def strfunc(a1, a2, a3, a4, args=strfunc_args):
1998 args.extend([a1, a2, a3, a4])
2000 af = SCons.Action.ActionFactory(actfunc, strfunc)
2001 ac = SCons.Action.ActionCaller(af, [1, '$FOO', 3, '$WS'], {})
2002 ac.strfunction([], [], Environment(FOO = 2, WS='white space'))
2003 assert strfunc_args == [1, '2', 3, 'white space'], strfunc_args
2006 d = {'a3' : 6, 'a2' : '$BAR', 'a1' : 4, 'a4' : '$WS'}
2007 ac = SCons.Action.ActionCaller(af, [], d)
2008 ac.strfunction([], [], Environment(BAR = 5, WS='w s'))
2009 assert strfunc_args == [4, '5', 6, 'w s'], strfunc_args
2011 class ActionFactoryTestCase(unittest.TestCase):
2012 def test___init__(self):
2013 """Test creation of an ActionFactory"""
2018 ac = SCons.Action.ActionFactory(actfunc, strfunc)
2019 assert ac.actfunc is actfunc, ac.actfunc
2020 assert ac.strfunc is strfunc, ac.strfunc
2022 def test___call__(self):
2023 """Test calling whatever's returned from an ActionFactory"""
2026 def actfunc(a1, a2, a3, args=actfunc_args):
2027 args.extend([a1, a2, a3])
2028 def strfunc(a1, a2, a3, args=strfunc_args):
2029 args.extend([a1, a2, a3])
2030 af = SCons.Action.ActionFactory(actfunc, strfunc)
2031 af(3, 6, 9)([], [], Environment())
2032 assert actfunc_args == [3, 6, 9], actfunc_args
2033 assert strfunc_args == [3, 6, 9], strfunc_args
2036 class ActionCompareTestCase(unittest.TestCase):
2038 def test_1_solo_name(self):
2039 """Test Lazy Cmd Generator Action get_name alone.
2041 Basically ensures we can locate the builder, comparing it to
2042 itself along the way."""
2043 bar = SCons.Builder.Builder(action = {})
2044 env = Environment( BUILDERS = {'BAR' : bar} )
2045 name = bar.get_name(env)
2046 assert name == 'BAR', name
2048 def test_2_multi_name(self):
2049 """Test LazyCmdGenerator Action get_name multi builders.
2051 Ensure that we can compare builders (and thereby actions) to
2052 each other safely."""
2053 foo = SCons.Builder.Builder(action = '$FOO', suffix = '.foo')
2054 bar = SCons.Builder.Builder(action = {})
2056 assert foo.action != bar.action
2057 env = Environment( BUILDERS = {'FOO' : foo,
2059 name = foo.get_name(env)
2060 assert name == 'FOO', name
2061 name = bar.get_name(env)
2062 assert name == 'BAR', name
2064 def test_3_dict_names(self):
2065 """Test Action/Suffix dicts with get_name.
2067 Verifies that Action/Suffix dictionaries work correctly,
2068 especially two builders that can generate the same suffix,
2069 where one of the builders has a suffix dictionary with a None
2072 foo = SCons.Builder.Builder(action = '$FOO', suffix = '.foo')
2073 bar = SCons.Builder.Builder(action = {}, suffix={None:'.bar'})
2074 bar.add_action('.cow', "$MOO")
2075 dog = SCons.Builder.Builder(suffix = '.bar')
2077 env = Environment( BUILDERS = {'FOO' : foo,
2081 assert foo.get_name(env) == 'FOO', foo.get_name(env)
2082 assert bar.get_name(env) == 'BAR', bar.get_name(env)
2083 assert dog.get_name(env) == 'DOG', dog.get_name(env)
2086 if __name__ == "__main__":
2087 suite = unittest.TestSuite()
2088 tclasses = [ _ActionActionTestCase,
2090 CommandActionTestCase,
2091 CommandGeneratorActionTestCase,
2092 FunctionActionTestCase,
2095 ActionCallerTestCase,
2096 ActionFactoryTestCase,
2097 ActionCompareTestCase ]
2098 for tclass in tclasses:
2099 names = unittest.getTestCaseNames(tclass, 'test_')
2100 suite.addTests(list(map(tclass, names)))
2101 if not unittest.TextTestRunner().run(suite).wasSuccessful():
2106 # indent-tabs-mode:nil
2108 # vim: set expandtab tabstop=4 shiftwidth=4: