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
,
42 from SCons
.Util
import CLVar
43 from SCons
.SConsign
import current_sconsign_filename
46 def diff_env(env1
, env2
):
50 for k
in list(env1
._dict
.keys()) + list(env2
._dict
.keys()):
52 for k
in sorted(d
.keys()):
55 if env1
[k
] != env2
[k
]:
56 s1
= s1
+ " " + repr(k
) + " : " + repr(env1
[k
]) + "\n"
57 s2
= s2
+ " " + repr(k
) + " : " + repr(env2
[k
]) + "\n"
59 s1
= s1
+ " " + repr(k
) + " : " + repr(env1
[k
]) + "\n"
61 s2
= s2
+ " " + repr(k
) + " : " + repr(env2
[k
]) + "\n"
66 def diff_dict(d1
, d2
):
70 for k
in list(d1
.keys()) + list(d2
.keys()):
72 for k
in sorted(d
.keys()):
76 s1
= s1
+ " " + repr(k
) + " : " + repr(d1
[k
]) + "\n"
77 s2
= s2
+ " " + repr(k
) + " : " + repr(d2
[k
]) + "\n"
79 s1
= s1
+ " " + repr(k
) + " : " + repr(d1
[k
]) + "\n"
81 s2
= s2
+ " " + repr(k
) + " : " + repr(d2
[k
]) + "\n"
89 class Builder(SCons
.Builder
.BuilderBase
):
90 """A dummy Builder class for testing purposes. "Building"
91 a target is simply setting a value in the dictionary.
93 def __init__(self
, name
= None) -> None:
96 def __call__(self
, env
, target
=None, source
=None, **kw
) -> None:
98 called_it
['target'] = target
99 called_it
['source'] = source
102 def execute(self
, target
= None, **kw
) -> None:
111 """A dummy Scanner class for testing purposes. "Scanning"
112 a target is simply setting a value in the dictionary.
114 def __init__(self
, name
, skeys
=[]) -> None:
118 def __call__(self
, filename
) -> None:
120 scanned_it
[filename
] = 1
122 def __eq__(self
, other
):
124 return self
.__dict
__ == other
.__dict
__
125 except AttributeError:
128 def get_skeys(self
, env
):
131 def __str__(self
) -> str:
136 def __init__(self
, name
) -> None:
138 def __str__(self
) -> str:
142 def get_subst_proxy(self
):
145 def test_tool( env
) -> None:
146 env
['_F77INCFLAGS'] = '${_concat(INCPREFIX, F77PATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE, affect_signature=False)}'
148 class TestEnvironmentFixture
:
149 def TestEnvironment(self
, *args
, **kw
):
150 if not kw
or 'tools' not in kw
:
151 kw
['tools'] = [test_tool
]
152 default_keys
= { 'CC' : 'cc',
153 'CCFLAGS' : '-DNDEBUG',
154 'ENV' : { 'TMP' : '/tmp' } }
155 for key
, value
in default_keys
.items():
158 if 'BUILDERS' not in kw
:
159 static_obj
= SCons
.Builder
.Builder(action
= {},
163 kw
['BUILDERS'] = {'Object' : static_obj
}
164 static_obj
.add_action('.cpp', 'fake action')
166 env
= Environment(*args
, **kw
)
169 class SubstitutionTestCase(unittest
.TestCase
):
171 def test___init__(self
) -> None:
172 """Test initializing a SubstitutionEnvironment."""
173 env
= SubstitutionEnvironment()
174 assert '__env__' not in env
176 def test___cmp__(self
) -> None:
177 """Test comparing SubstitutionEnvironments."""
178 env1
= SubstitutionEnvironment(XXX
= 'x')
179 env2
= SubstitutionEnvironment(XXX
= 'x')
180 env3
= SubstitutionEnvironment(XXX
= 'xxx')
181 env4
= SubstitutionEnvironment(XXX
= 'x', YYY
= 'x')
187 def test___delitem__(self
) -> None:
188 """Test deleting a variable from a SubstitutionEnvironment."""
189 env1
= SubstitutionEnvironment(XXX
= 'x', YYY
= 'y')
190 env2
= SubstitutionEnvironment(XXX
= 'x')
194 def test___getitem__(self
) -> None:
195 """Test fetching a variable from a SubstitutionEnvironment."""
196 env
= SubstitutionEnvironment(XXX
= 'x')
197 assert env
['XXX'] == 'x', env
['XXX']
199 def test___setitem__(self
) -> None:
200 """Test setting a variable in a SubstitutionEnvironment."""
201 env1
= SubstitutionEnvironment(XXX
= 'x')
202 env2
= SubstitutionEnvironment(XXX
= 'x', YYY
= 'y')
206 def test_get(self
) -> None:
207 """Test the SubstitutionEnvironment get() method."""
208 env
= SubstitutionEnvironment(XXX
= 'x')
209 assert env
.get('XXX') == 'x', env
.get('XXX')
210 assert env
.get('YYY') is None, env
.get('YYY')
212 def test_contains(self
) -> None:
213 """Test the SubstitutionEnvironment __contains__() method."""
214 env
= SubstitutionEnvironment(XXX
= 'x')
216 assert 'YYY' not in env
218 def test_keys(self
) -> None:
219 """Test the SubstitutionEnvironment keys() method."""
220 testdata
= {'XXX': 'x', 'YYY': 'y'}
221 env
= SubstitutionEnvironment(**testdata
)
222 keys
= list(env
.keys())
223 assert len(keys
) == 2, keys
224 for k
in testdata
.keys():
225 assert k
in keys
, keys
227 def test_values(self
) -> None:
228 """Test the SubstitutionEnvironment values() method."""
229 testdata
= {'XXX': 'x', 'YYY': 'y'}
230 env
= SubstitutionEnvironment(**testdata
)
231 values
= list(env
.values())
232 assert len(values
) == 2, values
233 for v
in testdata
.values():
234 assert v
in values
, values
236 def test_items(self
) -> None:
237 """Test the SubstitutionEnvironment items() method."""
238 testdata
= {'XXX': 'x', 'YYY': 'y'}
239 env
= SubstitutionEnvironment(**testdata
)
240 items
= list(env
.items())
241 assert len(items
) == 2, items
242 for k
, v
in testdata
.items():
243 assert (k
, v
) in items
, items
245 def test_setdefault(self
) -> None:
246 """Test the SubstitutionEnvironment setdefault() method."""
247 env
= SubstitutionEnvironment(XXX
= 'x')
248 assert env
.setdefault('XXX', 'z') == 'x', env
['XXX']
249 assert env
.setdefault('YYY', 'y') == 'y', env
['YYY']
252 def test_arg2nodes(self
) -> None:
253 """Test the arg2nodes method."""
254 env
= SubstitutionEnvironment()
256 class X(SCons
.Node
.Node
):
258 def Factory(name
, directory
= None, create
: int = 1, dict=dict, X
=X
):
261 dict[name
].name
= name
264 nodes
= env
.arg2nodes("Util.py UtilTests.py", Factory
)
265 assert len(nodes
) == 1, nodes
266 assert isinstance(nodes
[0], X
)
267 assert nodes
[0].name
== "Util.py UtilTests.py", nodes
[0].name
269 nodes
= env
.arg2nodes(["Util.py", "UtilTests.py"], Factory
)
270 assert len(nodes
) == 2, nodes
271 assert isinstance(nodes
[0], X
)
272 assert isinstance(nodes
[1], X
)
273 assert nodes
[0].name
== "Util.py", nodes
[0].name
274 assert nodes
[1].name
== "UtilTests.py", nodes
[1].name
276 n1
= Factory("Util.py")
277 nodes
= env
.arg2nodes([n1
, "UtilTests.py"], Factory
)
278 assert len(nodes
) == 2, nodes
279 assert isinstance(nodes
[0], X
)
280 assert isinstance(nodes
[1], X
)
281 assert nodes
[0].name
== "Util.py", nodes
[0].name
282 assert nodes
[1].name
== "UtilTests.py", nodes
[1].name
284 class SConsNode(SCons
.Node
.Node
):
286 nodes
= env
.arg2nodes(SConsNode())
287 assert len(nodes
) == 1, nodes
288 assert isinstance(nodes
[0], SConsNode
), nodes
[0]
292 nodes
= env
.arg2nodes(OtherNode())
293 assert len(nodes
) == 1, nodes
294 assert isinstance(nodes
[0], OtherNode
), nodes
[0]
296 def lookup_a(str, F
=Factory
):
304 def lookup_b(str, F
=Factory
):
312 env_ll
= SubstitutionEnvironment()
313 env_ll
.lookup_list
= [lookup_a
, lookup_b
]
315 nodes
= env_ll
.arg2nodes(['aaa', 'bbb', 'ccc'], Factory
)
316 assert len(nodes
) == 3, nodes
318 assert nodes
[0].name
== 'aaa', nodes
[0]
319 assert nodes
[0].a
== 1, nodes
[0]
320 assert not hasattr(nodes
[0], 'b'), nodes
[0]
322 assert nodes
[1].name
== 'bbb'
323 assert not hasattr(nodes
[1], 'a'), nodes
[1]
324 assert nodes
[1].b
== 1, nodes
[1]
326 assert nodes
[2].name
== 'ccc'
327 assert not hasattr(nodes
[2], 'a'), nodes
[1]
328 assert not hasattr(nodes
[2], 'b'), nodes
[1]
330 def lookup_bbbb(str, F
=Factory
):
338 def lookup_c(str, F
=Factory
):
346 nodes
= env
.arg2nodes(['bbbb', 'ccc'], Factory
,
347 [lookup_c
, lookup_bbbb
, lookup_b
])
348 assert len(nodes
) == 2, nodes
350 assert nodes
[0].name
== 'bbbb'
351 assert not hasattr(nodes
[0], 'a'), nodes
[1]
352 assert not hasattr(nodes
[0], 'b'), nodes
[1]
353 assert nodes
[0].bbbb
== 1, nodes
[1]
354 assert not hasattr(nodes
[0], 'c'), nodes
[0]
356 assert nodes
[1].name
== 'ccc'
357 assert not hasattr(nodes
[1], 'a'), nodes
[1]
358 assert not hasattr(nodes
[1], 'b'), nodes
[1]
359 assert not hasattr(nodes
[1], 'bbbb'), nodes
[0]
360 assert nodes
[1].c
== 1, nodes
[1]
362 def test_arg2nodes_target_source(self
) -> None:
363 """Test the arg2nodes method with target= and source= keywords
365 targets
= [DummyNode('t1'), DummyNode('t2')]
366 sources
= [DummyNode('s1'), DummyNode('s2')]
367 env
= SubstitutionEnvironment()
368 nodes
= env
.arg2nodes(['${TARGET}-a',
375 names
= [n
.name
for n
in nodes
]
376 assert names
== ['t1-a', 's1-b', 't2-c', 's2-d'], names
378 def test_gvars(self
) -> None:
379 """Test the base class gvars() method"""
380 env
= SubstitutionEnvironment()
382 assert gvars
== {}, gvars
384 def test_lvars(self
) -> None:
385 """Test the base class lvars() method"""
386 env
= SubstitutionEnvironment()
388 assert lvars
== {}, lvars
390 def test_subst(self
) -> None:
391 """Test substituting construction variables within strings
393 Check various combinations, including recursive expansion
394 of variables into other variables.
396 env
= SubstitutionEnvironment(AAA
= 'a', BBB
= 'b')
397 mystr
= env
.subst("$AAA ${AAA}A $BBBB $BBB")
398 assert mystr
== "a aA b", mystr
400 # Changed the tests below to reflect a bug fix in
402 env
= SubstitutionEnvironment(AAA
= '$BBB', BBB
= 'b', BBBA
= 'foo')
403 mystr
= env
.subst("$AAA ${AAA}A ${AAA}B $BBB")
404 assert mystr
== "b bA bB b", mystr
406 env
= SubstitutionEnvironment(AAA
= '$BBB', BBB
= '$CCC', CCC
= 'c')
407 mystr
= env
.subst("$AAA ${AAA}A ${AAA}B $BBB")
408 assert mystr
== "c cA cB c", mystr
411 env
= SubstitutionEnvironment(AAA
= ['a', 'aa', 'aaa'])
412 mystr
= env
.subst("$AAA")
413 assert mystr
== "a aa aaa", mystr
416 env
= SubstitutionEnvironment(AAA
= ('a', 'aa', 'aaa'))
417 mystr
= env
.subst("$AAA")
418 assert mystr
== "a aa aaa", mystr
425 env
= SubstitutionEnvironment(AAA
= 'aaa')
426 s
= env
.subst('$AAA $TARGET $SOURCES', target
=[t1
, t2
], source
=[s1
, s2
])
427 assert s
== "aaa t1 s1 s2", s
428 s
= env
.subst('$AAA $TARGETS $SOURCE', target
=[t1
, t2
], source
=[s1
, s2
])
429 assert s
== "aaa t1 t2 s1", s
431 # Test callables in the SubstitutionEnvironment
432 def foo(target
, source
, env
, for_signature
):
433 assert str(target
) == 't', target
434 assert str(source
) == 's', source
437 env
= SubstitutionEnvironment(BAR
=foo
, FOO
='baz')
441 subst
= env
.subst('test $BAR', target
=t
, source
=s
)
442 assert subst
== 'test baz', subst
444 # Test not calling callables in the SubstitutionEnvironment
446 # This will take some serious surgery to subst() and
447 # subst_list(), so just leave these tests out until we can
449 def bar(arg
) -> None:
452 env
= SubstitutionEnvironment(BAR
=bar
, FOO
='$BAR')
454 subst
= env
.subst('$BAR', call
=None)
455 assert subst
is bar
, subst
457 subst
= env
.subst('$FOO', call
=None)
458 assert subst
is bar
, subst
460 def test_subst_kw(self
) -> None:
461 """Test substituting construction variables within dictionaries"""
462 env
= SubstitutionEnvironment(AAA
= 'a', BBB
= 'b')
463 kw
= env
.subst_kw({'$AAA' : 'aaa', 'bbb' : '$BBB'})
464 assert len(kw
) == 2, kw
465 assert kw
['a'] == 'aaa', kw
['a']
466 assert kw
['bbb'] == 'b', kw
['bbb']
468 def test_subst_list(self
) -> None:
469 """Test substituting construction variables in command lists
471 env
= SubstitutionEnvironment(AAA
= 'a', BBB
= 'b')
472 l
= env
.subst_list("$AAA ${AAA}A $BBBB $BBB")
473 assert l
== [["a", "aA", "b"]], l
475 # Changed the tests below to reflect a bug fix in
477 env
= SubstitutionEnvironment(AAA
= '$BBB', BBB
= 'b', BBBA
= 'foo')
478 l
= env
.subst_list("$AAA ${AAA}A ${AAA}B $BBB")
479 assert l
== [["b", "bA", "bB", "b"]], l
481 env
= SubstitutionEnvironment(AAA
= '$BBB', BBB
= '$CCC', CCC
= 'c')
482 l
= env
.subst_list("$AAA ${AAA}A ${AAA}B $BBB")
483 assert l
== [["c", "cA", "cB", "c"]], l
485 env
= SubstitutionEnvironment(AAA
= '$BBB', BBB
= '$CCC', CCC
= [ 'a', 'b\nc' ])
486 lst
= env
.subst_list([ "$AAA", "B $CCC" ])
487 assert lst
== [[ "a", "b"], ["c", "B a", "b"], ["c"]], lst
494 env
= SubstitutionEnvironment(AAA
= 'aaa')
495 s
= env
.subst_list('$AAA $TARGET $SOURCES', target
=[t1
, t2
], source
=[s1
, s2
])
496 assert s
== [["aaa", "t1", "s1", "s2"]], s
497 s
= env
.subst_list('$AAA $TARGETS $SOURCE', target
=[t1
, t2
], source
=[s1
, s2
])
498 assert s
== [["aaa", "t1", "t2", "s1"]], s
500 # Test callables in the SubstitutionEnvironment
501 def foo(target
, source
, env
, for_signature
):
502 assert str(target
) == 't', target
503 assert str(source
) == 's', source
506 env
= SubstitutionEnvironment(BAR
=foo
, FOO
='baz')
510 lst
= env
.subst_list('test $BAR', target
=t
, source
=s
)
511 assert lst
== [['test', 'baz']], lst
513 # Test not calling callables in the SubstitutionEnvironment
515 # This will take some serious surgery to subst() and
516 # subst_list(), so just leave these tests out until we can
518 def bar(arg
) -> None:
521 env
= SubstitutionEnvironment(BAR
=bar
, FOO
='$BAR')
523 subst
= env
.subst_list('$BAR', call
=None)
524 assert subst
is bar
, subst
526 subst
= env
.subst_list('$FOO', call
=None)
527 assert subst
is bar
, subst
529 def test_subst_path(self
) -> None:
530 """Test substituting a path list
533 def __init__(self
, val
) -> None:
536 return self
.val
+ '-proxy'
539 def __init__(self
, val
) -> None:
541 def get_subst_proxy(self
):
543 def __str__(self
) -> str:
550 env
= SubstitutionEnvironment(FOO
='foo',
553 PROXY
=MyProxy('my1'))
555 r
= env
.subst_path('$FOO')
556 assert r
== ['foo'], r
558 r
= env
.subst_path(['$FOO', 'xxx', '$BAR'])
559 assert r
== ['foo', 'xxx', 'bar'], r
561 r
= env
.subst_path(['$FOO', '$LIST', '$BAR'])
562 assert list(map(str, r
)) == ['foo', 'one two', 'bar'], r
564 r
= env
.subst_path(['$FOO', '$TARGET', '$SOURCE', '$BAR'])
565 assert r
== ['foo', '', '', 'bar'], r
567 r
= env
.subst_path(['$FOO', '$TARGET', '$BAR'], target
=MyNode('ttt'))
568 assert list(map(str, r
)) == ['foo', 'ttt', 'bar'], r
570 r
= env
.subst_path(['$FOO', '$SOURCE', '$BAR'], source
=MyNode('sss'))
571 assert list(map(str, r
)) == ['foo', 'sss', 'bar'], r
575 r
= env
.subst_path(['$PROXY', MyProxy('my2'), n
])
576 assert r
== ['my1-proxy', 'my2-proxy', n
], r
579 def __init__(self
, s
) -> None:
581 def __str__(self
) -> str:
584 env
= SubstitutionEnvironment(FOO
=StringableObj("foo"),
585 BAR
=StringableObj("bar"))
587 r
= env
.subst_path([ "${FOO}/bar", "${BAR}/baz" ])
588 assert r
== [ "foo/bar", "bar/baz" ], r
590 r
= env
.subst_path([ "bar/${FOO}", "baz/${BAR}" ])
591 assert r
== [ "bar/foo", "baz/bar" ], r
593 r
= env
.subst_path([ "bar/${FOO}/bar", "baz/${BAR}/baz" ])
594 assert r
== [ "bar/foo/bar", "baz/bar/baz" ], r
596 def test_subst_target_source(self
) -> None:
597 """Test the base environment subst_target_source() method"""
598 env
= SubstitutionEnvironment(AAA
= 'a', BBB
= 'b')
599 mystr
= env
.subst_target_source("$AAA ${AAA}A $BBBB $BBB")
600 assert mystr
== "a aA b", mystr
602 def test_backtick(self
) -> None:
603 """Test the backtick() method for capturing command output"""
604 env
= SubstitutionEnvironment()
606 test
= TestCmd
.TestCmd(workdir
= '')
607 test
.write('stdout.py', """\
609 sys.stdout.write('this came from stdout.py\\n')
612 test
.write('stderr.py', """\
614 sys.stderr.write('this came from stderr.py\\n')
617 test
.write('fail.py', """\
621 test
.write('echo.py', """\
623 sys.stdout.write(os.environ['ECHO'] + '\\n')
627 save_stderr
= sys
.stderr
629 python
= '"' + sys
.executable
+ '"'
632 sys
.stderr
= io
.StringIO()
633 cmd
= '%s %s' % (python
, test
.workpath('stdout.py'))
634 output
= env
.backtick(cmd
)
635 errout
= sys
.stderr
.getvalue()
636 assert output
== 'this came from stdout.py\n', output
637 assert errout
== '', errout
639 sys
.stderr
= io
.StringIO()
640 cmd
= '%s %s' % (python
, test
.workpath('stderr.py'))
641 output
= env
.backtick(cmd
)
642 errout
= sys
.stderr
.getvalue()
643 assert output
== '', output
644 assert errout
== 'this came from stderr.py\n', errout
646 sys
.stderr
= io
.StringIO()
647 cmd
= '%s %s' % (python
, test
.workpath('fail.py'))
651 assert str(e
) == f
'{cmd!r} exited 1', str(e
)
653 self
.fail("did not catch expected OSError")
655 sys
.stderr
= io
.StringIO()
656 cmd
= '%s %s' % (python
, test
.workpath('echo.py'))
657 env
['ENV'] = os
.environ
.copy()
658 env
['ENV']['ECHO'] = 'this came from ECHO'
659 output
= env
.backtick(cmd
)
660 errout
= sys
.stderr
.getvalue()
661 assert output
== 'this came from ECHO\n', output
662 assert errout
== '', errout
665 sys
.stderr
= save_stderr
667 def test_AddMethod(self
) -> None:
668 """Test the AddMethod() method"""
669 env
= SubstitutionEnvironment(FOO
= 'foo')
672 return 'func-' + self
['FOO']
674 assert not hasattr(env
, 'func')
677 assert r
== 'func-foo', r
679 assert not hasattr(env
, 'bar')
680 env
.AddMethod(func
, 'bar')
682 assert r
== 'func-foo', r
684 def func2(self
, arg
: str=''):
685 return 'func2-' + self
['FOO'] + arg
689 assert r
== 'func2-foo', r
690 r
= env
.func2('-xxx')
691 assert r
== 'func2-foo-xxx', r
693 env
.AddMethod(func2
, 'func')
695 assert r
== 'func2-foo', r
697 assert r
== 'func2-foo-yyy', r
699 # Test that clones of clones correctly re-bind added methods.
700 env1
= Environment(FOO
= '1')
701 env1
.AddMethod(func2
)
702 env2
= env1
.Clone(FOO
= '2')
703 env3
= env2
.Clone(FOO
= '3')
704 env4
= env3
.Clone(FOO
= '4')
706 assert r
== 'func2-1', r
708 assert r
== 'func2-2', r
710 assert r
== 'func2-3', r
712 assert r
== 'func2-4', r
714 # Test that clones don't re-bind an attribute that the user set.
715 env1
= Environment(FOO
= '1')
716 env1
.AddMethod(func2
)
717 def replace_func2() -> str:
718 return 'replace_func2'
719 env1
.func2
= replace_func2
720 env2
= env1
.Clone(FOO
= '2')
722 assert r
== 'replace_func2', r
724 # Test clone rebinding if using global AddMethod.
725 env1
= Environment(FOO
='1')
726 SCons
.Util
.AddMethod(env1
, func2
)
728 assert r
== 'func2-1', r
729 r
= env1
.func2('-xxx')
730 assert r
== 'func2-1-xxx', r
731 env2
= env1
.Clone(FOO
='2')
733 assert r
== 'func2-2', r
736 def test_Override(self
) -> None:
737 """Test overriding construction variables"""
738 env
= SubstitutionEnvironment(ONE
=1, TWO
=2, THREE
=3, FOUR
=4)
739 assert env
['ONE'] == 1, env
['ONE']
740 assert env
['TWO'] == 2, env
['TWO']
741 assert env
['THREE'] == 3, env
['THREE']
742 assert env
['FOUR'] == 4, env
['FOUR']
744 env2
= env
.Override({'TWO' : '10',
745 'THREE' :'x $THREE y',
746 'FOUR' : ['x', '$FOUR', 'y']})
747 assert env2
['ONE'] == 1, env2
['ONE']
748 assert env2
['TWO'] == '10', env2
['TWO']
749 assert env2
['THREE'] == 'x 3 y', env2
['THREE']
750 assert env2
['FOUR'] == ['x', 4, 'y'], env2
['FOUR']
752 assert env
['ONE'] == 1, env
['ONE']
753 assert env
['TWO'] == 2, env
['TWO']
754 assert env
['THREE'] == 3, env
['THREE']
755 assert env
['FOUR'] == 4, env
['FOUR']
757 env2
.Replace(ONE
= "won")
758 assert env2
['ONE'] == "won", env2
['ONE']
759 assert env
['ONE'] == 1, env
['ONE']
761 def test_ParseFlags(self
) -> None:
762 """Test the ParseFlags() method
764 env
= SubstitutionEnvironment()
774 'FRAMEWORKPATH' : [],
782 d
= env
.ParseFlags(None)
785 d
= env
.ParseFlags('')
788 d
= env
.ParseFlags([])
792 "-I/usr/include/fum -I bar -X "
793 '-I"C:\\Program Files\\ASCEND\\include" '
794 "-L/usr/fax -L foo -lxxx -l yyy "
795 '-L"C:\\Program Files\\ASCEND" -lascend '
804 "-frameworkdir=fwd1 "
807 "-dylib_file foo-dylib "
809 "-fmerge-all-constants "
811 "-mno-cygwin -mwindows "
814 "-iquote /usr/include/foo1 "
815 "-isystem /usr/include/foo2 "
816 "-idirafter /usr/include/foo3 "
817 "-imacros /usr/include/foo4 "
818 "-include /usr/include/foo5 "
819 "--param l1-cache-size=32 --param l2-cache-size=6144 "
821 "-DFOO -DBAR=value -D BAZ "
823 "-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', '-stdlib=libc++'], 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, except if an entry
1532 # begins with LIBLITERALPREFIX. Check this with and without that
1533 # argument being passed, and whether or not LIBLITERALPREFIX is
1535 e
= self
.TestEnvironment(
1538 LIST
=['xxx-a', 'b.yyy', 'zzxxx-c.yyy'],
1539 LIBPREFIXES
=['xxx-'],
1540 LIBSUFFIXES
=['.yyy'],
1543 # e['LIBLITERALPREFIX'] = ''
1544 with self
.subTest():
1545 x
= e
.subst('$( ${_stripixes(PRE, LIST, SUF, LIBPREFIXES, LIBSUFFIXES,__env__, LIBLITERALPREFIX)} $)')
1546 self
.assertEqual('preasuf prebsuf prezzxxx-csuf', x
)
1548 with self
.subTest():
1549 x
= e
.subst('$( ${_stripixes(PRE, LIST, SUF, LIBPREFIXES, LIBSUFFIXES,__env__)} $)')
1550 self
.assertEqual('preasuf prebsuf prezzxxx-csuf', x
)
1552 # add it to the env:
1553 e
['LIBLITERALPREFIX'] = 'zz'
1555 with self
.subTest():
1556 x
= e
.subst('$( ${_stripixes(PRE, LIST, SUF, LIBPREFIXES, LIBSUFFIXES,__env__, LIBLITERALPREFIX)} $)')
1557 self
.assertEqual('preasuf prebsuf prezzxxx-c.yyysuf', x
)
1559 with self
.subTest():
1560 x
= e
.subst('$( ${_stripixes(PRE, LIST, SUF, LIBPREFIXES, LIBSUFFIXES,__env__)} $)')
1561 self
.assertEqual('preasuf prebsuf prezzxxx-csuf', x
)
1563 # And special case: LIBLITERALPREFIX is the same as os.pathsep:
1564 e
['LIBLITERALPREFIX'] = os
.pathsep
1565 with self
.subTest():
1566 x
= e
.subst('$( ${_stripixes(PRE, LIST, SUF, LIBPREFIXES, LIBSUFFIXES,__env__, LIBLITERALPREFIX)} $)')
1567 self
.assertEqual('preasuf prebsuf prezzxxx-csuf', x
)
1570 def test_gvars(self
) -> None:
1571 """Test the Environment gvars() method"""
1572 env
= self
.TestEnvironment(XXX
= 'x', YYY
= 'y', ZZZ
= 'z')
1574 assert gvars
['XXX'] == 'x', gvars
['XXX']
1575 assert gvars
['YYY'] == 'y', gvars
['YYY']
1576 assert gvars
['ZZZ'] == 'z', gvars
['ZZZ']
1578 def test__update(self
) -> None:
1579 """Test the _update() method"""
1580 env
= self
.TestEnvironment(X
= 'x', Y
= 'y', Z
= 'z')
1581 assert env
['X'] == 'x', env
['X']
1582 assert env
['Y'] == 'y', env
['Y']
1583 assert env
['Z'] == 'z', env
['Z']
1584 env
._update
({'X' : 'xxx',
1590 assert env
['X'] == 'xxx', env
['X']
1591 assert env
['Y'] == 'y', env
['Y']
1592 assert env
['Z'] == 'zzz', env
['Z']
1593 assert env
['TARGET'] == 't', env
['TARGET']
1594 assert env
['TARGETS'] == 'ttt', env
['TARGETS']
1595 assert env
['SOURCE'] == 's', env
['SOURCE']
1596 assert env
['SOURCES'] == 'sss', env
['SOURCES']
1598 def test_Append(self
) -> None:
1599 """Test appending to construction variables in an Environment
1602 b1
= Environment()['BUILDERS']
1603 b2
= Environment()['BUILDERS']
1604 assert b1
== b2
, diff_dict(b1
, b2
)
1608 'a2', ['A2'], ['a2', 'A2'],
1609 'a3', UL(['A3']), UL(['a', '3', 'A3']),
1612 'a6', UL([]), UL(['a', '6']),
1613 'a7', [''], ['a7', ''],
1614 'a8', UL(['']), UL(['a', '8', '']),
1616 ['e1'], 'E1', ['e1', 'E1'],
1617 ['e2'], ['E2'], ['e2', 'E2'],
1618 ['e3'], UL(['E3']), UL(['e3', 'E3']),
1621 ['e6'], UL([]), UL(['e6']),
1622 ['e7'], [''], ['e7', ''],
1623 ['e8'], UL(['']), UL(['e8', '']),
1625 UL(['i1']), 'I1', UL(['i1', 'I', '1']),
1626 UL(['i2']), ['I2'], UL(['i2', 'I2']),
1627 UL(['i3']), UL(['I3']), UL(['i3', 'I3']),
1628 UL(['i4']), '', UL(['i4']),
1629 UL(['i5']), [], UL(['i5']),
1630 UL(['i6']), UL([]), UL(['i6']),
1631 UL(['i7']), [''], UL(['i7', '']),
1632 UL(['i8']), UL(['']), UL(['i8', '']),
1634 {'d1':1}, 'D1', {'d1':1, 'D1':None},
1635 {'d2':1}, ['D2'], {'d2':1, 'D2':None},
1636 {'d3':1}, UL(['D3']), {'d3':1, 'D3':None},
1637 {'d4':1}, {'D4':1}, {'d4':1, 'D4':1},
1638 {'d5':1}, UD({'D5':1}), UD({'d5':1, 'D5':1}),
1640 UD({'u1':1}), 'U1', UD({'u1':1, 'U1':None}),
1641 UD({'u2':1}), ['U2'], UD({'u2':1, 'U2':None}),
1642 UD({'u3':1}), UL(['U3']), UD({'u3':1, 'U3':None}),
1643 UD({'u4':1}), {'U4':1}, UD({'u4':1, 'U4':1}),
1644 UD({'u5':1}), UD({'U5':1}), UD({'u5':1, 'U5':1}),
1648 '', UL(['M3']), UL(['M3']),
1653 '', UL(['']), UL(['']),
1657 [], UL(['N3']), UL(['N3']),
1662 [], UL(['']), UL(['']),
1664 UL([]), 'O1', ['O', '1'],
1665 UL([]), ['O2'], ['O2'],
1666 UL([]), UL(['O3']), UL(['O3']),
1669 UL([]), UL([]), UL([]),
1670 UL([]), [''], UL(['']),
1671 UL([]), UL(['']), UL(['']),
1673 [''], 'P1', ['', 'P1'],
1674 [''], ['P2'], ['', 'P2'],
1675 [''], UL(['P3']), UL(['', 'P3']),
1678 [''], UL([]), UL(['']),
1679 [''], [''], ['', ''],
1680 [''], UL(['']), UL(['', '']),
1682 UL(['']), 'Q1', ['', 'Q', '1'],
1683 UL(['']), ['Q2'], ['', 'Q2'],
1684 UL(['']), UL(['Q3']), UL(['', 'Q3']),
1685 UL(['']), '', UL(['']),
1686 UL(['']), [], UL(['']),
1687 UL(['']), UL([]), UL(['']),
1688 UL(['']), [''], UL(['', '']),
1689 UL(['']), UL(['']), UL(['', '']),
1695 input, append
, expect
= cases
[:3]
1696 env
['XXX'] = copy
.copy(input)
1698 env
.Append(XXX
= append
)
1699 except Exception as e
:
1700 if failed
== 0: print()
1701 print(" %s Append %s exception: %s" % \
1702 (repr(input), repr(append
), e
))
1706 if result
!= expect
:
1707 if failed
== 0: print()
1708 print(" %s Append %s => %s did not match %s" % \
1709 (repr(input), repr(append
), repr(result
), repr(expect
)))
1712 assert failed
== 0, "%d Append() cases failed" % failed
1714 env
['UL'] = UL(['foo'])
1715 env
.Append(UL
= 'bar')
1717 assert isinstance(result
, UL
), repr(result
)
1718 assert result
== ['foo', 'b', 'a', 'r'], result
1720 env
['CLVar'] = CLVar(['foo'])
1721 env
.Append(CLVar
= 'bar')
1722 result
= env
['CLVar']
1723 assert isinstance(result
, CLVar
), repr(result
)
1724 assert result
== ['foo', 'bar'], result
1727 def __init__(self
, name
) -> None:
1729 def __str__(self
) -> str:
1731 def __eq__(self
, other
):
1732 raise Exception("should not compare")
1736 env2
= self
.TestEnvironment(CCC1
= ['c1'], CCC2
= ccc
)
1737 env2
.Append(CCC1
= ccc
, CCC2
= ['c2'])
1738 assert env2
['CCC1'][0] == 'c1', env2
['CCC1']
1739 assert env2
['CCC1'][1] is ccc
, env2
['CCC1']
1740 assert env2
['CCC2'][0] is ccc
, env2
['CCC2']
1741 assert env2
['CCC2'][1] == 'c2', env2
['CCC2']
1743 env3
= self
.TestEnvironment(X
= {'x1' : 7})
1744 env3
.Append(X
= {'x1' : 8, 'x2' : 9}, Y
= {'y1' : 10})
1745 assert env3
['X'] == {'x1': 8, 'x2': 9}, env3
['X']
1746 assert env3
['Y'] == {'y1': 10}, env3
['Y']
1750 env4
= self
.TestEnvironment(BUILDERS
= {'z1' : z1
})
1751 env4
.Append(BUILDERS
= {'z2' : z2
})
1752 assert env4
['BUILDERS'] == {'z1' : z1
, 'z2' : z2
}, env4
['BUILDERS']
1753 assert hasattr(env4
, 'z1')
1754 assert hasattr(env4
, 'z2')
1756 def test_AppendENVPath(self
) -> None:
1757 """Test appending to an ENV path."""
1758 env1
= self
.TestEnvironment(
1759 ENV
={'PATH': r
'C:\dir\num\one;C:\dir\num\two'},
1760 MYENV
={'MYPATH': r
'C:\mydir\num\one;C:\mydir\num\two'},
1762 # have to include the pathsep here so that the test will work on UNIX too.
1763 env1
.AppendENVPath('PATH', r
'C:\dir\num\two', sep
=';')
1764 env1
.AppendENVPath('PATH', r
'C:\dir\num\three', sep
=';')
1765 env1
.AppendENVPath('MYPATH', r
'C:\mydir\num\three', 'MYENV', sep
=';')
1767 env1
['ENV']['PATH'] == r
'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three'
1768 ), env1
['ENV']['PATH']
1770 env1
.AppendENVPath('MYPATH', r
'C:\mydir\num\three', 'MYENV', sep
=';')
1772 'MYPATH', r
'C:\mydir\num\one', 'MYENV', sep
=';', delete_existing
=1
1774 # this should do nothing since delete_existing is 0
1776 env1
['MYENV']['MYPATH'] == r
'C:\mydir\num\two;C:\mydir\num\three;C:\mydir\num\one'
1777 ), env1
['MYENV']['MYPATH']
1779 test
= TestCmd
.TestCmd(workdir
='')
1780 test
.subdir('sub1', 'sub2')
1781 p
= env1
['ENV']['PATH']
1782 env1
.AppendENVPath('PATH', '#sub1', sep
=';')
1783 env1
.AppendENVPath('PATH', env1
.fs
.Dir('sub2'), sep
=';')
1784 assert env1
['ENV']['PATH'] == p
+ ';sub1;sub2', env1
['ENV']['PATH']
1786 def test_AppendUnique(self
) -> None:
1787 """Test appending to unique values to construction variables
1789 This strips values that are already present when lists are
1791 env
= self
.TestEnvironment(AAA1
= 'a1',
1803 DDD1
= ['a', 'b', 'c'])
1804 env
['LL1'] = [env
.Literal('a literal'), env
.Literal('b literal')]
1805 env
['LL2'] = [env
.Literal('c literal'), env
.Literal('b literal')]
1806 env
.AppendUnique(AAA1
= 'a1',
1808 AAA3
= ['a3', 'b', 'c', 'c', 'b', 'a3'], # ignore dups
1813 BBB3
= ['b3', 'c', 'd', 'c', 'b3'],
1819 LL1
= env
.Literal('a literal'),
1820 LL2
= env
.Literal('a literal'))
1822 assert env
['AAA1'] == 'a1a1', env
['AAA1']
1823 assert env
['AAA2'] == ['a2'], env
['AAA2']
1824 assert env
['AAA3'] == ['a3', 'b', 'c'], env
['AAA3']
1825 assert env
['AAA4'] == 'a4a4.new', env
['AAA4']
1826 assert env
['AAA5'] == ['a5', 'a5.new'], env
['AAA5']
1827 assert env
['BBB1'] == ['b1'], env
['BBB1']
1828 assert env
['BBB2'] == ['b2'], env
['BBB2']
1829 assert env
['BBB3'] == ['b3', 'c', 'd'], env
['BBB3']
1830 assert env
['BBB4'] == ['b4', 'b4.new'], env
['BBB4']
1831 assert env
['BBB5'] == ['b5', 'b5.new'], env
['BBB5']
1832 assert env
['CCC1'] == 'c1', env
['CCC1']
1833 assert env
['CCC2'] == ['c2'], env
['CCC2']
1834 assert env
['DDD1'] == ['a', 'b', 'c'], env
['DDD1']
1835 assert env
['LL1'] == [env
.Literal('a literal'), env
.Literal('b literal')], env
['LL1']
1836 assert env
['LL2'] == [env
.Literal('c literal'), env
.Literal('b literal'), env
.Literal('a literal')], [str(x
) for x
in env
['LL2']]
1838 env
.AppendUnique(DDD1
= 'b', delete_existing
=1)
1839 assert env
['DDD1'] == ['a', 'c', 'b'], env
['DDD1'] # b moves to end
1840 env
.AppendUnique(DDD1
= ['a','b'], delete_existing
=1)
1841 assert env
['DDD1'] == ['c', 'a', 'b'], env
['DDD1'] # a & b move to end
1842 env
.AppendUnique(DDD1
= ['e','f', 'e'], delete_existing
=1)
1843 assert env
['DDD1'] == ['c', 'a', 'b', 'f', 'e'], env
['DDD1'] # add last
1845 env
['CLVar'] = CLVar([])
1846 env
.AppendUnique(CLVar
= 'bar')
1847 result
= env
['CLVar']
1848 assert isinstance(result
, CLVar
), repr(result
)
1849 assert result
== ['bar'], result
1851 env
['CLVar'] = CLVar(['abc'])
1852 env
.AppendUnique(CLVar
= 'bar')
1853 result
= env
['CLVar']
1854 assert isinstance(result
, CLVar
), repr(result
)
1855 assert result
== ['abc', 'bar'], result
1857 env
['CLVar'] = CLVar(['bar'])
1858 env
.AppendUnique(CLVar
= 'bar')
1859 result
= env
['CLVar']
1860 assert isinstance(result
, CLVar
), repr(result
)
1861 assert result
== ['bar'], result
1863 def test_Clone(self
) -> None:
1864 """Test construction environment cloning.
1866 The clone should compare equal if there are no overrides.
1867 Update the clone independently afterwards and check that
1868 the original remains intact (that is, no dangling
1869 references point to objects in the copied environment).
1870 Clone the original with some construction variable
1871 updates and check that the original remains intact
1872 and the copy has the updated values.
1874 with self
.subTest():
1875 env1
= self
.TestEnvironment(XXX
='x', YYY
='y')
1877 env1copy
= env1
.Clone()
1878 self
.assertEqual(env1copy
, env1
)
1879 self
.assertEqual(env2
, env1
)
1880 env2
.Replace(YYY
= 'yyy')
1881 self
.assertNotEqual(env1
, env2
)
1882 self
.assertEqual(env1
, env1copy
)
1884 env3
= env1
.Clone(XXX
='x3', ZZZ
='z3')
1885 self
.assertNotEqual(env3
, env1
)
1886 self
.assertEqual(env3
.Dictionary('XXX'), 'x3')
1887 self
.assertEqual(env1
.Dictionary('XXX'), 'x')
1888 self
.assertEqual(env3
.Dictionary('YYY'), 'y')
1889 self
.assertEqual(env3
.Dictionary('ZZZ'), 'z3')
1890 self
.assertRaises(KeyError, env1
.Dictionary
, 'ZZZ') # leak test
1891 self
.assertEqual(env1
, env1copy
)
1893 # Ensure that lists and dictionaries are deep copied, but not instances
1894 with self
.subTest():
1899 env1
= self
.TestEnvironment(
1905 env2
.Dictionary('YYY').append(4)
1906 env2
.Dictionary('ZZZ')[5] = 6
1907 self
.assertIs(env1
.Dictionary('XXX'), env2
.Dictionary('XXX'))
1908 self
.assertIn(4, env2
.Dictionary('YYY'))
1909 self
.assertNotIn(4, env1
.Dictionary('YYY'))
1910 self
.assertIn(5, env2
.Dictionary('ZZZ'))
1911 self
.assertNotIn(5, env1
.Dictionary('ZZZ'))
1913 # We also need to look at the special cases in semi_deepcopy()
1914 # used when cloning - these should not leak to the original either
1915 with self
.subTest():
1916 env1
= self
.TestEnvironment(
1917 XXX
=deque([1, 2, 3]),
1919 ZZZ
=UD({1: 2, 3: 4}),
1922 env2
['XXX'].append(4)
1923 env2
['YYY'].append(4)
1925 self
.assertIn(4, env2
['XXX'])
1926 self
.assertNotIn(4, env1
['XXX'])
1927 self
.assertIn(4, env2
['YYY'])
1928 self
.assertNotIn(4, env1
['YYY'])
1929 self
.assertIn(5, env2
['ZZZ'])
1930 self
.assertNotIn(5, env1
['ZZZ'])
1932 # BUILDERS is special...
1933 with self
.subTest():
1934 env1
= self
.TestEnvironment(BUILDERS
={'b1': Builder()})
1935 assert hasattr(env1
, 'b1'), "env1.b1 was not set"
1936 assert env1
.b1
.object == env1
, "b1.object doesn't point to env1"
1937 env2
= env1
.Clone(BUILDERS
= {'b2' : Builder()})
1939 assert hasattr(env1
, 'b1'), "b1 was mistakenly cleared from env1"
1940 assert env1
.b1
.object == env1
, "b1.object was changed"
1941 assert not hasattr(env2
, 'b1'), "b1 was not cleared from env2"
1942 assert hasattr(env2
, 'b2'), "env2.b2 was not set"
1943 assert env2
.b2
.object == env2
, "b2.object doesn't point to env2"
1945 # Ensure that specifying new tools in a copied environment works.
1946 with self
.subTest():
1948 def foo(env
) -> None:
1951 def bar(env
) -> None:
1954 def baz(env
) -> None:
1957 env1
= self
.TestEnvironment(tools
=[foo
])
1959 env3
= env1
.Clone(tools
=[bar
, baz
])
1961 assert env1
.get('FOO') == 1
1962 assert env1
.get('BAR') is None
1963 assert env1
.get('BAZ') is None
1964 assert env2
.get('FOO') == 1
1965 assert env2
.get('BAR') is None
1966 assert env2
.get('BAZ') is None
1967 assert env3
.get('FOO') == 1
1968 assert env3
.get('BAR') == 2
1969 assert env3
.get('BAZ') == 3
1971 # Ensure that recursive variable substitution when copying
1972 # environments works properly.
1973 with self
.subTest():
1974 env1
= self
.TestEnvironment(CCFLAGS
='-DFOO', XYZ
='-DXYZ')
1976 CCFLAGS
='$CCFLAGS -DBAR', XYZ
=['-DABC', 'x $XYZ y', '-DDEF']
1978 x
= env2
.get('CCFLAGS')
1979 assert x
== '-DFOO -DBAR', x
1981 assert x
== ['-DABC', 'x -DXYZ y', '-DDEF'], x
1983 # Ensure that special properties of a class don't get
1985 with self
.subTest():
1986 env1
= self
.TestEnvironment(FLAGS
=CLVar('flag1 flag2'))
1987 x
= env1
.get('FLAGS')
1988 assert x
== ['flag1', 'flag2'], x
1990 env2
.Append(FLAGS
='flag3 flag4')
1991 x
= env2
.get('FLAGS')
1992 assert x
== ['flag1', 'flag2', 'flag3', 'flag4'], x
1993 x
= env1
.get('FLAGS')
1994 assert x
== ['flag1', 'flag2'], x
1996 # Ensure that appending directly to a copied CLVar
1997 # doesn't modify the original.
1998 with self
.subTest():
1999 env1
= self
.TestEnvironment(FLAGS
=CLVar('flag1 flag2'))
2000 x
= env1
.get('FLAGS')
2001 assert x
== ['flag1', 'flag2'], x
2003 env2
['FLAGS'] += ['flag3', 'flag4']
2004 x
= env2
.get('FLAGS')
2005 assert x
== ['flag1', 'flag2', 'flag3', 'flag4'], x
2006 x
= env1
.get('FLAGS')
2007 assert x
== ['flag1', 'flag2'], x
2009 # Test that the environment stores the toolpath and
2010 # re-uses it for copies.
2011 with self
.subTest():
2012 test
= TestCmd
.TestCmd(workdir
='')
2014 test
.write('xxx.py', """\
2021 test
.write('yyy.py', """\
2028 env
= self
.TestEnvironment(tools
=['xxx'], toolpath
=[test
.workpath('')])
2029 assert env
['XXX'] == 'one', env
['XXX']
2030 env
= env
.Clone(tools
=['yyy'])
2031 assert env
['YYY'] == 'two', env
['YYY']
2034 with self
.subTest():
2037 def my_tool(env
, rv
=real_value
) -> None:
2038 assert env
['KEY_THAT_I_WANT'] == rv
[0]
2039 env
['KEY_THAT_I_WANT'] = rv
[0] + 1
2041 env
= self
.TestEnvironment()
2044 env
= env
.Clone(KEY_THAT_I_WANT
=5, tools
=[my_tool
])
2045 assert env
['KEY_THAT_I_WANT'] == real_value
[0], env
['KEY_THAT_I_WANT']
2048 env
= env
.Clone(KEY_THAT_I_WANT
=6, tools
=[my_tool
])
2049 assert env
['KEY_THAT_I_WANT'] == real_value
[0], env
['KEY_THAT_I_WANT']
2051 # test for pull request #150
2052 with self
.subTest():
2053 env
= self
.TestEnvironment()
2054 env
._dict
.pop('BUILDERS')
2055 assert ('BUILDERS' in env
) is False
2058 def test_Detect(self
) -> None:
2059 """Test Detect()ing tools"""
2060 test
= TestCmd
.TestCmd(workdir
= '')
2061 test
.subdir('sub1', 'sub2')
2062 sub1
= test
.workpath('sub1')
2063 sub2
= test
.workpath('sub2')
2065 if sys
.platform
== 'win32':
2066 test
.write(['sub1', 'xxx'], "sub1/xxx\n")
2067 test
.write(['sub2', 'xxx'], "sub2/xxx\n")
2069 env
= self
.TestEnvironment(ENV
= { 'PATH' : [sub1
, sub2
] })
2071 x
= env
.Detect('xxx.exe')
2074 test
.write(['sub2', 'xxx.exe'], "sub2/xxx.exe\n")
2076 env
= self
.TestEnvironment(ENV
= { 'PATH' : [sub1
, sub2
] })
2078 x
= env
.Detect('xxx.exe')
2079 assert x
== 'xxx.exe', x
2081 test
.write(['sub1', 'xxx.exe'], "sub1/xxx.exe\n")
2083 x
= env
.Detect('xxx.exe')
2084 assert x
== 'xxx.exe', x
2087 test
.write(['sub1', 'xxx.exe'], "sub1/xxx.exe\n")
2088 test
.write(['sub2', 'xxx.exe'], "sub2/xxx.exe\n")
2090 env
= self
.TestEnvironment(ENV
= { 'PATH' : [sub1
, sub2
] })
2092 x
= env
.Detect('xxx.exe')
2095 sub2_xxx_exe
= test
.workpath('sub2', 'xxx.exe')
2096 os
.chmod(sub2_xxx_exe
, 0o755)
2098 env
= self
.TestEnvironment(ENV
= { 'PATH' : [sub1
, sub2
] })
2100 x
= env
.Detect('xxx.exe')
2101 assert x
== 'xxx.exe', x
2103 sub1_xxx_exe
= test
.workpath('sub1', 'xxx.exe')
2104 os
.chmod(sub1_xxx_exe
, 0o755)
2106 x
= env
.Detect('xxx.exe')
2107 assert x
== 'xxx.exe', x
2109 env
= self
.TestEnvironment(ENV
= { 'PATH' : [] })
2110 x
= env
.Detect('xxx.exe')
2113 def test_Dictionary(self
) -> None:
2114 """Test retrieval of known construction variables
2116 Fetch them from the Dictionary and check for well-known
2117 defaults that get inserted.
2119 env
= self
.TestEnvironment(XXX
= 'x', YYY
= 'y', ZZZ
= 'z')
2120 assert env
.Dictionary('XXX') == 'x'
2121 assert env
.Dictionary('YYY') == 'y'
2122 assert env
.Dictionary('XXX', 'ZZZ') == ['x', 'z']
2123 xxx
, zzz
= env
.Dictionary('XXX', 'ZZZ')
2126 assert 'BUILDERS' in env
.Dictionary()
2127 assert 'CC' in env
.Dictionary()
2128 assert 'CCFLAGS' in env
.Dictionary()
2129 assert 'ENV' in env
.Dictionary()
2131 assert env
['XXX'] == 'x'
2133 assert env
.Dictionary('XXX') == 'foo'
2135 assert 'XXX' not in env
.Dictionary()
2137 def test_FindIxes(self
) -> None:
2138 """Test FindIxes()"""
2139 env
= self
.TestEnvironment(LIBPREFIX
='lib',
2146 paths
= [os
.path
.join('dir', 'libfoo.a'),
2147 os
.path
.join('dir', 'libfoo.so')]
2149 assert paths
[0] == env
.FindIxes(paths
, 'LIBPREFIX', 'LIBSUFFIX')
2150 assert paths
[1] == env
.FindIxes(paths
, 'SHLIBPREFIX', 'SHLIBSUFFIX')
2151 assert None is env
.FindIxes(paths
, 'PREFIX', 'POST')
2153 paths
= ['libfoo.a', 'prefoopost']
2155 assert paths
[0] == env
.FindIxes(paths
, 'LIBPREFIX', 'LIBSUFFIX')
2156 assert None is env
.FindIxes(paths
, 'SHLIBPREFIX', 'SHLIBSUFFIX')
2157 assert paths
[1] == env
.FindIxes(paths
, 'PREFIX', 'SUFFIX')
2159 def test_ParseConfig(self
) -> None:
2160 """Test the ParseConfig() method"""
2161 env
= self
.TestEnvironment(COMMAND
='command',
2162 ASFLAGS
='assembler',
2174 orig_backtick
= env
.backtick
2176 """mocked backtick routine so command is not actually issued.
2178 Just returns the string it was given.
2180 def __init__(self
, save_command
, output
) -> None:
2181 self
.save_command
= save_command
2182 self
.output
= output
2183 def __call__(self
, command
):
2184 self
.save_command
.append(command
)
2189 env
.backtick
= my_backtick(save_command
,
2190 "-I/usr/include/fum -I bar -X\n" + \
2191 "-L/usr/fax -L foo -lxxx -l yyy " + \
2192 "-Wa,-as -Wl,-link " + \
2193 "-Wl,-rpath=rpath1 " + \
2194 "-Wl,-R,rpath2 " + \
2197 "-framework Carbon " + \
2198 "-frameworkdir=fwd1 " + \
2202 "-fmerge-all-constants " + \
2203 "-mno-cygwin -mwindows " + \
2204 "-arch i386 -isysroot /tmp " + \
2205 "-iquote /usr/include/foo1 " + \
2206 "-isystem /usr/include/foo2 " + \
2207 "-idirafter /usr/include/foo3 " + \
2209 "-DFOO -DBAR=value")
2210 env
.ParseConfig("fake $COMMAND")
2211 assert save_command
== ['fake command'], save_command
2212 assert env
['ASFLAGS'] == ['assembler', '-as'], env
['ASFLAGS']
2213 assert env
['CCFLAGS'] == ['', '-X', '-Wa,-as',
2214 '-pthread', '-fmerge-all-constants', '-mno-cygwin',
2215 ('-arch', 'i386'), ('-isysroot', '/tmp'),
2216 ('-iquote', '/usr/include/foo1'),
2217 ('-isystem', '/usr/include/foo2'),
2218 ('-idirafter', '/usr/include/foo3'),
2219 '+DD64'], env
['CCFLAGS']
2220 self
.assertEqual(list(env
['CPPDEFINES']), ['FOO', ['BAR', 'value']])
2221 assert env
['CPPFLAGS'] == ['', '-Wp,-cpp'], env
['CPPFLAGS']
2222 assert env
['CPPPATH'] == ['string', '/usr/include/fum', 'bar'], env
['CPPPATH']
2223 assert env
['FRAMEWORKPATH'] == ['fwd1', 'fwd2', 'fwd3'], env
['FRAMEWORKPATH']
2224 assert env
['FRAMEWORKS'] == ['Carbon'], env
['FRAMEWORKS']
2225 assert env
['LIBPATH'] == ['list', '/usr/fax', 'foo'], env
['LIBPATH']
2226 assert env
['LIBS'] == ['xxx', 'yyy', env
.File('abc')], env
['LIBS']
2227 assert env
['LINKFLAGS'] == ['', '-Wl,-link', '-pthread',
2228 '-fmerge-all-constants',
2229 '-mno-cygwin', '-mwindows',
2231 ('-isysroot', '/tmp'),
2232 '+DD64'], env
['LINKFLAGS']
2233 assert env
['RPATH'] == ['rpath1', 'rpath2', 'rpath3'], env
['RPATH']
2235 env
.backtick
= my_backtick([], "-Ibar")
2236 env
.ParseConfig("fake2")
2237 assert env
['CPPPATH'] == ['string', '/usr/include/fum', 'bar'], env
['CPPPATH']
2238 env
.ParseConfig("fake2", unique
=0)
2239 assert env
['CPPPATH'] == ['string', '/usr/include/fum', 'bar', 'bar'], env
['CPPPATH']
2241 env
.backtick
= orig_backtick
2243 # check that we can pass our own function,
2244 # and that it works for both values of unique
2246 def my_function(myenv
, flags
, unique
: bool=True) -> None:
2249 args
= json
.loads(flags
)
2251 myenv
.AppendUnique(**args
)
2253 myenv
.Append(**args
)
2255 json_str
= '{"LIBS": ["yyy", "xxx", "yyy"]}'
2257 env
= Environment(LIBS
=['xxx'])
2259 env
.backtick
= my_backtick([], json_str
)
2260 env2
.backtick
= my_backtick([], json_str
)
2262 env
.ParseConfig("foo", my_function
)
2263 assert env
['LIBS'] == ['xxx', 'yyy'], env
['LIBS']
2265 env2
.ParseConfig("foo2", my_function
, unique
=False)
2266 assert env2
['LIBS'] == ['xxx', 'yyy', 'xxx', 'yyy'], env2
['LIBS']
2269 def test_ParseDepends(self
) -> None:
2270 """Test the ParseDepends() method"""
2271 test
= TestCmd
.TestCmd(workdir
= '')
2273 test
.write('single', """
2283 test
.write('multiple', """
2294 env
= self
.TestEnvironment(SINGLE
= test
.workpath('single'))
2298 def my_depends(target
, dependency
, tlist
=tlist
, dlist
=dlist
) -> None:
2299 tlist
.extend(target
)
2300 dlist
.extend(dependency
)
2302 env
.Depends
= my_depends
2304 env
.ParseDepends(test
.workpath('does_not_exist'))
2308 env
.ParseDepends(test
.workpath('does_not_exist'), must_exist
=True)
2311 assert exc_caught
, "did not catch expected IOError"
2316 env
.ParseDepends('$SINGLE', only_one
=True)
2317 t
= list(map(str, tlist
))
2318 d
= list(map(str, dlist
))
2319 assert t
== ['f0'], t
2320 assert d
== ['d1', 'd2', 'd3'], d
2325 env
.ParseDepends(test
.workpath('multiple'))
2326 t
= list(map(str, tlist
))
2327 d
= list(map(str, dlist
))
2328 assert t
== ['f1', 'f2', 'f3', 'f4', 'f5'], t
2329 assert d
== ['foo', 'bar', 'abc', 'def', 'ghi', 'jkl', 'mno'], d
2333 env
.ParseDepends(test
.workpath('multiple'), only_one
=True)
2334 except SCons
.Errors
.UserError
:
2336 assert exc_caught
, "did not catch expected UserError"
2338 def test_Platform(self
) -> None:
2339 """Test the Platform() method"""
2340 env
= self
.TestEnvironment(WIN32
='win32', NONE
='no-such-platform')
2344 env
.Platform('does_not_exist')
2345 except SCons
.Errors
.UserError
:
2347 assert exc_caught
, "did not catch expected UserError"
2351 env
.Platform('$NONE')
2352 except SCons
.Errors
.UserError
:
2354 assert exc_caught
, "did not catch expected UserError"
2356 env
.Platform('posix')
2357 assert env
['OBJSUFFIX'] == '.o', env
['OBJSUFFIX']
2359 env
.Platform('$WIN32')
2360 assert env
['OBJSUFFIX'] == '.obj', env
['OBJSUFFIX']
2362 def test_Prepend(self
) -> None:
2363 """Test prepending to construction variables in an Environment
2367 'a2', ['A2'], ['A2', 'a2'],
2368 'a3', UL(['A3']), UL(['A3', 'a', '3']),
2371 'a6', UL([]), UL(['a', '6']),
2372 'a7', [''], ['', 'a7'],
2373 'a8', UL(['']), UL(['', 'a', '8']),
2375 ['e1'], 'E1', ['E1', 'e1'],
2376 ['e2'], ['E2'], ['E2', 'e2'],
2377 ['e3'], UL(['E3']), UL(['E3', 'e3']),
2380 ['e6'], UL([]), UL(['e6']),
2381 ['e7'], [''], ['', 'e7'],
2382 ['e8'], UL(['']), UL(['', 'e8']),
2384 UL(['i1']), 'I1', UL(['I', '1', 'i1']),
2385 UL(['i2']), ['I2'], UL(['I2', 'i2']),
2386 UL(['i3']), UL(['I3']), UL(['I3', 'i3']),
2387 UL(['i4']), '', UL(['i4']),
2388 UL(['i5']), [], UL(['i5']),
2389 UL(['i6']), UL([]), UL(['i6']),
2390 UL(['i7']), [''], UL(['', 'i7']),
2391 UL(['i8']), UL(['']), UL(['', 'i8']),
2393 {'d1':1}, 'D1', {'d1':1, 'D1':None},
2394 {'d2':1}, ['D2'], {'d2':1, 'D2':None},
2395 {'d3':1}, UL(['D3']), {'d3':1, 'D3':None},
2396 {'d4':1}, {'D4':1}, {'d4':1, 'D4':1},
2397 {'d5':1}, UD({'D5':1}), UD({'d5':1, 'D5':1}),
2399 UD({'u1':1}), 'U1', UD({'u1':1, 'U1':None}),
2400 UD({'u2':1}), ['U2'], UD({'u2':1, 'U2':None}),
2401 UD({'u3':1}), UL(['U3']), UD({'u3':1, 'U3':None}),
2402 UD({'u4':1}), {'U4':1}, UD({'u4':1, 'U4':1}),
2403 UD({'u5':1}), UD({'U5':1}), UD({'u5':1, 'U5':1}),
2407 '', UL(['M3']), UL(['M3']),
2412 '', UL(['']), UL(['']),
2416 [], UL(['N3']), UL(['N3']),
2421 [], UL(['']), UL(['']),
2423 UL([]), 'O1', UL(['O', '1']),
2424 UL([]), ['O2'], UL(['O2']),
2425 UL([]), UL(['O3']), UL(['O3']),
2428 UL([]), UL([]), UL([]),
2429 UL([]), [''], UL(['']),
2430 UL([]), UL(['']), UL(['']),
2432 [''], 'P1', ['P1', ''],
2433 [''], ['P2'], ['P2', ''],
2434 [''], UL(['P3']), UL(['P3', '']),
2437 [''], UL([]), UL(['']),
2438 [''], [''], ['', ''],
2439 [''], UL(['']), UL(['', '']),
2441 UL(['']), 'Q1', UL(['Q', '1', '']),
2442 UL(['']), ['Q2'], UL(['Q2', '']),
2443 UL(['']), UL(['Q3']), UL(['Q3', '']),
2444 UL(['']), '', UL(['']),
2445 UL(['']), [], UL(['']),
2446 UL(['']), UL([]), UL(['']),
2447 UL(['']), [''], UL(['', '']),
2448 UL(['']), UL(['']), UL(['', '']),
2454 input, prepend
, expect
= cases
[:3]
2455 env
['XXX'] = copy
.copy(input)
2457 env
.Prepend(XXX
= prepend
)
2458 except Exception as e
:
2459 if failed
== 0: print()
2460 print(" %s Prepend %s exception: %s" % \
2461 (repr(input), repr(prepend
), e
))
2465 if result
!= expect
:
2466 if failed
== 0: print()
2467 print(" %s Prepend %s => %s did not match %s" % \
2468 (repr(input), repr(prepend
), repr(result
), repr(expect
)))
2471 assert failed
== 0, "%d Prepend() cases failed" % failed
2473 env
['UL'] = UL(['foo'])
2474 env
.Prepend(UL
= 'bar')
2476 assert isinstance(result
, UL
), repr(result
)
2477 assert result
== ['b', 'a', 'r', 'foo'], result
2479 env
['CLVar'] = CLVar(['foo'])
2480 env
.Prepend(CLVar
= 'bar')
2481 result
= env
['CLVar']
2482 assert isinstance(result
, CLVar
), repr(result
)
2483 assert result
== ['bar', 'foo'], result
2485 env3
= self
.TestEnvironment(X
= {'x1' : 7})
2486 env3
.Prepend(X
= {'x1' : 8, 'x2' : 9}, Y
= {'y1' : 10})
2487 assert env3
['X'] == {'x1': 8, 'x2' : 9}, env3
['X']
2488 assert env3
['Y'] == {'y1': 10}, env3
['Y']
2492 env4
= self
.TestEnvironment(BUILDERS
= {'z1' : z1
})
2493 env4
.Prepend(BUILDERS
= {'z2' : z2
})
2494 assert env4
['BUILDERS'] == {'z1' : z1
, 'z2' : z2
}, env4
['BUILDERS']
2495 assert hasattr(env4
, 'z1')
2496 assert hasattr(env4
, 'z2')
2498 def test_PrependENVPath(self
) -> None:
2499 """Test prepending to an ENV path."""
2500 env1
= self
.TestEnvironment(
2501 ENV
={'PATH': r
'C:\dir\num\one;C:\dir\num\two'},
2502 MYENV
={'MYPATH': r
'C:\mydir\num\one;C:\mydir\num\two'},
2504 # have to include the pathsep here so that the test will work on UNIX too.
2505 env1
.PrependENVPath('PATH', r
'C:\dir\num\two', sep
=';')
2506 env1
.PrependENVPath('PATH', r
'C:\dir\num\three', sep
=';')
2508 env1
['ENV']['PATH'] == r
'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one'
2509 ), env1
['ENV']['PATH']
2511 env1
.PrependENVPath('MYPATH', r
'C:\mydir\num\three', 'MYENV', sep
=';')
2512 env1
.PrependENVPath('MYPATH', r
'C:\mydir\num\one', 'MYENV', sep
=';')
2513 # this should do nothing since delete_existing is 0
2514 env1
.PrependENVPath(
2515 'MYPATH', r
'C:\mydir\num\three', 'MYENV', sep
=';', delete_existing
=0
2518 env1
['MYENV']['MYPATH'] == r
'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two'
2519 ), env1
['MYENV']['MYPATH']
2521 test
= TestCmd
.TestCmd(workdir
='')
2522 test
.subdir('sub1', 'sub2')
2523 p
= env1
['ENV']['PATH']
2524 env1
.PrependENVPath('PATH', '#sub1', sep
=';')
2525 env1
.PrependENVPath('PATH', env1
.fs
.Dir('sub2'), sep
=';')
2526 assert env1
['ENV']['PATH'] == 'sub2;sub1;' + p
, env1
['ENV']['PATH']
2528 def test_PrependUnique(self
) -> None:
2529 """Test prepending unique values to construction variables
2531 This strips values that are already present when lists are
2533 env
= self
.TestEnvironment(AAA1
= 'a1',
2545 DDD1
= ['a', 'b', 'c'])
2546 env
.PrependUnique(AAA1
= 'a1',
2548 AAA3
= ['a3', 'b', 'c', 'b', 'a3'], # ignore dups
2553 BBB3
= ['b3', 'b', 'c', 'b3'],
2559 assert env
['AAA1'] == 'a1a1', env
['AAA1']
2560 assert env
['AAA2'] == ['a2'], env
['AAA2']
2561 assert env
['AAA3'] == ['c', 'b', 'a3'], env
['AAA3']
2562 assert env
['AAA4'] == 'a4.newa4', env
['AAA4']
2563 assert env
['AAA5'] == ['a5.new', 'a5'], env
['AAA5']
2564 assert env
['BBB1'] == ['b1'], env
['BBB1']
2565 assert env
['BBB2'] == ['b2'], env
['BBB2']
2566 assert env
['BBB3'] == ['b', 'c', 'b3'], env
['BBB3']
2567 assert env
['BBB4'] == ['b4.new', 'b4'], env
['BBB4']
2568 assert env
['BBB5'] == ['b5.new', 'b5'], env
['BBB5']
2569 assert env
['CCC1'] == 'c1', env
['CCC1']
2570 assert env
['CCC2'] == ['c2'], env
['CCC2']
2571 assert env
['DDD1'] == ['a', 'b', 'c'], env
['DDD1']
2573 env
.PrependUnique(DDD1
= 'b', delete_existing
=1)
2574 assert env
['DDD1'] == ['b', 'a', 'c'], env
['DDD1'] # b moves to front
2575 env
.PrependUnique(DDD1
= ['a','c'], delete_existing
=1)
2576 assert env
['DDD1'] == ['a', 'c', 'b'], env
['DDD1'] # a & c move to front
2577 env
.PrependUnique(DDD1
= ['d','e','d'], delete_existing
=1)
2578 assert env
['DDD1'] == ['d', 'e', 'a', 'c', 'b'], env
['DDD1']
2581 env
['CLVar'] = CLVar([])
2582 env
.PrependUnique(CLVar
= 'bar')
2583 result
= env
['CLVar']
2584 assert isinstance(result
, CLVar
), repr(result
)
2585 assert result
== ['bar'], result
2587 env
['CLVar'] = CLVar(['abc'])
2588 env
.PrependUnique(CLVar
= 'bar')
2589 result
= env
['CLVar']
2590 assert isinstance(result
, CLVar
), repr(result
)
2591 assert result
== ['bar', 'abc'], result
2593 env
['CLVar'] = CLVar(['bar'])
2594 env
.PrependUnique(CLVar
= 'bar')
2595 result
= env
['CLVar']
2596 assert isinstance(result
, CLVar
), repr(result
)
2597 assert result
== ['bar'], result
2599 def test_Replace(self
) -> None:
2600 """Test replacing construction variables in an Environment
2602 After creation of the Environment, of course.
2604 env1
= self
.TestEnvironment(AAA
= 'a', BBB
= 'b')
2605 env1
.Replace(BBB
= 'bbb', CCC
= 'ccc')
2607 env2
= self
.TestEnvironment(AAA
= 'a', BBB
= 'bbb', CCC
= 'ccc')
2608 assert env1
== env2
, diff_env(env1
, env2
)
2612 env3
= self
.TestEnvironment(BUILDERS
= {'b1' : b1
})
2613 assert hasattr(env3
, 'b1'), "b1 was not set"
2614 env3
.Replace(BUILDERS
= {'b2' : b2
})
2615 assert not hasattr(env3
, 'b1'), "b1 was not cleared"
2616 assert hasattr(env3
, 'b2'), "b2 was not set"
2618 def test_ReplaceIxes(self
) -> None:
2619 """Test ReplaceIxes()"""
2620 env
= self
.TestEnvironment(LIBPREFIX
='lib',
2627 assert 'libfoo.a' == env
.ReplaceIxes('libfoo.so',
2628 'SHLIBPREFIX', 'SHLIBSUFFIX',
2629 'LIBPREFIX', 'LIBSUFFIX')
2631 assert os
.path
.join('dir', 'libfoo.a') == env
.ReplaceIxes(os
.path
.join('dir', 'libfoo.so'),
2632 'SHLIBPREFIX', 'SHLIBSUFFIX',
2633 'LIBPREFIX', 'LIBSUFFIX')
2635 assert 'libfoo.a' == env
.ReplaceIxes('prefoopost',
2637 'LIBPREFIX', 'LIBSUFFIX')
2639 def test_SetDefault(self
) -> None:
2640 """Test the SetDefault method"""
2641 env
= self
.TestEnvironment(tools
= [])
2642 env
.SetDefault(V1
= 1)
2643 env
.SetDefault(V1
= 2)
2644 assert env
['V1'] == 1
2646 env
.SetDefault(V2
= 1)
2647 assert env
['V2'] == 2
2649 def test_Tool(self
) -> None:
2650 """Test the Tool() method"""
2651 env
= self
.TestEnvironment(LINK
='link', NONE
='no-such-tool')
2655 tool
= env
.Tool('does_not_exist')
2656 except SCons
.Errors
.UserError
:
2659 assert isinstance(tool
, SCons
.Tool
.Tool
)
2660 assert exc_caught
, "did not catch expected UserError"
2665 except SCons
.Errors
.UserError
:
2667 assert exc_caught
, "did not catch expected UserError"
2669 # Use a non-existent toolpath directory just to make sure we
2670 # can call Tool() with the keyword argument.
2671 env
.Tool('cc', toolpath
=['/no/such/directory'])
2672 assert env
['CC'] == 'cc', env
['CC']
2675 assert env
['LINK'] == '$SMARTLINK', env
['LINK']
2677 # Test that the environment stores the toolpath and
2678 # re-uses it for later calls.
2679 test
= TestCmd
.TestCmd(workdir
= '')
2681 test
.write('xxx.py', """\
2688 test
.write('yyy.py', """\
2695 env
= self
.TestEnvironment(tools
=['xxx'], toolpath
=[test
.workpath('')])
2696 assert env
['XXX'] == 'one', env
['XXX']
2698 assert env
['YYY'] == 'two', env
['YYY']
2700 def test_WhereIs(self
) -> None:
2701 """Test the WhereIs() method"""
2702 test
= TestCmd
.TestCmd(workdir
= '')
2704 sub1_xxx_exe
= test
.workpath('sub1', 'xxx.exe')
2705 sub2_xxx_exe
= test
.workpath('sub2', 'xxx.exe')
2706 sub3_xxx_exe
= test
.workpath('sub3', 'xxx.exe')
2707 sub4_xxx_exe
= test
.workpath('sub4', 'xxx.exe')
2709 test
.subdir('subdir', 'sub1', 'sub2', 'sub3', 'sub4')
2711 if sys
.platform
!= 'win32':
2712 test
.write(sub1_xxx_exe
, "\n")
2714 os
.mkdir(sub2_xxx_exe
)
2716 test
.write(sub3_xxx_exe
, "\n")
2717 os
.chmod(sub3_xxx_exe
, 0o777)
2719 test
.write(sub4_xxx_exe
, "\n")
2720 os
.chmod(sub4_xxx_exe
, 0o777)
2722 env_path
= os
.environ
['PATH']
2724 pathdirs_1234
= [ test
.workpath('sub1'),
2725 test
.workpath('sub2'),
2726 test
.workpath('sub3'),
2727 test
.workpath('sub4'),
2728 ] + env_path
.split(os
.pathsep
)
2730 pathdirs_1243
= [ test
.workpath('sub1'),
2731 test
.workpath('sub2'),
2732 test
.workpath('sub4'),
2733 test
.workpath('sub3'),
2734 ] + env_path
.split(os
.pathsep
)
2736 path
= os
.pathsep
.join(pathdirs_1234
)
2737 env
= self
.TestEnvironment(ENV
= {'PATH' : path
})
2738 wi
= env
.WhereIs('')
2740 wi
= env
.WhereIs('xxx.exe')
2741 assert wi
== test
.workpath(sub3_xxx_exe
), wi
2742 wi
= env
.WhereIs('xxx.exe', pathdirs_1243
)
2743 assert wi
== test
.workpath(sub4_xxx_exe
), wi
2744 wi
= env
.WhereIs('xxx.exe', os
.pathsep
.join(pathdirs_1243
))
2745 assert wi
== test
.workpath(sub4_xxx_exe
), wi
2747 wi
= env
.WhereIs('xxx.exe', reject
= sub3_xxx_exe
)
2748 assert wi
== test
.workpath(sub4_xxx_exe
), wi
2749 wi
= env
.WhereIs('xxx.exe', pathdirs_1243
, reject
= sub3_xxx_exe
)
2750 assert wi
== test
.workpath(sub4_xxx_exe
), wi
2752 path
= os
.pathsep
.join(pathdirs_1243
)
2753 env
= self
.TestEnvironment(ENV
= {'PATH' : path
})
2754 wi
= env
.WhereIs('xxx.exe')
2755 assert wi
== test
.workpath(sub4_xxx_exe
), wi
2756 wi
= env
.WhereIs('xxx.exe', pathdirs_1234
)
2757 assert wi
== test
.workpath(sub3_xxx_exe
), wi
2758 wi
= env
.WhereIs('xxx.exe', os
.pathsep
.join(pathdirs_1234
))
2759 assert wi
== test
.workpath(sub3_xxx_exe
), wi
2761 if sys
.platform
== 'win32':
2762 wi
= env
.WhereIs('xxx', pathext
= '')
2763 assert wi
is None, wi
2765 wi
= env
.WhereIs('xxx', pathext
= '.exe')
2766 assert wi
== test
.workpath(sub4_xxx_exe
), wi
2768 wi
= env
.WhereIs('xxx', path
= pathdirs_1234
, pathext
= '.BAT;.EXE')
2769 assert wi
.lower() == test
.workpath(sub3_xxx_exe
).lower(), wi
2771 # Test that we return a normalized path even when
2772 # the path contains forward slashes.
2773 forward_slash
= test
.workpath('') + '/sub3'
2774 wi
= env
.WhereIs('xxx', path
= forward_slash
, pathext
= '.EXE')
2775 assert wi
.lower() == test
.workpath(sub3_xxx_exe
).lower(), wi
2779 def test_Action(self
) -> None:
2780 """Test the Action() method"""
2783 env
= self
.TestEnvironment(FOO
= 'xyzzy')
2785 a
= env
.Action('foo')
2787 assert a
.__class
__ is SCons
.Action
.CommandAction
, a
.__class
__
2789 a
= env
.Action('$FOO')
2791 assert a
.__class
__ is SCons
.Action
.CommandAction
, a
.__class
__
2793 a
= env
.Action('$$FOO')
2795 assert a
.__class
__ is SCons
.Action
.LazyAction
, a
.__class
__
2797 a
= env
.Action(['$FOO', 'foo'])
2799 assert a
.__class
__ is SCons
.Action
.ListAction
, a
.__class
__
2801 def func(arg
) -> None:
2803 a
= env
.Action(func
)
2805 assert a
.__class
__ is SCons
.Action
.FunctionAction
, a
.__class
__
2807 def test_AddPostAction(self
) -> None:
2808 """Test the AddPostAction() method"""
2809 env
= self
.TestEnvironment(FOO
='fff', BAR
='bbb')
2811 n
= env
.AddPostAction('$FOO', lambda x
: x
)
2812 assert str(n
[0]) == 'fff', n
[0]
2814 n
= env
.AddPostAction(['ggg', '$BAR'], lambda x
: x
)
2815 assert str(n
[0]) == 'ggg', n
[0]
2816 assert str(n
[1]) == 'bbb', n
[1]
2818 def test_AddPreAction(self
) -> None:
2819 """Test the AddPreAction() method"""
2820 env
= self
.TestEnvironment(FOO
='fff', BAR
='bbb')
2822 n
= env
.AddPreAction('$FOO', lambda x
: x
)
2823 assert str(n
[0]) == 'fff', n
[0]
2825 n
= env
.AddPreAction(['ggg', '$BAR'], lambda x
: x
)
2826 assert str(n
[0]) == 'ggg', n
[0]
2827 assert str(n
[1]) == 'bbb', n
[1]
2829 def test_Alias(self
) -> None:
2830 """Test the Alias() method"""
2831 env
= self
.TestEnvironment(FOO
='kkk', BAR
='lll', EA
='export_alias')
2833 tgt
= env
.Alias('new_alias')[0]
2834 assert str(tgt
) == 'new_alias', tgt
2835 assert tgt
.sources
== [], tgt
.sources
2836 assert not hasattr(tgt
, 'builder'), tgt
.builder
2838 tgt
= env
.Alias('None_alias', None)[0]
2839 assert str(tgt
) == 'None_alias', tgt
2840 assert tgt
.sources
== [], tgt
.sources
2842 tgt
= env
.Alias('empty_list', [])[0]
2843 assert str(tgt
) == 'empty_list', tgt
2844 assert tgt
.sources
== [], tgt
.sources
2846 tgt
= env
.Alias('export_alias', [ 'asrc1', '$FOO' ])[0]
2847 assert str(tgt
) == 'export_alias', tgt
2848 assert len(tgt
.sources
) == 2, list(map(str, tgt
.sources
))
2849 assert str(tgt
.sources
[0]) == 'asrc1', list(map(str, tgt
.sources
))
2850 assert str(tgt
.sources
[1]) == 'kkk', list(map(str, tgt
.sources
))
2852 n
= env
.Alias(tgt
, source
= ['$BAR', 'asrc4'])[0]
2854 assert len(tgt
.sources
) == 4, list(map(str, tgt
.sources
))
2855 assert str(tgt
.sources
[2]) == 'lll', list(map(str, tgt
.sources
))
2856 assert str(tgt
.sources
[3]) == 'asrc4', list(map(str, tgt
.sources
))
2858 n
= env
.Alias('$EA', 'asrc5')[0]
2860 assert len(tgt
.sources
) == 5, list(map(str, tgt
.sources
))
2861 assert str(tgt
.sources
[4]) == 'asrc5', list(map(str, tgt
.sources
))
2863 t1
, t2
= env
.Alias(['t1', 't2'], ['asrc6', 'asrc7'])
2864 assert str(t1
) == 't1', t1
2865 assert str(t2
) == 't2', t2
2866 assert len(t1
.sources
) == 2, list(map(str, t1
.sources
))
2867 assert str(t1
.sources
[0]) == 'asrc6', list(map(str, t1
.sources
))
2868 assert str(t1
.sources
[1]) == 'asrc7', list(map(str, t1
.sources
))
2869 assert len(t2
.sources
) == 2, list(map(str, t2
.sources
))
2870 assert str(t2
.sources
[0]) == 'asrc6', list(map(str, t2
.sources
))
2871 assert str(t2
.sources
[1]) == 'asrc7', list(map(str, t2
.sources
))
2873 tgt
= env
.Alias('add', 's1')
2874 tgt
= env
.Alias('add', 's2')[0]
2875 s
= list(map(str, tgt
.sources
))
2876 assert s
== ['s1', 's2'], s
2877 tgt
= env
.Alias(tgt
, 's3')[0]
2878 s
= list(map(str, tgt
.sources
))
2879 assert s
== ['s1', 's2', 's3'], s
2881 tgt
= env
.Alias('act', None, "action1")[0]
2882 s
= str(tgt
.builder
.action
)
2883 assert s
== "action1", s
2884 tgt
= env
.Alias('act', None, "action2")[0]
2885 s
= str(tgt
.builder
.action
)
2886 assert s
== "action1\naction2", s
2887 tgt
= env
.Alias(tgt
, None, "action3")[0]
2888 s
= str(tgt
.builder
.action
)
2889 assert s
== "action1\naction2\naction3", s
2891 def test_AlwaysBuild(self
) -> None:
2892 """Test the AlwaysBuild() method"""
2893 env
= self
.TestEnvironment(FOO
='fff', BAR
='bbb')
2894 t
= env
.AlwaysBuild('a', 'b$FOO', ['c', 'd'], '$BAR',
2895 env
.fs
.Dir('dir'), env
.fs
.File('file'))
2896 assert t
[0].__class
__.__name
__ == 'Entry'
2897 assert t
[0].get_internal_path() == 'a'
2898 assert t
[0].always_build
2899 assert t
[1].__class
__.__name
__ == 'Entry'
2900 assert t
[1].get_internal_path() == 'bfff'
2901 assert t
[1].always_build
2902 assert t
[2].__class
__.__name
__ == 'Entry'
2903 assert t
[2].get_internal_path() == 'c'
2904 assert t
[2].always_build
2905 assert t
[3].__class
__.__name
__ == 'Entry'
2906 assert t
[3].get_internal_path() == 'd'
2907 assert t
[3].always_build
2908 assert t
[4].__class
__.__name
__ == 'Entry'
2909 assert t
[4].get_internal_path() == 'bbb'
2910 assert t
[4].always_build
2911 assert t
[5].__class
__.__name
__ == 'Dir'
2912 assert t
[5].get_internal_path() == 'dir'
2913 assert t
[5].always_build
2914 assert t
[6].__class
__.__name
__ == 'File'
2915 assert t
[6].get_internal_path() == 'file'
2916 assert t
[6].always_build
2918 def test_VariantDir(self
) -> None:
2919 """Test the VariantDir() method"""
2921 def Dir(self
, name
):
2923 def VariantDir(self
, variant_dir
, src_dir
, duplicate
) -> None:
2924 self
.variant_dir
= variant_dir
2925 self
.src_dir
= src_dir
2926 self
.duplicate
= duplicate
2928 env
= self
.TestEnvironment(FOO
= 'fff', BAR
= 'bbb')
2931 env
.VariantDir('build', 'src')
2932 assert env
.fs
.variant_dir
== 'build', env
.fs
.variant_dir
2933 assert env
.fs
.src_dir
== 'src', env
.fs
.src_dir
2934 assert env
.fs
.duplicate
== 1, env
.fs
.duplicate
2936 env
.VariantDir('build${FOO}', '${BAR}src', 0)
2937 assert env
.fs
.variant_dir
== 'buildfff', env
.fs
.variant_dir
2938 assert env
.fs
.src_dir
== 'bbbsrc', env
.fs
.src_dir
2939 assert env
.fs
.duplicate
== 0, env
.fs
.duplicate
2941 def test_Builder(self
) -> None:
2942 """Test the Builder() method"""
2943 env
= self
.TestEnvironment(FOO
= 'xyzzy')
2945 b
= env
.Builder(action
= 'foo')
2946 assert b
is not None, b
2948 b
= env
.Builder(action
= '$FOO')
2949 assert b
is not None, b
2951 b
= env
.Builder(action
= ['$FOO', 'foo'])
2952 assert b
is not None, b
2954 def func(arg
) -> None:
2956 b
= env
.Builder(action
= func
)
2957 assert b
is not None, b
2958 b
= env
.Builder(generator
= func
)
2959 assert b
is not None, b
2961 def test_CacheDir(self
) -> None:
2962 """Test the CacheDir() method"""
2964 test
= TestCmd
.TestCmd(workdir
= '')
2966 test_cachedir
= os
.path
.join(test
.workpath(),'CacheDir')
2967 test_cachedir_config
= os
.path
.join(test_cachedir
, 'config')
2968 test_foo
= os
.path
.join(test
.workpath(), 'foo-cachedir')
2969 test_foo_config
= os
.path
.join(test_foo
,'config')
2970 test_foo1
= os
.path
.join(test
.workpath(), 'foo1-cachedir')
2971 test_foo1_config
= os
.path
.join(test_foo1
, 'config')
2973 env
= self
.TestEnvironment(CD
= test_cachedir
)
2975 env
.CacheDir(test_foo
)
2976 assert env
._CacheDir
_path
== test_foo
, env
._CacheDir
_path
2977 assert os
.path
.isfile(test_foo_config
), "No file %s"%test_foo_config
2980 assert env
._CacheDir
_path
== test_cachedir
, env
._CacheDir
_path
2981 assert os
.path
.isfile(test_cachedir_config
), "No file %s"%test_cachedir_config
2983 # Now verify that -n/-no_exec wil prevent the CacheDir/config from being created
2985 SCons
.Action
.execute_actions
= False
2986 env
.CacheDir(test_foo1
)
2987 assert env
._CacheDir
_path
== test_foo1
, env
._CacheDir
_path
2988 assert not os
.path
.isfile(test_foo1_config
), "No file %s"%test_foo1_config
2991 def test_Clean(self
) -> None:
2992 """Test the Clean() method"""
2993 env
= self
.TestEnvironment(FOO
= 'fff', BAR
= 'bbb')
2995 CT
= SCons
.Environment
.CleanTargets
2997 foo
= env
.arg2nodes('foo')[0]
2998 fff
= env
.arg2nodes('fff')[0]
3000 t
= env
.Clean('foo', 'aaa')
3001 l
= list(map(str, CT
[foo
]))
3002 assert l
== ['aaa'], l
3004 t
= env
.Clean(foo
, ['$BAR', 'ccc'])
3005 l
= list(map(str, CT
[foo
]))
3006 assert l
== ['aaa', 'bbb', 'ccc'], l
3008 eee
= env
.arg2nodes('eee')[0]
3010 t
= env
.Clean('$FOO', 'ddd')
3011 l
= list(map(str, CT
[fff
]))
3012 assert l
== ['ddd'], l
3013 t
= env
.Clean(fff
, [eee
, 'fff'])
3014 l
= list(map(str, CT
[fff
]))
3015 assert l
== ['ddd', 'eee', 'fff'], l
3017 def test_Command(self
) -> None:
3018 """Test the Command() method."""
3020 t
= env
.Command(target
='foo.out', source
=['foo1.in', 'foo2.in'],
3021 action
='buildfoo $target $source')[0]
3022 assert t
.builder
is not None
3023 assert t
.builder
.action
.__class
__.__name
__ == 'CommandAction'
3024 assert t
.builder
.action
.cmd_list
== 'buildfoo $target $source'
3025 assert 'foo1.in' in [x
.get_internal_path() for x
in t
.sources
]
3026 assert 'foo2.in' in [x
.get_internal_path() for x
in t
.sources
]
3028 sub
= env
.fs
.Dir('sub')
3029 t
= env
.Command(target
='bar.out', source
='sub',
3030 action
='buildbar $target $source')[0]
3031 assert 'sub' in [x
.get_internal_path() for x
in t
.sources
]
3033 def testFunc(env
, target
, source
) -> int:
3034 assert str(target
[0]) == 'foo.out'
3035 srcs
= list(map(str, source
))
3036 assert 'foo1.in' in srcs
and 'foo2.in' in srcs
, srcs
3039 # avoid spurious output from action
3040 act
= env
.Action(testFunc
, cmdstr
=None)
3041 t
= env
.Command(target
='foo.out', source
=['foo1.in','foo2.in'],
3043 assert t
.builder
is not None
3044 assert t
.builder
.action
.__class
__.__name
__ == 'FunctionAction'
3046 assert 'foo1.in' in [x
.get_internal_path() for x
in t
.sources
]
3047 assert 'foo2.in' in [x
.get_internal_path() for x
in t
.sources
]
3050 def test2(baz
, x
=x
) -> None:
3052 env
= self
.TestEnvironment(TEST2
= test2
)
3053 t
= env
.Command(target
='baz.out', source
='baz.in',
3054 action
='${TEST2(XYZ)}',
3055 XYZ
='magic word')[0]
3056 assert t
.builder
is not None
3058 assert x
[0] == 'magic word', x
3060 t
= env
.Command(target
='${X}.out', source
='${X}.in',
3063 assert str(t
) == 'xxx.out', str(t
)
3064 assert 'xxx.in' in [x
.get_internal_path() for x
in t
.sources
]
3066 env
= self
.TestEnvironment(source_scanner
= 'should_not_find_this')
3067 t
= env
.Command(target
='file.out', source
='file.in',
3069 source_scanner
= 'fake')[0]
3070 assert t
.builder
.source_scanner
== 'fake', t
.builder
.source_scanner
3072 def test_Configure(self
) -> None:
3073 """Test the Configure() method"""
3074 # Configure() will write to a local temporary file.
3075 test
= TestCmd
.TestCmd(workdir
= '')
3079 os
.chdir(test
.workpath())
3081 env
= self
.TestEnvironment(FOO
= 'xyzzy')
3083 def func(arg
) -> None:
3087 assert c
is not None, c
3090 c
= env
.Configure(custom_tests
= {'foo' : func
, '$FOO' : func
})
3091 assert c
is not None, c
3092 assert hasattr(c
, 'foo')
3093 assert hasattr(c
, 'xyzzy')
3098 def test_Depends(self
) -> None:
3099 """Test the explicit Depends method."""
3100 env
= self
.TestEnvironment(FOO
= 'xxx', BAR
='yyy')
3105 t
= env
.Depends(target
='EnvironmentTest.py',
3106 dependency
='Environment.py')[0]
3107 assert t
.__class
__.__name
__ == 'Entry', t
.__class
__.__name
__
3108 assert t
.get_internal_path() == 'EnvironmentTest.py'
3109 assert len(t
.depends
) == 1
3111 assert d
.__class
__.__name
__ == 'Entry', d
.__class
__.__name
__
3112 assert d
.get_internal_path() == 'Environment.py'
3114 t
= env
.Depends(target
='${FOO}.py', dependency
='${BAR}.py')[0]
3115 assert t
.__class
__.__name
__ == 'File', t
.__class
__.__name
__
3116 assert t
.get_internal_path() == 'xxx.py'
3117 assert len(t
.depends
) == 1
3119 assert d
.__class
__.__name
__ == 'File', d
.__class
__.__name
__
3120 assert d
.get_internal_path() == 'yyy.py'
3122 t
= env
.Depends(target
='dir1', dependency
='dir2')[0]
3123 assert t
.__class
__.__name
__ == 'Dir', t
.__class
__.__name
__
3124 assert t
.get_internal_path() == 'dir1'
3125 assert len(t
.depends
) == 1
3127 assert d
.__class
__.__name
__ == 'Dir', d
.__class
__.__name
__
3128 assert d
.get_internal_path() == 'dir2'
3130 def test_Dir(self
) -> None:
3131 """Test the Dir() method"""
3133 def Dir(self
, name
) -> str:
3134 return 'Dir(%s)' % name
3136 env
= self
.TestEnvironment(FOO
= 'foodir', BAR
= 'bardir')
3140 assert d
== 'Dir(d)', d
3143 assert d
== 'Dir(foodir)', d
3145 d
= env
.Dir('${BAR}_$BAR')
3146 assert d
== 'Dir(bardir_bardir)', d
3148 d
= env
.Dir(['dir1'])
3149 assert d
== ['Dir(dir1)'], d
3151 d
= env
.Dir(['dir1', 'dir2'])
3152 assert d
== ['Dir(dir1)', 'Dir(dir2)'], d
3154 def test_NoClean(self
) -> None:
3155 """Test the NoClean() method"""
3156 env
= self
.TestEnvironment(FOO
='ggg', BAR
='hhh')
3159 t
= env
.NoClean('p_a', 'p_${BAR}b', ['p_c', 'p_d'], 'p_$FOO')
3161 assert t
[0].__class
__.__name
__ == 'Entry', t
[0].__class
__.__name
__
3162 assert t
[0].get_internal_path() == 'p_a'
3164 assert t
[1].__class
__.__name
__ == 'Dir', t
[1].__class
__.__name
__
3165 assert t
[1].get_internal_path() == 'p_hhhb'
3167 assert t
[2].__class
__.__name
__ == 'Entry', t
[2].__class
__.__name
__
3168 assert t
[2].get_internal_path() == 'p_c'
3170 assert t
[3].__class
__.__name
__ == 'File', t
[3].__class
__.__name
__
3171 assert t
[3].get_internal_path() == 'p_d'
3173 assert t
[4].__class
__.__name
__ == 'Entry', t
[4].__class
__.__name
__
3174 assert t
[4].get_internal_path() == 'p_ggg'
3177 def test_Dump(self
) -> None:
3178 """Test the Dump() method"""
3180 env
= self
.TestEnvironment(FOO
='foo', FOOFLAGS
=CLVar('--bar --baz'))
3181 assert env
.Dump('FOO') == "'foo'", env
.Dump('FOO')
3182 assert len(env
.Dump()) > 200, env
.Dump() # no args version
3184 assert env
.Dump('FOO', 'json') == '"foo"' # JSON key version
3185 expect
= """[\n "--bar",\n "--baz"\n]"""
3186 self
.assertEqual(env
.Dump('FOOFLAGS', 'json'), expect
)
3188 env_dict
= json
.loads(env
.Dump(format
= 'json'))
3189 assert env_dict
['FOO'] == 'foo' # full JSON version
3192 env
.Dump(format
= 'markdown')
3193 except ValueError as e
:
3194 assert str(e
) == "Unsupported serialization format: markdown."
3196 self
.fail("Did not catch expected ValueError.")
3198 def test_Environment(self
) -> None:
3199 """Test the Environment() method"""
3200 env
= self
.TestEnvironment(FOO
= 'xxx', BAR
= 'yyy')
3202 e2
= env
.Environment(X
= '$FOO', Y
= '$BAR')
3203 assert e2
['X'] == 'xxx', e2
['X']
3204 assert e2
['Y'] == 'yyy', e2
['Y']
3206 def test_Execute(self
) -> None:
3207 """Test the Execute() method"""
3210 def __init__(self
, *args
, **kw
) -> None:
3212 def __call__(self
, target
, source
, env
) -> str:
3213 return "%s executed" % self
.args
3216 env
.Action
= MyAction
3218 result
= env
.Execute("foo")
3219 assert result
== "foo executed", result
3221 def test_Entry(self
) -> None:
3222 """Test the Entry() method"""
3224 def Entry(self
, name
) -> str:
3225 return 'Entry(%s)' % name
3227 env
= self
.TestEnvironment(FOO
= 'fooentry', BAR
= 'barentry')
3231 assert e
== 'Entry(e)', e
3233 e
= env
.Entry('$FOO')
3234 assert e
== 'Entry(fooentry)', e
3236 e
= env
.Entry('${BAR}_$BAR')
3237 assert e
== 'Entry(barentry_barentry)', e
3239 e
= env
.Entry(['entry1'])
3240 assert e
== ['Entry(entry1)'], e
3242 e
= env
.Entry(['entry1', 'entry2'])
3243 assert e
== ['Entry(entry1)', 'Entry(entry2)'], e
3245 def test_File(self
) -> None:
3246 """Test the File() method"""
3248 def File(self
, name
) -> str:
3249 return 'File(%s)' % name
3251 env
= self
.TestEnvironment(FOO
= 'foofile', BAR
= 'barfile')
3255 assert f
== 'File(f)', f
3257 f
= env
.File('$FOO')
3258 assert f
== 'File(foofile)', f
3260 f
= env
.File('${BAR}_$BAR')
3261 assert f
== 'File(barfile_barfile)', f
3263 f
= env
.File(['file1'])
3264 assert f
== ['File(file1)'], f
3266 f
= env
.File(['file1', 'file2'])
3267 assert f
== ['File(file1)', 'File(file2)'], f
3269 def test_FindFile(self
) -> None:
3270 """Test the FindFile() method"""
3271 env
= self
.TestEnvironment(FOO
= 'fff', BAR
= 'bbb')
3273 r
= env
.FindFile('foo', ['no_such_directory'])
3278 def test_Flatten(self
) -> None:
3279 """Test the Flatten() method"""
3281 l
= env
.Flatten([1])
3283 l
= env
.Flatten([1, [2, [3, [4]]]])
3284 assert l
== [1, 2, 3, 4], l
3286 def test_GetBuildPath(self
) -> None:
3287 """Test the GetBuildPath() method."""
3288 env
= self
.TestEnvironment(MAGIC
= 'xyzzy')
3290 p
= env
.GetBuildPath('foo')
3291 assert p
== 'foo', p
3293 p
= env
.GetBuildPath('$MAGIC')
3294 assert p
== 'xyzzy', p
3296 def test_Ignore(self
) -> None:
3297 """Test the explicit Ignore method."""
3298 env
= self
.TestEnvironment(FOO
='yyy', BAR
='zzz')
3304 t
= env
.Ignore(target
='targ.py', dependency
='dep.py')[0]
3305 assert t
.__class
__.__name
__ == 'Entry', t
.__class
__.__name
__
3306 assert t
.get_internal_path() == 'targ.py'
3307 assert len(t
.ignore
) == 1
3309 assert i
.__class
__.__name
__ == 'Entry', i
.__class
__.__name
__
3310 assert i
.get_internal_path() == 'dep.py'
3312 t
= env
.Ignore(target
='$FOO$BAR', dependency
='$BAR$FOO')[0]
3313 assert t
.__class
__.__name
__ == 'File', t
.__class
__.__name
__
3314 assert t
.get_internal_path() == 'yyyzzz'
3315 assert len(t
.ignore
) == 1
3317 assert i
.__class
__.__name
__ == 'File', i
.__class
__.__name
__
3318 assert i
.get_internal_path() == 'zzzyyy'
3320 t
= env
.Ignore(target
='dir1', dependency
='dir2')[0]
3321 assert t
.__class
__.__name
__ == 'Dir', t
.__class
__.__name
__
3322 assert t
.get_internal_path() == 'dir1'
3323 assert len(t
.ignore
) == 1
3325 assert i
.__class
__.__name
__ == 'Dir', i
.__class
__.__name
__
3326 assert i
.get_internal_path() == 'dir2'
3328 def test_Literal(self
) -> None:
3329 """Test the Literal() method"""
3330 env
= self
.TestEnvironment(FOO
='fff', BAR
='bbb')
3331 list = env
.subst_list([env
.Literal('$FOO'), '$BAR'])[0]
3332 assert list == ['$FOO', 'bbb'], list
3333 list = env
.subst_list(['$FOO', env
.Literal('$BAR')])[0]
3334 assert list == ['fff', '$BAR'], list
3336 def test_Local(self
) -> None:
3337 """Test the Local() method."""
3338 env
= self
.TestEnvironment(FOO
='lll')
3340 l
= env
.Local(env
.fs
.File('fff'))
3341 assert str(l
[0]) == 'fff', l
[0]
3343 l
= env
.Local('ggg', '$FOO')
3344 assert str(l
[0]) == 'ggg', l
[0]
3345 assert str(l
[1]) == 'lll', l
[1]
3347 def test_Precious(self
) -> None:
3348 """Test the Precious() method"""
3349 env
= self
.TestEnvironment(FOO
='ggg', BAR
='hhh')
3352 t
= env
.Precious('p_a', 'p_${BAR}b', ['p_c', 'p_d'], 'p_$FOO')
3354 assert t
[0].__class
__.__name
__ == 'Entry', t
[0].__class
__.__name
__
3355 assert t
[0].get_internal_path() == 'p_a'
3356 assert t
[0].precious
3357 assert t
[1].__class
__.__name
__ == 'Dir', t
[1].__class
__.__name
__
3358 assert t
[1].get_internal_path() == 'p_hhhb'
3359 assert t
[1].precious
3360 assert t
[2].__class
__.__name
__ == 'Entry', t
[2].__class
__.__name
__
3361 assert t
[2].get_internal_path() == 'p_c'
3362 assert t
[2].precious
3363 assert t
[3].__class
__.__name
__ == 'File', t
[3].__class
__.__name
__
3364 assert t
[3].get_internal_path() == 'p_d'
3365 assert t
[3].precious
3366 assert t
[4].__class
__.__name
__ == 'Entry', t
[4].__class
__.__name
__
3367 assert t
[4].get_internal_path() == 'p_ggg'
3368 assert t
[4].precious
3370 def test_Pseudo(self
) -> None:
3371 """Test the Pseudo() method"""
3372 env
= self
.TestEnvironment(FOO
='ggg', BAR
='hhh')
3375 t
= env
.Pseudo('p_a', 'p_${BAR}b', ['p_c', 'p_d'], 'p_$FOO')
3377 assert t
[0].__class
__.__name
__ == 'Entry', t
[0].__class
__.__name
__
3378 assert t
[0].get_internal_path() == 'p_a'
3380 assert t
[1].__class
__.__name
__ == 'Dir', t
[1].__class
__.__name
__
3381 assert t
[1].get_internal_path() == 'p_hhhb'
3383 assert t
[2].__class
__.__name
__ == 'Entry', t
[2].__class
__.__name
__
3384 assert t
[2].get_internal_path() == 'p_c'
3386 assert t
[3].__class
__.__name
__ == 'File', t
[3].__class
__.__name
__
3387 assert t
[3].get_internal_path() == 'p_d'
3389 assert t
[4].__class
__.__name
__ == 'Entry', t
[4].__class
__.__name
__
3390 assert t
[4].get_internal_path() == 'p_ggg'
3393 def test_Repository(self
) -> None:
3394 """Test the Repository() method."""
3396 def __init__(self
) -> None:
3398 def Repository(self
, *dirs
) -> None:
3399 self
.list.extend(list(dirs
))
3400 def Dir(self
, name
):
3402 env
= self
.TestEnvironment(FOO
='rrr', BAR
='sss')
3404 env
.Repository('/tmp/foo')
3405 env
.Repository('/tmp/$FOO', '/tmp/$BAR/foo')
3406 expect
= ['/tmp/foo', '/tmp/rrr', '/tmp/sss/foo']
3407 assert env
.fs
.list == expect
, env
.fs
.list
3409 def test_Scanner(self
) -> None:
3410 """Test the Scanner() method"""
3411 def scan(node
, env
, target
, arg
) -> None:
3414 env
= self
.TestEnvironment(FOO
= scan
)
3416 s
= env
.Scanner('foo')
3417 assert s
is not None, s
3419 s
= env
.Scanner(function
= 'foo')
3420 assert s
is not None, s
3423 s
= env
.Scanner('$FOO')
3424 assert s
is not None, s
3426 s
= env
.Scanner(function
= '$FOO')
3427 assert s
is not None, s
3429 def test_SConsignFile(self
) -> None:
3430 """Test the SConsignFile() method"""
3431 import SCons
.SConsign
3434 SConstruct_dir
= os
.sep
+ 'dir'
3436 env
= self
.TestEnvironment(FOO
= 'SConsign',
3437 BAR
= os
.path
.join(os
.sep
, 'File'))
3439 env
.Execute
= lambda action
: None
3444 def capture(name
, dbm_module
, fnames
=fnames
, dbms
=dbms
) -> None:
3446 dbms
.append(dbm_module
)
3448 save_SConsign_File
= SCons
.SConsign
.File
3449 SCons
.SConsign
.File
= capture
3451 env
.SConsignFile('foo')
3452 assert fnames
[-1] == os
.path
.join(os
.sep
, 'dir', 'foo'), fnames
3453 assert dbms
[-1] is None, dbms
3455 env
.SConsignFile('$FOO')
3456 assert fnames
[-1] == os
.path
.join(os
.sep
, 'dir', 'SConsign'), fnames
3457 assert dbms
[-1] is None, dbms
3459 env
.SConsignFile('/$FOO')
3460 assert fnames
[-1] == os
.sep
+ 'SConsign', fnames
3461 assert dbms
[-1] is None, dbms
3463 env
.SConsignFile(os
.sep
+ '$FOO')
3464 assert fnames
[-1] == os
.sep
+ 'SConsign', fnames
3465 assert dbms
[-1] is None, dbms
3467 env
.SConsignFile('$BAR', 'x')
3468 assert fnames
[-1] == os
.path
.join(os
.sep
, 'File'), fnames
3469 assert dbms
[-1] == 'x', dbms
3471 env
.SConsignFile('__$BAR', 7)
3472 assert fnames
[-1] == os
.path
.join(os
.sep
, 'dir', '__', 'File'), fnames
3473 assert dbms
[-1] == 7, dbms
3476 assert fnames
[-1] == os
.path
.join(os
.sep
, 'dir', current_sconsign_filename()), fnames
3477 assert dbms
[-1] is None, dbms
3479 env
.SConsignFile(None)
3480 assert fnames
[-1] is None, fnames
3481 assert dbms
[-1] is None, dbms
3483 SCons
.SConsign
.File
= save_SConsign_File
3485 def test_SideEffect(self
) -> None:
3486 """Test the SideEffect() method"""
3487 env
= self
.TestEnvironment(LIB
='lll', FOO
='fff', BAR
='bbb')
3488 env
.File('mylll.pdb')
3489 env
.Dir('mymmm.pdb')
3491 foo
= env
.Object('foo.obj', 'foo.cpp')[0]
3492 bar
= env
.Object('bar.obj', 'bar.cpp')[0]
3493 s
= env
.SideEffect('mylib.pdb', ['foo.obj', 'bar.obj'])
3494 assert len(s
) == 1, len(s
)
3496 assert s
.__class
__.__name
__ == 'Entry', s
.__class
__.__name
__
3497 assert s
.get_internal_path() == 'mylib.pdb'
3498 assert s
.side_effect
3499 assert foo
.side_effects
== [s
]
3500 assert bar
.side_effects
== [s
]
3502 fff
= env
.Object('fff.obj', 'fff.cpp')[0]
3503 bbb
= env
.Object('bbb.obj', 'bbb.cpp')[0]
3504 s
= env
.SideEffect('my${LIB}.pdb', ['${FOO}.obj', '${BAR}.obj'])
3505 assert len(s
) == 1, len(s
)
3507 assert s
.__class
__.__name
__ == 'File', s
.__class
__.__name
__
3508 assert s
.get_internal_path() == 'mylll.pdb'
3509 assert s
.side_effect
3510 assert fff
.side_effects
== [s
], fff
.side_effects
3511 assert bbb
.side_effects
== [s
], bbb
.side_effects
3513 ggg
= env
.Object('ggg.obj', 'ggg.cpp')[0]
3514 ccc
= env
.Object('ccc.obj', 'ccc.cpp')[0]
3515 s
= env
.SideEffect('mymmm.pdb', ['ggg.obj', 'ccc.obj'])
3516 assert len(s
) == 1, len(s
)
3518 assert s
.__class
__.__name
__ == 'Dir', s
.__class
__.__name
__
3519 assert s
.get_internal_path() == 'mymmm.pdb'
3520 assert s
.side_effect
3521 assert ggg
.side_effects
== [s
], ggg
.side_effects
3522 assert ccc
.side_effects
== [s
], ccc
.side_effects
3524 # Verify that duplicate side effects are not allowed.
3525 before
= len(ggg
.side_effects
)
3526 s
= env
.SideEffect('mymmm.pdb', ggg
)
3527 assert len(s
) == 0, len(s
)
3528 assert len(ggg
.side_effects
) == before
, len(ggg
.side_effects
)
3530 def test_Split(self
) -> None:
3531 """Test the Split() method"""
3532 env
= self
.TestEnvironment(FOO
= 'fff', BAR
= 'bbb')
3533 s
= env
.Split("foo bar")
3534 assert s
== ["foo", "bar"], s
3535 s
= env
.Split("$FOO bar")
3536 assert s
== ["fff", "bar"], s
3537 s
= env
.Split(["foo", "bar"])
3538 assert s
== ["foo", "bar"], s
3539 s
= env
.Split(["foo", "${BAR}-bbb"])
3540 assert s
== ["foo", "bbb-bbb"], s
3541 s
= env
.Split("foo")
3542 assert s
== ["foo"], s
3543 s
= env
.Split("$FOO$BAR")
3544 assert s
== ["fffbbb"], s
3547 def test_Value(self
) -> None:
3548 """Test creating a Value() object
3552 assert v1
.value
== 'a', v1
.value
3555 v2
= env
.Value(value2
)
3556 assert v2
.value
== value2
, v2
.value
3557 assert v2
.value
is value2
, v2
.value
3561 v3
= env
.Value('c', 'build-c')
3562 assert v3
.value
== 'c', v3
.value
3564 v4
= env
.Value(b
'\x00\x0F', name
='name')
3565 assert v4
.value
== b
'\x00\x0F', v4
.value
3566 assert v4
.name
== 'name', v4
.name
3569 def test_Environment_global_variable(self
) -> None:
3570 """Test setting Environment variable to an Environment.Base subclass"""
3571 class MyEnv(SCons
.Environment
.Base
):
3572 def xxx(self
, string
):
3573 return self
.subst(string
)
3575 SCons
.Environment
.Environment
= MyEnv
3577 env
= SCons
.Environment
.Environment(FOO
= 'foo')
3579 f
= env
.subst('$FOO')
3580 assert f
== 'foo', f
3583 assert f
== 'foo', f
3585 def test_bad_keywords(self
) -> None:
3586 """Test trying to use reserved keywords in an Environment"""
3589 env
= self
.TestEnvironment(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 bad_msg
= '%s is not reserved, but got omitted; see Environment.construction_var_name_ok'
3599 added
.append('INIT')
3600 for x
in self
.reserved_variables
:
3601 assert x
not in env
, env
[x
]
3603 assert x
in env
, bad_msg
% x
3605 env
.Append(TARGETS
= 'targets',
3606 SOURCES
= 'sources',
3609 CHANGED_SOURCES
= 'changed_sources',
3610 CHANGED_TARGETS
= 'changed_targets',
3611 UNCHANGED_SOURCES
= 'unchanged_sources',
3612 UNCHANGED_TARGETS
= 'unchanged_targets',
3614 added
.append('APPEND')
3615 for x
in self
.reserved_variables
:
3616 assert x
not in env
, env
[x
]
3618 assert x
in env
, bad_msg
% x
3620 env
.AppendUnique(TARGETS
= 'targets',
3621 SOURCES
= 'sources',
3624 CHANGED_SOURCES
= 'changed_sources',
3625 CHANGED_TARGETS
= 'changed_targets',
3626 UNCHANGED_SOURCES
= 'unchanged_sources',
3627 UNCHANGED_TARGETS
= 'unchanged_targets',
3628 APPENDUNIQUE
= 'appendunique')
3629 added
.append('APPENDUNIQUE')
3630 for x
in self
.reserved_variables
:
3631 assert x
not in env
, env
[x
]
3633 assert x
in env
, bad_msg
% x
3635 env
.Prepend(TARGETS
= 'targets',
3636 SOURCES
= 'sources',
3639 CHANGED_SOURCES
= 'changed_sources',
3640 CHANGED_TARGETS
= 'changed_targets',
3641 UNCHANGED_SOURCES
= 'unchanged_sources',
3642 UNCHANGED_TARGETS
= 'unchanged_targets',
3643 PREPEND
= 'prepend')
3644 added
.append('PREPEND')
3645 for x
in self
.reserved_variables
:
3646 assert x
not in env
, env
[x
]
3648 assert x
in env
, bad_msg
% x
3650 env
.Prepend(TARGETS
= 'targets',
3651 SOURCES
= 'sources',
3654 CHANGED_SOURCES
= 'changed_sources',
3655 CHANGED_TARGETS
= 'changed_targets',
3656 UNCHANGED_SOURCES
= 'unchanged_sources',
3657 UNCHANGED_TARGETS
= 'unchanged_targets',
3658 PREPENDUNIQUE
= 'prependunique')
3659 added
.append('PREPENDUNIQUE')
3660 for x
in self
.reserved_variables
:
3661 assert x
not in env
, env
[x
]
3663 assert x
in env
, bad_msg
% x
3665 env
.Replace(TARGETS
= 'targets',
3666 SOURCES
= 'sources',
3669 CHANGED_SOURCES
= 'changed_sources',
3670 CHANGED_TARGETS
= 'changed_targets',
3671 UNCHANGED_SOURCES
= 'unchanged_sources',
3672 UNCHANGED_TARGETS
= 'unchanged_targets',
3673 REPLACE
= 'replace')
3674 added
.append('REPLACE')
3675 for x
in self
.reserved_variables
:
3676 assert x
not in env
, env
[x
]
3678 assert x
in env
, bad_msg
% x
3680 copy
= env
.Clone(TARGETS
= 'targets',
3681 SOURCES
= 'sources',
3684 CHANGED_SOURCES
= 'changed_sources',
3685 CHANGED_TARGETS
= 'changed_targets',
3686 UNCHANGED_SOURCES
= 'unchanged_sources',
3687 UNCHANGED_TARGETS
= 'unchanged_targets',
3689 for x
in self
.reserved_variables
:
3690 assert x
not in copy
, env
[x
]
3691 for x
in added
+ ['COPY']:
3692 assert x
in copy
, bad_msg
% x
3694 over
= env
.Override({'TARGETS' : 'targets',
3695 'SOURCES' : 'sources',
3696 'SOURCE' : 'source',
3697 'TARGET' : 'target',
3698 'CHANGED_SOURCES' : 'changed_sources',
3699 'CHANGED_TARGETS' : 'changed_targets',
3700 'UNCHANGED_SOURCES' : 'unchanged_sources',
3701 'UNCHANGED_TARGETS' : 'unchanged_targets',
3702 'OVERRIDE' : 'override'})
3703 for x
in self
.reserved_variables
:
3704 assert x
not in over
, over
[x
]
3705 for x
in added
+ ['OVERRIDE']:
3706 assert x
in over
, bad_msg
% x
3708 def test_parse_flags(self
) -> None:
3709 """Test the Base class parse_flags argument"""
3710 # all we have to show is that it gets to MergeFlags internally
3711 env
= Environment(tools
=[], parse_flags
= '-X')
3712 assert env
['CCFLAGS'] == ['-X'], env
['CCFLAGS']
3714 env
= Environment(tools
=[], CCFLAGS
=None, parse_flags
= '-Y')
3715 assert env
['CCFLAGS'] == ['-Y'], env
['CCFLAGS']
3717 env
= Environment(tools
=[], CPPDEFINES
='FOO', parse_flags
='-std=c99 -X -DBAR')
3718 assert env
['CFLAGS'] == ['-std=c99'], env
['CFLAGS']
3719 assert env
['CCFLAGS'] == ['-X'], env
['CCFLAGS']
3720 self
.assertEqual(list(env
['CPPDEFINES']), ['FOO', 'BAR'])
3722 def test_clone_parse_flags(self
) -> None:
3723 """Test the env.Clone() parse_flags argument"""
3724 # all we have to show is that it gets to MergeFlags internally
3725 env
= Environment(tools
= [])
3726 env2
= env
.Clone(parse_flags
= '-X')
3727 assert 'CCFLAGS' not in env
3728 assert env2
['CCFLAGS'] == ['-X'], env2
['CCFLAGS']
3730 env
= Environment(tools
= [], CCFLAGS
=None)
3731 env2
= env
.Clone(parse_flags
= '-Y')
3732 assert env
['CCFLAGS'] is None, env
['CCFLAGS']
3733 assert env2
['CCFLAGS'] == ['-Y'], env2
['CCFLAGS']
3735 env
= Environment(tools
= [], CPPDEFINES
= 'FOO')
3736 env2
= env
.Clone(parse_flags
= '-std=c99 -X -DBAR')
3737 assert 'CFLAGS' not in env
3738 assert env2
['CFLAGS'] == ['-std=c99'], env2
['CFLAGS']
3739 assert 'CCFLAGS' not in env
3740 assert env2
['CCFLAGS'] == ['-X'], env2
['CCFLAGS']
3741 assert env
['CPPDEFINES'] == 'FOO', env
['CPPDEFINES']
3742 self
.assertEqual(list(env2
['CPPDEFINES']), ['FOO','BAR'])
3745 class OverrideEnvironmentTestCase(unittest
.TestCase
,TestEnvironmentFixture
):
3747 def setUp(self
) -> None:
3749 env
._dict
= {'XXX' : 'x', 'YYY' : 'y'}
3750 def verify_value(env
, key
, value
, *args
, **kwargs
) -> None:
3751 """Verifies that key is value on the env this is called with."""
3752 assert env
[key
] == value
3753 env
.AddMethod(verify_value
)
3754 env2
= OverrideEnvironment(env
, {'XXX' : 'x2'})
3755 env3
= OverrideEnvironment(env2
, {'XXX' : 'x3', 'YYY' : 'y3', 'ZZZ' : 'z3'})
3756 self
.envs
= [ env
, env2
, env3
]
3758 def checkpath(self
, node
, expect
):
3759 return str(node
) == os
.path
.normpath(expect
)
3761 def test___init__(self
) -> None:
3762 """Test OverrideEnvironment initialization"""
3763 env
, env2
, env3
= self
.envs
3764 assert env
['XXX'] == 'x', env
['XXX']
3765 assert env2
['XXX'] == 'x2', env2
['XXX']
3766 assert env3
['XXX'] == 'x3', env3
['XXX']
3767 assert env
['YYY'] == 'y', env
['YYY']
3768 assert env2
['YYY'] == 'y', env2
['YYY']
3769 assert env3
['YYY'] == 'y3', env3
['YYY']
3771 def test___delitem__(self
) -> None:
3772 """Test deleting variables from an OverrideEnvironment"""
3773 env
, env2
, env3
= self
.envs
3776 assert 'XXX' not in env
, "env has XXX?"
3777 assert 'XXX' not in env2
, "env2 has XXX?"
3778 assert 'XXX' not in env3
, "env3 has XXX?"
3781 assert 'YYY' not in env
, "env has YYY?"
3782 assert 'YYY' not in env2
, "env2 has YYY?"
3783 assert 'YYY' not in env3
, "env3 has YYY?"
3786 assert 'ZZZ' not in env
, "env has ZZZ?"
3787 assert 'ZZZ' not in env2
, "env2 has ZZZ?"
3788 assert 'ZZZ' not in env3
, "env3 has ZZZ?"
3790 def test_get(self
) -> None:
3791 """Test the OverrideEnvironment get() method"""
3792 env
, env2
, env3
= self
.envs
3793 assert env
.get('XXX') == 'x', env
.get('XXX')
3794 assert env2
.get('XXX') == 'x2', env2
.get('XXX')
3795 assert env3
.get('XXX') == 'x3', env3
.get('XXX')
3796 assert env
.get('YYY') == 'y', env
.get('YYY')
3797 assert env2
.get('YYY') == 'y', env2
.get('YYY')
3798 assert env3
.get('YYY') == 'y3', env3
.get('YYY')
3799 assert env
.get('ZZZ') is None, env
.get('ZZZ')
3800 assert env2
.get('ZZZ') is None, env2
.get('ZZZ')
3801 assert env3
.get('ZZZ') == 'z3', env3
.get('ZZZ')
3803 def test_contains(self
) -> None:
3804 """Test the OverrideEnvironment __contains__() method"""
3805 env
, env2
, env3
= self
.envs
3806 assert 'XXX' in env
, 'XXX' in env
3807 assert 'XXX' in env2
, 'XXX' in env2
3808 assert 'XXX' in env3
, 'XXX' in env3
3809 assert 'YYY' in env
, 'YYY' in env
3810 assert 'YYY' in env2
, 'YYY' in env2
3811 assert 'YYY' in env3
, 'YYY' in env3
3812 assert 'ZZZ' not in env
, 'ZZZ' in env
3813 assert 'ZZZ' not in env2
, 'ZZZ' in env2
3814 assert 'ZZZ' in env3
, 'ZZZ' in env3
3816 def test_Dictionary(self
) -> None:
3817 """Test the OverrideEnvironment Dictionary() method"""
3818 env
, env2
, env3
= self
.envs
3819 # nothing overrriden
3820 items
= env
.Dictionary()
3821 assert items
== {'XXX' : 'x', 'YYY' : 'y'}, items
3822 # env2 overrides XXX, YYY unchanged
3823 items
= env2
.Dictionary()
3824 assert items
== {'XXX' : 'x2', 'YYY' : 'y'}, items
3825 # env3 overrides XXX, YYY, adds ZZZ
3826 items
= env3
.Dictionary()
3827 assert items
== {'XXX' : 'x3', 'YYY' : 'y3', 'ZZZ' : 'z3'}, items
3828 # test one-arg and multi-arg Dictionary
3829 assert env3
.Dictionary('XXX') == 'x3', env3
.Dictionary('XXX')
3830 xxx
, yyy
= env2
.Dictionary('XXX', 'YYY')
3831 assert xxx
== 'x2', xxx
3832 assert yyy
== 'y', yyy
3834 assert 'XXX' not in env3
.Dictionary()
3835 assert 'XXX' not in env2
.Dictionary()
3836 assert 'XXX' not in env
.Dictionary()
3838 def test_items(self
) -> None:
3839 """Test the OverrideEnvironment items() method"""
3840 env
, env2
, env3
= self
.envs
3841 items
= sorted(env
.items())
3842 assert items
== [('XXX', 'x'), ('YYY', 'y')], items
3843 items
= sorted(env2
.items())
3844 assert items
== [('XXX', 'x2'), ('YYY', 'y')], items
3845 items
= sorted(env3
.items())
3846 assert items
== [('XXX', 'x3'), ('YYY', 'y3'), ('ZZZ', 'z3')], items
3848 def test_keys(self
) -> None:
3849 """Test the OverrideEnvironment keys() method"""
3850 env
, env2
, env3
= self
.envs
3851 keys
= sorted(env
.keys())
3852 assert keys
== ['XXX', 'YYY'], keys
3853 keys
= sorted(env2
.keys())
3854 assert keys
== ['XXX', 'YYY'], keys
3855 keys
= sorted(env3
.keys())
3856 assert keys
== ['XXX', 'YYY', 'ZZZ'], keys
3858 def test_values(self
) -> None:
3859 """Test the OverrideEnvironment values() method"""
3860 env
, env2
, env3
= self
.envs
3861 values
= sorted(env
.values())
3862 assert values
== ['x', 'y'], values
3863 values
= sorted(env2
.values())
3864 assert values
== ['x2', 'y'], values
3865 values
= sorted(env3
.values())
3866 assert values
== ['x3', 'y3', 'z3'], values
3868 def test_setdefault(self
) -> None:
3869 """Test the OverrideEnvironment setdefault() method."""
3870 env
, env2
, env3
= self
.envs
3871 # does not set for existing key
3872 assert env2
.setdefault('XXX', 'z') == 'x2', env2
['XXX']
3873 # set/return using default for non-existing key
3874 assert env2
.setdefault('ZZZ', 'z2') == 'z2', env2
['ZZZ']
3875 # set did not leak through to base env
3876 assert 'ZZZ' not in env
3878 def test_gvars(self
) -> None:
3879 """Test the OverrideEnvironment gvars() method"""
3880 env
, env2
, env3
= self
.envs
3882 assert gvars
== {'XXX' : 'x', 'YYY' : 'y'}, gvars
3883 gvars
= env2
.gvars()
3884 assert gvars
== {'XXX' : 'x', 'YYY' : 'y'}, gvars
3885 gvars
= env3
.gvars()
3886 assert gvars
== {'XXX' : 'x', 'YYY' : 'y'}, gvars
3888 def test_lvars(self
) -> None:
3889 """Test the OverrideEnvironment lvars() method"""
3890 env
, env2
, env3
= self
.envs
3892 assert lvars
== {}, lvars
3893 lvars
= env2
.lvars()
3894 assert lvars
== {'XXX' : 'x2'}, lvars
3895 lvars
= env3
.lvars()
3896 assert lvars
== {'XXX' : 'x3', 'YYY' : 'y3', 'ZZZ' : 'z3'}, lvars
3898 def test_Replace(self
) -> None:
3899 """Test the OverrideEnvironment Replace() method"""
3900 env
, env2
, env3
= self
.envs
3901 assert env
['XXX'] == 'x', env
['XXX']
3902 assert env2
['XXX'] == 'x2', env2
['XXX']
3903 assert env3
['XXX'] == 'x3', env3
['XXX']
3904 assert env
['YYY'] == 'y', env
['YYY']
3905 assert env2
['YYY'] == 'y', env2
['YYY']
3906 assert env3
['YYY'] == 'y3', env3
['YYY']
3908 env
.Replace(YYY
= 'y4')
3910 assert env
['XXX'] == 'x', env
['XXX']
3911 assert env2
['XXX'] == 'x2', env2
['XXX']
3912 assert env3
['XXX'] == 'x3', env3
['XXX']
3913 assert env
['YYY'] == 'y4', env
['YYY']
3914 assert env2
['YYY'] == 'y4', env2
['YYY']
3915 assert env3
['YYY'] == 'y3', env3
['YYY']
3917 # Tests a number of Base methods through an OverrideEnvironment to
3918 # make sure they handle overridden constructionv variables properly.
3920 # The following Base methods also call self.subst(), and so could
3921 # theoretically be subject to problems with evaluating overridden
3922 # variables, but they're never really called that way in the rest
3923 # of our code, so we won't worry about them (at least for now):
3939 # It's unlikely Clone() will ever be called this way, so let the
3940 # other methods test that handling overridden values works.
3941 #def test_Clone(self):
3942 # """Test the OverrideEnvironment Clone() method"""
3945 def test_FindIxes(self
) -> None:
3946 """Test the OverrideEnvironment FindIxes() method"""
3947 env
, env2
, env3
= self
.envs
3948 x
= env
.FindIxes(['xaaay'], 'XXX', 'YYY')
3949 assert x
== 'xaaay', x
3950 x
= env2
.FindIxes(['x2aaay'], 'XXX', 'YYY')
3951 assert x
== 'x2aaay', x
3952 x
= env3
.FindIxes(['x3aaay3'], 'XXX', 'YYY')
3953 assert x
== 'x3aaay3', x
3955 def test_ReplaceIxes(self
) -> None:
3956 """Test the OverrideEnvironment ReplaceIxes() method"""
3957 env
, env2
, env3
= self
.envs
3958 x
= env
.ReplaceIxes('xaaay', 'XXX', 'YYY', 'YYY', 'XXX')
3959 assert x
== 'yaaax', x
3960 x
= env2
.ReplaceIxes('x2aaay', 'XXX', 'YYY', 'YYY', 'XXX')
3961 assert x
== 'yaaax2', x
3962 x
= env3
.ReplaceIxes('x3aaay3', 'XXX', 'YYY', 'YYY', 'XXX')
3963 assert x
== 'y3aaax3', x
3965 # It's unlikely WhereIs() will ever be called this way, so let the
3966 # other methods test that handling overridden values works.
3967 #def test_WhereIs(self):
3968 # """Test the OverrideEnvironment WhereIs() method"""
3971 def test_PseudoBuilderInherits(self
) -> None:
3972 """Test that pseudo-builders inherit the overrided values."""
3973 env
, env2
, env3
= self
.envs
3974 env
.verify_value('XXX', 'x')
3975 env2
.verify_value('XXX', 'x2')
3976 env3
.verify_value('XXX', 'x3')
3978 def test_Dir(self
) -> None:
3979 """Test the OverrideEnvironment Dir() method"""
3980 env
, env2
, env3
= self
.envs
3981 x
= env
.Dir('ddir/$XXX')
3982 assert self
.checkpath(x
, 'ddir/x'), str(x
)
3983 x
= env2
.Dir('ddir/$XXX')
3984 assert self
.checkpath(x
, 'ddir/x2'), str(x
)
3985 x
= env3
.Dir('ddir/$XXX')
3986 assert self
.checkpath(x
, 'ddir/x3'), str(x
)
3988 def test_Entry(self
) -> None:
3989 """Test the OverrideEnvironment Entry() method"""
3990 env
, env2
, env3
= self
.envs
3991 x
= env
.Entry('edir/$XXX')
3992 assert self
.checkpath(x
, 'edir/x'), str(x
)
3993 x
= env2
.Entry('edir/$XXX')
3994 assert self
.checkpath(x
, 'edir/x2'), str(x
)
3995 x
= env3
.Entry('edir/$XXX')
3996 assert self
.checkpath(x
, 'edir/x3'), str(x
)
3998 def test_File(self
) -> None:
3999 """Test the OverrideEnvironment File() method"""
4000 env
, env2
, env3
= self
.envs
4001 x
= env
.File('fdir/$XXX')
4002 assert self
.checkpath(x
, 'fdir/x'), str(x
)
4003 x
= env2
.File('fdir/$XXX')
4004 assert self
.checkpath(x
, 'fdir/x2'), str(x
)
4005 x
= env3
.File('fdir/$XXX')
4006 assert self
.checkpath(x
, 'fdir/x3'), str(x
)
4008 def test_Split(self
) -> None:
4009 """Test the OverrideEnvironment Split() method"""
4010 env
, env2
, env3
= self
.envs
4011 env
['AAA'] = '$XXX $YYY $ZZZ'
4012 x
= env
.Split('$AAA')
4013 assert x
== ['x', 'y'], x
4014 x
= env2
.Split('$AAA')
4015 assert x
== ['x2', 'y'], x
4016 x
= env3
.Split('$AAA')
4017 assert x
== ['x3', 'y3', 'z3'], x
4019 def test_parse_flags(self
) -> None:
4020 """Test the OverrideEnvironment parse_flags argument"""
4021 # all we have to show is that it gets to MergeFlags internally
4022 env
= SubstitutionEnvironment()
4023 env2
= env
.Override({'parse_flags' : '-X'})
4024 assert 'CCFLAGS' not in env
4025 assert env2
['CCFLAGS'] == ['-X'], env2
['CCFLAGS']
4027 env
= SubstitutionEnvironment(CCFLAGS
=None)
4028 env2
= env
.Override({'parse_flags' : '-Y'})
4029 assert env
['CCFLAGS'] is None, env
['CCFLAGS']
4030 assert env2
['CCFLAGS'] == ['-Y'], env2
['CCFLAGS']
4032 env
= SubstitutionEnvironment(CPPDEFINES
='FOO')
4033 env2
= env
.Override({'parse_flags': '-std=c99 -X -DBAR'})
4034 assert 'CFLAGS' not in env
4035 assert env2
['CFLAGS'] == ['-std=c99'], env2
['CFLAGS']
4036 assert 'CCFLAGS' not in env
4037 assert env2
['CCFLAGS'] == ['-X'], env2
['CCFLAGS']
4038 # make sure they are independent
4039 self
.assertIsNot(env
['CPPDEFINES'], env2
['CPPDEFINES'])
4040 assert env
['CPPDEFINES'] == 'FOO', env
['CPPDEFINES']
4041 self
.assertEqual(list(env2
['CPPDEFINES']), ['FOO','BAR'])
4044 class NoSubstitutionProxyTestCase(unittest
.TestCase
,TestEnvironmentFixture
):
4046 def test___init__(self
) -> None:
4047 """Test NoSubstitutionProxy initialization"""
4048 env
= self
.TestEnvironment(XXX
= 'x', YYY
= 'y')
4049 assert env
['XXX'] == 'x', env
['XXX']
4050 assert env
['YYY'] == 'y', env
['YYY']
4052 proxy
= NoSubstitutionProxy(env
)
4053 assert proxy
['XXX'] == 'x', proxy
['XXX']
4054 assert proxy
['YYY'] == 'y', proxy
['YYY']
4056 def test_attributes(self
) -> None:
4057 """Test getting and setting NoSubstitutionProxy attributes"""
4059 setattr(env
, 'env_attr', 'value1')
4061 proxy
= NoSubstitutionProxy(env
)
4062 setattr(proxy
, 'proxy_attr', 'value2')
4064 x
= getattr(env
, 'env_attr')
4065 assert x
== 'value1', x
4066 x
= getattr(proxy
, 'env_attr')
4067 assert x
== 'value1', x
4069 x
= getattr(env
, 'proxy_attr')
4070 assert x
== 'value2', x
4071 x
= getattr(proxy
, 'proxy_attr')
4072 assert x
== 'value2', x
4074 def test_subst(self
) -> None:
4075 """Test the NoSubstitutionProxy.subst() method"""
4076 env
= self
.TestEnvironment(XXX
= 'x', YYY
= 'y')
4077 assert env
['XXX'] == 'x', env
['XXX']
4078 assert env
['YYY'] == 'y', env
['YYY']
4080 proxy
= NoSubstitutionProxy(env
)
4081 assert proxy
['XXX'] == 'x', proxy
['XXX']
4082 assert proxy
['YYY'] == 'y', proxy
['YYY']
4084 x
= env
.subst('$XXX')
4086 x
= proxy
.subst('$XXX')
4087 assert x
== '$XXX', x
4089 x
= proxy
.subst('$YYY', raw
=7, target
=None, source
=None,
4091 extra_meaningless_keyword_argument
=None)
4092 assert x
== '$YYY', x
4094 def test_subst_kw(self
) -> None:
4095 """Test the NoSubstitutionProxy.subst_kw() method"""
4096 env
= self
.TestEnvironment(XXX
= 'x', YYY
= 'y')
4097 assert env
['XXX'] == 'x', env
['XXX']
4098 assert env
['YYY'] == 'y', env
['YYY']
4100 proxy
= NoSubstitutionProxy(env
)
4101 assert proxy
['XXX'] == 'x', proxy
['XXX']
4102 assert proxy
['YYY'] == 'y', proxy
['YYY']
4104 x
= env
.subst_kw({'$XXX':'$YYY'})
4105 assert x
== {'x':'y'}, x
4106 x
= proxy
.subst_kw({'$XXX':'$YYY'})
4107 assert x
== {'$XXX':'$YYY'}, x
4109 def test_subst_list(self
) -> None:
4110 """Test the NoSubstitutionProxy.subst_list() method"""
4111 env
= self
.TestEnvironment(XXX
= 'x', YYY
= 'y')
4112 assert env
['XXX'] == 'x', env
['XXX']
4113 assert env
['YYY'] == 'y', env
['YYY']
4115 proxy
= NoSubstitutionProxy(env
)
4116 assert proxy
['XXX'] == 'x', proxy
['XXX']
4117 assert proxy
['YYY'] == 'y', proxy
['YYY']
4119 x
= env
.subst_list('$XXX')
4120 assert x
== [['x']], x
4121 x
= proxy
.subst_list('$XXX')
4124 x
= proxy
.subst_list('$YYY', raw
=0, target
=None, source
=None, conv
=None)
4127 def test_subst_target_source(self
) -> None:
4128 """Test the NoSubstitutionProxy.subst_target_source() method"""
4129 env
= self
.TestEnvironment(XXX
= 'x', YYY
= 'y')
4130 assert env
['XXX'] == 'x', env
['XXX']
4131 assert env
['YYY'] == 'y', env
['YYY']
4133 proxy
= NoSubstitutionProxy(env
)
4134 assert proxy
['XXX'] == 'x', proxy
['XXX']
4135 assert proxy
['YYY'] == 'y', proxy
['YYY']
4137 args
= ('$XXX $TARGET $SOURCE $YYY',)
4138 kw
= {'target' : DummyNode('ttt'), 'source' : DummyNode('sss')}
4139 x
= env
.subst_target_source(*args
, **kw
)
4140 assert x
== 'x ttt sss y', x
4141 x
= proxy
.subst_target_source(*args
, **kw
)
4142 assert x
== ' ttt sss ', x
4145 if __name__
== "__main__":
4150 # indent-tabs-mode:nil
4152 # vim: set expandtab tabstop=4 shiftwidth=4: