3 # Copyright The SCons Foundation
5 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to
10 # permit persons to whom the Software is furnished to do so, subject to
11 # the following conditions:
13 # The above copyright notice and this permission notice shall be included
14 # in all copies or substantial portions of the Software.
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
17 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
18 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 # Define a null function and a null class for use as builder actions.
26 # Where these are defined in the file seems to affect their byte-code
27 # contents, so try to minimize changes by defining them here, before we
28 # even import anything.
30 from __future__
import annotations
32 def GlobalFunc() -> None:
37 def __call__(self
) -> None:
46 from unittest
import mock
47 from subprocess
import PIPE
48 from typing
import TYPE_CHECKING
51 import SCons
.Environment
53 from SCons
.Action
import scons_subproc_run
56 from SCons
.Executor
import Executor
60 # Initial setup of the common environment for all tests,
61 # a temporary working directory containing a
62 # script for writing arguments to an output file.
64 # We don't do this as a setUp() method because it's
65 # unnecessary to create a separate directory and script
66 # for each test, they can just use the one.
67 test
= TestCmd
.TestCmd(workdir
='')
69 test
.write('act.py', """\
70 import os, string, sys
72 with open(sys.argv[1], 'w') as f:
73 f.write("act.py: '" + "' '".join(sys.argv[2:]) + "'\\n")
76 f.write("act.py: '" + os.environ[sys.argv[3]] + "'\\n")
80 if 'ACTPY_PIPE' in os.environ:
81 if 'PIPE_STDOUT_FILE' in os.environ:
82 with open(os.environ['PIPE_STDOUT_FILE'], 'r') as f:
85 stdout_msg = "act.py: stdout: executed act.py %s\\n" % ' '.join(sys.argv[1:])
86 sys.stdout.write(stdout_msg)
87 if 'PIPE_STDERR_FILE' in os.environ:
88 with open(os.environ['PIPE_STDERR_FILE'], 'r') as f:
91 stderr_msg = "act.py: stderr: executed act.py %s\\n" % ' '.join(sys.argv[1:])
92 sys.stderr.write(stderr_msg)
96 test
.write('exit.py', """\
98 sys.exit(int(sys.argv[1]))
101 act_py
= test
.workpath('act.py')
102 exit_py
= test
.workpath('exit.py')
104 outfile
= test
.workpath('outfile')
105 outfile2
= test
.workpath('outfile2')
106 pipe_file
= test
.workpath('pipe.out')
108 scons_env
= SCons
.Environment
.Environment()
110 # Capture all the stuff the Actions will print,
111 # so it doesn't clutter the output.
112 sys
.stdout
= io
.StringIO()
115 class CmdStringHolder
:
116 def __init__(self
, cmd
, literal
=None) -> None:
118 self
.literal
= literal
120 def is_literal(self
) -> bool:
123 def escape(self
, escape_func
):
124 """Escape the string with the supplied function.
126 The function is expected to take an arbitrary string, then
127 return it with all special characters escaped and ready
128 for passing to the command interpreter.
130 After calling this function, the next call to str() will
131 return the escaped string.
134 if self
.is_literal():
135 return escape_func(self
.data
)
136 elif ' ' in self
.data
or '\t' in self
.data
:
137 return '"%s"' % self
.data
143 def __init__(self
, **kw
) -> None:
145 self
.d
['SHELL'] = scons_env
['SHELL']
146 self
.d
['SPAWN'] = scons_env
['SPAWN']
147 self
.d
['PSPAWN'] = scons_env
['PSPAWN']
148 self
.d
['ESCAPE'] = scons_env
['ESCAPE']
149 for k
, v
in kw
.items():
152 # Just use the underlying scons_subst*() utility methods.
153 def subst(self
, strSubst
, raw
: int=0, target
=[], source
=[], conv
=None, overrides
: bool=False):
154 return SCons
.Subst
.scons_subst(strSubst
, self
, raw
,
155 target
, source
, self
.d
, conv
=conv
, overrides
=overrides
)
157 subst_target_source
= subst
159 def subst_list(self
, strSubst
, raw
: int=0, target
=[], source
=[], conv
=None, overrides
: bool=False):
160 return SCons
.Subst
.scons_subst_list(strSubst
, self
, raw
,
161 target
, source
, self
.d
, conv
=conv
, overrides
=overrides
)
163 def __getitem__(self
, item
):
166 def __setitem__(self
, item
, value
) -> None:
169 def __contains__(self
, key
) -> bool:
172 def get(self
, key
, value
=None):
173 return self
.d
.get(key
, value
)
176 return list(self
.d
.items())
178 def Dictionary(self
):
181 def Clone(self
, **kw
):
183 res
.d
= SCons
.Util
.semi_deepcopy(self
.d
)
184 for k
, v
in kw
.items():
190 for k
, v
in self
.items(): d
[k
] = v
191 d
['TARGETS'] = ['__t1__', '__t2__', '__t3__', '__t4__', '__t5__', '__t6__']
192 d
['TARGET'] = d
['TARGETS'][0]
193 d
['SOURCES'] = ['__s1__', '__s2__', '__s3__', '__s4__', '__s5__', '__s6__']
194 d
['SOURCE'] = d
['SOURCES'][0]
199 def __init__(self
, name
) -> None:
202 def str_for_display(self
):
203 return '"' + self
.name
+ '"'
205 def __str__(self
) -> str:
211 def get_subst_proxy(self
):
215 if os
.name
== 'java':
216 python
= os
.path
.join(sys
.prefix
, 'jython')
218 python
= os
.environ
.get('python_executable', sys
.executable
)
219 _python_
= test
.escape(python
)
221 _null
= SCons
.Action
._null
224 def test_varlist(pos_call
, str_call
, cmd
, cmdstrfunc
, **kw
) -> None:
225 def call_action(a
, pos_call
=pos_call
, str_call
=str_call
, kw
=kw
):
226 a
= SCons
.Action
.Action(*a
, **kw
)
227 # returned object must provide these entry points
228 assert hasattr(a
, '__call__')
229 assert hasattr(a
, 'get_contents')
230 assert hasattr(a
, 'genstring')
235 a
= call_action((cmd
, cmdstrfunc
))
236 assert a
.varlist
== (), a
.varlist
238 a
= call_action((cmd
, cmdstrfunc
, 'foo'))
239 assert a
.varlist
== ('foo',), a
.varlist
241 a
= call_action((cmd
, cmdstrfunc
, 'a', 'b', 'c'))
242 assert a
.varlist
== ('a', 'b', 'c'), a
.varlist
244 a
= call_action((cmd
, cmdstrfunc
, ['a', 'b', 'c']))
245 assert a
.varlist
== ('a', 'b', 'c'), a
.varlist
247 kw
['varlist'] = 'foo'
248 a
= call_action((cmd
, cmdstrfunc
))
249 assert a
.varlist
== ('foo',), a
.varlist
251 kw
['varlist'] = ['x', 'y', 'z']
252 a
= call_action((cmd
, cmdstrfunc
))
253 assert a
.varlist
== ('x', 'y', 'z'), a
.varlist
255 a
= call_action((cmd
, cmdstrfunc
, 'foo'))
256 assert a
.varlist
== ('foo', 'x', 'y', 'z'), a
.varlist
258 a
= call_action((cmd
, cmdstrfunc
, 'a', 'b', 'c'))
259 assert a
.varlist
== ('a', 'b', 'c', 'x', 'y', 'z'), a
.varlist
262 def test_positional_args(pos_callback
, cmd
, **kw
):
263 """Test that Action returns the expected type and positional args work."""
265 act
= SCons
.Action
.Action(cmd
, **kw
)
267 assert act
.varlist
== (), act
.varlist
269 if not isinstance(act
, SCons
.Action
._ActionAction
):
270 # only valid cmdstrfunc is None
274 test_varlist(pos_callback
, none
, cmd
, None, **kw
)
276 # _ActionAction should have set these
277 assert hasattr(act
, 'strfunction')
278 assert act
.cmdstr
is _null
, act
.cmdstr
279 assert act
.presub
is _null
, act
.presub
280 assert act
.chdir
is None, act
.chdir
281 assert act
.exitstatfunc
is SCons
.Action
.default_exitstatfunc
, \
284 def cmdstr(a
) -> None:
285 assert hasattr(a
, 'strfunction')
286 assert a
.cmdstr
== 'cmdstr', a
.cmdstr
288 test_varlist(pos_callback
, cmdstr
, cmd
, 'cmdstr', **kw
)
293 def strfun(a
, fun
=fun
) -> None:
294 assert a
.strfunction
is fun
, a
.strfunction
295 assert a
.cmdstr
== _null
, a
.cmdstr
297 test_varlist(pos_callback
, strfun
, cmd
, fun
, **kw
)
300 assert hasattr(a
, 'strfunction')
301 assert a
.cmdstr
is None, a
.cmdstr
303 test_varlist(pos_callback
, none
, cmd
, None, **kw
)
305 # Test handling of bad cmdstrfunc arguments
307 a
= SCons
.Action
.Action(cmd
, [], **kw
)
308 except SCons
.Errors
.UserError
as e
:
310 m
= 'Invalid command display variable'
311 assert s
.find(m
) != -1, 'Unexpected string: %s' % s
313 raise Exception("did not catch expected UserError")
318 class ActionTestCase(unittest
.TestCase
):
319 """Test the Action() factory function"""
321 def test_FunctionAction(self
) -> None:
322 """Test the Action() factory's creation of FunctionAction objects."""
327 def func_action(a
, foo
=foo
) -> None:
328 assert isinstance(a
, SCons
.Action
.FunctionAction
), a
329 assert a
.execfunction
== foo
, a
.execfunction
331 test_positional_args(func_action
, foo
)
332 # a singleton list returns the contained action
333 test_positional_args(func_action
, [foo
])
335 def test_CommandAction(self
) -> None:
336 """Test the Action() factory's creation of CommandAction objects."""
338 def cmd_action(a
) -> None:
339 assert isinstance(a
, SCons
.Action
.CommandAction
), a
340 assert a
.cmd_list
== "string", a
.cmd_list
342 test_positional_args(cmd_action
, "string")
343 # a singleton list returns the contained action
344 test_positional_args(cmd_action
, ["string"])
346 def line_action(a
) -> None:
347 assert isinstance(a
, SCons
.Action
.CommandAction
), a
348 assert a
.cmd_list
== ["explicit", "command", "line"], a
.cmd_list
350 test_positional_args(line_action
, [["explicit", "command", "line"]])
352 def test_ListAction(self
) -> None:
353 """Test the Action() factory's creation of ListAction objects."""
355 a1
= SCons
.Action
.Action(["x", "y", "z", ["a", "b", "c"]])
356 assert isinstance(a1
, SCons
.Action
.ListAction
), f
"a1 is {type(a1)}"
357 assert a1
.varlist
== (), a1
.varlist
358 assert isinstance(a1
.list[0], SCons
.Action
.CommandAction
), a1
.list[0]
359 assert a1
.list[0].cmd_list
== "x", a1
.list[0].cmd_list
360 assert isinstance(a1
.list[1], SCons
.Action
.CommandAction
), a1
.list[1]
361 assert a1
.list[1].cmd_list
== "y", a1
.list[1].cmd_list
362 assert isinstance(a1
.list[2], SCons
.Action
.CommandAction
), a1
.list[2]
363 assert a1
.list[2].cmd_list
== "z", a1
.list[2].cmd_list
364 assert isinstance(a1
.list[3], SCons
.Action
.CommandAction
), a1
.list[3]
365 assert a1
.list[3].cmd_list
== ["a", "b", "c"], a1
.list[3].cmd_list
367 a2
= SCons
.Action
.Action("x\ny\nz")
368 assert isinstance(a2
, SCons
.Action
.ListAction
), f
"a2 is {type(a2)}"
369 assert a2
.varlist
== (), a2
.varlist
370 assert isinstance(a2
.list[0], SCons
.Action
.CommandAction
), a2
.list[0]
371 assert a2
.list[0].cmd_list
== "x", a2
.list[0].cmd_list
372 assert isinstance(a2
.list[1], SCons
.Action
.CommandAction
), a2
.list[1]
373 assert a2
.list[1].cmd_list
== "y", a2
.list[1].cmd_list
374 assert isinstance(a2
.list[2], SCons
.Action
.CommandAction
), a2
.list[2]
375 assert a2
.list[2].cmd_list
== "z", a2
.list[2].cmd_list
380 a3
= SCons
.Action
.Action(["x", foo
, "z"])
381 assert isinstance(a3
, SCons
.Action
.ListAction
), f
"a3 is {type(a3)}"
382 assert a3
.varlist
== (), a3
.varlist
383 assert isinstance(a3
.list[0], SCons
.Action
.CommandAction
), a3
.list[0]
384 assert a3
.list[0].cmd_list
== "x", a3
.list[0].cmd_list
385 assert isinstance(a3
.list[1], SCons
.Action
.FunctionAction
), a3
.list[1]
386 assert a3
.list[1].execfunction
== foo
, a3
.list[1].execfunction
387 assert isinstance(a3
.list[2], SCons
.Action
.CommandAction
), a3
.list[2]
388 assert a3
.list[2].cmd_list
== "z", a3
.list[2].cmd_list
390 a4
= SCons
.Action
.Action(["x", "y"], strfunction
=foo
)
391 assert isinstance(a4
, SCons
.Action
.ListAction
), f
"a4 is {type(a4)}"
392 assert a4
.varlist
== (), a4
.varlist
393 assert isinstance(a4
.list[0], SCons
.Action
.CommandAction
), a4
.list[0]
394 assert a4
.list[0].cmd_list
== "x", a4
.list[0].cmd_list
395 assert a4
.list[0].strfunction
== foo
, a4
.list[0].strfunction
396 assert isinstance(a4
.list[1], SCons
.Action
.CommandAction
), a4
.list[1]
397 assert a4
.list[1].cmd_list
== "y", a4
.list[1].cmd_list
398 assert a4
.list[1].strfunction
== foo
, a4
.list[1].strfunction
400 a5
= SCons
.Action
.Action("x\ny", strfunction
=foo
)
401 assert isinstance(a5
, SCons
.Action
.ListAction
), f
"a5 is {type(a5)}"
402 assert a5
.varlist
== (), a5
.varlist
403 assert isinstance(a5
.list[0], SCons
.Action
.CommandAction
), a5
.list[0]
404 assert a5
.list[0].cmd_list
== "x", a5
.list[0].cmd_list
405 assert a5
.list[0].strfunction
== foo
, a5
.list[0].strfunction
406 assert isinstance(a5
.list[1], SCons
.Action
.CommandAction
), a5
.list[1]
407 assert a5
.list[1].cmd_list
== "y", a5
.list[1].cmd_list
408 assert a5
.list[1].strfunction
== foo
, a5
.list[1].strfunction
410 a6
= SCons
.Action
.Action(["action with space"])
411 assert isinstance(a6
, SCons
.Action
.CommandAction
), f
"a6 is {type(a6)}"
413 def test_CommandGeneratorAction(self
) -> None:
414 """Test the Action factory's creation of CommandGeneratorAction objects."""
416 def foo() -> None: pass
418 def gen_action(a
, foo
=foo
) -> None:
419 assert isinstance(a
, SCons
.Action
.CommandGeneratorAction
), a
420 assert a
.generator
is foo
, a
.generator
422 test_positional_args(gen_action
, foo
, generator
=1)
424 def test_LazyCmdGeneratorAction(self
) -> None:
425 """Test the Action factory's creation of lazy CommandGeneratorAction objects."""
427 def lazy_action(a
) -> None:
428 assert isinstance(a
, SCons
.Action
.LazyAction
), a
429 assert a
.var
== "FOO", a
.var
430 assert a
.cmd_list
== "${FOO}", a
.cmd_list
432 test_positional_args(lazy_action
, "$FOO")
433 test_positional_args(lazy_action
, "${FOO}")
435 def test_no_action(self
) -> None:
436 """Test when the Action() factory can't create an action object."""
439 a5
= SCons
.Action
.Action(1)
443 assert 0, "Should have thrown a TypeError creating Action from an int."
445 def test_reentrance(self
) -> None:
446 """Test the Action factory when the action is already an Action object."""
448 a1
= SCons
.Action
.Action("foo")
449 a2
= SCons
.Action
.Action(a1
)
453 class _ActionActionTestCase(unittest
.TestCase
):
455 def test__init__(self
) -> None:
456 """Test creation of _ActionAction objects."""
467 a
= SCons
.Action
._ActionAction
()
468 assert not hasattr(a
, 'strfunction')
469 assert a
.cmdstr
is _null
, a
.cmdstr
470 assert a
.varlist
== (), a
.varlist
471 assert a
.presub
is _null
, a
.presub
472 assert a
.chdir
is None, a
.chdir
473 assert a
.exitstatfunc
is SCons
.Action
.default_exitstatfunc
, a
.exitstatfunc
475 assert SCons
.Action
._ActionAction
(kwarg
=1)
476 assert not hasattr(a
, 'kwarg')
477 assert not hasattr(a
, 'strfunction')
478 assert a
.cmdstr
is _null
, a
.cmdstr
479 assert a
.varlist
== (), a
.varlist
480 assert a
.presub
is _null
, a
.presub
481 assert a
.chdir
is None, a
.chdir
482 assert a
.exitstatfunc
is SCons
.Action
.default_exitstatfunc
, a
.exitstatfunc
484 a
= SCons
.Action
._ActionAction
(strfunction
=func1
)
485 assert a
.strfunction
is func1
, a
.strfunction
487 a
= SCons
.Action
._ActionAction
(strfunction
=None)
488 assert not hasattr(a
, 'strfunction')
489 assert a
.cmdstr
is None, a
.cmdstr
491 a
= SCons
.Action
._ActionAction
(cmdstr
='cmdstr')
492 assert not hasattr(a
, 'strfunction')
493 assert a
.cmdstr
== 'cmdstr', a
.cmdstr
495 a
= SCons
.Action
._ActionAction
(cmdstr
=None)
496 assert not hasattr(a
, 'strfunction')
497 assert a
.cmdstr
is None, a
.cmdstr
500 a
= SCons
.Action
._ActionAction
(varlist
=t
)
501 assert a
.varlist
== t
, a
.varlist
503 a
= SCons
.Action
._ActionAction
(presub
=func1
)
504 assert a
.presub
is func1
, a
.presub
506 a
= SCons
.Action
._ActionAction
(chdir
=1)
507 assert a
.chdir
== 1, a
.chdir
509 a
= SCons
.Action
._ActionAction
(exitstatfunc
=func1
)
510 assert a
.exitstatfunc
is func1
, a
.exitstatfunc
512 a
= SCons
.Action
._ActionAction
(
513 # alphabetical order ...
521 assert a
.chdir
== 'x', a
.chdir
522 assert a
.cmdstr
== 'cmdstr', a
.cmdstr
523 assert a
.exitstatfunc
is func3
, a
.exitstatfunc
524 assert a
.presub
is func2
, a
.presub
525 assert a
.strfunction
is func1
, a
.strfunction
526 assert a
.varlist
is t
, a
.varlist
528 def test_dup_keywords(self
):
529 """Test handling of both cmdstr and strfunction arguments."""
535 a
= SCons
.Action
.Action('foo', cmdstr
='string', strfunction
=func
)
536 except SCons
.Errors
.UserError
as e
:
538 m
= 'Cannot have both strfunction and cmdstr args to Action()'
539 assert s
.find(m
) != -1, 'Unexpected string: %s' % s
541 raise Exception("did not catch expected UserError")
543 def test___cmp__(self
) -> None:
544 """Test Action comparison."""
546 a1
= SCons
.Action
.Action("x")
547 a2
= SCons
.Action
.Action("x")
549 a3
= SCons
.Action
.Action("y")
553 def test_print_cmd_lines(self
) -> None:
554 """Test the print_cmd_lines() method."""
556 save_stdout
= sys
.stdout
559 def execfunc(target
, source
, env
) -> None:
562 a
= SCons
.Action
.Action(execfunc
)
566 a
.print_cmd_line("foo bar", None, None, None)
568 assert s
== "foo bar\n", s
571 sys
.stdout
= save_stdout
573 def test___call__(self
) -> None:
574 """Test calling an Action."""
576 save_stdout
= sys
.stdout
578 save_print_actions
= SCons
.Action
.print_actions
579 save_print_actions_presub
= SCons
.Action
.print_actions_presub
580 save_execute_actions
= SCons
.Action
.execute_actions
581 # SCons.Action.print_actions = 0
583 test
= TestCmd
.TestCmd(workdir
='')
584 test
.subdir('sub', 'xyz')
585 os
.chdir(test
.workpath())
590 def execfunc(target
, source
, env
) -> int:
591 assert isinstance(target
, list), type(target
)
592 assert isinstance(source
, list), type(source
)
595 a
= SCons
.Action
.Action(execfunc
)
597 def firstfunc(target
, source
, env
) -> int:
598 assert isinstance(target
, list), type(target
)
599 assert isinstance(source
, list), type(source
)
602 def lastfunc(target
, source
, env
) -> int:
603 assert isinstance(target
, list), type(target
)
604 assert isinstance(source
, list), type(source
)
607 b
= SCons
.Action
.Action([firstfunc
, execfunc
, lastfunc
])
611 result
= a("out", "in", env
)
612 assert result
.status
== 7, result
614 assert s
== "execfunc(['out'], ['in'])\n", s
617 expect
= "os.chdir(%s)\nexecfunc(['out'], ['in'])\nos.chdir(%s)\n"
621 result
= a("out", "in", env
)
622 assert result
.status
== 7, result
.status
624 assert s
== expect
% (repr('xyz'), repr(test
.workpath())), s
628 result
= a("out", "in", env
, chdir
='sub')
629 assert result
.status
== 7, result
.status
631 assert s
== expect
% (repr('sub'), repr(test
.workpath())), s
637 result
= b("out", "in", env
)
638 assert result
.status
== 7, result
.status
640 assert s
== "firstfunc(['out'], ['in'])\nexecfunc(['out'], ['in'])\n", s
642 SCons
.Action
.execute_actions
= 0
646 result
= a("out", "in", env
)
647 assert result
== 0, result
649 assert s
== "execfunc(['out'], ['in'])\n", s
653 result
= b("out", "in", env
)
654 assert result
== 0, result
656 assert s
== "firstfunc(['out'], ['in'])\nexecfunc(['out'], ['in'])\nlastfunc(['out'], ['in'])\n", s
658 SCons
.Action
.print_actions_presub
= 1
659 SCons
.Action
.execute_actions
= 1
663 result
= a("out", "in", env
)
664 assert result
.status
== 7, result
.status
666 assert s
== "Building out with action:\n execfunc(target, source, env)\nexecfunc(['out'], ['in'])\n", s
670 result
= a("out", "in", env
, presub
=0)
671 assert result
.status
== 7, result
.status
673 assert s
== "execfunc(['out'], ['in'])\n", s
677 result
= a("out", "in", env
, presub
=1)
678 assert result
.status
== 7, result
.status
680 assert s
== "Building out with action:\n execfunc(target, source, env)\nexecfunc(['out'], ['in'])\n", s
684 result
= b(["out"], "in", env
, presub
=1)
685 assert result
.status
== 7, result
.status
687 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
691 result
= b(["out", "list"], "in", env
, presub
=1)
692 assert result
.status
== 7, result
.status
694 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
696 a2
= SCons
.Action
.Action(execfunc
)
700 result
= a2("out", "in", env
)
701 assert result
.status
== 7, result
.status
703 assert s
== "Building out with action:\n execfunc(target, source, env)\nexecfunc(['out'], ['in'])\n", s
707 result
= a2("out", "in", env
, presub
=0)
708 assert result
.status
== 7, result
.status
710 assert s
== "execfunc(['out'], ['in'])\n", s
712 SCons
.Action
.execute_actions
= 0
716 result
= a2("out", "in", env
, presub
=0)
717 assert result
== 0, result
719 assert s
== "execfunc(['out'], ['in'])\n", s
723 result
= a("out", "in", env
, presub
=0, execute
=1, show
=0)
724 assert result
.status
== 7, result
.status
728 sys
.stdout
= save_stdout
729 exitstatfunc_result
= []
731 def exitstatfunc(stat
, result
=exitstatfunc_result
):
735 result
= a("out", "in", env
, exitstatfunc
=exitstatfunc
)
736 assert result
== 0, result
737 assert exitstatfunc_result
== [], exitstatfunc_result
739 result
= a("out", "in", env
, execute
=1, exitstatfunc
=exitstatfunc
)
740 assert result
.status
== 7, result
.status
741 assert exitstatfunc_result
== [7], exitstatfunc_result
743 SCons
.Action
.execute_actions
= 1
747 def my_print_cmd_line(s
, target
, source
, env
, result
=result
) -> None:
750 env
['PRINT_CMD_LINE_FUNC'] = my_print_cmd_line
751 a("output", "input", env
)
752 assert result
== ["execfunc(['output'], ['input'])"], result
756 sys
.stdout
= save_stdout
757 SCons
.Action
.print_actions
= save_print_actions
758 SCons
.Action
.print_actions_presub
= save_print_actions_presub
759 SCons
.Action
.execute_actions
= save_execute_actions
761 def test_presub_lines(self
) -> None:
762 """Test the presub_lines() method."""
765 a
= SCons
.Action
.Action("x")
766 s
= a
.presub_lines(env
)
769 a
= SCons
.Action
.Action(["y", "z"])
770 s
= a
.presub_lines(env
)
771 assert s
== ['y', 'z'], s
776 a
= SCons
.Action
.Action(func
)
777 s
= a
.presub_lines(env
)
778 assert s
== ["func(target, source, env)"], s
780 def gen(target
, source
, env
, for_signature
):
781 return 'generat' + env
.get('GEN', 'or')
783 a
= SCons
.Action
.Action(gen
, generator
=1)
784 s
= a
.presub_lines(env
)
785 assert s
== ["generator"], s
786 s
= a
.presub_lines(Environment(GEN
='ed'))
787 assert s
== ["generated"], s
789 a
= SCons
.Action
.Action("$ACT")
790 s
= a
.presub_lines(env
)
792 s
= a
.presub_lines(Environment(ACT
='expanded action'))
793 assert s
== ['expanded action'], s
795 def test_add(self
) -> None:
796 """Test adding Actions to stuff."""
798 # Adding actions to other Actions or to stuff that can
799 # be converted into an Action should produce a ListAction
800 # containing all the Actions.
804 baz
= SCons
.Action
.Action(bar
, generator
=1)
805 act1
= SCons
.Action
.Action('foo bar')
806 act2
= SCons
.Action
.Action(['foo', bar
])
809 assert isinstance(sum, SCons
.Action
.ListAction
), str(sum)
810 assert len(sum.list) == 3, len(sum.list)
811 assert [isinstance(x
, SCons
.Action
.ActionBase
) for x
in sum.list] == [1, 1, 1]
814 assert isinstance(sum, SCons
.Action
.ListAction
), str(sum)
815 assert len(sum.list) == 2, len(sum.list)
818 assert isinstance(sum, SCons
.Action
.ListAction
), str(sum)
819 assert len(sum.list) == 4, len(sum.list)
821 # Should also be able to add command generators to each other
824 assert isinstance(sum, SCons
.Action
.ListAction
), str(sum)
825 assert len(sum.list) == 2, len(sum.list)
828 assert isinstance(sum, SCons
.Action
.ListAction
), str(sum)
829 assert len(sum.list) == 2, len(sum.list)
832 assert isinstance(sum, SCons
.Action
.ListAction
), str(sum)
833 assert len(sum.list) == 3, len(sum.list)
835 # Also should be able to add Actions to anything that can
836 # be converted into an action.
838 assert isinstance(sum, SCons
.Action
.ListAction
), str(sum)
839 assert len(sum.list) == 2, len(sum.list)
840 assert isinstance(sum.list[1], SCons
.Action
.FunctionAction
)
842 sum = 'foo bar' + act2
843 assert isinstance(sum, SCons
.Action
.ListAction
), str(sum)
844 assert len(sum.list) == 3, len(sum.list)
845 assert isinstance(sum.list[0], SCons
.Action
.CommandAction
)
847 sum = ['foo', 'bar'] + act1
848 assert isinstance(sum, SCons
.Action
.ListAction
), str(sum)
849 assert len(sum.list) == 3, sum.list
850 assert isinstance(sum.list[0], SCons
.Action
.CommandAction
)
851 assert isinstance(sum.list[1], SCons
.Action
.CommandAction
)
853 sum = act2
+ [baz
, bar
]
854 assert isinstance(sum, SCons
.Action
.ListAction
), str(sum)
855 assert len(sum.list) == 4, len(sum.list)
856 assert isinstance(sum.list[2], SCons
.Action
.CommandGeneratorAction
)
857 assert isinstance(sum.list[3], SCons
.Action
.FunctionAction
)
859 # OK to add None on either side (should be ignored)
871 assert 0, "Should have thrown a TypeError adding to an int."
878 assert 0, "Should have thrown a TypeError adding to an int."
881 class CommandActionTestCase(unittest
.TestCase
):
883 def test___init__(self
) -> None:
884 """Test creation of a command Action."""
886 a
= SCons
.Action
.CommandAction(["xyzzy"])
887 assert a
.cmd_list
== ["xyzzy"], a
.cmd_list
888 assert a
.cmdstr
is _null
, a
.cmdstr
890 a
= SCons
.Action
.CommandAction(["abra"], cmdstr
="cadabra")
891 assert a
.cmd_list
== ["abra"], a
.cmd_list
892 assert a
.cmdstr
== "cadabra", a
.cmdstr
894 def test___str__(self
) -> None:
895 """Test fetching the pre-substitution string for command Actions."""
898 act
= SCons
.Action
.CommandAction('xyzzy $TARGET $SOURCE')
900 assert s
== 'xyzzy $TARGET $SOURCE', s
902 act
= SCons
.Action
.CommandAction(['xyzzy',
903 '$TARGET', '$SOURCE',
904 '$TARGETS', '$SOURCES'])
906 assert s
== "xyzzy $TARGET $SOURCE $TARGETS $SOURCES", s
908 def test_genstring(self
) -> None:
909 """Test the genstring() method for command Actions."""
916 act
= SCons
.Action
.CommandAction('xyzzy $TARGET $SOURCE')
917 expect
= 'xyzzy $TARGET $SOURCE'
918 s
= act
.genstring([], [], env
)
919 assert s
== expect
, s
920 s
= act
.genstring([t1
], [s1
], env
)
921 assert s
== expect
, s
922 s
= act
.genstring([t1
, t2
], [s1
, s2
], env
)
923 assert s
== expect
, s
925 act
= SCons
.Action
.CommandAction('xyzzy $TARGETS $SOURCES')
926 expect
= 'xyzzy $TARGETS $SOURCES'
927 s
= act
.genstring([], [], env
)
928 assert s
== expect
, s
929 s
= act
.genstring([t1
], [s1
], env
)
930 assert s
== expect
, s
931 s
= act
.genstring([t1
, t2
], [s1
, s2
], env
)
932 assert s
== expect
, s
934 act
= SCons
.Action
.CommandAction(['xyzzy',
935 '$TARGET', '$SOURCE',
936 '$TARGETS', '$SOURCES'])
937 expect
= "xyzzy $TARGET $SOURCE $TARGETS $SOURCES"
938 s
= act
.genstring([], [], env
)
939 assert s
== expect
, s
940 s
= act
.genstring([t1
], [s1
], env
)
941 assert s
== expect
, s
942 s
= act
.genstring([t1
, t2
], [s1
, s2
], env
)
943 assert s
== expect
, s
945 def test_strfunction(self
) -> None:
946 """Test fetching the string representation of command Actions."""
953 act
= SCons
.Action
.CommandAction('xyzzy $TARGET $SOURCE')
954 s
= act
.strfunction([], [], env
)
955 assert s
== 'xyzzy', s
956 s
= act
.strfunction([t1
], [s1
], env
)
957 assert s
== 'xyzzy t1 s1', s
958 s
= act
.strfunction([t1
, t2
], [s1
, s2
], env
)
959 assert s
== 'xyzzy t1 s1', s
961 act
= SCons
.Action
.CommandAction('xyzzy $TARGET $SOURCE',
962 cmdstr
='cmdstr - $SOURCE - $TARGET -')
963 s
= act
.strfunction([], [], env
)
964 assert s
== 'cmdstr - - -', s
965 s
= act
.strfunction([t1
], [s1
], env
)
966 assert s
== 'cmdstr - s1 - t1 -', s
967 s
= act
.strfunction([t1
, t2
], [s1
, s2
], env
)
968 assert s
== 'cmdstr - s1 - t1 -', s
970 act
= SCons
.Action
.CommandAction('xyzzy $TARGETS $SOURCES')
971 s
= act
.strfunction([], [], env
)
972 assert s
== 'xyzzy', s
973 s
= act
.strfunction([t1
], [s1
], env
)
974 assert s
== 'xyzzy t1 s1', s
975 s
= act
.strfunction([t1
, t2
], [s1
, s2
], env
)
976 assert s
== 'xyzzy t1 t2 s1 s2', s
978 act
= SCons
.Action
.CommandAction('xyzzy $TARGETS $SOURCES',
979 cmdstr
='cmdstr = $SOURCES = $TARGETS =')
980 s
= act
.strfunction([], [], env
)
981 assert s
== 'cmdstr = = =', s
982 s
= act
.strfunction([t1
], [s1
], env
)
983 assert s
== 'cmdstr = s1 = t1 =', s
984 s
= act
.strfunction([t1
, t2
], [s1
, s2
], env
)
985 assert s
== 'cmdstr = s1 s2 = t1 t2 =', s
987 act
= SCons
.Action
.CommandAction(['xyzzy',
988 '$TARGET', '$SOURCE',
989 '$TARGETS', '$SOURCES'])
990 s
= act
.strfunction([], [], env
)
991 assert s
== 'xyzzy', s
992 s
= act
.strfunction([t1
], [s1
], env
)
993 assert s
== 'xyzzy t1 s1 t1 s1', s
994 s
= act
.strfunction([t1
, t2
], [s1
, s2
], env
)
995 assert s
== 'xyzzy t1 s1 t1 t2 s1 s2', s
997 act
= SCons
.Action
.CommandAction('xyzzy $TARGETS $SOURCES',
998 cmdstr
='cmdstr\t$TARGETS\n$SOURCES ')
1000 s
= act
.strfunction([], [], env
)
1001 assert s
== 'cmdstr\t\n ', s
1002 s
= act
.strfunction([t1
], [s1
], env
)
1003 assert s
== 'cmdstr\tt1\ns1 ', s
1004 s
= act
.strfunction([t1
, t2
], [s1
, s2
], env
)
1005 assert s
== 'cmdstr\tt1 t2\ns1 s2 ', s
1007 def sf(target
, source
, env
) -> str:
1008 return "sf was called"
1010 act
= SCons
.Action
.CommandAction('foo', strfunction
=sf
)
1011 s
= act
.strfunction([], [], env
)
1012 assert s
== "sf was called", s
1015 def __init__(self
, targets
, sources
, env
) -> None:
1018 def __call__(self
) -> int:
1022 def __init__(self
, targets
, sources
, env
) -> None:
1023 self
.strfunction
= 5
1025 def __call__(self
) -> int:
1029 def __init__(self
, targets
, sources
, env
) -> None:
1032 def __call__(self
) -> int:
1035 def strfunction(self
, targets
, sources
, env
) -> str:
1036 return 'actclass3 on %s to get %s' % (str(sources
[0]),
1040 def __init__(self
, targets
, sources
, env
) -> None:
1043 def __call__(self
) -> int:
1048 act1
= SCons
.Action
.Action(actclass1([t1
], [s1
], env
))
1049 s
= act1
.strfunction([t1
], [s1
], env
)
1050 assert s
== 'actclass1(["t1"], ["s1"])', s
1052 act2
= SCons
.Action
.Action(actclass2([t1
], [s1
], env
))
1053 s
= act2
.strfunction([t1
], [s1
], env
)
1054 assert s
== 'actclass2(["t1"], ["s1"])', s
1056 act3
= SCons
.Action
.Action(actclass3([t1
], [s1
], env
))
1057 s
= act3
.strfunction([t1
], [s1
], env
)
1058 assert s
== 'actclass3 on s1 to get t1', s
1060 act4
= SCons
.Action
.Action(actclass4([t1
], [s1
], env
))
1061 s
= act4
.strfunction([t1
], [s1
], env
)
1064 act
= SCons
.Action
.CommandAction("@foo bar")
1065 s
= act
.strfunction([], [], env
)
1068 act
= SCons
.Action
.CommandAction("@-foo bar")
1069 s
= act
.strfunction([], [], env
)
1072 act
= SCons
.Action
.CommandAction("-@foo bar")
1073 s
= act
.strfunction([], [], env
)
1076 act
= SCons
.Action
.CommandAction("-foo bar")
1077 s
= act
.strfunction([], [], env
)
1078 assert s
== "foo bar", s
1080 act
= SCons
.Action
.CommandAction("@ foo bar")
1081 s
= act
.strfunction([], [], env
)
1084 act
= SCons
.Action
.CommandAction("@- foo bar")
1085 s
= act
.strfunction([], [], env
)
1088 act
= SCons
.Action
.CommandAction("-@ foo bar")
1089 s
= act
.strfunction([], [], env
)
1092 act
= SCons
.Action
.CommandAction("- foo bar")
1093 s
= act
.strfunction([], [], env
)
1094 assert s
== "foo bar", s
1096 def test_execute(self
) -> None:
1097 """Test execution of command Actions."""
1101 except AttributeError:
1104 cmd1
= r
'%s %s %s xyzzy' % (_python_
, act_py
, outfile
)
1106 act
= SCons
.Action
.CommandAction(cmd1
)
1107 r
= act([], [], env
.Clone())
1109 c
= test
.read(outfile
, 'r')
1110 assert c
== "act.py: 'xyzzy'\n", c
1112 cmd2
= r
'%s %s %s $TARGET' % (_python_
, act_py
, outfile
)
1114 act
= SCons
.Action
.CommandAction(cmd2
)
1115 r
= act(DummyNode('foo'), [], env
.Clone())
1117 c
= test
.read(outfile
, 'r')
1118 assert c
== "act.py: 'foo'\n", c
1120 cmd3
= r
'%s %s %s ${TARGETS}' % (_python_
, act_py
, outfile
)
1122 act
= SCons
.Action
.CommandAction(cmd3
)
1123 r
= act(list(map(DummyNode
, ['aaa', 'bbb'])), [], env
.Clone())
1125 c
= test
.read(outfile
, 'r')
1126 assert c
== "act.py: 'aaa' 'bbb'\n", c
1128 cmd4
= r
'%s %s %s $SOURCES' % (_python_
, act_py
, outfile
)
1130 act
= SCons
.Action
.CommandAction(cmd4
)
1131 r
= act([], [DummyNode('one'), DummyNode('two')], env
.Clone())
1133 c
= test
.read(outfile
, 'r')
1134 assert c
== "act.py: 'one' 'two'\n", c
1136 cmd4
= r
'%s %s %s ${SOURCES[:2]}' % (_python_
, act_py
, outfile
)
1138 act
= SCons
.Action
.CommandAction(cmd4
)
1139 sources
= [DummyNode('three'), DummyNode('four'), DummyNode('five')]
1141 r
= act([], source
=sources
, env
=env2
)
1143 c
= test
.read(outfile
, 'r')
1144 assert c
== "act.py: 'three' 'four'\n", c
1146 cmd5
= r
'%s %s %s $TARGET XYZZY' % (_python_
, act_py
, outfile
)
1148 act
= SCons
.Action
.CommandAction(cmd5
)
1149 env5
= Environment()
1150 if 'ENV' in scons_env
:
1151 env5
['ENV'] = scons_env
['ENV']
1152 PATH
= scons_env
['ENV'].get('PATH', '')
1157 env5
['ENV']['XYZZY'] = 'xyzzy'
1158 r
= act(target
=DummyNode('out5'), source
=[], env
=env5
)
1160 act
= SCons
.Action
.CommandAction(cmd5
)
1161 r
= act(target
=DummyNode('out5'),
1163 env
=env
.Clone(ENV
={'XYZZY': 'xyzzy5',
1166 c
= test
.read(outfile
, 'r')
1167 assert c
== "act.py: 'out5' 'XYZZY'\nact.py: 'xyzzy5'\n", c
1170 def __init__(self
, str) -> None:
1173 def __str__(self
) -> str:
1179 def get_subst_proxy(self
):
1182 cmd6
= r
'%s %s %s ${TARGETS[1]} $TARGET ${SOURCES[:2]}' % (_python_
, act_py
, outfile
)
1184 act
= SCons
.Action
.CommandAction(cmd6
)
1185 r
= act(target
=[Obj('111'), Obj('222')],
1186 source
=[Obj('333'), Obj('444'), Obj('555')],
1189 c
= test
.read(outfile
, 'r')
1190 assert c
== "act.py: '222' '111' '333' '444'\n", c
1193 # NT treats execs of directories and non-executable files
1194 # as "file not found" errors
1195 expect_nonexistent
= 1
1196 expect_nonexecutable_file
= 1
1197 expect_nonexecutable_dir
= 1
1198 elif sys
.platform
== 'cygwin':
1199 expect_nonexistent
= 127
1200 # Newer cygwin seems to return 126 for following
1201 expect_nonexecutable_file
= 126
1202 expect_nonexecutable_dir
= 127
1204 expect_nonexistent
= 127
1205 expect_nonexecutable_file
= 126
1206 expect_nonexecutable_dir
= 126
1208 # Test that a nonexistent command returns 127
1209 act
= SCons
.Action
.CommandAction(python
+ "_no_such_command_")
1210 r
= act([], [], env
.Clone(out
=outfile
))
1211 assert r
.status
== expect_nonexistent
, r
.status
1213 # Test that trying to execute a directory returns 126
1214 dir, tail
= os
.path
.split(python
)
1215 act
= SCons
.Action
.CommandAction(dir)
1216 r
= act([], [], env
.Clone(out
=outfile
))
1217 assert r
.status
== expect_nonexecutable_file
, r
.status
1219 # Test that trying to execute a non-executable file returns 126
1220 act
= SCons
.Action
.CommandAction(outfile
)
1221 r
= act([], [], env
.Clone(out
=outfile
))
1222 assert r
.status
== expect_nonexecutable_dir
, r
.status
1224 act
= SCons
.Action
.CommandAction('%s %s 1' % (_python_
, exit_py
))
1225 r
= act([], [], env
)
1226 assert r
.status
== 1, r
.status
1228 act
= SCons
.Action
.CommandAction('@%s %s 1' % (_python_
, exit_py
))
1229 r
= act([], [], env
)
1230 assert r
.status
== 1, r
.status
1232 act
= SCons
.Action
.CommandAction('@-%s %s 1' % (_python_
, exit_py
))
1233 r
= act([], [], env
)
1236 act
= SCons
.Action
.CommandAction('-%s %s 1' % (_python_
, exit_py
))
1237 r
= act([], [], env
)
1240 act
= SCons
.Action
.CommandAction('@ %s %s 1' % (_python_
, exit_py
))
1241 r
= act([], [], env
)
1242 assert r
.status
== 1, r
.status
1244 act
= SCons
.Action
.CommandAction('@- %s %s 1' % (_python_
, exit_py
))
1245 r
= act([], [], env
)
1248 act
= SCons
.Action
.CommandAction('- %s %s 1' % (_python_
, exit_py
))
1249 r
= act([], [], env
)
1252 def test_set_handler(self
) -> None:
1253 """Test setting the command handler..."""
1256 def __init__(self
) -> None:
1261 def func(sh
, escape
, cmd
, args
, env
, test
=t
) -> int:
1262 test
.executed
= args
1266 def escape_func(cmd
):
1267 return '**' + cmd
+ '**'
1270 def __init__(self
, x
) -> None:
1273 def __str__(self
) -> str:
1276 def escape(self
, escape_func
):
1277 return escape_func(self
.data
)
1279 def is_literal(self
) -> bool:
1282 a
= SCons
.Action
.CommandAction(["xyzzy"])
1283 e
= Environment(SPAWN
=func
)
1285 assert t
.executed
== ['xyzzy'], t
.executed
1287 a
= SCons
.Action
.CommandAction(["xyzzy"])
1288 e
= Environment(SPAWN
='$FUNC', FUNC
=func
)
1290 assert t
.executed
== ['xyzzy'], t
.executed
1292 a
= SCons
.Action
.CommandAction(["xyzzy"])
1293 e
= Environment(SPAWN
=func
, SHELL
='fake shell')
1295 assert t
.executed
== ['xyzzy'], t
.executed
1296 assert t
.shell
== 'fake shell', t
.shell
1298 a
= SCons
.Action
.CommandAction([LiteralStr("xyzzy")])
1299 e
= Environment(SPAWN
=func
, ESCAPE
=escape_func
)
1301 assert t
.executed
== ['**xyzzy**'], t
.executed
1303 def test_get_contents(self
) -> None:
1304 """Test fetching the contents of a command Action."""
1306 def CmdGen(target
, source
, env
, for_signature
) -> str:
1307 assert for_signature
1309 (env
["foo"], env
["bar"])
1311 # The number 1 is there to make sure all args get converted to strings.
1312 a
= SCons
.Action
.CommandAction(["|", "$(", "$foo", "|", "$(", "$bar",
1313 "$)", "stuff", "$)", "|", "$baz", 1])
1314 c
= a
.get_contents(target
=[], source
=[],
1315 env
=Environment(foo
='FFF', bar
='BBB',
1317 assert c
== b
"| | FFF BBB 1", c
1319 # Make sure that CommandActions use an Environment's
1320 # subst_target_source() method for substitution.
1321 class SpecialEnvironment(Environment
):
1322 def subst_target_source(self
, strSubst
, raw
: int=0, target
=[], source
=[]):
1323 return 'subst_target_source: ' + strSubst
1325 c
= a
.get_contents(target
=DummyNode('ttt'), source
=DummyNode('sss'),
1326 env
=SpecialEnvironment(foo
='GGG', bar
='CCC',
1328 assert c
== b
'subst_target_source: | $( $foo | $( $bar $) stuff $) | $baz 1', c
1330 # We've discussed using the real target and source names in a
1331 # CommandAction's signature contents. This would have have the
1332 # advantage of recompiling when a file's name changes (keeping
1333 # debug info current), but it would currently break repository
1334 # logic that will change the file name based on whether the
1335 # files come from a repository or locally. If we ever move to
1336 # that scheme, then all of the '__t1__' and '__s6__' file names
1337 # in the asserts below would change to 't1' and 's6' and the
1339 t
= list(map(DummyNode
, ['t1', 't2', 't3', 't4', 't5', 't6']))
1340 s
= list(map(DummyNode
, ['s1', 's2', 's3', 's4', 's5', 's6']))
1343 a
= SCons
.Action
.CommandAction(["$TARGET"])
1344 c
= a
.get_contents(target
=t
, source
=s
, env
=env
)
1345 assert c
== b
"t1", c
1347 a
= SCons
.Action
.CommandAction(["$TARGETS"])
1348 c
= a
.get_contents(target
=t
, source
=s
, env
=env
)
1349 assert c
== b
"t1 t2 t3 t4 t5 t6", c
1351 a
= SCons
.Action
.CommandAction(["${TARGETS[2]}"])
1352 c
= a
.get_contents(target
=t
, source
=s
, env
=env
)
1353 assert c
== b
"t3", c
1355 a
= SCons
.Action
.CommandAction(["${TARGETS[3:5]}"])
1356 c
= a
.get_contents(target
=t
, source
=s
, env
=env
)
1357 assert c
== b
"t4 t5", c
1359 a
= SCons
.Action
.CommandAction(["$SOURCE"])
1360 c
= a
.get_contents(target
=t
, source
=s
, env
=env
)
1361 assert c
== b
"s1", c
1363 a
= SCons
.Action
.CommandAction(["$SOURCES"])
1364 c
= a
.get_contents(target
=t
, source
=s
, env
=env
)
1365 assert c
== b
"s1 s2 s3 s4 s5 s6", c
1367 a
= SCons
.Action
.CommandAction(["${SOURCES[2]}"])
1368 c
= a
.get_contents(target
=t
, source
=s
, env
=env
)
1369 assert c
== b
"s3", c
1371 a
= SCons
.Action
.CommandAction(["${SOURCES[3:5]}"])
1372 c
= a
.get_contents(target
=t
, source
=s
, env
=env
)
1373 assert c
== b
"s4 s5", c
1375 def test_get_implicit_deps(self
) -> None:
1376 """Test getting the implicit dependencies of a command Action."""
1378 class SpecialEnvironment(Environment
):
1379 def WhereIs(self
, prog
):
1386 env
= SpecialEnvironment()
1387 a
= SCons
.Action
.CommandAction([_python_
, exit_py
])
1388 self
.assertEqual(a
.get_implicit_deps(target
=[], source
=[], env
=env
), [_python_
])
1390 for false_like_value
in [False, 0, None, "None", "False", "0", "NONE", "FALSE", "off", "OFF", "NO", "no"]:
1391 env
= SpecialEnvironment(IMPLICIT_COMMAND_DEPENDENCIES
=false_like_value
)
1392 a
= SCons
.Action
.CommandAction([_python_
, exit_py
])
1393 self
.assertEqual(a
.get_implicit_deps(target
=[], source
=[], env
=env
), [])
1395 env
= SpecialEnvironment(IMPLICIT_COMMAND_DEPENDENCIES
="$SUBST_VALUE", SUBST_VALUE
=false_like_value
)
1396 a
= SCons
.Action
.CommandAction([_python_
, exit_py
])
1397 self
.assertEqual(a
.get_implicit_deps(target
=[], source
=[], env
=env
), [])
1399 for true_like_value
in [True, 1, "True", "TRUE", "1"]:
1400 env
= SpecialEnvironment(IMPLICIT_COMMAND_DEPENDENCIES
=true_like_value
)
1401 a
= SCons
.Action
.CommandAction([_python_
, exit_py
])
1402 self
.assertEqual(a
.get_implicit_deps(target
=[], source
=[], env
=env
), [_python_
])
1404 env
= SpecialEnvironment(IMPLICIT_COMMAND_DEPENDENCIES
="$SUBST_VALUE", SUBST_VALUE
=true_like_value
)
1405 a
= SCons
.Action
.CommandAction([_python_
, exit_py
])
1406 self
.assertEqual(a
.get_implicit_deps(target
=[], source
=[], env
=env
), [_python_
])
1408 for all_like_Value
in ["all", "ALL", 2, "2"]:
1409 env
= SpecialEnvironment(IMPLICIT_COMMAND_DEPENDENCIES
=all_like_Value
)
1410 a
= SCons
.Action
.CommandAction([_python_
, exit_py
])
1411 self
.assertEqual(a
.get_implicit_deps(target
=[], source
=[], env
=env
), [_python_
, exit_py
])
1414 class CommandGeneratorActionTestCase(unittest
.TestCase
):
1416 def factory(self
, act
, **kw
):
1417 """Pass any keywords as a dict"""
1419 return SCons
.Action
.CommandGeneratorAction(act
, kw
)
1421 def test___init__(self
) -> None:
1422 """Test creation of a command generator Action."""
1424 def f(target
, source
, env
) -> None:
1428 assert a
.generator
== f
1430 def test___str__(self
) -> None:
1431 """Test the pre-substitution strings for command generator Actions."""
1433 def f(target
, source
, env
, for_signature
, self
=self
) -> str:
1434 # See if "env" is really a construction environment (or
1435 # looks like one) by accessing the FindIxes attribute.
1436 # (The Tool/mingw.py module has a generator that uses this,
1437 # and the __str__() method used to cause problems by passing
1438 # us a regular dictionary as a fallback.)
1445 assert s
== 'FOO', s
1447 def test_genstring(self
) -> None:
1448 """Test the command generator Action genstring() method."""
1450 def f(target
, source
, env
, for_signature
, self
=self
) -> str:
1451 dummy
= env
['dummy']
1453 return "$FOO $TARGET $SOURCE $TARGETS $SOURCES"
1457 s
= a
.genstring([], [], env
=Environment(FOO
='xyzzy', dummy
=1))
1458 assert self
.dummy
== 1, self
.dummy
1459 assert s
== "$FOO $TARGET $SOURCE $TARGETS $SOURCES", s
1461 def test_execute(self
) -> None:
1462 """Test executing a command generator Action."""
1464 def f(target
, source
, env
, for_signature
, self
=self
) -> str:
1465 dummy
= env
['dummy']
1467 s
= env
.subst("$FOO")
1468 assert s
== 'foo baz\nbar ack', s
1471 def func_action(target
, source
, env
, self
=self
) -> None:
1472 dummy
= env
['dummy']
1473 s
= env
.subst('$foo')
1474 assert s
== 'bar', s
1477 def f2(target
, source
, env
, for_signature
, f
=func_action
):
1480 def ch(sh
, escape
, cmd
, args
, env
, self
=self
) -> None:
1481 self
.cmd
.append(cmd
)
1482 self
.args
.append(args
)
1488 a([], [], env
=Environment(FOO
='foo baz\nbar ack',
1491 assert self
.dummy
== 1, self
.dummy
1492 assert self
.cmd
== ['foo', 'bar'], self
.cmd
1493 assert self
.args
== [['foo', 'baz'], ['bar', 'ack']], self
.args
1495 b
= self
.factory(f2
)
1497 b(target
=[], source
=[], env
=Environment(foo
='bar',
1499 assert self
.dummy
== 2, self
.dummy
1503 def __init__(self
, t
) -> None:
1507 self
.t
.rfile_called
= 1
1510 def get_subst_proxy(self
):
1513 def f3(target
, source
, env
, for_signature
) -> str:
1516 c
= self
.factory(f3
)
1517 c(target
=[], source
=DummyFile(self
), env
=Environment())
1518 assert self
.rfile_called
1520 def test_get_contents(self
) -> None:
1521 """Test fetching the contents of a command generator Action."""
1523 def f(target
, source
, env
, for_signature
):
1526 assert for_signature
, for_signature
1527 return [["guux", foo
, "$(", "$ignore", "$)", bar
,
1528 '${test("$( foo $bar $)")}']]
1530 def test(mystr
) -> str:
1531 assert mystr
== "$( foo $bar $)", mystr
1534 env
= Environment(foo
='FFF', bar
='BBB',
1535 ignore
='foo', test
=test
)
1537 c
= a
.get_contents(target
=[], source
=[], env
=env
)
1538 assert c
== b
"guux FFF BBB test", c
1540 def test_get_contents_of_function_action(self
) -> None:
1541 """Test contents of a CommandGeneratorAction-generated FunctionAction."""
1543 def LocalFunc() -> None:
1546 # Since the python bytecode has per version differences, we need different expected results per version
1548 (3, 7): bytearray(b
'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
1549 (3, 8): bytearray(b
'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
1550 (3, 9): bytearray(b
'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
1551 (3, 10): bytearray(b
'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
1552 (3, 11): bytearray(b
'0, 0, 0, 0,(),(),(\x97\x00d\x00S\x00),(),()'),
1553 (3, 12): bytearray(b
'0, 0, 0, 0,(),(),(\x97\x00y\x00),(),()'),
1554 (3, 13): bytearray(b
'0, 0, 0, 0,(),(),(\x95\x00g\x00),(),()'),
1558 b
"1, 1, 0, 0,(),(),(d\000\000S),(),()",
1559 b
"1, 1, 0, 0,(),(),(d\x00\x00S),(),()",
1562 def f_global(target
, source
, env
, for_signature
):
1563 return SCons
.Action
.Action(GlobalFunc
)
1565 def f_local(target
, source
, env
, for_signature
):
1566 return SCons
.Action
.Action(LocalFunc
)
1568 env
= Environment(XYZ
='foo')
1570 with self
.subTest():
1571 a
= self
.factory(f_global
)
1572 c
= a
.get_contents(target
=[], source
=[], env
=env
)
1573 self
.assertEqual(c
, func_matches
[sys
.version_info
[:2]])
1575 with self
.subTest():
1576 a
= self
.factory(f_local
)
1577 c
= a
.get_contents(target
=[], source
=[], env
=env
)
1578 self
.assertEqual(c
, func_matches
[sys
.version_info
[:2]])
1580 def f_global2(target
, source
, env
, for_signature
):
1581 return SCons
.Action
.Action(GlobalFunc
, varlist
=['XYZ'])
1583 def f_local2(target
, source
, env
, for_signature
):
1584 return SCons
.Action
.Action(LocalFunc
, varlist
=['XYZ'])
1586 matches_foo
= func_matches
[sys
.version_info
[:2]] + b
'foo'
1588 with self
.subTest():
1589 a
= self
.factory(f_global2
)
1590 c
= a
.get_contents(target
=[], source
=[], env
=env
)
1591 self
.assertIn(c
, matches_foo
)
1593 with self
.subTest():
1594 a
= self
.factory(f_local2
)
1595 c
= a
.get_contents(target
=[], source
=[], env
=env
)
1596 self
.assertIn(c
, matches_foo
)
1599 class FunctionActionTestCase(unittest
.TestCase
):
1601 def test___init__(self
) -> None:
1602 """Test creation of a function Action."""
1604 def func1() -> None:
1607 def func2() -> None:
1610 def func3() -> None:
1613 def func4() -> None:
1616 a
= SCons
.Action
.FunctionAction(func1
, {})
1617 assert a
.execfunction
== func1
, a
.execfunction
1618 assert isinstance(a
.strfunction
, types
.MethodType
), type(a
.strfunction
)
1620 a
= SCons
.Action
.FunctionAction(func2
, {'strfunction': func3
})
1621 assert a
.execfunction
== func2
, a
.execfunction
1622 assert a
.strfunction
== func3
, a
.strfunction
1624 def test___str__(self
) -> None:
1625 """Test the __str__() method for function Actions."""
1627 def func1() -> None:
1630 a
= SCons
.Action
.FunctionAction(func1
, {})
1632 assert s
== "func1(target, source, env)", s
1635 def __call__(self
) -> None:
1638 a
= SCons
.Action
.FunctionAction(class1(), {})
1640 assert s
== "class1(target, source, env)", s
1642 def test_execute(self
) -> None:
1643 """Test executing a function Action."""
1647 def f(target
, source
, env
) -> int:
1652 assert env
.subst("$BAR") == 'foo bar', env
.subst("$BAR")
1655 a
= SCons
.Action
.FunctionAction(f
, {})
1656 a(target
=1, source
=2, env
=Environment(BAR
='foo bar',
1658 assert self
.inc
== 1, self
.inc
1659 assert self
.source
== [2], self
.source
1660 assert self
.target
== [1], self
.target
1665 def function1(target
, source
, env
) -> int:
1669 with
open(t
, 'w') as f
:
1670 f
.write("function1\n")
1673 act
= SCons
.Action
.FunctionAction(function1
, {})
1674 r
= act(target
=[outfile
, outfile2
], source
=[], env
=Environment())
1675 assert r
.status
== 1, r
.status
1677 assert count
== 1, count
1678 c
= test
.read(outfile
, 'r')
1679 assert c
== "function1\n", c
1680 c
= test
.read(outfile2
, 'r')
1681 assert c
== "function1\n", c
1684 def __init__(self
, target
, source
, env
) -> None:
1685 with
open(env
['out'], 'w') as f
:
1686 f
.write("class1a\n")
1688 act
= SCons
.Action
.FunctionAction(class1a
, {})
1689 r
= act([], [], Environment(out
=outfile
))
1690 assert isinstance(r
.status
, class1a
), r
.status
1691 c
= test
.read(outfile
, 'r')
1692 assert c
== "class1a\n", c
1695 def __call__(self
, target
, source
, env
) -> int:
1696 with
open(env
['out'], 'w') as f
:
1697 f
.write("class1b\n")
1700 act
= SCons
.Action
.FunctionAction(class1b(), {})
1701 r
= act([], [], Environment(out
=outfile
))
1702 assert r
.status
== 2, r
.status
1703 c
= test
.read(outfile
, 'r')
1704 assert c
== "class1b\n", c
1706 def build_it(target
, source
, env
, executor
: Executor |
None = None, self
=self
) -> int:
1710 def string_it(target
, source
, env
, executor
: Executor |
None = None, self
=self
):
1714 act
= SCons
.Action
.FunctionAction(build_it
,
1715 {'strfunction': string_it
})
1716 r
= act([], [], Environment())
1718 assert self
.build_it
1719 assert self
.string_it
1721 def test_get_contents(self
) -> None:
1722 """Test fetching the contents of a function Action."""
1724 def LocalFunc() -> None:
1728 (3, 7): bytearray(b
'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
1729 (3, 8): bytearray(b
'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
1730 (3, 9): bytearray(b
'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
1731 (3, 10): bytearray(b
'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
1732 (3, 11): bytearray(b
'0, 0, 0, 0,(),(),(\x97\x00d\x00S\x00),(),()'),
1733 (3, 12): bytearray(b
'0, 0, 0, 0,(),(),(\x97\x00y\x00),(),()'),
1734 (3, 13): bytearray(b
'0, 0, 0, 0,(),(),(\x95\x00g\x00),(),()'),
1739 (3, 7): bytearray(b
'1, 1, 0, 0,(),(),(d\x00S\x00),(),()'),
1740 (3, 8): bytearray(b
'1, 1, 0, 0,(),(),(d\x00S\x00),(),()'),
1741 (3, 9): bytearray(b
'1, 1, 0, 0,(),(),(d\x00S\x00),(),()'),
1742 (3, 10): bytearray(b
'1, 1, 0, 0,(),(),(d\x00S\x00),(),()'),
1743 (3, 11): bytearray(b
'1, 1, 0, 0,(),(),(\x97\x00d\x00S\x00),(),()'),
1744 (3, 12): bytearray(b
'1, 1, 0, 0,(),(),(\x97\x00y\x00),(),()'),
1745 (3, 13): bytearray(b
'1, 1, 0, 0,(),(),(\x95\x00g\x00),(),()'),
1748 def factory(act
, **kw
):
1749 return SCons
.Action
.FunctionAction(act
, kw
)
1751 with self
.subTest():
1752 a
= factory(GlobalFunc
)
1753 c
= a
.get_contents(target
=[], source
=[], env
=Environment())
1754 self
.assertEqual(c
, func_matches
[sys
.version_info
[:2]])
1756 with self
.subTest():
1757 a
= factory(LocalFunc
)
1758 c
= a
.get_contents(target
=[], source
=[], env
=Environment())
1759 self
.assertEqual(c
, func_matches
[sys
.version_info
[:2]])
1761 matches_foo
= func_matches
[sys
.version_info
[:2]] + b
'foo'
1763 with self
.subTest():
1764 a
= factory(GlobalFunc
, varlist
=['XYZ'])
1765 c
= a
.get_contents(target
=[], source
=[], env
=Environment())
1766 self
.assertEqual(c
, func_matches
[sys
.version_info
[:2]])
1768 with self
.subTest():
1769 c
= a
.get_contents(target
=[], source
=[], env
=Environment(XYZ
='foo'))
1770 self
.assertEqual(c
, matches_foo
)
1772 ##TODO: is this set of tests still needed?
1773 # Make sure a bare string varlist works
1774 with self
.subTest():
1775 a
= factory(GlobalFunc
, varlist
='XYZ')
1776 c
= a
.get_contents(target
=[], source
=[], env
=Environment())
1777 self
.assertEqual(c
, func_matches
[sys
.version_info
[:2]])
1779 with self
.subTest():
1780 c
= a
.get_contents(target
=[], source
=[], env
=Environment(XYZ
='foo'))
1781 self
.assertIn(c
, matches_foo
)
1784 def get_contents(self
, target
, source
, env
) -> bytes
:
1787 with self
.subTest():
1789 c
= a
.get_contents(target
=[], source
=[], env
=Environment())
1790 self
.assertEqual(c
, b
'xyzzy')
1793 def LocalMethod(self
) -> None:
1796 with self
.subTest():
1798 a
= factory(lc
.LocalMethod
)
1799 c
= a
.get_contents(target
=[], source
=[], env
=Environment())
1800 self
.assertEqual(c
, meth_matches
[sys
.version_info
[:2]])
1802 def test_strfunction(self
) -> None:
1803 """Test the FunctionAction.strfunction() method."""
1808 def factory(act
, **kw
):
1809 return SCons
.Action
.FunctionAction(act
, kw
)
1812 s
= a
.strfunction(target
=[], source
=[], env
=Environment())
1813 assert s
== 'func([], [])', s
1815 a
= factory(func
, strfunction
=None)
1816 s
= a
.strfunction(target
=[], source
=[], env
=Environment())
1819 a
= factory(func
, cmdstr
='function')
1820 s
= a
.strfunction(target
=[], source
=[], env
=Environment())
1821 assert s
== 'function', s
1824 class ListActionTestCase(unittest
.TestCase
):
1826 def test___init__(self
) -> None:
1827 """Test creation of a list of subsidiary Actions."""
1832 a
= SCons
.Action
.ListAction(["x", func
, ["y", "z"]])
1833 assert isinstance(a
.list[0], SCons
.Action
.CommandAction
)
1834 assert isinstance(a
.list[1], SCons
.Action
.FunctionAction
)
1835 assert isinstance(a
.list[2], SCons
.Action
.ListAction
)
1836 assert a
.list[2].list[0].cmd_list
== 'y'
1838 def test___str__(self
) -> None:
1839 """Test the __str__() method for a list of subsidiary Actions."""
1841 def f(target
, source
, env
) -> None:
1844 def g(target
, source
, env
) -> None:
1847 a
= SCons
.Action
.ListAction([f
, g
, "XXX", f
])
1849 assert s
== "f(target, source, env)\ng(target, source, env)\nXXX\nf(target, source, env)", s
1851 def test_genstring(self
) -> None:
1852 """Test the genstring() method for a list of subsidiary Actions."""
1854 def f(target
, source
, env
) -> None:
1857 def g(target
, source
, env
, for_signature
) -> str:
1858 return 'generated %s %s' % (target
[0], source
[0])
1860 g
= SCons
.Action
.Action(g
, generator
=1)
1861 a
= SCons
.Action
.ListAction([f
, g
, "XXX", f
])
1862 s
= a
.genstring(['foo.x'], ['bar.y'], Environment())
1863 assert s
== "f(target, source, env)\ngenerated foo.x bar.y\nXXX\nf(target, source, env)", s
1865 def test_execute(self
) -> None:
1866 """Test executing a list of subsidiary Actions."""
1869 def f(target
, source
, env
) -> None:
1873 a
= SCons
.Action
.ListAction([f
, f
, f
])
1874 a([], [], Environment(s
=self
))
1875 assert self
.inc
== 3, self
.inc
1877 cmd2
= r
'%s %s %s syzygy' % (_python_
, act_py
, outfile
)
1879 def function2(target
, source
, env
) -> int:
1880 with
open(env
['out'], 'a') as f
:
1881 f
.write("function2\n")
1885 def __call__(self
, target
, source
, env
) -> int:
1886 with
open(env
['out'], 'a') as f
:
1887 f
.write("class2a\n")
1891 def __init__(self
, target
, source
, env
) -> None:
1892 with
open(env
['out'], 'a') as f
:
1893 f
.write("class2b\n")
1895 act
= SCons
.Action
.ListAction([cmd2
, function2
, class2a(), class2b
])
1896 r
= act([], [], Environment(out
=outfile
))
1897 assert isinstance(r
.status
, class2b
), r
.status
1898 c
= test
.read(outfile
, 'r')
1899 assert c
== "act.py: 'syzygy'\nfunction2\nclass2a\nclass2b\n", c
1901 def test_get_contents(self
) -> None:
1902 """Test fetching the contents of a list of subsidiary Actions."""
1906 def gen(target
, source
, env
, for_signature
) -> str:
1911 a
= SCons
.Action
.ListAction(["x",
1912 SCons
.Action
.Action(gen
, generator
=1),
1914 c
= a
.get_contents(target
=[], source
=[], env
=Environment(s
=self
))
1915 assert self
.foo
== 1, self
.foo
1916 assert c
== b
"xyz", c
1919 class LazyActionTestCase(unittest
.TestCase
):
1920 def test___init__(self
) -> None:
1921 """Test creation of a lazy-evaluation Action."""
1923 # Environment variable references should create a special type
1924 # of LazyAction that lazily evaluates the variable for whether
1925 # it's a string or something else before doing anything.
1926 a9
= SCons
.Action
.Action('$FOO')
1927 assert isinstance(a9
, SCons
.Action
.LazyAction
), a9
1928 assert a9
.var
== 'FOO', a9
.var
1930 a10
= SCons
.Action
.Action('${FOO}')
1931 assert isinstance(a10
, SCons
.Action
.LazyAction
), a10
1932 assert a10
.var
== 'FOO', a10
.var
1934 def test_genstring(self
) -> None:
1935 """Test the lazy-evaluation Action genstring() method."""
1937 def f(target
, source
, env
) -> None:
1940 a
= SCons
.Action
.Action('$BAR')
1941 env1
= Environment(BAR
=f
, s
=self
)
1942 env2
= Environment(BAR
='xxx', s
=self
)
1943 s
= a
.genstring([], [], env
=env1
)
1944 assert s
== "f(target, source, env)", s
1945 s
= a
.genstring([], [], env
=env2
)
1946 assert s
== 'xxx', s
1948 def test_execute(self
) -> None:
1949 """Test executing a lazy-evaluation Action."""
1951 def f(target
, source
, env
) -> int:
1956 a
= SCons
.Action
.Action('$BAR')
1957 a([], [], env
=Environment(BAR
=f
, s
=self
))
1958 assert self
.test
== 1, self
.test
1959 cmd
= r
'%s %s %s lazy' % (_python_
, act_py
, outfile
)
1960 a([], [], env
=Environment(BAR
=cmd
, s
=self
))
1961 c
= test
.read(outfile
, 'r')
1962 assert c
== "act.py: 'lazy'\n", c
1964 def test_get_contents(self
) -> None:
1965 """Test fetching the contents of a lazy-evaluation Action."""
1967 a
= SCons
.Action
.Action("${FOO}")
1968 env
= Environment(FOO
=[["This", "is", "a", "test"]])
1969 c
= a
.get_contents(target
=[], source
=[], env
=env
)
1970 assert c
== b
"This is a test", c
1972 def test_get_contents_of_function_action(self
) -> None:
1973 """Test fetching the contents of a lazy-evaluation FunctionAction."""
1975 def LocalFunc() -> None:
1979 (3, 7): bytearray(b
'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
1980 (3, 8): bytearray(b
'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
1981 (3, 9): bytearray(b
'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
1982 (3, 10): bytearray(b
'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
1983 (3, 11): bytearray(b
'0, 0, 0, 0,(),(),(\x97\x00d\x00S\x00),(),()'),
1984 (3, 12): bytearray(b
'0, 0, 0, 0,(),(),(\x97\x00y\x00),(),()'),
1985 (3, 13): bytearray(b
'0, 0, 0, 0,(),(),(\x95\x00g\x00),(),()'),
1989 b
"1, 1, 0, 0,(),(),(d\000\000S),(),()",
1990 b
"1, 1, 0, 0,(),(),(d\x00\x00S),(),()",
1993 def factory(act
, **kw
):
1994 return SCons
.Action
.FunctionAction(act
, kw
)
1996 a
= SCons
.Action
.Action("${FOO}")
1998 with self
.subTest():
1999 env
= Environment(FOO
=factory(GlobalFunc
))
2000 c
= a
.get_contents(target
=[], source
=[], env
=env
)
2001 self
.assertEqual(c
, func_matches
[sys
.version_info
[:2]])
2003 with self
.subTest():
2004 env
= Environment(FOO
=factory(LocalFunc
))
2005 c
= a
.get_contents(target
=[], source
=[], env
=env
)
2006 self
.assertEqual(c
, func_matches
[sys
.version_info
[:2]])
2008 # matches_foo = [x + b"foo" for x in func_matches]
2009 matches_foo
= func_matches
[sys
.version_info
[:2]] + b
'foo'
2011 with self
.subTest():
2012 env
= Environment(FOO
=factory(GlobalFunc
, varlist
=['XYZ']))
2013 c
= a
.get_contents(target
=[], source
=[], env
=env
)
2014 self
.assertEqual(c
, func_matches
[sys
.version_info
[:2]])
2016 with self
.subTest():
2018 c
= a
.get_contents(target
=[], source
=[], env
=env
)
2019 self
.assertIn(c
, matches_foo
)
2022 class ActionCallerTestCase(unittest
.TestCase
):
2023 def test___init__(self
) -> None:
2024 """Test creation of an ActionCaller"""
2026 ac
= SCons
.Action
.ActionCaller(1, [2, 3], {'FOO': 4, 'BAR': 5})
2027 assert ac
.parent
== 1, ac
.parent
2028 assert ac
.args
== [2, 3], ac
.args
2029 assert ac
.kw
== {'FOO': 4, 'BAR': 5}, ac
.kw
2031 def test_get_contents(self
) -> None:
2032 """Test fetching the contents of an ActionCaller"""
2034 def strfunc() -> None:
2037 def LocalFunc() -> None:
2041 (3, 7): b
'd\x00S\x00',
2042 (3, 8): b
'd\x00S\x00',
2043 (3, 9): b
'd\x00S\x00',
2044 (3, 10): b
'd\x00S\x00',
2045 (3, 11): b
'\x97\x00d\x00S\x00',
2046 (3, 12): b
'\x97\x00y\x00',
2047 (3, 13): b
'\x95\x00g\x00',
2050 with self
.subTest():
2051 af
= SCons
.Action
.ActionFactory(GlobalFunc
, strfunc
)
2052 ac
= SCons
.Action
.ActionCaller(af
, [], {})
2053 c
= ac
.get_contents([], [], Environment())
2054 self
.assertEqual(c
, matches
[sys
.version_info
[:2]])
2056 with self
.subTest():
2057 af
= SCons
.Action
.ActionFactory(LocalFunc
, strfunc
)
2058 ac
= SCons
.Action
.ActionCaller(af
, [], {})
2059 c
= ac
.get_contents([], [], Environment())
2060 self
.assertEqual(c
, matches
[sys
.version_info
[:2]])
2063 def __call__(self
) -> None:
2066 with self
.subTest():
2067 af
= SCons
.Action
.ActionFactory(GlobalActFunc(), strfunc
)
2068 ac
= SCons
.Action
.ActionCaller(af
, [], {})
2069 c
= ac
.get_contents([], [], Environment())
2070 self
.assertEqual(c
, matches
[sys
.version_info
[:2]])
2072 with self
.subTest():
2073 af
= SCons
.Action
.ActionFactory(LocalActFunc(), strfunc
)
2074 ac
= SCons
.Action
.ActionCaller(af
, [], {})
2075 c
= ac
.get_contents([], [], Environment())
2076 self
.assertEqual(c
, matches
[sys
.version_info
[:2]])
2079 b
"<built-in function str>",
2083 with self
.subTest():
2084 af
= SCons
.Action
.ActionFactory(str, strfunc
)
2085 ac
= SCons
.Action
.ActionCaller(af
, [], {})
2086 c
= ac
.get_contents([], [], Environment())
2087 self
.assertIn(c
, ("<built-in function str>", "<type 'str'>", "<class 'str'>"))
2088 # ^^ class str for python3
2090 def test___call__(self
) -> None:
2091 """Test calling an ActionCaller"""
2095 def actfunc(a1
, a2
, a3
, args
=actfunc_args
) -> None:
2096 args
.extend([a1
, a2
, a3
])
2098 def strfunc(a1
, a2
, a3
) -> None:
2101 e
= Environment(FOO
=2, BAR
=5)
2103 af
= SCons
.Action
.ActionFactory(actfunc
, strfunc
)
2104 ac
= SCons
.Action
.ActionCaller(af
, ['$__env__', '$FOO', 3], {})
2106 assert actfunc_args
[0] is e
, actfunc_args
2107 assert actfunc_args
[1] == '2', actfunc_args
2108 assert actfunc_args
[2] == 3, actfunc_args
2111 ac
= SCons
.Action
.ActionCaller(af
, [], {'a3': '$__env__', 'a2': '$BAR', 'a1': 4})
2113 assert actfunc_args
[0] == 4, actfunc_args
2114 assert actfunc_args
[1] == '5', actfunc_args
2115 assert actfunc_args
[2] is e
, actfunc_args
2118 def test_strfunction(self
) -> None:
2119 """Test calling the ActionCaller strfunction() method"""
2123 def actfunc(a1
, a2
, a3
, a4
) -> None:
2126 def strfunc(a1
, a2
, a3
, a4
, args
=strfunc_args
) -> None:
2127 args
.extend([a1
, a2
, a3
, a4
])
2129 af
= SCons
.Action
.ActionFactory(actfunc
, strfunc
)
2130 ac
= SCons
.Action
.ActionCaller(af
, [1, '$FOO', 3, '$WS'], {})
2131 ac
.strfunction([], [], Environment(FOO
=2, WS
='white space'))
2132 assert strfunc_args
== [1, '2', 3, 'white space'], strfunc_args
2135 d
= {'a3': 6, 'a2': '$BAR', 'a1': 4, 'a4': '$WS'}
2136 ac
= SCons
.Action
.ActionCaller(af
, [], d
)
2137 ac
.strfunction([], [], Environment(BAR
=5, WS
='w s'))
2138 assert strfunc_args
== [4, '5', 6, 'w s'], strfunc_args
2141 class ActionFactoryTestCase(unittest
.TestCase
):
2142 def test___init__(self
) -> None:
2143 """Test creation of an ActionFactory"""
2145 def actfunc() -> None:
2148 def strfunc() -> None:
2151 ac
= SCons
.Action
.ActionFactory(actfunc
, strfunc
)
2152 assert ac
.actfunc
is actfunc
, ac
.actfunc
2153 assert ac
.strfunc
is strfunc
, ac
.strfunc
2155 def test___call__(self
) -> None:
2156 """Test calling whatever's returned from an ActionFactory"""
2161 def actfunc(a1
, a2
, a3
, args
=actfunc_args
) -> None:
2162 args
.extend([a1
, a2
, a3
])
2164 def strfunc(a1
, a2
, a3
, args
=strfunc_args
) -> None:
2165 args
.extend([a1
, a2
, a3
])
2167 af
= SCons
.Action
.ActionFactory(actfunc
, strfunc
)
2168 af(3, 6, 9)([], [], Environment())
2169 assert actfunc_args
== [3, 6, 9], actfunc_args
2170 assert strfunc_args
== [3, 6, 9], strfunc_args
2173 class ActionCompareTestCase(unittest
.TestCase
):
2174 def test_1_solo_name(self
) -> None:
2175 """Test Lazy Cmd Generator Action get_name alone.
2177 Basically ensures we can locate the builder, comparing it to
2178 itself along the way."""
2180 bar
= SCons
.Builder
.Builder(action
={})
2181 env
= Environment(BUILDERS
={'BAR': bar
})
2182 name
= bar
.get_name(env
)
2183 assert name
== 'BAR', name
2185 def test_2_multi_name(self
) -> None:
2186 """Test LazyCmdGenerator Action get_name multi builders.
2188 Ensure that we can compare builders (and thereby actions) to
2189 each other safely."""
2191 foo
= SCons
.Builder
.Builder(action
='$FOO', suffix
='.foo')
2192 bar
= SCons
.Builder
.Builder(action
={})
2194 assert foo
.action
!= bar
.action
2195 env
= Environment(BUILDERS
={'FOO': foo
, 'BAR': bar
})
2196 name
= foo
.get_name(env
)
2197 assert name
== 'FOO', name
2198 name
= bar
.get_name(env
)
2199 assert name
== 'BAR', name
2201 def test_3_dict_names(self
) -> None:
2202 """Test Action/Suffix dicts with get_name.
2204 Verifies that Action/Suffix dictionaries work correctly,
2205 especially two builders that can generate the same suffix,
2206 where one of the builders has a suffix dictionary with a None
2209 foo
= SCons
.Builder
.Builder(action
='$FOO', suffix
='.foo')
2210 bar
= SCons
.Builder
.Builder(action
={}, suffix
={None: '.bar'})
2211 bar
.add_action('.cow', "$MOO")
2212 dog
= SCons
.Builder
.Builder(suffix
='.bar')
2213 env
= Environment(BUILDERS
={'FOO': foo
, 'BAR': bar
, 'DOG': dog
})
2215 assert foo
.get_name(env
) == 'FOO', foo
.get_name(env
)
2216 assert bar
.get_name(env
) == 'BAR', bar
.get_name(env
)
2217 assert dog
.get_name(env
) == 'DOG', dog
.get_name(env
)
2221 """A test class used by ObjectContentsTestCase.test_object_contents"""
2223 def __init__(self
) -> None:
2227 def method(self
, arg
) -> None:
2231 class ObjectContentsTestCase(unittest
.TestCase
):
2232 def test_function_contents(self
) -> None:
2233 """Test that Action._function_contents works"""
2236 """A test function"""
2239 # Since the python bytecode has per version differences,
2240 # we need different expected results per version
2241 # Note unlike the others, this result is a tuple, use assertIn
2243 (3, 7): (bytearray(b
'3, 3, 0, 0,(),(),(|\x00S\x00),(),()'),),
2244 (3, 8): (bytearray(b
'3, 3, 0, 0,(),(),(|\x00S\x00),(),()'),),
2245 (3, 9): (bytearray(b
'3, 3, 0, 0,(),(),(|\x00S\x00),(),()'),),
2246 (3, 10): ( # 3.10.1, 3.10.2
2247 bytearray(b
'3, 3, 0, 0,(N.),(),(|\x00S\x00),(),()'),
2248 bytearray(b
'3, 3, 0, 0,(),(),(|\x00S\x00),(),()'),
2250 (3, 11): (bytearray(b
'3, 3, 0, 0,(),(),(\x97\x00|\x00S\x00),(),()'),),
2251 (3, 12): (bytearray(b
'3, 3, 0, 0,(),(),(\x97\x00|\x00S\x00),(),()'),),
2252 (3, 13): (bytearray(b
'3, 3, 0, 0,(),(),(\x95\x00U\x00$\x00),(),()'),),
2255 c
= SCons
.Action
._function
_contents
(func1
)
2256 self
.assertIn(c
, expected
[sys
.version_info
[:2]])
2258 def test_object_contents(self
) -> None:
2259 """Test that Action._object_contents works"""
2261 # See definition above
2263 c
= SCons
.Action
._object
_contents
(o
)
2265 # c = SCons.Action._object_instance_content(o)
2267 # Since the python bytecode has per version differences,
2268 # we need different expected results per version
2271 b
"{TestClass:__main__}[[[(<class \'object\'>, ()), [(<class \'__main__.TestClass\'>, (<class \'object\'>,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01|\x00_\x00d\x02|\x00_\x01d\x00S\x00),(),(),2, 2, 0, 0,(),(),(d\x00S\x00),(),()}}{{{a=a,b=b}}}"
2274 b
"{TestClass:__main__}[[[(<class \'object\'>, ()), [(<class \'__main__.TestClass\'>, (<class \'object\'>,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01|\x00_\x00d\x02|\x00_\x01d\x00S\x00),(),(),2, 2, 0, 0,(),(),(d\x00S\x00),(),()}}{{{a=a,b=b}}}"
2277 b
"{TestClass:__main__}[[[(<class \'object\'>, ()), [(<class \'__main__.TestClass\'>, (<class \'object\'>,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01|\x00_\x00d\x02|\x00_\x01d\x00S\x00),(),(),2, 2, 0, 0,(),(),(d\x00S\x00),(),()}}{{{a=a,b=b}}}"
2280 b
"{TestClass:__main__}[[[(<class \'object\'>, ()), [(<class \'__main__.TestClass\'>, (<class \'object\'>,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01|\x00_\x00d\x02|\x00_\x01d\x00S\x00),(),(),2, 2, 0, 0,(),(),(d\x00S\x00),(),()}}{{{a=a,b=b}}}"
2283 b
"{TestClass:__main__}[[[(<class \'object\'>, ()), [(<class \'__main__.TestClass\'>, (<class \'object\'>,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(\x97\x00d\x01|\x00_\x00\x00\x00\x00\x00\x00\x00\x00\x00d\x02|\x00_\x01\x00\x00\x00\x00\x00\x00\x00\x00d\x00S\x00),(),(),2, 2, 0, 0,(),(),(\x97\x00d\x00S\x00),(),()}}{{{a=a,b=b}}}"
2286 b
"{TestClass:__main__}[[[(<class \'object\'>, ()), [(<class \'__main__.TestClass\'>, (<class \'object\'>,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(\x97\x00d\x01|\x00_\x00\x00\x00\x00\x00\x00\x00\x00\x00d\x02|\x00_\x01\x00\x00\x00\x00\x00\x00\x00\x00y\x00),(),(),2, 2, 0, 0,(),(),(\x97\x00y\x00),(),()}}{{{a=a,b=b}}}"
2289 b
"{TestClass:__main__}[[[(<class \'object\'>, ()), [(<class \'__main__.TestClass\'>, (<class \'object\'>,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(\x95\x00S\x01U\x00l\x00\x00\x00\x00\x00\x00\x00\x00\x00S\x02U\x00l\x01\x00\x00\x00\x00\x00\x00\x00\x00g\x00),(),(),2, 2, 0, 0,(),(),(\x95\x00g\x00),(),()}}{{{a=a,b=b}}}"
2293 self
.assertEqual(c
, expected
[sys
.version_info
[:2]])
2295 def test_code_contents(self
) -> None:
2296 """Test that Action._code_contents works"""
2298 code
= compile("print('Hello, World!')", '<string>', 'exec')
2299 c
= SCons
.Action
._code
_contents
(code
)
2301 # Since the python bytecode has per version differences, we need different expected results per version
2304 b
'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)'
2307 b
'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)'
2310 b
'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)'
2313 b
'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)'
2316 b
'0, 0, 0, 0,(Hello, World!),(print),(\x97\x00\x02\x00e\x00d\x00\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00d\x01S\x00)'
2319 b
'0, 0, 0, 0,(Hello, World!),(print),(\x97\x00\x02\x00e\x00d\x00\xab\x01\x00\x00\x00\x00\x00\x00\x01\x00y\x01)'
2322 b
'0, 0, 0, 0,(Hello, World!),(print),(\x95\x00\\\x00"\x00S\x005\x01\x00\x00\x00\x00\x00\x00 \x00g\x01)'
2326 self
.assertEqual(c
, expected
[sys
.version_info
[:2]])
2328 def test_uncaught_exception_bubbles(self
):
2329 """Test that scons_subproc_run bubbles uncaught exceptions"""
2331 cp
= scons_subproc_run(Environment(), None, stdout
=PIPE
)
2332 except EnvironmentError:
2338 raise Exception("expected a non-EnvironmentError exception")
2341 def mock_subprocess_run(*args
, **kwargs
):
2342 """Replacement subprocess.run: return kwargs for checking."""
2343 kwargs
.pop("env") # the value of env isn't interesting here
2346 @mock.patch("subprocess.run", mock_subprocess_run
)
2347 def test_scons_subproc_run(self
):
2348 """Test the argument remapping options."""
2349 # set phony Python versions to trigger the logic in scons_subproc_run:
2350 # any version greater than 3.6, really
2351 save_info
, sys
.version_info
= sys
.version_info
, (3, 11, 1)
2353 self
.assertEqual(scons_subproc_run(env
), {"check": False})
2354 with self
.subTest():
2356 scons_subproc_run(env
, error
="raise"),
2359 with self
.subTest():
2361 scons_subproc_run(env
, capture_output
=True),
2362 {"capture_output": True, "check": False},
2364 with self
.subTest():
2366 scons_subproc_run(env
, text
=True),
2367 {"text": True, "check": False},
2371 sys
.version_info
= (3, 7, 2)
2372 with self
.subTest():
2374 scons_subproc_run(env
, capture_output
=True),
2375 {"capture_output": True, "check": False},
2377 with self
.subTest():
2379 scons_subproc_run(env
, text
=True),
2380 {"check": False, "text": True},
2382 with self
.subTest():
2384 scons_subproc_run(env
, universal_newlines
=True),
2385 {"universal_newlines": True, "check": False},
2387 sys
.version_info
= save_info
2390 if __name__
== "__main__":
2395 # indent-tabs-mode:nil
2397 # vim: set expandtab tabstop=4 shiftwidth=4: