Return master to development mode post release
[scons.git] / SCons / EnvironmentTests.py
blob8d90d4d171e40a23dca664addd04a706631d7b42
1 # MIT License
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.
24 import SCons.compat
26 import copy
27 import io
28 import os
29 import sys
30 import unittest
31 from collections import UserDict as UD, UserList as UL, deque
33 import TestCmd
35 import SCons.Warnings
36 from SCons.Environment import (
37 Environment,
38 NoSubstitutionProxy,
39 OverrideEnvironment,
40 SubstitutionEnvironment,
42 from SCons.Util import CLVar
43 from SCons.SConsign import current_sconsign_filename
46 def diff_env(env1, env2):
47 s1 = "env1 = {\n"
48 s2 = "env2 = {\n"
49 d = {}
50 for k in list(env1._dict.keys()) + list(env2._dict.keys()):
51 d[k] = None
52 for k in sorted(d.keys()):
53 if k in env1:
54 if k in env2:
55 if env1[k] != env2[k]:
56 s1 = s1 + " " + repr(k) + " : " + repr(env1[k]) + "\n"
57 s2 = s2 + " " + repr(k) + " : " + repr(env2[k]) + "\n"
58 else:
59 s1 = s1 + " " + repr(k) + " : " + repr(env1[k]) + "\n"
60 elif k in env2:
61 s2 = s2 + " " + repr(k) + " : " + repr(env2[k]) + "\n"
62 s1 = s1 + "}\n"
63 s2 = s2 + "}\n"
64 return s1 + s2
66 def diff_dict(d1, d2):
67 s1 = "d1 = {\n"
68 s2 = "d2 = {\n"
69 d = {}
70 for k in list(d1.keys()) + list(d2.keys()):
71 d[k] = None
72 for k in sorted(d.keys()):
73 if k in d1:
74 if k in d2:
75 if d1[k] != d2[k]:
76 s1 = s1 + " " + repr(k) + " : " + repr(d1[k]) + "\n"
77 s2 = s2 + " " + repr(k) + " : " + repr(d2[k]) + "\n"
78 else:
79 s1 = s1 + " " + repr(k) + " : " + repr(d1[k]) + "\n"
80 elif k in d2:
81 s2 = s2 + " " + repr(k) + " : " + repr(d2[k]) + "\n"
82 s1 = s1 + "}\n"
83 s2 = s2 + "}\n"
84 return s1 + s2
86 called_it = {}
87 built_it = {}
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.
92 """
93 def __init__(self, name = None) -> None:
94 self.name = name
96 def __call__(self, env, target=None, source=None, **kw) -> None:
97 global called_it
98 called_it['target'] = target
99 called_it['source'] = source
100 called_it.update(kw)
102 def execute(self, target = None, **kw) -> None:
103 global built_it
104 built_it[target] = 1
108 scanned_it = {}
110 class Scanner:
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:
115 self.name = name
116 self.skeys = skeys
118 def __call__(self, filename) -> None:
119 global scanned_it
120 scanned_it[filename] = 1
122 def __eq__(self, other):
123 try:
124 return self.__dict__ == other.__dict__
125 except AttributeError:
126 return False
128 def get_skeys(self, env):
129 return self.skeys
131 def __str__(self) -> str:
132 return self.name
135 class DummyNode:
136 def __init__(self, name) -> None:
137 self.name = name
138 def __str__(self) -> str:
139 return self.name
140 def rfile(self):
141 return self
142 def get_subst_proxy(self):
143 return 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():
156 if key not in kw:
157 kw[key] = value
158 if 'BUILDERS' not in kw:
159 static_obj = SCons.Builder.Builder(action = {},
160 emitter = {},
161 suffix = '.o',
162 single_source = 1)
163 kw['BUILDERS'] = {'Object' : static_obj}
164 static_obj.add_action('.cpp', 'fake action')
166 env = Environment(*args, **kw)
167 return env
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')
183 assert env1 == env2
184 assert env1 != env3
185 assert env1 != env4
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')
191 del env1['YYY']
192 assert env1 == env2
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')
203 env1['YYY'] = 'y'
204 assert env1 == env2
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')
215 assert 'XXX' in env
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']
250 assert 'YYY' in env
252 def test_arg2nodes(self) -> None:
253 """Test the arg2nodes method."""
254 env = SubstitutionEnvironment()
255 dict = {}
256 class X(SCons.Node.Node):
257 pass
258 def Factory(name, directory = None, create: int = 1, dict=dict, X=X):
259 if name not in dict:
260 dict[name] = X()
261 dict[name].name = name
262 return dict[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):
285 pass
286 nodes = env.arg2nodes(SConsNode())
287 assert len(nodes) == 1, nodes
288 assert isinstance(nodes[0], SConsNode), nodes[0]
290 class OtherNode:
291 pass
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):
297 if str[0] == 'a':
298 n = F(str)
299 n.a = 1
300 return n
301 else:
302 return None
304 def lookup_b(str, F=Factory):
305 if str[0] == 'b':
306 n = F(str)
307 n.b = 1
308 return n
309 else:
310 return None
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):
331 if str == 'bbbb':
332 n = F(str)
333 n.bbbb = 1
334 return n
335 else:
336 return None
338 def lookup_c(str, F=Factory):
339 if str[0] == 'c':
340 n = F(str)
341 n.c = 1
342 return n
343 else:
344 return None
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',
369 '${SOURCE}-b',
370 '${TARGETS[1]}-c',
371 '${SOURCES[1]}-d'],
372 DummyNode,
373 target=targets,
374 source=sources)
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()
381 gvars = env.gvars()
382 assert gvars == {}, gvars
384 def test_lvars(self) -> None:
385 """Test the base class lvars() method"""
386 env = SubstitutionEnvironment()
387 lvars = env.lvars()
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
401 # subst()
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
410 # Lists:
411 env = SubstitutionEnvironment(AAA = ['a', 'aa', 'aaa'])
412 mystr = env.subst("$AAA")
413 assert mystr == "a aa aaa", mystr
415 # Tuples:
416 env = SubstitutionEnvironment(AAA = ('a', 'aa', 'aaa'))
417 mystr = env.subst("$AAA")
418 assert mystr == "a aa aaa", mystr
420 t1 = DummyNode('t1')
421 t2 = DummyNode('t2')
422 s1 = DummyNode('s1')
423 s2 = DummyNode('s2')
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
435 return env["FOO"]
437 env = SubstitutionEnvironment(BAR=foo, FOO='baz')
438 t = DummyNode('t')
439 s = DummyNode('s')
441 subst = env.subst('test $BAR', target=t, source=s)
442 assert subst == 'test baz', subst
444 # Test not calling callables in the SubstitutionEnvironment
445 if 0:
446 # This will take some serious surgery to subst() and
447 # subst_list(), so just leave these tests out until we can
448 # do that.
449 def bar(arg) -> None:
450 pass
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
476 # subst()
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
489 t1 = DummyNode('t1')
490 t2 = DummyNode('t2')
491 s1 = DummyNode('s1')
492 s2 = DummyNode('s2')
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
504 return env["FOO"]
506 env = SubstitutionEnvironment(BAR=foo, FOO='baz')
507 t = DummyNode('t')
508 s = DummyNode('s')
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
514 if 0:
515 # This will take some serious surgery to subst() and
516 # subst_list(), so just leave these tests out until we can
517 # do that.
518 def bar(arg) -> None:
519 pass
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
532 class MyProxy:
533 def __init__(self, val) -> None:
534 self.val = val
535 def get(self):
536 return self.val + '-proxy'
538 class MyNode:
539 def __init__(self, val) -> None:
540 self.val = val
541 def get_subst_proxy(self):
542 return self
543 def __str__(self) -> str:
544 return self.val
546 class MyObj:
547 def get(self):
548 return self
550 env = SubstitutionEnvironment(FOO='foo',
551 BAR='bar',
552 LIST=['one', 'two'],
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
573 n = MyObj()
575 r = env.subst_path(['$PROXY', MyProxy('my2'), n])
576 assert r == ['my1-proxy', 'my2-proxy', n], r
578 class StringableObj:
579 def __init__(self, s) -> None:
580 self.s = s
581 def __str__(self) -> str:
582 return self.s
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', """\
608 import sys
609 sys.stdout.write('this came from stdout.py\\n')
610 sys.exit(0)
611 """)
612 test.write('stderr.py', """\
613 import sys
614 sys.stderr.write('this came from stderr.py\\n')
615 sys.exit(0)
616 """)
617 test.write('fail.py', """\
618 import sys
619 sys.exit(1)
620 """)
621 test.write('echo.py', """\
622 import os, sys
623 sys.stdout.write(os.environ['ECHO'] + '\\n')
624 sys.exit(0)
625 """)
627 save_stderr = sys.stderr
629 python = '"' + sys.executable + '"'
631 try:
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'))
648 try:
649 env.backtick(cmd)
650 except OSError as e:
651 assert str(e) == f'{cmd!r} exited 1', str(e)
652 else:
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
664 finally:
665 sys.stderr = save_stderr
667 def test_AddMethod(self) -> None:
668 """Test the AddMethod() method"""
669 env = SubstitutionEnvironment(FOO = 'foo')
671 def func(self):
672 return 'func-' + self['FOO']
674 assert not hasattr(env, 'func')
675 env.AddMethod(func)
676 r = env.func()
677 assert r == 'func-foo', r
679 assert not hasattr(env, 'bar')
680 env.AddMethod(func, 'bar')
681 r = env.bar()
682 assert r == 'func-foo', r
684 def func2(self, arg: str=''):
685 return 'func2-' + self['FOO'] + arg
687 env.AddMethod(func2)
688 r = env.func2()
689 assert r == 'func2-foo', r
690 r = env.func2('-xxx')
691 assert r == 'func2-foo-xxx', r
693 env.AddMethod(func2, 'func')
694 r = env.func()
695 assert r == 'func2-foo', r
696 r = env.func('-yyy')
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')
705 r = env1.func2()
706 assert r == 'func2-1', r
707 r = env2.func2()
708 assert r == 'func2-2', r
709 r = env3.func2()
710 assert r == 'func2-3', r
711 r = env4.func2()
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')
721 r = env2.func2()
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)
727 r = 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')
732 r = env2.func2()
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()
766 empty = {
767 'ASFLAGS' : [],
768 'CFLAGS' : [],
769 'CCFLAGS' : [],
770 'CXXFLAGS' : [],
771 'CPPDEFINES' : [],
772 'CPPFLAGS' : [],
773 'CPPPATH' : [],
774 'FRAMEWORKPATH' : [],
775 'FRAMEWORKS' : [],
776 'LIBPATH' : [],
777 'LIBS' : [],
778 'LINKFLAGS' : [],
779 'RPATH' : [],
782 d = env.ParseFlags(None)
783 assert d == empty, d
785 d = env.ParseFlags('')
786 assert d == empty, d
788 d = env.ParseFlags([])
789 assert d == empty, d
791 s = (
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 '
796 "-Wa,-as -Wl,-link "
797 "-Wl,-rpath=rpath1 "
798 "-Wl,-R,rpath2 "
799 "-Wl,-Rrpath3 "
800 "-Wp,-cpp "
801 "-std=c99 "
802 "-std=c++0x "
803 "-framework Carbon "
804 "-frameworkdir=fwd1 "
805 "-Ffwd2 "
806 "-F fwd3 "
807 "-dylib_file foo-dylib "
808 "-pthread "
809 "-fmerge-all-constants "
810 "-fopenmp "
811 "-mno-cygwin -mwindows "
812 "-arch i386 "
813 "-isysroot /tmp "
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 "
820 "+DD64 "
821 "-DFOO -DBAR=value -D BAZ "
822 "-fsanitize=memory "
823 "-fsanitize-address-use-after-return "
824 "-stdlib=libc++"
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'),
841 '+DD64',
842 '-fsanitize=memory',
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',
848 'bar',
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',
853 'foo',
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',
861 ('-arch', 'i386'),
862 ('-isysroot', '/tmp'),
863 '+DD64',
864 '-fsanitize=memory',
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
874 env.MergeFlags('')
875 assert 'CCFLAGS' not in env, env['CCFLAGS']
876 # merges value if flag did not exist
877 env.MergeFlags('-X')
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
884 env.MergeFlags('-X')
885 assert env['CCFLAGS'] == ['-X'], env['CCFLAGS']
886 # default Unique=True enforces no dupes
887 env.MergeFlags('-X')
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()
914 try:
915 del env['CFLAGS'] # just to be sure
916 except KeyError:
917 pass
918 flags = {'CFLAGS': ['-pipe', '-pthread', '-g']}
919 import copy
921 saveflags = copy.deepcopy(flags)
922 env.MergeFlags(flags)
923 self.assertEqual(flags, saveflags)
926 class BaseTestCase(unittest.TestCase,TestEnvironmentFixture):
928 reserved_variables = [
929 'CHANGED_SOURCES',
930 'CHANGED_TARGETS',
931 'SOURCE',
932 'SOURCES',
933 'TARGET',
934 'TARGETS',
935 'UNCHANGED_SOURCES',
936 'UNCHANGED_TARGETS',
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."""
954 class FakeOptions:
955 def __init__(self, key, val) -> None:
956 self.calls = 0
957 self.key = key
958 self.val = val
959 def keys(self):
960 return [self.key]
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')
974 x = env.get('aaa')
975 assert x == 'AAA', x
976 x = env.get('aaa', 'XXX')
977 assert x == 'AAA', x
978 x = env.get('bbb')
979 assert x is None, x
980 x = env.get('bbb', 'XXX')
981 assert x == 'XXX', x
983 def test_Builder_calls(self) -> None:
984 """Test Builder calls through different environments
986 global called_it
988 b1 = Builder()
989 b2 = Builder()
991 env = Environment()
992 env.Replace(BUILDERS = { 'builder1' : b1,
993 'builder2' : b2 })
994 called_it = {}
995 env.builder1('in1')
996 assert called_it['target'] is None, called_it
997 assert called_it['source'] == ['in1'], called_it
999 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
1005 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."""
1013 b1 = Builder()
1014 b2 = Builder()
1015 e1 = Environment()
1016 e2 = Environment()
1018 e1.Replace(BUILDERS={'b': b1})
1019 bw = e1.b
1021 assert bw.env is e1
1022 bw.env = e2
1023 assert bw.env is e2
1025 assert bw.builder is b1
1026 bw.builder = b2
1027 assert bw.builder is b2
1029 self.assertRaises(AttributeError, getattr, bw, 'foobar')
1030 bw.foobar = 42
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
1036 # that's mistaken.
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.
1044 global built_it
1046 b1 = Builder()
1047 b2 = Builder()
1049 built_it = {}
1050 env3 = Environment()
1051 env3.Replace(BUILDERS = { 'builder1' : b1,
1052 'builder2' : b2 })
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']
1060 env4 = env3.Clone()
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.
1067 built_it = {}
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']
1075 built_it = {}
1076 env6 = Environment()
1077 env6['BUILDERS'] = { 'foo' : b1,
1078 'bar' : b2 }
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.
1093 global scanned_it
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
1102 # scanned_it = {}
1103 # env1 = self.TestEnvironment(SCANNERS = s1)
1104 # env1.scanner1(filename = 'out1')
1105 # assert scanned_it['out1']
1107 # scanned_it = {}
1108 # env2 = self.TestEnvironment(SCANNERS = [s1])
1109 # env1.scanner1(filename = 'out1')
1110 # assert scanned_it['out1']
1112 # scanned_it = {}
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"]
1124 env = Environment()
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],
1166 PLATFORM = 'linux')
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
1188 env = Environment()
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 = [
1198 'CHANGED_SOURCES',
1199 'CHANGED_TARGETS',
1200 'SOURCE',
1201 'SOURCES',
1202 'TARGET',
1203 'TARGETS',
1204 'UNCHANGED_SOURCES',
1205 'UNCHANGED_TARGETS',
1208 warning = SCons.Warnings.ReservedVariableWarning
1209 SCons.Warnings.enableWarningClass(warning)
1210 old = SCons.Warnings.warningAsException(1)
1212 try:
1213 env4 = Environment()
1214 for kw in self.reserved_variables:
1215 exc_caught = None
1216 try:
1217 env4[kw] = 'xyzzy'
1218 except warning:
1219 exc_caught = 1
1220 assert exc_caught, "Did not catch ReservedVariableWarning for `%s'" % kw
1221 assert kw not in env4, "`%s' variable was incorrectly set" % kw
1222 finally:
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)
1234 try:
1235 env4 = Environment()
1236 for kw in future_reserved_variables:
1237 exc_caught = None
1238 try:
1239 env4[kw] = 'xyzzy'
1240 except warning:
1241 exc_caught = 1
1242 assert exc_caught, "Did not catch FutureReservedVariableWarning for `%s'" % kw
1243 assert kw in env4, "`%s' variable was not set" % kw
1244 finally:
1245 SCons.Warnings.warningAsException(old)
1247 def test_IllegalVariables(self) -> None:
1248 """Test that use of illegal variables raises an exception"""
1249 env = Environment()
1250 def test_it(var, env=env) -> None:
1251 exc_caught = None
1252 try:
1253 env[var] = 1
1254 except SCons.Errors.UserError:
1255 exc_caught = 1
1256 assert exc_caught, "did not catch UserError for '%s'" % var
1257 env['aaa'] = 1
1258 assert env['aaa'] == 1, env['aaa']
1259 test_it('foo/bar')
1260 test_it('foo.bar')
1261 test_it('foo-bar')
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 '\\/':
1269 path = drive + path
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 ],
1288 INCPREFIX = 'foo ',
1289 INCSUFFIX = 'bar',
1290 FOO = 'baz')
1291 flags = env.subst_list('$_CPPINCFLAGS', 1)[0]
1292 expect = [ '$(',
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'),
1299 '$)',
1301 assert flags == expect, flags
1303 env.Replace(F77PATH = [ 'foo', '$FOO/bar', blat ],
1304 INCPREFIX = 'foo ',
1305 INCSUFFIX = 'bar',
1306 FOO = 'baz')
1307 flags = env.subst_list('$_F77INCFLAGS', 1)[0]
1308 expect = [ '$(',
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'),
1315 '$)',
1317 assert flags == expect, flags
1319 env.Replace(CPPPATH = '', F77PATH = '', LIBPATH = '')
1320 l = env.subst_list('$_CPPINCFLAGS')
1321 assert l == [[]], l
1322 l = env.subst_list('$_F77INCFLAGS')
1323 assert l == [[]], l
1324 l = env.subst_list('$_LIBDIRFLAGS')
1325 assert l == [[]], l
1327 env.fs.Repository('/rep1')
1328 env.fs.Repository('/rep2')
1329 env.Replace(CPPPATH = [ 'foo', '/__a__/b', '$FOO/bar', blat],
1330 INCPREFIX = '-I ',
1331 INCSUFFIX = 'XXX',
1332 FOO = 'baz')
1333 flags = env.subst_list('$_CPPINCFLAGS', 1)[0]
1334 expect = [ '$(',
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'),
1343 '$)'
1345 def normalize_if_path(arg, np=normalize_path):
1346 if arg not in ('$(','$)','-I'):
1347 return np(str(arg))
1348 return arg
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."""
1354 class platform:
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"""
1369 class platform:
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()
1379 try:
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"
1388 finally:
1389 SCons.Defaults.ConstructionEnvironment = save
1391 def test_tools(self) -> None:
1392 """Test specifying a tool callable when instantiating."""
1393 def t1(env) -> None:
1394 env['TOOL1'] = 111
1395 def t2(env) -> None:
1396 env['TOOL2'] = 222
1397 def t3(env) -> None:
1398 env['AAA'] = env['XYZ']
1399 def t4(env) -> None:
1400 env['TOOL4'] = 444
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
1405 t4(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():
1412 env[k] = v
1414 def exists(env):
1415 return True
1416 """)
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:
1427 env['TOOL5'] = 555
1428 def t6(env) -> None:
1429 env['TOOL6'] = 666
1430 def t7(env) -> None:
1431 env['BBB'] = env['XYZ']
1432 def t8(env) -> None:
1433 env['TOOL8'] = 888
1435 import SCons.Defaults
1436 save = SCons.Defaults.ConstructionEnvironment.copy()
1437 try:
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
1445 t8(env)
1446 assert env['TOOL8'] == 888, env
1447 finally:
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:
1453 env['TOOL1'] = 111
1454 def t2(env) -> None:
1455 env['TOOL2'] = 222
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:
1468 copied = False
1470 def copy2(self, src, dst) -> None:
1471 nonlocal copied
1472 copied = True
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')
1483 assert copied
1485 copied = False
1486 SCons.Environment.default_copy_to_cache(env, 'test.in', 'test.out')
1487 assert copied
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'])
1496 s = e1.subst
1497 x = s("${_concat('', '', '', __env__)}")
1498 assert x == '', x
1499 x = s("${_concat('', [], '', __env__)}")
1500 assert x == '', x
1501 x = s("${_concat(PRE, '', SUF, __env__)}")
1502 assert x == '', x
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',
1515 L1=['a', 'b'],
1516 L2=['c', 'd'],
1517 L3=['$L2'])
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
1534 # explicitly set.
1535 e = self.TestEnvironment(
1536 PRE='pre',
1537 SUF='suf',
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')
1573 gvars = env.gvars()
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',
1585 'TARGET' : 't',
1586 'TARGETS' : 'ttt',
1587 'SOURCE' : 's',
1588 'SOURCES' : 'sss',
1589 'Z' : 'zzz'})
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)
1606 cases = [
1607 'a1', 'A1', 'a1A1',
1608 'a2', ['A2'], ['a2', 'A2'],
1609 'a3', UL(['A3']), UL(['a', '3', 'A3']),
1610 'a4', '', 'a4',
1611 'a5', [], ['a5'],
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']),
1619 ['e4'], '', ['e4'],
1620 ['e5'], [], ['e5'],
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}),
1646 '', 'M1', 'M1',
1647 '', ['M2'], ['M2'],
1648 '', UL(['M3']), UL(['M3']),
1649 '', '', '',
1650 '', [], [],
1651 '', UL([]), UL([]),
1652 '', [''], [''],
1653 '', UL(['']), UL(['']),
1655 [], 'N1', ['N1'],
1656 [], ['N2'], ['N2'],
1657 [], UL(['N3']), UL(['N3']),
1658 [], '', [],
1659 [], [], [],
1660 [], UL([]), UL([]),
1661 [], [''], [''],
1662 [], UL(['']), UL(['']),
1664 UL([]), 'O1', ['O', '1'],
1665 UL([]), ['O2'], ['O2'],
1666 UL([]), UL(['O3']), UL(['O3']),
1667 UL([]), '', UL([]),
1668 UL([]), [], UL([]),
1669 UL([]), UL([]), UL([]),
1670 UL([]), [''], UL(['']),
1671 UL([]), UL(['']), UL(['']),
1673 [''], 'P1', ['', 'P1'],
1674 [''], ['P2'], ['', 'P2'],
1675 [''], UL(['P3']), UL(['', 'P3']),
1676 [''], '', [''],
1677 [''], [], [''],
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(['', '']),
1692 env = Environment()
1693 failed = 0
1694 while cases:
1695 input, append, expect = cases[:3]
1696 env['XXX'] = copy.copy(input)
1697 try:
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))
1703 failed = failed + 1
1704 else:
1705 result = env['XXX']
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)))
1710 failed = failed + 1
1711 del cases[:3]
1712 assert failed == 0, "%d Append() cases failed" % failed
1714 env['UL'] = UL(['foo'])
1715 env.Append(UL = 'bar')
1716 result = env['UL']
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
1726 class C:
1727 def __init__(self, name) -> None:
1728 self.name = name
1729 def __str__(self) -> str:
1730 return self.name
1731 def __eq__(self, other):
1732 raise Exception("should not compare")
1734 ccc = C('ccc')
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']
1748 z1 = Builder()
1749 z2 = Builder()
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=';')
1766 assert (
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=';')
1771 env1.AppendENVPath(
1772 'MYPATH', r'C:\mydir\num\one', 'MYENV', sep=';', delete_existing=1
1774 # this should do nothing since delete_existing is 0
1775 assert (
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
1790 involved."""
1791 env = self.TestEnvironment(AAA1 = 'a1',
1792 AAA2 = 'a2',
1793 AAA3 = 'a3',
1794 AAA4 = 'a4',
1795 AAA5 = 'a5',
1796 BBB1 = ['b1'],
1797 BBB2 = ['b2'],
1798 BBB3 = ['b3'],
1799 BBB4 = ['b4'],
1800 BBB5 = ['b5'],
1801 CCC1 = '',
1802 CCC2 = '',
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',
1807 AAA2 = ['a2'],
1808 AAA3 = ['a3', 'b', 'c', 'c', 'b', 'a3'], # ignore dups
1809 AAA4 = 'a4.new',
1810 AAA5 = ['a5.new'],
1811 BBB1 = 'b1',
1812 BBB2 = ['b2'],
1813 BBB3 = ['b3', 'c', 'd', 'c', 'b3'],
1814 BBB4 = 'b4.new',
1815 BBB5 = ['b5.new'],
1816 CCC1 = 'c1',
1817 CCC2 = ['c2'],
1818 DDD1 = 'b',
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')
1876 env2 = env1.Clone()
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():
1896 class TestA:
1897 pass
1899 env1 = self.TestEnvironment(
1900 XXX=TestA(),
1901 YYY=[1, 2, 3],
1902 ZZZ={1: 2, 3: 4}
1904 env2 = env1.Clone()
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]),
1918 YYY=UL([1, 2, 3]),
1919 ZZZ=UD({1: 2, 3: 4}),
1921 env2 = env1.Clone()
1922 env2['XXX'].append(4)
1923 env2['YYY'].append(4)
1924 env2['ZZZ'][5] = 6
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()})
1938 assert env2 != env1
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:
1949 env['FOO'] = 1
1951 def bar(env) -> None:
1952 env['BAR'] = 2
1954 def baz(env) -> None:
1955 env['BAZ'] = 3
1957 env1 = self.TestEnvironment(tools=[foo])
1958 env2 = env1.Clone()
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')
1975 env2 = env1.Clone(
1976 CCFLAGS='$CCFLAGS -DBAR', XYZ=['-DABC', 'x $XYZ y', '-DDEF']
1978 x = env2.get('CCFLAGS')
1979 assert x == '-DFOO -DBAR', x
1980 x = env2.get('XYZ')
1981 assert x == ['-DABC', 'x -DXYZ y', '-DDEF'], x
1983 # Ensure that special properties of a class don't get
1984 # lost on copying.
1985 with self.subTest():
1986 env1 = self.TestEnvironment(FLAGS=CLVar('flag1 flag2'))
1987 x = env1.get('FLAGS')
1988 assert x == ['flag1', 'flag2'], x
1989 env2 = env1.Clone()
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
2002 env2 = env1.Clone()
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', """\
2015 def exists(env):
2016 return True
2017 def generate(env):
2018 env['XXX'] = 'one'
2019 """)
2021 test.write('yyy.py', """\
2022 def exists(env):
2023 return True
2024 def generate(env):
2025 env['YYY'] = 'two'
2026 """)
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']
2033 # Test that
2034 with self.subTest():
2035 real_value = [4]
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()
2043 real_value[0] = 5
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']
2047 real_value[0] = 6
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
2056 env2 = env.Clone()
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')
2072 assert x is None, x
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
2086 else:
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')
2093 assert x is None, x
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')
2111 assert x is None, x
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')
2124 assert xxx == 'x'
2125 assert zzz == 'z'
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'
2132 env['XXX'] = 'foo'
2133 assert env.Dictionary('XXX') == 'foo'
2134 del env['XXX']
2135 assert 'XXX' not in env.Dictionary()
2137 def test_FindIxes(self) -> None:
2138 """Test FindIxes()"""
2139 env = self.TestEnvironment(LIBPREFIX='lib',
2140 LIBSUFFIX='.a',
2141 SHLIBPREFIX='lib',
2142 SHLIBSUFFIX='.so',
2143 PREFIX='pre',
2144 SUFFIX='post')
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',
2163 CCFLAGS=[''],
2164 CPPDEFINES=[],
2165 CPPFLAGS=[''],
2166 CPPPATH='string',
2167 FRAMEWORKPATH=[],
2168 FRAMEWORKS=[],
2169 LIBPATH=['list'],
2170 LIBS='',
2171 LINKFLAGS=[''],
2172 RPATH=[])
2174 orig_backtick = env.backtick
2175 class my_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)
2185 return self.output
2187 try:
2188 save_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 " + \
2195 "-Wl,-Rrpath3 " + \
2196 "-Wp,-cpp abc " + \
2197 "-framework Carbon " + \
2198 "-frameworkdir=fwd1 " + \
2199 "-Ffwd2 " + \
2200 "-F fwd3 " + \
2201 "-pthread " + \
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 " + \
2208 "+DD64 " + \
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',
2230 ('-arch', 'i386'),
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']
2240 finally:
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:
2247 import json
2249 args = json.loads(flags)
2250 if unique:
2251 myenv.AppendUnique(**args)
2252 else:
2253 myenv.Append(**args)
2255 json_str = '{"LIBS": ["yyy", "xxx", "yyy"]}'
2257 env = Environment(LIBS=['xxx'])
2258 env2 = env.Clone()
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', """
2274 #file: dependency
2276 f0: \
2277 d1 \
2278 d2 \
2279 d3 \
2281 """)
2283 test.write('multiple', """
2284 f1: foo
2285 f2 f3: bar
2286 f4: abc def
2287 #file: dependency
2288 f5: \
2289 ghi \
2290 jkl \
2291 mno \
2292 """)
2294 env = self.TestEnvironment(SINGLE = test.workpath('single'))
2296 tlist = []
2297 dlist = []
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'))
2306 exc_caught = None
2307 try:
2308 env.ParseDepends(test.workpath('does_not_exist'), must_exist=True)
2309 except IOError:
2310 exc_caught = 1
2311 assert exc_caught, "did not catch expected IOError"
2313 del tlist[:]
2314 del dlist[:]
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
2322 del tlist[:]
2323 del dlist[:]
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
2331 exc_caught = None
2332 try:
2333 env.ParseDepends(test.workpath('multiple'), only_one=True)
2334 except SCons.Errors.UserError:
2335 exc_caught = 1
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')
2342 exc_caught = None
2343 try:
2344 env.Platform('does_not_exist')
2345 except SCons.Errors.UserError:
2346 exc_caught = 1
2347 assert exc_caught, "did not catch expected UserError"
2349 exc_caught = None
2350 try:
2351 env.Platform('$NONE')
2352 except SCons.Errors.UserError:
2353 exc_caught = 1
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
2365 cases = [
2366 'a1', 'A1', 'A1a1',
2367 'a2', ['A2'], ['A2', 'a2'],
2368 'a3', UL(['A3']), UL(['A3', 'a', '3']),
2369 'a4', '', 'a4',
2370 'a5', [], ['a5'],
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']),
2378 ['e4'], '', ['e4'],
2379 ['e5'], [], ['e5'],
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}),
2405 '', 'M1', 'M1',
2406 '', ['M2'], ['M2'],
2407 '', UL(['M3']), UL(['M3']),
2408 '', '', '',
2409 '', [], [],
2410 '', UL([]), UL([]),
2411 '', [''], [''],
2412 '', UL(['']), UL(['']),
2414 [], 'N1', ['N1'],
2415 [], ['N2'], ['N2'],
2416 [], UL(['N3']), UL(['N3']),
2417 [], '', [],
2418 [], [], [],
2419 [], UL([]), UL([]),
2420 [], [''], [''],
2421 [], UL(['']), UL(['']),
2423 UL([]), 'O1', UL(['O', '1']),
2424 UL([]), ['O2'], UL(['O2']),
2425 UL([]), UL(['O3']), UL(['O3']),
2426 UL([]), '', UL([]),
2427 UL([]), [], UL([]),
2428 UL([]), UL([]), UL([]),
2429 UL([]), [''], UL(['']),
2430 UL([]), UL(['']), UL(['']),
2432 [''], 'P1', ['P1', ''],
2433 [''], ['P2'], ['P2', ''],
2434 [''], UL(['P3']), UL(['P3', '']),
2435 [''], '', [''],
2436 [''], [], [''],
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(['', '']),
2451 env = Environment()
2452 failed = 0
2453 while cases:
2454 input, prepend, expect = cases[:3]
2455 env['XXX'] = copy.copy(input)
2456 try:
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))
2462 failed = failed + 1
2463 else:
2464 result = env['XXX']
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)))
2469 failed = failed + 1
2470 del cases[:3]
2471 assert failed == 0, "%d Prepend() cases failed" % failed
2473 env['UL'] = UL(['foo'])
2474 env.Prepend(UL = 'bar')
2475 result = env['UL']
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']
2490 z1 = Builder()
2491 z2 = Builder()
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=';')
2507 assert (
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
2517 assert (
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
2532 involved."""
2533 env = self.TestEnvironment(AAA1 = 'a1',
2534 AAA2 = 'a2',
2535 AAA3 = 'a3',
2536 AAA4 = 'a4',
2537 AAA5 = 'a5',
2538 BBB1 = ['b1'],
2539 BBB2 = ['b2'],
2540 BBB3 = ['b3'],
2541 BBB4 = ['b4'],
2542 BBB5 = ['b5'],
2543 CCC1 = '',
2544 CCC2 = '',
2545 DDD1 = ['a', 'b', 'c'])
2546 env.PrependUnique(AAA1 = 'a1',
2547 AAA2 = ['a2'],
2548 AAA3 = ['a3', 'b', 'c', 'b', 'a3'], # ignore dups
2549 AAA4 = 'a4.new',
2550 AAA5 = ['a5.new'],
2551 BBB1 = 'b1',
2552 BBB2 = ['b2'],
2553 BBB3 = ['b3', 'b', 'c', 'b3'],
2554 BBB4 = 'b4.new',
2555 BBB5 = ['b5.new'],
2556 CCC1 = 'c1',
2557 CCC2 = ['c2'],
2558 DDD1 = 'b')
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)
2610 b1 = Builder()
2611 b2 = Builder()
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',
2621 LIBSUFFIX='.a',
2622 SHLIBPREFIX='lib',
2623 SHLIBSUFFIX='.so',
2624 PREFIX='pre',
2625 SUFFIX='post')
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',
2636 'PREFIX', 'SUFFIX',
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
2645 env['V2'] = 2
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')
2653 exc_caught = None
2654 try:
2655 tool = env.Tool('does_not_exist')
2656 except SCons.Errors.UserError:
2657 exc_caught = 1
2658 else:
2659 assert isinstance(tool, SCons.Tool.Tool)
2660 assert exc_caught, "did not catch expected UserError"
2662 exc_caught = None
2663 try:
2664 env.Tool('$NONE')
2665 except SCons.Errors.UserError:
2666 exc_caught = 1
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']
2674 env.Tool('$LINK')
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', """\
2682 def exists(env):
2683 return True
2684 def generate(env):
2685 env['XXX'] = 'one'
2686 """)
2688 test.write('yyy.py', """\
2689 def exists(env):
2690 return True
2691 def generate(env):
2692 env['YYY'] = 'two'
2693 """)
2695 env = self.TestEnvironment(tools=['xxx'], toolpath=[test.workpath('')])
2696 assert env['XXX'] == 'one', env['XXX']
2697 env.Tool('yyy')
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('')
2739 assert wi is None
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"""
2781 import SCons.Action
2783 env = self.TestEnvironment(FOO = 'xyzzy')
2785 a = env.Action('foo')
2786 assert a, a
2787 assert a.__class__ is SCons.Action.CommandAction, a.__class__
2789 a = env.Action('$FOO')
2790 assert a, a
2791 assert a.__class__ is SCons.Action.CommandAction, a.__class__
2793 a = env.Action('$$FOO')
2794 assert a, a
2795 assert a.__class__ is SCons.Action.LazyAction, a.__class__
2797 a = env.Action(['$FOO', 'foo'])
2798 assert a, a
2799 assert a.__class__ is SCons.Action.ListAction, a.__class__
2801 def func(arg) -> None:
2802 pass
2803 a = env.Action(func)
2804 assert a, a
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]
2853 assert n is tgt, n
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]
2859 assert n is tgt, n
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"""
2920 class MyFS:
2921 def Dir(self, name):
2922 return 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')
2929 env.fs = MyFS()
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:
2955 pass
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
2979 env.CacheDir('$CD')
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
2984 import SCons.Action
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."""
3019 env = Environment()
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
3037 return 0
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'],
3042 action=act)[0]
3043 assert t.builder is not None
3044 assert t.builder.action.__class__.__name__ == 'FunctionAction'
3045 t.build()
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]
3049 x = []
3050 def test2(baz, x=x) -> None:
3051 x.append(baz)
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
3057 t.build()
3058 assert x[0] == 'magic word', x
3060 t = env.Command(target='${X}.out', source='${X}.in',
3061 action = 'foo',
3062 X = 'xxx')[0]
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',
3068 action = 'foo',
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 = '')
3076 save = os.getcwd()
3078 try:
3079 os.chdir(test.workpath())
3081 env = self.TestEnvironment(FOO = 'xyzzy')
3083 def func(arg) -> None:
3084 pass
3086 c = env.Configure()
3087 assert c is not None, c
3088 c.Finish()
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')
3094 c.Finish()
3095 finally:
3096 os.chdir(save)
3098 def test_Depends(self) -> None:
3099 """Test the explicit Depends method."""
3100 env = self.TestEnvironment(FOO = 'xxx', BAR='yyy')
3101 env.Dir('dir1')
3102 env.Dir('dir2')
3103 env.File('xxx.py')
3104 env.File('yyy.py')
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
3110 d = t.depends[0]
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
3118 d = t.depends[0]
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
3126 d = t.depends[0]
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"""
3132 class MyFS:
3133 def Dir(self, name) -> str:
3134 return 'Dir(%s)' % name
3136 env = self.TestEnvironment(FOO = 'foodir', BAR = 'bardir')
3137 env.fs = MyFS()
3139 d = env.Dir('d')
3140 assert d == 'Dir(d)', d
3142 d = env.Dir('$FOO')
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')
3157 env.Dir('p_hhhb')
3158 env.File('p_d')
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'
3163 assert t[0].noclean
3164 assert t[1].__class__.__name__ == 'Dir', t[1].__class__.__name__
3165 assert t[1].get_internal_path() == 'p_hhhb'
3166 assert t[1].noclean
3167 assert t[2].__class__.__name__ == 'Entry', t[2].__class__.__name__
3168 assert t[2].get_internal_path() == 'p_c'
3169 assert t[2].noclean
3170 assert t[3].__class__.__name__ == 'File', t[3].__class__.__name__
3171 assert t[3].get_internal_path() == 'p_d'
3172 assert t[3].noclean
3173 assert t[4].__class__.__name__ == 'Entry', t[4].__class__.__name__
3174 assert t[4].get_internal_path() == 'p_ggg'
3175 assert t[4].noclean
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)
3187 import json
3188 env_dict = json.loads(env.Dump(format = 'json'))
3189 assert env_dict['FOO'] == 'foo' # full JSON version
3191 try:
3192 env.Dump(format = 'markdown')
3193 except ValueError as e:
3194 assert str(e) == "Unsupported serialization format: markdown."
3195 else:
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"""
3209 class MyAction:
3210 def __init__(self, *args, **kw) -> None:
3211 self.args = args
3212 def __call__(self, target, source, env) -> str:
3213 return "%s executed" % self.args
3215 env = Environment()
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"""
3223 class MyFS:
3224 def Entry(self, name) -> str:
3225 return 'Entry(%s)' % name
3227 env = self.TestEnvironment(FOO = 'fooentry', BAR = 'barentry')
3228 env.fs = MyFS()
3230 e = env.Entry('e')
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"""
3247 class MyFS:
3248 def File(self, name) -> str:
3249 return 'File(%s)' % name
3251 env = self.TestEnvironment(FOO = 'foofile', BAR = 'barfile')
3252 env.fs = MyFS()
3254 f = env.File('f')
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'])
3274 assert r is None, r
3276 # XXX
3278 def test_Flatten(self) -> None:
3279 """Test the Flatten() method"""
3280 env = Environment()
3281 l = env.Flatten([1])
3282 assert l == [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')
3299 env.Dir('dir1')
3300 env.Dir('dir2')
3301 env.File('yyyzzz')
3302 env.File('zzzyyy')
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
3308 i = t.ignore[0]
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
3316 i = t.ignore[0]
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
3324 i = t.ignore[0]
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')
3350 env.Dir('p_hhhb')
3351 env.File('p_d')
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')
3373 env.Dir('p_hhhb')
3374 env.File('p_d')
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'
3379 assert t[0].pseudo
3380 assert t[1].__class__.__name__ == 'Dir', t[1].__class__.__name__
3381 assert t[1].get_internal_path() == 'p_hhhb'
3382 assert t[1].pseudo
3383 assert t[2].__class__.__name__ == 'Entry', t[2].__class__.__name__
3384 assert t[2].get_internal_path() == 'p_c'
3385 assert t[2].pseudo
3386 assert t[3].__class__.__name__ == 'File', t[3].__class__.__name__
3387 assert t[3].get_internal_path() == 'p_d'
3388 assert t[3].pseudo
3389 assert t[4].__class__.__name__ == 'Entry', t[4].__class__.__name__
3390 assert t[4].get_internal_path() == 'p_ggg'
3391 assert t[4].pseudo
3393 def test_Repository(self) -> None:
3394 """Test the Repository() method."""
3395 class MyFS:
3396 def __init__(self) -> None:
3397 self.list = []
3398 def Repository(self, *dirs) -> None:
3399 self.list.extend(list(dirs))
3400 def Dir(self, name):
3401 return name
3402 env = self.TestEnvironment(FOO='rrr', BAR='sss')
3403 env.fs = MyFS()
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:
3412 pass
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
3422 if 0:
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
3433 class MyFS:
3434 SConstruct_dir = os.sep + 'dir'
3436 env = self.TestEnvironment(FOO = 'SConsign',
3437 BAR = os.path.join(os.sep, 'File'))
3438 env.fs = MyFS()
3439 env.Execute = lambda action: None
3441 try:
3442 fnames = []
3443 dbms = []
3444 def capture(name, dbm_module, fnames=fnames, dbms=dbms) -> None:
3445 fnames.append(name)
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
3475 env.SConsignFile()
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
3482 finally:
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)
3495 s = s[0]
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)
3506 s = s[0]
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)
3517 s = s[0]
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
3550 env = Environment()
3551 v1 = env.Value('a')
3552 assert v1.value == 'a', v1.value
3554 value2 = 'a'
3555 v2 = env.Value(value2)
3556 assert v2.value == value2, v2.value
3557 assert v2.value is value2, v2.value
3559 assert v1 is v2
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
3582 f = env.xxx('$FOO')
3583 assert f == 'foo', f
3585 def test_bad_keywords(self) -> None:
3586 """Test trying to use reserved keywords in an Environment"""
3587 added = []
3589 env = self.TestEnvironment(TARGETS = 'targets',
3590 SOURCES = 'sources',
3591 SOURCE = 'source',
3592 TARGET = 'target',
3593 CHANGED_SOURCES = 'changed_sources',
3594 CHANGED_TARGETS = 'changed_targets',
3595 UNCHANGED_SOURCES = 'unchanged_sources',
3596 UNCHANGED_TARGETS = 'unchanged_targets',
3597 INIT = 'init')
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]
3602 for x in added:
3603 assert x in env, bad_msg % x
3605 env.Append(TARGETS = 'targets',
3606 SOURCES = 'sources',
3607 SOURCE = 'source',
3608 TARGET = 'target',
3609 CHANGED_SOURCES = 'changed_sources',
3610 CHANGED_TARGETS = 'changed_targets',
3611 UNCHANGED_SOURCES = 'unchanged_sources',
3612 UNCHANGED_TARGETS = 'unchanged_targets',
3613 APPEND = 'append')
3614 added.append('APPEND')
3615 for x in self.reserved_variables:
3616 assert x not in env, env[x]
3617 for x in added:
3618 assert x in env, bad_msg % x
3620 env.AppendUnique(TARGETS = 'targets',
3621 SOURCES = 'sources',
3622 SOURCE = 'source',
3623 TARGET = 'target',
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]
3632 for x in added:
3633 assert x in env, bad_msg % x
3635 env.Prepend(TARGETS = 'targets',
3636 SOURCES = 'sources',
3637 SOURCE = 'source',
3638 TARGET = 'target',
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]
3647 for x in added:
3648 assert x in env, bad_msg % x
3650 env.Prepend(TARGETS = 'targets',
3651 SOURCES = 'sources',
3652 SOURCE = 'source',
3653 TARGET = 'target',
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]
3662 for x in added:
3663 assert x in env, bad_msg % x
3665 env.Replace(TARGETS = 'targets',
3666 SOURCES = 'sources',
3667 SOURCE = 'source',
3668 TARGET = 'target',
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]
3677 for x in added:
3678 assert x in env, bad_msg % x
3680 copy = env.Clone(TARGETS = 'targets',
3681 SOURCES = 'sources',
3682 SOURCE = 'source',
3683 TARGET = 'target',
3684 CHANGED_SOURCES = 'changed_sources',
3685 CHANGED_TARGETS = 'changed_targets',
3686 UNCHANGED_SOURCES = 'unchanged_sources',
3687 UNCHANGED_TARGETS = 'unchanged_targets',
3688 COPY = 'copy')
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:
3748 env = Environment()
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
3775 del env3['XXX']
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?"
3780 del env3['YYY']
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?"
3785 del env3['ZZZ']
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
3833 del env3['XXX']
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
3881 gvars = env.gvars()
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
3891 lvars = env.lvars()
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):
3925 # ParseConfig()
3926 # ParseDepends()
3927 # Platform()
3928 # Tool()
3930 # Action()
3931 # Alias()
3932 # Builder()
3933 # CacheDir()
3934 # Configure()
3935 # Environment()
3936 # FindFile()
3937 # Scanner()
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"""
3943 # pass
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"""
3969 # pass
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"""
4058 env = Environment()
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')
4085 assert x == 'x', x
4086 x = proxy.subst('$XXX')
4087 assert x == '$XXX', x
4089 x = proxy.subst('$YYY', raw=7, target=None, source=None,
4090 conv=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')
4122 assert x == [[]], x
4124 x = proxy.subst_list('$YYY', raw=0, target=None, source=None, conv=None)
4125 assert x == [[]], x
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__":
4146 unittest.main()
4148 # Local Variables:
4149 # tab-width:4
4150 # indent-tabs-mode:nil
4151 # End:
4152 # vim: set expandtab tabstop=4 shiftwidth=4: