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
) == f
'{cmd!r} exited 1', 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 # function is in Defaults.py, tested here to use TestEnvironment
1493 def test__concat(self
) -> None:
1494 """Test _concat()"""
1495 e1
= self
.TestEnvironment(PRE
='pre', SUF
='suf', STR
='a b', LIST
=['a', 'b'])
1497 x
= s("${_concat('', '', '', __env__)}")
1499 x
= s("${_concat('', [], '', __env__)}")
1501 x
= s("${_concat(PRE, '', SUF, __env__)}")
1503 x
= s("${_concat(PRE, STR, SUF, __env__)}")
1504 assert x
== 'prea bsuf', x
1505 x
= s("${_concat(PRE, LIST, SUF, __env__)}")
1506 assert x
== 'preasuf prebsuf', x
1507 x
= s("${_concat(PRE, LIST, SUF, __env__,affect_signature=False)}", raw
=True)
1508 assert x
== '$( preasuf prebsuf $)', x
1511 # function is in Defaults.py, tested here to use TestEnvironment
1512 def test__concat_nested(self
) -> None:
1513 """Test _concat() on a nested substitution strings."""
1514 e
= self
.TestEnvironment(PRE
='pre', SUF
='suf',
1518 x
= e
.subst('$( ${_concat(PRE, L1, SUF, __env__)} $)')
1519 assert x
== 'preasuf prebsuf', x
1520 e
.AppendUnique(L1
= ['$L2'])
1521 x
= e
.subst('$( ${_concat(PRE, L1, SUF, __env__)} $)')
1522 assert x
== 'preasuf prebsuf precsuf predsuf', x
1523 e
.AppendUnique(L1
= ['$L3'])
1524 x
= e
.subst('$( ${_concat(PRE, L1, SUF, __env__)} $)')
1525 assert x
== 'preasuf prebsuf precsuf predsuf precsuf predsuf', x
1528 # function is in Defaults.py, tested here to use TestEnvironment
1529 def test__stripixes(self
) -> None:
1530 """Test _stripixes()"""
1531 # LIBPREFIXES and LIBSUFFIXES are stripped,
1532 # except if an entry begins with LIBLITERAL
1533 e
= self
.TestEnvironment(
1536 LIST
=['xxx-a', 'b.yyy', 'zzxxx-c.yyy'],
1537 LIBPREFIXES
=['xxx-'],
1538 LIBSUFFIXES
=['.yyy'],
1541 x
= e
.subst('$( ${_stripixes(PRE, LIST, SUF, LIBPREFIXES, LIBSUFFIXES,__env__, LIBLITERAL)} $)')
1542 self
.assertEqual(x
, 'preasuf prebsuf prezzxxx-c.yyysuf')
1544 # Test that setting literal_prefix (in this case LIBLITERAL)
1545 # same as os.pathsep disables the literal protection
1546 e
['LIBLITERAL'] = os
.pathsep
1547 x
= e
.subst('$( ${_stripixes(PRE, LIST, SUF, LIBPREFIXES, LIBSUFFIXES,__env__, LIBLITERAL)} $)')
1548 self
.assertEqual(x
, 'preasuf prebsuf prezzxxx-csuf')
1550 # Test that setting not settingliteral_prefix doesn't fail
1551 x
= e
.subst('$( ${_stripixes(PRE, LIST, SUF, LIBPREFIXES, LIBSUFFIXES,__env__)} $)')
1552 self
.assertEqual(x
, 'preasuf prebsuf prezzxxx-csuf')
1556 def test_gvars(self
) -> None:
1557 """Test the Environment gvars() method"""
1558 env
= self
.TestEnvironment(XXX
= 'x', YYY
= 'y', ZZZ
= 'z')
1560 assert gvars
['XXX'] == 'x', gvars
['XXX']
1561 assert gvars
['YYY'] == 'y', gvars
['YYY']
1562 assert gvars
['ZZZ'] == 'z', gvars
['ZZZ']
1564 def test__update(self
) -> None:
1565 """Test the _update() method"""
1566 env
= self
.TestEnvironment(X
= 'x', Y
= 'y', Z
= 'z')
1567 assert env
['X'] == 'x', env
['X']
1568 assert env
['Y'] == 'y', env
['Y']
1569 assert env
['Z'] == 'z', env
['Z']
1570 env
._update
({'X' : 'xxx',
1576 assert env
['X'] == 'xxx', env
['X']
1577 assert env
['Y'] == 'y', env
['Y']
1578 assert env
['Z'] == 'zzz', env
['Z']
1579 assert env
['TARGET'] == 't', env
['TARGET']
1580 assert env
['TARGETS'] == 'ttt', env
['TARGETS']
1581 assert env
['SOURCE'] == 's', env
['SOURCE']
1582 assert env
['SOURCES'] == 'sss', env
['SOURCES']
1584 def test_Append(self
) -> None:
1585 """Test appending to construction variables in an Environment
1588 b1
= Environment()['BUILDERS']
1589 b2
= Environment()['BUILDERS']
1590 assert b1
== b2
, diff_dict(b1
, b2
)
1594 'a2', ['A2'], ['a2', 'A2'],
1595 'a3', UL(['A3']), UL(['a', '3', 'A3']),
1598 'a6', UL([]), UL(['a', '6']),
1599 'a7', [''], ['a7', ''],
1600 'a8', UL(['']), UL(['a', '8', '']),
1602 ['e1'], 'E1', ['e1', 'E1'],
1603 ['e2'], ['E2'], ['e2', 'E2'],
1604 ['e3'], UL(['E3']), UL(['e3', 'E3']),
1607 ['e6'], UL([]), UL(['e6']),
1608 ['e7'], [''], ['e7', ''],
1609 ['e8'], UL(['']), UL(['e8', '']),
1611 UL(['i1']), 'I1', UL(['i1', 'I', '1']),
1612 UL(['i2']), ['I2'], UL(['i2', 'I2']),
1613 UL(['i3']), UL(['I3']), UL(['i3', 'I3']),
1614 UL(['i4']), '', UL(['i4']),
1615 UL(['i5']), [], UL(['i5']),
1616 UL(['i6']), UL([]), UL(['i6']),
1617 UL(['i7']), [''], UL(['i7', '']),
1618 UL(['i8']), UL(['']), UL(['i8', '']),
1620 {'d1':1}, 'D1', {'d1':1, 'D1':None},
1621 {'d2':1}, ['D2'], {'d2':1, 'D2':None},
1622 {'d3':1}, UL(['D3']), {'d3':1, 'D3':None},
1623 {'d4':1}, {'D4':1}, {'d4':1, 'D4':1},
1624 {'d5':1}, UD({'D5':1}), UD({'d5':1, 'D5':1}),
1626 UD({'u1':1}), 'U1', UD({'u1':1, 'U1':None}),
1627 UD({'u2':1}), ['U2'], UD({'u2':1, 'U2':None}),
1628 UD({'u3':1}), UL(['U3']), UD({'u3':1, 'U3':None}),
1629 UD({'u4':1}), {'U4':1}, UD({'u4':1, 'U4':1}),
1630 UD({'u5':1}), UD({'U5':1}), UD({'u5':1, 'U5':1}),
1634 '', UL(['M3']), UL(['M3']),
1639 '', UL(['']), UL(['']),
1643 [], UL(['N3']), UL(['N3']),
1648 [], UL(['']), UL(['']),
1650 UL([]), 'O1', ['O', '1'],
1651 UL([]), ['O2'], ['O2'],
1652 UL([]), UL(['O3']), UL(['O3']),
1655 UL([]), UL([]), UL([]),
1656 UL([]), [''], UL(['']),
1657 UL([]), UL(['']), UL(['']),
1659 [''], 'P1', ['', 'P1'],
1660 [''], ['P2'], ['', 'P2'],
1661 [''], UL(['P3']), UL(['', 'P3']),
1664 [''], UL([]), UL(['']),
1665 [''], [''], ['', ''],
1666 [''], UL(['']), UL(['', '']),
1668 UL(['']), 'Q1', ['', 'Q', '1'],
1669 UL(['']), ['Q2'], ['', 'Q2'],
1670 UL(['']), UL(['Q3']), UL(['', 'Q3']),
1671 UL(['']), '', UL(['']),
1672 UL(['']), [], UL(['']),
1673 UL(['']), UL([]), UL(['']),
1674 UL(['']), [''], UL(['', '']),
1675 UL(['']), UL(['']), UL(['', '']),
1681 input, append
, expect
= cases
[:3]
1682 env
['XXX'] = copy
.copy(input)
1684 env
.Append(XXX
= append
)
1685 except Exception as e
:
1686 if failed
== 0: print()
1687 print(" %s Append %s exception: %s" % \
1688 (repr(input), repr(append
), e
))
1692 if result
!= expect
:
1693 if failed
== 0: print()
1694 print(" %s Append %s => %s did not match %s" % \
1695 (repr(input), repr(append
), repr(result
), repr(expect
)))
1698 assert failed
== 0, "%d Append() cases failed" % failed
1700 env
['UL'] = UL(['foo'])
1701 env
.Append(UL
= 'bar')
1703 assert isinstance(result
, UL
), repr(result
)
1704 assert result
== ['foo', 'b', 'a', 'r'], result
1706 env
['CLVar'] = CLVar(['foo'])
1707 env
.Append(CLVar
= 'bar')
1708 result
= env
['CLVar']
1709 assert isinstance(result
, CLVar
), repr(result
)
1710 assert result
== ['foo', 'bar'], result
1713 def __init__(self
, name
) -> None:
1715 def __str__(self
) -> str:
1717 def __eq__(self
, other
):
1718 raise Exception("should not compare")
1722 env2
= self
.TestEnvironment(CCC1
= ['c1'], CCC2
= ccc
)
1723 env2
.Append(CCC1
= ccc
, CCC2
= ['c2'])
1724 assert env2
['CCC1'][0] == 'c1', env2
['CCC1']
1725 assert env2
['CCC1'][1] is ccc
, env2
['CCC1']
1726 assert env2
['CCC2'][0] is ccc
, env2
['CCC2']
1727 assert env2
['CCC2'][1] == 'c2', env2
['CCC2']
1729 env3
= self
.TestEnvironment(X
= {'x1' : 7})
1730 env3
.Append(X
= {'x1' : 8, 'x2' : 9}, Y
= {'y1' : 10})
1731 assert env3
['X'] == {'x1': 8, 'x2': 9}, env3
['X']
1732 assert env3
['Y'] == {'y1': 10}, env3
['Y']
1736 env4
= self
.TestEnvironment(BUILDERS
= {'z1' : z1
})
1737 env4
.Append(BUILDERS
= {'z2' : z2
})
1738 assert env4
['BUILDERS'] == {'z1' : z1
, 'z2' : z2
}, env4
['BUILDERS']
1739 assert hasattr(env4
, 'z1')
1740 assert hasattr(env4
, 'z2')
1742 def test_AppendENVPath(self
) -> None:
1743 """Test appending to an ENV path."""
1744 env1
= self
.TestEnvironment(
1745 ENV
={'PATH': r
'C:\dir\num\one;C:\dir\num\two'},
1746 MYENV
={'MYPATH': r
'C:\mydir\num\one;C:\mydir\num\two'},
1748 # have to include the pathsep here so that the test will work on UNIX too.
1749 env1
.AppendENVPath('PATH', r
'C:\dir\num\two', sep
=';')
1750 env1
.AppendENVPath('PATH', r
'C:\dir\num\three', sep
=';')
1751 env1
.AppendENVPath('MYPATH', r
'C:\mydir\num\three', 'MYENV', sep
=';')
1753 env1
['ENV']['PATH'] == r
'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three'
1754 ), env1
['ENV']['PATH']
1756 env1
.AppendENVPath('MYPATH', r
'C:\mydir\num\three', 'MYENV', sep
=';')
1758 'MYPATH', r
'C:\mydir\num\one', 'MYENV', sep
=';', delete_existing
=1
1760 # this should do nothing since delete_existing is 0
1762 env1
['MYENV']['MYPATH'] == r
'C:\mydir\num\two;C:\mydir\num\three;C:\mydir\num\one'
1763 ), env1
['MYENV']['MYPATH']
1765 test
= TestCmd
.TestCmd(workdir
='')
1766 test
.subdir('sub1', 'sub2')
1767 p
= env1
['ENV']['PATH']
1768 env1
.AppendENVPath('PATH', '#sub1', sep
=';')
1769 env1
.AppendENVPath('PATH', env1
.fs
.Dir('sub2'), sep
=';')
1770 assert env1
['ENV']['PATH'] == p
+ ';sub1;sub2', env1
['ENV']['PATH']
1772 def test_AppendUnique(self
) -> None:
1773 """Test appending to unique values to construction variables
1775 This strips values that are already present when lists are
1777 env
= self
.TestEnvironment(AAA1
= 'a1',
1789 DDD1
= ['a', 'b', 'c'])
1790 env
['LL1'] = [env
.Literal('a literal'), env
.Literal('b literal')]
1791 env
['LL2'] = [env
.Literal('c literal'), env
.Literal('b literal')]
1792 env
.AppendUnique(AAA1
= 'a1',
1794 AAA3
= ['a3', 'b', 'c', 'c', 'b', 'a3'], # ignore dups
1799 BBB3
= ['b3', 'c', 'd', 'c', 'b3'],
1805 LL1
= env
.Literal('a literal'),
1806 LL2
= env
.Literal('a literal'))
1808 assert env
['AAA1'] == 'a1a1', env
['AAA1']
1809 assert env
['AAA2'] == ['a2'], env
['AAA2']
1810 assert env
['AAA3'] == ['a3', 'b', 'c'], env
['AAA3']
1811 assert env
['AAA4'] == 'a4a4.new', env
['AAA4']
1812 assert env
['AAA5'] == ['a5', 'a5.new'], env
['AAA5']
1813 assert env
['BBB1'] == ['b1'], env
['BBB1']
1814 assert env
['BBB2'] == ['b2'], env
['BBB2']
1815 assert env
['BBB3'] == ['b3', 'c', 'd'], env
['BBB3']
1816 assert env
['BBB4'] == ['b4', 'b4.new'], env
['BBB4']
1817 assert env
['BBB5'] == ['b5', 'b5.new'], env
['BBB5']
1818 assert env
['CCC1'] == 'c1', env
['CCC1']
1819 assert env
['CCC2'] == ['c2'], env
['CCC2']
1820 assert env
['DDD1'] == ['a', 'b', 'c'], env
['DDD1']
1821 assert env
['LL1'] == [env
.Literal('a literal'), env
.Literal('b literal')], env
['LL1']
1822 assert env
['LL2'] == [env
.Literal('c literal'), env
.Literal('b literal'), env
.Literal('a literal')], [str(x
) for x
in env
['LL2']]
1824 env
.AppendUnique(DDD1
= 'b', delete_existing
=1)
1825 assert env
['DDD1'] == ['a', 'c', 'b'], env
['DDD1'] # b moves to end
1826 env
.AppendUnique(DDD1
= ['a','b'], delete_existing
=1)
1827 assert env
['DDD1'] == ['c', 'a', 'b'], env
['DDD1'] # a & b move to end
1828 env
.AppendUnique(DDD1
= ['e','f', 'e'], delete_existing
=1)
1829 assert env
['DDD1'] == ['c', 'a', 'b', 'f', 'e'], env
['DDD1'] # add last
1831 env
['CLVar'] = CLVar([])
1832 env
.AppendUnique(CLVar
= 'bar')
1833 result
= env
['CLVar']
1834 assert isinstance(result
, CLVar
), repr(result
)
1835 assert result
== ['bar'], result
1837 env
['CLVar'] = CLVar(['abc'])
1838 env
.AppendUnique(CLVar
= 'bar')
1839 result
= env
['CLVar']
1840 assert isinstance(result
, CLVar
), repr(result
)
1841 assert result
== ['abc', 'bar'], result
1843 env
['CLVar'] = CLVar(['bar'])
1844 env
.AppendUnique(CLVar
= 'bar')
1845 result
= env
['CLVar']
1846 assert isinstance(result
, CLVar
), repr(result
)
1847 assert result
== ['bar'], result
1849 def test_Clone(self
) -> None:
1850 """Test construction environment cloning.
1852 The clone should compare equal if there are no overrides.
1853 Update the clone independently afterwards and check that
1854 the original remains intact (that is, no dangling
1855 references point to objects in the copied environment).
1856 Clone the original with some construction variable
1857 updates and check that the original remains intact
1858 and the copy has the updated values.
1860 with self
.subTest():
1861 env1
= self
.TestEnvironment(XXX
='x', YYY
='y')
1863 env1copy
= env1
.Clone()
1864 self
.assertEqual(env1copy
, env1
)
1865 self
.assertEqual(env2
, env1
)
1866 env2
.Replace(YYY
= 'yyy')
1867 self
.assertNotEqual(env1
, env2
)
1868 self
.assertEqual(env1
, env1copy
)
1870 env3
= env1
.Clone(XXX
='x3', ZZZ
='z3')
1871 self
.assertNotEqual(env3
, env1
)
1872 self
.assertEqual(env3
.Dictionary('XXX'), 'x3')
1873 self
.assertEqual(env1
.Dictionary('XXX'), 'x')
1874 self
.assertEqual(env3
.Dictionary('YYY'), 'y')
1875 self
.assertEqual(env3
.Dictionary('ZZZ'), 'z3')
1876 self
.assertRaises(KeyError, env1
.Dictionary
, 'ZZZ') # leak test
1877 self
.assertEqual(env1
, env1copy
)
1879 # Ensure that lists and dictionaries are deep copied, but not instances
1880 with self
.subTest():
1885 env1
= self
.TestEnvironment(
1891 env2
.Dictionary('YYY').append(4)
1892 env2
.Dictionary('ZZZ')[5] = 6
1893 self
.assertIs(env1
.Dictionary('XXX'), env2
.Dictionary('XXX'))
1894 self
.assertIn(4, env2
.Dictionary('YYY'))
1895 self
.assertNotIn(4, env1
.Dictionary('YYY'))
1896 self
.assertIn(5, env2
.Dictionary('ZZZ'))
1897 self
.assertNotIn(5, env1
.Dictionary('ZZZ'))
1899 # We also need to look at the special cases in semi_deepcopy()
1900 # used when cloning - these should not leak to the original either
1901 with self
.subTest():
1902 env1
= self
.TestEnvironment(
1903 XXX
=deque([1, 2, 3]),
1905 ZZZ
=UD({1: 2, 3: 4}),
1908 env2
['XXX'].append(4)
1909 env2
['YYY'].append(4)
1911 self
.assertIn(4, env2
['XXX'])
1912 self
.assertNotIn(4, env1
['XXX'])
1913 self
.assertIn(4, env2
['YYY'])
1914 self
.assertNotIn(4, env1
['YYY'])
1915 self
.assertIn(5, env2
['ZZZ'])
1916 self
.assertNotIn(5, env1
['ZZZ'])
1918 # BUILDERS is special...
1919 with self
.subTest():
1920 env1
= self
.TestEnvironment(BUILDERS
={'b1': Builder()})
1921 assert hasattr(env1
, 'b1'), "env1.b1 was not set"
1922 assert env1
.b1
.object == env1
, "b1.object doesn't point to env1"
1923 env2
= env1
.Clone(BUILDERS
= {'b2' : Builder()})
1925 assert hasattr(env1
, 'b1'), "b1 was mistakenly cleared from env1"
1926 assert env1
.b1
.object == env1
, "b1.object was changed"
1927 assert not hasattr(env2
, 'b1'), "b1 was not cleared from env2"
1928 assert hasattr(env2
, 'b2'), "env2.b2 was not set"
1929 assert env2
.b2
.object == env2
, "b2.object doesn't point to env2"
1931 # Ensure that specifying new tools in a copied environment works.
1932 with self
.subTest():
1934 def foo(env
) -> None:
1937 def bar(env
) -> None:
1940 def baz(env
) -> None:
1943 env1
= self
.TestEnvironment(tools
=[foo
])
1945 env3
= env1
.Clone(tools
=[bar
, baz
])
1947 assert env1
.get('FOO') == 1
1948 assert env1
.get('BAR') is None
1949 assert env1
.get('BAZ') is None
1950 assert env2
.get('FOO') == 1
1951 assert env2
.get('BAR') is None
1952 assert env2
.get('BAZ') is None
1953 assert env3
.get('FOO') == 1
1954 assert env3
.get('BAR') == 2
1955 assert env3
.get('BAZ') == 3
1957 # Ensure that recursive variable substitution when copying
1958 # environments works properly.
1959 with self
.subTest():
1960 env1
= self
.TestEnvironment(CCFLAGS
='-DFOO', XYZ
='-DXYZ')
1962 CCFLAGS
='$CCFLAGS -DBAR', XYZ
=['-DABC', 'x $XYZ y', '-DDEF']
1964 x
= env2
.get('CCFLAGS')
1965 assert x
== '-DFOO -DBAR', x
1967 assert x
== ['-DABC', 'x -DXYZ y', '-DDEF'], x
1969 # Ensure that special properties of a class don't get
1971 with self
.subTest():
1972 env1
= self
.TestEnvironment(FLAGS
=CLVar('flag1 flag2'))
1973 x
= env1
.get('FLAGS')
1974 assert x
== ['flag1', 'flag2'], x
1976 env2
.Append(FLAGS
='flag3 flag4')
1977 x
= env2
.get('FLAGS')
1978 assert x
== ['flag1', 'flag2', 'flag3', 'flag4'], x
1979 x
= env1
.get('FLAGS')
1980 assert x
== ['flag1', 'flag2'], x
1982 # Ensure that appending directly to a copied CLVar
1983 # doesn't modify the original.
1984 with self
.subTest():
1985 env1
= self
.TestEnvironment(FLAGS
=CLVar('flag1 flag2'))
1986 x
= env1
.get('FLAGS')
1987 assert x
== ['flag1', 'flag2'], x
1989 env2
['FLAGS'] += ['flag3', 'flag4']
1990 x
= env2
.get('FLAGS')
1991 assert x
== ['flag1', 'flag2', 'flag3', 'flag4'], x
1992 x
= env1
.get('FLAGS')
1993 assert x
== ['flag1', 'flag2'], x
1995 # Test that the environment stores the toolpath and
1996 # re-uses it for copies.
1997 with self
.subTest():
1998 test
= TestCmd
.TestCmd(workdir
='')
2000 test
.write('xxx.py', """\
2007 test
.write('yyy.py', """\
2014 env
= self
.TestEnvironment(tools
=['xxx'], toolpath
=[test
.workpath('')])
2015 assert env
['XXX'] == 'one', env
['XXX']
2016 env
= env
.Clone(tools
=['yyy'])
2017 assert env
['YYY'] == 'two', env
['YYY']
2020 with self
.subTest():
2023 def my_tool(env
, rv
=real_value
) -> None:
2024 assert env
['KEY_THAT_I_WANT'] == rv
[0]
2025 env
['KEY_THAT_I_WANT'] = rv
[0] + 1
2027 env
= self
.TestEnvironment()
2030 env
= env
.Clone(KEY_THAT_I_WANT
=5, tools
=[my_tool
])
2031 assert env
['KEY_THAT_I_WANT'] == real_value
[0], env
['KEY_THAT_I_WANT']
2034 env
= env
.Clone(KEY_THAT_I_WANT
=6, tools
=[my_tool
])
2035 assert env
['KEY_THAT_I_WANT'] == real_value
[0], env
['KEY_THAT_I_WANT']
2037 # test for pull request #150
2038 with self
.subTest():
2039 env
= self
.TestEnvironment()
2040 env
._dict
.pop('BUILDERS')
2041 assert ('BUILDERS' in env
) is False
2044 def test_Detect(self
) -> None:
2045 """Test Detect()ing tools"""
2046 test
= TestCmd
.TestCmd(workdir
= '')
2047 test
.subdir('sub1', 'sub2')
2048 sub1
= test
.workpath('sub1')
2049 sub2
= test
.workpath('sub2')
2051 if sys
.platform
== 'win32':
2052 test
.write(['sub1', 'xxx'], "sub1/xxx\n")
2053 test
.write(['sub2', 'xxx'], "sub2/xxx\n")
2055 env
= self
.TestEnvironment(ENV
= { 'PATH' : [sub1
, sub2
] })
2057 x
= env
.Detect('xxx.exe')
2060 test
.write(['sub2', 'xxx.exe'], "sub2/xxx.exe\n")
2062 env
= self
.TestEnvironment(ENV
= { 'PATH' : [sub1
, sub2
] })
2064 x
= env
.Detect('xxx.exe')
2065 assert x
== 'xxx.exe', x
2067 test
.write(['sub1', 'xxx.exe'], "sub1/xxx.exe\n")
2069 x
= env
.Detect('xxx.exe')
2070 assert x
== 'xxx.exe', x
2073 test
.write(['sub1', 'xxx.exe'], "sub1/xxx.exe\n")
2074 test
.write(['sub2', 'xxx.exe'], "sub2/xxx.exe\n")
2076 env
= self
.TestEnvironment(ENV
= { 'PATH' : [sub1
, sub2
] })
2078 x
= env
.Detect('xxx.exe')
2081 sub2_xxx_exe
= test
.workpath('sub2', 'xxx.exe')
2082 os
.chmod(sub2_xxx_exe
, 0o755)
2084 env
= self
.TestEnvironment(ENV
= { 'PATH' : [sub1
, sub2
] })
2086 x
= env
.Detect('xxx.exe')
2087 assert x
== 'xxx.exe', x
2089 sub1_xxx_exe
= test
.workpath('sub1', 'xxx.exe')
2090 os
.chmod(sub1_xxx_exe
, 0o755)
2092 x
= env
.Detect('xxx.exe')
2093 assert x
== 'xxx.exe', x
2095 env
= self
.TestEnvironment(ENV
= { 'PATH' : [] })
2096 x
= env
.Detect('xxx.exe')
2099 def test_Dictionary(self
) -> None:
2100 """Test retrieval of known construction variables
2102 Fetch them from the Dictionary and check for well-known
2103 defaults that get inserted.
2105 env
= self
.TestEnvironment(XXX
= 'x', YYY
= 'y', ZZZ
= 'z')
2106 assert env
.Dictionary('XXX') == 'x'
2107 assert env
.Dictionary('YYY') == 'y'
2108 assert env
.Dictionary('XXX', 'ZZZ') == ['x', 'z']
2109 xxx
, zzz
= env
.Dictionary('XXX', 'ZZZ')
2112 assert 'BUILDERS' in env
.Dictionary()
2113 assert 'CC' in env
.Dictionary()
2114 assert 'CCFLAGS' in env
.Dictionary()
2115 assert 'ENV' in env
.Dictionary()
2117 assert env
['XXX'] == 'x'
2119 assert env
.Dictionary('XXX') == 'foo'
2121 assert 'XXX' not in env
.Dictionary()
2123 def test_FindIxes(self
) -> None:
2124 """Test FindIxes()"""
2125 env
= self
.TestEnvironment(LIBPREFIX
='lib',
2132 paths
= [os
.path
.join('dir', 'libfoo.a'),
2133 os
.path
.join('dir', 'libfoo.so')]
2135 assert paths
[0] == env
.FindIxes(paths
, 'LIBPREFIX', 'LIBSUFFIX')
2136 assert paths
[1] == env
.FindIxes(paths
, 'SHLIBPREFIX', 'SHLIBSUFFIX')
2137 assert None is env
.FindIxes(paths
, 'PREFIX', 'POST')
2139 paths
= ['libfoo.a', 'prefoopost']
2141 assert paths
[0] == env
.FindIxes(paths
, 'LIBPREFIX', 'LIBSUFFIX')
2142 assert None is env
.FindIxes(paths
, 'SHLIBPREFIX', 'SHLIBSUFFIX')
2143 assert paths
[1] == env
.FindIxes(paths
, 'PREFIX', 'SUFFIX')
2145 def test_ParseConfig(self
) -> None:
2146 """Test the ParseConfig() method"""
2147 env
= self
.TestEnvironment(COMMAND
='command',
2148 ASFLAGS
='assembler',
2160 orig_backtick
= env
.backtick
2162 """mocked backtick routine so command is not actually issued.
2164 Just returns the string it was given.
2166 def __init__(self
, save_command
, output
) -> None:
2167 self
.save_command
= save_command
2168 self
.output
= output
2169 def __call__(self
, command
):
2170 self
.save_command
.append(command
)
2175 env
.backtick
= my_backtick(save_command
,
2176 "-I/usr/include/fum -I bar -X\n" + \
2177 "-L/usr/fax -L foo -lxxx -l yyy " + \
2178 "-Wa,-as -Wl,-link " + \
2179 "-Wl,-rpath=rpath1 " + \
2180 "-Wl,-R,rpath2 " + \
2183 "-framework Carbon " + \
2184 "-frameworkdir=fwd1 " + \
2188 "-fmerge-all-constants " + \
2189 "-mno-cygwin -mwindows " + \
2190 "-arch i386 -isysroot /tmp " + \
2191 "-iquote /usr/include/foo1 " + \
2192 "-isystem /usr/include/foo2 " + \
2193 "-idirafter /usr/include/foo3 " + \
2195 "-DFOO -DBAR=value")
2196 env
.ParseConfig("fake $COMMAND")
2197 assert save_command
== ['fake command'], save_command
2198 assert env
['ASFLAGS'] == ['assembler', '-as'], env
['ASFLAGS']
2199 assert env
['CCFLAGS'] == ['', '-X', '-Wa,-as',
2200 '-pthread', '-fmerge-all-constants', '-mno-cygwin',
2201 ('-arch', 'i386'), ('-isysroot', '/tmp'),
2202 ('-iquote', '/usr/include/foo1'),
2203 ('-isystem', '/usr/include/foo2'),
2204 ('-idirafter', '/usr/include/foo3'),
2205 '+DD64'], env
['CCFLAGS']
2206 self
.assertEqual(list(env
['CPPDEFINES']), ['FOO', ['BAR', 'value']])
2207 assert env
['CPPFLAGS'] == ['', '-Wp,-cpp'], env
['CPPFLAGS']
2208 assert env
['CPPPATH'] == ['string', '/usr/include/fum', 'bar'], env
['CPPPATH']
2209 assert env
['FRAMEWORKPATH'] == ['fwd1', 'fwd2', 'fwd3'], env
['FRAMEWORKPATH']
2210 assert env
['FRAMEWORKS'] == ['Carbon'], env
['FRAMEWORKS']
2211 assert env
['LIBPATH'] == ['list', '/usr/fax', 'foo'], env
['LIBPATH']
2212 assert env
['LIBS'] == ['xxx', 'yyy', env
.File('abc')], env
['LIBS']
2213 assert env
['LINKFLAGS'] == ['', '-Wl,-link', '-pthread',
2214 '-fmerge-all-constants',
2215 '-mno-cygwin', '-mwindows',
2217 ('-isysroot', '/tmp'),
2218 '+DD64'], env
['LINKFLAGS']
2219 assert env
['RPATH'] == ['rpath1', 'rpath2', 'rpath3'], env
['RPATH']
2221 env
.backtick
= my_backtick([], "-Ibar")
2222 env
.ParseConfig("fake2")
2223 assert env
['CPPPATH'] == ['string', '/usr/include/fum', 'bar'], env
['CPPPATH']
2224 env
.ParseConfig("fake2", unique
=0)
2225 assert env
['CPPPATH'] == ['string', '/usr/include/fum', 'bar', 'bar'], env
['CPPPATH']
2227 env
.backtick
= orig_backtick
2229 # check that we can pass our own function,
2230 # and that it works for both values of unique
2232 def my_function(myenv
, flags
, unique
: bool=True) -> None:
2235 args
= json
.loads(flags
)
2237 myenv
.AppendUnique(**args
)
2239 myenv
.Append(**args
)
2241 json_str
= '{"LIBS": ["yyy", "xxx", "yyy"]}'
2243 env
= Environment(LIBS
=['xxx'])
2245 env
.backtick
= my_backtick([], json_str
)
2246 env2
.backtick
= my_backtick([], json_str
)
2248 env
.ParseConfig("foo", my_function
)
2249 assert env
['LIBS'] == ['xxx', 'yyy'], env
['LIBS']
2251 env2
.ParseConfig("foo2", my_function
, unique
=False)
2252 assert env2
['LIBS'] == ['xxx', 'yyy', 'xxx', 'yyy'], env2
['LIBS']
2255 def test_ParseDepends(self
) -> None:
2256 """Test the ParseDepends() method"""
2257 test
= TestCmd
.TestCmd(workdir
= '')
2259 test
.write('single', """
2269 test
.write('multiple', """
2280 env
= self
.TestEnvironment(SINGLE
= test
.workpath('single'))
2284 def my_depends(target
, dependency
, tlist
=tlist
, dlist
=dlist
) -> None:
2285 tlist
.extend(target
)
2286 dlist
.extend(dependency
)
2288 env
.Depends
= my_depends
2290 env
.ParseDepends(test
.workpath('does_not_exist'))
2294 env
.ParseDepends(test
.workpath('does_not_exist'), must_exist
=1)
2297 assert exc_caught
, "did not catch expected IOError"
2302 env
.ParseDepends('$SINGLE', only_one
=1)
2303 t
= list(map(str, tlist
))
2304 d
= list(map(str, dlist
))
2305 assert t
== ['f0'], t
2306 assert d
== ['d1', 'd2', 'd3'], d
2311 env
.ParseDepends(test
.workpath('multiple'))
2312 t
= list(map(str, tlist
))
2313 d
= list(map(str, dlist
))
2314 assert t
== ['f1', 'f2', 'f3', 'f4', 'f5'], t
2315 assert d
== ['foo', 'bar', 'abc', 'def', 'ghi', 'jkl', 'mno'], d
2319 env
.ParseDepends(test
.workpath('multiple'), only_one
=1)
2320 except SCons
.Errors
.UserError
:
2322 assert exc_caught
, "did not catch expected UserError"
2324 def test_Platform(self
) -> None:
2325 """Test the Platform() method"""
2326 env
= self
.TestEnvironment(WIN32
='win32', NONE
='no-such-platform')
2330 env
.Platform('does_not_exist')
2331 except SCons
.Errors
.UserError
:
2333 assert exc_caught
, "did not catch expected UserError"
2337 env
.Platform('$NONE')
2338 except SCons
.Errors
.UserError
:
2340 assert exc_caught
, "did not catch expected UserError"
2342 env
.Platform('posix')
2343 assert env
['OBJSUFFIX'] == '.o', env
['OBJSUFFIX']
2345 env
.Platform('$WIN32')
2346 assert env
['OBJSUFFIX'] == '.obj', env
['OBJSUFFIX']
2348 def test_Prepend(self
) -> None:
2349 """Test prepending to construction variables in an Environment
2353 'a2', ['A2'], ['A2', 'a2'],
2354 'a3', UL(['A3']), UL(['A3', 'a', '3']),
2357 'a6', UL([]), UL(['a', '6']),
2358 'a7', [''], ['', 'a7'],
2359 'a8', UL(['']), UL(['', 'a', '8']),
2361 ['e1'], 'E1', ['E1', 'e1'],
2362 ['e2'], ['E2'], ['E2', 'e2'],
2363 ['e3'], UL(['E3']), UL(['E3', 'e3']),
2366 ['e6'], UL([]), UL(['e6']),
2367 ['e7'], [''], ['', 'e7'],
2368 ['e8'], UL(['']), UL(['', 'e8']),
2370 UL(['i1']), 'I1', UL(['I', '1', 'i1']),
2371 UL(['i2']), ['I2'], UL(['I2', 'i2']),
2372 UL(['i3']), UL(['I3']), UL(['I3', 'i3']),
2373 UL(['i4']), '', UL(['i4']),
2374 UL(['i5']), [], UL(['i5']),
2375 UL(['i6']), UL([]), UL(['i6']),
2376 UL(['i7']), [''], UL(['', 'i7']),
2377 UL(['i8']), UL(['']), UL(['', 'i8']),
2379 {'d1':1}, 'D1', {'d1':1, 'D1':None},
2380 {'d2':1}, ['D2'], {'d2':1, 'D2':None},
2381 {'d3':1}, UL(['D3']), {'d3':1, 'D3':None},
2382 {'d4':1}, {'D4':1}, {'d4':1, 'D4':1},
2383 {'d5':1}, UD({'D5':1}), UD({'d5':1, 'D5':1}),
2385 UD({'u1':1}), 'U1', UD({'u1':1, 'U1':None}),
2386 UD({'u2':1}), ['U2'], UD({'u2':1, 'U2':None}),
2387 UD({'u3':1}), UL(['U3']), UD({'u3':1, 'U3':None}),
2388 UD({'u4':1}), {'U4':1}, UD({'u4':1, 'U4':1}),
2389 UD({'u5':1}), UD({'U5':1}), UD({'u5':1, 'U5':1}),
2393 '', UL(['M3']), UL(['M3']),
2398 '', UL(['']), UL(['']),
2402 [], UL(['N3']), UL(['N3']),
2407 [], UL(['']), UL(['']),
2409 UL([]), 'O1', UL(['O', '1']),
2410 UL([]), ['O2'], UL(['O2']),
2411 UL([]), UL(['O3']), UL(['O3']),
2414 UL([]), UL([]), UL([]),
2415 UL([]), [''], UL(['']),
2416 UL([]), UL(['']), UL(['']),
2418 [''], 'P1', ['P1', ''],
2419 [''], ['P2'], ['P2', ''],
2420 [''], UL(['P3']), UL(['P3', '']),
2423 [''], UL([]), UL(['']),
2424 [''], [''], ['', ''],
2425 [''], UL(['']), UL(['', '']),
2427 UL(['']), 'Q1', UL(['Q', '1', '']),
2428 UL(['']), ['Q2'], UL(['Q2', '']),
2429 UL(['']), UL(['Q3']), UL(['Q3', '']),
2430 UL(['']), '', UL(['']),
2431 UL(['']), [], UL(['']),
2432 UL(['']), UL([]), UL(['']),
2433 UL(['']), [''], UL(['', '']),
2434 UL(['']), UL(['']), UL(['', '']),
2440 input, prepend
, expect
= cases
[:3]
2441 env
['XXX'] = copy
.copy(input)
2443 env
.Prepend(XXX
= prepend
)
2444 except Exception as e
:
2445 if failed
== 0: print()
2446 print(" %s Prepend %s exception: %s" % \
2447 (repr(input), repr(prepend
), e
))
2451 if result
!= expect
:
2452 if failed
== 0: print()
2453 print(" %s Prepend %s => %s did not match %s" % \
2454 (repr(input), repr(prepend
), repr(result
), repr(expect
)))
2457 assert failed
== 0, "%d Prepend() cases failed" % failed
2459 env
['UL'] = UL(['foo'])
2460 env
.Prepend(UL
= 'bar')
2462 assert isinstance(result
, UL
), repr(result
)
2463 assert result
== ['b', 'a', 'r', 'foo'], result
2465 env
['CLVar'] = CLVar(['foo'])
2466 env
.Prepend(CLVar
= 'bar')
2467 result
= env
['CLVar']
2468 assert isinstance(result
, CLVar
), repr(result
)
2469 assert result
== ['bar', 'foo'], result
2471 env3
= self
.TestEnvironment(X
= {'x1' : 7})
2472 env3
.Prepend(X
= {'x1' : 8, 'x2' : 9}, Y
= {'y1' : 10})
2473 assert env3
['X'] == {'x1': 8, 'x2' : 9}, env3
['X']
2474 assert env3
['Y'] == {'y1': 10}, env3
['Y']
2478 env4
= self
.TestEnvironment(BUILDERS
= {'z1' : z1
})
2479 env4
.Prepend(BUILDERS
= {'z2' : z2
})
2480 assert env4
['BUILDERS'] == {'z1' : z1
, 'z2' : z2
}, env4
['BUILDERS']
2481 assert hasattr(env4
, 'z1')
2482 assert hasattr(env4
, 'z2')
2484 def test_PrependENVPath(self
) -> None:
2485 """Test prepending to an ENV path."""
2486 env1
= self
.TestEnvironment(
2487 ENV
={'PATH': r
'C:\dir\num\one;C:\dir\num\two'},
2488 MYENV
={'MYPATH': r
'C:\mydir\num\one;C:\mydir\num\two'},
2490 # have to include the pathsep here so that the test will work on UNIX too.
2491 env1
.PrependENVPath('PATH', r
'C:\dir\num\two', sep
=';')
2492 env1
.PrependENVPath('PATH', r
'C:\dir\num\three', sep
=';')
2494 env1
['ENV']['PATH'] == r
'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one'
2495 ), env1
['ENV']['PATH']
2497 env1
.PrependENVPath('MYPATH', r
'C:\mydir\num\three', 'MYENV', sep
=';')
2498 env1
.PrependENVPath('MYPATH', r
'C:\mydir\num\one', 'MYENV', sep
=';')
2499 # this should do nothing since delete_existing is 0
2500 env1
.PrependENVPath(
2501 'MYPATH', r
'C:\mydir\num\three', 'MYENV', sep
=';', delete_existing
=0
2504 env1
['MYENV']['MYPATH'] == r
'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two'
2505 ), env1
['MYENV']['MYPATH']
2507 test
= TestCmd
.TestCmd(workdir
='')
2508 test
.subdir('sub1', 'sub2')
2509 p
= env1
['ENV']['PATH']
2510 env1
.PrependENVPath('PATH', '#sub1', sep
=';')
2511 env1
.PrependENVPath('PATH', env1
.fs
.Dir('sub2'), sep
=';')
2512 assert env1
['ENV']['PATH'] == 'sub2;sub1;' + p
, env1
['ENV']['PATH']
2514 def test_PrependUnique(self
) -> None:
2515 """Test prepending unique values to construction variables
2517 This strips values that are already present when lists are
2519 env
= self
.TestEnvironment(AAA1
= 'a1',
2531 DDD1
= ['a', 'b', 'c'])
2532 env
.PrependUnique(AAA1
= 'a1',
2534 AAA3
= ['a3', 'b', 'c', 'b', 'a3'], # ignore dups
2539 BBB3
= ['b3', 'b', 'c', 'b3'],
2545 assert env
['AAA1'] == 'a1a1', env
['AAA1']
2546 assert env
['AAA2'] == ['a2'], env
['AAA2']
2547 assert env
['AAA3'] == ['c', 'b', 'a3'], env
['AAA3']
2548 assert env
['AAA4'] == 'a4.newa4', env
['AAA4']
2549 assert env
['AAA5'] == ['a5.new', 'a5'], env
['AAA5']
2550 assert env
['BBB1'] == ['b1'], env
['BBB1']
2551 assert env
['BBB2'] == ['b2'], env
['BBB2']
2552 assert env
['BBB3'] == ['b', 'c', 'b3'], env
['BBB3']
2553 assert env
['BBB4'] == ['b4.new', 'b4'], env
['BBB4']
2554 assert env
['BBB5'] == ['b5.new', 'b5'], env
['BBB5']
2555 assert env
['CCC1'] == 'c1', env
['CCC1']
2556 assert env
['CCC2'] == ['c2'], env
['CCC2']
2557 assert env
['DDD1'] == ['a', 'b', 'c'], env
['DDD1']
2559 env
.PrependUnique(DDD1
= 'b', delete_existing
=1)
2560 assert env
['DDD1'] == ['b', 'a', 'c'], env
['DDD1'] # b moves to front
2561 env
.PrependUnique(DDD1
= ['a','c'], delete_existing
=1)
2562 assert env
['DDD1'] == ['a', 'c', 'b'], env
['DDD1'] # a & c move to front
2563 env
.PrependUnique(DDD1
= ['d','e','d'], delete_existing
=1)
2564 assert env
['DDD1'] == ['d', 'e', 'a', 'c', 'b'], env
['DDD1']
2567 env
['CLVar'] = CLVar([])
2568 env
.PrependUnique(CLVar
= 'bar')
2569 result
= env
['CLVar']
2570 assert isinstance(result
, CLVar
), repr(result
)
2571 assert result
== ['bar'], result
2573 env
['CLVar'] = CLVar(['abc'])
2574 env
.PrependUnique(CLVar
= 'bar')
2575 result
= env
['CLVar']
2576 assert isinstance(result
, CLVar
), repr(result
)
2577 assert result
== ['bar', 'abc'], result
2579 env
['CLVar'] = CLVar(['bar'])
2580 env
.PrependUnique(CLVar
= 'bar')
2581 result
= env
['CLVar']
2582 assert isinstance(result
, CLVar
), repr(result
)
2583 assert result
== ['bar'], result
2585 def test_Replace(self
) -> None:
2586 """Test replacing construction variables in an Environment
2588 After creation of the Environment, of course.
2590 env1
= self
.TestEnvironment(AAA
= 'a', BBB
= 'b')
2591 env1
.Replace(BBB
= 'bbb', CCC
= 'ccc')
2593 env2
= self
.TestEnvironment(AAA
= 'a', BBB
= 'bbb', CCC
= 'ccc')
2594 assert env1
== env2
, diff_env(env1
, env2
)
2598 env3
= self
.TestEnvironment(BUILDERS
= {'b1' : b1
})
2599 assert hasattr(env3
, 'b1'), "b1 was not set"
2600 env3
.Replace(BUILDERS
= {'b2' : b2
})
2601 assert not hasattr(env3
, 'b1'), "b1 was not cleared"
2602 assert hasattr(env3
, 'b2'), "b2 was not set"
2604 def test_ReplaceIxes(self
) -> None:
2605 """Test ReplaceIxes()"""
2606 env
= self
.TestEnvironment(LIBPREFIX
='lib',
2613 assert 'libfoo.a' == env
.ReplaceIxes('libfoo.so',
2614 'SHLIBPREFIX', 'SHLIBSUFFIX',
2615 'LIBPREFIX', 'LIBSUFFIX')
2617 assert os
.path
.join('dir', 'libfoo.a') == env
.ReplaceIxes(os
.path
.join('dir', 'libfoo.so'),
2618 'SHLIBPREFIX', 'SHLIBSUFFIX',
2619 'LIBPREFIX', 'LIBSUFFIX')
2621 assert 'libfoo.a' == env
.ReplaceIxes('prefoopost',
2623 'LIBPREFIX', 'LIBSUFFIX')
2625 def test_SetDefault(self
) -> None:
2626 """Test the SetDefault method"""
2627 env
= self
.TestEnvironment(tools
= [])
2628 env
.SetDefault(V1
= 1)
2629 env
.SetDefault(V1
= 2)
2630 assert env
['V1'] == 1
2632 env
.SetDefault(V2
= 1)
2633 assert env
['V2'] == 2
2635 def test_Tool(self
) -> None:
2636 """Test the Tool() method"""
2637 env
= self
.TestEnvironment(LINK
='link', NONE
='no-such-tool')
2641 tool
= env
.Tool('does_not_exist')
2642 except SCons
.Errors
.UserError
:
2645 assert isinstance(tool
, SCons
.Tool
.Tool
)
2646 assert exc_caught
, "did not catch expected UserError"
2651 except SCons
.Errors
.UserError
:
2653 assert exc_caught
, "did not catch expected UserError"
2655 # Use a non-existent toolpath directory just to make sure we
2656 # can call Tool() with the keyword argument.
2657 env
.Tool('cc', toolpath
=['/no/such/directory'])
2658 assert env
['CC'] == 'cc', env
['CC']
2661 assert env
['LINK'] == '$SMARTLINK', env
['LINK']
2663 # Test that the environment stores the toolpath and
2664 # re-uses it for later calls.
2665 test
= TestCmd
.TestCmd(workdir
= '')
2667 test
.write('xxx.py', """\
2674 test
.write('yyy.py', """\
2681 env
= self
.TestEnvironment(tools
=['xxx'], toolpath
=[test
.workpath('')])
2682 assert env
['XXX'] == 'one', env
['XXX']
2684 assert env
['YYY'] == 'two', env
['YYY']
2686 def test_WhereIs(self
) -> None:
2687 """Test the WhereIs() method"""
2688 test
= TestCmd
.TestCmd(workdir
= '')
2690 sub1_xxx_exe
= test
.workpath('sub1', 'xxx.exe')
2691 sub2_xxx_exe
= test
.workpath('sub2', 'xxx.exe')
2692 sub3_xxx_exe
= test
.workpath('sub3', 'xxx.exe')
2693 sub4_xxx_exe
= test
.workpath('sub4', 'xxx.exe')
2695 test
.subdir('subdir', 'sub1', 'sub2', 'sub3', 'sub4')
2697 if sys
.platform
!= 'win32':
2698 test
.write(sub1_xxx_exe
, "\n")
2700 os
.mkdir(sub2_xxx_exe
)
2702 test
.write(sub3_xxx_exe
, "\n")
2703 os
.chmod(sub3_xxx_exe
, 0o777)
2705 test
.write(sub4_xxx_exe
, "\n")
2706 os
.chmod(sub4_xxx_exe
, 0o777)
2708 env_path
= os
.environ
['PATH']
2710 pathdirs_1234
= [ test
.workpath('sub1'),
2711 test
.workpath('sub2'),
2712 test
.workpath('sub3'),
2713 test
.workpath('sub4'),
2714 ] + env_path
.split(os
.pathsep
)
2716 pathdirs_1243
= [ test
.workpath('sub1'),
2717 test
.workpath('sub2'),
2718 test
.workpath('sub4'),
2719 test
.workpath('sub3'),
2720 ] + env_path
.split(os
.pathsep
)
2722 path
= os
.pathsep
.join(pathdirs_1234
)
2723 env
= self
.TestEnvironment(ENV
= {'PATH' : path
})
2724 wi
= env
.WhereIs('')
2726 wi
= env
.WhereIs('xxx.exe')
2727 assert wi
== test
.workpath(sub3_xxx_exe
), wi
2728 wi
= env
.WhereIs('xxx.exe', pathdirs_1243
)
2729 assert wi
== test
.workpath(sub4_xxx_exe
), wi
2730 wi
= env
.WhereIs('xxx.exe', os
.pathsep
.join(pathdirs_1243
))
2731 assert wi
== test
.workpath(sub4_xxx_exe
), wi
2733 wi
= env
.WhereIs('xxx.exe', reject
= sub3_xxx_exe
)
2734 assert wi
== test
.workpath(sub4_xxx_exe
), wi
2735 wi
= env
.WhereIs('xxx.exe', pathdirs_1243
, reject
= sub3_xxx_exe
)
2736 assert wi
== test
.workpath(sub4_xxx_exe
), wi
2738 path
= os
.pathsep
.join(pathdirs_1243
)
2739 env
= self
.TestEnvironment(ENV
= {'PATH' : path
})
2740 wi
= env
.WhereIs('xxx.exe')
2741 assert wi
== test
.workpath(sub4_xxx_exe
), wi
2742 wi
= env
.WhereIs('xxx.exe', pathdirs_1234
)
2743 assert wi
== test
.workpath(sub3_xxx_exe
), wi
2744 wi
= env
.WhereIs('xxx.exe', os
.pathsep
.join(pathdirs_1234
))
2745 assert wi
== test
.workpath(sub3_xxx_exe
), wi
2747 if sys
.platform
== 'win32':
2748 wi
= env
.WhereIs('xxx', pathext
= '')
2749 assert wi
is None, wi
2751 wi
= env
.WhereIs('xxx', pathext
= '.exe')
2752 assert wi
== test
.workpath(sub4_xxx_exe
), wi
2754 wi
= env
.WhereIs('xxx', path
= pathdirs_1234
, pathext
= '.BAT;.EXE')
2755 assert wi
.lower() == test
.workpath(sub3_xxx_exe
).lower(), wi
2757 # Test that we return a normalized path even when
2758 # the path contains forward slashes.
2759 forward_slash
= test
.workpath('') + '/sub3'
2760 wi
= env
.WhereIs('xxx', path
= forward_slash
, pathext
= '.EXE')
2761 assert wi
.lower() == test
.workpath(sub3_xxx_exe
).lower(), wi
2765 def test_Action(self
) -> None:
2766 """Test the Action() method"""
2769 env
= self
.TestEnvironment(FOO
= 'xyzzy')
2771 a
= env
.Action('foo')
2773 assert a
.__class
__ is SCons
.Action
.CommandAction
, a
.__class
__
2775 a
= env
.Action('$FOO')
2777 assert a
.__class
__ is SCons
.Action
.CommandAction
, a
.__class
__
2779 a
= env
.Action('$$FOO')
2781 assert a
.__class
__ is SCons
.Action
.LazyAction
, a
.__class
__
2783 a
= env
.Action(['$FOO', 'foo'])
2785 assert a
.__class
__ is SCons
.Action
.ListAction
, a
.__class
__
2787 def func(arg
) -> None:
2789 a
= env
.Action(func
)
2791 assert a
.__class
__ is SCons
.Action
.FunctionAction
, a
.__class
__
2793 def test_AddPostAction(self
) -> None:
2794 """Test the AddPostAction() method"""
2795 env
= self
.TestEnvironment(FOO
='fff', BAR
='bbb')
2797 n
= env
.AddPostAction('$FOO', lambda x
: x
)
2798 assert str(n
[0]) == 'fff', n
[0]
2800 n
= env
.AddPostAction(['ggg', '$BAR'], lambda x
: x
)
2801 assert str(n
[0]) == 'ggg', n
[0]
2802 assert str(n
[1]) == 'bbb', n
[1]
2804 def test_AddPreAction(self
) -> None:
2805 """Test the AddPreAction() method"""
2806 env
= self
.TestEnvironment(FOO
='fff', BAR
='bbb')
2808 n
= env
.AddPreAction('$FOO', lambda x
: x
)
2809 assert str(n
[0]) == 'fff', n
[0]
2811 n
= env
.AddPreAction(['ggg', '$BAR'], lambda x
: x
)
2812 assert str(n
[0]) == 'ggg', n
[0]
2813 assert str(n
[1]) == 'bbb', n
[1]
2815 def test_Alias(self
) -> None:
2816 """Test the Alias() method"""
2817 env
= self
.TestEnvironment(FOO
='kkk', BAR
='lll', EA
='export_alias')
2819 tgt
= env
.Alias('new_alias')[0]
2820 assert str(tgt
) == 'new_alias', tgt
2821 assert tgt
.sources
== [], tgt
.sources
2822 assert not hasattr(tgt
, 'builder'), tgt
.builder
2824 tgt
= env
.Alias('None_alias', None)[0]
2825 assert str(tgt
) == 'None_alias', tgt
2826 assert tgt
.sources
== [], tgt
.sources
2828 tgt
= env
.Alias('empty_list', [])[0]
2829 assert str(tgt
) == 'empty_list', tgt
2830 assert tgt
.sources
== [], tgt
.sources
2832 tgt
= env
.Alias('export_alias', [ 'asrc1', '$FOO' ])[0]
2833 assert str(tgt
) == 'export_alias', tgt
2834 assert len(tgt
.sources
) == 2, list(map(str, tgt
.sources
))
2835 assert str(tgt
.sources
[0]) == 'asrc1', list(map(str, tgt
.sources
))
2836 assert str(tgt
.sources
[1]) == 'kkk', list(map(str, tgt
.sources
))
2838 n
= env
.Alias(tgt
, source
= ['$BAR', 'asrc4'])[0]
2840 assert len(tgt
.sources
) == 4, list(map(str, tgt
.sources
))
2841 assert str(tgt
.sources
[2]) == 'lll', list(map(str, tgt
.sources
))
2842 assert str(tgt
.sources
[3]) == 'asrc4', list(map(str, tgt
.sources
))
2844 n
= env
.Alias('$EA', 'asrc5')[0]
2846 assert len(tgt
.sources
) == 5, list(map(str, tgt
.sources
))
2847 assert str(tgt
.sources
[4]) == 'asrc5', list(map(str, tgt
.sources
))
2849 t1
, t2
= env
.Alias(['t1', 't2'], ['asrc6', 'asrc7'])
2850 assert str(t1
) == 't1', t1
2851 assert str(t2
) == 't2', t2
2852 assert len(t1
.sources
) == 2, list(map(str, t1
.sources
))
2853 assert str(t1
.sources
[0]) == 'asrc6', list(map(str, t1
.sources
))
2854 assert str(t1
.sources
[1]) == 'asrc7', list(map(str, t1
.sources
))
2855 assert len(t2
.sources
) == 2, list(map(str, t2
.sources
))
2856 assert str(t2
.sources
[0]) == 'asrc6', list(map(str, t2
.sources
))
2857 assert str(t2
.sources
[1]) == 'asrc7', list(map(str, t2
.sources
))
2859 tgt
= env
.Alias('add', 's1')
2860 tgt
= env
.Alias('add', 's2')[0]
2861 s
= list(map(str, tgt
.sources
))
2862 assert s
== ['s1', 's2'], s
2863 tgt
= env
.Alias(tgt
, 's3')[0]
2864 s
= list(map(str, tgt
.sources
))
2865 assert s
== ['s1', 's2', 's3'], s
2867 tgt
= env
.Alias('act', None, "action1")[0]
2868 s
= str(tgt
.builder
.action
)
2869 assert s
== "action1", s
2870 tgt
= env
.Alias('act', None, "action2")[0]
2871 s
= str(tgt
.builder
.action
)
2872 assert s
== "action1\naction2", s
2873 tgt
= env
.Alias(tgt
, None, "action3")[0]
2874 s
= str(tgt
.builder
.action
)
2875 assert s
== "action1\naction2\naction3", s
2877 def test_AlwaysBuild(self
) -> None:
2878 """Test the AlwaysBuild() method"""
2879 env
= self
.TestEnvironment(FOO
='fff', BAR
='bbb')
2880 t
= env
.AlwaysBuild('a', 'b$FOO', ['c', 'd'], '$BAR',
2881 env
.fs
.Dir('dir'), env
.fs
.File('file'))
2882 assert t
[0].__class
__.__name
__ == 'Entry'
2883 assert t
[0].get_internal_path() == 'a'
2884 assert t
[0].always_build
2885 assert t
[1].__class
__.__name
__ == 'Entry'
2886 assert t
[1].get_internal_path() == 'bfff'
2887 assert t
[1].always_build
2888 assert t
[2].__class
__.__name
__ == 'Entry'
2889 assert t
[2].get_internal_path() == 'c'
2890 assert t
[2].always_build
2891 assert t
[3].__class
__.__name
__ == 'Entry'
2892 assert t
[3].get_internal_path() == 'd'
2893 assert t
[3].always_build
2894 assert t
[4].__class
__.__name
__ == 'Entry'
2895 assert t
[4].get_internal_path() == 'bbb'
2896 assert t
[4].always_build
2897 assert t
[5].__class
__.__name
__ == 'Dir'
2898 assert t
[5].get_internal_path() == 'dir'
2899 assert t
[5].always_build
2900 assert t
[6].__class
__.__name
__ == 'File'
2901 assert t
[6].get_internal_path() == 'file'
2902 assert t
[6].always_build
2904 def test_VariantDir(self
) -> None:
2905 """Test the VariantDir() method"""
2907 def Dir(self
, name
):
2909 def VariantDir(self
, variant_dir
, src_dir
, duplicate
) -> None:
2910 self
.variant_dir
= variant_dir
2911 self
.src_dir
= src_dir
2912 self
.duplicate
= duplicate
2914 env
= self
.TestEnvironment(FOO
= 'fff', BAR
= 'bbb')
2917 env
.VariantDir('build', 'src')
2918 assert env
.fs
.variant_dir
== 'build', env
.fs
.variant_dir
2919 assert env
.fs
.src_dir
== 'src', env
.fs
.src_dir
2920 assert env
.fs
.duplicate
== 1, env
.fs
.duplicate
2922 env
.VariantDir('build${FOO}', '${BAR}src', 0)
2923 assert env
.fs
.variant_dir
== 'buildfff', env
.fs
.variant_dir
2924 assert env
.fs
.src_dir
== 'bbbsrc', env
.fs
.src_dir
2925 assert env
.fs
.duplicate
== 0, env
.fs
.duplicate
2927 def test_Builder(self
) -> None:
2928 """Test the Builder() method"""
2929 env
= self
.TestEnvironment(FOO
= 'xyzzy')
2931 b
= env
.Builder(action
= 'foo')
2932 assert b
is not None, b
2934 b
= env
.Builder(action
= '$FOO')
2935 assert b
is not None, b
2937 b
= env
.Builder(action
= ['$FOO', 'foo'])
2938 assert b
is not None, b
2940 def func(arg
) -> None:
2942 b
= env
.Builder(action
= func
)
2943 assert b
is not None, b
2944 b
= env
.Builder(generator
= func
)
2945 assert b
is not None, b
2947 def test_CacheDir(self
) -> None:
2948 """Test the CacheDir() method"""
2950 test
= TestCmd
.TestCmd(workdir
= '')
2952 test_cachedir
= os
.path
.join(test
.workpath(),'CacheDir')
2953 test_cachedir_config
= os
.path
.join(test_cachedir
, 'config')
2954 test_foo
= os
.path
.join(test
.workpath(), 'foo-cachedir')
2955 test_foo_config
= os
.path
.join(test_foo
,'config')
2956 test_foo1
= os
.path
.join(test
.workpath(), 'foo1-cachedir')
2957 test_foo1_config
= os
.path
.join(test_foo1
, 'config')
2959 env
= self
.TestEnvironment(CD
= test_cachedir
)
2961 env
.CacheDir(test_foo
)
2962 assert env
._CacheDir
_path
== test_foo
, env
._CacheDir
_path
2963 assert os
.path
.isfile(test_foo_config
), "No file %s"%test_foo_config
2966 assert env
._CacheDir
_path
== test_cachedir
, env
._CacheDir
_path
2967 assert os
.path
.isfile(test_cachedir_config
), "No file %s"%test_cachedir_config
2969 # Now verify that -n/-no_exec wil prevent the CacheDir/config from being created
2971 SCons
.Action
.execute_actions
= False
2972 env
.CacheDir(test_foo1
)
2973 assert env
._CacheDir
_path
== test_foo1
, env
._CacheDir
_path
2974 assert not os
.path
.isfile(test_foo1_config
), "No file %s"%test_foo1_config
2977 def test_Clean(self
) -> None:
2978 """Test the Clean() method"""
2979 env
= self
.TestEnvironment(FOO
= 'fff', BAR
= 'bbb')
2981 CT
= SCons
.Environment
.CleanTargets
2983 foo
= env
.arg2nodes('foo')[0]
2984 fff
= env
.arg2nodes('fff')[0]
2986 t
= env
.Clean('foo', 'aaa')
2987 l
= list(map(str, CT
[foo
]))
2988 assert l
== ['aaa'], l
2990 t
= env
.Clean(foo
, ['$BAR', 'ccc'])
2991 l
= list(map(str, CT
[foo
]))
2992 assert l
== ['aaa', 'bbb', 'ccc'], l
2994 eee
= env
.arg2nodes('eee')[0]
2996 t
= env
.Clean('$FOO', 'ddd')
2997 l
= list(map(str, CT
[fff
]))
2998 assert l
== ['ddd'], l
2999 t
= env
.Clean(fff
, [eee
, 'fff'])
3000 l
= list(map(str, CT
[fff
]))
3001 assert l
== ['ddd', 'eee', 'fff'], l
3003 def test_Command(self
) -> None:
3004 """Test the Command() method."""
3006 t
= env
.Command(target
='foo.out', source
=['foo1.in', 'foo2.in'],
3007 action
='buildfoo $target $source')[0]
3008 assert t
.builder
is not None
3009 assert t
.builder
.action
.__class
__.__name
__ == 'CommandAction'
3010 assert t
.builder
.action
.cmd_list
== 'buildfoo $target $source'
3011 assert 'foo1.in' in [x
.get_internal_path() for x
in t
.sources
]
3012 assert 'foo2.in' in [x
.get_internal_path() for x
in t
.sources
]
3014 sub
= env
.fs
.Dir('sub')
3015 t
= env
.Command(target
='bar.out', source
='sub',
3016 action
='buildbar $target $source')[0]
3017 assert 'sub' in [x
.get_internal_path() for x
in t
.sources
]
3019 def testFunc(env
, target
, source
) -> int:
3020 assert str(target
[0]) == 'foo.out'
3021 srcs
= list(map(str, source
))
3022 assert 'foo1.in' in srcs
and 'foo2.in' in srcs
, srcs
3025 # avoid spurious output from action
3026 act
= env
.Action(testFunc
, cmdstr
=None)
3027 t
= env
.Command(target
='foo.out', source
=['foo1.in','foo2.in'],
3029 assert t
.builder
is not None
3030 assert t
.builder
.action
.__class
__.__name
__ == 'FunctionAction'
3032 assert 'foo1.in' in [x
.get_internal_path() for x
in t
.sources
]
3033 assert 'foo2.in' in [x
.get_internal_path() for x
in t
.sources
]
3036 def test2(baz
, x
=x
) -> None:
3038 env
= self
.TestEnvironment(TEST2
= test2
)
3039 t
= env
.Command(target
='baz.out', source
='baz.in',
3040 action
='${TEST2(XYZ)}',
3041 XYZ
='magic word')[0]
3042 assert t
.builder
is not None
3044 assert x
[0] == 'magic word', x
3046 t
= env
.Command(target
='${X}.out', source
='${X}.in',
3049 assert str(t
) == 'xxx.out', str(t
)
3050 assert 'xxx.in' in [x
.get_internal_path() for x
in t
.sources
]
3052 env
= self
.TestEnvironment(source_scanner
= 'should_not_find_this')
3053 t
= env
.Command(target
='file.out', source
='file.in',
3055 source_scanner
= 'fake')[0]
3056 assert t
.builder
.source_scanner
== 'fake', t
.builder
.source_scanner
3058 def test_Configure(self
) -> None:
3059 """Test the Configure() method"""
3060 # Configure() will write to a local temporary file.
3061 test
= TestCmd
.TestCmd(workdir
= '')
3065 os
.chdir(test
.workpath())
3067 env
= self
.TestEnvironment(FOO
= 'xyzzy')
3069 def func(arg
) -> None:
3073 assert c
is not None, c
3076 c
= env
.Configure(custom_tests
= {'foo' : func
, '$FOO' : func
})
3077 assert c
is not None, c
3078 assert hasattr(c
, 'foo')
3079 assert hasattr(c
, 'xyzzy')
3084 def test_Depends(self
) -> None:
3085 """Test the explicit Depends method."""
3086 env
= self
.TestEnvironment(FOO
= 'xxx', BAR
='yyy')
3091 t
= env
.Depends(target
='EnvironmentTest.py',
3092 dependency
='Environment.py')[0]
3093 assert t
.__class
__.__name
__ == 'Entry', t
.__class
__.__name
__
3094 assert t
.get_internal_path() == 'EnvironmentTest.py'
3095 assert len(t
.depends
) == 1
3097 assert d
.__class
__.__name
__ == 'Entry', d
.__class
__.__name
__
3098 assert d
.get_internal_path() == 'Environment.py'
3100 t
= env
.Depends(target
='${FOO}.py', dependency
='${BAR}.py')[0]
3101 assert t
.__class
__.__name
__ == 'File', t
.__class
__.__name
__
3102 assert t
.get_internal_path() == 'xxx.py'
3103 assert len(t
.depends
) == 1
3105 assert d
.__class
__.__name
__ == 'File', d
.__class
__.__name
__
3106 assert d
.get_internal_path() == 'yyy.py'
3108 t
= env
.Depends(target
='dir1', dependency
='dir2')[0]
3109 assert t
.__class
__.__name
__ == 'Dir', t
.__class
__.__name
__
3110 assert t
.get_internal_path() == 'dir1'
3111 assert len(t
.depends
) == 1
3113 assert d
.__class
__.__name
__ == 'Dir', d
.__class
__.__name
__
3114 assert d
.get_internal_path() == 'dir2'
3116 def test_Dir(self
) -> None:
3117 """Test the Dir() method"""
3119 def Dir(self
, name
) -> str:
3120 return 'Dir(%s)' % name
3122 env
= self
.TestEnvironment(FOO
= 'foodir', BAR
= 'bardir')
3126 assert d
== 'Dir(d)', d
3129 assert d
== 'Dir(foodir)', d
3131 d
= env
.Dir('${BAR}_$BAR')
3132 assert d
== 'Dir(bardir_bardir)', d
3134 d
= env
.Dir(['dir1'])
3135 assert d
== ['Dir(dir1)'], d
3137 d
= env
.Dir(['dir1', 'dir2'])
3138 assert d
== ['Dir(dir1)', 'Dir(dir2)'], d
3140 def test_NoClean(self
) -> None:
3141 """Test the NoClean() method"""
3142 env
= self
.TestEnvironment(FOO
='ggg', BAR
='hhh')
3145 t
= env
.NoClean('p_a', 'p_${BAR}b', ['p_c', 'p_d'], 'p_$FOO')
3147 assert t
[0].__class
__.__name
__ == 'Entry', t
[0].__class
__.__name
__
3148 assert t
[0].get_internal_path() == 'p_a'
3150 assert t
[1].__class
__.__name
__ == 'Dir', t
[1].__class
__.__name
__
3151 assert t
[1].get_internal_path() == 'p_hhhb'
3153 assert t
[2].__class
__.__name
__ == 'Entry', t
[2].__class
__.__name
__
3154 assert t
[2].get_internal_path() == 'p_c'
3156 assert t
[3].__class
__.__name
__ == 'File', t
[3].__class
__.__name
__
3157 assert t
[3].get_internal_path() == 'p_d'
3159 assert t
[4].__class
__.__name
__ == 'Entry', t
[4].__class
__.__name
__
3160 assert t
[4].get_internal_path() == 'p_ggg'
3163 def test_Dump(self
) -> None:
3164 """Test the Dump() method"""
3166 env
= self
.TestEnvironment(FOO
= 'foo')
3167 assert env
.Dump('FOO') == "'foo'", env
.Dump('FOO')
3168 assert len(env
.Dump()) > 200, env
.Dump() # no args version
3170 assert env
.Dump('FOO', 'json') == '"foo"' # JSON key version
3172 env_dict
= json
.loads(env
.Dump(format
= 'json'))
3173 assert env_dict
['FOO'] == 'foo' # full JSON version
3176 env
.Dump(format
= 'markdown')
3177 except ValueError as e
:
3178 assert str(e
) == "Unsupported serialization format: markdown."
3180 self
.fail("Did not catch expected ValueError.")
3182 def test_Environment(self
) -> None:
3183 """Test the Environment() method"""
3184 env
= self
.TestEnvironment(FOO
= 'xxx', BAR
= 'yyy')
3186 e2
= env
.Environment(X
= '$FOO', Y
= '$BAR')
3187 assert e2
['X'] == 'xxx', e2
['X']
3188 assert e2
['Y'] == 'yyy', e2
['Y']
3190 def test_Execute(self
) -> None:
3191 """Test the Execute() method"""
3194 def __init__(self
, *args
, **kw
) -> None:
3196 def __call__(self
, target
, source
, env
) -> str:
3197 return "%s executed" % self
.args
3200 env
.Action
= MyAction
3202 result
= env
.Execute("foo")
3203 assert result
== "foo executed", result
3205 def test_Entry(self
) -> None:
3206 """Test the Entry() method"""
3208 def Entry(self
, name
) -> str:
3209 return 'Entry(%s)' % name
3211 env
= self
.TestEnvironment(FOO
= 'fooentry', BAR
= 'barentry')
3215 assert e
== 'Entry(e)', e
3217 e
= env
.Entry('$FOO')
3218 assert e
== 'Entry(fooentry)', e
3220 e
= env
.Entry('${BAR}_$BAR')
3221 assert e
== 'Entry(barentry_barentry)', e
3223 e
= env
.Entry(['entry1'])
3224 assert e
== ['Entry(entry1)'], e
3226 e
= env
.Entry(['entry1', 'entry2'])
3227 assert e
== ['Entry(entry1)', 'Entry(entry2)'], e
3229 def test_File(self
) -> None:
3230 """Test the File() method"""
3232 def File(self
, name
) -> str:
3233 return 'File(%s)' % name
3235 env
= self
.TestEnvironment(FOO
= 'foofile', BAR
= 'barfile')
3239 assert f
== 'File(f)', f
3241 f
= env
.File('$FOO')
3242 assert f
== 'File(foofile)', f
3244 f
= env
.File('${BAR}_$BAR')
3245 assert f
== 'File(barfile_barfile)', f
3247 f
= env
.File(['file1'])
3248 assert f
== ['File(file1)'], f
3250 f
= env
.File(['file1', 'file2'])
3251 assert f
== ['File(file1)', 'File(file2)'], f
3253 def test_FindFile(self
) -> None:
3254 """Test the FindFile() method"""
3255 env
= self
.TestEnvironment(FOO
= 'fff', BAR
= 'bbb')
3257 r
= env
.FindFile('foo', ['no_such_directory'])
3262 def test_Flatten(self
) -> None:
3263 """Test the Flatten() method"""
3265 l
= env
.Flatten([1])
3267 l
= env
.Flatten([1, [2, [3, [4]]]])
3268 assert l
== [1, 2, 3, 4], l
3270 def test_GetBuildPath(self
) -> None:
3271 """Test the GetBuildPath() method."""
3272 env
= self
.TestEnvironment(MAGIC
= 'xyzzy')
3274 p
= env
.GetBuildPath('foo')
3275 assert p
== 'foo', p
3277 p
= env
.GetBuildPath('$MAGIC')
3278 assert p
== 'xyzzy', p
3280 def test_Ignore(self
) -> None:
3281 """Test the explicit Ignore method."""
3282 env
= self
.TestEnvironment(FOO
='yyy', BAR
='zzz')
3288 t
= env
.Ignore(target
='targ.py', dependency
='dep.py')[0]
3289 assert t
.__class
__.__name
__ == 'Entry', t
.__class
__.__name
__
3290 assert t
.get_internal_path() == 'targ.py'
3291 assert len(t
.ignore
) == 1
3293 assert i
.__class
__.__name
__ == 'Entry', i
.__class
__.__name
__
3294 assert i
.get_internal_path() == 'dep.py'
3296 t
= env
.Ignore(target
='$FOO$BAR', dependency
='$BAR$FOO')[0]
3297 assert t
.__class
__.__name
__ == 'File', t
.__class
__.__name
__
3298 assert t
.get_internal_path() == 'yyyzzz'
3299 assert len(t
.ignore
) == 1
3301 assert i
.__class
__.__name
__ == 'File', i
.__class
__.__name
__
3302 assert i
.get_internal_path() == 'zzzyyy'
3304 t
= env
.Ignore(target
='dir1', dependency
='dir2')[0]
3305 assert t
.__class
__.__name
__ == 'Dir', t
.__class
__.__name
__
3306 assert t
.get_internal_path() == 'dir1'
3307 assert len(t
.ignore
) == 1
3309 assert i
.__class
__.__name
__ == 'Dir', i
.__class
__.__name
__
3310 assert i
.get_internal_path() == 'dir2'
3312 def test_Literal(self
) -> None:
3313 """Test the Literal() method"""
3314 env
= self
.TestEnvironment(FOO
='fff', BAR
='bbb')
3315 list = env
.subst_list([env
.Literal('$FOO'), '$BAR'])[0]
3316 assert list == ['$FOO', 'bbb'], list
3317 list = env
.subst_list(['$FOO', env
.Literal('$BAR')])[0]
3318 assert list == ['fff', '$BAR'], list
3320 def test_Local(self
) -> None:
3321 """Test the Local() method."""
3322 env
= self
.TestEnvironment(FOO
='lll')
3324 l
= env
.Local(env
.fs
.File('fff'))
3325 assert str(l
[0]) == 'fff', l
[0]
3327 l
= env
.Local('ggg', '$FOO')
3328 assert str(l
[0]) == 'ggg', l
[0]
3329 assert str(l
[1]) == 'lll', l
[1]
3331 def test_Precious(self
) -> None:
3332 """Test the Precious() method"""
3333 env
= self
.TestEnvironment(FOO
='ggg', BAR
='hhh')
3336 t
= env
.Precious('p_a', 'p_${BAR}b', ['p_c', 'p_d'], 'p_$FOO')
3338 assert t
[0].__class
__.__name
__ == 'Entry', t
[0].__class
__.__name
__
3339 assert t
[0].get_internal_path() == 'p_a'
3340 assert t
[0].precious
3341 assert t
[1].__class
__.__name
__ == 'Dir', t
[1].__class
__.__name
__
3342 assert t
[1].get_internal_path() == 'p_hhhb'
3343 assert t
[1].precious
3344 assert t
[2].__class
__.__name
__ == 'Entry', t
[2].__class
__.__name
__
3345 assert t
[2].get_internal_path() == 'p_c'
3346 assert t
[2].precious
3347 assert t
[3].__class
__.__name
__ == 'File', t
[3].__class
__.__name
__
3348 assert t
[3].get_internal_path() == 'p_d'
3349 assert t
[3].precious
3350 assert t
[4].__class
__.__name
__ == 'Entry', t
[4].__class
__.__name
__
3351 assert t
[4].get_internal_path() == 'p_ggg'
3352 assert t
[4].precious
3354 def test_Pseudo(self
) -> None:
3355 """Test the Pseudo() method"""
3356 env
= self
.TestEnvironment(FOO
='ggg', BAR
='hhh')
3359 t
= env
.Pseudo('p_a', 'p_${BAR}b', ['p_c', 'p_d'], 'p_$FOO')
3361 assert t
[0].__class
__.__name
__ == 'Entry', t
[0].__class
__.__name
__
3362 assert t
[0].get_internal_path() == 'p_a'
3364 assert t
[1].__class
__.__name
__ == 'Dir', t
[1].__class
__.__name
__
3365 assert t
[1].get_internal_path() == 'p_hhhb'
3367 assert t
[2].__class
__.__name
__ == 'Entry', t
[2].__class
__.__name
__
3368 assert t
[2].get_internal_path() == 'p_c'
3370 assert t
[3].__class
__.__name
__ == 'File', t
[3].__class
__.__name
__
3371 assert t
[3].get_internal_path() == 'p_d'
3373 assert t
[4].__class
__.__name
__ == 'Entry', t
[4].__class
__.__name
__
3374 assert t
[4].get_internal_path() == 'p_ggg'
3377 def test_Repository(self
) -> None:
3378 """Test the Repository() method."""
3380 def __init__(self
) -> None:
3382 def Repository(self
, *dirs
) -> None:
3383 self
.list.extend(list(dirs
))
3384 def Dir(self
, name
):
3386 env
= self
.TestEnvironment(FOO
='rrr', BAR
='sss')
3388 env
.Repository('/tmp/foo')
3389 env
.Repository('/tmp/$FOO', '/tmp/$BAR/foo')
3390 expect
= ['/tmp/foo', '/tmp/rrr', '/tmp/sss/foo']
3391 assert env
.fs
.list == expect
, env
.fs
.list
3393 def test_Scanner(self
) -> None:
3394 """Test the Scanner() method"""
3395 def scan(node
, env
, target
, arg
) -> None:
3398 env
= self
.TestEnvironment(FOO
= scan
)
3400 s
= env
.Scanner('foo')
3401 assert s
is not None, s
3403 s
= env
.Scanner(function
= 'foo')
3404 assert s
is not None, s
3407 s
= env
.Scanner('$FOO')
3408 assert s
is not None, s
3410 s
= env
.Scanner(function
= '$FOO')
3411 assert s
is not None, s
3413 def test_SConsignFile(self
) -> None:
3414 """Test the SConsignFile() method"""
3415 import SCons
.SConsign
3418 SConstruct_dir
= os
.sep
+ 'dir'
3420 env
= self
.TestEnvironment(FOO
= 'SConsign',
3421 BAR
= os
.path
.join(os
.sep
, 'File'))
3423 env
.Execute
= lambda action
: None
3428 def capture(name
, dbm_module
, fnames
=fnames
, dbms
=dbms
) -> None:
3430 dbms
.append(dbm_module
)
3432 save_SConsign_File
= SCons
.SConsign
.File
3433 SCons
.SConsign
.File
= capture
3435 env
.SConsignFile('foo')
3436 assert fnames
[-1] == os
.path
.join(os
.sep
, 'dir', 'foo'), fnames
3437 assert dbms
[-1] is None, dbms
3439 env
.SConsignFile('$FOO')
3440 assert fnames
[-1] == os
.path
.join(os
.sep
, 'dir', 'SConsign'), fnames
3441 assert dbms
[-1] is None, dbms
3443 env
.SConsignFile('/$FOO')
3444 assert fnames
[-1] == os
.sep
+ 'SConsign', fnames
3445 assert dbms
[-1] is None, dbms
3447 env
.SConsignFile(os
.sep
+ '$FOO')
3448 assert fnames
[-1] == os
.sep
+ 'SConsign', fnames
3449 assert dbms
[-1] is None, dbms
3451 env
.SConsignFile('$BAR', 'x')
3452 assert fnames
[-1] == os
.path
.join(os
.sep
, 'File'), fnames
3453 assert dbms
[-1] == 'x', dbms
3455 env
.SConsignFile('__$BAR', 7)
3456 assert fnames
[-1] == os
.path
.join(os
.sep
, 'dir', '__', 'File'), fnames
3457 assert dbms
[-1] == 7, dbms
3460 assert fnames
[-1] == os
.path
.join(os
.sep
, 'dir', current_sconsign_filename()), fnames
3461 assert dbms
[-1] is None, dbms
3463 env
.SConsignFile(None)
3464 assert fnames
[-1] is None, fnames
3465 assert dbms
[-1] is None, dbms
3467 SCons
.SConsign
.File
= save_SConsign_File
3469 def test_SideEffect(self
) -> None:
3470 """Test the SideEffect() method"""
3471 env
= self
.TestEnvironment(LIB
='lll', FOO
='fff', BAR
='bbb')
3472 env
.File('mylll.pdb')
3473 env
.Dir('mymmm.pdb')
3475 foo
= env
.Object('foo.obj', 'foo.cpp')[0]
3476 bar
= env
.Object('bar.obj', 'bar.cpp')[0]
3477 s
= env
.SideEffect('mylib.pdb', ['foo.obj', 'bar.obj'])
3478 assert len(s
) == 1, len(s
)
3480 assert s
.__class
__.__name
__ == 'Entry', s
.__class
__.__name
__
3481 assert s
.get_internal_path() == 'mylib.pdb'
3482 assert s
.side_effect
3483 assert foo
.side_effects
== [s
]
3484 assert bar
.side_effects
== [s
]
3486 fff
= env
.Object('fff.obj', 'fff.cpp')[0]
3487 bbb
= env
.Object('bbb.obj', 'bbb.cpp')[0]
3488 s
= env
.SideEffect('my${LIB}.pdb', ['${FOO}.obj', '${BAR}.obj'])
3489 assert len(s
) == 1, len(s
)
3491 assert s
.__class
__.__name
__ == 'File', s
.__class
__.__name
__
3492 assert s
.get_internal_path() == 'mylll.pdb'
3493 assert s
.side_effect
3494 assert fff
.side_effects
== [s
], fff
.side_effects
3495 assert bbb
.side_effects
== [s
], bbb
.side_effects
3497 ggg
= env
.Object('ggg.obj', 'ggg.cpp')[0]
3498 ccc
= env
.Object('ccc.obj', 'ccc.cpp')[0]
3499 s
= env
.SideEffect('mymmm.pdb', ['ggg.obj', 'ccc.obj'])
3500 assert len(s
) == 1, len(s
)
3502 assert s
.__class
__.__name
__ == 'Dir', s
.__class
__.__name
__
3503 assert s
.get_internal_path() == 'mymmm.pdb'
3504 assert s
.side_effect
3505 assert ggg
.side_effects
== [s
], ggg
.side_effects
3506 assert ccc
.side_effects
== [s
], ccc
.side_effects
3508 # Verify that duplicate side effects are not allowed.
3509 before
= len(ggg
.side_effects
)
3510 s
= env
.SideEffect('mymmm.pdb', ggg
)
3511 assert len(s
) == 0, len(s
)
3512 assert len(ggg
.side_effects
) == before
, len(ggg
.side_effects
)
3514 def test_Split(self
) -> None:
3515 """Test the Split() method"""
3516 env
= self
.TestEnvironment(FOO
= 'fff', BAR
= 'bbb')
3517 s
= env
.Split("foo bar")
3518 assert s
== ["foo", "bar"], s
3519 s
= env
.Split("$FOO bar")
3520 assert s
== ["fff", "bar"], s
3521 s
= env
.Split(["foo", "bar"])
3522 assert s
== ["foo", "bar"], s
3523 s
= env
.Split(["foo", "${BAR}-bbb"])
3524 assert s
== ["foo", "bbb-bbb"], s
3525 s
= env
.Split("foo")
3526 assert s
== ["foo"], s
3527 s
= env
.Split("$FOO$BAR")
3528 assert s
== ["fffbbb"], s
3531 def test_Value(self
) -> None:
3532 """Test creating a Value() object
3536 assert v1
.value
== 'a', v1
.value
3539 v2
= env
.Value(value2
)
3540 assert v2
.value
== value2
, v2
.value
3541 assert v2
.value
is value2
, v2
.value
3545 v3
= env
.Value('c', 'build-c')
3546 assert v3
.value
== 'c', v3
.value
3548 v4
= env
.Value(b
'\x00\x0F', name
='name')
3549 assert v4
.value
== b
'\x00\x0F', v4
.value
3550 assert v4
.name
== 'name', v4
.name
3553 def test_Environment_global_variable(self
) -> None:
3554 """Test setting Environment variable to an Environment.Base subclass"""
3555 class MyEnv(SCons
.Environment
.Base
):
3556 def xxx(self
, string
):
3557 return self
.subst(string
)
3559 SCons
.Environment
.Environment
= MyEnv
3561 env
= SCons
.Environment
.Environment(FOO
= 'foo')
3563 f
= env
.subst('$FOO')
3564 assert f
== 'foo', f
3567 assert f
== 'foo', f
3569 def test_bad_keywords(self
) -> None:
3570 """Test trying to use reserved keywords in an Environment"""
3573 env
= self
.TestEnvironment(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',
3582 bad_msg
= '%s is not reserved, but got omitted; see Environment.construction_var_name_ok'
3583 added
.append('INIT')
3584 for x
in self
.reserved_variables
:
3585 assert x
not in env
, env
[x
]
3587 assert x
in env
, bad_msg
% x
3589 env
.Append(TARGETS
= 'targets',
3590 SOURCES
= 'sources',
3593 CHANGED_SOURCES
= 'changed_sources',
3594 CHANGED_TARGETS
= 'changed_targets',
3595 UNCHANGED_SOURCES
= 'unchanged_sources',
3596 UNCHANGED_TARGETS
= 'unchanged_targets',
3598 added
.append('APPEND')
3599 for x
in self
.reserved_variables
:
3600 assert x
not in env
, env
[x
]
3602 assert x
in env
, bad_msg
% x
3604 env
.AppendUnique(TARGETS
= 'targets',
3605 SOURCES
= 'sources',
3608 CHANGED_SOURCES
= 'changed_sources',
3609 CHANGED_TARGETS
= 'changed_targets',
3610 UNCHANGED_SOURCES
= 'unchanged_sources',
3611 UNCHANGED_TARGETS
= 'unchanged_targets',
3612 APPENDUNIQUE
= 'appendunique')
3613 added
.append('APPENDUNIQUE')
3614 for x
in self
.reserved_variables
:
3615 assert x
not in env
, env
[x
]
3617 assert x
in env
, bad_msg
% x
3619 env
.Prepend(TARGETS
= 'targets',
3620 SOURCES
= 'sources',
3623 CHANGED_SOURCES
= 'changed_sources',
3624 CHANGED_TARGETS
= 'changed_targets',
3625 UNCHANGED_SOURCES
= 'unchanged_sources',
3626 UNCHANGED_TARGETS
= 'unchanged_targets',
3627 PREPEND
= 'prepend')
3628 added
.append('PREPEND')
3629 for x
in self
.reserved_variables
:
3630 assert x
not in env
, env
[x
]
3632 assert x
in env
, bad_msg
% x
3634 env
.Prepend(TARGETS
= 'targets',
3635 SOURCES
= 'sources',
3638 CHANGED_SOURCES
= 'changed_sources',
3639 CHANGED_TARGETS
= 'changed_targets',
3640 UNCHANGED_SOURCES
= 'unchanged_sources',
3641 UNCHANGED_TARGETS
= 'unchanged_targets',
3642 PREPENDUNIQUE
= 'prependunique')
3643 added
.append('PREPENDUNIQUE')
3644 for x
in self
.reserved_variables
:
3645 assert x
not in env
, env
[x
]
3647 assert x
in env
, bad_msg
% x
3649 env
.Replace(TARGETS
= 'targets',
3650 SOURCES
= 'sources',
3653 CHANGED_SOURCES
= 'changed_sources',
3654 CHANGED_TARGETS
= 'changed_targets',
3655 UNCHANGED_SOURCES
= 'unchanged_sources',
3656 UNCHANGED_TARGETS
= 'unchanged_targets',
3657 REPLACE
= 'replace')
3658 added
.append('REPLACE')
3659 for x
in self
.reserved_variables
:
3660 assert x
not in env
, env
[x
]
3662 assert x
in env
, bad_msg
% x
3664 copy
= env
.Clone(TARGETS
= 'targets',
3665 SOURCES
= 'sources',
3668 CHANGED_SOURCES
= 'changed_sources',
3669 CHANGED_TARGETS
= 'changed_targets',
3670 UNCHANGED_SOURCES
= 'unchanged_sources',
3671 UNCHANGED_TARGETS
= 'unchanged_targets',
3673 for x
in self
.reserved_variables
:
3674 assert x
not in copy
, env
[x
]
3675 for x
in added
+ ['COPY']:
3676 assert x
in copy
, bad_msg
% x
3678 over
= env
.Override({'TARGETS' : 'targets',
3679 'SOURCES' : 'sources',
3680 'SOURCE' : 'source',
3681 'TARGET' : 'target',
3682 'CHANGED_SOURCES' : 'changed_sources',
3683 'CHANGED_TARGETS' : 'changed_targets',
3684 'UNCHANGED_SOURCES' : 'unchanged_sources',
3685 'UNCHANGED_TARGETS' : 'unchanged_targets',
3686 'OVERRIDE' : 'override'})
3687 for x
in self
.reserved_variables
:
3688 assert x
not in over
, over
[x
]
3689 for x
in added
+ ['OVERRIDE']:
3690 assert x
in over
, bad_msg
% x
3692 def test_parse_flags(self
) -> None:
3693 """Test the Base class parse_flags argument"""
3694 # all we have to show is that it gets to MergeFlags internally
3695 env
= Environment(tools
=[], parse_flags
= '-X')
3696 assert env
['CCFLAGS'] == ['-X'], env
['CCFLAGS']
3698 env
= Environment(tools
=[], CCFLAGS
=None, parse_flags
= '-Y')
3699 assert env
['CCFLAGS'] == ['-Y'], env
['CCFLAGS']
3701 env
= Environment(tools
=[], CPPDEFINES
='FOO', parse_flags
='-std=c99 -X -DBAR')
3702 assert env
['CFLAGS'] == ['-std=c99'], env
['CFLAGS']
3703 assert env
['CCFLAGS'] == ['-X'], env
['CCFLAGS']
3704 self
.assertEqual(list(env
['CPPDEFINES']), ['FOO', 'BAR'])
3706 def test_clone_parse_flags(self
) -> None:
3707 """Test the env.Clone() parse_flags argument"""
3708 # all we have to show is that it gets to MergeFlags internally
3709 env
= Environment(tools
= [])
3710 env2
= env
.Clone(parse_flags
= '-X')
3711 assert 'CCFLAGS' not in env
3712 assert env2
['CCFLAGS'] == ['-X'], env2
['CCFLAGS']
3714 env
= Environment(tools
= [], CCFLAGS
=None)
3715 env2
= env
.Clone(parse_flags
= '-Y')
3716 assert env
['CCFLAGS'] is None, env
['CCFLAGS']
3717 assert env2
['CCFLAGS'] == ['-Y'], env2
['CCFLAGS']
3719 env
= Environment(tools
= [], CPPDEFINES
= 'FOO')
3720 env2
= env
.Clone(parse_flags
= '-std=c99 -X -DBAR')
3721 assert 'CFLAGS' not in env
3722 assert env2
['CFLAGS'] == ['-std=c99'], env2
['CFLAGS']
3723 assert 'CCFLAGS' not in env
3724 assert env2
['CCFLAGS'] == ['-X'], env2
['CCFLAGS']
3725 assert env
['CPPDEFINES'] == 'FOO', env
['CPPDEFINES']
3726 self
.assertEqual(list(env2
['CPPDEFINES']), ['FOO','BAR'])
3729 class OverrideEnvironmentTestCase(unittest
.TestCase
,TestEnvironmentFixture
):
3731 def setUp(self
) -> None:
3733 env
._dict
= {'XXX' : 'x', 'YYY' : 'y'}
3734 def verify_value(env
, key
, value
, *args
, **kwargs
) -> None:
3735 """Verifies that key is value on the env this is called with."""
3736 assert env
[key
] == value
3737 env
.AddMethod(verify_value
)
3738 env2
= OverrideEnvironment(env
, {'XXX' : 'x2'})
3739 env3
= OverrideEnvironment(env2
, {'XXX' : 'x3', 'YYY' : 'y3', 'ZZZ' : 'z3'})
3740 self
.envs
= [ env
, env2
, env3
]
3742 def checkpath(self
, node
, expect
):
3743 return str(node
) == os
.path
.normpath(expect
)
3745 def test___init__(self
) -> None:
3746 """Test OverrideEnvironment initialization"""
3747 env
, env2
, env3
= self
.envs
3748 assert env
['XXX'] == 'x', env
['XXX']
3749 assert env2
['XXX'] == 'x2', env2
['XXX']
3750 assert env3
['XXX'] == 'x3', env3
['XXX']
3751 assert env
['YYY'] == 'y', env
['YYY']
3752 assert env2
['YYY'] == 'y', env2
['YYY']
3753 assert env3
['YYY'] == 'y3', env3
['YYY']
3755 def test___delitem__(self
) -> None:
3756 """Test deleting variables from an OverrideEnvironment"""
3757 env
, env2
, env3
= self
.envs
3760 assert 'XXX' not in env
, "env has XXX?"
3761 assert 'XXX' not in env2
, "env2 has XXX?"
3762 assert 'XXX' not in env3
, "env3 has XXX?"
3765 assert 'YYY' not in env
, "env has YYY?"
3766 assert 'YYY' not in env2
, "env2 has YYY?"
3767 assert 'YYY' not in env3
, "env3 has YYY?"
3770 assert 'ZZZ' not in env
, "env has ZZZ?"
3771 assert 'ZZZ' not in env2
, "env2 has ZZZ?"
3772 assert 'ZZZ' not in env3
, "env3 has ZZZ?"
3774 def test_get(self
) -> None:
3775 """Test the OverrideEnvironment get() method"""
3776 env
, env2
, env3
= self
.envs
3777 assert env
.get('XXX') == 'x', env
.get('XXX')
3778 assert env2
.get('XXX') == 'x2', env2
.get('XXX')
3779 assert env3
.get('XXX') == 'x3', env3
.get('XXX')
3780 assert env
.get('YYY') == 'y', env
.get('YYY')
3781 assert env2
.get('YYY') == 'y', env2
.get('YYY')
3782 assert env3
.get('YYY') == 'y3', env3
.get('YYY')
3783 assert env
.get('ZZZ') is None, env
.get('ZZZ')
3784 assert env2
.get('ZZZ') is None, env2
.get('ZZZ')
3785 assert env3
.get('ZZZ') == 'z3', env3
.get('ZZZ')
3787 def test_contains(self
) -> None:
3788 """Test the OverrideEnvironment __contains__() method"""
3789 env
, env2
, env3
= self
.envs
3790 assert 'XXX' in env
, 'XXX' in env
3791 assert 'XXX' in env2
, 'XXX' in env2
3792 assert 'XXX' in env3
, 'XXX' in env3
3793 assert 'YYY' in env
, 'YYY' in env
3794 assert 'YYY' in env2
, 'YYY' in env2
3795 assert 'YYY' in env3
, 'YYY' in env3
3796 assert 'ZZZ' not in env
, 'ZZZ' in env
3797 assert 'ZZZ' not in env2
, 'ZZZ' in env2
3798 assert 'ZZZ' in env3
, 'ZZZ' in env3
3800 def test_Dictionary(self
) -> None:
3801 """Test the OverrideEnvironment Dictionary() method"""
3802 env
, env2
, env3
= self
.envs
3803 # nothing overrriden
3804 items
= env
.Dictionary()
3805 assert items
== {'XXX' : 'x', 'YYY' : 'y'}, items
3806 # env2 overrides XXX, YYY unchanged
3807 items
= env2
.Dictionary()
3808 assert items
== {'XXX' : 'x2', 'YYY' : 'y'}, items
3809 # env3 overrides XXX, YYY, adds ZZZ
3810 items
= env3
.Dictionary()
3811 assert items
== {'XXX' : 'x3', 'YYY' : 'y3', 'ZZZ' : 'z3'}, items
3812 # test one-arg and multi-arg Dictionary
3813 assert env3
.Dictionary('XXX') == 'x3', env3
.Dictionary('XXX')
3814 xxx
, yyy
= env2
.Dictionary('XXX', 'YYY')
3815 assert xxx
== 'x2', xxx
3816 assert yyy
== 'y', yyy
3818 assert 'XXX' not in env3
.Dictionary()
3819 assert 'XXX' not in env2
.Dictionary()
3820 assert 'XXX' not in env
.Dictionary()
3822 def test_items(self
) -> None:
3823 """Test the OverrideEnvironment items() method"""
3824 env
, env2
, env3
= self
.envs
3825 items
= sorted(env
.items())
3826 assert items
== [('XXX', 'x'), ('YYY', 'y')], items
3827 items
= sorted(env2
.items())
3828 assert items
== [('XXX', 'x2'), ('YYY', 'y')], items
3829 items
= sorted(env3
.items())
3830 assert items
== [('XXX', 'x3'), ('YYY', 'y3'), ('ZZZ', 'z3')], items
3832 def test_keys(self
) -> None:
3833 """Test the OverrideEnvironment keys() method"""
3834 env
, env2
, env3
= self
.envs
3835 keys
= sorted(env
.keys())
3836 assert keys
== ['XXX', 'YYY'], keys
3837 keys
= sorted(env2
.keys())
3838 assert keys
== ['XXX', 'YYY'], keys
3839 keys
= sorted(env3
.keys())
3840 assert keys
== ['XXX', 'YYY', 'ZZZ'], keys
3842 def test_values(self
) -> None:
3843 """Test the OverrideEnvironment values() method"""
3844 env
, env2
, env3
= self
.envs
3845 values
= sorted(env
.values())
3846 assert values
== ['x', 'y'], values
3847 values
= sorted(env2
.values())
3848 assert values
== ['x2', 'y'], values
3849 values
= sorted(env3
.values())
3850 assert values
== ['x3', 'y3', 'z3'], values
3852 def test_setdefault(self
) -> None:
3853 """Test the OverrideEnvironment setdefault() method."""
3854 env
, env2
, env3
= self
.envs
3855 # does not set for existing key
3856 assert env2
.setdefault('XXX', 'z') == 'x2', env2
['XXX']
3857 # set/return using default for non-existing key
3858 assert env2
.setdefault('ZZZ', 'z2') == 'z2', env2
['ZZZ']
3859 # set did not leak through to base env
3860 assert 'ZZZ' not in env
3862 def test_gvars(self
) -> None:
3863 """Test the OverrideEnvironment gvars() method"""
3864 env
, env2
, env3
= self
.envs
3866 assert gvars
== {'XXX' : 'x', 'YYY' : 'y'}, gvars
3867 gvars
= env2
.gvars()
3868 assert gvars
== {'XXX' : 'x', 'YYY' : 'y'}, gvars
3869 gvars
= env3
.gvars()
3870 assert gvars
== {'XXX' : 'x', 'YYY' : 'y'}, gvars
3872 def test_lvars(self
) -> None:
3873 """Test the OverrideEnvironment lvars() method"""
3874 env
, env2
, env3
= self
.envs
3876 assert lvars
== {}, lvars
3877 lvars
= env2
.lvars()
3878 assert lvars
== {'XXX' : 'x2'}, lvars
3879 lvars
= env3
.lvars()
3880 assert lvars
== {'XXX' : 'x3', 'YYY' : 'y3', 'ZZZ' : 'z3'}, lvars
3882 def test_Replace(self
) -> None:
3883 """Test the OverrideEnvironment Replace() method"""
3884 env
, env2
, env3
= self
.envs
3885 assert env
['XXX'] == 'x', env
['XXX']
3886 assert env2
['XXX'] == 'x2', env2
['XXX']
3887 assert env3
['XXX'] == 'x3', env3
['XXX']
3888 assert env
['YYY'] == 'y', env
['YYY']
3889 assert env2
['YYY'] == 'y', env2
['YYY']
3890 assert env3
['YYY'] == 'y3', env3
['YYY']
3892 env
.Replace(YYY
= 'y4')
3894 assert env
['XXX'] == 'x', env
['XXX']
3895 assert env2
['XXX'] == 'x2', env2
['XXX']
3896 assert env3
['XXX'] == 'x3', env3
['XXX']
3897 assert env
['YYY'] == 'y4', env
['YYY']
3898 assert env2
['YYY'] == 'y4', env2
['YYY']
3899 assert env3
['YYY'] == 'y3', env3
['YYY']
3901 # Tests a number of Base methods through an OverrideEnvironment to
3902 # make sure they handle overridden constructionv variables properly.
3904 # The following Base methods also call self.subst(), and so could
3905 # theoretically be subject to problems with evaluating overridden
3906 # variables, but they're never really called that way in the rest
3907 # of our code, so we won't worry about them (at least for now):
3923 # It's unlikely Clone() will ever be called this way, so let the
3924 # other methods test that handling overridden values works.
3925 #def test_Clone(self):
3926 # """Test the OverrideEnvironment Clone() method"""
3929 def test_FindIxes(self
) -> None:
3930 """Test the OverrideEnvironment FindIxes() method"""
3931 env
, env2
, env3
= self
.envs
3932 x
= env
.FindIxes(['xaaay'], 'XXX', 'YYY')
3933 assert x
== 'xaaay', x
3934 x
= env2
.FindIxes(['x2aaay'], 'XXX', 'YYY')
3935 assert x
== 'x2aaay', x
3936 x
= env3
.FindIxes(['x3aaay3'], 'XXX', 'YYY')
3937 assert x
== 'x3aaay3', x
3939 def test_ReplaceIxes(self
) -> None:
3940 """Test the OverrideEnvironment ReplaceIxes() method"""
3941 env
, env2
, env3
= self
.envs
3942 x
= env
.ReplaceIxes('xaaay', 'XXX', 'YYY', 'YYY', 'XXX')
3943 assert x
== 'yaaax', x
3944 x
= env2
.ReplaceIxes('x2aaay', 'XXX', 'YYY', 'YYY', 'XXX')
3945 assert x
== 'yaaax2', x
3946 x
= env3
.ReplaceIxes('x3aaay3', 'XXX', 'YYY', 'YYY', 'XXX')
3947 assert x
== 'y3aaax3', x
3949 # It's unlikely WhereIs() will ever be called this way, so let the
3950 # other methods test that handling overridden values works.
3951 #def test_WhereIs(self):
3952 # """Test the OverrideEnvironment WhereIs() method"""
3955 def test_PseudoBuilderInherits(self
) -> None:
3956 """Test that pseudo-builders inherit the overrided values."""
3957 env
, env2
, env3
= self
.envs
3958 env
.verify_value('XXX', 'x')
3959 env2
.verify_value('XXX', 'x2')
3960 env3
.verify_value('XXX', 'x3')
3962 def test_Dir(self
) -> None:
3963 """Test the OverrideEnvironment Dir() method"""
3964 env
, env2
, env3
= self
.envs
3965 x
= env
.Dir('ddir/$XXX')
3966 assert self
.checkpath(x
, 'ddir/x'), str(x
)
3967 x
= env2
.Dir('ddir/$XXX')
3968 assert self
.checkpath(x
, 'ddir/x2'), str(x
)
3969 x
= env3
.Dir('ddir/$XXX')
3970 assert self
.checkpath(x
, 'ddir/x3'), str(x
)
3972 def test_Entry(self
) -> None:
3973 """Test the OverrideEnvironment Entry() method"""
3974 env
, env2
, env3
= self
.envs
3975 x
= env
.Entry('edir/$XXX')
3976 assert self
.checkpath(x
, 'edir/x'), str(x
)
3977 x
= env2
.Entry('edir/$XXX')
3978 assert self
.checkpath(x
, 'edir/x2'), str(x
)
3979 x
= env3
.Entry('edir/$XXX')
3980 assert self
.checkpath(x
, 'edir/x3'), str(x
)
3982 def test_File(self
) -> None:
3983 """Test the OverrideEnvironment File() method"""
3984 env
, env2
, env3
= self
.envs
3985 x
= env
.File('fdir/$XXX')
3986 assert self
.checkpath(x
, 'fdir/x'), str(x
)
3987 x
= env2
.File('fdir/$XXX')
3988 assert self
.checkpath(x
, 'fdir/x2'), str(x
)
3989 x
= env3
.File('fdir/$XXX')
3990 assert self
.checkpath(x
, 'fdir/x3'), str(x
)
3992 def test_Split(self
) -> None:
3993 """Test the OverrideEnvironment Split() method"""
3994 env
, env2
, env3
= self
.envs
3995 env
['AAA'] = '$XXX $YYY $ZZZ'
3996 x
= env
.Split('$AAA')
3997 assert x
== ['x', 'y'], x
3998 x
= env2
.Split('$AAA')
3999 assert x
== ['x2', 'y'], x
4000 x
= env3
.Split('$AAA')
4001 assert x
== ['x3', 'y3', 'z3'], x
4003 def test_parse_flags(self
) -> None:
4004 """Test the OverrideEnvironment parse_flags argument"""
4005 # all we have to show is that it gets to MergeFlags internally
4006 env
= SubstitutionEnvironment()
4007 env2
= env
.Override({'parse_flags' : '-X'})
4008 assert 'CCFLAGS' not in env
4009 assert env2
['CCFLAGS'] == ['-X'], env2
['CCFLAGS']
4011 env
= SubstitutionEnvironment(CCFLAGS
=None)
4012 env2
= env
.Override({'parse_flags' : '-Y'})
4013 assert env
['CCFLAGS'] is None, env
['CCFLAGS']
4014 assert env2
['CCFLAGS'] == ['-Y'], env2
['CCFLAGS']
4016 env
= SubstitutionEnvironment(CPPDEFINES
='FOO')
4017 env2
= env
.Override({'parse_flags': '-std=c99 -X -DBAR'})
4018 assert 'CFLAGS' not in env
4019 assert env2
['CFLAGS'] == ['-std=c99'], env2
['CFLAGS']
4020 assert 'CCFLAGS' not in env
4021 assert env2
['CCFLAGS'] == ['-X'], env2
['CCFLAGS']
4022 # make sure they are independent
4023 self
.assertIsNot(env
['CPPDEFINES'], env2
['CPPDEFINES'])
4024 assert env
['CPPDEFINES'] == 'FOO', env
['CPPDEFINES']
4025 self
.assertEqual(list(env2
['CPPDEFINES']), ['FOO','BAR'])
4028 class NoSubstitutionProxyTestCase(unittest
.TestCase
,TestEnvironmentFixture
):
4030 def test___init__(self
) -> None:
4031 """Test NoSubstitutionProxy initialization"""
4032 env
= self
.TestEnvironment(XXX
= 'x', YYY
= 'y')
4033 assert env
['XXX'] == 'x', env
['XXX']
4034 assert env
['YYY'] == 'y', env
['YYY']
4036 proxy
= NoSubstitutionProxy(env
)
4037 assert proxy
['XXX'] == 'x', proxy
['XXX']
4038 assert proxy
['YYY'] == 'y', proxy
['YYY']
4040 def test_attributes(self
) -> None:
4041 """Test getting and setting NoSubstitutionProxy attributes"""
4043 setattr(env
, 'env_attr', 'value1')
4045 proxy
= NoSubstitutionProxy(env
)
4046 setattr(proxy
, 'proxy_attr', 'value2')
4048 x
= getattr(env
, 'env_attr')
4049 assert x
== 'value1', x
4050 x
= getattr(proxy
, 'env_attr')
4051 assert x
== 'value1', x
4053 x
= getattr(env
, 'proxy_attr')
4054 assert x
== 'value2', x
4055 x
= getattr(proxy
, 'proxy_attr')
4056 assert x
== 'value2', x
4058 def test_subst(self
) -> None:
4059 """Test the NoSubstitutionProxy.subst() method"""
4060 env
= self
.TestEnvironment(XXX
= 'x', YYY
= 'y')
4061 assert env
['XXX'] == 'x', env
['XXX']
4062 assert env
['YYY'] == 'y', env
['YYY']
4064 proxy
= NoSubstitutionProxy(env
)
4065 assert proxy
['XXX'] == 'x', proxy
['XXX']
4066 assert proxy
['YYY'] == 'y', proxy
['YYY']
4068 x
= env
.subst('$XXX')
4070 x
= proxy
.subst('$XXX')
4071 assert x
== '$XXX', x
4073 x
= proxy
.subst('$YYY', raw
=7, target
=None, source
=None,
4075 extra_meaningless_keyword_argument
=None)
4076 assert x
== '$YYY', x
4078 def test_subst_kw(self
) -> None:
4079 """Test the NoSubstitutionProxy.subst_kw() method"""
4080 env
= self
.TestEnvironment(XXX
= 'x', YYY
= 'y')
4081 assert env
['XXX'] == 'x', env
['XXX']
4082 assert env
['YYY'] == 'y', env
['YYY']
4084 proxy
= NoSubstitutionProxy(env
)
4085 assert proxy
['XXX'] == 'x', proxy
['XXX']
4086 assert proxy
['YYY'] == 'y', proxy
['YYY']
4088 x
= env
.subst_kw({'$XXX':'$YYY'})
4089 assert x
== {'x':'y'}, x
4090 x
= proxy
.subst_kw({'$XXX':'$YYY'})
4091 assert x
== {'$XXX':'$YYY'}, x
4093 def test_subst_list(self
) -> None:
4094 """Test the NoSubstitutionProxy.subst_list() method"""
4095 env
= self
.TestEnvironment(XXX
= 'x', YYY
= 'y')
4096 assert env
['XXX'] == 'x', env
['XXX']
4097 assert env
['YYY'] == 'y', env
['YYY']
4099 proxy
= NoSubstitutionProxy(env
)
4100 assert proxy
['XXX'] == 'x', proxy
['XXX']
4101 assert proxy
['YYY'] == 'y', proxy
['YYY']
4103 x
= env
.subst_list('$XXX')
4104 assert x
== [['x']], x
4105 x
= proxy
.subst_list('$XXX')
4108 x
= proxy
.subst_list('$YYY', raw
=0, target
=None, source
=None, conv
=None)
4111 def test_subst_target_source(self
) -> None:
4112 """Test the NoSubstitutionProxy.subst_target_source() method"""
4113 env
= self
.TestEnvironment(XXX
= 'x', YYY
= 'y')
4114 assert env
['XXX'] == 'x', env
['XXX']
4115 assert env
['YYY'] == 'y', env
['YYY']
4117 proxy
= NoSubstitutionProxy(env
)
4118 assert proxy
['XXX'] == 'x', proxy
['XXX']
4119 assert proxy
['YYY'] == 'y', proxy
['YYY']
4121 args
= ('$XXX $TARGET $SOURCE $YYY',)
4122 kw
= {'target' : DummyNode('ttt'), 'source' : DummyNode('sss')}
4123 x
= env
.subst_target_source(*args
, **kw
)
4124 assert x
== 'x ttt sss y', x
4125 x
= proxy
.subst_target_source(*args
, **kw
)
4126 assert x
== ' ttt sss ', x
4128 class EnvironmentVariableTestCase(unittest
.TestCase
):
4130 def test_is_valid_construction_var(self
) -> None:
4131 """Testing is_valid_construction_var()"""
4132 r
= is_valid_construction_var("_a")
4133 assert r
is not None, r
4134 r
= is_valid_construction_var("z_")
4135 assert r
is not None, r
4136 r
= is_valid_construction_var("X_")
4137 assert r
is not None, r
4138 r
= is_valid_construction_var("2a")
4140 r
= is_valid_construction_var("a2_")
4141 assert r
is not None, r
4142 r
= is_valid_construction_var("/")
4144 r
= is_valid_construction_var("_/")
4146 r
= is_valid_construction_var("a/")
4148 r
= is_valid_construction_var(".b")
4150 r
= is_valid_construction_var("_.b")
4152 r
= is_valid_construction_var("b1._")
4154 r
= is_valid_construction_var("-b")
4156 r
= is_valid_construction_var("_-b")
4158 r
= is_valid_construction_var("b1-_")
4163 if __name__
== "__main__":
4168 # indent-tabs-mode:nil
4170 # vim: set expandtab tabstop=4 shiftwidth=4: