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.
31 from collections
import UserDict
as UD
, UserList
as UL
, deque
36 from SCons
.Environment
import (
40 SubstitutionEnvironment
,
41 is_valid_construction_var
,
43 from SCons
.Util
import CLVar
44 from SCons
.SConsign
import current_sconsign_filename
47 def diff_env(env1
, env2
):
51 for k
in list(env1
._dict
.keys()) + list(env2
._dict
.keys()):
53 for k
in sorted(d
.keys()):
56 if env1
[k
] != env2
[k
]:
57 s1
= s1
+ " " + repr(k
) + " : " + repr(env1
[k
]) + "\n"
58 s2
= s2
+ " " + repr(k
) + " : " + repr(env2
[k
]) + "\n"
60 s1
= s1
+ " " + repr(k
) + " : " + repr(env1
[k
]) + "\n"
62 s2
= s2
+ " " + repr(k
) + " : " + repr(env2
[k
]) + "\n"
67 def diff_dict(d1
, d2
):
71 for k
in list(d1
.keys()) + list(d2
.keys()):
73 for k
in sorted(d
.keys()):
77 s1
= s1
+ " " + repr(k
) + " : " + repr(d1
[k
]) + "\n"
78 s2
= s2
+ " " + repr(k
) + " : " + repr(d2
[k
]) + "\n"
80 s1
= s1
+ " " + repr(k
) + " : " + repr(d1
[k
]) + "\n"
82 s2
= s2
+ " " + repr(k
) + " : " + repr(d2
[k
]) + "\n"
90 class Builder(SCons
.Builder
.BuilderBase
):
91 """A dummy Builder class for testing purposes. "Building"
92 a target is simply setting a value in the dictionary.
94 def __init__(self
, name
= None) -> None:
97 def __call__(self
, env
, target
=None, source
=None, **kw
) -> None:
99 called_it
['target'] = target
100 called_it
['source'] = source
103 def execute(self
, target
= None, **kw
) -> None:
112 """A dummy Scanner class for testing purposes. "Scanning"
113 a target is simply setting a value in the dictionary.
115 def __init__(self
, name
, skeys
=[]) -> None:
119 def __call__(self
, filename
) -> None:
121 scanned_it
[filename
] = 1
123 def __eq__(self
, other
):
125 return self
.__dict
__ == other
.__dict
__
126 except AttributeError:
129 def get_skeys(self
, env
):
132 def __str__(self
) -> str:
137 def __init__(self
, name
) -> None:
139 def __str__(self
) -> str:
143 def get_subst_proxy(self
):
146 def test_tool( env
) -> None:
147 env
['_F77INCFLAGS'] = '${_concat(INCPREFIX, F77PATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE, affect_signature=False)}'
149 class TestEnvironmentFixture
:
150 def TestEnvironment(self
, *args
, **kw
):
151 if not kw
or 'tools' not in kw
:
152 kw
['tools'] = [test_tool
]
153 default_keys
= { 'CC' : 'cc',
154 'CCFLAGS' : '-DNDEBUG',
155 'ENV' : { 'TMP' : '/tmp' } }
156 for key
, value
in default_keys
.items():
159 if 'BUILDERS' not in kw
:
160 static_obj
= SCons
.Builder
.Builder(action
= {},
164 kw
['BUILDERS'] = {'Object' : static_obj
}
165 static_obj
.add_action('.cpp', 'fake action')
167 env
= Environment(*args
, **kw
)
170 class SubstitutionTestCase(unittest
.TestCase
):
172 def test___init__(self
) -> None:
173 """Test initializing a SubstitutionEnvironment."""
174 env
= SubstitutionEnvironment()
175 assert '__env__' not in env
177 def test___cmp__(self
) -> None:
178 """Test comparing SubstitutionEnvironments."""
179 env1
= SubstitutionEnvironment(XXX
= 'x')
180 env2
= SubstitutionEnvironment(XXX
= 'x')
181 env3
= SubstitutionEnvironment(XXX
= 'xxx')
182 env4
= SubstitutionEnvironment(XXX
= 'x', YYY
= 'x')
188 def test___delitem__(self
) -> None:
189 """Test deleting a variable from a SubstitutionEnvironment."""
190 env1
= SubstitutionEnvironment(XXX
= 'x', YYY
= 'y')
191 env2
= SubstitutionEnvironment(XXX
= 'x')
195 def test___getitem__(self
) -> None:
196 """Test fetching a variable from a SubstitutionEnvironment."""
197 env
= SubstitutionEnvironment(XXX
= 'x')
198 assert env
['XXX'] == 'x', env
['XXX']
200 def test___setitem__(self
) -> None:
201 """Test setting a variable in a SubstitutionEnvironment."""
202 env1
= SubstitutionEnvironment(XXX
= 'x')
203 env2
= SubstitutionEnvironment(XXX
= 'x', YYY
= 'y')
207 def test_get(self
) -> None:
208 """Test the SubstitutionEnvironment get() method."""
209 env
= SubstitutionEnvironment(XXX
= 'x')
210 assert env
.get('XXX') == 'x', env
.get('XXX')
211 assert env
.get('YYY') is None, env
.get('YYY')
213 def test_contains(self
) -> None:
214 """Test the SubstitutionEnvironment __contains__() method."""
215 env
= SubstitutionEnvironment(XXX
= 'x')
217 assert 'YYY' not in env
219 def test_keys(self
) -> None:
220 """Test the SubstitutionEnvironment keys() method."""
221 testdata
= {'XXX': 'x', 'YYY': 'y'}
222 env
= SubstitutionEnvironment(**testdata
)
223 keys
= list(env
.keys())
224 assert len(keys
) == 2, keys
225 for k
in testdata
.keys():
226 assert k
in keys
, keys
228 def test_values(self
) -> None:
229 """Test the SubstitutionEnvironment values() method."""
230 testdata
= {'XXX': 'x', 'YYY': 'y'}
231 env
= SubstitutionEnvironment(**testdata
)
232 values
= list(env
.values())
233 assert len(values
) == 2, values
234 for v
in testdata
.values():
235 assert v
in values
, values
237 def test_items(self
) -> None:
238 """Test the SubstitutionEnvironment items() method."""
239 testdata
= {'XXX': 'x', 'YYY': 'y'}
240 env
= SubstitutionEnvironment(**testdata
)
241 items
= list(env
.items())
242 assert len(items
) == 2, items
243 for k
, v
in testdata
.items():
244 assert (k
, v
) in items
, items
246 def test_setdefault(self
) -> None:
247 """Test the SubstitutionEnvironment setdefault() method."""
248 env
= SubstitutionEnvironment(XXX
= 'x')
249 assert env
.setdefault('XXX', 'z') == 'x', env
['XXX']
250 assert env
.setdefault('YYY', 'y') == 'y', env
['YYY']
253 def test_arg2nodes(self
) -> None:
254 """Test the arg2nodes method."""
255 env
= SubstitutionEnvironment()
257 class X(SCons
.Node
.Node
):
259 def Factory(name
, directory
= None, create
: int = 1, dict=dict, X
=X
):
262 dict[name
].name
= name
265 nodes
= env
.arg2nodes("Util.py UtilTests.py", Factory
)
266 assert len(nodes
) == 1, nodes
267 assert isinstance(nodes
[0], X
)
268 assert nodes
[0].name
== "Util.py UtilTests.py", nodes
[0].name
270 nodes
= env
.arg2nodes(["Util.py", "UtilTests.py"], Factory
)
271 assert len(nodes
) == 2, nodes
272 assert isinstance(nodes
[0], X
)
273 assert isinstance(nodes
[1], X
)
274 assert nodes
[0].name
== "Util.py", nodes
[0].name
275 assert nodes
[1].name
== "UtilTests.py", nodes
[1].name
277 n1
= Factory("Util.py")
278 nodes
= env
.arg2nodes([n1
, "UtilTests.py"], Factory
)
279 assert len(nodes
) == 2, nodes
280 assert isinstance(nodes
[0], X
)
281 assert isinstance(nodes
[1], X
)
282 assert nodes
[0].name
== "Util.py", nodes
[0].name
283 assert nodes
[1].name
== "UtilTests.py", nodes
[1].name
285 class SConsNode(SCons
.Node
.Node
):
287 nodes
= env
.arg2nodes(SConsNode())
288 assert len(nodes
) == 1, nodes
289 assert isinstance(nodes
[0], SConsNode
), nodes
[0]
293 nodes
= env
.arg2nodes(OtherNode())
294 assert len(nodes
) == 1, nodes
295 assert isinstance(nodes
[0], OtherNode
), nodes
[0]
297 def lookup_a(str, F
=Factory
):
305 def lookup_b(str, F
=Factory
):
313 env_ll
= SubstitutionEnvironment()
314 env_ll
.lookup_list
= [lookup_a
, lookup_b
]
316 nodes
= env_ll
.arg2nodes(['aaa', 'bbb', 'ccc'], Factory
)
317 assert len(nodes
) == 3, nodes
319 assert nodes
[0].name
== 'aaa', nodes
[0]
320 assert nodes
[0].a
== 1, nodes
[0]
321 assert not hasattr(nodes
[0], 'b'), nodes
[0]
323 assert nodes
[1].name
== 'bbb'
324 assert not hasattr(nodes
[1], 'a'), nodes
[1]
325 assert nodes
[1].b
== 1, nodes
[1]
327 assert nodes
[2].name
== 'ccc'
328 assert not hasattr(nodes
[2], 'a'), nodes
[1]
329 assert not hasattr(nodes
[2], 'b'), nodes
[1]
331 def lookup_bbbb(str, F
=Factory
):
339 def lookup_c(str, F
=Factory
):
347 nodes
= env
.arg2nodes(['bbbb', 'ccc'], Factory
,
348 [lookup_c
, lookup_bbbb
, lookup_b
])
349 assert len(nodes
) == 2, nodes
351 assert nodes
[0].name
== 'bbbb'
352 assert not hasattr(nodes
[0], 'a'), nodes
[1]
353 assert not hasattr(nodes
[0], 'b'), nodes
[1]
354 assert nodes
[0].bbbb
== 1, nodes
[1]
355 assert not hasattr(nodes
[0], 'c'), nodes
[0]
357 assert nodes
[1].name
== 'ccc'
358 assert not hasattr(nodes
[1], 'a'), nodes
[1]
359 assert not hasattr(nodes
[1], 'b'), nodes
[1]
360 assert not hasattr(nodes
[1], 'bbbb'), nodes
[0]
361 assert nodes
[1].c
== 1, nodes
[1]
363 def test_arg2nodes_target_source(self
) -> None:
364 """Test the arg2nodes method with target= and source= keywords
366 targets
= [DummyNode('t1'), DummyNode('t2')]
367 sources
= [DummyNode('s1'), DummyNode('s2')]
368 env
= SubstitutionEnvironment()
369 nodes
= env
.arg2nodes(['${TARGET}-a',
376 names
= [n
.name
for n
in nodes
]
377 assert names
== ['t1-a', 's1-b', 't2-c', 's2-d'], names
379 def test_gvars(self
) -> None:
380 """Test the base class gvars() method"""
381 env
= SubstitutionEnvironment()
383 assert gvars
== {}, gvars
385 def test_lvars(self
) -> None:
386 """Test the base class lvars() method"""
387 env
= SubstitutionEnvironment()
389 assert lvars
== {}, lvars
391 def test_subst(self
) -> None:
392 """Test substituting construction variables within strings
394 Check various combinations, including recursive expansion
395 of variables into other variables.
397 env
= SubstitutionEnvironment(AAA
= 'a', BBB
= 'b')
398 mystr
= env
.subst("$AAA ${AAA}A $BBBB $BBB")
399 assert mystr
== "a aA b", mystr
401 # Changed the tests below to reflect a bug fix in
403 env
= SubstitutionEnvironment(AAA
= '$BBB', BBB
= 'b', BBBA
= 'foo')
404 mystr
= env
.subst("$AAA ${AAA}A ${AAA}B $BBB")
405 assert mystr
== "b bA bB b", mystr
407 env
= SubstitutionEnvironment(AAA
= '$BBB', BBB
= '$CCC', CCC
= 'c')
408 mystr
= env
.subst("$AAA ${AAA}A ${AAA}B $BBB")
409 assert mystr
== "c cA cB c", mystr
412 env
= SubstitutionEnvironment(AAA
= ['a', 'aa', 'aaa'])
413 mystr
= env
.subst("$AAA")
414 assert mystr
== "a aa aaa", mystr
417 env
= SubstitutionEnvironment(AAA
= ('a', 'aa', 'aaa'))
418 mystr
= env
.subst("$AAA")
419 assert mystr
== "a aa aaa", mystr
426 env
= SubstitutionEnvironment(AAA
= 'aaa')
427 s
= env
.subst('$AAA $TARGET $SOURCES', target
=[t1
, t2
], source
=[s1
, s2
])
428 assert s
== "aaa t1 s1 s2", s
429 s
= env
.subst('$AAA $TARGETS $SOURCE', target
=[t1
, t2
], source
=[s1
, s2
])
430 assert s
== "aaa t1 t2 s1", s
432 # Test callables in the SubstitutionEnvironment
433 def foo(target
, source
, env
, for_signature
):
434 assert str(target
) == 't', target
435 assert str(source
) == 's', source
438 env
= SubstitutionEnvironment(BAR
=foo
, FOO
='baz')
442 subst
= env
.subst('test $BAR', target
=t
, source
=s
)
443 assert subst
== 'test baz', subst
445 # Test not calling callables in the SubstitutionEnvironment
447 # This will take some serious surgery to subst() and
448 # subst_list(), so just leave these tests out until we can
450 def bar(arg
) -> None:
453 env
= SubstitutionEnvironment(BAR
=bar
, FOO
='$BAR')
455 subst
= env
.subst('$BAR', call
=None)
456 assert subst
is bar
, subst
458 subst
= env
.subst('$FOO', call
=None)
459 assert subst
is bar
, subst
461 def test_subst_kw(self
) -> None:
462 """Test substituting construction variables within dictionaries"""
463 env
= SubstitutionEnvironment(AAA
= 'a', BBB
= 'b')
464 kw
= env
.subst_kw({'$AAA' : 'aaa', 'bbb' : '$BBB'})
465 assert len(kw
) == 2, kw
466 assert kw
['a'] == 'aaa', kw
['a']
467 assert kw
['bbb'] == 'b', kw
['bbb']
469 def test_subst_list(self
) -> None:
470 """Test substituting construction variables in command lists
472 env
= SubstitutionEnvironment(AAA
= 'a', BBB
= 'b')
473 l
= env
.subst_list("$AAA ${AAA}A $BBBB $BBB")
474 assert l
== [["a", "aA", "b"]], l
476 # Changed the tests below to reflect a bug fix in
478 env
= SubstitutionEnvironment(AAA
= '$BBB', BBB
= 'b', BBBA
= 'foo')
479 l
= env
.subst_list("$AAA ${AAA}A ${AAA}B $BBB")
480 assert l
== [["b", "bA", "bB", "b"]], l
482 env
= SubstitutionEnvironment(AAA
= '$BBB', BBB
= '$CCC', CCC
= 'c')
483 l
= env
.subst_list("$AAA ${AAA}A ${AAA}B $BBB")
484 assert l
== [["c", "cA", "cB", "c"]], l
486 env
= SubstitutionEnvironment(AAA
= '$BBB', BBB
= '$CCC', CCC
= [ 'a', 'b\nc' ])
487 lst
= env
.subst_list([ "$AAA", "B $CCC" ])
488 assert lst
== [[ "a", "b"], ["c", "B a", "b"], ["c"]], lst
495 env
= SubstitutionEnvironment(AAA
= 'aaa')
496 s
= env
.subst_list('$AAA $TARGET $SOURCES', target
=[t1
, t2
], source
=[s1
, s2
])
497 assert s
== [["aaa", "t1", "s1", "s2"]], s
498 s
= env
.subst_list('$AAA $TARGETS $SOURCE', target
=[t1
, t2
], source
=[s1
, s2
])
499 assert s
== [["aaa", "t1", "t2", "s1"]], s
501 # Test callables in the SubstitutionEnvironment
502 def foo(target
, source
, env
, for_signature
):
503 assert str(target
) == 't', target
504 assert str(source
) == 's', source
507 env
= SubstitutionEnvironment(BAR
=foo
, FOO
='baz')
511 lst
= env
.subst_list('test $BAR', target
=t
, source
=s
)
512 assert lst
== [['test', 'baz']], lst
514 # Test not calling callables in the SubstitutionEnvironment
516 # This will take some serious surgery to subst() and
517 # subst_list(), so just leave these tests out until we can
519 def bar(arg
) -> None:
522 env
= SubstitutionEnvironment(BAR
=bar
, FOO
='$BAR')
524 subst
= env
.subst_list('$BAR', call
=None)
525 assert subst
is bar
, subst
527 subst
= env
.subst_list('$FOO', call
=None)
528 assert subst
is bar
, subst
530 def test_subst_path(self
) -> None:
531 """Test substituting a path list
534 def __init__(self
, val
) -> None:
537 return self
.val
+ '-proxy'
540 def __init__(self
, val
) -> None:
542 def get_subst_proxy(self
):
544 def __str__(self
) -> str:
551 env
= SubstitutionEnvironment(FOO
='foo',
554 PROXY
=MyProxy('my1'))
556 r
= env
.subst_path('$FOO')
557 assert r
== ['foo'], r
559 r
= env
.subst_path(['$FOO', 'xxx', '$BAR'])
560 assert r
== ['foo', 'xxx', 'bar'], r
562 r
= env
.subst_path(['$FOO', '$LIST', '$BAR'])
563 assert list(map(str, r
)) == ['foo', 'one two', 'bar'], r
565 r
= env
.subst_path(['$FOO', '$TARGET', '$SOURCE', '$BAR'])
566 assert r
== ['foo', '', '', 'bar'], r
568 r
= env
.subst_path(['$FOO', '$TARGET', '$BAR'], target
=MyNode('ttt'))
569 assert list(map(str, r
)) == ['foo', 'ttt', 'bar'], r
571 r
= env
.subst_path(['$FOO', '$SOURCE', '$BAR'], source
=MyNode('sss'))
572 assert list(map(str, r
)) == ['foo', 'sss', 'bar'], r
576 r
= env
.subst_path(['$PROXY', MyProxy('my2'), n
])
577 assert r
== ['my1-proxy', 'my2-proxy', n
], r
580 def __init__(self
, s
) -> None:
582 def __str__(self
) -> str:
585 env
= SubstitutionEnvironment(FOO
=StringableObj("foo"),
586 BAR
=StringableObj("bar"))
588 r
= env
.subst_path([ "${FOO}/bar", "${BAR}/baz" ])
589 assert r
== [ "foo/bar", "bar/baz" ], r
591 r
= env
.subst_path([ "bar/${FOO}", "baz/${BAR}" ])
592 assert r
== [ "bar/foo", "baz/bar" ], r
594 r
= env
.subst_path([ "bar/${FOO}/bar", "baz/${BAR}/baz" ])
595 assert r
== [ "bar/foo/bar", "baz/bar/baz" ], r
597 def test_subst_target_source(self
) -> None:
598 """Test the base environment subst_target_source() method"""
599 env
= SubstitutionEnvironment(AAA
= 'a', BBB
= 'b')
600 mystr
= env
.subst_target_source("$AAA ${AAA}A $BBBB $BBB")
601 assert mystr
== "a aA b", mystr
603 def test_backtick(self
) -> None:
604 """Test the backtick() method for capturing command output"""
605 env
= SubstitutionEnvironment()
607 test
= TestCmd
.TestCmd(workdir
= '')
608 test
.write('stdout.py', """\
610 sys.stdout.write('this came from stdout.py\\n')
613 test
.write('stderr.py', """\
615 sys.stderr.write('this came from stderr.py\\n')
618 test
.write('fail.py', """\
622 test
.write('echo.py', """\
624 sys.stdout.write(os.environ['ECHO'] + '\\n')
628 save_stderr
= sys
.stderr
630 python
= '"' + sys
.executable
+ '"'
633 sys
.stderr
= io
.StringIO()
634 cmd
= '%s %s' % (python
, test
.workpath('stdout.py'))
635 output
= env
.backtick(cmd
)
636 errout
= sys
.stderr
.getvalue()
637 assert output
== 'this came from stdout.py\n', output
638 assert errout
== '', errout
640 sys
.stderr
= io
.StringIO()
641 cmd
= '%s %s' % (python
, test
.workpath('stderr.py'))
642 output
= env
.backtick(cmd
)
643 errout
= sys
.stderr
.getvalue()
644 assert output
== '', output
645 assert errout
== 'this came from stderr.py\n', errout
647 sys
.stderr
= io
.StringIO()
648 cmd
= '%s %s' % (python
, test
.workpath('fail.py'))
652 assert str(e
) == "'%s' exited 1" % cmd
, str(e
)
654 self
.fail("did not catch expected OSError")
656 sys
.stderr
= io
.StringIO()
657 cmd
= '%s %s' % (python
, test
.workpath('echo.py'))
658 env
['ENV'] = os
.environ
.copy()
659 env
['ENV']['ECHO'] = 'this came from ECHO'
660 output
= env
.backtick(cmd
)
661 errout
= sys
.stderr
.getvalue()
662 assert output
== 'this came from ECHO\n', output
663 assert errout
== '', errout
666 sys
.stderr
= save_stderr
668 def test_AddMethod(self
) -> None:
669 """Test the AddMethod() method"""
670 env
= SubstitutionEnvironment(FOO
= 'foo')
673 return 'func-' + self
['FOO']
675 assert not hasattr(env
, 'func')
678 assert r
== 'func-foo', r
680 assert not hasattr(env
, 'bar')
681 env
.AddMethod(func
, 'bar')
683 assert r
== 'func-foo', r
685 def func2(self
, arg
: str=''):
686 return 'func2-' + self
['FOO'] + arg
690 assert r
== 'func2-foo', r
691 r
= env
.func2('-xxx')
692 assert r
== 'func2-foo-xxx', r
694 env
.AddMethod(func2
, 'func')
696 assert r
== 'func2-foo', r
698 assert r
== 'func2-foo-yyy', r
700 # Test that clones of clones correctly re-bind added methods.
701 env1
= Environment(FOO
= '1')
702 env1
.AddMethod(func2
)
703 env2
= env1
.Clone(FOO
= '2')
704 env3
= env2
.Clone(FOO
= '3')
705 env4
= env3
.Clone(FOO
= '4')
707 assert r
== 'func2-1', r
709 assert r
== 'func2-2', r
711 assert r
== 'func2-3', r
713 assert r
== 'func2-4', r
715 # Test that clones don't re-bind an attribute that the user set.
716 env1
= Environment(FOO
= '1')
717 env1
.AddMethod(func2
)
718 def replace_func2() -> str:
719 return 'replace_func2'
720 env1
.func2
= replace_func2
721 env2
= env1
.Clone(FOO
= '2')
723 assert r
== 'replace_func2', r
725 # Test clone rebinding if using global AddMethod.
726 env1
= Environment(FOO
='1')
727 SCons
.Util
.AddMethod(env1
, func2
)
729 assert r
== 'func2-1', r
730 r
= env1
.func2('-xxx')
731 assert r
== 'func2-1-xxx', r
732 env2
= env1
.Clone(FOO
='2')
734 assert r
== 'func2-2', r
737 def test_Override(self
) -> None:
738 """Test overriding construction variables"""
739 env
= SubstitutionEnvironment(ONE
=1, TWO
=2, THREE
=3, FOUR
=4)
740 assert env
['ONE'] == 1, env
['ONE']
741 assert env
['TWO'] == 2, env
['TWO']
742 assert env
['THREE'] == 3, env
['THREE']
743 assert env
['FOUR'] == 4, env
['FOUR']
745 env2
= env
.Override({'TWO' : '10',
746 'THREE' :'x $THREE y',
747 'FOUR' : ['x', '$FOUR', 'y']})
748 assert env2
['ONE'] == 1, env2
['ONE']
749 assert env2
['TWO'] == '10', env2
['TWO']
750 assert env2
['THREE'] == 'x 3 y', env2
['THREE']
751 assert env2
['FOUR'] == ['x', 4, 'y'], env2
['FOUR']
753 assert env
['ONE'] == 1, env
['ONE']
754 assert env
['TWO'] == 2, env
['TWO']
755 assert env
['THREE'] == 3, env
['THREE']
756 assert env
['FOUR'] == 4, env
['FOUR']
758 env2
.Replace(ONE
= "won")
759 assert env2
['ONE'] == "won", env2
['ONE']
760 assert env
['ONE'] == 1, env
['ONE']
762 def test_ParseFlags(self
) -> None:
763 """Test the ParseFlags() method
765 env
= SubstitutionEnvironment()
775 'FRAMEWORKPATH' : [],
783 d
= env
.ParseFlags(None)
786 d
= env
.ParseFlags('')
789 d
= env
.ParseFlags([])
793 "-I/usr/include/fum -I bar -X "
794 '-I"C:\\Program Files\\ASCEND\\include" '
795 "-L/usr/fax -L foo -lxxx -l yyy "
796 '-L"C:\\Program Files\\ASCEND" -lascend '
805 "-frameworkdir=fwd1 "
808 "-dylib_file foo-dylib "
810 "-fmerge-all-constants "
812 "-mno-cygwin -mwindows "
815 "-iquote /usr/include/foo1 "
816 "-isystem /usr/include/foo2 "
817 "-idirafter /usr/include/foo3 "
818 "-imacros /usr/include/foo4 "
819 "-include /usr/include/foo5 "
820 "--param l1-cache-size=32 --param l2-cache-size=6144 "
822 "-DFOO -DBAR=value -D BAZ "
824 "-fsanitize-address-use-after-return "
827 d
= env
.ParseFlags(s
)
829 assert d
['ASFLAGS'] == ['-as'], d
['ASFLAGS']
830 assert d
['CFLAGS'] == ['-std=c99']
831 assert d
['CCFLAGS'] == ['-X', '-Wa,-as',
832 '-pthread', '-fmerge-all-constants',
833 '-fopenmp', '-mno-cygwin',
834 ('-arch', 'i386'), ('-isysroot', '/tmp'),
835 ('-iquote', '/usr/include/foo1'),
836 ('-isystem', '/usr/include/foo2'),
837 ('-idirafter', '/usr/include/foo3'),
838 ('-imacros', env
.fs
.File('/usr/include/foo4')),
839 ('-include', env
.fs
.File('/usr/include/foo5')),
840 ('--param', 'l1-cache-size=32'), ('--param', 'l2-cache-size=6144'),
843 '-fsanitize-address-use-after-return'], repr(d
['CCFLAGS'])
844 assert d
['CXXFLAGS'] == ['-std=c++0x'], repr(d
['CXXFLAGS'])
845 assert d
['CPPDEFINES'] == ['FOO', ['BAR', 'value'], 'BAZ'], d
['CPPDEFINES']
846 assert d
['CPPFLAGS'] == ['-Wp,-cpp'], d
['CPPFLAGS']
847 assert d
['CPPPATH'] == ['/usr/include/fum',
849 'C:\\Program Files\\ASCEND\\include'], d
['CPPPATH']
850 assert d
['FRAMEWORKPATH'] == ['fwd1', 'fwd2', 'fwd3'], d
['FRAMEWORKPATH']
851 assert d
['FRAMEWORKS'] == ['Carbon'], d
['FRAMEWORKS']
852 assert d
['LIBPATH'] == ['/usr/fax',
854 'C:\\Program Files\\ASCEND'], d
['LIBPATH']
855 LIBS
= list(map(str, d
['LIBS']))
856 assert LIBS
== ['xxx', 'yyy', 'ascend'], (d
['LIBS'], LIBS
)
857 assert d
['LINKFLAGS'] == ['-Wl,-link',
858 '-dylib_file', 'foo-dylib',
859 '-pthread', '-fmerge-all-constants', '-fopenmp',
860 '-mno-cygwin', '-mwindows',
862 ('-isysroot', '/tmp'),
865 '-fsanitize-address-use-after-return'], repr(d
['LINKFLAGS'])
866 assert d
['RPATH'] == ['rpath1', 'rpath2', 'rpath3'], d
['RPATH']
869 def test_MergeFlags(self
) -> None:
870 """Test the MergeFlags() method."""
872 env
= SubstitutionEnvironment()
873 # does not set flag if value empty
875 assert 'CCFLAGS' not in env
, env
['CCFLAGS']
876 # merges value if flag did not exist
878 assert env
['CCFLAGS'] == ['-X'], env
['CCFLAGS']
880 # avoid SubstitutionEnvironment for these, has no .Append method,
881 # which is needed for unique=False test
882 env
= Environment(CCFLAGS
="")
883 # merge with existing but empty flag
885 assert env
['CCFLAGS'] == ['-X'], env
['CCFLAGS']
886 # default Unique=True enforces no dupes
888 assert env
['CCFLAGS'] == ['-X'], env
['CCFLAGS']
889 # Unique=False allows dupes
890 env
.MergeFlags('-X', unique
=False)
891 assert env
['CCFLAGS'] == ['-X', '-X'], env
['CCFLAGS']
893 # merge from a dict with list values
894 env
= SubstitutionEnvironment(B
='b')
895 env
.MergeFlags({'A': ['aaa'], 'B': ['bb', 'bbb']})
896 assert env
['A'] == ['aaa'], env
['A']
897 assert env
['B'] == ['b', 'bb', 'bbb'], env
['B']
899 # issue #2961: merge from a dict with string values
900 env
= SubstitutionEnvironment(B
='b')
901 env
.MergeFlags({'A': 'aaa', 'B': 'bb bbb'})
902 assert env
['A'] == ['aaa'], env
['A']
903 assert env
['B'] == ['b', 'bb', 'bbb'], env
['B']
905 # issue #4231: CPPDEFINES can be a deque, tripped up merge logic
906 env
= Environment(CPPDEFINES
=deque(['aaa', 'bbb']))
907 env
.MergeFlags({'CPPDEFINES': 'ccc'})
908 self
.assertEqual(env
['CPPDEFINES'], deque(['aaa', 'bbb', 'ccc']))
910 # issue #3665: if merging dict which is a compound object
911 # (i.e. value can be lists, etc.), the value object should not
912 # be modified. per the issue, this happened if key not in env.
913 env
= SubstitutionEnvironment()
915 del env
['CFLAGS'] # just to be sure
918 flags
= {'CFLAGS': ['-pipe', '-pthread', '-g']}
921 saveflags
= copy
.deepcopy(flags
)
922 env
.MergeFlags(flags
)
923 self
.assertEqual(flags
, saveflags
)
926 class BaseTestCase(unittest
.TestCase
,TestEnvironmentFixture
):
928 reserved_variables
= [
939 def test___init__(self
) -> None:
940 """Test construction Environment creation
942 Create two with identical arguments and check that
943 they compare the same.
945 env1
= self
.TestEnvironment(XXX
= 'x', YYY
= 'y')
946 env2
= self
.TestEnvironment(XXX
= 'x', YYY
= 'y')
947 assert env1
== env2
, diff_env(env1
, env2
)
949 assert '__env__' not in env1
950 assert '__env__' not in env2
952 def test_variables(self
) -> None:
953 """Test that variables only get applied once."""
955 def __init__(self
, key
, val
) -> None:
961 def Update(self
, env
) -> None:
962 env
[self
.key
] = self
.val
963 self
.calls
= self
.calls
+ 1
965 o
= FakeOptions('AAA', 'fake_opt')
966 env
= Environment(variables
=o
, AAA
='keyword_arg')
967 assert o
.calls
== 1, o
.calls
968 assert env
['AAA'] == 'fake_opt', env
['AAA']
970 def test_get(self
) -> None:
971 """Test the get() method."""
972 env
= self
.TestEnvironment(aaa
= 'AAA')
976 x
= env
.get('aaa', 'XXX')
980 x
= env
.get('bbb', 'XXX')
983 def test_Builder_calls(self
) -> None:
984 """Test Builder calls through different environments
992 env
.Replace(BUILDERS
= { 'builder1' : b1
,
996 assert called_it
['target'] is None, called_it
997 assert called_it
['source'] == ['in1'], called_it
1000 env
.builder2(source
= 'in2', xyzzy
= 1)
1001 assert called_it
['target'] is None, called_it
1002 assert called_it
['source'] == ['in2'], called_it
1003 assert called_it
['xyzzy'] == 1, called_it
1006 env
.builder1(foo
= 'bar')
1007 assert called_it
['foo'] == 'bar', called_it
1008 assert called_it
['target'] is None, called_it
1009 assert called_it
['source'] is None, called_it
1011 def test_BuilderWrapper_attributes(self
) -> None:
1012 """Test getting and setting of BuilderWrapper attributes."""
1018 e1
.Replace(BUILDERS
={'b': b1
})
1025 assert bw
.builder
is b1
1027 assert bw
.builder
is b2
1029 self
.assertRaises(AttributeError, getattr, bw
, 'foobar')
1031 assert bw
.foobar
== 42
1033 # This unit test is currently disabled because we don't think the
1034 # underlying method it tests (Environment.BuilderWrapper.execute())
1035 # is necessary, but we're leaving the code here for now in case
1037 def _DO_NOT_test_Builder_execs(self
) -> None:
1038 """Test Builder execution through different environments
1040 One environment is initialized with a single
1041 Builder object, one with a list of a single Builder
1042 object, and one with a list of two Builder objects.
1050 env3
= Environment()
1051 env3
.Replace(BUILDERS
= { 'builder1' : b1
,
1053 env3
.builder1
.execute(target
= 'out1')
1054 env3
.builder2
.execute(target
= 'out2')
1055 env3
.builder1
.execute(target
= 'out3')
1056 assert built_it
['out1']
1057 assert built_it
['out2']
1058 assert built_it
['out3']
1061 assert env4
.builder1
.env
is env4
, "builder1.env (%s) == env3 (%s)?" % (
1062 env4
.builder1
.env
, env3
)
1063 assert env4
.builder2
.env
is env4
, "builder2.env (%s) == env3 (%s)?" % (
1064 env4
.builder1
.env
, env3
)
1066 # Now test BUILDERS as a dictionary.
1068 env5
= self
.TestEnvironment(BUILDERS
={ 'foo' : b1
})
1069 env5
['BUILDERS']['bar'] = b2
1070 env5
.foo
.execute(target
='out1')
1071 env5
.bar
.execute(target
='out2')
1072 assert built_it
['out1']
1073 assert built_it
['out2']
1076 env6
= Environment()
1077 env6
['BUILDERS'] = { 'foo' : b1
,
1079 env6
.foo
.execute(target
='out1')
1080 env6
.bar
.execute(target
='out2')
1081 assert built_it
['out1']
1082 assert built_it
['out2']
1086 def test_Scanners(self
) -> None:
1087 """Test setting SCANNERS in various ways
1089 One environment is initialized with a single
1090 Scanner object, one with a list of a single Scanner
1091 object, and one with a list of two Scanner objects.
1095 s1
= Scanner(name
= 'scanner1', skeys
= [".c", ".cc"])
1096 s2
= Scanner(name
= 'scanner2', skeys
= [".m4"])
1097 s3
= Scanner(name
= 'scanner3', skeys
= [".m4", ".m5"])
1098 s4
= Scanner(name
= 'scanner4', skeys
= [None])
1100 # XXX Tests for scanner execution through different environments,
1101 # XXX if we ever want to do that some day
1103 # env1 = self.TestEnvironment(SCANNERS = s1)
1104 # env1.scanner1(filename = 'out1')
1105 # assert scanned_it['out1']
1108 # env2 = self.TestEnvironment(SCANNERS = [s1])
1109 # env1.scanner1(filename = 'out1')
1110 # assert scanned_it['out1']
1113 # env3 = Environment()
1114 # env3.Replace(SCANNERS = [s1])
1115 # env3.scanner1(filename = 'out1')
1116 # env3.scanner2(filename = 'out2')
1117 # env3.scanner1(filename = 'out3')
1118 # assert scanned_it['out1']
1119 # assert scanned_it['out2']
1120 # assert scanned_it['out3']
1122 suffixes
= [".c", ".cc", ".cxx", ".m4", ".m5"]
1125 try: del env
['SCANNERS']
1126 except KeyError: pass
1127 s
= list(map(env
.get_scanner
, suffixes
))
1128 assert s
== [None, None, None, None, None], s
1130 env
= self
.TestEnvironment(SCANNERS
= [])
1131 s
= list(map(env
.get_scanner
, suffixes
))
1132 assert s
== [None, None, None, None, None], s
1134 env
.Replace(SCANNERS
= [s1
])
1135 s
= list(map(env
.get_scanner
, suffixes
))
1136 assert s
== [s1
, s1
, None, None, None], s
1138 env
.Append(SCANNERS
= [s2
])
1139 s
= list(map(env
.get_scanner
, suffixes
))
1140 assert s
== [s1
, s1
, None, s2
, None], s
1142 env
.AppendUnique(SCANNERS
= [s3
])
1143 s
= list(map(env
.get_scanner
, suffixes
))
1144 assert s
== [s1
, s1
, None, s2
, s3
], s
1146 env
= env
.Clone(SCANNERS
= [s2
])
1147 s
= list(map(env
.get_scanner
, suffixes
))
1148 assert s
== [None, None, None, s2
, None], s
1150 env
['SCANNERS'] = [s1
]
1151 s
= list(map(env
.get_scanner
, suffixes
))
1152 assert s
== [s1
, s1
, None, None, None], s
1154 env
.PrependUnique(SCANNERS
= [s2
, s1
])
1155 s
= list(map(env
.get_scanner
, suffixes
))
1156 assert s
== [s1
, s1
, None, s2
, None], s
1158 env
.Prepend(SCANNERS
= [s3
])
1159 s
= list(map(env
.get_scanner
, suffixes
))
1160 assert s
== [s1
, s1
, None, s3
, s3
], s
1162 # Verify behavior of case-insensitive suffix matches on Windows.
1163 uc_suffixes
= [_
.upper() for _
in suffixes
]
1165 env
= Environment(SCANNERS
= [s1
, s2
, s3
],
1168 s
= list(map(env
.get_scanner
, suffixes
))
1169 assert s
== [s1
, s1
, None, s2
, s3
], s
1171 s
= list(map(env
.get_scanner
, uc_suffixes
))
1172 assert s
== [None, None, None, None, None], s
1174 env
['PLATFORM'] = 'win32'
1176 s
= list(map(env
.get_scanner
, uc_suffixes
))
1177 assert s
== [s1
, s1
, None, s2
, s3
], s
1179 # Verify behavior for a scanner returning None (on Windows
1180 # where we might try to perform case manipulation on None).
1181 env
.Replace(SCANNERS
= [s4
])
1182 s
= list(map(env
.get_scanner
, suffixes
))
1183 assert s
== [None, None, None, None, None], s
1185 def test_ENV(self
) -> None:
1186 """Test setting the external ENV in Environments
1189 assert 'ENV' in env
.Dictionary()
1191 env
= self
.TestEnvironment(ENV
= { 'PATH' : '/foo:/bar' })
1192 assert env
.Dictionary('ENV')['PATH'] == '/foo:/bar'
1194 def test_ReservedVariables(self
) -> None:
1195 """Test warning generation when reserved variable names are set"""
1197 reserved_variables
= [
1204 'UNCHANGED_SOURCES',
1205 'UNCHANGED_TARGETS',
1208 warning
= SCons
.Warnings
.ReservedVariableWarning
1209 SCons
.Warnings
.enableWarningClass(warning
)
1210 old
= SCons
.Warnings
.warningAsException(1)
1213 env4
= Environment()
1214 for kw
in self
.reserved_variables
:
1220 assert exc_caught
, "Did not catch ReservedVariableWarning for `%s'" % kw
1221 assert kw
not in env4
, "`%s' variable was incorrectly set" % kw
1223 SCons
.Warnings
.warningAsException(old
)
1225 def test_FutureReservedVariables(self
) -> None:
1226 """Test warning generation when future reserved variable names are set"""
1228 future_reserved_variables
= []
1230 warning
= SCons
.Warnings
.FutureReservedVariableWarning
1231 SCons
.Warnings
.enableWarningClass(warning
)
1232 old
= SCons
.Warnings
.warningAsException(1)
1235 env4
= Environment()
1236 for kw
in future_reserved_variables
:
1242 assert exc_caught
, "Did not catch FutureReservedVariableWarning for `%s'" % kw
1243 assert kw
in env4
, "`%s' variable was not set" % kw
1245 SCons
.Warnings
.warningAsException(old
)
1247 def test_IllegalVariables(self
) -> None:
1248 """Test that use of illegal variables raises an exception"""
1250 def test_it(var
, env
=env
) -> None:
1254 except SCons
.Errors
.UserError
:
1256 assert exc_caught
, "did not catch UserError for '%s'" % var
1258 assert env
['aaa'] == 1, env
['aaa']
1263 def test_autogenerate(self
) -> None:
1264 """Test autogenerating variables in a dictionary."""
1266 drive
, p
= os
.path
.splitdrive(os
.getcwd())
1267 def normalize_path(path
, drive
=drive
):
1268 if path
[0] in '\\/':
1270 path
= os
.path
.normpath(path
)
1271 drive
, path
= os
.path
.splitdrive(path
)
1272 return drive
.lower() + path
1274 env
= self
.TestEnvironment(LIBS
= [ 'foo', 'bar', 'baz' ],
1275 LIBLINKPREFIX
= 'foo',
1276 LIBLINKSUFFIX
= 'bar')
1278 def RDirs(pathlist
, fs
=env
.fs
):
1279 return fs
.Dir('xx').Rfindalldirs(pathlist
)
1281 env
['RDirs'] = RDirs
1282 flags
= env
.subst_list('$_LIBFLAGS', 1)[0]
1283 assert flags
== ['foobar', 'foobar', 'foobazbar'], flags
1285 blat
= env
.fs
.Dir('blat')
1287 env
.Replace(CPPPATH
= [ 'foo', '$FOO/bar', blat
],
1291 flags
= env
.subst_list('$_CPPINCFLAGS', 1)[0]
1293 normalize_path('foo'),
1294 normalize_path('xx/foobar'),
1295 normalize_path('foo'),
1296 normalize_path('xx/baz/bar'),
1297 normalize_path('foo'),
1298 normalize_path('blatbar'),
1301 assert flags
== expect
, flags
1303 env
.Replace(F77PATH
= [ 'foo', '$FOO/bar', blat
],
1307 flags
= env
.subst_list('$_F77INCFLAGS', 1)[0]
1309 normalize_path('foo'),
1310 normalize_path('xx/foobar'),
1311 normalize_path('foo'),
1312 normalize_path('xx/baz/bar'),
1313 normalize_path('foo'),
1314 normalize_path('blatbar'),
1317 assert flags
== expect
, flags
1319 env
.Replace(CPPPATH
= '', F77PATH
= '', LIBPATH
= '')
1320 l
= env
.subst_list('$_CPPINCFLAGS')
1322 l
= env
.subst_list('$_F77INCFLAGS')
1324 l
= env
.subst_list('$_LIBDIRFLAGS')
1327 env
.fs
.Repository('/rep1')
1328 env
.fs
.Repository('/rep2')
1329 env
.Replace(CPPPATH
= [ 'foo', '/__a__/b', '$FOO/bar', blat
],
1333 flags
= env
.subst_list('$_CPPINCFLAGS', 1)[0]
1335 '-I', normalize_path('xx/fooXXX'),
1336 '-I', normalize_path('/rep1/xx/fooXXX'),
1337 '-I', normalize_path('/rep2/xx/fooXXX'),
1338 '-I', normalize_path('/__a__/bXXX'),
1339 '-I', normalize_path('xx/baz/barXXX'),
1340 '-I', normalize_path('/rep1/xx/baz/barXXX'),
1341 '-I', normalize_path('/rep2/xx/baz/barXXX'),
1342 '-I', normalize_path('blatXXX'),
1345 def normalize_if_path(arg
, np
=normalize_path
):
1346 if arg
not in ('$(','$)','-I'):
1349 flags
= list(map(normalize_if_path
, flags
))
1350 assert flags
== expect
, flags
1352 def test_platform(self
) -> None:
1353 """Test specifying a platform callable when instantiating."""
1355 def __str__(self
) -> str: return "TestPlatform"
1356 def __call__(self
, env
) -> None: env
['XYZZY'] = 777
1358 def tool(env
) -> None:
1359 env
['SET_TOOL'] = 'initialized'
1360 assert env
['PLATFORM'] == "TestPlatform"
1362 env
= self
.TestEnvironment(platform
= platform(), tools
= [tool
])
1363 assert env
['XYZZY'] == 777, env
1364 assert env
['PLATFORM'] == "TestPlatform"
1365 assert env
['SET_TOOL'] == "initialized"
1367 def test_Default_PLATFORM(self
) -> None:
1368 """Test overriding the default PLATFORM variable"""
1370 def __str__(self
) -> str: return "DefaultTestPlatform"
1371 def __call__(self
, env
) -> None: env
['XYZZY'] = 888
1373 def tool(env
) -> None:
1374 env
['SET_TOOL'] = 'abcde'
1375 assert env
['PLATFORM'] == "DefaultTestPlatform"
1377 import SCons
.Defaults
1378 save
= SCons
.Defaults
.ConstructionEnvironment
.copy()
1380 import SCons
.Defaults
1381 SCons
.Defaults
.ConstructionEnvironment
.update({
1382 'PLATFORM' : platform(),
1384 env
= self
.TestEnvironment(tools
= [tool
])
1385 assert env
['XYZZY'] == 888, env
1386 assert env
['PLATFORM'] == "DefaultTestPlatform"
1387 assert env
['SET_TOOL'] == "abcde"
1389 SCons
.Defaults
.ConstructionEnvironment
= save
1391 def test_tools(self
) -> None:
1392 """Test specifying a tool callable when instantiating."""
1393 def t1(env
) -> None:
1395 def t2(env
) -> None:
1397 def t3(env
) -> None:
1398 env
['AAA'] = env
['XYZ']
1399 def t4(env
) -> None:
1401 env
= self
.TestEnvironment(tools
= [t1
, t2
, t3
], XYZ
= 'aaa')
1402 assert env
['TOOL1'] == 111, env
['TOOL1']
1403 assert env
['TOOL2'] == 222, env
1404 assert env
['AAA'] == 'aaa', env
1406 assert env
['TOOL4'] == 444, env
1408 test
= TestCmd
.TestCmd(workdir
= '')
1409 test
.write('faketool.py', """\
1410 def generate(env, **kw):
1411 for k, v in kw.items():
1418 env
= self
.TestEnvironment(tools
= [('faketool', {'a':1, 'b':2, 'c':3})],
1419 toolpath
= [test
.workpath('')])
1420 assert env
['a'] == 1, env
['a']
1421 assert env
['b'] == 2, env
['b']
1422 assert env
['c'] == 3, env
['c']
1424 def test_Default_TOOLS(self
) -> None:
1425 """Test overriding the default TOOLS variable"""
1426 def t5(env
) -> None:
1428 def t6(env
) -> None:
1430 def t7(env
) -> None:
1431 env
['BBB'] = env
['XYZ']
1432 def t8(env
) -> None:
1435 import SCons
.Defaults
1436 save
= SCons
.Defaults
.ConstructionEnvironment
.copy()
1438 SCons
.Defaults
.ConstructionEnvironment
.update({
1439 'TOOLS' : [t5
, t6
, t7
],
1441 env
= Environment(XYZ
= 'bbb')
1442 assert env
['TOOL5'] == 555, env
['TOOL5']
1443 assert env
['TOOL6'] == 666, env
1444 assert env
['BBB'] == 'bbb', env
1446 assert env
['TOOL8'] == 888, env
1448 SCons
.Defaults
.ConstructionEnvironment
= save
1450 def test_null_tools(self
) -> None:
1451 """Test specifying a tool of None is OK."""
1452 def t1(env
) -> None:
1454 def t2(env
) -> None:
1456 env
= self
.TestEnvironment(tools
= [t1
, None, t2
], XYZ
= 'aaa')
1457 assert env
['TOOL1'] == 111, env
['TOOL1']
1458 assert env
['TOOL2'] == 222, env
1459 assert env
['XYZ'] == 'aaa', env
1460 env
= self
.TestEnvironment(tools
= [None], XYZ
= 'xyz')
1461 assert env
['XYZ'] == 'xyz', env
1462 env
= self
.TestEnvironment(tools
= [t1
, '', t2
], XYZ
= 'ddd')
1463 assert env
['TOOL1'] == 111, env
['TOOL1']
1464 assert env
['TOOL2'] == 222, env
1465 assert env
['XYZ'] == 'ddd', env
1467 def test_default_copy_cache(self
) -> None:
1470 def copy2(self
, src
, dst
) -> None:
1474 save_copy_from_cache
= SCons
.CacheDir
.CacheDir
.copy_from_cache
1475 SCons
.CacheDir
.CacheDir
.copy_from_cache
= copy2
1477 save_copy_to_cache
= SCons
.CacheDir
.CacheDir
.copy_to_cache
1478 SCons
.CacheDir
.CacheDir
.copy_to_cache
= copy2
1480 env
= self
.TestEnvironment()
1482 SCons
.Environment
.default_copy_from_cache(env
, 'test.in', 'test.out')
1486 SCons
.Environment
.default_copy_to_cache(env
, 'test.in', 'test.out')
1489 SCons
.CacheDir
.CacheDir
.copy_from_cache
= save_copy_from_cache
1490 SCons
.CacheDir
.CacheDir
.copy_to_cache
= save_copy_to_cache
1492 def test_concat(self
) -> None:
1493 """Test _concat()"""
1494 e1
= self
.TestEnvironment(PRE
='pre', SUF
='suf', STR
='a b', LIST
=['a', 'b'])
1496 x
= s("${_concat('', '', '', __env__)}")
1498 x
= s("${_concat('', [], '', __env__)}")
1500 x
= s("${_concat(PRE, '', SUF, __env__)}")
1502 x
= s("${_concat(PRE, STR, SUF, __env__)}")
1503 assert x
== 'prea bsuf', x
1504 x
= s("${_concat(PRE, LIST, SUF, __env__)}")
1505 assert x
== 'preasuf prebsuf', x
1506 x
= s("${_concat(PRE, LIST, SUF, __env__,affect_signature=False)}", raw
=True)
1507 assert x
== '$( preasuf prebsuf $)', x
1510 def test_concat_nested(self
) -> None:
1511 """Test _concat() on a nested substitution strings."""
1512 e
= self
.TestEnvironment(PRE
='pre', SUF
='suf',
1516 x
= e
.subst('$( ${_concat(PRE, L1, SUF, __env__)} $)')
1517 assert x
== 'preasuf prebsuf', x
1518 e
.AppendUnique(L1
= ['$L2'])
1519 x
= e
.subst('$( ${_concat(PRE, L1, SUF, __env__)} $)')
1520 assert x
== 'preasuf prebsuf precsuf predsuf', x
1521 e
.AppendUnique(L1
= ['$L3'])
1522 x
= e
.subst('$( ${_concat(PRE, L1, SUF, __env__)} $)')
1523 assert x
== 'preasuf prebsuf precsuf predsuf precsuf predsuf', x
1525 def test_gvars(self
) -> None:
1526 """Test the Environment gvars() method"""
1527 env
= self
.TestEnvironment(XXX
= 'x', YYY
= 'y', ZZZ
= 'z')
1529 assert gvars
['XXX'] == 'x', gvars
['XXX']
1530 assert gvars
['YYY'] == 'y', gvars
['YYY']
1531 assert gvars
['ZZZ'] == 'z', gvars
['ZZZ']
1533 def test__update(self
) -> None:
1534 """Test the _update() method"""
1535 env
= self
.TestEnvironment(X
= 'x', Y
= 'y', Z
= 'z')
1536 assert env
['X'] == 'x', env
['X']
1537 assert env
['Y'] == 'y', env
['Y']
1538 assert env
['Z'] == 'z', env
['Z']
1539 env
._update
({'X' : 'xxx',
1545 assert env
['X'] == 'xxx', env
['X']
1546 assert env
['Y'] == 'y', env
['Y']
1547 assert env
['Z'] == 'zzz', env
['Z']
1548 assert env
['TARGET'] == 't', env
['TARGET']
1549 assert env
['TARGETS'] == 'ttt', env
['TARGETS']
1550 assert env
['SOURCE'] == 's', env
['SOURCE']
1551 assert env
['SOURCES'] == 'sss', env
['SOURCES']
1553 def test_Append(self
) -> None:
1554 """Test appending to construction variables in an Environment
1557 b1
= Environment()['BUILDERS']
1558 b2
= Environment()['BUILDERS']
1559 assert b1
== b2
, diff_dict(b1
, b2
)
1563 'a2', ['A2'], ['a2', 'A2'],
1564 'a3', UL(['A3']), UL(['a', '3', 'A3']),
1567 'a6', UL([]), UL(['a', '6']),
1568 'a7', [''], ['a7', ''],
1569 'a8', UL(['']), UL(['a', '8', '']),
1571 ['e1'], 'E1', ['e1', 'E1'],
1572 ['e2'], ['E2'], ['e2', 'E2'],
1573 ['e3'], UL(['E3']), UL(['e3', 'E3']),
1576 ['e6'], UL([]), UL(['e6']),
1577 ['e7'], [''], ['e7', ''],
1578 ['e8'], UL(['']), UL(['e8', '']),
1580 UL(['i1']), 'I1', UL(['i1', 'I', '1']),
1581 UL(['i2']), ['I2'], UL(['i2', 'I2']),
1582 UL(['i3']), UL(['I3']), UL(['i3', 'I3']),
1583 UL(['i4']), '', UL(['i4']),
1584 UL(['i5']), [], UL(['i5']),
1585 UL(['i6']), UL([]), UL(['i6']),
1586 UL(['i7']), [''], UL(['i7', '']),
1587 UL(['i8']), UL(['']), UL(['i8', '']),
1589 {'d1':1}, 'D1', {'d1':1, 'D1':None},
1590 {'d2':1}, ['D2'], {'d2':1, 'D2':None},
1591 {'d3':1}, UL(['D3']), {'d3':1, 'D3':None},
1592 {'d4':1}, {'D4':1}, {'d4':1, 'D4':1},
1593 {'d5':1}, UD({'D5':1}), UD({'d5':1, 'D5':1}),
1595 UD({'u1':1}), 'U1', UD({'u1':1, 'U1':None}),
1596 UD({'u2':1}), ['U2'], UD({'u2':1, 'U2':None}),
1597 UD({'u3':1}), UL(['U3']), UD({'u3':1, 'U3':None}),
1598 UD({'u4':1}), {'U4':1}, UD({'u4':1, 'U4':1}),
1599 UD({'u5':1}), UD({'U5':1}), UD({'u5':1, 'U5':1}),
1603 '', UL(['M3']), UL(['M3']),
1608 '', UL(['']), UL(['']),
1612 [], UL(['N3']), UL(['N3']),
1617 [], UL(['']), UL(['']),
1619 UL([]), 'O1', ['O', '1'],
1620 UL([]), ['O2'], ['O2'],
1621 UL([]), UL(['O3']), UL(['O3']),
1624 UL([]), UL([]), UL([]),
1625 UL([]), [''], UL(['']),
1626 UL([]), UL(['']), UL(['']),
1628 [''], 'P1', ['', 'P1'],
1629 [''], ['P2'], ['', 'P2'],
1630 [''], UL(['P3']), UL(['', 'P3']),
1633 [''], UL([]), UL(['']),
1634 [''], [''], ['', ''],
1635 [''], UL(['']), UL(['', '']),
1637 UL(['']), 'Q1', ['', 'Q', '1'],
1638 UL(['']), ['Q2'], ['', 'Q2'],
1639 UL(['']), UL(['Q3']), UL(['', 'Q3']),
1640 UL(['']), '', UL(['']),
1641 UL(['']), [], UL(['']),
1642 UL(['']), UL([]), UL(['']),
1643 UL(['']), [''], UL(['', '']),
1644 UL(['']), UL(['']), UL(['', '']),
1650 input, append
, expect
= cases
[:3]
1651 env
['XXX'] = copy
.copy(input)
1653 env
.Append(XXX
= append
)
1654 except Exception as e
:
1655 if failed
== 0: print()
1656 print(" %s Append %s exception: %s" % \
1657 (repr(input), repr(append
), e
))
1661 if result
!= expect
:
1662 if failed
== 0: print()
1663 print(" %s Append %s => %s did not match %s" % \
1664 (repr(input), repr(append
), repr(result
), repr(expect
)))
1667 assert failed
== 0, "%d Append() cases failed" % failed
1669 env
['UL'] = UL(['foo'])
1670 env
.Append(UL
= 'bar')
1672 assert isinstance(result
, UL
), repr(result
)
1673 assert result
== ['foo', 'b', 'a', 'r'], result
1675 env
['CLVar'] = CLVar(['foo'])
1676 env
.Append(CLVar
= 'bar')
1677 result
= env
['CLVar']
1678 assert isinstance(result
, CLVar
), repr(result
)
1679 assert result
== ['foo', 'bar'], result
1682 def __init__(self
, name
) -> None:
1684 def __str__(self
) -> str:
1686 def __eq__(self
, other
):
1687 raise Exception("should not compare")
1691 env2
= self
.TestEnvironment(CCC1
= ['c1'], CCC2
= ccc
)
1692 env2
.Append(CCC1
= ccc
, CCC2
= ['c2'])
1693 assert env2
['CCC1'][0] == 'c1', env2
['CCC1']
1694 assert env2
['CCC1'][1] is ccc
, env2
['CCC1']
1695 assert env2
['CCC2'][0] is ccc
, env2
['CCC2']
1696 assert env2
['CCC2'][1] == 'c2', env2
['CCC2']
1698 env3
= self
.TestEnvironment(X
= {'x1' : 7})
1699 env3
.Append(X
= {'x1' : 8, 'x2' : 9}, Y
= {'y1' : 10})
1700 assert env3
['X'] == {'x1': 8, 'x2': 9}, env3
['X']
1701 assert env3
['Y'] == {'y1': 10}, env3
['Y']
1705 env4
= self
.TestEnvironment(BUILDERS
= {'z1' : z1
})
1706 env4
.Append(BUILDERS
= {'z2' : z2
})
1707 assert env4
['BUILDERS'] == {'z1' : z1
, 'z2' : z2
}, env4
['BUILDERS']
1708 assert hasattr(env4
, 'z1')
1709 assert hasattr(env4
, 'z2')
1711 def test_AppendENVPath(self
) -> None:
1712 """Test appending to an ENV path."""
1713 env1
= self
.TestEnvironment(
1714 ENV
={'PATH': r
'C:\dir\num\one;C:\dir\num\two'},
1715 MYENV
={'MYPATH': r
'C:\mydir\num\one;C:\mydir\num\two'},
1717 # have to include the pathsep here so that the test will work on UNIX too.
1718 env1
.AppendENVPath('PATH', r
'C:\dir\num\two', sep
=';')
1719 env1
.AppendENVPath('PATH', r
'C:\dir\num\three', sep
=';')
1720 env1
.AppendENVPath('MYPATH', r
'C:\mydir\num\three', 'MYENV', sep
=';')
1722 env1
['ENV']['PATH'] == r
'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three'
1723 ), env1
['ENV']['PATH']
1725 env1
.AppendENVPath('MYPATH', r
'C:\mydir\num\three', 'MYENV', sep
=';')
1727 'MYPATH', r
'C:\mydir\num\one', 'MYENV', sep
=';', delete_existing
=1
1729 # this should do nothing since delete_existing is 0
1731 env1
['MYENV']['MYPATH'] == r
'C:\mydir\num\two;C:\mydir\num\three;C:\mydir\num\one'
1732 ), env1
['MYENV']['MYPATH']
1734 test
= TestCmd
.TestCmd(workdir
='')
1735 test
.subdir('sub1', 'sub2')
1736 p
= env1
['ENV']['PATH']
1737 env1
.AppendENVPath('PATH', '#sub1', sep
=';')
1738 env1
.AppendENVPath('PATH', env1
.fs
.Dir('sub2'), sep
=';')
1739 assert env1
['ENV']['PATH'] == p
+ ';sub1;sub2', env1
['ENV']['PATH']
1741 def test_AppendUnique(self
) -> None:
1742 """Test appending to unique values to construction variables
1744 This strips values that are already present when lists are
1746 env
= self
.TestEnvironment(AAA1
= 'a1',
1758 DDD1
= ['a', 'b', 'c'])
1759 env
['LL1'] = [env
.Literal('a literal'), env
.Literal('b literal')]
1760 env
['LL2'] = [env
.Literal('c literal'), env
.Literal('b literal')]
1761 env
.AppendUnique(AAA1
= 'a1',
1763 AAA3
= ['a3', 'b', 'c', 'c', 'b', 'a3'], # ignore dups
1768 BBB3
= ['b3', 'c', 'd', 'c', 'b3'],
1774 LL1
= env
.Literal('a literal'),
1775 LL2
= env
.Literal('a literal'))
1777 assert env
['AAA1'] == 'a1a1', env
['AAA1']
1778 assert env
['AAA2'] == ['a2'], env
['AAA2']
1779 assert env
['AAA3'] == ['a3', 'b', 'c'], env
['AAA3']
1780 assert env
['AAA4'] == 'a4a4.new', env
['AAA4']
1781 assert env
['AAA5'] == ['a5', 'a5.new'], env
['AAA5']
1782 assert env
['BBB1'] == ['b1'], env
['BBB1']
1783 assert env
['BBB2'] == ['b2'], env
['BBB2']
1784 assert env
['BBB3'] == ['b3', 'c', 'd'], env
['BBB3']
1785 assert env
['BBB4'] == ['b4', 'b4.new'], env
['BBB4']
1786 assert env
['BBB5'] == ['b5', 'b5.new'], env
['BBB5']
1787 assert env
['CCC1'] == 'c1', env
['CCC1']
1788 assert env
['CCC2'] == ['c2'], env
['CCC2']
1789 assert env
['DDD1'] == ['a', 'b', 'c'], env
['DDD1']
1790 assert env
['LL1'] == [env
.Literal('a literal'), env
.Literal('b literal')], env
['LL1']
1791 assert env
['LL2'] == [env
.Literal('c literal'), env
.Literal('b literal'), env
.Literal('a literal')], [str(x
) for x
in env
['LL2']]
1793 env
.AppendUnique(DDD1
= 'b', delete_existing
=1)
1794 assert env
['DDD1'] == ['a', 'c', 'b'], env
['DDD1'] # b moves to end
1795 env
.AppendUnique(DDD1
= ['a','b'], delete_existing
=1)
1796 assert env
['DDD1'] == ['c', 'a', 'b'], env
['DDD1'] # a & b move to end
1797 env
.AppendUnique(DDD1
= ['e','f', 'e'], delete_existing
=1)
1798 assert env
['DDD1'] == ['c', 'a', 'b', 'f', 'e'], env
['DDD1'] # add last
1800 env
['CLVar'] = CLVar([])
1801 env
.AppendUnique(CLVar
= 'bar')
1802 result
= env
['CLVar']
1803 assert isinstance(result
, CLVar
), repr(result
)
1804 assert result
== ['bar'], result
1806 env
['CLVar'] = CLVar(['abc'])
1807 env
.AppendUnique(CLVar
= 'bar')
1808 result
= env
['CLVar']
1809 assert isinstance(result
, CLVar
), repr(result
)
1810 assert result
== ['abc', 'bar'], result
1812 env
['CLVar'] = CLVar(['bar'])
1813 env
.AppendUnique(CLVar
= 'bar')
1814 result
= env
['CLVar']
1815 assert isinstance(result
, CLVar
), repr(result
)
1816 assert result
== ['bar'], result
1818 def test_Clone(self
) -> None:
1819 """Test construction environment cloning.
1821 The clone should compare equal if there are no overrides.
1822 Update the clone independently afterwards and check that
1823 the original remains intact (that is, no dangling
1824 references point to objects in the copied environment).
1825 Clone the original with some construction variable
1826 updates and check that the original remains intact
1827 and the copy has the updated values.
1829 with self
.subTest():
1830 env1
= self
.TestEnvironment(XXX
='x', YYY
='y')
1832 env1copy
= env1
.Clone()
1833 self
.assertEqual(env1copy
, env1
)
1834 self
.assertEqual(env2
, env1
)
1835 env2
.Replace(YYY
= 'yyy')
1836 self
.assertNotEqual(env1
, env2
)
1837 self
.assertEqual(env1
, env1copy
)
1839 env3
= env1
.Clone(XXX
='x3', ZZZ
='z3')
1840 self
.assertNotEqual(env3
, env1
)
1841 self
.assertEqual(env3
.Dictionary('XXX'), 'x3')
1842 self
.assertEqual(env1
.Dictionary('XXX'), 'x')
1843 self
.assertEqual(env3
.Dictionary('YYY'), 'y')
1844 self
.assertEqual(env3
.Dictionary('ZZZ'), 'z3')
1845 self
.assertRaises(KeyError, env1
.Dictionary
, 'ZZZ') # leak test
1846 self
.assertEqual(env1
, env1copy
)
1848 # Ensure that lists and dictionaries are deep copied, but not instances
1849 with self
.subTest():
1854 env1
= self
.TestEnvironment(
1860 env2
.Dictionary('YYY').append(4)
1861 env2
.Dictionary('ZZZ')[5] = 6
1862 self
.assertIs(env1
.Dictionary('XXX'), env2
.Dictionary('XXX'))
1863 self
.assertIn(4, env2
.Dictionary('YYY'))
1864 self
.assertNotIn(4, env1
.Dictionary('YYY'))
1865 self
.assertIn(5, env2
.Dictionary('ZZZ'))
1866 self
.assertNotIn(5, env1
.Dictionary('ZZZ'))
1868 # We also need to look at the special cases in semi_deepcopy()
1869 # used when cloning - these should not leak to the original either
1870 with self
.subTest():
1871 env1
= self
.TestEnvironment(
1872 XXX
=deque([1, 2, 3]),
1874 ZZZ
=UD({1: 2, 3: 4}),
1877 env2
['XXX'].append(4)
1878 env2
['YYY'].append(4)
1880 self
.assertIn(4, env2
['XXX'])
1881 self
.assertNotIn(4, env1
['XXX'])
1882 self
.assertIn(4, env2
['YYY'])
1883 self
.assertNotIn(4, env1
['YYY'])
1884 self
.assertIn(5, env2
['ZZZ'])
1885 self
.assertNotIn(5, env1
['ZZZ'])
1887 # BUILDERS is special...
1888 with self
.subTest():
1889 env1
= self
.TestEnvironment(BUILDERS
={'b1': Builder()})
1890 assert hasattr(env1
, 'b1'), "env1.b1 was not set"
1891 assert env1
.b1
.object == env1
, "b1.object doesn't point to env1"
1892 env2
= env1
.Clone(BUILDERS
= {'b2' : Builder()})
1894 assert hasattr(env1
, 'b1'), "b1 was mistakenly cleared from env1"
1895 assert env1
.b1
.object == env1
, "b1.object was changed"
1896 assert not hasattr(env2
, 'b1'), "b1 was not cleared from env2"
1897 assert hasattr(env2
, 'b2'), "env2.b2 was not set"
1898 assert env2
.b2
.object == env2
, "b2.object doesn't point to env2"
1900 # Ensure that specifying new tools in a copied environment works.
1901 with self
.subTest():
1903 def foo(env
) -> None:
1906 def bar(env
) -> None:
1909 def baz(env
) -> None:
1912 env1
= self
.TestEnvironment(tools
=[foo
])
1914 env3
= env1
.Clone(tools
=[bar
, baz
])
1916 assert env1
.get('FOO') == 1
1917 assert env1
.get('BAR') is None
1918 assert env1
.get('BAZ') is None
1919 assert env2
.get('FOO') == 1
1920 assert env2
.get('BAR') is None
1921 assert env2
.get('BAZ') is None
1922 assert env3
.get('FOO') == 1
1923 assert env3
.get('BAR') == 2
1924 assert env3
.get('BAZ') == 3
1926 # Ensure that recursive variable substitution when copying
1927 # environments works properly.
1928 with self
.subTest():
1929 env1
= self
.TestEnvironment(CCFLAGS
='-DFOO', XYZ
='-DXYZ')
1931 CCFLAGS
='$CCFLAGS -DBAR', XYZ
=['-DABC', 'x $XYZ y', '-DDEF']
1933 x
= env2
.get('CCFLAGS')
1934 assert x
== '-DFOO -DBAR', x
1936 assert x
== ['-DABC', 'x -DXYZ y', '-DDEF'], x
1938 # Ensure that special properties of a class don't get
1940 with self
.subTest():
1941 env1
= self
.TestEnvironment(FLAGS
=CLVar('flag1 flag2'))
1942 x
= env1
.get('FLAGS')
1943 assert x
== ['flag1', 'flag2'], x
1945 env2
.Append(FLAGS
='flag3 flag4')
1946 x
= env2
.get('FLAGS')
1947 assert x
== ['flag1', 'flag2', 'flag3', 'flag4'], x
1948 x
= env1
.get('FLAGS')
1949 assert x
== ['flag1', 'flag2'], x
1951 # Ensure that appending directly to a copied CLVar
1952 # doesn't modify the original.
1953 with self
.subTest():
1954 env1
= self
.TestEnvironment(FLAGS
=CLVar('flag1 flag2'))
1955 x
= env1
.get('FLAGS')
1956 assert x
== ['flag1', 'flag2'], x
1958 env2
['FLAGS'] += ['flag3', 'flag4']
1959 x
= env2
.get('FLAGS')
1960 assert x
== ['flag1', 'flag2', 'flag3', 'flag4'], x
1961 x
= env1
.get('FLAGS')
1962 assert x
== ['flag1', 'flag2'], x
1964 # Test that the environment stores the toolpath and
1965 # re-uses it for copies.
1966 with self
.subTest():
1967 test
= TestCmd
.TestCmd(workdir
='')
1969 test
.write('xxx.py', """\
1976 test
.write('yyy.py', """\
1983 env
= self
.TestEnvironment(tools
=['xxx'], toolpath
=[test
.workpath('')])
1984 assert env
['XXX'] == 'one', env
['XXX']
1985 env
= env
.Clone(tools
=['yyy'])
1986 assert env
['YYY'] == 'two', env
['YYY']
1989 with self
.subTest():
1992 def my_tool(env
, rv
=real_value
) -> None:
1993 assert env
['KEY_THAT_I_WANT'] == rv
[0]
1994 env
['KEY_THAT_I_WANT'] = rv
[0] + 1
1996 env
= self
.TestEnvironment()
1999 env
= env
.Clone(KEY_THAT_I_WANT
=5, tools
=[my_tool
])
2000 assert env
['KEY_THAT_I_WANT'] == real_value
[0], env
['KEY_THAT_I_WANT']
2003 env
= env
.Clone(KEY_THAT_I_WANT
=6, tools
=[my_tool
])
2004 assert env
['KEY_THAT_I_WANT'] == real_value
[0], env
['KEY_THAT_I_WANT']
2006 # test for pull request #150
2007 with self
.subTest():
2008 env
= self
.TestEnvironment()
2009 env
._dict
.pop('BUILDERS')
2010 assert ('BUILDERS' in env
) is False
2013 def test_Detect(self
) -> None:
2014 """Test Detect()ing tools"""
2015 test
= TestCmd
.TestCmd(workdir
= '')
2016 test
.subdir('sub1', 'sub2')
2017 sub1
= test
.workpath('sub1')
2018 sub2
= test
.workpath('sub2')
2020 if sys
.platform
== 'win32':
2021 test
.write(['sub1', 'xxx'], "sub1/xxx\n")
2022 test
.write(['sub2', 'xxx'], "sub2/xxx\n")
2024 env
= self
.TestEnvironment(ENV
= { 'PATH' : [sub1
, sub2
] })
2026 x
= env
.Detect('xxx.exe')
2029 test
.write(['sub2', 'xxx.exe'], "sub2/xxx.exe\n")
2031 env
= self
.TestEnvironment(ENV
= { 'PATH' : [sub1
, sub2
] })
2033 x
= env
.Detect('xxx.exe')
2034 assert x
== 'xxx.exe', x
2036 test
.write(['sub1', 'xxx.exe'], "sub1/xxx.exe\n")
2038 x
= env
.Detect('xxx.exe')
2039 assert x
== 'xxx.exe', x
2042 test
.write(['sub1', 'xxx.exe'], "sub1/xxx.exe\n")
2043 test
.write(['sub2', 'xxx.exe'], "sub2/xxx.exe\n")
2045 env
= self
.TestEnvironment(ENV
= { 'PATH' : [sub1
, sub2
] })
2047 x
= env
.Detect('xxx.exe')
2050 sub2_xxx_exe
= test
.workpath('sub2', 'xxx.exe')
2051 os
.chmod(sub2_xxx_exe
, 0o755)
2053 env
= self
.TestEnvironment(ENV
= { 'PATH' : [sub1
, sub2
] })
2055 x
= env
.Detect('xxx.exe')
2056 assert x
== 'xxx.exe', x
2058 sub1_xxx_exe
= test
.workpath('sub1', 'xxx.exe')
2059 os
.chmod(sub1_xxx_exe
, 0o755)
2061 x
= env
.Detect('xxx.exe')
2062 assert x
== 'xxx.exe', x
2064 env
= self
.TestEnvironment(ENV
= { 'PATH' : [] })
2065 x
= env
.Detect('xxx.exe')
2068 def test_Dictionary(self
) -> None:
2069 """Test retrieval of known construction variables
2071 Fetch them from the Dictionary and check for well-known
2072 defaults that get inserted.
2074 env
= self
.TestEnvironment(XXX
= 'x', YYY
= 'y', ZZZ
= 'z')
2075 assert env
.Dictionary('XXX') == 'x'
2076 assert env
.Dictionary('YYY') == 'y'
2077 assert env
.Dictionary('XXX', 'ZZZ') == ['x', 'z']
2078 xxx
, zzz
= env
.Dictionary('XXX', 'ZZZ')
2081 assert 'BUILDERS' in env
.Dictionary()
2082 assert 'CC' in env
.Dictionary()
2083 assert 'CCFLAGS' in env
.Dictionary()
2084 assert 'ENV' in env
.Dictionary()
2086 assert env
['XXX'] == 'x'
2088 assert env
.Dictionary('XXX') == 'foo'
2090 assert 'XXX' not in env
.Dictionary()
2092 def test_FindIxes(self
) -> None:
2093 """Test FindIxes()"""
2094 env
= self
.TestEnvironment(LIBPREFIX
='lib',
2101 paths
= [os
.path
.join('dir', 'libfoo.a'),
2102 os
.path
.join('dir', 'libfoo.so')]
2104 assert paths
[0] == env
.FindIxes(paths
, 'LIBPREFIX', 'LIBSUFFIX')
2105 assert paths
[1] == env
.FindIxes(paths
, 'SHLIBPREFIX', 'SHLIBSUFFIX')
2106 assert None is env
.FindIxes(paths
, 'PREFIX', 'POST')
2108 paths
= ['libfoo.a', 'prefoopost']
2110 assert paths
[0] == env
.FindIxes(paths
, 'LIBPREFIX', 'LIBSUFFIX')
2111 assert None is env
.FindIxes(paths
, 'SHLIBPREFIX', 'SHLIBSUFFIX')
2112 assert paths
[1] == env
.FindIxes(paths
, 'PREFIX', 'SUFFIX')
2114 def test_ParseConfig(self
) -> None:
2115 """Test the ParseConfig() method"""
2116 env
= self
.TestEnvironment(COMMAND
='command',
2117 ASFLAGS
='assembler',
2129 orig_backtick
= env
.backtick
2131 """mocked backtick routine so command is not actually issued.
2133 Just returns the string it was given.
2135 def __init__(self
, save_command
, output
) -> None:
2136 self
.save_command
= save_command
2137 self
.output
= output
2138 def __call__(self
, command
):
2139 self
.save_command
.append(command
)
2144 env
.backtick
= my_backtick(save_command
,
2145 "-I/usr/include/fum -I bar -X\n" + \
2146 "-L/usr/fax -L foo -lxxx -l yyy " + \
2147 "-Wa,-as -Wl,-link " + \
2148 "-Wl,-rpath=rpath1 " + \
2149 "-Wl,-R,rpath2 " + \
2152 "-framework Carbon " + \
2153 "-frameworkdir=fwd1 " + \
2157 "-fmerge-all-constants " + \
2158 "-mno-cygwin -mwindows " + \
2159 "-arch i386 -isysroot /tmp " + \
2160 "-iquote /usr/include/foo1 " + \
2161 "-isystem /usr/include/foo2 " + \
2162 "-idirafter /usr/include/foo3 " + \
2164 "-DFOO -DBAR=value")
2165 env
.ParseConfig("fake $COMMAND")
2166 assert save_command
== ['fake command'], save_command
2167 assert env
['ASFLAGS'] == ['assembler', '-as'], env
['ASFLAGS']
2168 assert env
['CCFLAGS'] == ['', '-X', '-Wa,-as',
2169 '-pthread', '-fmerge-all-constants', '-mno-cygwin',
2170 ('-arch', 'i386'), ('-isysroot', '/tmp'),
2171 ('-iquote', '/usr/include/foo1'),
2172 ('-isystem', '/usr/include/foo2'),
2173 ('-idirafter', '/usr/include/foo3'),
2174 '+DD64'], env
['CCFLAGS']
2175 self
.assertEqual(list(env
['CPPDEFINES']), ['FOO', ['BAR', 'value']])
2176 assert env
['CPPFLAGS'] == ['', '-Wp,-cpp'], env
['CPPFLAGS']
2177 assert env
['CPPPATH'] == ['string', '/usr/include/fum', 'bar'], env
['CPPPATH']
2178 assert env
['FRAMEWORKPATH'] == ['fwd1', 'fwd2', 'fwd3'], env
['FRAMEWORKPATH']
2179 assert env
['FRAMEWORKS'] == ['Carbon'], env
['FRAMEWORKS']
2180 assert env
['LIBPATH'] == ['list', '/usr/fax', 'foo'], env
['LIBPATH']
2181 assert env
['LIBS'] == ['xxx', 'yyy', env
.File('abc')], env
['LIBS']
2182 assert env
['LINKFLAGS'] == ['', '-Wl,-link', '-pthread',
2183 '-fmerge-all-constants',
2184 '-mno-cygwin', '-mwindows',
2186 ('-isysroot', '/tmp'),
2187 '+DD64'], env
['LINKFLAGS']
2188 assert env
['RPATH'] == ['rpath1', 'rpath2', 'rpath3'], env
['RPATH']
2190 env
.backtick
= my_backtick([], "-Ibar")
2191 env
.ParseConfig("fake2")
2192 assert env
['CPPPATH'] == ['string', '/usr/include/fum', 'bar'], env
['CPPPATH']
2193 env
.ParseConfig("fake2", unique
=0)
2194 assert env
['CPPPATH'] == ['string', '/usr/include/fum', 'bar', 'bar'], env
['CPPPATH']
2196 env
.backtick
= orig_backtick
2198 # check that we can pass our own function,
2199 # and that it works for both values of unique
2201 def my_function(myenv
, flags
, unique
: bool=True) -> None:
2204 args
= json
.loads(flags
)
2206 myenv
.AppendUnique(**args
)
2208 myenv
.Append(**args
)
2210 json_str
= '{"LIBS": ["yyy", "xxx", "yyy"]}'
2212 env
= Environment(LIBS
=['xxx'])
2214 env
.backtick
= my_backtick([], json_str
)
2215 env2
.backtick
= my_backtick([], json_str
)
2217 env
.ParseConfig("foo", my_function
)
2218 assert env
['LIBS'] == ['xxx', 'yyy'], env
['LIBS']
2220 env2
.ParseConfig("foo2", my_function
, unique
=False)
2221 assert env2
['LIBS'] == ['xxx', 'yyy', 'xxx', 'yyy'], env2
['LIBS']
2224 def test_ParseDepends(self
) -> None:
2225 """Test the ParseDepends() method"""
2226 test
= TestCmd
.TestCmd(workdir
= '')
2228 test
.write('single', """
2238 test
.write('multiple', """
2249 env
= self
.TestEnvironment(SINGLE
= test
.workpath('single'))
2253 def my_depends(target
, dependency
, tlist
=tlist
, dlist
=dlist
) -> None:
2254 tlist
.extend(target
)
2255 dlist
.extend(dependency
)
2257 env
.Depends
= my_depends
2259 env
.ParseDepends(test
.workpath('does_not_exist'))
2263 env
.ParseDepends(test
.workpath('does_not_exist'), must_exist
=1)
2266 assert exc_caught
, "did not catch expected IOError"
2271 env
.ParseDepends('$SINGLE', only_one
=1)
2272 t
= list(map(str, tlist
))
2273 d
= list(map(str, dlist
))
2274 assert t
== ['f0'], t
2275 assert d
== ['d1', 'd2', 'd3'], d
2280 env
.ParseDepends(test
.workpath('multiple'))
2281 t
= list(map(str, tlist
))
2282 d
= list(map(str, dlist
))
2283 assert t
== ['f1', 'f2', 'f3', 'f4', 'f5'], t
2284 assert d
== ['foo', 'bar', 'abc', 'def', 'ghi', 'jkl', 'mno'], d
2288 env
.ParseDepends(test
.workpath('multiple'), only_one
=1)
2289 except SCons
.Errors
.UserError
:
2291 assert exc_caught
, "did not catch expected UserError"
2293 def test_Platform(self
) -> None:
2294 """Test the Platform() method"""
2295 env
= self
.TestEnvironment(WIN32
='win32', NONE
='no-such-platform')
2299 env
.Platform('does_not_exist')
2300 except SCons
.Errors
.UserError
:
2302 assert exc_caught
, "did not catch expected UserError"
2306 env
.Platform('$NONE')
2307 except SCons
.Errors
.UserError
:
2309 assert exc_caught
, "did not catch expected UserError"
2311 env
.Platform('posix')
2312 assert env
['OBJSUFFIX'] == '.o', env
['OBJSUFFIX']
2314 env
.Platform('$WIN32')
2315 assert env
['OBJSUFFIX'] == '.obj', env
['OBJSUFFIX']
2317 def test_Prepend(self
) -> None:
2318 """Test prepending to construction variables in an Environment
2322 'a2', ['A2'], ['A2', 'a2'],
2323 'a3', UL(['A3']), UL(['A3', 'a', '3']),
2326 'a6', UL([]), UL(['a', '6']),
2327 'a7', [''], ['', 'a7'],
2328 'a8', UL(['']), UL(['', 'a', '8']),
2330 ['e1'], 'E1', ['E1', 'e1'],
2331 ['e2'], ['E2'], ['E2', 'e2'],
2332 ['e3'], UL(['E3']), UL(['E3', 'e3']),
2335 ['e6'], UL([]), UL(['e6']),
2336 ['e7'], [''], ['', 'e7'],
2337 ['e8'], UL(['']), UL(['', 'e8']),
2339 UL(['i1']), 'I1', UL(['I', '1', 'i1']),
2340 UL(['i2']), ['I2'], UL(['I2', 'i2']),
2341 UL(['i3']), UL(['I3']), UL(['I3', 'i3']),
2342 UL(['i4']), '', UL(['i4']),
2343 UL(['i5']), [], UL(['i5']),
2344 UL(['i6']), UL([]), UL(['i6']),
2345 UL(['i7']), [''], UL(['', 'i7']),
2346 UL(['i8']), UL(['']), UL(['', 'i8']),
2348 {'d1':1}, 'D1', {'d1':1, 'D1':None},
2349 {'d2':1}, ['D2'], {'d2':1, 'D2':None},
2350 {'d3':1}, UL(['D3']), {'d3':1, 'D3':None},
2351 {'d4':1}, {'D4':1}, {'d4':1, 'D4':1},
2352 {'d5':1}, UD({'D5':1}), UD({'d5':1, 'D5':1}),
2354 UD({'u1':1}), 'U1', UD({'u1':1, 'U1':None}),
2355 UD({'u2':1}), ['U2'], UD({'u2':1, 'U2':None}),
2356 UD({'u3':1}), UL(['U3']), UD({'u3':1, 'U3':None}),
2357 UD({'u4':1}), {'U4':1}, UD({'u4':1, 'U4':1}),
2358 UD({'u5':1}), UD({'U5':1}), UD({'u5':1, 'U5':1}),
2362 '', UL(['M3']), UL(['M3']),
2367 '', UL(['']), UL(['']),
2371 [], UL(['N3']), UL(['N3']),
2376 [], UL(['']), UL(['']),
2378 UL([]), 'O1', UL(['O', '1']),
2379 UL([]), ['O2'], UL(['O2']),
2380 UL([]), UL(['O3']), UL(['O3']),
2383 UL([]), UL([]), UL([]),
2384 UL([]), [''], UL(['']),
2385 UL([]), UL(['']), UL(['']),
2387 [''], 'P1', ['P1', ''],
2388 [''], ['P2'], ['P2', ''],
2389 [''], UL(['P3']), UL(['P3', '']),
2392 [''], UL([]), UL(['']),
2393 [''], [''], ['', ''],
2394 [''], UL(['']), UL(['', '']),
2396 UL(['']), 'Q1', UL(['Q', '1', '']),
2397 UL(['']), ['Q2'], UL(['Q2', '']),
2398 UL(['']), UL(['Q3']), UL(['Q3', '']),
2399 UL(['']), '', UL(['']),
2400 UL(['']), [], UL(['']),
2401 UL(['']), UL([]), UL(['']),
2402 UL(['']), [''], UL(['', '']),
2403 UL(['']), UL(['']), UL(['', '']),
2409 input, prepend
, expect
= cases
[:3]
2410 env
['XXX'] = copy
.copy(input)
2412 env
.Prepend(XXX
= prepend
)
2413 except Exception as e
:
2414 if failed
== 0: print()
2415 print(" %s Prepend %s exception: %s" % \
2416 (repr(input), repr(prepend
), e
))
2420 if result
!= expect
:
2421 if failed
== 0: print()
2422 print(" %s Prepend %s => %s did not match %s" % \
2423 (repr(input), repr(prepend
), repr(result
), repr(expect
)))
2426 assert failed
== 0, "%d Prepend() cases failed" % failed
2428 env
['UL'] = UL(['foo'])
2429 env
.Prepend(UL
= 'bar')
2431 assert isinstance(result
, UL
), repr(result
)
2432 assert result
== ['b', 'a', 'r', 'foo'], result
2434 env
['CLVar'] = CLVar(['foo'])
2435 env
.Prepend(CLVar
= 'bar')
2436 result
= env
['CLVar']
2437 assert isinstance(result
, CLVar
), repr(result
)
2438 assert result
== ['bar', 'foo'], result
2440 env3
= self
.TestEnvironment(X
= {'x1' : 7})
2441 env3
.Prepend(X
= {'x1' : 8, 'x2' : 9}, Y
= {'y1' : 10})
2442 assert env3
['X'] == {'x1': 8, 'x2' : 9}, env3
['X']
2443 assert env3
['Y'] == {'y1': 10}, env3
['Y']
2447 env4
= self
.TestEnvironment(BUILDERS
= {'z1' : z1
})
2448 env4
.Prepend(BUILDERS
= {'z2' : z2
})
2449 assert env4
['BUILDERS'] == {'z1' : z1
, 'z2' : z2
}, env4
['BUILDERS']
2450 assert hasattr(env4
, 'z1')
2451 assert hasattr(env4
, 'z2')
2453 def test_PrependENVPath(self
) -> None:
2454 """Test prepending to an ENV path."""
2455 env1
= self
.TestEnvironment(
2456 ENV
={'PATH': r
'C:\dir\num\one;C:\dir\num\two'},
2457 MYENV
={'MYPATH': r
'C:\mydir\num\one;C:\mydir\num\two'},
2459 # have to include the pathsep here so that the test will work on UNIX too.
2460 env1
.PrependENVPath('PATH', r
'C:\dir\num\two', sep
=';')
2461 env1
.PrependENVPath('PATH', r
'C:\dir\num\three', sep
=';')
2463 env1
['ENV']['PATH'] == r
'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one'
2464 ), env1
['ENV']['PATH']
2466 env1
.PrependENVPath('MYPATH', r
'C:\mydir\num\three', 'MYENV', sep
=';')
2467 env1
.PrependENVPath('MYPATH', r
'C:\mydir\num\one', 'MYENV', sep
=';')
2468 # this should do nothing since delete_existing is 0
2469 env1
.PrependENVPath(
2470 'MYPATH', r
'C:\mydir\num\three', 'MYENV', sep
=';', delete_existing
=0
2473 env1
['MYENV']['MYPATH'] == r
'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two'
2474 ), env1
['MYENV']['MYPATH']
2476 test
= TestCmd
.TestCmd(workdir
='')
2477 test
.subdir('sub1', 'sub2')
2478 p
= env1
['ENV']['PATH']
2479 env1
.PrependENVPath('PATH', '#sub1', sep
=';')
2480 env1
.PrependENVPath('PATH', env1
.fs
.Dir('sub2'), sep
=';')
2481 assert env1
['ENV']['PATH'] == 'sub2;sub1;' + p
, env1
['ENV']['PATH']
2483 def test_PrependUnique(self
) -> None:
2484 """Test prepending unique values to construction variables
2486 This strips values that are already present when lists are
2488 env
= self
.TestEnvironment(AAA1
= 'a1',
2500 DDD1
= ['a', 'b', 'c'])
2501 env
.PrependUnique(AAA1
= 'a1',
2503 AAA3
= ['a3', 'b', 'c', 'b', 'a3'], # ignore dups
2508 BBB3
= ['b3', 'b', 'c', 'b3'],
2514 assert env
['AAA1'] == 'a1a1', env
['AAA1']
2515 assert env
['AAA2'] == ['a2'], env
['AAA2']
2516 assert env
['AAA3'] == ['c', 'b', 'a3'], env
['AAA3']
2517 assert env
['AAA4'] == 'a4.newa4', env
['AAA4']
2518 assert env
['AAA5'] == ['a5.new', 'a5'], env
['AAA5']
2519 assert env
['BBB1'] == ['b1'], env
['BBB1']
2520 assert env
['BBB2'] == ['b2'], env
['BBB2']
2521 assert env
['BBB3'] == ['b', 'c', 'b3'], env
['BBB3']
2522 assert env
['BBB4'] == ['b4.new', 'b4'], env
['BBB4']
2523 assert env
['BBB5'] == ['b5.new', 'b5'], env
['BBB5']
2524 assert env
['CCC1'] == 'c1', env
['CCC1']
2525 assert env
['CCC2'] == ['c2'], env
['CCC2']
2526 assert env
['DDD1'] == ['a', 'b', 'c'], env
['DDD1']
2528 env
.PrependUnique(DDD1
= 'b', delete_existing
=1)
2529 assert env
['DDD1'] == ['b', 'a', 'c'], env
['DDD1'] # b moves to front
2530 env
.PrependUnique(DDD1
= ['a','c'], delete_existing
=1)
2531 assert env
['DDD1'] == ['a', 'c', 'b'], env
['DDD1'] # a & c move to front
2532 env
.PrependUnique(DDD1
= ['d','e','d'], delete_existing
=1)
2533 assert env
['DDD1'] == ['d', 'e', 'a', 'c', 'b'], env
['DDD1']
2536 env
['CLVar'] = CLVar([])
2537 env
.PrependUnique(CLVar
= 'bar')
2538 result
= env
['CLVar']
2539 assert isinstance(result
, CLVar
), repr(result
)
2540 assert result
== ['bar'], result
2542 env
['CLVar'] = CLVar(['abc'])
2543 env
.PrependUnique(CLVar
= 'bar')
2544 result
= env
['CLVar']
2545 assert isinstance(result
, CLVar
), repr(result
)
2546 assert result
== ['bar', 'abc'], result
2548 env
['CLVar'] = CLVar(['bar'])
2549 env
.PrependUnique(CLVar
= 'bar')
2550 result
= env
['CLVar']
2551 assert isinstance(result
, CLVar
), repr(result
)
2552 assert result
== ['bar'], result
2554 def test_Replace(self
) -> None:
2555 """Test replacing construction variables in an Environment
2557 After creation of the Environment, of course.
2559 env1
= self
.TestEnvironment(AAA
= 'a', BBB
= 'b')
2560 env1
.Replace(BBB
= 'bbb', CCC
= 'ccc')
2562 env2
= self
.TestEnvironment(AAA
= 'a', BBB
= 'bbb', CCC
= 'ccc')
2563 assert env1
== env2
, diff_env(env1
, env2
)
2567 env3
= self
.TestEnvironment(BUILDERS
= {'b1' : b1
})
2568 assert hasattr(env3
, 'b1'), "b1 was not set"
2569 env3
.Replace(BUILDERS
= {'b2' : b2
})
2570 assert not hasattr(env3
, 'b1'), "b1 was not cleared"
2571 assert hasattr(env3
, 'b2'), "b2 was not set"
2573 def test_ReplaceIxes(self
) -> None:
2574 """Test ReplaceIxes()"""
2575 env
= self
.TestEnvironment(LIBPREFIX
='lib',
2582 assert 'libfoo.a' == env
.ReplaceIxes('libfoo.so',
2583 'SHLIBPREFIX', 'SHLIBSUFFIX',
2584 'LIBPREFIX', 'LIBSUFFIX')
2586 assert os
.path
.join('dir', 'libfoo.a') == env
.ReplaceIxes(os
.path
.join('dir', 'libfoo.so'),
2587 'SHLIBPREFIX', 'SHLIBSUFFIX',
2588 'LIBPREFIX', 'LIBSUFFIX')
2590 assert 'libfoo.a' == env
.ReplaceIxes('prefoopost',
2592 'LIBPREFIX', 'LIBSUFFIX')
2594 def test_SetDefault(self
) -> None:
2595 """Test the SetDefault method"""
2596 env
= self
.TestEnvironment(tools
= [])
2597 env
.SetDefault(V1
= 1)
2598 env
.SetDefault(V1
= 2)
2599 assert env
['V1'] == 1
2601 env
.SetDefault(V2
= 1)
2602 assert env
['V2'] == 2
2604 def test_Tool(self
) -> None:
2605 """Test the Tool() method"""
2606 env
= self
.TestEnvironment(LINK
='link', NONE
='no-such-tool')
2610 tool
= env
.Tool('does_not_exist')
2611 except SCons
.Errors
.UserError
:
2614 assert isinstance(tool
, SCons
.Tool
.Tool
)
2615 assert exc_caught
, "did not catch expected UserError"
2620 except SCons
.Errors
.UserError
:
2622 assert exc_caught
, "did not catch expected UserError"
2624 # Use a non-existent toolpath directory just to make sure we
2625 # can call Tool() with the keyword argument.
2626 env
.Tool('cc', toolpath
=['/no/such/directory'])
2627 assert env
['CC'] == 'cc', env
['CC']
2630 assert env
['LINK'] == '$SMARTLINK', env
['LINK']
2632 # Test that the environment stores the toolpath and
2633 # re-uses it for later calls.
2634 test
= TestCmd
.TestCmd(workdir
= '')
2636 test
.write('xxx.py', """\
2643 test
.write('yyy.py', """\
2650 env
= self
.TestEnvironment(tools
=['xxx'], toolpath
=[test
.workpath('')])
2651 assert env
['XXX'] == 'one', env
['XXX']
2653 assert env
['YYY'] == 'two', env
['YYY']
2655 def test_WhereIs(self
) -> None:
2656 """Test the WhereIs() method"""
2657 test
= TestCmd
.TestCmd(workdir
= '')
2659 sub1_xxx_exe
= test
.workpath('sub1', 'xxx.exe')
2660 sub2_xxx_exe
= test
.workpath('sub2', 'xxx.exe')
2661 sub3_xxx_exe
= test
.workpath('sub3', 'xxx.exe')
2662 sub4_xxx_exe
= test
.workpath('sub4', 'xxx.exe')
2664 test
.subdir('subdir', 'sub1', 'sub2', 'sub3', 'sub4')
2666 if sys
.platform
!= 'win32':
2667 test
.write(sub1_xxx_exe
, "\n")
2669 os
.mkdir(sub2_xxx_exe
)
2671 test
.write(sub3_xxx_exe
, "\n")
2672 os
.chmod(sub3_xxx_exe
, 0o777)
2674 test
.write(sub4_xxx_exe
, "\n")
2675 os
.chmod(sub4_xxx_exe
, 0o777)
2677 env_path
= os
.environ
['PATH']
2679 pathdirs_1234
= [ test
.workpath('sub1'),
2680 test
.workpath('sub2'),
2681 test
.workpath('sub3'),
2682 test
.workpath('sub4'),
2683 ] + env_path
.split(os
.pathsep
)
2685 pathdirs_1243
= [ test
.workpath('sub1'),
2686 test
.workpath('sub2'),
2687 test
.workpath('sub4'),
2688 test
.workpath('sub3'),
2689 ] + env_path
.split(os
.pathsep
)
2691 path
= os
.pathsep
.join(pathdirs_1234
)
2692 env
= self
.TestEnvironment(ENV
= {'PATH' : path
})
2693 wi
= env
.WhereIs('')
2695 wi
= env
.WhereIs('xxx.exe')
2696 assert wi
== test
.workpath(sub3_xxx_exe
), wi
2697 wi
= env
.WhereIs('xxx.exe', pathdirs_1243
)
2698 assert wi
== test
.workpath(sub4_xxx_exe
), wi
2699 wi
= env
.WhereIs('xxx.exe', os
.pathsep
.join(pathdirs_1243
))
2700 assert wi
== test
.workpath(sub4_xxx_exe
), wi
2702 wi
= env
.WhereIs('xxx.exe', reject
= sub3_xxx_exe
)
2703 assert wi
== test
.workpath(sub4_xxx_exe
), wi
2704 wi
= env
.WhereIs('xxx.exe', pathdirs_1243
, reject
= sub3_xxx_exe
)
2705 assert wi
== test
.workpath(sub4_xxx_exe
), wi
2707 path
= os
.pathsep
.join(pathdirs_1243
)
2708 env
= self
.TestEnvironment(ENV
= {'PATH' : path
})
2709 wi
= env
.WhereIs('xxx.exe')
2710 assert wi
== test
.workpath(sub4_xxx_exe
), wi
2711 wi
= env
.WhereIs('xxx.exe', pathdirs_1234
)
2712 assert wi
== test
.workpath(sub3_xxx_exe
), wi
2713 wi
= env
.WhereIs('xxx.exe', os
.pathsep
.join(pathdirs_1234
))
2714 assert wi
== test
.workpath(sub3_xxx_exe
), wi
2716 if sys
.platform
== 'win32':
2717 wi
= env
.WhereIs('xxx', pathext
= '')
2718 assert wi
is None, wi
2720 wi
= env
.WhereIs('xxx', pathext
= '.exe')
2721 assert wi
== test
.workpath(sub4_xxx_exe
), wi
2723 wi
= env
.WhereIs('xxx', path
= pathdirs_1234
, pathext
= '.BAT;.EXE')
2724 assert wi
.lower() == test
.workpath(sub3_xxx_exe
).lower(), wi
2726 # Test that we return a normalized path even when
2727 # the path contains forward slashes.
2728 forward_slash
= test
.workpath('') + '/sub3'
2729 wi
= env
.WhereIs('xxx', path
= forward_slash
, pathext
= '.EXE')
2730 assert wi
.lower() == test
.workpath(sub3_xxx_exe
).lower(), wi
2734 def test_Action(self
) -> None:
2735 """Test the Action() method"""
2738 env
= self
.TestEnvironment(FOO
= 'xyzzy')
2740 a
= env
.Action('foo')
2742 assert a
.__class
__ is SCons
.Action
.CommandAction
, a
.__class
__
2744 a
= env
.Action('$FOO')
2746 assert a
.__class
__ is SCons
.Action
.CommandAction
, a
.__class
__
2748 a
= env
.Action('$$FOO')
2750 assert a
.__class
__ is SCons
.Action
.LazyAction
, a
.__class
__
2752 a
= env
.Action(['$FOO', 'foo'])
2754 assert a
.__class
__ is SCons
.Action
.ListAction
, a
.__class
__
2756 def func(arg
) -> None:
2758 a
= env
.Action(func
)
2760 assert a
.__class
__ is SCons
.Action
.FunctionAction
, a
.__class
__
2762 def test_AddPostAction(self
) -> None:
2763 """Test the AddPostAction() method"""
2764 env
= self
.TestEnvironment(FOO
='fff', BAR
='bbb')
2766 n
= env
.AddPostAction('$FOO', lambda x
: x
)
2767 assert str(n
[0]) == 'fff', n
[0]
2769 n
= env
.AddPostAction(['ggg', '$BAR'], lambda x
: x
)
2770 assert str(n
[0]) == 'ggg', n
[0]
2771 assert str(n
[1]) == 'bbb', n
[1]
2773 def test_AddPreAction(self
) -> None:
2774 """Test the AddPreAction() method"""
2775 env
= self
.TestEnvironment(FOO
='fff', BAR
='bbb')
2777 n
= env
.AddPreAction('$FOO', lambda x
: x
)
2778 assert str(n
[0]) == 'fff', n
[0]
2780 n
= env
.AddPreAction(['ggg', '$BAR'], lambda x
: x
)
2781 assert str(n
[0]) == 'ggg', n
[0]
2782 assert str(n
[1]) == 'bbb', n
[1]
2784 def test_Alias(self
) -> None:
2785 """Test the Alias() method"""
2786 env
= self
.TestEnvironment(FOO
='kkk', BAR
='lll', EA
='export_alias')
2788 tgt
= env
.Alias('new_alias')[0]
2789 assert str(tgt
) == 'new_alias', tgt
2790 assert tgt
.sources
== [], tgt
.sources
2791 assert not hasattr(tgt
, 'builder'), tgt
.builder
2793 tgt
= env
.Alias('None_alias', None)[0]
2794 assert str(tgt
) == 'None_alias', tgt
2795 assert tgt
.sources
== [], tgt
.sources
2797 tgt
= env
.Alias('empty_list', [])[0]
2798 assert str(tgt
) == 'empty_list', tgt
2799 assert tgt
.sources
== [], tgt
.sources
2801 tgt
= env
.Alias('export_alias', [ 'asrc1', '$FOO' ])[0]
2802 assert str(tgt
) == 'export_alias', tgt
2803 assert len(tgt
.sources
) == 2, list(map(str, tgt
.sources
))
2804 assert str(tgt
.sources
[0]) == 'asrc1', list(map(str, tgt
.sources
))
2805 assert str(tgt
.sources
[1]) == 'kkk', list(map(str, tgt
.sources
))
2807 n
= env
.Alias(tgt
, source
= ['$BAR', 'asrc4'])[0]
2809 assert len(tgt
.sources
) == 4, list(map(str, tgt
.sources
))
2810 assert str(tgt
.sources
[2]) == 'lll', list(map(str, tgt
.sources
))
2811 assert str(tgt
.sources
[3]) == 'asrc4', list(map(str, tgt
.sources
))
2813 n
= env
.Alias('$EA', 'asrc5')[0]
2815 assert len(tgt
.sources
) == 5, list(map(str, tgt
.sources
))
2816 assert str(tgt
.sources
[4]) == 'asrc5', list(map(str, tgt
.sources
))
2818 t1
, t2
= env
.Alias(['t1', 't2'], ['asrc6', 'asrc7'])
2819 assert str(t1
) == 't1', t1
2820 assert str(t2
) == 't2', t2
2821 assert len(t1
.sources
) == 2, list(map(str, t1
.sources
))
2822 assert str(t1
.sources
[0]) == 'asrc6', list(map(str, t1
.sources
))
2823 assert str(t1
.sources
[1]) == 'asrc7', list(map(str, t1
.sources
))
2824 assert len(t2
.sources
) == 2, list(map(str, t2
.sources
))
2825 assert str(t2
.sources
[0]) == 'asrc6', list(map(str, t2
.sources
))
2826 assert str(t2
.sources
[1]) == 'asrc7', list(map(str, t2
.sources
))
2828 tgt
= env
.Alias('add', 's1')
2829 tgt
= env
.Alias('add', 's2')[0]
2830 s
= list(map(str, tgt
.sources
))
2831 assert s
== ['s1', 's2'], s
2832 tgt
= env
.Alias(tgt
, 's3')[0]
2833 s
= list(map(str, tgt
.sources
))
2834 assert s
== ['s1', 's2', 's3'], s
2836 tgt
= env
.Alias('act', None, "action1")[0]
2837 s
= str(tgt
.builder
.action
)
2838 assert s
== "action1", s
2839 tgt
= env
.Alias('act', None, "action2")[0]
2840 s
= str(tgt
.builder
.action
)
2841 assert s
== "action1\naction2", s
2842 tgt
= env
.Alias(tgt
, None, "action3")[0]
2843 s
= str(tgt
.builder
.action
)
2844 assert s
== "action1\naction2\naction3", s
2846 def test_AlwaysBuild(self
) -> None:
2847 """Test the AlwaysBuild() method"""
2848 env
= self
.TestEnvironment(FOO
='fff', BAR
='bbb')
2849 t
= env
.AlwaysBuild('a', 'b$FOO', ['c', 'd'], '$BAR',
2850 env
.fs
.Dir('dir'), env
.fs
.File('file'))
2851 assert t
[0].__class
__.__name
__ == 'Entry'
2852 assert t
[0].get_internal_path() == 'a'
2853 assert t
[0].always_build
2854 assert t
[1].__class
__.__name
__ == 'Entry'
2855 assert t
[1].get_internal_path() == 'bfff'
2856 assert t
[1].always_build
2857 assert t
[2].__class
__.__name
__ == 'Entry'
2858 assert t
[2].get_internal_path() == 'c'
2859 assert t
[2].always_build
2860 assert t
[3].__class
__.__name
__ == 'Entry'
2861 assert t
[3].get_internal_path() == 'd'
2862 assert t
[3].always_build
2863 assert t
[4].__class
__.__name
__ == 'Entry'
2864 assert t
[4].get_internal_path() == 'bbb'
2865 assert t
[4].always_build
2866 assert t
[5].__class
__.__name
__ == 'Dir'
2867 assert t
[5].get_internal_path() == 'dir'
2868 assert t
[5].always_build
2869 assert t
[6].__class
__.__name
__ == 'File'
2870 assert t
[6].get_internal_path() == 'file'
2871 assert t
[6].always_build
2873 def test_VariantDir(self
) -> None:
2874 """Test the VariantDir() method"""
2876 def Dir(self
, name
):
2878 def VariantDir(self
, variant_dir
, src_dir
, duplicate
) -> None:
2879 self
.variant_dir
= variant_dir
2880 self
.src_dir
= src_dir
2881 self
.duplicate
= duplicate
2883 env
= self
.TestEnvironment(FOO
= 'fff', BAR
= 'bbb')
2886 env
.VariantDir('build', 'src')
2887 assert env
.fs
.variant_dir
== 'build', env
.fs
.variant_dir
2888 assert env
.fs
.src_dir
== 'src', env
.fs
.src_dir
2889 assert env
.fs
.duplicate
== 1, env
.fs
.duplicate
2891 env
.VariantDir('build${FOO}', '${BAR}src', 0)
2892 assert env
.fs
.variant_dir
== 'buildfff', env
.fs
.variant_dir
2893 assert env
.fs
.src_dir
== 'bbbsrc', env
.fs
.src_dir
2894 assert env
.fs
.duplicate
== 0, env
.fs
.duplicate
2896 def test_Builder(self
) -> None:
2897 """Test the Builder() method"""
2898 env
= self
.TestEnvironment(FOO
= 'xyzzy')
2900 b
= env
.Builder(action
= 'foo')
2901 assert b
is not None, b
2903 b
= env
.Builder(action
= '$FOO')
2904 assert b
is not None, b
2906 b
= env
.Builder(action
= ['$FOO', 'foo'])
2907 assert b
is not None, b
2909 def func(arg
) -> None:
2911 b
= env
.Builder(action
= func
)
2912 assert b
is not None, b
2913 b
= env
.Builder(generator
= func
)
2914 assert b
is not None, b
2916 def test_CacheDir(self
) -> None:
2917 """Test the CacheDir() method"""
2919 test
= TestCmd
.TestCmd(workdir
= '')
2921 test_cachedir
= os
.path
.join(test
.workpath(),'CacheDir')
2922 test_cachedir_config
= os
.path
.join(test_cachedir
, 'config')
2923 test_foo
= os
.path
.join(test
.workpath(), 'foo-cachedir')
2924 test_foo_config
= os
.path
.join(test_foo
,'config')
2925 test_foo1
= os
.path
.join(test
.workpath(), 'foo1-cachedir')
2926 test_foo1_config
= os
.path
.join(test_foo1
, 'config')
2928 env
= self
.TestEnvironment(CD
= test_cachedir
)
2930 env
.CacheDir(test_foo
)
2931 assert env
._CacheDir
_path
== test_foo
, env
._CacheDir
_path
2932 assert os
.path
.isfile(test_foo_config
), "No file %s"%test_foo_config
2935 assert env
._CacheDir
_path
== test_cachedir
, env
._CacheDir
_path
2936 assert os
.path
.isfile(test_cachedir_config
), "No file %s"%test_cachedir_config
2938 # Now verify that -n/-no_exec wil prevent the CacheDir/config from being created
2940 SCons
.Action
.execute_actions
= False
2941 env
.CacheDir(test_foo1
)
2942 assert env
._CacheDir
_path
== test_foo1
, env
._CacheDir
_path
2943 assert not os
.path
.isfile(test_foo1_config
), "No file %s"%test_foo1_config
2946 def test_Clean(self
) -> None:
2947 """Test the Clean() method"""
2948 env
= self
.TestEnvironment(FOO
= 'fff', BAR
= 'bbb')
2950 CT
= SCons
.Environment
.CleanTargets
2952 foo
= env
.arg2nodes('foo')[0]
2953 fff
= env
.arg2nodes('fff')[0]
2955 t
= env
.Clean('foo', 'aaa')
2956 l
= list(map(str, CT
[foo
]))
2957 assert l
== ['aaa'], l
2959 t
= env
.Clean(foo
, ['$BAR', 'ccc'])
2960 l
= list(map(str, CT
[foo
]))
2961 assert l
== ['aaa', 'bbb', 'ccc'], l
2963 eee
= env
.arg2nodes('eee')[0]
2965 t
= env
.Clean('$FOO', 'ddd')
2966 l
= list(map(str, CT
[fff
]))
2967 assert l
== ['ddd'], l
2968 t
= env
.Clean(fff
, [eee
, 'fff'])
2969 l
= list(map(str, CT
[fff
]))
2970 assert l
== ['ddd', 'eee', 'fff'], l
2972 def test_Command(self
) -> None:
2973 """Test the Command() method."""
2975 t
= env
.Command(target
='foo.out', source
=['foo1.in', 'foo2.in'],
2976 action
='buildfoo $target $source')[0]
2977 assert t
.builder
is not None
2978 assert t
.builder
.action
.__class
__.__name
__ == 'CommandAction'
2979 assert t
.builder
.action
.cmd_list
== 'buildfoo $target $source'
2980 assert 'foo1.in' in [x
.get_internal_path() for x
in t
.sources
]
2981 assert 'foo2.in' in [x
.get_internal_path() for x
in t
.sources
]
2983 sub
= env
.fs
.Dir('sub')
2984 t
= env
.Command(target
='bar.out', source
='sub',
2985 action
='buildbar $target $source')[0]
2986 assert 'sub' in [x
.get_internal_path() for x
in t
.sources
]
2988 def testFunc(env
, target
, source
) -> int:
2989 assert str(target
[0]) == 'foo.out'
2990 srcs
= list(map(str, source
))
2991 assert 'foo1.in' in srcs
and 'foo2.in' in srcs
, srcs
2994 # avoid spurious output from action
2995 act
= env
.Action(testFunc
, cmdstr
=None)
2996 t
= env
.Command(target
='foo.out', source
=['foo1.in','foo2.in'],
2998 assert t
.builder
is not None
2999 assert t
.builder
.action
.__class
__.__name
__ == 'FunctionAction'
3001 assert 'foo1.in' in [x
.get_internal_path() for x
in t
.sources
]
3002 assert 'foo2.in' in [x
.get_internal_path() for x
in t
.sources
]
3005 def test2(baz
, x
=x
) -> None:
3007 env
= self
.TestEnvironment(TEST2
= test2
)
3008 t
= env
.Command(target
='baz.out', source
='baz.in',
3009 action
='${TEST2(XYZ)}',
3010 XYZ
='magic word')[0]
3011 assert t
.builder
is not None
3013 assert x
[0] == 'magic word', x
3015 t
= env
.Command(target
='${X}.out', source
='${X}.in',
3018 assert str(t
) == 'xxx.out', str(t
)
3019 assert 'xxx.in' in [x
.get_internal_path() for x
in t
.sources
]
3021 env
= self
.TestEnvironment(source_scanner
= 'should_not_find_this')
3022 t
= env
.Command(target
='file.out', source
='file.in',
3024 source_scanner
= 'fake')[0]
3025 assert t
.builder
.source_scanner
== 'fake', t
.builder
.source_scanner
3027 def test_Configure(self
) -> None:
3028 """Test the Configure() method"""
3029 # Configure() will write to a local temporary file.
3030 test
= TestCmd
.TestCmd(workdir
= '')
3034 os
.chdir(test
.workpath())
3036 env
= self
.TestEnvironment(FOO
= 'xyzzy')
3038 def func(arg
) -> None:
3042 assert c
is not None, c
3045 c
= env
.Configure(custom_tests
= {'foo' : func
, '$FOO' : func
})
3046 assert c
is not None, c
3047 assert hasattr(c
, 'foo')
3048 assert hasattr(c
, 'xyzzy')
3053 def test_Depends(self
) -> None:
3054 """Test the explicit Depends method."""
3055 env
= self
.TestEnvironment(FOO
= 'xxx', BAR
='yyy')
3060 t
= env
.Depends(target
='EnvironmentTest.py',
3061 dependency
='Environment.py')[0]
3062 assert t
.__class
__.__name
__ == 'Entry', t
.__class
__.__name
__
3063 assert t
.get_internal_path() == 'EnvironmentTest.py'
3064 assert len(t
.depends
) == 1
3066 assert d
.__class
__.__name
__ == 'Entry', d
.__class
__.__name
__
3067 assert d
.get_internal_path() == 'Environment.py'
3069 t
= env
.Depends(target
='${FOO}.py', dependency
='${BAR}.py')[0]
3070 assert t
.__class
__.__name
__ == 'File', t
.__class
__.__name
__
3071 assert t
.get_internal_path() == 'xxx.py'
3072 assert len(t
.depends
) == 1
3074 assert d
.__class
__.__name
__ == 'File', d
.__class
__.__name
__
3075 assert d
.get_internal_path() == 'yyy.py'
3077 t
= env
.Depends(target
='dir1', dependency
='dir2')[0]
3078 assert t
.__class
__.__name
__ == 'Dir', t
.__class
__.__name
__
3079 assert t
.get_internal_path() == 'dir1'
3080 assert len(t
.depends
) == 1
3082 assert d
.__class
__.__name
__ == 'Dir', d
.__class
__.__name
__
3083 assert d
.get_internal_path() == 'dir2'
3085 def test_Dir(self
) -> None:
3086 """Test the Dir() method"""
3088 def Dir(self
, name
) -> str:
3089 return 'Dir(%s)' % name
3091 env
= self
.TestEnvironment(FOO
= 'foodir', BAR
= 'bardir')
3095 assert d
== 'Dir(d)', d
3098 assert d
== 'Dir(foodir)', d
3100 d
= env
.Dir('${BAR}_$BAR')
3101 assert d
== 'Dir(bardir_bardir)', d
3103 d
= env
.Dir(['dir1'])
3104 assert d
== ['Dir(dir1)'], d
3106 d
= env
.Dir(['dir1', 'dir2'])
3107 assert d
== ['Dir(dir1)', 'Dir(dir2)'], d
3109 def test_NoClean(self
) -> None:
3110 """Test the NoClean() method"""
3111 env
= self
.TestEnvironment(FOO
='ggg', BAR
='hhh')
3114 t
= env
.NoClean('p_a', 'p_${BAR}b', ['p_c', 'p_d'], 'p_$FOO')
3116 assert t
[0].__class
__.__name
__ == 'Entry', t
[0].__class
__.__name
__
3117 assert t
[0].get_internal_path() == 'p_a'
3119 assert t
[1].__class
__.__name
__ == 'Dir', t
[1].__class
__.__name
__
3120 assert t
[1].get_internal_path() == 'p_hhhb'
3122 assert t
[2].__class
__.__name
__ == 'Entry', t
[2].__class
__.__name
__
3123 assert t
[2].get_internal_path() == 'p_c'
3125 assert t
[3].__class
__.__name
__ == 'File', t
[3].__class
__.__name
__
3126 assert t
[3].get_internal_path() == 'p_d'
3128 assert t
[4].__class
__.__name
__ == 'Entry', t
[4].__class
__.__name
__
3129 assert t
[4].get_internal_path() == 'p_ggg'
3132 def test_Dump(self
) -> None:
3133 """Test the Dump() method"""
3135 env
= self
.TestEnvironment(FOO
= 'foo')
3136 assert env
.Dump('FOO') == "'foo'", env
.Dump('FOO')
3137 assert len(env
.Dump()) > 200, env
.Dump() # no args version
3139 assert env
.Dump('FOO', 'json') == '"foo"' # JSON key version
3141 env_dict
= json
.loads(env
.Dump(format
= 'json'))
3142 assert env_dict
['FOO'] == 'foo' # full JSON version
3145 env
.Dump(format
= 'markdown')
3146 except ValueError as e
:
3147 assert str(e
) == "Unsupported serialization format: markdown."
3149 self
.fail("Did not catch expected ValueError.")
3151 def test_Environment(self
) -> None:
3152 """Test the Environment() method"""
3153 env
= self
.TestEnvironment(FOO
= 'xxx', BAR
= 'yyy')
3155 e2
= env
.Environment(X
= '$FOO', Y
= '$BAR')
3156 assert e2
['X'] == 'xxx', e2
['X']
3157 assert e2
['Y'] == 'yyy', e2
['Y']
3159 def test_Execute(self
) -> None:
3160 """Test the Execute() method"""
3163 def __init__(self
, *args
, **kw
) -> None:
3165 def __call__(self
, target
, source
, env
) -> str:
3166 return "%s executed" % self
.args
3169 env
.Action
= MyAction
3171 result
= env
.Execute("foo")
3172 assert result
== "foo executed", result
3174 def test_Entry(self
) -> None:
3175 """Test the Entry() method"""
3177 def Entry(self
, name
) -> str:
3178 return 'Entry(%s)' % name
3180 env
= self
.TestEnvironment(FOO
= 'fooentry', BAR
= 'barentry')
3184 assert e
== 'Entry(e)', e
3186 e
= env
.Entry('$FOO')
3187 assert e
== 'Entry(fooentry)', e
3189 e
= env
.Entry('${BAR}_$BAR')
3190 assert e
== 'Entry(barentry_barentry)', e
3192 e
= env
.Entry(['entry1'])
3193 assert e
== ['Entry(entry1)'], e
3195 e
= env
.Entry(['entry1', 'entry2'])
3196 assert e
== ['Entry(entry1)', 'Entry(entry2)'], e
3198 def test_File(self
) -> None:
3199 """Test the File() method"""
3201 def File(self
, name
) -> str:
3202 return 'File(%s)' % name
3204 env
= self
.TestEnvironment(FOO
= 'foofile', BAR
= 'barfile')
3208 assert f
== 'File(f)', f
3210 f
= env
.File('$FOO')
3211 assert f
== 'File(foofile)', f
3213 f
= env
.File('${BAR}_$BAR')
3214 assert f
== 'File(barfile_barfile)', f
3216 f
= env
.File(['file1'])
3217 assert f
== ['File(file1)'], f
3219 f
= env
.File(['file1', 'file2'])
3220 assert f
== ['File(file1)', 'File(file2)'], f
3222 def test_FindFile(self
) -> None:
3223 """Test the FindFile() method"""
3224 env
= self
.TestEnvironment(FOO
= 'fff', BAR
= 'bbb')
3226 r
= env
.FindFile('foo', ['no_such_directory'])
3231 def test_Flatten(self
) -> None:
3232 """Test the Flatten() method"""
3234 l
= env
.Flatten([1])
3236 l
= env
.Flatten([1, [2, [3, [4]]]])
3237 assert l
== [1, 2, 3, 4], l
3239 def test_GetBuildPath(self
) -> None:
3240 """Test the GetBuildPath() method."""
3241 env
= self
.TestEnvironment(MAGIC
= 'xyzzy')
3243 p
= env
.GetBuildPath('foo')
3244 assert p
== 'foo', p
3246 p
= env
.GetBuildPath('$MAGIC')
3247 assert p
== 'xyzzy', p
3249 def test_Ignore(self
) -> None:
3250 """Test the explicit Ignore method."""
3251 env
= self
.TestEnvironment(FOO
='yyy', BAR
='zzz')
3257 t
= env
.Ignore(target
='targ.py', dependency
='dep.py')[0]
3258 assert t
.__class
__.__name
__ == 'Entry', t
.__class
__.__name
__
3259 assert t
.get_internal_path() == 'targ.py'
3260 assert len(t
.ignore
) == 1
3262 assert i
.__class
__.__name
__ == 'Entry', i
.__class
__.__name
__
3263 assert i
.get_internal_path() == 'dep.py'
3265 t
= env
.Ignore(target
='$FOO$BAR', dependency
='$BAR$FOO')[0]
3266 assert t
.__class
__.__name
__ == 'File', t
.__class
__.__name
__
3267 assert t
.get_internal_path() == 'yyyzzz'
3268 assert len(t
.ignore
) == 1
3270 assert i
.__class
__.__name
__ == 'File', i
.__class
__.__name
__
3271 assert i
.get_internal_path() == 'zzzyyy'
3273 t
= env
.Ignore(target
='dir1', dependency
='dir2')[0]
3274 assert t
.__class
__.__name
__ == 'Dir', t
.__class
__.__name
__
3275 assert t
.get_internal_path() == 'dir1'
3276 assert len(t
.ignore
) == 1
3278 assert i
.__class
__.__name
__ == 'Dir', i
.__class
__.__name
__
3279 assert i
.get_internal_path() == 'dir2'
3281 def test_Literal(self
) -> None:
3282 """Test the Literal() method"""
3283 env
= self
.TestEnvironment(FOO
='fff', BAR
='bbb')
3284 list = env
.subst_list([env
.Literal('$FOO'), '$BAR'])[0]
3285 assert list == ['$FOO', 'bbb'], list
3286 list = env
.subst_list(['$FOO', env
.Literal('$BAR')])[0]
3287 assert list == ['fff', '$BAR'], list
3289 def test_Local(self
) -> None:
3290 """Test the Local() method."""
3291 env
= self
.TestEnvironment(FOO
='lll')
3293 l
= env
.Local(env
.fs
.File('fff'))
3294 assert str(l
[0]) == 'fff', l
[0]
3296 l
= env
.Local('ggg', '$FOO')
3297 assert str(l
[0]) == 'ggg', l
[0]
3298 assert str(l
[1]) == 'lll', l
[1]
3300 def test_Precious(self
) -> None:
3301 """Test the Precious() method"""
3302 env
= self
.TestEnvironment(FOO
='ggg', BAR
='hhh')
3305 t
= env
.Precious('p_a', 'p_${BAR}b', ['p_c', 'p_d'], 'p_$FOO')
3307 assert t
[0].__class
__.__name
__ == 'Entry', t
[0].__class
__.__name
__
3308 assert t
[0].get_internal_path() == 'p_a'
3309 assert t
[0].precious
3310 assert t
[1].__class
__.__name
__ == 'Dir', t
[1].__class
__.__name
__
3311 assert t
[1].get_internal_path() == 'p_hhhb'
3312 assert t
[1].precious
3313 assert t
[2].__class
__.__name
__ == 'Entry', t
[2].__class
__.__name
__
3314 assert t
[2].get_internal_path() == 'p_c'
3315 assert t
[2].precious
3316 assert t
[3].__class
__.__name
__ == 'File', t
[3].__class
__.__name
__
3317 assert t
[3].get_internal_path() == 'p_d'
3318 assert t
[3].precious
3319 assert t
[4].__class
__.__name
__ == 'Entry', t
[4].__class
__.__name
__
3320 assert t
[4].get_internal_path() == 'p_ggg'
3321 assert t
[4].precious
3323 def test_Pseudo(self
) -> None:
3324 """Test the Pseudo() method"""
3325 env
= self
.TestEnvironment(FOO
='ggg', BAR
='hhh')
3328 t
= env
.Pseudo('p_a', 'p_${BAR}b', ['p_c', 'p_d'], 'p_$FOO')
3330 assert t
[0].__class
__.__name
__ == 'Entry', t
[0].__class
__.__name
__
3331 assert t
[0].get_internal_path() == 'p_a'
3333 assert t
[1].__class
__.__name
__ == 'Dir', t
[1].__class
__.__name
__
3334 assert t
[1].get_internal_path() == 'p_hhhb'
3336 assert t
[2].__class
__.__name
__ == 'Entry', t
[2].__class
__.__name
__
3337 assert t
[2].get_internal_path() == 'p_c'
3339 assert t
[3].__class
__.__name
__ == 'File', t
[3].__class
__.__name
__
3340 assert t
[3].get_internal_path() == 'p_d'
3342 assert t
[4].__class
__.__name
__ == 'Entry', t
[4].__class
__.__name
__
3343 assert t
[4].get_internal_path() == 'p_ggg'
3346 def test_Repository(self
) -> None:
3347 """Test the Repository() method."""
3349 def __init__(self
) -> None:
3351 def Repository(self
, *dirs
) -> None:
3352 self
.list.extend(list(dirs
))
3353 def Dir(self
, name
):
3355 env
= self
.TestEnvironment(FOO
='rrr', BAR
='sss')
3357 env
.Repository('/tmp/foo')
3358 env
.Repository('/tmp/$FOO', '/tmp/$BAR/foo')
3359 expect
= ['/tmp/foo', '/tmp/rrr', '/tmp/sss/foo']
3360 assert env
.fs
.list == expect
, env
.fs
.list
3362 def test_Scanner(self
) -> None:
3363 """Test the Scanner() method"""
3364 def scan(node
, env
, target
, arg
) -> None:
3367 env
= self
.TestEnvironment(FOO
= scan
)
3369 s
= env
.Scanner('foo')
3370 assert s
is not None, s
3372 s
= env
.Scanner(function
= 'foo')
3373 assert s
is not None, s
3376 s
= env
.Scanner('$FOO')
3377 assert s
is not None, s
3379 s
= env
.Scanner(function
= '$FOO')
3380 assert s
is not None, s
3382 def test_SConsignFile(self
) -> None:
3383 """Test the SConsignFile() method"""
3384 import SCons
.SConsign
3387 SConstruct_dir
= os
.sep
+ 'dir'
3389 env
= self
.TestEnvironment(FOO
= 'SConsign',
3390 BAR
= os
.path
.join(os
.sep
, 'File'))
3392 env
.Execute
= lambda action
: None
3397 def capture(name
, dbm_module
, fnames
=fnames
, dbms
=dbms
) -> None:
3399 dbms
.append(dbm_module
)
3401 save_SConsign_File
= SCons
.SConsign
.File
3402 SCons
.SConsign
.File
= capture
3404 env
.SConsignFile('foo')
3405 assert fnames
[-1] == os
.path
.join(os
.sep
, 'dir', 'foo'), fnames
3406 assert dbms
[-1] is None, dbms
3408 env
.SConsignFile('$FOO')
3409 assert fnames
[-1] == os
.path
.join(os
.sep
, 'dir', 'SConsign'), fnames
3410 assert dbms
[-1] is None, dbms
3412 env
.SConsignFile('/$FOO')
3413 assert fnames
[-1] == os
.sep
+ 'SConsign', fnames
3414 assert dbms
[-1] is None, dbms
3416 env
.SConsignFile(os
.sep
+ '$FOO')
3417 assert fnames
[-1] == os
.sep
+ 'SConsign', fnames
3418 assert dbms
[-1] is None, dbms
3420 env
.SConsignFile('$BAR', 'x')
3421 assert fnames
[-1] == os
.path
.join(os
.sep
, 'File'), fnames
3422 assert dbms
[-1] == 'x', dbms
3424 env
.SConsignFile('__$BAR', 7)
3425 assert fnames
[-1] == os
.path
.join(os
.sep
, 'dir', '__', 'File'), fnames
3426 assert dbms
[-1] == 7, dbms
3429 assert fnames
[-1] == os
.path
.join(os
.sep
, 'dir', current_sconsign_filename()), fnames
3430 assert dbms
[-1] is None, dbms
3432 env
.SConsignFile(None)
3433 assert fnames
[-1] is None, fnames
3434 assert dbms
[-1] is None, dbms
3436 SCons
.SConsign
.File
= save_SConsign_File
3438 def test_SideEffect(self
) -> None:
3439 """Test the SideEffect() method"""
3440 env
= self
.TestEnvironment(LIB
='lll', FOO
='fff', BAR
='bbb')
3441 env
.File('mylll.pdb')
3442 env
.Dir('mymmm.pdb')
3444 foo
= env
.Object('foo.obj', 'foo.cpp')[0]
3445 bar
= env
.Object('bar.obj', 'bar.cpp')[0]
3446 s
= env
.SideEffect('mylib.pdb', ['foo.obj', 'bar.obj'])
3447 assert len(s
) == 1, len(s
)
3449 assert s
.__class
__.__name
__ == 'Entry', s
.__class
__.__name
__
3450 assert s
.get_internal_path() == 'mylib.pdb'
3451 assert s
.side_effect
3452 assert foo
.side_effects
== [s
]
3453 assert bar
.side_effects
== [s
]
3455 fff
= env
.Object('fff.obj', 'fff.cpp')[0]
3456 bbb
= env
.Object('bbb.obj', 'bbb.cpp')[0]
3457 s
= env
.SideEffect('my${LIB}.pdb', ['${FOO}.obj', '${BAR}.obj'])
3458 assert len(s
) == 1, len(s
)
3460 assert s
.__class
__.__name
__ == 'File', s
.__class
__.__name
__
3461 assert s
.get_internal_path() == 'mylll.pdb'
3462 assert s
.side_effect
3463 assert fff
.side_effects
== [s
], fff
.side_effects
3464 assert bbb
.side_effects
== [s
], bbb
.side_effects
3466 ggg
= env
.Object('ggg.obj', 'ggg.cpp')[0]
3467 ccc
= env
.Object('ccc.obj', 'ccc.cpp')[0]
3468 s
= env
.SideEffect('mymmm.pdb', ['ggg.obj', 'ccc.obj'])
3469 assert len(s
) == 1, len(s
)
3471 assert s
.__class
__.__name
__ == 'Dir', s
.__class
__.__name
__
3472 assert s
.get_internal_path() == 'mymmm.pdb'
3473 assert s
.side_effect
3474 assert ggg
.side_effects
== [s
], ggg
.side_effects
3475 assert ccc
.side_effects
== [s
], ccc
.side_effects
3477 # Verify that duplicate side effects are not allowed.
3478 before
= len(ggg
.side_effects
)
3479 s
= env
.SideEffect('mymmm.pdb', ggg
)
3480 assert len(s
) == 0, len(s
)
3481 assert len(ggg
.side_effects
) == before
, len(ggg
.side_effects
)
3483 def test_Split(self
) -> None:
3484 """Test the Split() method"""
3485 env
= self
.TestEnvironment(FOO
= 'fff', BAR
= 'bbb')
3486 s
= env
.Split("foo bar")
3487 assert s
== ["foo", "bar"], s
3488 s
= env
.Split("$FOO bar")
3489 assert s
== ["fff", "bar"], s
3490 s
= env
.Split(["foo", "bar"])
3491 assert s
== ["foo", "bar"], s
3492 s
= env
.Split(["foo", "${BAR}-bbb"])
3493 assert s
== ["foo", "bbb-bbb"], s
3494 s
= env
.Split("foo")
3495 assert s
== ["foo"], s
3496 s
= env
.Split("$FOO$BAR")
3497 assert s
== ["fffbbb"], s
3500 def test_Value(self
) -> None:
3501 """Test creating a Value() object
3505 assert v1
.value
== 'a', v1
.value
3508 v2
= env
.Value(value2
)
3509 assert v2
.value
== value2
, v2
.value
3510 assert v2
.value
is value2
, v2
.value
3514 v3
= env
.Value('c', 'build-c')
3515 assert v3
.value
== 'c', v3
.value
3517 v4
= env
.Value(b
'\x00\x0F', name
='name')
3518 assert v4
.value
== b
'\x00\x0F', v4
.value
3519 assert v4
.name
== 'name', v4
.name
3522 def test_Environment_global_variable(self
) -> None:
3523 """Test setting Environment variable to an Environment.Base subclass"""
3524 class MyEnv(SCons
.Environment
.Base
):
3525 def xxx(self
, string
):
3526 return self
.subst(string
)
3528 SCons
.Environment
.Environment
= MyEnv
3530 env
= SCons
.Environment
.Environment(FOO
= 'foo')
3532 f
= env
.subst('$FOO')
3533 assert f
== 'foo', f
3536 assert f
== 'foo', f
3538 def test_bad_keywords(self
) -> None:
3539 """Test trying to use reserved keywords in an Environment"""
3542 env
= self
.TestEnvironment(TARGETS
= 'targets',
3543 SOURCES
= 'sources',
3546 CHANGED_SOURCES
= 'changed_sources',
3547 CHANGED_TARGETS
= 'changed_targets',
3548 UNCHANGED_SOURCES
= 'unchanged_sources',
3549 UNCHANGED_TARGETS
= 'unchanged_targets',
3551 bad_msg
= '%s is not reserved, but got omitted; see Environment.construction_var_name_ok'
3552 added
.append('INIT')
3553 for x
in self
.reserved_variables
:
3554 assert x
not in env
, env
[x
]
3556 assert x
in env
, bad_msg
% x
3558 env
.Append(TARGETS
= 'targets',
3559 SOURCES
= 'sources',
3562 CHANGED_SOURCES
= 'changed_sources',
3563 CHANGED_TARGETS
= 'changed_targets',
3564 UNCHANGED_SOURCES
= 'unchanged_sources',
3565 UNCHANGED_TARGETS
= 'unchanged_targets',
3567 added
.append('APPEND')
3568 for x
in self
.reserved_variables
:
3569 assert x
not in env
, env
[x
]
3571 assert x
in env
, bad_msg
% x
3573 env
.AppendUnique(TARGETS
= 'targets',
3574 SOURCES
= 'sources',
3577 CHANGED_SOURCES
= 'changed_sources',
3578 CHANGED_TARGETS
= 'changed_targets',
3579 UNCHANGED_SOURCES
= 'unchanged_sources',
3580 UNCHANGED_TARGETS
= 'unchanged_targets',
3581 APPENDUNIQUE
= 'appendunique')
3582 added
.append('APPENDUNIQUE')
3583 for x
in self
.reserved_variables
:
3584 assert x
not in env
, env
[x
]
3586 assert x
in env
, bad_msg
% x
3588 env
.Prepend(TARGETS
= 'targets',
3589 SOURCES
= 'sources',
3592 CHANGED_SOURCES
= 'changed_sources',
3593 CHANGED_TARGETS
= 'changed_targets',
3594 UNCHANGED_SOURCES
= 'unchanged_sources',
3595 UNCHANGED_TARGETS
= 'unchanged_targets',
3596 PREPEND
= 'prepend')
3597 added
.append('PREPEND')
3598 for x
in self
.reserved_variables
:
3599 assert x
not in env
, env
[x
]
3601 assert x
in env
, bad_msg
% x
3603 env
.Prepend(TARGETS
= 'targets',
3604 SOURCES
= 'sources',
3607 CHANGED_SOURCES
= 'changed_sources',
3608 CHANGED_TARGETS
= 'changed_targets',
3609 UNCHANGED_SOURCES
= 'unchanged_sources',
3610 UNCHANGED_TARGETS
= 'unchanged_targets',
3611 PREPENDUNIQUE
= 'prependunique')
3612 added
.append('PREPENDUNIQUE')
3613 for x
in self
.reserved_variables
:
3614 assert x
not in env
, env
[x
]
3616 assert x
in env
, bad_msg
% x
3618 env
.Replace(TARGETS
= 'targets',
3619 SOURCES
= 'sources',
3622 CHANGED_SOURCES
= 'changed_sources',
3623 CHANGED_TARGETS
= 'changed_targets',
3624 UNCHANGED_SOURCES
= 'unchanged_sources',
3625 UNCHANGED_TARGETS
= 'unchanged_targets',
3626 REPLACE
= 'replace')
3627 added
.append('REPLACE')
3628 for x
in self
.reserved_variables
:
3629 assert x
not in env
, env
[x
]
3631 assert x
in env
, bad_msg
% x
3633 copy
= env
.Clone(TARGETS
= 'targets',
3634 SOURCES
= 'sources',
3637 CHANGED_SOURCES
= 'changed_sources',
3638 CHANGED_TARGETS
= 'changed_targets',
3639 UNCHANGED_SOURCES
= 'unchanged_sources',
3640 UNCHANGED_TARGETS
= 'unchanged_targets',
3642 for x
in self
.reserved_variables
:
3643 assert x
not in copy
, env
[x
]
3644 for x
in added
+ ['COPY']:
3645 assert x
in copy
, bad_msg
% x
3647 over
= env
.Override({'TARGETS' : 'targets',
3648 'SOURCES' : 'sources',
3649 'SOURCE' : 'source',
3650 'TARGET' : 'target',
3651 'CHANGED_SOURCES' : 'changed_sources',
3652 'CHANGED_TARGETS' : 'changed_targets',
3653 'UNCHANGED_SOURCES' : 'unchanged_sources',
3654 'UNCHANGED_TARGETS' : 'unchanged_targets',
3655 'OVERRIDE' : 'override'})
3656 for x
in self
.reserved_variables
:
3657 assert x
not in over
, over
[x
]
3658 for x
in added
+ ['OVERRIDE']:
3659 assert x
in over
, bad_msg
% x
3661 def test_parse_flags(self
) -> None:
3662 """Test the Base class parse_flags argument"""
3663 # all we have to show is that it gets to MergeFlags internally
3664 env
= Environment(tools
=[], parse_flags
= '-X')
3665 assert env
['CCFLAGS'] == ['-X'], env
['CCFLAGS']
3667 env
= Environment(tools
=[], CCFLAGS
=None, parse_flags
= '-Y')
3668 assert env
['CCFLAGS'] == ['-Y'], env
['CCFLAGS']
3670 env
= Environment(tools
=[], CPPDEFINES
='FOO', parse_flags
='-std=c99 -X -DBAR')
3671 assert env
['CFLAGS'] == ['-std=c99'], env
['CFLAGS']
3672 assert env
['CCFLAGS'] == ['-X'], env
['CCFLAGS']
3673 self
.assertEqual(list(env
['CPPDEFINES']), ['FOO', 'BAR'])
3675 def test_clone_parse_flags(self
) -> None:
3676 """Test the env.Clone() parse_flags argument"""
3677 # all we have to show is that it gets to MergeFlags internally
3678 env
= Environment(tools
= [])
3679 env2
= env
.Clone(parse_flags
= '-X')
3680 assert 'CCFLAGS' not in env
3681 assert env2
['CCFLAGS'] == ['-X'], env2
['CCFLAGS']
3683 env
= Environment(tools
= [], CCFLAGS
=None)
3684 env2
= env
.Clone(parse_flags
= '-Y')
3685 assert env
['CCFLAGS'] is None, env
['CCFLAGS']
3686 assert env2
['CCFLAGS'] == ['-Y'], env2
['CCFLAGS']
3688 env
= Environment(tools
= [], CPPDEFINES
= 'FOO')
3689 env2
= env
.Clone(parse_flags
= '-std=c99 -X -DBAR')
3690 assert 'CFLAGS' not in env
3691 assert env2
['CFLAGS'] == ['-std=c99'], env2
['CFLAGS']
3692 assert 'CCFLAGS' not in env
3693 assert env2
['CCFLAGS'] == ['-X'], env2
['CCFLAGS']
3694 assert env
['CPPDEFINES'] == 'FOO', env
['CPPDEFINES']
3695 self
.assertEqual(list(env2
['CPPDEFINES']), ['FOO','BAR'])
3698 class OverrideEnvironmentTestCase(unittest
.TestCase
,TestEnvironmentFixture
):
3700 def setUp(self
) -> None:
3702 env
._dict
= {'XXX' : 'x', 'YYY' : 'y'}
3703 def verify_value(env
, key
, value
, *args
, **kwargs
) -> None:
3704 """Verifies that key is value on the env this is called with."""
3705 assert env
[key
] == value
3706 env
.AddMethod(verify_value
)
3707 env2
= OverrideEnvironment(env
, {'XXX' : 'x2'})
3708 env3
= OverrideEnvironment(env2
, {'XXX' : 'x3', 'YYY' : 'y3', 'ZZZ' : 'z3'})
3709 self
.envs
= [ env
, env2
, env3
]
3711 def checkpath(self
, node
, expect
):
3712 return str(node
) == os
.path
.normpath(expect
)
3714 def test___init__(self
) -> None:
3715 """Test OverrideEnvironment initialization"""
3716 env
, env2
, env3
= self
.envs
3717 assert env
['XXX'] == 'x', env
['XXX']
3718 assert env2
['XXX'] == 'x2', env2
['XXX']
3719 assert env3
['XXX'] == 'x3', env3
['XXX']
3720 assert env
['YYY'] == 'y', env
['YYY']
3721 assert env2
['YYY'] == 'y', env2
['YYY']
3722 assert env3
['YYY'] == 'y3', env3
['YYY']
3724 def test___delitem__(self
) -> None:
3725 """Test deleting variables from an OverrideEnvironment"""
3726 env
, env2
, env3
= self
.envs
3729 assert 'XXX' not in env
, "env has XXX?"
3730 assert 'XXX' not in env2
, "env2 has XXX?"
3731 assert 'XXX' not in env3
, "env3 has XXX?"
3734 assert 'YYY' not in env
, "env has YYY?"
3735 assert 'YYY' not in env2
, "env2 has YYY?"
3736 assert 'YYY' not in env3
, "env3 has YYY?"
3739 assert 'ZZZ' not in env
, "env has ZZZ?"
3740 assert 'ZZZ' not in env2
, "env2 has ZZZ?"
3741 assert 'ZZZ' not in env3
, "env3 has ZZZ?"
3743 def test_get(self
) -> None:
3744 """Test the OverrideEnvironment get() method"""
3745 env
, env2
, env3
= self
.envs
3746 assert env
.get('XXX') == 'x', env
.get('XXX')
3747 assert env2
.get('XXX') == 'x2', env2
.get('XXX')
3748 assert env3
.get('XXX') == 'x3', env3
.get('XXX')
3749 assert env
.get('YYY') == 'y', env
.get('YYY')
3750 assert env2
.get('YYY') == 'y', env2
.get('YYY')
3751 assert env3
.get('YYY') == 'y3', env3
.get('YYY')
3752 assert env
.get('ZZZ') is None, env
.get('ZZZ')
3753 assert env2
.get('ZZZ') is None, env2
.get('ZZZ')
3754 assert env3
.get('ZZZ') == 'z3', env3
.get('ZZZ')
3756 def test_contains(self
) -> None:
3757 """Test the OverrideEnvironment __contains__() method"""
3758 env
, env2
, env3
= self
.envs
3759 assert 'XXX' in env
, 'XXX' in env
3760 assert 'XXX' in env2
, 'XXX' in env2
3761 assert 'XXX' in env3
, 'XXX' in env3
3762 assert 'YYY' in env
, 'YYY' in env
3763 assert 'YYY' in env2
, 'YYY' in env2
3764 assert 'YYY' in env3
, 'YYY' in env3
3765 assert 'ZZZ' not in env
, 'ZZZ' in env
3766 assert 'ZZZ' not in env2
, 'ZZZ' in env2
3767 assert 'ZZZ' in env3
, 'ZZZ' in env3
3769 def test_Dictionary(self
) -> None:
3770 """Test the OverrideEnvironment Dictionary() method"""
3771 env
, env2
, env3
= self
.envs
3772 # nothing overrriden
3773 items
= env
.Dictionary()
3774 assert items
== {'XXX' : 'x', 'YYY' : 'y'}, items
3775 # env2 overrides XXX, YYY unchanged
3776 items
= env2
.Dictionary()
3777 assert items
== {'XXX' : 'x2', 'YYY' : 'y'}, items
3778 # env3 overrides XXX, YYY, adds ZZZ
3779 items
= env3
.Dictionary()
3780 assert items
== {'XXX' : 'x3', 'YYY' : 'y3', 'ZZZ' : 'z3'}, items
3781 # test one-arg and multi-arg Dictionary
3782 assert env3
.Dictionary('XXX') == 'x3', env3
.Dictionary('XXX')
3783 xxx
, yyy
= env2
.Dictionary('XXX', 'YYY')
3784 assert xxx
== 'x2', xxx
3785 assert yyy
== 'y', yyy
3787 assert 'XXX' not in env3
.Dictionary()
3788 assert 'XXX' not in env2
.Dictionary()
3789 assert 'XXX' not in env
.Dictionary()
3791 def test_items(self
) -> None:
3792 """Test the OverrideEnvironment items() method"""
3793 env
, env2
, env3
= self
.envs
3794 items
= sorted(env
.items())
3795 assert items
== [('XXX', 'x'), ('YYY', 'y')], items
3796 items
= sorted(env2
.items())
3797 assert items
== [('XXX', 'x2'), ('YYY', 'y')], items
3798 items
= sorted(env3
.items())
3799 assert items
== [('XXX', 'x3'), ('YYY', 'y3'), ('ZZZ', 'z3')], items
3801 def test_keys(self
) -> None:
3802 """Test the OverrideEnvironment keys() method"""
3803 env
, env2
, env3
= self
.envs
3804 keys
= sorted(env
.keys())
3805 assert keys
== ['XXX', 'YYY'], keys
3806 keys
= sorted(env2
.keys())
3807 assert keys
== ['XXX', 'YYY'], keys
3808 keys
= sorted(env3
.keys())
3809 assert keys
== ['XXX', 'YYY', 'ZZZ'], keys
3811 def test_values(self
) -> None:
3812 """Test the OverrideEnvironment values() method"""
3813 env
, env2
, env3
= self
.envs
3814 values
= sorted(env
.values())
3815 assert values
== ['x', 'y'], values
3816 values
= sorted(env2
.values())
3817 assert values
== ['x2', 'y'], values
3818 values
= sorted(env3
.values())
3819 assert values
== ['x3', 'y3', 'z3'], values
3821 def test_setdefault(self
) -> None:
3822 """Test the OverrideEnvironment setdefault() method."""
3823 env
, env2
, env3
= self
.envs
3824 # does not set for existing key
3825 assert env2
.setdefault('XXX', 'z') == 'x2', env2
['XXX']
3826 # set/return using default for non-existing key
3827 assert env2
.setdefault('ZZZ', 'z2') == 'z2', env2
['ZZZ']
3828 # set did not leak through to base env
3829 assert 'ZZZ' not in env
3831 def test_gvars(self
) -> None:
3832 """Test the OverrideEnvironment gvars() method"""
3833 env
, env2
, env3
= self
.envs
3835 assert gvars
== {'XXX' : 'x', 'YYY' : 'y'}, gvars
3836 gvars
= env2
.gvars()
3837 assert gvars
== {'XXX' : 'x', 'YYY' : 'y'}, gvars
3838 gvars
= env3
.gvars()
3839 assert gvars
== {'XXX' : 'x', 'YYY' : 'y'}, gvars
3841 def test_lvars(self
) -> None:
3842 """Test the OverrideEnvironment lvars() method"""
3843 env
, env2
, env3
= self
.envs
3845 assert lvars
== {}, lvars
3846 lvars
= env2
.lvars()
3847 assert lvars
== {'XXX' : 'x2'}, lvars
3848 lvars
= env3
.lvars()
3849 assert lvars
== {'XXX' : 'x3', 'YYY' : 'y3', 'ZZZ' : 'z3'}, lvars
3851 def test_Replace(self
) -> None:
3852 """Test the OverrideEnvironment Replace() method"""
3853 env
, env2
, env3
= self
.envs
3854 assert env
['XXX'] == 'x', env
['XXX']
3855 assert env2
['XXX'] == 'x2', env2
['XXX']
3856 assert env3
['XXX'] == 'x3', env3
['XXX']
3857 assert env
['YYY'] == 'y', env
['YYY']
3858 assert env2
['YYY'] == 'y', env2
['YYY']
3859 assert env3
['YYY'] == 'y3', env3
['YYY']
3861 env
.Replace(YYY
= 'y4')
3863 assert env
['XXX'] == 'x', env
['XXX']
3864 assert env2
['XXX'] == 'x2', env2
['XXX']
3865 assert env3
['XXX'] == 'x3', env3
['XXX']
3866 assert env
['YYY'] == 'y4', env
['YYY']
3867 assert env2
['YYY'] == 'y4', env2
['YYY']
3868 assert env3
['YYY'] == 'y3', env3
['YYY']
3870 # Tests a number of Base methods through an OverrideEnvironment to
3871 # make sure they handle overridden constructionv variables properly.
3873 # The following Base methods also call self.subst(), and so could
3874 # theoretically be subject to problems with evaluating overridden
3875 # variables, but they're never really called that way in the rest
3876 # of our code, so we won't worry about them (at least for now):
3892 # It's unlikely Clone() will ever be called this way, so let the
3893 # other methods test that handling overridden values works.
3894 #def test_Clone(self):
3895 # """Test the OverrideEnvironment Clone() method"""
3898 def test_FindIxes(self
) -> None:
3899 """Test the OverrideEnvironment FindIxes() method"""
3900 env
, env2
, env3
= self
.envs
3901 x
= env
.FindIxes(['xaaay'], 'XXX', 'YYY')
3902 assert x
== 'xaaay', x
3903 x
= env2
.FindIxes(['x2aaay'], 'XXX', 'YYY')
3904 assert x
== 'x2aaay', x
3905 x
= env3
.FindIxes(['x3aaay3'], 'XXX', 'YYY')
3906 assert x
== 'x3aaay3', x
3908 def test_ReplaceIxes(self
) -> None:
3909 """Test the OverrideEnvironment ReplaceIxes() method"""
3910 env
, env2
, env3
= self
.envs
3911 x
= env
.ReplaceIxes('xaaay', 'XXX', 'YYY', 'YYY', 'XXX')
3912 assert x
== 'yaaax', x
3913 x
= env2
.ReplaceIxes('x2aaay', 'XXX', 'YYY', 'YYY', 'XXX')
3914 assert x
== 'yaaax2', x
3915 x
= env3
.ReplaceIxes('x3aaay3', 'XXX', 'YYY', 'YYY', 'XXX')
3916 assert x
== 'y3aaax3', x
3918 # It's unlikely WhereIs() will ever be called this way, so let the
3919 # other methods test that handling overridden values works.
3920 #def test_WhereIs(self):
3921 # """Test the OverrideEnvironment WhereIs() method"""
3924 def test_PseudoBuilderInherits(self
) -> None:
3925 """Test that pseudo-builders inherit the overrided values."""
3926 env
, env2
, env3
= self
.envs
3927 env
.verify_value('XXX', 'x')
3928 env2
.verify_value('XXX', 'x2')
3929 env3
.verify_value('XXX', 'x3')
3931 def test_Dir(self
) -> None:
3932 """Test the OverrideEnvironment Dir() method"""
3933 env
, env2
, env3
= self
.envs
3934 x
= env
.Dir('ddir/$XXX')
3935 assert self
.checkpath(x
, 'ddir/x'), str(x
)
3936 x
= env2
.Dir('ddir/$XXX')
3937 assert self
.checkpath(x
, 'ddir/x2'), str(x
)
3938 x
= env3
.Dir('ddir/$XXX')
3939 assert self
.checkpath(x
, 'ddir/x3'), str(x
)
3941 def test_Entry(self
) -> None:
3942 """Test the OverrideEnvironment Entry() method"""
3943 env
, env2
, env3
= self
.envs
3944 x
= env
.Entry('edir/$XXX')
3945 assert self
.checkpath(x
, 'edir/x'), str(x
)
3946 x
= env2
.Entry('edir/$XXX')
3947 assert self
.checkpath(x
, 'edir/x2'), str(x
)
3948 x
= env3
.Entry('edir/$XXX')
3949 assert self
.checkpath(x
, 'edir/x3'), str(x
)
3951 def test_File(self
) -> None:
3952 """Test the OverrideEnvironment File() method"""
3953 env
, env2
, env3
= self
.envs
3954 x
= env
.File('fdir/$XXX')
3955 assert self
.checkpath(x
, 'fdir/x'), str(x
)
3956 x
= env2
.File('fdir/$XXX')
3957 assert self
.checkpath(x
, 'fdir/x2'), str(x
)
3958 x
= env3
.File('fdir/$XXX')
3959 assert self
.checkpath(x
, 'fdir/x3'), str(x
)
3961 def test_Split(self
) -> None:
3962 """Test the OverrideEnvironment Split() method"""
3963 env
, env2
, env3
= self
.envs
3964 env
['AAA'] = '$XXX $YYY $ZZZ'
3965 x
= env
.Split('$AAA')
3966 assert x
== ['x', 'y'], x
3967 x
= env2
.Split('$AAA')
3968 assert x
== ['x2', 'y'], x
3969 x
= env3
.Split('$AAA')
3970 assert x
== ['x3', 'y3', 'z3'], x
3972 def test_parse_flags(self
) -> None:
3973 """Test the OverrideEnvironment parse_flags argument"""
3974 # all we have to show is that it gets to MergeFlags internally
3975 env
= SubstitutionEnvironment()
3976 env2
= env
.Override({'parse_flags' : '-X'})
3977 assert 'CCFLAGS' not in env
3978 assert env2
['CCFLAGS'] == ['-X'], env2
['CCFLAGS']
3980 env
= SubstitutionEnvironment(CCFLAGS
=None)
3981 env2
= env
.Override({'parse_flags' : '-Y'})
3982 assert env
['CCFLAGS'] is None, env
['CCFLAGS']
3983 assert env2
['CCFLAGS'] == ['-Y'], env2
['CCFLAGS']
3985 env
= SubstitutionEnvironment(CPPDEFINES
='FOO')
3986 env2
= env
.Override({'parse_flags': '-std=c99 -X -DBAR'})
3987 assert 'CFLAGS' not in env
3988 assert env2
['CFLAGS'] == ['-std=c99'], env2
['CFLAGS']
3989 assert 'CCFLAGS' not in env
3990 assert env2
['CCFLAGS'] == ['-X'], env2
['CCFLAGS']
3991 # make sure they are independent
3992 self
.assertIsNot(env
['CPPDEFINES'], env2
['CPPDEFINES'])
3993 assert env
['CPPDEFINES'] == 'FOO', env
['CPPDEFINES']
3994 self
.assertEqual(list(env2
['CPPDEFINES']), ['FOO','BAR'])
3997 class NoSubstitutionProxyTestCase(unittest
.TestCase
,TestEnvironmentFixture
):
3999 def test___init__(self
) -> None:
4000 """Test NoSubstitutionProxy initialization"""
4001 env
= self
.TestEnvironment(XXX
= 'x', YYY
= 'y')
4002 assert env
['XXX'] == 'x', env
['XXX']
4003 assert env
['YYY'] == 'y', env
['YYY']
4005 proxy
= NoSubstitutionProxy(env
)
4006 assert proxy
['XXX'] == 'x', proxy
['XXX']
4007 assert proxy
['YYY'] == 'y', proxy
['YYY']
4009 def test_attributes(self
) -> None:
4010 """Test getting and setting NoSubstitutionProxy attributes"""
4012 setattr(env
, 'env_attr', 'value1')
4014 proxy
= NoSubstitutionProxy(env
)
4015 setattr(proxy
, 'proxy_attr', 'value2')
4017 x
= getattr(env
, 'env_attr')
4018 assert x
== 'value1', x
4019 x
= getattr(proxy
, 'env_attr')
4020 assert x
== 'value1', x
4022 x
= getattr(env
, 'proxy_attr')
4023 assert x
== 'value2', x
4024 x
= getattr(proxy
, 'proxy_attr')
4025 assert x
== 'value2', x
4027 def test_subst(self
) -> None:
4028 """Test the NoSubstitutionProxy.subst() method"""
4029 env
= self
.TestEnvironment(XXX
= 'x', YYY
= 'y')
4030 assert env
['XXX'] == 'x', env
['XXX']
4031 assert env
['YYY'] == 'y', env
['YYY']
4033 proxy
= NoSubstitutionProxy(env
)
4034 assert proxy
['XXX'] == 'x', proxy
['XXX']
4035 assert proxy
['YYY'] == 'y', proxy
['YYY']
4037 x
= env
.subst('$XXX')
4039 x
= proxy
.subst('$XXX')
4040 assert x
== '$XXX', x
4042 x
= proxy
.subst('$YYY', raw
=7, target
=None, source
=None,
4044 extra_meaningless_keyword_argument
=None)
4045 assert x
== '$YYY', x
4047 def test_subst_kw(self
) -> None:
4048 """Test the NoSubstitutionProxy.subst_kw() method"""
4049 env
= self
.TestEnvironment(XXX
= 'x', YYY
= 'y')
4050 assert env
['XXX'] == 'x', env
['XXX']
4051 assert env
['YYY'] == 'y', env
['YYY']
4053 proxy
= NoSubstitutionProxy(env
)
4054 assert proxy
['XXX'] == 'x', proxy
['XXX']
4055 assert proxy
['YYY'] == 'y', proxy
['YYY']
4057 x
= env
.subst_kw({'$XXX':'$YYY'})
4058 assert x
== {'x':'y'}, x
4059 x
= proxy
.subst_kw({'$XXX':'$YYY'})
4060 assert x
== {'$XXX':'$YYY'}, x
4062 def test_subst_list(self
) -> None:
4063 """Test the NoSubstitutionProxy.subst_list() method"""
4064 env
= self
.TestEnvironment(XXX
= 'x', YYY
= 'y')
4065 assert env
['XXX'] == 'x', env
['XXX']
4066 assert env
['YYY'] == 'y', env
['YYY']
4068 proxy
= NoSubstitutionProxy(env
)
4069 assert proxy
['XXX'] == 'x', proxy
['XXX']
4070 assert proxy
['YYY'] == 'y', proxy
['YYY']
4072 x
= env
.subst_list('$XXX')
4073 assert x
== [['x']], x
4074 x
= proxy
.subst_list('$XXX')
4077 x
= proxy
.subst_list('$YYY', raw
=0, target
=None, source
=None, conv
=None)
4080 def test_subst_target_source(self
) -> None:
4081 """Test the NoSubstitutionProxy.subst_target_source() method"""
4082 env
= self
.TestEnvironment(XXX
= 'x', YYY
= 'y')
4083 assert env
['XXX'] == 'x', env
['XXX']
4084 assert env
['YYY'] == 'y', env
['YYY']
4086 proxy
= NoSubstitutionProxy(env
)
4087 assert proxy
['XXX'] == 'x', proxy
['XXX']
4088 assert proxy
['YYY'] == 'y', proxy
['YYY']
4090 args
= ('$XXX $TARGET $SOURCE $YYY',)
4091 kw
= {'target' : DummyNode('ttt'), 'source' : DummyNode('sss')}
4092 x
= env
.subst_target_source(*args
, **kw
)
4093 assert x
== 'x ttt sss y', x
4094 x
= proxy
.subst_target_source(*args
, **kw
)
4095 assert x
== ' ttt sss ', x
4097 class EnvironmentVariableTestCase(unittest
.TestCase
):
4099 def test_is_valid_construction_var(self
) -> None:
4100 """Testing is_valid_construction_var()"""
4101 r
= is_valid_construction_var("_a")
4102 assert r
is not None, r
4103 r
= is_valid_construction_var("z_")
4104 assert r
is not None, r
4105 r
= is_valid_construction_var("X_")
4106 assert r
is not None, r
4107 r
= is_valid_construction_var("2a")
4109 r
= is_valid_construction_var("a2_")
4110 assert r
is not None, r
4111 r
= is_valid_construction_var("/")
4113 r
= is_valid_construction_var("_/")
4115 r
= is_valid_construction_var("a/")
4117 r
= is_valid_construction_var(".b")
4119 r
= is_valid_construction_var("_.b")
4121 r
= is_valid_construction_var("b1._")
4123 r
= is_valid_construction_var("-b")
4125 r
= is_valid_construction_var("_-b")
4127 r
= is_valid_construction_var("b1-_")
4132 if __name__
== "__main__":
4137 # indent-tabs-mode:nil
4139 # vim: set expandtab tabstop=4 shiftwidth=4: