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"])
307 if hasattr(types, 'UnicodeType'):
308 a2 = eval("SCons.Action.Action(u'string')")
309 assert isinstance(a2, SCons.Action.CommandAction), a2
312 assert isinstance(a, SCons.Action.CommandAction), a
313 assert a.cmd_list == [ "explicit", "command", "line" ], a.cmd_list
314 test_positional_args(line_action, [[ "explicit", "command", "line" ]])
316 def test_ListAction(self):
317 """Test the Action() factory's creation of ListAction objects
319 a1 = SCons.Action.Action(["x", "y", "z", [ "a", "b", "c"]])
320 assert isinstance(a1, SCons.Action.ListAction), a1
321 assert a1.varlist is (), a1.varlist
322 assert isinstance(a1.list[0], SCons.Action.CommandAction), a1.list[0]
323 assert a1.list[0].cmd_list == "x", a1.list[0].cmd_list
324 assert isinstance(a1.list[1], SCons.Action.CommandAction), a1.list[1]
325 assert a1.list[1].cmd_list == "y", a1.list[1].cmd_list
326 assert isinstance(a1.list[2], SCons.Action.CommandAction), a1.list[2]
327 assert a1.list[2].cmd_list == "z", a1.list[2].cmd_list
328 assert isinstance(a1.list[3], SCons.Action.CommandAction), a1.list[3]
329 assert a1.list[3].cmd_list == [ "a", "b", "c" ], a1.list[3].cmd_list
331 a2 = SCons.Action.Action("x\ny\nz")
332 assert isinstance(a2, SCons.Action.ListAction), a2
333 assert a2.varlist is (), a2.varlist
334 assert isinstance(a2.list[0], SCons.Action.CommandAction), a2.list[0]
335 assert a2.list[0].cmd_list == "x", a2.list[0].cmd_list
336 assert isinstance(a2.list[1], SCons.Action.CommandAction), a2.list[1]
337 assert a2.list[1].cmd_list == "y", a2.list[1].cmd_list
338 assert isinstance(a2.list[2], SCons.Action.CommandAction), a2.list[2]
339 assert a2.list[2].cmd_list == "z", a2.list[2].cmd_list
344 a3 = SCons.Action.Action(["x", foo, "z"])
345 assert isinstance(a3, SCons.Action.ListAction), a3
346 assert a3.varlist is (), a3.varlist
347 assert isinstance(a3.list[0], SCons.Action.CommandAction), a3.list[0]
348 assert a3.list[0].cmd_list == "x", a3.list[0].cmd_list
349 assert isinstance(a3.list[1], SCons.Action.FunctionAction), a3.list[1]
350 assert a3.list[1].execfunction == foo, a3.list[1].execfunction
351 assert isinstance(a3.list[2], SCons.Action.CommandAction), a3.list[2]
352 assert a3.list[2].cmd_list == "z", a3.list[2].cmd_list
354 a4 = SCons.Action.Action(["x", "y"], strfunction=foo)
355 assert isinstance(a4, SCons.Action.ListAction), a4
356 assert a4.varlist is (), a4.varlist
357 assert isinstance(a4.list[0], SCons.Action.CommandAction), a4.list[0]
358 assert a4.list[0].cmd_list == "x", a4.list[0].cmd_list
359 assert a4.list[0].strfunction == foo, a4.list[0].strfunction
360 assert isinstance(a4.list[1], SCons.Action.CommandAction), a4.list[1]
361 assert a4.list[1].cmd_list == "y", a4.list[1].cmd_list
362 assert a4.list[1].strfunction == foo, a4.list[1].strfunction
364 a5 = SCons.Action.Action("x\ny", strfunction=foo)
365 assert isinstance(a5, SCons.Action.ListAction), a5
366 assert a5.varlist is (), a5.varlist
367 assert isinstance(a5.list[0], SCons.Action.CommandAction), a5.list[0]
368 assert a5.list[0].cmd_list == "x", a5.list[0].cmd_list
369 assert a5.list[0].strfunction == foo, a5.list[0].strfunction
370 assert isinstance(a5.list[1], SCons.Action.CommandAction), a5.list[1]
371 assert a5.list[1].cmd_list == "y", a5.list[1].cmd_list
372 assert a5.list[1].strfunction == foo, a5.list[1].strfunction
374 def test_CommandGeneratorAction(self):
375 """Test the Action() factory's creation of CommandGeneratorAction objects
379 def gen_action(a, foo=foo):
380 assert isinstance(a, SCons.Action.CommandGeneratorAction), a
381 assert a.generator is foo, a.generator
382 test_positional_args(gen_action, foo, generator=1)
384 def test_LazyCmdGeneratorAction(self):
385 """Test the Action() factory's creation of lazy CommandGeneratorAction objects
388 assert isinstance(a, SCons.Action.LazyAction), a
389 assert a.var == "FOO", a.var
390 assert a.cmd_list == "${FOO}", a.cmd_list
391 test_positional_args(lazy_action, "$FOO")
392 test_positional_args(lazy_action, "${FOO}")
394 def test_no_action(self):
395 """Test when the Action() factory can't create an action object
397 a5 = SCons.Action.Action(1)
398 assert a5 is None, a5
400 def test_reentrance(self):
401 """Test the Action() factory when the action is already an Action object
403 a1 = SCons.Action.Action("foo")
404 a2 = SCons.Action.Action(a1)
407 class _ActionActionTestCase(unittest.TestCase):
409 def test__init__(self):
410 """Test creation of _ActionAction objects
422 a = SCons.Action._ActionAction()
423 assert not hasattr(a, 'strfunction')
424 assert a.cmdstr is _null, a.cmdstr
425 assert a.varlist == (), a.varlist
426 assert a.presub is _null, a.presub
427 assert a.chdir is None, a.chdir
428 assert a.exitstatfunc is SCons.Action.default_exitstatfunc, a.exitstatfunc
430 assert SCons.Action._ActionAction(kwarg = 1)
431 assert not hasattr(a, 'kwarg')
432 assert not hasattr(a, 'strfunction')
433 assert a.cmdstr is _null, a.cmdstr
434 assert a.varlist == (), a.varlist
435 assert a.presub is _null, a.presub
436 assert a.chdir is None, a.chdir
437 assert a.exitstatfunc is SCons.Action.default_exitstatfunc, a.exitstatfunc
439 a = SCons.Action._ActionAction(strfunction=func1)
440 assert a.strfunction is func1, a.strfunction
442 a = SCons.Action._ActionAction(strfunction=None)
443 assert not hasattr(a, 'strfunction')
444 assert a.cmdstr is None, a.cmdstr
446 a = SCons.Action._ActionAction(cmdstr='cmdstr')
447 assert not hasattr(a, 'strfunction')
448 assert a.cmdstr is 'cmdstr', a.cmdstr
450 a = SCons.Action._ActionAction(cmdstr=None)
451 assert not hasattr(a, 'strfunction')
452 assert a.cmdstr is None, a.cmdstr
455 a = SCons.Action._ActionAction(varlist=t)
456 assert a.varlist == t, a.varlist
458 a = SCons.Action._ActionAction(presub=func1)
459 assert a.presub is func1, a.presub
461 a = SCons.Action._ActionAction(chdir=1)
462 assert a.chdir is 1, a.chdir
464 a = SCons.Action._ActionAction(exitstatfunc=func1)
465 assert a.exitstatfunc is func1, a.exitstatfunc
467 a = SCons.Action._ActionAction(
468 # alphabetical order ...
476 assert a.chdir is 'x', a.chdir
477 assert a.cmdstr is 'cmdstr', a.cmdstr
478 assert a.exitstatfunc is func3, a.exitstatfunc
479 assert a.presub is func2, a.presub
480 assert a.strfunction is func1, a.strfunction
481 assert a.varlist is t, a.varlist
483 def test_dup_keywords(self):
484 """Test handling of both cmdstr and strfunction arguments
488 a = SCons.Action.Action('foo', cmdstr='string', strfunction=func)
489 except SCons.Errors.UserError, e:
491 m = 'Cannot have both strfunction and cmdstr args to Action()'
492 assert s.find(m) != -1, 'Unexpected string: %s' % s
494 raise Exception, "did not catch expected UserError"
496 def test___cmp__(self):
497 """Test Action comparison
499 a1 = SCons.Action.Action("x")
500 a2 = SCons.Action.Action("x")
502 a3 = SCons.Action.Action("y")
506 def test_print_cmd_lines(self):
507 """Test the print_cmd_lines() method
509 save_stdout = sys.stdout
512 def execfunc(target, source, env):
514 a = SCons.Action.Action(execfunc)
516 sio = StringIO.StringIO()
518 a.print_cmd_line("foo bar", None, None, None)
520 assert s == "foo bar\n", s
523 sys.stdout = save_stdout
525 def test___call__(self):
526 """Test calling an Action
528 save_stdout = sys.stdout
530 save_print_actions = SCons.Action.print_actions
531 save_print_actions_presub = SCons.Action.print_actions_presub
532 save_execute_actions = SCons.Action.execute_actions
533 #SCons.Action.print_actions = 0
535 test = TestCmd.TestCmd(workdir = '')
536 test.subdir('sub', 'xyz')
537 os.chdir(test.workpath())
542 def execfunc(target, source, env):
543 assert type(target) is type([]), type(target)
544 assert type(source) is type([]), type(source)
546 a = SCons.Action.Action(execfunc)
548 def firstfunc(target, source, env):
549 assert type(target) is type([]), type(target)
550 assert type(source) is type([]), type(source)
552 def lastfunc(target, source, env):
553 assert type(target) is type([]), type(target)
554 assert type(source) is type([]), type(source)
556 b = SCons.Action.Action([firstfunc, execfunc, lastfunc])
558 sio = StringIO.StringIO()
560 result = a("out", "in", env)
561 assert result.status == 7, result
563 assert s == "execfunc(['out'], ['in'])\n", s
566 expect = "os.chdir(%s)\nexecfunc(['out'], ['in'])\nos.chdir(%s)\n"
568 sio = StringIO.StringIO()
570 result = a("out", "in", env)
571 assert result.status == 7, result.status
573 assert s == expect % (repr('xyz'), repr(test.workpath())), s
575 sio = StringIO.StringIO()
577 result = a("out", "in", env, chdir='sub')
578 assert result.status == 7, result.status
580 assert s == expect % (repr('sub'), repr(test.workpath())), s
584 sio = StringIO.StringIO()
586 result = b("out", "in", env)
587 assert result.status == 7, result.status
589 assert s == "firstfunc(['out'], ['in'])\nexecfunc(['out'], ['in'])\n", s
591 SCons.Action.execute_actions = 0
593 sio = StringIO.StringIO()
595 result = a("out", "in", env)
596 assert result == 0, result
598 assert s == "execfunc(['out'], ['in'])\n", s
600 sio = StringIO.StringIO()
602 result = b("out", "in", env)
603 assert result == 0, result
605 assert s == "firstfunc(['out'], ['in'])\nexecfunc(['out'], ['in'])\nlastfunc(['out'], ['in'])\n", s
607 SCons.Action.print_actions_presub = 1
608 SCons.Action.execute_actions = 1
610 sio = StringIO.StringIO()
612 result = a("out", "in", env)
613 assert result.status == 7, result.status
615 assert s == "Building out with action:\n execfunc(target, source, env)\nexecfunc(['out'], ['in'])\n", s
617 sio = StringIO.StringIO()
619 result = a("out", "in", env, presub=0)
620 assert result.status == 7, result.status
622 assert s == "execfunc(['out'], ['in'])\n", s
624 sio = StringIO.StringIO()
626 result = a("out", "in", env, presub=1)
627 assert result.status == 7, result.status
629 assert s == "Building out with action:\n execfunc(target, source, env)\nexecfunc(['out'], ['in'])\n", s
631 sio = StringIO.StringIO()
633 result = b(["out"], "in", env, presub=1)
634 assert result.status == 7, result.status
636 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
638 sio = StringIO.StringIO()
640 result = b(["out", "list"], "in", env, presub=1)
641 assert result.status == 7, result.status
643 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
645 a2 = SCons.Action.Action(execfunc)
647 sio = StringIO.StringIO()
649 result = a2("out", "in", env)
650 assert result.status == 7, result.status
652 assert s == "Building out with action:\n execfunc(target, source, env)\nexecfunc(['out'], ['in'])\n", s
654 sio = StringIO.StringIO()
656 result = a2("out", "in", env, presub=0)
657 assert result.status == 7, result.status
659 assert s == "execfunc(['out'], ['in'])\n", s
661 SCons.Action.execute_actions = 0
663 sio = StringIO.StringIO()
665 result = a2("out", "in", env, presub=0)
666 assert result == 0, result
668 assert s == "execfunc(['out'], ['in'])\n", s
670 sio = StringIO.StringIO()
672 result = a("out", "in", env, presub=0, execute=1, show=0)
673 assert result.status == 7, result.status
677 sys.stdout = save_stdout
678 exitstatfunc_result = []
680 def exitstatfunc(stat, result=exitstatfunc_result):
684 result = a("out", "in", env, exitstatfunc=exitstatfunc)
685 assert result == 0, result
686 assert exitstatfunc_result == [], exitstatfunc_result
688 result = a("out", "in", env, execute=1, exitstatfunc=exitstatfunc)
689 assert result.status == 7, result.status
690 assert exitstatfunc_result == [7], exitstatfunc_result
692 SCons.Action.execute_actions = 1
695 def my_print_cmd_line(s, target, source, env, result=result):
697 env['PRINT_CMD_LINE_FUNC'] = my_print_cmd_line
698 a("output", "input", env)
699 assert result == ["execfunc(['output'], ['input'])"], result
703 sys.stdout = save_stdout
704 SCons.Action.print_actions = save_print_actions
705 SCons.Action.print_actions_presub = save_print_actions_presub
706 SCons.Action.execute_actions = save_execute_actions
708 def test_presub_lines(self):
709 """Test the presub_lines() method
712 a = SCons.Action.Action("x")
713 s = a.presub_lines(env)
716 a = SCons.Action.Action(["y", "z"])
717 s = a.presub_lines(env)
718 assert s == ['y', 'z'], s
722 a = SCons.Action.Action(func)
723 s = a.presub_lines(env)
724 assert s == ["func(target, source, env)"], s
726 def gen(target, source, env, for_signature):
727 return 'generat' + env.get('GEN', 'or')
728 a = SCons.Action.Action(gen, generator=1)
729 s = a.presub_lines(env)
730 assert s == ["generator"], s
731 s = a.presub_lines(Environment(GEN = 'ed'))
732 assert s == ["generated"], s
734 a = SCons.Action.Action("$ACT")
735 s = a.presub_lines(env)
737 s = a.presub_lines(Environment(ACT = 'expanded action'))
738 assert s == ['expanded action'], s
741 """Test adding Actions to stuff."""
742 # Adding actions to other Actions or to stuff that can
743 # be converted into an Action should produce a ListAction
744 # containing all the Actions.
747 baz = SCons.Action.Action(bar, generator=1)
748 act1 = SCons.Action.Action('foo bar')
749 act2 = SCons.Action.Action([ 'foo', bar ])
752 assert isinstance(sum, SCons.Action.ListAction), str(sum)
753 assert len(sum.list) == 3, len(sum.list)
754 assert [isinstance(x, SCons.Action.ActionBase) for x in sum.list] == [ 1, 1, 1 ]
757 assert isinstance(sum, SCons.Action.ListAction), str(sum)
758 assert len(sum.list) == 2, len(sum.list)
761 assert isinstance(sum, SCons.Action.ListAction), str(sum)
762 assert len(sum.list) == 4, len(sum.list)
764 # Should also be able to add command generators to each other
767 assert isinstance(sum, SCons.Action.ListAction), str(sum)
768 assert len(sum.list) == 2, len(sum.list)
771 assert isinstance(sum, SCons.Action.ListAction), str(sum)
772 assert len(sum.list) == 2, len(sum.list)
775 assert isinstance(sum, SCons.Action.ListAction), str(sum)
776 assert len(sum.list) == 3, len(sum.list)
778 # Also should be able to add Actions to anything that can
779 # be converted into an action.
781 assert isinstance(sum, SCons.Action.ListAction), str(sum)
782 assert len(sum.list) == 2, len(sum.list)
783 assert isinstance(sum.list[1], SCons.Action.FunctionAction)
785 sum = 'foo bar' + act2
786 assert isinstance(sum, SCons.Action.ListAction), str(sum)
787 assert len(sum.list) == 3, len(sum.list)
788 assert isinstance(sum.list[0], SCons.Action.CommandAction)
790 sum = [ 'foo', 'bar' ] + act1
791 assert isinstance(sum, SCons.Action.ListAction), str(sum)
792 assert len(sum.list) == 3, sum.list
793 assert isinstance(sum.list[0], SCons.Action.CommandAction)
794 assert isinstance(sum.list[1], SCons.Action.CommandAction)
796 sum = act2 + [ baz, bar ]
797 assert isinstance(sum, SCons.Action.ListAction), str(sum)
798 assert len(sum.list) == 4, len(sum.list)
799 assert isinstance(sum.list[2], SCons.Action.CommandGeneratorAction)
800 assert isinstance(sum.list[3], SCons.Action.FunctionAction)
807 assert 0, "Should have thrown a TypeError adding to an int."
814 assert 0, "Should have thrown a TypeError adding to an int."
816 class CommandActionTestCase(unittest.TestCase):
818 def test___init__(self):
819 """Test creation of a command Action
821 a = SCons.Action.CommandAction(["xyzzy"])
822 assert a.cmd_list == [ "xyzzy" ], a.cmd_list
823 assert a.cmdstr is _null, a.cmdstr
825 a = SCons.Action.CommandAction(["abra"], cmdstr="cadabra")
826 assert a.cmd_list == [ "abra" ], a.cmd_list
827 assert a.cmdstr == "cadabra", a.cmdstr
829 def test___str__(self):
830 """Test fetching the pre-substitution string for command Actions
833 act = SCons.Action.CommandAction('xyzzy $TARGET $SOURCE')
835 assert s == 'xyzzy $TARGET $SOURCE', s
837 act = SCons.Action.CommandAction(['xyzzy',
838 '$TARGET', '$SOURCE',
839 '$TARGETS', '$SOURCES'])
841 assert s == "xyzzy $TARGET $SOURCE $TARGETS $SOURCES", s
843 def test_genstring(self):
844 """Test the genstring() method for command Actions
852 act = SCons.Action.CommandAction('xyzzy $TARGET $SOURCE')
853 expect = 'xyzzy $TARGET $SOURCE'
854 s = act.genstring([], [], env)
855 assert s == expect, s
856 s = act.genstring([t1], [s1], env)
857 assert s == expect, s
858 s = act.genstring([t1, t2], [s1, s2], env)
859 assert s == expect, s
861 act = SCons.Action.CommandAction('xyzzy $TARGETS $SOURCES')
862 expect = 'xyzzy $TARGETS $SOURCES'
863 s = act.genstring([], [], env)
864 assert s == expect, s
865 s = act.genstring([t1], [s1], env)
866 assert s == expect, s
867 s = act.genstring([t1, t2], [s1, s2], env)
868 assert s == expect, s
870 act = SCons.Action.CommandAction(['xyzzy',
871 '$TARGET', '$SOURCE',
872 '$TARGETS', '$SOURCES'])
873 expect = "xyzzy $TARGET $SOURCE $TARGETS $SOURCES"
874 s = act.genstring([], [], env)
875 assert s == expect, s
876 s = act.genstring([t1], [s1], env)
877 assert s == expect, s
878 s = act.genstring([t1, t2], [s1, s2], env)
879 assert s == expect, s
881 def test_strfunction(self):
882 """Test fetching the string representation of command Actions
890 act = SCons.Action.CommandAction('xyzzy $TARGET $SOURCE')
891 s = act.strfunction([], [], env)
892 assert s == 'xyzzy', s
893 s = act.strfunction([t1], [s1], env)
894 assert s == 'xyzzy t1 s1', s
895 s = act.strfunction([t1, t2], [s1, s2], env)
896 assert s == 'xyzzy t1 s1', s
898 act = SCons.Action.CommandAction('xyzzy $TARGET $SOURCE',
899 cmdstr='cmdstr - $SOURCE - $TARGET -')
900 s = act.strfunction([], [], env)
901 assert s == 'cmdstr - - -', s
902 s = act.strfunction([t1], [s1], env)
903 assert s == 'cmdstr - s1 - t1 -', s
904 s = act.strfunction([t1, t2], [s1, s2], env)
905 assert s == 'cmdstr - s1 - t1 -', s
907 act = SCons.Action.CommandAction('xyzzy $TARGETS $SOURCES')
908 s = act.strfunction([], [], env)
909 assert s == 'xyzzy', s
910 s = act.strfunction([t1], [s1], env)
911 assert s == 'xyzzy t1 s1', s
912 s = act.strfunction([t1, t2], [s1, s2], env)
913 assert s == 'xyzzy t1 t2 s1 s2', s
915 act = SCons.Action.CommandAction('xyzzy $TARGETS $SOURCES',
916 cmdstr='cmdstr = $SOURCES = $TARGETS =')
917 s = act.strfunction([], [], env)
918 assert s == 'cmdstr = = =', s
919 s = act.strfunction([t1], [s1], env)
920 assert s == 'cmdstr = s1 = t1 =', s
921 s = act.strfunction([t1, t2], [s1, s2], env)
922 assert s == 'cmdstr = s1 s2 = t1 t2 =', s
924 act = SCons.Action.CommandAction(['xyzzy',
925 '$TARGET', '$SOURCE',
926 '$TARGETS', '$SOURCES'])
927 s = act.strfunction([], [], env)
928 assert s == 'xyzzy', s
929 s = act.strfunction([t1], [s1], env)
930 assert s == 'xyzzy t1 s1 t1 s1', s
931 s = act.strfunction([t1, t2], [s1, s2], env)
932 assert s == 'xyzzy t1 s1 t1 t2 s1 s2', s
934 act = SCons.Action.CommandAction('xyzzy $TARGETS $SOURCES',
935 cmdstr='cmdstr\t$TARGETS\n$SOURCES ')
937 s = act.strfunction([], [], env)
938 assert s == 'cmdstr\t\n ', s
939 s = act.strfunction([t1], [s1], env)
940 assert s == 'cmdstr\tt1\ns1 ', s
941 s = act.strfunction([t1, t2], [s1, s2], env)
942 assert s == 'cmdstr\tt1 t2\ns1 s2 ', s
944 def sf(target, source, env):
945 return "sf was called"
946 act = SCons.Action.CommandAction('foo', strfunction=sf)
947 s = act.strfunction([], [], env)
948 assert s == "sf was called", s
951 def __init__(self, targets, sources, env):
956 def __init__(self, targets, sources, env):
961 def __init__(self, targets, sources, env):
965 def strfunction(self, targets, sources, env):
966 return 'actclass3 on %s to get %s'%(str(sources[0]),
969 def __init__(self, targets, sources, env):
975 act1 = SCons.Action.Action(actclass1([t1], [s1], env))
976 s = act1.strfunction([t1], [s1], env)
977 assert s == 'actclass1(["t1"], ["s1"])', s
979 act2 = SCons.Action.Action(actclass2([t1], [s1], env))
980 s = act2.strfunction([t1], [s1], env)
981 assert s == 'actclass2(["t1"], ["s1"])', s
983 act3 = SCons.Action.Action(actclass3([t1], [s1], env))
984 s = act3.strfunction([t1], [s1], env)
985 assert s == 'actclass3 on s1 to get t1', s
987 act4 = SCons.Action.Action(actclass4([t1], [s1], env))
988 s = act4.strfunction([t1], [s1], env)
991 act = SCons.Action.CommandAction("@foo bar")
992 s = act.strfunction([], [], env)
995 act = SCons.Action.CommandAction("@-foo bar")
996 s = act.strfunction([], [], env)
999 act = SCons.Action.CommandAction("-@foo bar")
1000 s = act.strfunction([], [], env)
1003 act = SCons.Action.CommandAction("-foo bar")
1004 s = act.strfunction([], [], env)
1005 assert s == "foo bar", s
1007 act = SCons.Action.CommandAction("@ foo bar")
1008 s = act.strfunction([], [], env)
1011 act = SCons.Action.CommandAction("@- foo bar")
1012 s = act.strfunction([], [], env)
1015 act = SCons.Action.CommandAction("-@ foo bar")
1016 s = act.strfunction([], [], env)
1019 act = SCons.Action.CommandAction("- foo bar")
1020 s = act.strfunction([], [], env)
1021 assert s == "foo bar", s
1023 def test_execute(self):
1024 """Test execution of command Actions
1029 except AttributeError:
1032 cmd1 = r'%s %s %s xyzzy' % (_python_, act_py, outfile)
1034 act = SCons.Action.CommandAction(cmd1)
1035 r = act([], [], env.Clone())
1037 c = test.read(outfile, 'r')
1038 assert c == "act.py: 'xyzzy'\n", c
1040 cmd2 = r'%s %s %s $TARGET' % (_python_, act_py, outfile)
1042 act = SCons.Action.CommandAction(cmd2)
1043 r = act(DummyNode('foo'), [], env.Clone())
1045 c = test.read(outfile, 'r')
1046 assert c == "act.py: 'foo'\n", c
1048 cmd3 = r'%s %s %s ${TARGETS}' % (_python_, act_py, outfile)
1050 act = SCons.Action.CommandAction(cmd3)
1051 r = act(list(map(DummyNode, ['aaa', 'bbb'])), [], env.Clone())
1053 c = test.read(outfile, 'r')
1054 assert c == "act.py: 'aaa' 'bbb'\n", c
1056 cmd4 = r'%s %s %s $SOURCES' % (_python_, act_py, outfile)
1058 act = SCons.Action.CommandAction(cmd4)
1059 r = act([], [DummyNode('one'), DummyNode('two')], env.Clone())
1061 c = test.read(outfile, 'r')
1062 assert c == "act.py: 'one' 'two'\n", c
1064 cmd4 = r'%s %s %s ${SOURCES[:2]}' % (_python_, act_py, outfile)
1066 act = SCons.Action.CommandAction(cmd4)
1067 sources = [DummyNode('three'), DummyNode('four'), DummyNode('five')]
1069 r = act([], source = sources, env = env2)
1071 c = test.read(outfile, 'r')
1072 assert c == "act.py: 'three' 'four'\n", c
1074 cmd5 = r'%s %s %s $TARGET XYZZY' % (_python_, act_py, outfile)
1076 act = SCons.Action.CommandAction(cmd5)
1077 env5 = Environment()
1078 if 'ENV' in scons_env:
1079 env5['ENV'] = scons_env['ENV']
1080 PATH = scons_env['ENV'].get('PATH', '')
1085 env5['ENV']['XYZZY'] = 'xyzzy'
1086 r = act(target = DummyNode('out5'), source = [], env = env5)
1088 act = SCons.Action.CommandAction(cmd5)
1089 r = act(target = DummyNode('out5'),
1091 env = env.Clone(ENV = {'XYZZY' : 'xyzzy5',
1094 c = test.read(outfile, 'r')
1095 assert c == "act.py: 'out5' 'XYZZY'\nact.py: 'xyzzy5'\n", c
1098 def __init__(self, str):
1104 def get_subst_proxy(self):
1107 cmd6 = r'%s %s %s ${TARGETS[1]} $TARGET ${SOURCES[:2]}' % (_python_, act_py, outfile)
1109 act = SCons.Action.CommandAction(cmd6)
1110 r = act(target = [Obj('111'), Obj('222')],
1111 source = [Obj('333'), Obj('444'), Obj('555')],
1114 c = test.read(outfile, 'r')
1115 assert c == "act.py: '222' '111' '333' '444'\n", c
1118 # NT treats execs of directories and non-executable files
1119 # as "file not found" errors
1120 expect_nonexistent = 1
1121 expect_nonexecutable_file = 1
1122 expect_nonexecutable_dir = 1
1123 elif sys.platform == 'cygwin':
1124 expect_nonexistent = 127
1125 # Newer cygwin seems to return 126 for following
1126 expect_nonexecutable_file = 126
1127 expect_nonexecutable_dir = 127
1129 expect_nonexistent = 127
1130 expect_nonexecutable_file = 126
1131 expect_nonexecutable_dir = 126
1133 # Test that a nonexistent command returns 127
1134 act = SCons.Action.CommandAction(python + "_no_such_command_")
1135 r = act([], [], env.Clone(out = outfile))
1136 assert r.status == expect_nonexistent, r.status
1138 # Test that trying to execute a directory returns 126
1139 dir, tail = os.path.split(python)
1140 act = SCons.Action.CommandAction(dir)
1141 r = act([], [], env.Clone(out = outfile))
1142 assert r.status == expect_nonexecutable_file, r.status
1144 # Test that trying to execute a non-executable file returns 126
1145 act = SCons.Action.CommandAction(outfile)
1146 r = act([], [], env.Clone(out = outfile))
1147 assert r.status == expect_nonexecutable_dir, r.status
1149 act = SCons.Action.CommandAction('%s %s 1' % (_python_, exit_py))
1150 r = act([], [], env)
1151 assert r.status == 1, r.status
1153 act = SCons.Action.CommandAction('@%s %s 1' % (_python_, exit_py))
1154 r = act([], [], env)
1155 assert r.status == 1, r.status
1157 act = SCons.Action.CommandAction('@-%s %s 1' % (_python_, exit_py))
1158 r = act([], [], env)
1161 act = SCons.Action.CommandAction('-%s %s 1' % (_python_, exit_py))
1162 r = act([], [], env)
1165 act = SCons.Action.CommandAction('@ %s %s 1' % (_python_, exit_py))
1166 r = act([], [], env)
1167 assert r.status == 1, r.status
1169 act = SCons.Action.CommandAction('@- %s %s 1' % (_python_, exit_py))
1170 r = act([], [], env)
1173 act = SCons.Action.CommandAction('- %s %s 1' % (_python_, exit_py))
1174 r = act([], [], env)
1177 def _DO_NOT_EXECUTE_test_pipe_execute(self):
1178 """Test capturing piped output from an action
1180 We used to have PIPE_BUILD support built right into
1181 Action.execute() for the benefit of the SConf subsystem, but we've
1182 moved that logic back into SConf itself. We'll leave this code
1183 here, just in case we ever want to resurrect this functionality
1184 in the future, but change the name of the test so it doesn't
1185 get executed as part of the normal test suite.
1187 pipe = open( pipe_file, "w" )
1188 self.env = Environment(ENV = {'ACTPY_PIPE' : '1'}, PIPE_BUILD = 1,
1189 PSTDOUT = pipe, PSTDERR = pipe)
1190 # everything should also work when piping output
1192 self.env['PSTDOUT'].close()
1193 pipe_out = test.read( pipe_file )
1195 act_out = "act.py: stdout: executed act.py"
1196 act_err = "act.py: stderr: executed act.py"
1198 # Since we are now using select(), stdout and stderr can be
1199 # intermixed, so count the lines separately.
1200 outlines = re.findall(act_out, pipe_out)
1201 errlines = re.findall(act_err, pipe_out)
1202 assert len(outlines) == 6, pipe_out + repr(outlines)
1203 assert len(errlines) == 6, pipe_out + repr(errlines)
1205 # test redirection operators
1206 def test_redirect(self, redir, stdout_msg, stderr_msg):
1207 cmd = r'%s %s %s xyzzy %s' % (_python_, act_py, outfile, redir)
1208 # Write the output and error messages to files because
1209 # Windows can't handle strings that are too big in its
1210 # external environment (os.spawnve() returns EINVAL,
1211 # "Invalid argument").
1212 stdout_file = test.workpath('stdout_msg')
1213 stderr_file = test.workpath('stderr_msg')
1214 open(stdout_file, 'w').write(stdout_msg)
1215 open(stderr_file, 'w').write(stderr_msg)
1216 pipe = open( pipe_file, "w" )
1217 act = SCons.Action.CommandAction(cmd)
1218 env = Environment( ENV = {'ACTPY_PIPE' : '1',
1219 'PIPE_STDOUT_FILE' : stdout_file,
1220 'PIPE_STDERR_FILE' : stderr_file},
1222 PSTDOUT = pipe, PSTDERR = pipe )
1223 r = act([], [], env)
1226 return (test.read(outfile2, 'r'), test.read(pipe_file, 'r'))
1228 (redirected, pipe_out) = test_redirect(self,'> %s' % outfile2,
1230 assert redirected == act_out
1231 assert pipe_out == act_err
1233 (redirected, pipe_out) = test_redirect(self,'2> %s' % outfile2,
1235 assert redirected == act_err
1236 assert pipe_out == act_out
1238 (redirected, pipe_out) = test_redirect(self,'> %s 2>&1' % outfile2,
1240 assert (redirected == act_out + act_err or
1241 redirected == act_err + act_out)
1242 assert pipe_out == ""
1244 act_err = "Long Command Output\n"*3000
1245 # the size of the string should exceed the system's default block size
1247 (redirected, pipe_out) = test_redirect(self,'> %s' % outfile2,
1249 assert (redirected == act_out)
1250 assert (pipe_out == act_err)
1252 def test_set_handler(self):
1253 """Test setting the command handler...
1259 def func(sh, escape, cmd, args, env, test=t):
1260 test.executed = args
1263 def escape_func(cmd):
1264 return '**' + cmd + '**'
1267 def __init__(self, x):
1271 def escape(self, escape_func):
1272 return escape_func(self.data)
1273 def is_literal(self):
1276 a = SCons.Action.CommandAction(["xyzzy"])
1277 e = Environment(SPAWN = func)
1279 assert t.executed == [ 'xyzzy' ], t.executed
1281 a = SCons.Action.CommandAction(["xyzzy"])
1282 e = Environment(SPAWN = '$FUNC', FUNC = func)
1284 assert t.executed == [ 'xyzzy' ], t.executed
1286 a = SCons.Action.CommandAction(["xyzzy"])
1287 e = Environment(SPAWN = func, SHELL = 'fake shell')
1289 assert t.executed == [ 'xyzzy' ], t.executed
1290 assert t.shell == 'fake shell', t.shell
1292 a = SCons.Action.CommandAction([ LiteralStr("xyzzy") ])
1293 e = Environment(SPAWN = func, ESCAPE = escape_func)
1295 assert t.executed == [ '**xyzzy**' ], t.executed
1297 def test_get_contents(self):
1298 """Test fetching the contents of a command Action
1300 def CmdGen(target, source, env, for_signature):
1301 assert for_signature
1303 (env["foo"], env["bar"])
1305 # The number 1 is there to make sure all args get converted to strings.
1306 a = SCons.Action.CommandAction(["|", "$(", "$foo", "|", "$bar",
1307 "$)", "|", "$baz", 1])
1308 c = a.get_contents(target=[], source=[],
1309 env=Environment(foo = 'FFF', bar = 'BBB',
1311 assert c == "| | FFF BBB 1", c
1313 # Make sure that CommandActions use an Environment's
1314 # subst_target_source() method for substitution.
1315 class SpecialEnvironment(Environment):
1316 def subst_target_source(self, strSubst, raw=0, target=[], source=[]):
1317 return 'subst_target_source: ' + strSubst
1319 c = a.get_contents(target=DummyNode('ttt'), source = DummyNode('sss'),
1320 env=SpecialEnvironment(foo = 'GGG', bar = 'CCC',
1322 assert c == 'subst_target_source: | $( $foo | $bar $) | $baz 1', c
1324 # We've discussed using the real target and source names in a
1325 # CommandAction's signature contents. This would have have the
1326 # advantage of recompiling when a file's name changes (keeping
1327 # debug info current), but it would currently break repository
1328 # logic that will change the file name based on whether the
1329 # files come from a repository or locally. If we ever move to
1330 # that scheme, then all of the '__t1__' and '__s6__' file names
1331 # in the asserts below would change to 't1' and 's6' and the
1333 t = list(map(DummyNode, ['t1', 't2', 't3', 't4', 't5', 't6']))
1334 s = list(map(DummyNode, ['s1', 's2', 's3', 's4', 's5', 's6']))
1337 a = SCons.Action.CommandAction(["$TARGET"])
1338 c = a.get_contents(target=t, source=s, env=env)
1341 a = SCons.Action.CommandAction(["$TARGETS"])
1342 c = a.get_contents(target=t, source=s, env=env)
1343 assert c == "t1 t2 t3 t4 t5 t6", c
1345 a = SCons.Action.CommandAction(["${TARGETS[2]}"])
1346 c = a.get_contents(target=t, source=s, env=env)
1349 a = SCons.Action.CommandAction(["${TARGETS[3:5]}"])
1350 c = a.get_contents(target=t, source=s, env=env)
1351 assert c == "t4 t5", c
1353 a = SCons.Action.CommandAction(["$SOURCE"])
1354 c = a.get_contents(target=t, source=s, env=env)
1357 a = SCons.Action.CommandAction(["$SOURCES"])
1358 c = a.get_contents(target=t, source=s, env=env)
1359 assert c == "s1 s2 s3 s4 s5 s6", c
1361 a = SCons.Action.CommandAction(["${SOURCES[2]}"])
1362 c = a.get_contents(target=t, source=s, env=env)
1365 a = SCons.Action.CommandAction(["${SOURCES[3:5]}"])
1366 c = a.get_contents(target=t, source=s, env=env)
1367 assert c == "s4 s5", c
1369 class CommandGeneratorActionTestCase(unittest.TestCase):
1371 def factory(self, act, **kw):
1372 """Pass any keywords as a dict"""
1373 return SCons.Action.CommandGeneratorAction(act, kw)
1375 def test___init__(self):
1376 """Test creation of a command generator Action
1378 def f(target, source, env):
1381 assert a.generator == f
1383 def test___str__(self):
1384 """Test the pre-substitution strings for command generator Actions
1386 def f(target, source, env, for_signature, self=self):
1388 # See if "env" is really a construction environment (or
1389 # looks like one) by accessing the FindIxes attribute.
1390 # (The Tool/mingw.py module has a generator that uses this,
1391 # and the __str__() method used to cause problems by passing
1392 # us a regular dictionary as a fallback.)
1398 assert s == 'FOO', s
1400 def test_genstring(self):
1401 """Test the command generator Action genstring() method
1403 def f(target, source, env, for_signature, self=self):
1404 dummy = env['dummy']
1406 return "$FOO $TARGET $SOURCE $TARGETS $SOURCES"
1409 s = a.genstring([], [], env=Environment(FOO='xyzzy', dummy=1))
1410 assert self.dummy == 1, self.dummy
1411 assert s == "$FOO $TARGET $SOURCE $TARGETS $SOURCES", s
1413 def test_execute(self):
1414 """Test executing a command generator Action
1417 def f(target, source, env, for_signature, self=self):
1418 dummy = env['dummy']
1420 s = env.subst("$FOO")
1421 assert s == 'foo baz\nbar ack', s
1423 def func_action(target, source, env, self=self):
1425 s = env.subst('$foo')
1426 assert s == 'bar', s
1428 def f2(target, source, env, for_signature, f=func_action):
1430 def ch(sh, escape, cmd, args, env, self=self):
1431 self.cmd.append(cmd)
1432 self.args.append(args)
1438 a([], [], env=Environment(FOO = 'foo baz\nbar ack',
1441 assert self.dummy == 1, self.dummy
1442 assert self.cmd == ['foo', 'bar'], self.cmd
1443 assert self.args == [[ 'foo', 'baz' ], [ 'bar', 'ack' ]], self.args
1445 b = self.factory(f2)
1447 b(target=[], source=[], env=Environment(foo = 'bar',
1449 assert self.dummy==2, self.dummy
1453 def __init__(self, t):
1456 self.t.rfile_called = 1
1458 def get_subst_proxy(self):
1460 def f3(target, source, env, for_signature):
1462 c = self.factory(f3)
1463 c(target=[], source=DummyFile(self), env=Environment())
1464 assert self.rfile_called
1466 def test_get_contents(self):
1467 """Test fetching the contents of a command generator Action
1469 def f(target, source, env, for_signature):
1472 assert for_signature, for_signature
1473 return [["guux", foo, "$(", "$ignore", "$)", bar,
1474 '${test("$( foo $bar $)")}' ]]
1477 assert mystr == "$( foo $bar $)", mystr
1480 env = Environment(foo = 'FFF', bar = 'BBB',
1481 ignore = 'foo', test=test)
1483 c = a.get_contents(target=[], source=[], env=env)
1484 assert c == "guux FFF BBB test", c
1486 def test_get_contents_of_function_action(self):
1487 """Test contents of a CommandGeneratorAction-generated FunctionAction
1494 "0,0,0,0,(),(),(d\000\000S),(),()",
1495 "0,0,0,0,(),(),(d\x00\x00S),(),()",
1499 "1,1,0,0,(),(),(d\000\000S),(),()",
1500 "1,1,0,0,(),(),(d\x00\x00S),(),()",
1503 def f_global(target, source, env, for_signature):
1504 return SCons.Action.Action(GlobalFunc)
1507 #def f_local(target, source, env, for_signature):
1508 def f_local(target, source, env, for_signature, LocalFunc=LocalFunc):
1509 return SCons.Action.Action(LocalFunc)
1511 env = Environment(XYZ = 'foo')
1513 a = self.factory(f_global)
1514 c = a.get_contents(target=[], source=[], env=env)
1515 assert c in func_matches, repr(c)
1517 a = self.factory(f_local)
1518 c = a.get_contents(target=[], source=[], env=env)
1519 assert c in func_matches, repr(c)
1521 def f_global(target, source, env, for_signature):
1522 return SCons.Action.Action(GlobalFunc, varlist=['XYZ'])
1525 #def f_local(target, source, env, for_signature):
1526 def f_local(target, source, env, for_signature, LocalFunc=LocalFunc):
1527 return SCons.Action.Action(LocalFunc, varlist=['XYZ'])
1529 matches_foo = [x + "foo" for x in func_matches]
1531 a = self.factory(f_global)
1532 c = a.get_contents(target=[], source=[], env=env)
1533 assert c in matches_foo, repr(c)
1535 a = self.factory(f_local)
1536 c = a.get_contents(target=[], source=[], env=env)
1537 assert c in matches_foo, repr(c)
1540 class FunctionActionTestCase(unittest.TestCase):
1542 def test___init__(self):
1543 """Test creation of a function Action
1554 a = SCons.Action.FunctionAction(func1, {})
1555 assert a.execfunction == func1, a.execfunction
1556 assert isinstance(a.strfunction, types.MethodType), type(a.strfunction)
1558 a = SCons.Action.FunctionAction(func2, { 'strfunction' : func3 })
1559 assert a.execfunction == func2, a.execfunction
1560 assert a.strfunction == func3, a.strfunction
1562 def test___str__(self):
1563 """Test the __str__() method for function Actions
1567 a = SCons.Action.FunctionAction(func1, {})
1569 assert s == "func1(target, source, env)", s
1574 a = SCons.Action.FunctionAction(class1(), {})
1576 assert s == "class1(target, source, env)", s
1578 def test_execute(self):
1579 """Test executing a function Action
1582 def f(target, source, env):
1587 assert env.subst("$BAR") == 'foo bar', env.subst("$BAR")
1589 a = SCons.Action.FunctionAction(f, {})
1590 a(target=1, source=2, env=Environment(BAR = 'foo bar',
1592 assert self.inc == 1, self.inc
1593 assert self.source == [2], self.source
1594 assert self.target == [1], self.target
1598 def function1(target, source, env):
1602 open(t, 'w').write("function1\n")
1605 act = SCons.Action.FunctionAction(function1, {})
1606 r = act(target = [outfile, outfile2], source=[], env=Environment())
1607 assert r.status == 1, r.status
1609 assert count == 1, count
1610 c = test.read(outfile, 'r')
1611 assert c == "function1\n", c
1612 c = test.read(outfile2, 'r')
1613 assert c == "function1\n", c
1616 def __init__(self, target, source, env):
1617 open(env['out'], 'w').write("class1a\n")
1619 act = SCons.Action.FunctionAction(class1a, {})
1620 r = act([], [], Environment(out = outfile))
1621 assert isinstance(r.status, class1a), r.status
1622 c = test.read(outfile, 'r')
1623 assert c == "class1a\n", c
1626 def __call__(self, target, source, env):
1627 open(env['out'], 'w').write("class1b\n")
1630 act = SCons.Action.FunctionAction(class1b(), {})
1631 r = act([], [], Environment(out = outfile))
1632 assert r.status == 2, r.status
1633 c = test.read(outfile, 'r')
1634 assert c == "class1b\n", c
1636 def build_it(target, source, env, executor=None, self=self):
1639 def string_it(target, source, env, executor=None, self=self):
1642 act = SCons.Action.FunctionAction(build_it,
1643 { 'strfunction' : string_it })
1644 r = act([], [], Environment())
1646 assert self.build_it
1647 assert self.string_it
1649 def test_get_contents(self):
1650 """Test fetching the contents of a function Action
1657 "0,0,0,0,(),(),(d\000\000S),(),()",
1658 "0,0,0,0,(),(),(d\x00\x00S),(),()",
1662 "1,1,0,0,(),(),(d\000\000S),(),()",
1663 "1,1,0,0,(),(),(d\x00\x00S),(),()",
1666 def factory(act, **kw):
1667 return SCons.Action.FunctionAction(act, kw)
1669 a = factory(GlobalFunc)
1670 c = a.get_contents(target=[], source=[], env=Environment())
1671 assert c in func_matches, repr(c)
1673 a = factory(LocalFunc)
1674 c = a.get_contents(target=[], source=[], env=Environment())
1675 assert c in func_matches, repr(c)
1677 matches_foo = [x + "foo" for x in func_matches]
1679 a = factory(GlobalFunc, varlist=['XYZ'])
1680 c = a.get_contents(target=[], source=[], env=Environment())
1681 assert c in func_matches, repr(c)
1682 c = a.get_contents(target=[], source=[], env=Environment(XYZ='foo'))
1683 assert c in matches_foo, repr(c)
1685 ##TODO: is this set of tests still needed?
1686 # Make sure a bare string varlist works
1687 a = factory(GlobalFunc, varlist='XYZ')
1688 c = a.get_contents(target=[], source=[], env=Environment())
1689 assert c in func_matches, repr(c)
1690 c = a.get_contents(target=[], source=[], env=Environment(XYZ='foo'))
1691 assert c in matches_foo, repr(c)
1694 def get_contents(self, target, source, env):
1697 c = a.get_contents(target=[], source=[], env=Environment())
1698 assert c == 'xyzzy', repr(c)
1701 def LocalMethod(self):
1704 a = factory(lc.LocalMethod)
1705 c = a.get_contents(target=[], source=[], env=Environment())
1706 assert c in meth_matches, repr(c)
1708 def test_strfunction(self):
1709 """Test the FunctionAction.strfunction() method
1714 def factory(act, **kw):
1715 return SCons.Action.FunctionAction(act, kw)
1718 s = a.strfunction(target=[], source=[], env=Environment())
1719 assert s == 'func([], [])', s
1721 a = factory(func, strfunction=None)
1722 s = a.strfunction(target=[], source=[], env=Environment())
1725 a = factory(func, cmdstr='function')
1726 s = a.strfunction(target=[], source=[], env=Environment())
1727 assert s == 'function', s
1729 class ListActionTestCase(unittest.TestCase):
1731 def test___init__(self):
1732 """Test creation of a list of subsidiary Actions
1736 a = SCons.Action.ListAction(["x", func, ["y", "z"]])
1737 assert isinstance(a.list[0], SCons.Action.CommandAction)
1738 assert isinstance(a.list[1], SCons.Action.FunctionAction)
1739 assert isinstance(a.list[2], SCons.Action.ListAction)
1740 assert a.list[2].list[0].cmd_list == 'y'
1742 def test___str__(self):
1743 """Test the __str__() method for a list of subsidiary Actions
1745 def f(target,source,env):
1747 def g(target,source,env):
1749 a = SCons.Action.ListAction([f, g, "XXX", f])
1751 assert s == "f(target, source, env)\ng(target, source, env)\nXXX\nf(target, source, env)", s
1753 def test_genstring(self):
1754 """Test the genstring() method for a list of subsidiary Actions
1756 def f(target,source,env):
1758 def g(target,source,env,for_signature):
1759 return 'generated %s %s' % (target[0], source[0])
1760 g = SCons.Action.Action(g, generator=1)
1761 a = SCons.Action.ListAction([f, g, "XXX", f])
1762 s = a.genstring(['foo.x'], ['bar.y'], Environment())
1763 assert s == "f(target, source, env)\ngenerated foo.x bar.y\nXXX\nf(target, source, env)", s
1765 def test_execute(self):
1766 """Test executing a list of subsidiary Actions
1769 def f(target,source,env):
1772 a = SCons.Action.ListAction([f, f, f])
1773 a([], [], Environment(s = self))
1774 assert self.inc == 3, self.inc
1776 cmd2 = r'%s %s %s syzygy' % (_python_, act_py, outfile)
1778 def function2(target, source, env):
1779 open(env['out'], 'a').write("function2\n")
1783 def __call__(self, target, source, env):
1784 open(env['out'], 'a').write("class2a\n")
1788 def __init__(self, target, source, env):
1789 open(env['out'], 'a').write("class2b\n")
1790 act = SCons.Action.ListAction([cmd2, function2, class2a(), class2b])
1791 r = act([], [], Environment(out = outfile))
1792 assert isinstance(r.status, class2b), r.status
1793 c = test.read(outfile, 'r')
1794 assert c == "act.py: 'syzygy'\nfunction2\nclass2a\nclass2b\n", c
1796 def test_get_contents(self):
1797 """Test fetching the contents of a list of subsidiary Actions
1800 def gen(target, source, env, for_signature):
1804 a = SCons.Action.ListAction(["x",
1805 SCons.Action.Action(gen, generator=1),
1807 c = a.get_contents(target=[], source=[], env=Environment(s = self))
1808 assert self.foo==1, self.foo
1809 assert c == "xyz", c
1811 class LazyActionTestCase(unittest.TestCase):
1812 def test___init__(self):
1813 """Test creation of a lazy-evaluation Action
1815 # Environment variable references should create a special type
1816 # of LazyAction that lazily evaluates the variable for whether
1817 # it's a string or something else before doing anything.
1818 a9 = SCons.Action.Action('$FOO')
1819 assert isinstance(a9, SCons.Action.LazyAction), a9
1820 assert a9.var == 'FOO', a9.var
1822 a10 = SCons.Action.Action('${FOO}')
1823 assert isinstance(a10, SCons.Action.LazyAction), a10
1824 assert a10.var == 'FOO', a10.var
1826 def test_genstring(self):
1827 """Test the lazy-evaluation Action genstring() method
1829 def f(target, source, env):
1831 a = SCons.Action.Action('$BAR')
1832 env1 = Environment(BAR=f, s=self)
1833 env2 = Environment(BAR='xxx', s=self)
1834 s = a.genstring([], [], env=env1)
1835 assert s == "f(target, source, env)", s
1836 s = a.genstring([], [], env=env2)
1837 assert s == 'xxx', s
1839 def test_execute(self):
1840 """Test executing a lazy-evaluation Action
1842 def f(target, source, env):
1846 a = SCons.Action.Action('$BAR')
1847 a([], [], env=Environment(BAR = f, s = self))
1848 assert self.test == 1, self.test
1849 cmd = r'%s %s %s lazy' % (_python_, act_py, outfile)
1850 a([], [], env=Environment(BAR = cmd, s = self))
1851 c = test.read(outfile, 'r')
1852 assert c == "act.py: 'lazy'\n", c
1854 def test_get_contents(self):
1855 """Test fetching the contents of a lazy-evaluation Action
1857 a = SCons.Action.Action("${FOO}")
1858 env = Environment(FOO = [["This", "is", "a", "test"]])
1859 c = a.get_contents(target=[], source=[], env=env)
1860 assert c == "This is a test", c
1862 def test_get_contents_of_function_action(self):
1863 """Test fetching the contents of a lazy-evaluation FunctionAction
1870 "0,0,0,0,(),(),(d\000\000S),(),()",
1871 "0,0,0,0,(),(),(d\x00\x00S),(),()",
1875 "1,1,0,0,(),(),(d\000\000S),(),()",
1876 "1,1,0,0,(),(),(d\x00\x00S),(),()",
1879 def factory(act, **kw):
1880 return SCons.Action.FunctionAction(act, kw)
1883 a = SCons.Action.Action("${FOO}")
1885 env = Environment(FOO = factory(GlobalFunc))
1886 c = a.get_contents(target=[], source=[], env=env)
1887 assert c in func_matches, repr(c)
1889 env = Environment(FOO = factory(LocalFunc))
1890 c = a.get_contents(target=[], source=[], env=env)
1891 assert c in func_matches, repr(c)
1893 matches_foo = [x + "foo" for x in func_matches]
1895 env = Environment(FOO = factory(GlobalFunc, varlist=['XYZ']))
1896 c = a.get_contents(target=[], source=[], env=env)
1897 assert c in func_matches, repr(c)
1900 c = a.get_contents(target=[], source=[], env=env)
1901 assert c in matches_foo, repr(c)
1903 class ActionCallerTestCase(unittest.TestCase):
1904 def test___init__(self):
1905 """Test creation of an ActionCaller"""
1906 ac = SCons.Action.ActionCaller(1, [2, 3], {'FOO' : 4, 'BAR' : 5})
1907 assert ac.parent == 1, ac.parent
1908 assert ac.args == [2, 3], ac.args
1909 assert ac.kw == {'FOO' : 4, 'BAR' : 5}, ac.kw
1911 def test_get_contents(self):
1912 """Test fetching the contents of an ActionCaller"""
1924 af = SCons.Action.ActionFactory(GlobalFunc, strfunc)
1925 ac = SCons.Action.ActionCaller(af, [], {})
1926 c = ac.get_contents([], [], Environment())
1927 assert c in matches, repr(c)
1929 af = SCons.Action.ActionFactory(LocalFunc, strfunc)
1930 ac = SCons.Action.ActionCaller(af, [], {})
1931 c = ac.get_contents([], [], Environment())
1932 assert c in matches, repr(c)
1943 af = SCons.Action.ActionFactory(GlobalActFunc(), strfunc)
1944 ac = SCons.Action.ActionCaller(af, [], {})
1945 c = ac.get_contents([], [], Environment())
1946 assert c in matches, repr(c)
1948 af = SCons.Action.ActionFactory(LocalActFunc(), strfunc)
1949 ac = SCons.Action.ActionCaller(af, [], {})
1950 c = ac.get_contents([], [], Environment())
1951 assert c in matches, repr(c)
1954 "<built-in function str>",
1958 af = SCons.Action.ActionFactory(str, strfunc)
1959 ac = SCons.Action.ActionCaller(af, [], {})
1960 c = ac.get_contents([], [], Environment())
1961 assert c == "<built-in function str>" or \
1962 c == "<type 'str'>", repr(c)
1964 def test___call__(self):
1965 """Test calling an ActionCaller"""
1967 def actfunc(a1, a2, a3, args=actfunc_args):
1968 args.extend([a1, a2, a3])
1969 def strfunc(a1, a2, a3):
1972 e = Environment(FOO = 2, BAR = 5)
1974 af = SCons.Action.ActionFactory(actfunc, strfunc)
1975 ac = SCons.Action.ActionCaller(af, ['$__env__', '$FOO', 3], {})
1977 assert actfunc_args[0] is e, actfunc_args
1978 assert actfunc_args[1] == '2', actfunc_args
1979 assert actfunc_args[2] == 3, actfunc_args
1982 ac = SCons.Action.ActionCaller(af, [], {'a3' : '$__env__', 'a2' : '$BAR', 'a1' : 4})
1984 assert actfunc_args[0] == 4, actfunc_args
1985 assert actfunc_args[1] == '5', actfunc_args
1986 assert actfunc_args[2] is e, actfunc_args
1989 def test_strfunction(self):
1990 """Test calling the ActionCaller strfunction() method"""
1992 def actfunc(a1, a2, a3, a4):
1994 def strfunc(a1, a2, a3, a4, args=strfunc_args):
1995 args.extend([a1, a2, a3, a4])
1997 af = SCons.Action.ActionFactory(actfunc, strfunc)
1998 ac = SCons.Action.ActionCaller(af, [1, '$FOO', 3, '$WS'], {})
1999 ac.strfunction([], [], Environment(FOO = 2, WS='white space'))
2000 assert strfunc_args == [1, '2', 3, 'white space'], strfunc_args
2003 d = {'a3' : 6, 'a2' : '$BAR', 'a1' : 4, 'a4' : '$WS'}
2004 ac = SCons.Action.ActionCaller(af, [], d)
2005 ac.strfunction([], [], Environment(BAR = 5, WS='w s'))
2006 assert strfunc_args == [4, '5', 6, 'w s'], strfunc_args
2008 class ActionFactoryTestCase(unittest.TestCase):
2009 def test___init__(self):
2010 """Test creation of an ActionFactory"""
2015 ac = SCons.Action.ActionFactory(actfunc, strfunc)
2016 assert ac.actfunc is actfunc, ac.actfunc
2017 assert ac.strfunc is strfunc, ac.strfunc
2019 def test___call__(self):
2020 """Test calling whatever's returned from an ActionFactory"""
2023 def actfunc(a1, a2, a3, args=actfunc_args):
2024 args.extend([a1, a2, a3])
2025 def strfunc(a1, a2, a3, args=strfunc_args):
2026 args.extend([a1, a2, a3])
2027 af = SCons.Action.ActionFactory(actfunc, strfunc)
2028 af(3, 6, 9)([], [], Environment())
2029 assert actfunc_args == [3, 6, 9], actfunc_args
2030 assert strfunc_args == [3, 6, 9], strfunc_args
2033 class ActionCompareTestCase(unittest.TestCase):
2035 def test_1_solo_name(self):
2036 """Test Lazy Cmd Generator Action get_name alone.
2038 Basically ensures we can locate the builder, comparing it to
2039 itself along the way."""
2040 bar = SCons.Builder.Builder(action = {})
2041 env = Environment( BUILDERS = {'BAR' : bar} )
2042 name = bar.get_name(env)
2043 assert name == 'BAR', name
2045 def test_2_multi_name(self):
2046 """Test LazyCmdGenerator Action get_name multi builders.
2048 Ensure that we can compare builders (and thereby actions) to
2049 each other safely."""
2050 foo = SCons.Builder.Builder(action = '$FOO', suffix = '.foo')
2051 bar = SCons.Builder.Builder(action = {})
2053 assert foo.action != bar.action
2054 env = Environment( BUILDERS = {'FOO' : foo,
2056 name = foo.get_name(env)
2057 assert name == 'FOO', name
2058 name = bar.get_name(env)
2059 assert name == 'BAR', name
2061 def test_3_dict_names(self):
2062 """Test Action/Suffix dicts with get_name.
2064 Verifies that Action/Suffix dictionaries work correctly,
2065 especially two builders that can generate the same suffix,
2066 where one of the builders has a suffix dictionary with a None
2069 foo = SCons.Builder.Builder(action = '$FOO', suffix = '.foo')
2070 bar = SCons.Builder.Builder(action = {}, suffix={None:'.bar'})
2071 bar.add_action('.cow', "$MOO")
2072 dog = SCons.Builder.Builder(suffix = '.bar')
2074 env = Environment( BUILDERS = {'FOO' : foo,
2078 assert foo.get_name(env) == 'FOO', foo.get_name(env)
2079 assert bar.get_name(env) == 'BAR', bar.get_name(env)
2080 assert dog.get_name(env) == 'DOG', dog.get_name(env)
2083 if __name__ == "__main__":
2084 suite = unittest.TestSuite()
2085 tclasses = [ _ActionActionTestCase,
2087 CommandActionTestCase,
2088 CommandGeneratorActionTestCase,
2089 FunctionActionTestCase,
2092 ActionCallerTestCase,
2093 ActionFactoryTestCase,
2094 ActionCompareTestCase ]
2095 for tclass in tclasses:
2096 names = unittest.getTestCaseNames(tclass, 'test_')
2097 suite.addTests(list(map(tclass, names)))
2098 if not unittest.TextTestRunner().run(suite).wasSuccessful():
2103 # indent-tabs-mode:nil
2105 # vim: set expandtab tabstop=4 shiftwidth=4: