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__"
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.
46 import SCons.Environment
51 # Initial setup of the common environment for all tests,
52 # a temporary working directory containing a
53 # script for writing arguments to an output file.
55 # We don't do this as a setUp() method because it's
56 # unnecessary to create a separate directory and script
57 # for each test, they can just use the one.
58 test = TestCmd.TestCmd(workdir = '')
60 test.write('act.py', """\
61 import os, string, sys
62 f = open(sys.argv[1], 'w')
63 f.write("act.py: '" + string.join(sys.argv[2:], "' '") + "'\\n")
66 f.write("act.py: '" + os.environ[sys.argv[3]] + "'\\n")
70 if 'ACTPY_PIPE' in os.environ:
71 if 'PIPE_STDOUT_FILE' in os.environ:
72 stdout_msg = open(os.environ['PIPE_STDOUT_FILE'], 'r').read()
74 stdout_msg = "act.py: stdout: executed act.py %s\\n" % ' '.join(sys.argv[1:])
75 sys.stdout.write( stdout_msg )
76 if 'PIPE_STDERR_FILE' in os.environ:
77 stderr_msg = open(os.environ['PIPE_STDERR_FILE'], 'r').read()
79 stderr_msg = "act.py: stderr: executed act.py %s\\n" % ' '.join(sys.argv[1:])
80 sys.stderr.write( stderr_msg )
84 test.write('exit.py', """\
86 sys.exit(int(sys.argv[1]))
89 act_py = test.workpath('act.py')
90 exit_py = test.workpath('exit.py')
92 outfile = test.workpath('outfile')
93 outfile2 = test.workpath('outfile2')
94 pipe_file = test.workpath('pipe.out')
96 scons_env = SCons.Environment.Environment()
98 # Capture all the stuff the Actions will print,
99 # so it doesn't clutter the output.
100 sys.stdout = StringIO.StringIO()
102 class CmdStringHolder:
103 def __init__(self, cmd, literal=None):
105 self.literal = literal
107 def is_literal(self):
110 def escape(self, escape_func):
111 """Escape the string with the supplied function. The
112 function is expected to take an arbitrary string, then
113 return it with all special characters escaped and ready
114 for passing to the command interpreter.
116 After calling this function, the next call to str() will
117 return the escaped string.
120 if self.is_literal():
121 return escape_func(self.data)
122 elif ' ' in self.data or '\t' in self.data:
123 return '"%s"' % self.data
128 def __init__(self, **kw):
130 self.d['SHELL'] = scons_env['SHELL']
131 self.d['SPAWN'] = scons_env['SPAWN']
132 self.d['PSPAWN'] = scons_env['PSPAWN']
133 self.d['ESCAPE'] = scons_env['ESCAPE']
134 for k, v in kw.items():
136 # Just use the underlying scons_subst*() utility methods.
137 def subst(self, strSubst, raw=0, target=[], source=[], conv=None):
138 return SCons.Subst.scons_subst(strSubst, self, raw,
139 target, source, self.d, conv=conv)
140 subst_target_source = subst
141 def subst_list(self, strSubst, raw=0, target=[], source=[], conv=None):
142 return SCons.Subst.scons_subst_list(strSubst, self, raw,
143 target, source, self.d, conv=conv)
144 def __getitem__(self, item):
146 def __setitem__(self, item, value):
148 def has_key(self, item):
149 return item in self.d
150 def get(self, key, value=None):
151 return self.d.get(key, value)
153 return self.d.items()
154 def Dictionary(self):
156 def Clone(self, **kw):
158 res.d = SCons.Util.semi_deepcopy(self.d)
159 for k, v in kw.items():
164 for k,v in self.items(): d[k] = v
165 d['TARGETS'] = ['__t1__', '__t2__', '__t3__', '__t4__', '__t5__', '__t6__']
166 d['TARGET'] = d['TARGETS'][0]
167 d['SOURCES'] = ['__s1__', '__s2__', '__s3__', '__s4__', '__s5__', '__s6__']
168 d['SOURCE'] = d['SOURCES'][0]
172 def __init__(self, name):
174 def str_for_display(self):
175 return '"' + self.name + '"'
180 def get_subst_proxy(self):
183 if os.name == 'java':
184 python = os.path.join(sys.prefix, 'jython')
186 python = sys.executable
188 _python_ = '"' + python + '"'
190 _null = SCons.Action._null
192 def test_varlist(pos_call, str_call, cmd, cmdstrfunc, **kw):
193 def call_action(a, pos_call=pos_call, str_call=str_call, kw=kw):
194 #FUTURE a = SCons.Action.Action(*a, **kw)
195 a = SCons.Action.Action(*a, **kw)
196 # returned object must provide these entry points
197 assert hasattr(a, '__call__')
198 assert hasattr(a, 'get_contents')
199 assert hasattr(a, 'genstring')
204 a = call_action((cmd, cmdstrfunc))
205 assert a.varlist == (), a.varlist
207 a = call_action((cmd, cmdstrfunc, 'foo'))
208 assert a.varlist == ('foo',), a.varlist
210 a = call_action((cmd, cmdstrfunc, 'a', 'b', 'c'))
211 assert a.varlist == ('a', 'b', 'c'), a.varlist
213 kw['varlist'] = 'foo'
214 a = call_action((cmd, cmdstrfunc))
215 assert a.varlist == ('foo',), a.varlist
217 kw['varlist'] = ['x', 'y', 'z']
218 a = call_action((cmd, cmdstrfunc))
219 assert a.varlist == ('x', 'y', 'z'), a.varlist
221 a = call_action((cmd, cmdstrfunc, 'foo'))
222 assert a.varlist == ('foo', 'x', 'y', 'z'), a.varlist
224 a = call_action((cmd, cmdstrfunc, 'a', 'b', 'c'))
225 assert a.varlist == ('a', 'b', 'c', 'x', 'y', 'z'), a.varlist
227 def test_positional_args(pos_callback, cmd, **kw):
228 """Test that Action() returns the expected type and that positional args work.
230 #FUTURE act = SCons.Action.Action(cmd, **kw)
231 act = SCons.Action.Action(cmd, **kw)
233 assert act.varlist is (), act.varlist
235 if not isinstance(act, SCons.Action._ActionAction):
236 # only valid cmdstrfunc is None
238 #FUTURE test_varlist(pos_callback, none, cmd, None, **kw)
239 test_varlist(pos_callback, none, cmd, None, **kw)
241 # _ActionAction should have set these
242 assert hasattr(act, 'strfunction')
243 assert act.cmdstr is _null, act.cmdstr
244 assert act.presub is _null, act.presub
245 assert act.chdir is None, act.chdir
246 assert act.exitstatfunc is SCons.Action.default_exitstatfunc, \
250 assert hasattr(a, 'strfunction')
251 assert a.cmdstr == 'cmdstr', a.cmdstr
252 #FUTURE test_varlist(pos_callback, cmdstr, cmd, 'cmdstr', **kw)
253 test_varlist(pos_callback, cmdstr, cmd, 'cmdstr', **kw)
256 def strfun(a, fun=fun):
257 assert a.strfunction is fun, a.strfunction
258 assert a.cmdstr == _null, a.cmdstr
259 #FUTURE test_varlist(pos_callback, strfun, cmd, fun, **kw)
260 test_varlist(pos_callback, strfun, cmd, fun, **kw)
263 assert hasattr(a, 'strfunction')
264 assert a.cmdstr is None, a.cmdstr
265 #FUTURE test_varlist(pos_callback, none, cmd, None, **kw)
266 test_varlist(pos_callback, none, cmd, None, **kw)
268 """Test handling of bad cmdstrfunc arguments """
270 #FUTURE a = SCons.Action.Action(cmd, [], **kw)
271 a = SCons.Action.Action(cmd, [], **kw)
272 except SCons.Errors.UserError, e:
274 m = 'Invalid command display variable'
275 assert s.find(m) != -1, 'Unexpected string: %s' % s
277 raise Exception, "did not catch expected UserError"
281 class ActionTestCase(unittest.TestCase):
282 """Test the Action() factory function"""
284 def test_FunctionAction(self):
285 """Test the Action() factory's creation of FunctionAction objects
290 def func_action(a, foo=foo):
291 assert isinstance(a, SCons.Action.FunctionAction), a
292 assert a.execfunction == foo, a.execfunction
293 test_positional_args(func_action, foo)
294 # a singleton list returns the contained action
295 test_positional_args(func_action, [foo])
297 def test_CommandAction(self):
298 """Test the Action() factory's creation of CommandAction objects
301 assert isinstance(a, SCons.Action.CommandAction), a
302 assert a.cmd_list == "string", a.cmd_list
303 test_positional_args(cmd_action, "string")
304 # a singleton list returns the contained action
305 test_positional_args(cmd_action, ["string"])
308 except NameError: pass
310 a2 = eval("SCons.Action.Action(u'string')")
311 assert isinstance(a2, SCons.Action.CommandAction), a2
314 assert isinstance(a, SCons.Action.CommandAction), a
315 assert a.cmd_list == [ "explicit", "command", "line" ], a.cmd_list
316 test_positional_args(line_action, [[ "explicit", "command", "line" ]])
318 def test_ListAction(self):
319 """Test the Action() factory's creation of ListAction objects
321 a1 = SCons.Action.Action(["x", "y", "z", [ "a", "b", "c"]])
322 assert isinstance(a1, SCons.Action.ListAction), a1
323 assert a1.varlist is (), a1.varlist
324 assert isinstance(a1.list[0], SCons.Action.CommandAction), a1.list[0]
325 assert a1.list[0].cmd_list == "x", a1.list[0].cmd_list
326 assert isinstance(a1.list[1], SCons.Action.CommandAction), a1.list[1]
327 assert a1.list[1].cmd_list == "y", a1.list[1].cmd_list
328 assert isinstance(a1.list[2], SCons.Action.CommandAction), a1.list[2]
329 assert a1.list[2].cmd_list == "z", a1.list[2].cmd_list
330 assert isinstance(a1.list[3], SCons.Action.CommandAction), a1.list[3]
331 assert a1.list[3].cmd_list == [ "a", "b", "c" ], a1.list[3].cmd_list
333 a2 = SCons.Action.Action("x\ny\nz")
334 assert isinstance(a2, SCons.Action.ListAction), a2
335 assert a2.varlist is (), a2.varlist
336 assert isinstance(a2.list[0], SCons.Action.CommandAction), a2.list[0]
337 assert a2.list[0].cmd_list == "x", a2.list[0].cmd_list
338 assert isinstance(a2.list[1], SCons.Action.CommandAction), a2.list[1]
339 assert a2.list[1].cmd_list == "y", a2.list[1].cmd_list
340 assert isinstance(a2.list[2], SCons.Action.CommandAction), a2.list[2]
341 assert a2.list[2].cmd_list == "z", a2.list[2].cmd_list
346 a3 = SCons.Action.Action(["x", foo, "z"])
347 assert isinstance(a3, SCons.Action.ListAction), a3
348 assert a3.varlist is (), a3.varlist
349 assert isinstance(a3.list[0], SCons.Action.CommandAction), a3.list[0]
350 assert a3.list[0].cmd_list == "x", a3.list[0].cmd_list
351 assert isinstance(a3.list[1], SCons.Action.FunctionAction), a3.list[1]
352 assert a3.list[1].execfunction == foo, a3.list[1].execfunction
353 assert isinstance(a3.list[2], SCons.Action.CommandAction), a3.list[2]
354 assert a3.list[2].cmd_list == "z", a3.list[2].cmd_list
356 a4 = SCons.Action.Action(["x", "y"], strfunction=foo)
357 assert isinstance(a4, SCons.Action.ListAction), a4
358 assert a4.varlist is (), a4.varlist
359 assert isinstance(a4.list[0], SCons.Action.CommandAction), a4.list[0]
360 assert a4.list[0].cmd_list == "x", a4.list[0].cmd_list
361 assert a4.list[0].strfunction == foo, a4.list[0].strfunction
362 assert isinstance(a4.list[1], SCons.Action.CommandAction), a4.list[1]
363 assert a4.list[1].cmd_list == "y", a4.list[1].cmd_list
364 assert a4.list[1].strfunction == foo, a4.list[1].strfunction
366 a5 = SCons.Action.Action("x\ny", strfunction=foo)
367 assert isinstance(a5, SCons.Action.ListAction), a5
368 assert a5.varlist is (), a5.varlist
369 assert isinstance(a5.list[0], SCons.Action.CommandAction), a5.list[0]
370 assert a5.list[0].cmd_list == "x", a5.list[0].cmd_list
371 assert a5.list[0].strfunction == foo, a5.list[0].strfunction
372 assert isinstance(a5.list[1], SCons.Action.CommandAction), a5.list[1]
373 assert a5.list[1].cmd_list == "y", a5.list[1].cmd_list
374 assert a5.list[1].strfunction == foo, a5.list[1].strfunction
376 def test_CommandGeneratorAction(self):
377 """Test the Action() factory's creation of CommandGeneratorAction objects
381 def gen_action(a, foo=foo):
382 assert isinstance(a, SCons.Action.CommandGeneratorAction), a
383 assert a.generator is foo, a.generator
384 test_positional_args(gen_action, foo, generator=1)
386 def test_LazyCmdGeneratorAction(self):
387 """Test the Action() factory's creation of lazy CommandGeneratorAction objects
390 assert isinstance(a, SCons.Action.LazyAction), a
391 assert a.var == "FOO", a.var
392 assert a.cmd_list == "${FOO}", a.cmd_list
393 test_positional_args(lazy_action, "$FOO")
394 test_positional_args(lazy_action, "${FOO}")
396 def test_no_action(self):
397 """Test when the Action() factory can't create an action object
399 a5 = SCons.Action.Action(1)
400 assert a5 is None, a5
402 def test_reentrance(self):
403 """Test the Action() factory when the action is already an Action object
405 a1 = SCons.Action.Action("foo")
406 a2 = SCons.Action.Action(a1)
409 class _ActionActionTestCase(unittest.TestCase):
411 def test__init__(self):
412 """Test creation of _ActionAction objects
424 a = SCons.Action._ActionAction()
425 assert not hasattr(a, 'strfunction')
426 assert a.cmdstr is _null, a.cmdstr
427 assert a.varlist == (), a.varlist
428 assert a.presub is _null, a.presub
429 assert a.chdir is None, a.chdir
430 assert a.exitstatfunc is SCons.Action.default_exitstatfunc, a.exitstatfunc
432 assert SCons.Action._ActionAction(kwarg = 1)
433 assert not hasattr(a, 'kwarg')
434 assert not hasattr(a, 'strfunction')
435 assert a.cmdstr is _null, a.cmdstr
436 assert a.varlist == (), a.varlist
437 assert a.presub is _null, a.presub
438 assert a.chdir is None, a.chdir
439 assert a.exitstatfunc is SCons.Action.default_exitstatfunc, a.exitstatfunc
441 a = SCons.Action._ActionAction(strfunction=func1)
442 assert a.strfunction is func1, a.strfunction
444 a = SCons.Action._ActionAction(strfunction=None)
445 assert not hasattr(a, 'strfunction')
446 assert a.cmdstr is None, a.cmdstr
448 a = SCons.Action._ActionAction(cmdstr='cmdstr')
449 assert not hasattr(a, 'strfunction')
450 assert a.cmdstr is 'cmdstr', a.cmdstr
452 a = SCons.Action._ActionAction(cmdstr=None)
453 assert not hasattr(a, 'strfunction')
454 assert a.cmdstr is None, a.cmdstr
457 a = SCons.Action._ActionAction(varlist=t)
458 assert a.varlist == t, a.varlist
460 a = SCons.Action._ActionAction(presub=func1)
461 assert a.presub is func1, a.presub
463 a = SCons.Action._ActionAction(chdir=1)
464 assert a.chdir is 1, a.chdir
466 a = SCons.Action._ActionAction(exitstatfunc=func1)
467 assert a.exitstatfunc is func1, a.exitstatfunc
469 a = SCons.Action._ActionAction(
470 # alphabetical order ...
478 assert a.chdir is 'x', a.chdir
479 assert a.cmdstr is 'cmdstr', a.cmdstr
480 assert a.exitstatfunc is func3, a.exitstatfunc
481 assert a.presub is func2, a.presub
482 assert a.strfunction is func1, a.strfunction
483 assert a.varlist is t, a.varlist
485 def test_dup_keywords(self):
486 """Test handling of both cmdstr and strfunction arguments
490 a = SCons.Action.Action('foo', cmdstr='string', strfunction=func)
491 except SCons.Errors.UserError, e:
493 m = 'Cannot have both strfunction and cmdstr args to Action()'
494 assert s.find(m) != -1, 'Unexpected string: %s' % s
496 raise Exception, "did not catch expected UserError"
498 def test___cmp__(self):
499 """Test Action comparison
501 a1 = SCons.Action.Action("x")
502 a2 = SCons.Action.Action("x")
504 a3 = SCons.Action.Action("y")
508 def test_print_cmd_lines(self):
509 """Test the print_cmd_lines() method
511 save_stdout = sys.stdout
514 def execfunc(target, source, env):
516 a = SCons.Action.Action(execfunc)
518 sio = StringIO.StringIO()
520 a.print_cmd_line("foo bar", None, None, None)
522 assert s == "foo bar\n", s
525 sys.stdout = save_stdout
527 def test___call__(self):
528 """Test calling an Action
530 save_stdout = sys.stdout
532 save_print_actions = SCons.Action.print_actions
533 save_print_actions_presub = SCons.Action.print_actions_presub
534 save_execute_actions = SCons.Action.execute_actions
535 #SCons.Action.print_actions = 0
537 test = TestCmd.TestCmd(workdir = '')
538 test.subdir('sub', 'xyz')
539 os.chdir(test.workpath())
544 def execfunc(target, source, env):
545 assert isinstance(target, list), type(target)
546 assert isinstance(source, list), type(source)
548 a = SCons.Action.Action(execfunc)
550 def firstfunc(target, source, env):
551 assert isinstance(target, list), type(target)
552 assert isinstance(source, list), type(source)
554 def lastfunc(target, source, env):
555 assert isinstance(target, list), type(target)
556 assert isinstance(source, list), type(source)
558 b = SCons.Action.Action([firstfunc, execfunc, lastfunc])
560 sio = StringIO.StringIO()
562 result = a("out", "in", env)
563 assert result.status == 7, result
565 assert s == "execfunc(['out'], ['in'])\n", s
568 expect = "os.chdir(%s)\nexecfunc(['out'], ['in'])\nos.chdir(%s)\n"
570 sio = StringIO.StringIO()
572 result = a("out", "in", env)
573 assert result.status == 7, result.status
575 assert s == expect % (repr('xyz'), repr(test.workpath())), s
577 sio = StringIO.StringIO()
579 result = a("out", "in", env, chdir='sub')
580 assert result.status == 7, result.status
582 assert s == expect % (repr('sub'), repr(test.workpath())), s
586 sio = StringIO.StringIO()
588 result = b("out", "in", env)
589 assert result.status == 7, result.status
591 assert s == "firstfunc(['out'], ['in'])\nexecfunc(['out'], ['in'])\n", s
593 SCons.Action.execute_actions = 0
595 sio = StringIO.StringIO()
597 result = a("out", "in", env)
598 assert result == 0, result
600 assert s == "execfunc(['out'], ['in'])\n", s
602 sio = StringIO.StringIO()
604 result = b("out", "in", env)
605 assert result == 0, result
607 assert s == "firstfunc(['out'], ['in'])\nexecfunc(['out'], ['in'])\nlastfunc(['out'], ['in'])\n", s
609 SCons.Action.print_actions_presub = 1
610 SCons.Action.execute_actions = 1
612 sio = StringIO.StringIO()
614 result = a("out", "in", env)
615 assert result.status == 7, result.status
617 assert s == "Building out with action:\n execfunc(target, source, env)\nexecfunc(['out'], ['in'])\n", s
619 sio = StringIO.StringIO()
621 result = a("out", "in", env, presub=0)
622 assert result.status == 7, result.status
624 assert s == "execfunc(['out'], ['in'])\n", s
626 sio = StringIO.StringIO()
628 result = a("out", "in", env, presub=1)
629 assert result.status == 7, result.status
631 assert s == "Building out with action:\n execfunc(target, source, env)\nexecfunc(['out'], ['in'])\n", s
633 sio = StringIO.StringIO()
635 result = b(["out"], "in", env, presub=1)
636 assert result.status == 7, result.status
638 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
640 sio = StringIO.StringIO()
642 result = b(["out", "list"], "in", env, presub=1)
643 assert result.status == 7, result.status
645 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
647 a2 = SCons.Action.Action(execfunc)
649 sio = StringIO.StringIO()
651 result = a2("out", "in", env)
652 assert result.status == 7, result.status
654 assert s == "Building out with action:\n execfunc(target, source, env)\nexecfunc(['out'], ['in'])\n", s
656 sio = StringIO.StringIO()
658 result = a2("out", "in", env, presub=0)
659 assert result.status == 7, result.status
661 assert s == "execfunc(['out'], ['in'])\n", s
663 SCons.Action.execute_actions = 0
665 sio = StringIO.StringIO()
667 result = a2("out", "in", env, presub=0)
668 assert result == 0, result
670 assert s == "execfunc(['out'], ['in'])\n", s
672 sio = StringIO.StringIO()
674 result = a("out", "in", env, presub=0, execute=1, show=0)
675 assert result.status == 7, result.status
679 sys.stdout = save_stdout
680 exitstatfunc_result = []
682 def exitstatfunc(stat, result=exitstatfunc_result):
686 result = a("out", "in", env, exitstatfunc=exitstatfunc)
687 assert result == 0, result
688 assert exitstatfunc_result == [], exitstatfunc_result
690 result = a("out", "in", env, execute=1, exitstatfunc=exitstatfunc)
691 assert result.status == 7, result.status
692 assert exitstatfunc_result == [7], exitstatfunc_result
694 SCons.Action.execute_actions = 1
697 def my_print_cmd_line(s, target, source, env, result=result):
699 env['PRINT_CMD_LINE_FUNC'] = my_print_cmd_line
700 a("output", "input", env)
701 assert result == ["execfunc(['output'], ['input'])"], result
705 sys.stdout = save_stdout
706 SCons.Action.print_actions = save_print_actions
707 SCons.Action.print_actions_presub = save_print_actions_presub
708 SCons.Action.execute_actions = save_execute_actions
710 def test_presub_lines(self):
711 """Test the presub_lines() method
714 a = SCons.Action.Action("x")
715 s = a.presub_lines(env)
718 a = SCons.Action.Action(["y", "z"])
719 s = a.presub_lines(env)
720 assert s == ['y', 'z'], s
724 a = SCons.Action.Action(func)
725 s = a.presub_lines(env)
726 assert s == ["func(target, source, env)"], s
728 def gen(target, source, env, for_signature):
729 return 'generat' + env.get('GEN', 'or')
730 a = SCons.Action.Action(gen, generator=1)
731 s = a.presub_lines(env)
732 assert s == ["generator"], s
733 s = a.presub_lines(Environment(GEN = 'ed'))
734 assert s == ["generated"], s
736 a = SCons.Action.Action("$ACT")
737 s = a.presub_lines(env)
739 s = a.presub_lines(Environment(ACT = 'expanded action'))
740 assert s == ['expanded action'], s
743 """Test adding Actions to stuff."""
744 # Adding actions to other Actions or to stuff that can
745 # be converted into an Action should produce a ListAction
746 # containing all the Actions.
749 baz = SCons.Action.Action(bar, generator=1)
750 act1 = SCons.Action.Action('foo bar')
751 act2 = SCons.Action.Action([ 'foo', bar ])
754 assert isinstance(sum, SCons.Action.ListAction), str(sum)
755 assert len(sum.list) == 3, len(sum.list)
756 assert [isinstance(x, SCons.Action.ActionBase) for x in sum.list] == [ 1, 1, 1 ]
759 assert isinstance(sum, SCons.Action.ListAction), str(sum)
760 assert len(sum.list) == 2, len(sum.list)
763 assert isinstance(sum, SCons.Action.ListAction), str(sum)
764 assert len(sum.list) == 4, len(sum.list)
766 # Should also be able to add command generators to each other
769 assert isinstance(sum, SCons.Action.ListAction), str(sum)
770 assert len(sum.list) == 2, len(sum.list)
773 assert isinstance(sum, SCons.Action.ListAction), str(sum)
774 assert len(sum.list) == 2, len(sum.list)
777 assert isinstance(sum, SCons.Action.ListAction), str(sum)
778 assert len(sum.list) == 3, len(sum.list)
780 # Also should be able to add Actions to anything that can
781 # be converted into an action.
783 assert isinstance(sum, SCons.Action.ListAction), str(sum)
784 assert len(sum.list) == 2, len(sum.list)
785 assert isinstance(sum.list[1], SCons.Action.FunctionAction)
787 sum = 'foo bar' + act2
788 assert isinstance(sum, SCons.Action.ListAction), str(sum)
789 assert len(sum.list) == 3, len(sum.list)
790 assert isinstance(sum.list[0], SCons.Action.CommandAction)
792 sum = [ 'foo', 'bar' ] + act1
793 assert isinstance(sum, SCons.Action.ListAction), str(sum)
794 assert len(sum.list) == 3, sum.list
795 assert isinstance(sum.list[0], SCons.Action.CommandAction)
796 assert isinstance(sum.list[1], SCons.Action.CommandAction)
798 sum = act2 + [ baz, bar ]
799 assert isinstance(sum, SCons.Action.ListAction), str(sum)
800 assert len(sum.list) == 4, len(sum.list)
801 assert isinstance(sum.list[2], SCons.Action.CommandGeneratorAction)
802 assert isinstance(sum.list[3], SCons.Action.FunctionAction)
809 assert 0, "Should have thrown a TypeError adding to an int."
816 assert 0, "Should have thrown a TypeError adding to an int."
818 class CommandActionTestCase(unittest.TestCase):
820 def test___init__(self):
821 """Test creation of a command Action
823 a = SCons.Action.CommandAction(["xyzzy"])
824 assert a.cmd_list == [ "xyzzy" ], a.cmd_list
825 assert a.cmdstr is _null, a.cmdstr
827 a = SCons.Action.CommandAction(["abra"], cmdstr="cadabra")
828 assert a.cmd_list == [ "abra" ], a.cmd_list
829 assert a.cmdstr == "cadabra", a.cmdstr
831 def test___str__(self):
832 """Test fetching the pre-substitution string for command Actions
835 act = SCons.Action.CommandAction('xyzzy $TARGET $SOURCE')
837 assert s == 'xyzzy $TARGET $SOURCE', s
839 act = SCons.Action.CommandAction(['xyzzy',
840 '$TARGET', '$SOURCE',
841 '$TARGETS', '$SOURCES'])
843 assert s == "xyzzy $TARGET $SOURCE $TARGETS $SOURCES", s
845 def test_genstring(self):
846 """Test the genstring() method for command Actions
854 act = SCons.Action.CommandAction('xyzzy $TARGET $SOURCE')
855 expect = 'xyzzy $TARGET $SOURCE'
856 s = act.genstring([], [], env)
857 assert s == expect, s
858 s = act.genstring([t1], [s1], env)
859 assert s == expect, s
860 s = act.genstring([t1, t2], [s1, s2], env)
861 assert s == expect, s
863 act = SCons.Action.CommandAction('xyzzy $TARGETS $SOURCES')
864 expect = 'xyzzy $TARGETS $SOURCES'
865 s = act.genstring([], [], env)
866 assert s == expect, s
867 s = act.genstring([t1], [s1], env)
868 assert s == expect, s
869 s = act.genstring([t1, t2], [s1, s2], env)
870 assert s == expect, s
872 act = SCons.Action.CommandAction(['xyzzy',
873 '$TARGET', '$SOURCE',
874 '$TARGETS', '$SOURCES'])
875 expect = "xyzzy $TARGET $SOURCE $TARGETS $SOURCES"
876 s = act.genstring([], [], env)
877 assert s == expect, s
878 s = act.genstring([t1], [s1], env)
879 assert s == expect, s
880 s = act.genstring([t1, t2], [s1, s2], env)
881 assert s == expect, s
883 def test_strfunction(self):
884 """Test fetching the string representation of command Actions
892 act = SCons.Action.CommandAction('xyzzy $TARGET $SOURCE')
893 s = act.strfunction([], [], env)
894 assert s == 'xyzzy', s
895 s = act.strfunction([t1], [s1], env)
896 assert s == 'xyzzy t1 s1', s
897 s = act.strfunction([t1, t2], [s1, s2], env)
898 assert s == 'xyzzy t1 s1', s
900 act = SCons.Action.CommandAction('xyzzy $TARGET $SOURCE',
901 cmdstr='cmdstr - $SOURCE - $TARGET -')
902 s = act.strfunction([], [], env)
903 assert s == 'cmdstr - - -', s
904 s = act.strfunction([t1], [s1], env)
905 assert s == 'cmdstr - s1 - t1 -', s
906 s = act.strfunction([t1, t2], [s1, s2], env)
907 assert s == 'cmdstr - s1 - t1 -', s
909 act = SCons.Action.CommandAction('xyzzy $TARGETS $SOURCES')
910 s = act.strfunction([], [], env)
911 assert s == 'xyzzy', s
912 s = act.strfunction([t1], [s1], env)
913 assert s == 'xyzzy t1 s1', s
914 s = act.strfunction([t1, t2], [s1, s2], env)
915 assert s == 'xyzzy t1 t2 s1 s2', s
917 act = SCons.Action.CommandAction('xyzzy $TARGETS $SOURCES',
918 cmdstr='cmdstr = $SOURCES = $TARGETS =')
919 s = act.strfunction([], [], env)
920 assert s == 'cmdstr = = =', s
921 s = act.strfunction([t1], [s1], env)
922 assert s == 'cmdstr = s1 = t1 =', s
923 s = act.strfunction([t1, t2], [s1, s2], env)
924 assert s == 'cmdstr = s1 s2 = t1 t2 =', s
926 act = SCons.Action.CommandAction(['xyzzy',
927 '$TARGET', '$SOURCE',
928 '$TARGETS', '$SOURCES'])
929 s = act.strfunction([], [], env)
930 assert s == 'xyzzy', s
931 s = act.strfunction([t1], [s1], env)
932 assert s == 'xyzzy t1 s1 t1 s1', s
933 s = act.strfunction([t1, t2], [s1, s2], env)
934 assert s == 'xyzzy t1 s1 t1 t2 s1 s2', s
936 act = SCons.Action.CommandAction('xyzzy $TARGETS $SOURCES',
937 cmdstr='cmdstr\t$TARGETS\n$SOURCES ')
939 s = act.strfunction([], [], env)
940 assert s == 'cmdstr\t\n ', s
941 s = act.strfunction([t1], [s1], env)
942 assert s == 'cmdstr\tt1\ns1 ', s
943 s = act.strfunction([t1, t2], [s1, s2], env)
944 assert s == 'cmdstr\tt1 t2\ns1 s2 ', s
946 def sf(target, source, env):
947 return "sf was called"
948 act = SCons.Action.CommandAction('foo', strfunction=sf)
949 s = act.strfunction([], [], env)
950 assert s == "sf was called", s
953 def __init__(self, targets, sources, env):
958 def __init__(self, targets, sources, env):
963 def __init__(self, targets, sources, env):
967 def strfunction(self, targets, sources, env):
968 return 'actclass3 on %s to get %s'%(str(sources[0]),
971 def __init__(self, targets, sources, env):
977 act1 = SCons.Action.Action(actclass1([t1], [s1], env))
978 s = act1.strfunction([t1], [s1], env)
979 assert s == 'actclass1(["t1"], ["s1"])', s
981 act2 = SCons.Action.Action(actclass2([t1], [s1], env))
982 s = act2.strfunction([t1], [s1], env)
983 assert s == 'actclass2(["t1"], ["s1"])', s
985 act3 = SCons.Action.Action(actclass3([t1], [s1], env))
986 s = act3.strfunction([t1], [s1], env)
987 assert s == 'actclass3 on s1 to get t1', s
989 act4 = SCons.Action.Action(actclass4([t1], [s1], env))
990 s = act4.strfunction([t1], [s1], env)
993 act = SCons.Action.CommandAction("@foo bar")
994 s = act.strfunction([], [], env)
997 act = SCons.Action.CommandAction("@-foo bar")
998 s = act.strfunction([], [], env)
1001 act = SCons.Action.CommandAction("-@foo bar")
1002 s = act.strfunction([], [], env)
1005 act = SCons.Action.CommandAction("-foo bar")
1006 s = act.strfunction([], [], env)
1007 assert s == "foo bar", s
1009 act = SCons.Action.CommandAction("@ foo bar")
1010 s = act.strfunction([], [], env)
1013 act = SCons.Action.CommandAction("@- foo bar")
1014 s = act.strfunction([], [], env)
1017 act = SCons.Action.CommandAction("-@ foo bar")
1018 s = act.strfunction([], [], env)
1021 act = SCons.Action.CommandAction("- foo bar")
1022 s = act.strfunction([], [], env)
1023 assert s == "foo bar", s
1025 def test_execute(self):
1026 """Test execution of command Actions
1031 except AttributeError:
1034 cmd1 = r'%s %s %s xyzzy' % (_python_, act_py, outfile)
1036 act = SCons.Action.CommandAction(cmd1)
1037 r = act([], [], env.Clone())
1039 c = test.read(outfile, 'r')
1040 assert c == "act.py: 'xyzzy'\n", c
1042 cmd2 = r'%s %s %s $TARGET' % (_python_, act_py, outfile)
1044 act = SCons.Action.CommandAction(cmd2)
1045 r = act(DummyNode('foo'), [], env.Clone())
1047 c = test.read(outfile, 'r')
1048 assert c == "act.py: 'foo'\n", c
1050 cmd3 = r'%s %s %s ${TARGETS}' % (_python_, act_py, outfile)
1052 act = SCons.Action.CommandAction(cmd3)
1053 r = act(list(map(DummyNode, ['aaa', 'bbb'])), [], env.Clone())
1055 c = test.read(outfile, 'r')
1056 assert c == "act.py: 'aaa' 'bbb'\n", c
1058 cmd4 = r'%s %s %s $SOURCES' % (_python_, act_py, outfile)
1060 act = SCons.Action.CommandAction(cmd4)
1061 r = act([], [DummyNode('one'), DummyNode('two')], env.Clone())
1063 c = test.read(outfile, 'r')
1064 assert c == "act.py: 'one' 'two'\n", c
1066 cmd4 = r'%s %s %s ${SOURCES[:2]}' % (_python_, act_py, outfile)
1068 act = SCons.Action.CommandAction(cmd4)
1069 sources = [DummyNode('three'), DummyNode('four'), DummyNode('five')]
1071 r = act([], source = sources, env = env2)
1073 c = test.read(outfile, 'r')
1074 assert c == "act.py: 'three' 'four'\n", c
1076 cmd5 = r'%s %s %s $TARGET XYZZY' % (_python_, act_py, outfile)
1078 act = SCons.Action.CommandAction(cmd5)
1079 env5 = Environment()
1080 if 'ENV' in scons_env:
1081 env5['ENV'] = scons_env['ENV']
1082 PATH = scons_env['ENV'].get('PATH', '')
1087 env5['ENV']['XYZZY'] = 'xyzzy'
1088 r = act(target = DummyNode('out5'), source = [], env = env5)
1090 act = SCons.Action.CommandAction(cmd5)
1091 r = act(target = DummyNode('out5'),
1093 env = env.Clone(ENV = {'XYZZY' : 'xyzzy5',
1096 c = test.read(outfile, 'r')
1097 assert c == "act.py: 'out5' 'XYZZY'\nact.py: 'xyzzy5'\n", c
1100 def __init__(self, str):
1106 def get_subst_proxy(self):
1109 cmd6 = r'%s %s %s ${TARGETS[1]} $TARGET ${SOURCES[:2]}' % (_python_, act_py, outfile)
1111 act = SCons.Action.CommandAction(cmd6)
1112 r = act(target = [Obj('111'), Obj('222')],
1113 source = [Obj('333'), Obj('444'), Obj('555')],
1116 c = test.read(outfile, 'r')
1117 assert c == "act.py: '222' '111' '333' '444'\n", c
1120 # NT treats execs of directories and non-executable files
1121 # as "file not found" errors
1122 expect_nonexistent = 1
1123 expect_nonexecutable_file = 1
1124 expect_nonexecutable_dir = 1
1125 elif sys.platform == 'cygwin':
1126 expect_nonexistent = 127
1127 # Newer cygwin seems to return 126 for following
1128 expect_nonexecutable_file = 126
1129 expect_nonexecutable_dir = 127
1131 expect_nonexistent = 127
1132 expect_nonexecutable_file = 126
1133 expect_nonexecutable_dir = 126
1135 # Test that a nonexistent command returns 127
1136 act = SCons.Action.CommandAction(python + "_no_such_command_")
1137 r = act([], [], env.Clone(out = outfile))
1138 assert r.status == expect_nonexistent, r.status
1140 # Test that trying to execute a directory returns 126
1141 dir, tail = os.path.split(python)
1142 act = SCons.Action.CommandAction(dir)
1143 r = act([], [], env.Clone(out = outfile))
1144 assert r.status == expect_nonexecutable_file, r.status
1146 # Test that trying to execute a non-executable file returns 126
1147 act = SCons.Action.CommandAction(outfile)
1148 r = act([], [], env.Clone(out = outfile))
1149 assert r.status == expect_nonexecutable_dir, r.status
1151 act = SCons.Action.CommandAction('%s %s 1' % (_python_, exit_py))
1152 r = act([], [], env)
1153 assert r.status == 1, r.status
1155 act = SCons.Action.CommandAction('@%s %s 1' % (_python_, exit_py))
1156 r = act([], [], env)
1157 assert r.status == 1, r.status
1159 act = SCons.Action.CommandAction('@-%s %s 1' % (_python_, exit_py))
1160 r = act([], [], env)
1163 act = SCons.Action.CommandAction('-%s %s 1' % (_python_, exit_py))
1164 r = act([], [], env)
1167 act = SCons.Action.CommandAction('@ %s %s 1' % (_python_, exit_py))
1168 r = act([], [], env)
1169 assert r.status == 1, r.status
1171 act = SCons.Action.CommandAction('@- %s %s 1' % (_python_, exit_py))
1172 r = act([], [], env)
1175 act = SCons.Action.CommandAction('- %s %s 1' % (_python_, exit_py))
1176 r = act([], [], env)
1179 def _DO_NOT_EXECUTE_test_pipe_execute(self):
1180 """Test capturing piped output from an action
1182 We used to have PIPE_BUILD support built right into
1183 Action.execute() for the benefit of the SConf subsystem, but we've
1184 moved that logic back into SConf itself. We'll leave this code
1185 here, just in case we ever want to resurrect this functionality
1186 in the future, but change the name of the test so it doesn't
1187 get executed as part of the normal test suite.
1189 pipe = open( pipe_file, "w" )
1190 self.env = Environment(ENV = {'ACTPY_PIPE' : '1'}, PIPE_BUILD = 1,
1191 PSTDOUT = pipe, PSTDERR = pipe)
1192 # everything should also work when piping output
1194 self.env['PSTDOUT'].close()
1195 pipe_out = test.read( pipe_file )
1197 act_out = "act.py: stdout: executed act.py"
1198 act_err = "act.py: stderr: executed act.py"
1200 # Since we are now using select(), stdout and stderr can be
1201 # intermixed, so count the lines separately.
1202 outlines = re.findall(act_out, pipe_out)
1203 errlines = re.findall(act_err, pipe_out)
1204 assert len(outlines) == 6, pipe_out + repr(outlines)
1205 assert len(errlines) == 6, pipe_out + repr(errlines)
1207 # test redirection operators
1208 def test_redirect(self, redir, stdout_msg, stderr_msg):
1209 cmd = r'%s %s %s xyzzy %s' % (_python_, act_py, outfile, redir)
1210 # Write the output and error messages to files because
1211 # Windows can't handle strings that are too big in its
1212 # external environment (os.spawnve() returns EINVAL,
1213 # "Invalid argument").
1214 stdout_file = test.workpath('stdout_msg')
1215 stderr_file = test.workpath('stderr_msg')
1216 open(stdout_file, 'w').write(stdout_msg)
1217 open(stderr_file, 'w').write(stderr_msg)
1218 pipe = open( pipe_file, "w" )
1219 act = SCons.Action.CommandAction(cmd)
1220 env = Environment( ENV = {'ACTPY_PIPE' : '1',
1221 'PIPE_STDOUT_FILE' : stdout_file,
1222 'PIPE_STDERR_FILE' : stderr_file},
1224 PSTDOUT = pipe, PSTDERR = pipe )
1225 r = act([], [], env)
1228 return (test.read(outfile2, 'r'), test.read(pipe_file, 'r'))
1230 (redirected, pipe_out) = test_redirect(self,'> %s' % outfile2,
1232 assert redirected == act_out
1233 assert pipe_out == act_err
1235 (redirected, pipe_out) = test_redirect(self,'2> %s' % outfile2,
1237 assert redirected == act_err
1238 assert pipe_out == act_out
1240 (redirected, pipe_out) = test_redirect(self,'> %s 2>&1' % outfile2,
1242 assert (redirected == act_out + act_err or
1243 redirected == act_err + act_out)
1244 assert pipe_out == ""
1246 act_err = "Long Command Output\n"*3000
1247 # the size of the string should exceed the system's default block size
1249 (redirected, pipe_out) = test_redirect(self,'> %s' % outfile2,
1251 assert (redirected == act_out)
1252 assert (pipe_out == act_err)
1254 def test_set_handler(self):
1255 """Test setting the command handler...
1261 def func(sh, escape, cmd, args, env, test=t):
1262 test.executed = args
1265 def escape_func(cmd):
1266 return '**' + cmd + '**'
1269 def __init__(self, x):
1273 def escape(self, escape_func):
1274 return escape_func(self.data)
1275 def is_literal(self):
1278 a = SCons.Action.CommandAction(["xyzzy"])
1279 e = Environment(SPAWN = func)
1281 assert t.executed == [ 'xyzzy' ], t.executed
1283 a = SCons.Action.CommandAction(["xyzzy"])
1284 e = Environment(SPAWN = '$FUNC', FUNC = func)
1286 assert t.executed == [ 'xyzzy' ], t.executed
1288 a = SCons.Action.CommandAction(["xyzzy"])
1289 e = Environment(SPAWN = func, SHELL = 'fake shell')
1291 assert t.executed == [ 'xyzzy' ], t.executed
1292 assert t.shell == 'fake shell', t.shell
1294 a = SCons.Action.CommandAction([ LiteralStr("xyzzy") ])
1295 e = Environment(SPAWN = func, ESCAPE = escape_func)
1297 assert t.executed == [ '**xyzzy**' ], t.executed
1299 def test_get_contents(self):
1300 """Test fetching the contents of a command Action
1302 def CmdGen(target, source, env, for_signature):
1303 assert for_signature
1305 (env["foo"], env["bar"])
1307 # The number 1 is there to make sure all args get converted to strings.
1308 a = SCons.Action.CommandAction(["|", "$(", "$foo", "|", "$bar",
1309 "$)", "|", "$baz", 1])
1310 c = a.get_contents(target=[], source=[],
1311 env=Environment(foo = 'FFF', bar = 'BBB',
1313 assert c == "| | FFF BBB 1", c
1315 # Make sure that CommandActions use an Environment's
1316 # subst_target_source() method for substitution.
1317 class SpecialEnvironment(Environment):
1318 def subst_target_source(self, strSubst, raw=0, target=[], source=[]):
1319 return 'subst_target_source: ' + strSubst
1321 c = a.get_contents(target=DummyNode('ttt'), source = DummyNode('sss'),
1322 env=SpecialEnvironment(foo = 'GGG', bar = 'CCC',
1324 assert c == 'subst_target_source: | $( $foo | $bar $) | $baz 1', c
1326 # We've discussed using the real target and source names in a
1327 # CommandAction's signature contents. This would have have the
1328 # advantage of recompiling when a file's name changes (keeping
1329 # debug info current), but it would currently break repository
1330 # logic that will change the file name based on whether the
1331 # files come from a repository or locally. If we ever move to
1332 # that scheme, then all of the '__t1__' and '__s6__' file names
1333 # in the asserts below would change to 't1' and 's6' and the
1335 t = list(map(DummyNode, ['t1', 't2', 't3', 't4', 't5', 't6']))
1336 s = list(map(DummyNode, ['s1', 's2', 's3', 's4', 's5', 's6']))
1339 a = SCons.Action.CommandAction(["$TARGET"])
1340 c = a.get_contents(target=t, source=s, env=env)
1343 a = SCons.Action.CommandAction(["$TARGETS"])
1344 c = a.get_contents(target=t, source=s, env=env)
1345 assert c == "t1 t2 t3 t4 t5 t6", c
1347 a = SCons.Action.CommandAction(["${TARGETS[2]}"])
1348 c = a.get_contents(target=t, source=s, env=env)
1351 a = SCons.Action.CommandAction(["${TARGETS[3:5]}"])
1352 c = a.get_contents(target=t, source=s, env=env)
1353 assert c == "t4 t5", c
1355 a = SCons.Action.CommandAction(["$SOURCE"])
1356 c = a.get_contents(target=t, source=s, env=env)
1359 a = SCons.Action.CommandAction(["$SOURCES"])
1360 c = a.get_contents(target=t, source=s, env=env)
1361 assert c == "s1 s2 s3 s4 s5 s6", c
1363 a = SCons.Action.CommandAction(["${SOURCES[2]}"])
1364 c = a.get_contents(target=t, source=s, env=env)
1367 a = SCons.Action.CommandAction(["${SOURCES[3:5]}"])
1368 c = a.get_contents(target=t, source=s, env=env)
1369 assert c == "s4 s5", c
1371 class CommandGeneratorActionTestCase(unittest.TestCase):
1373 def factory(self, act, **kw):
1374 """Pass any keywords as a dict"""
1375 return SCons.Action.CommandGeneratorAction(act, kw)
1377 def test___init__(self):
1378 """Test creation of a command generator Action
1380 def f(target, source, env):
1383 assert a.generator == f
1385 def test___str__(self):
1386 """Test the pre-substitution strings for command generator Actions
1388 def f(target, source, env, for_signature, self=self):
1390 # See if "env" is really a construction environment (or
1391 # looks like one) by accessing the FindIxes attribute.
1392 # (The Tool/mingw.py module has a generator that uses this,
1393 # and the __str__() method used to cause problems by passing
1394 # us a regular dictionary as a fallback.)
1400 assert s == 'FOO', s
1402 def test_genstring(self):
1403 """Test the command generator Action genstring() method
1405 def f(target, source, env, for_signature, self=self):
1406 dummy = env['dummy']
1408 return "$FOO $TARGET $SOURCE $TARGETS $SOURCES"
1411 s = a.genstring([], [], env=Environment(FOO='xyzzy', dummy=1))
1412 assert self.dummy == 1, self.dummy
1413 assert s == "$FOO $TARGET $SOURCE $TARGETS $SOURCES", s
1415 def test_execute(self):
1416 """Test executing a command generator Action
1419 def f(target, source, env, for_signature, self=self):
1420 dummy = env['dummy']
1422 s = env.subst("$FOO")
1423 assert s == 'foo baz\nbar ack', s
1425 def func_action(target, source, env, self=self):
1427 s = env.subst('$foo')
1428 assert s == 'bar', s
1430 def f2(target, source, env, for_signature, f=func_action):
1432 def ch(sh, escape, cmd, args, env, self=self):
1433 self.cmd.append(cmd)
1434 self.args.append(args)
1440 a([], [], env=Environment(FOO = 'foo baz\nbar ack',
1443 assert self.dummy == 1, self.dummy
1444 assert self.cmd == ['foo', 'bar'], self.cmd
1445 assert self.args == [[ 'foo', 'baz' ], [ 'bar', 'ack' ]], self.args
1447 b = self.factory(f2)
1449 b(target=[], source=[], env=Environment(foo = 'bar',
1451 assert self.dummy==2, self.dummy
1455 def __init__(self, t):
1458 self.t.rfile_called = 1
1460 def get_subst_proxy(self):
1462 def f3(target, source, env, for_signature):
1464 c = self.factory(f3)
1465 c(target=[], source=DummyFile(self), env=Environment())
1466 assert self.rfile_called
1468 def test_get_contents(self):
1469 """Test fetching the contents of a command generator Action
1471 def f(target, source, env, for_signature):
1474 assert for_signature, for_signature
1475 return [["guux", foo, "$(", "$ignore", "$)", bar,
1476 '${test("$( foo $bar $)")}' ]]
1479 assert mystr == "$( foo $bar $)", mystr
1482 env = Environment(foo = 'FFF', bar = 'BBB',
1483 ignore = 'foo', test=test)
1485 c = a.get_contents(target=[], source=[], env=env)
1486 assert c == "guux FFF BBB test", c
1488 def test_get_contents_of_function_action(self):
1489 """Test contents of a CommandGeneratorAction-generated FunctionAction
1496 "0,0,0,0,(),(),(d\000\000S),(),()",
1497 "0,0,0,0,(),(),(d\x00\x00S),(),()",
1501 "1,1,0,0,(),(),(d\000\000S),(),()",
1502 "1,1,0,0,(),(),(d\x00\x00S),(),()",
1505 def f_global(target, source, env, for_signature):
1506 return SCons.Action.Action(GlobalFunc)
1509 #def f_local(target, source, env, for_signature):
1510 def f_local(target, source, env, for_signature, LocalFunc=LocalFunc):
1511 return SCons.Action.Action(LocalFunc)
1513 env = Environment(XYZ = 'foo')
1515 a = self.factory(f_global)
1516 c = a.get_contents(target=[], source=[], env=env)
1517 assert c in func_matches, repr(c)
1519 a = self.factory(f_local)
1520 c = a.get_contents(target=[], source=[], env=env)
1521 assert c in func_matches, repr(c)
1523 def f_global(target, source, env, for_signature):
1524 return SCons.Action.Action(GlobalFunc, varlist=['XYZ'])
1527 #def f_local(target, source, env, for_signature):
1528 def f_local(target, source, env, for_signature, LocalFunc=LocalFunc):
1529 return SCons.Action.Action(LocalFunc, varlist=['XYZ'])
1531 matches_foo = [x + "foo" for x in func_matches]
1533 a = self.factory(f_global)
1534 c = a.get_contents(target=[], source=[], env=env)
1535 assert c in matches_foo, repr(c)
1537 a = self.factory(f_local)
1538 c = a.get_contents(target=[], source=[], env=env)
1539 assert c in matches_foo, repr(c)
1542 class FunctionActionTestCase(unittest.TestCase):
1544 def test___init__(self):
1545 """Test creation of a function Action
1556 a = SCons.Action.FunctionAction(func1, {})
1557 assert a.execfunction == func1, a.execfunction
1558 assert isinstance(a.strfunction, types.MethodType), type(a.strfunction)
1560 a = SCons.Action.FunctionAction(func2, { 'strfunction' : func3 })
1561 assert a.execfunction == func2, a.execfunction
1562 assert a.strfunction == func3, a.strfunction
1564 def test___str__(self):
1565 """Test the __str__() method for function Actions
1569 a = SCons.Action.FunctionAction(func1, {})
1571 assert s == "func1(target, source, env)", s
1576 a = SCons.Action.FunctionAction(class1(), {})
1578 assert s == "class1(target, source, env)", s
1580 def test_execute(self):
1581 """Test executing a function Action
1584 def f(target, source, env):
1589 assert env.subst("$BAR") == 'foo bar', env.subst("$BAR")
1591 a = SCons.Action.FunctionAction(f, {})
1592 a(target=1, source=2, env=Environment(BAR = 'foo bar',
1594 assert self.inc == 1, self.inc
1595 assert self.source == [2], self.source
1596 assert self.target == [1], self.target
1600 def function1(target, source, env):
1604 open(t, 'w').write("function1\n")
1607 act = SCons.Action.FunctionAction(function1, {})
1608 r = act(target = [outfile, outfile2], source=[], env=Environment())
1609 assert r.status == 1, r.status
1611 assert count == 1, count
1612 c = test.read(outfile, 'r')
1613 assert c == "function1\n", c
1614 c = test.read(outfile2, 'r')
1615 assert c == "function1\n", c
1618 def __init__(self, target, source, env):
1619 open(env['out'], 'w').write("class1a\n")
1621 act = SCons.Action.FunctionAction(class1a, {})
1622 r = act([], [], Environment(out = outfile))
1623 assert isinstance(r.status, class1a), r.status
1624 c = test.read(outfile, 'r')
1625 assert c == "class1a\n", c
1628 def __call__(self, target, source, env):
1629 open(env['out'], 'w').write("class1b\n")
1632 act = SCons.Action.FunctionAction(class1b(), {})
1633 r = act([], [], Environment(out = outfile))
1634 assert r.status == 2, r.status
1635 c = test.read(outfile, 'r')
1636 assert c == "class1b\n", c
1638 def build_it(target, source, env, executor=None, self=self):
1641 def string_it(target, source, env, executor=None, self=self):
1644 act = SCons.Action.FunctionAction(build_it,
1645 { 'strfunction' : string_it })
1646 r = act([], [], Environment())
1648 assert self.build_it
1649 assert self.string_it
1651 def test_get_contents(self):
1652 """Test fetching the contents of a function Action
1659 "0,0,0,0,(),(),(d\000\000S),(),()",
1660 "0,0,0,0,(),(),(d\x00\x00S),(),()",
1664 "1,1,0,0,(),(),(d\000\000S),(),()",
1665 "1,1,0,0,(),(),(d\x00\x00S),(),()",
1668 def factory(act, **kw):
1669 return SCons.Action.FunctionAction(act, kw)
1671 a = factory(GlobalFunc)
1672 c = a.get_contents(target=[], source=[], env=Environment())
1673 assert c in func_matches, repr(c)
1675 a = factory(LocalFunc)
1676 c = a.get_contents(target=[], source=[], env=Environment())
1677 assert c in func_matches, repr(c)
1679 matches_foo = [x + "foo" for x in func_matches]
1681 a = factory(GlobalFunc, varlist=['XYZ'])
1682 c = a.get_contents(target=[], source=[], env=Environment())
1683 assert c in func_matches, repr(c)
1684 c = a.get_contents(target=[], source=[], env=Environment(XYZ='foo'))
1685 assert c in matches_foo, repr(c)
1687 ##TODO: is this set of tests still needed?
1688 # Make sure a bare string varlist works
1689 a = factory(GlobalFunc, varlist='XYZ')
1690 c = a.get_contents(target=[], source=[], env=Environment())
1691 assert c in func_matches, repr(c)
1692 c = a.get_contents(target=[], source=[], env=Environment(XYZ='foo'))
1693 assert c in matches_foo, repr(c)
1696 def get_contents(self, target, source, env):
1699 c = a.get_contents(target=[], source=[], env=Environment())
1700 assert c == 'xyzzy', repr(c)
1703 def LocalMethod(self):
1706 a = factory(lc.LocalMethod)
1707 c = a.get_contents(target=[], source=[], env=Environment())
1708 assert c in meth_matches, repr(c)
1710 def test_strfunction(self):
1711 """Test the FunctionAction.strfunction() method
1716 def factory(act, **kw):
1717 return SCons.Action.FunctionAction(act, kw)
1720 s = a.strfunction(target=[], source=[], env=Environment())
1721 assert s == 'func([], [])', s
1723 a = factory(func, strfunction=None)
1724 s = a.strfunction(target=[], source=[], env=Environment())
1727 a = factory(func, cmdstr='function')
1728 s = a.strfunction(target=[], source=[], env=Environment())
1729 assert s == 'function', s
1731 class ListActionTestCase(unittest.TestCase):
1733 def test___init__(self):
1734 """Test creation of a list of subsidiary Actions
1738 a = SCons.Action.ListAction(["x", func, ["y", "z"]])
1739 assert isinstance(a.list[0], SCons.Action.CommandAction)
1740 assert isinstance(a.list[1], SCons.Action.FunctionAction)
1741 assert isinstance(a.list[2], SCons.Action.ListAction)
1742 assert a.list[2].list[0].cmd_list == 'y'
1744 def test___str__(self):
1745 """Test the __str__() method for a list of subsidiary Actions
1747 def f(target,source,env):
1749 def g(target,source,env):
1751 a = SCons.Action.ListAction([f, g, "XXX", f])
1753 assert s == "f(target, source, env)\ng(target, source, env)\nXXX\nf(target, source, env)", s
1755 def test_genstring(self):
1756 """Test the genstring() method for a list of subsidiary Actions
1758 def f(target,source,env):
1760 def g(target,source,env,for_signature):
1761 return 'generated %s %s' % (target[0], source[0])
1762 g = SCons.Action.Action(g, generator=1)
1763 a = SCons.Action.ListAction([f, g, "XXX", f])
1764 s = a.genstring(['foo.x'], ['bar.y'], Environment())
1765 assert s == "f(target, source, env)\ngenerated foo.x bar.y\nXXX\nf(target, source, env)", s
1767 def test_execute(self):
1768 """Test executing a list of subsidiary Actions
1771 def f(target,source,env):
1774 a = SCons.Action.ListAction([f, f, f])
1775 a([], [], Environment(s = self))
1776 assert self.inc == 3, self.inc
1778 cmd2 = r'%s %s %s syzygy' % (_python_, act_py, outfile)
1780 def function2(target, source, env):
1781 open(env['out'], 'a').write("function2\n")
1785 def __call__(self, target, source, env):
1786 open(env['out'], 'a').write("class2a\n")
1790 def __init__(self, target, source, env):
1791 open(env['out'], 'a').write("class2b\n")
1792 act = SCons.Action.ListAction([cmd2, function2, class2a(), class2b])
1793 r = act([], [], Environment(out = outfile))
1794 assert isinstance(r.status, class2b), r.status
1795 c = test.read(outfile, 'r')
1796 assert c == "act.py: 'syzygy'\nfunction2\nclass2a\nclass2b\n", c
1798 def test_get_contents(self):
1799 """Test fetching the contents of a list of subsidiary Actions
1802 def gen(target, source, env, for_signature):
1806 a = SCons.Action.ListAction(["x",
1807 SCons.Action.Action(gen, generator=1),
1809 c = a.get_contents(target=[], source=[], env=Environment(s = self))
1810 assert self.foo==1, self.foo
1811 assert c == "xyz", c
1813 class LazyActionTestCase(unittest.TestCase):
1814 def test___init__(self):
1815 """Test creation of a lazy-evaluation Action
1817 # Environment variable references should create a special type
1818 # of LazyAction that lazily evaluates the variable for whether
1819 # it's a string or something else before doing anything.
1820 a9 = SCons.Action.Action('$FOO')
1821 assert isinstance(a9, SCons.Action.LazyAction), a9
1822 assert a9.var == 'FOO', a9.var
1824 a10 = SCons.Action.Action('${FOO}')
1825 assert isinstance(a10, SCons.Action.LazyAction), a10
1826 assert a10.var == 'FOO', a10.var
1828 def test_genstring(self):
1829 """Test the lazy-evaluation Action genstring() method
1831 def f(target, source, env):
1833 a = SCons.Action.Action('$BAR')
1834 env1 = Environment(BAR=f, s=self)
1835 env2 = Environment(BAR='xxx', s=self)
1836 s = a.genstring([], [], env=env1)
1837 assert s == "f(target, source, env)", s
1838 s = a.genstring([], [], env=env2)
1839 assert s == 'xxx', s
1841 def test_execute(self):
1842 """Test executing a lazy-evaluation Action
1844 def f(target, source, env):
1848 a = SCons.Action.Action('$BAR')
1849 a([], [], env=Environment(BAR = f, s = self))
1850 assert self.test == 1, self.test
1851 cmd = r'%s %s %s lazy' % (_python_, act_py, outfile)
1852 a([], [], env=Environment(BAR = cmd, s = self))
1853 c = test.read(outfile, 'r')
1854 assert c == "act.py: 'lazy'\n", c
1856 def test_get_contents(self):
1857 """Test fetching the contents of a lazy-evaluation Action
1859 a = SCons.Action.Action("${FOO}")
1860 env = Environment(FOO = [["This", "is", "a", "test"]])
1861 c = a.get_contents(target=[], source=[], env=env)
1862 assert c == "This is a test", c
1864 def test_get_contents_of_function_action(self):
1865 """Test fetching the contents of a lazy-evaluation FunctionAction
1872 "0,0,0,0,(),(),(d\000\000S),(),()",
1873 "0,0,0,0,(),(),(d\x00\x00S),(),()",
1877 "1,1,0,0,(),(),(d\000\000S),(),()",
1878 "1,1,0,0,(),(),(d\x00\x00S),(),()",
1881 def factory(act, **kw):
1882 return SCons.Action.FunctionAction(act, kw)
1885 a = SCons.Action.Action("${FOO}")
1887 env = Environment(FOO = factory(GlobalFunc))
1888 c = a.get_contents(target=[], source=[], env=env)
1889 assert c in func_matches, repr(c)
1891 env = Environment(FOO = factory(LocalFunc))
1892 c = a.get_contents(target=[], source=[], env=env)
1893 assert c in func_matches, repr(c)
1895 matches_foo = [x + "foo" for x in func_matches]
1897 env = Environment(FOO = factory(GlobalFunc, varlist=['XYZ']))
1898 c = a.get_contents(target=[], source=[], env=env)
1899 assert c in func_matches, repr(c)
1902 c = a.get_contents(target=[], source=[], env=env)
1903 assert c in matches_foo, repr(c)
1905 class ActionCallerTestCase(unittest.TestCase):
1906 def test___init__(self):
1907 """Test creation of an ActionCaller"""
1908 ac = SCons.Action.ActionCaller(1, [2, 3], {'FOO' : 4, 'BAR' : 5})
1909 assert ac.parent == 1, ac.parent
1910 assert ac.args == [2, 3], ac.args
1911 assert ac.kw == {'FOO' : 4, 'BAR' : 5}, ac.kw
1913 def test_get_contents(self):
1914 """Test fetching the contents of an ActionCaller"""
1926 af = SCons.Action.ActionFactory(GlobalFunc, strfunc)
1927 ac = SCons.Action.ActionCaller(af, [], {})
1928 c = ac.get_contents([], [], Environment())
1929 assert c in matches, repr(c)
1931 af = SCons.Action.ActionFactory(LocalFunc, strfunc)
1932 ac = SCons.Action.ActionCaller(af, [], {})
1933 c = ac.get_contents([], [], Environment())
1934 assert c in matches, repr(c)
1945 af = SCons.Action.ActionFactory(GlobalActFunc(), strfunc)
1946 ac = SCons.Action.ActionCaller(af, [], {})
1947 c = ac.get_contents([], [], Environment())
1948 assert c in matches, repr(c)
1950 af = SCons.Action.ActionFactory(LocalActFunc(), strfunc)
1951 ac = SCons.Action.ActionCaller(af, [], {})
1952 c = ac.get_contents([], [], Environment())
1953 assert c in matches, repr(c)
1956 "<built-in function str>",
1960 af = SCons.Action.ActionFactory(str, strfunc)
1961 ac = SCons.Action.ActionCaller(af, [], {})
1962 c = ac.get_contents([], [], Environment())
1963 assert c == "<built-in function str>" or \
1964 c == "<type 'str'>", repr(c)
1966 def test___call__(self):
1967 """Test calling an ActionCaller"""
1969 def actfunc(a1, a2, a3, args=actfunc_args):
1970 args.extend([a1, a2, a3])
1971 def strfunc(a1, a2, a3):
1974 e = Environment(FOO = 2, BAR = 5)
1976 af = SCons.Action.ActionFactory(actfunc, strfunc)
1977 ac = SCons.Action.ActionCaller(af, ['$__env__', '$FOO', 3], {})
1979 assert actfunc_args[0] is e, actfunc_args
1980 assert actfunc_args[1] == '2', actfunc_args
1981 assert actfunc_args[2] == 3, actfunc_args
1984 ac = SCons.Action.ActionCaller(af, [], {'a3' : '$__env__', 'a2' : '$BAR', 'a1' : 4})
1986 assert actfunc_args[0] == 4, actfunc_args
1987 assert actfunc_args[1] == '5', actfunc_args
1988 assert actfunc_args[2] is e, actfunc_args
1991 def test_strfunction(self):
1992 """Test calling the ActionCaller strfunction() method"""
1994 def actfunc(a1, a2, a3, a4):
1996 def strfunc(a1, a2, a3, a4, args=strfunc_args):
1997 args.extend([a1, a2, a3, a4])
1999 af = SCons.Action.ActionFactory(actfunc, strfunc)
2000 ac = SCons.Action.ActionCaller(af, [1, '$FOO', 3, '$WS'], {})
2001 ac.strfunction([], [], Environment(FOO = 2, WS='white space'))
2002 assert strfunc_args == [1, '2', 3, 'white space'], strfunc_args
2005 d = {'a3' : 6, 'a2' : '$BAR', 'a1' : 4, 'a4' : '$WS'}
2006 ac = SCons.Action.ActionCaller(af, [], d)
2007 ac.strfunction([], [], Environment(BAR = 5, WS='w s'))
2008 assert strfunc_args == [4, '5', 6, 'w s'], strfunc_args
2010 class ActionFactoryTestCase(unittest.TestCase):
2011 def test___init__(self):
2012 """Test creation of an ActionFactory"""
2017 ac = SCons.Action.ActionFactory(actfunc, strfunc)
2018 assert ac.actfunc is actfunc, ac.actfunc
2019 assert ac.strfunc is strfunc, ac.strfunc
2021 def test___call__(self):
2022 """Test calling whatever's returned from an ActionFactory"""
2025 def actfunc(a1, a2, a3, args=actfunc_args):
2026 args.extend([a1, a2, a3])
2027 def strfunc(a1, a2, a3, args=strfunc_args):
2028 args.extend([a1, a2, a3])
2029 af = SCons.Action.ActionFactory(actfunc, strfunc)
2030 af(3, 6, 9)([], [], Environment())
2031 assert actfunc_args == [3, 6, 9], actfunc_args
2032 assert strfunc_args == [3, 6, 9], strfunc_args
2035 class ActionCompareTestCase(unittest.TestCase):
2037 def test_1_solo_name(self):
2038 """Test Lazy Cmd Generator Action get_name alone.
2040 Basically ensures we can locate the builder, comparing it to
2041 itself along the way."""
2042 bar = SCons.Builder.Builder(action = {})
2043 env = Environment( BUILDERS = {'BAR' : bar} )
2044 name = bar.get_name(env)
2045 assert name == 'BAR', name
2047 def test_2_multi_name(self):
2048 """Test LazyCmdGenerator Action get_name multi builders.
2050 Ensure that we can compare builders (and thereby actions) to
2051 each other safely."""
2052 foo = SCons.Builder.Builder(action = '$FOO', suffix = '.foo')
2053 bar = SCons.Builder.Builder(action = {})
2055 assert foo.action != bar.action
2056 env = Environment( BUILDERS = {'FOO' : foo,
2058 name = foo.get_name(env)
2059 assert name == 'FOO', name
2060 name = bar.get_name(env)
2061 assert name == 'BAR', name
2063 def test_3_dict_names(self):
2064 """Test Action/Suffix dicts with get_name.
2066 Verifies that Action/Suffix dictionaries work correctly,
2067 especially two builders that can generate the same suffix,
2068 where one of the builders has a suffix dictionary with a None
2071 foo = SCons.Builder.Builder(action = '$FOO', suffix = '.foo')
2072 bar = SCons.Builder.Builder(action = {}, suffix={None:'.bar'})
2073 bar.add_action('.cow', "$MOO")
2074 dog = SCons.Builder.Builder(suffix = '.bar')
2076 env = Environment( BUILDERS = {'FOO' : foo,
2080 assert foo.get_name(env) == 'FOO', foo.get_name(env)
2081 assert bar.get_name(env) == 'BAR', bar.get_name(env)
2082 assert dog.get_name(env) == 'DOG', dog.get_name(env)
2085 if __name__ == "__main__":
2086 suite = unittest.TestSuite()
2087 tclasses = [ _ActionActionTestCase,
2089 CommandActionTestCase,
2090 CommandGeneratorActionTestCase,
2091 FunctionActionTestCase,
2094 ActionCallerTestCase,
2095 ActionFactoryTestCase,
2096 ActionCompareTestCase ]
2097 for tclass in tclasses:
2098 names = unittest.getTestCaseNames(tclass, 'test_')
2099 suite.addTests(list(map(tclass, names)))
2100 if not unittest.TextTestRunner().run(suite).wasSuccessful():
2105 # indent-tabs-mode:nil
2107 # vim: set expandtab tabstop=4 shiftwidth=4: