switch from embedding LIBLITERAL in _stripixes() to being a passed argument with...
[scons.git] / SCons / EnvironmentTests.py
blobb1b6a0d648daf517cd5890a9ebd27a44d8322def
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,
41 is_valid_construction_var,
43 from SCons.Util import CLVar
44 from SCons.SConsign import current_sconsign_filename
47 def diff_env(env1, env2):
48 s1 = "env1 = {\n"
49 s2 = "env2 = {\n"
50 d = {}
51 for k in list(env1._dict.keys()) + list(env2._dict.keys()):
52 d[k] = None
53 for k in sorted(d.keys()):
54 if k in env1:
55 if k in env2:
56 if env1[k] != env2[k]:
57 s1 = s1 + " " + repr(k) + " : " + repr(env1[k]) + "\n"
58 s2 = s2 + " " + repr(k) + " : " + repr(env2[k]) + "\n"
59 else:
60 s1 = s1 + " " + repr(k) + " : " + repr(env1[k]) + "\n"
61 elif k in env2:
62 s2 = s2 + " " + repr(k) + " : " + repr(env2[k]) + "\n"
63 s1 = s1 + "}\n"
64 s2 = s2 + "}\n"
65 return s1 + s2
67 def diff_dict(d1, d2):
68 s1 = "d1 = {\n"
69 s2 = "d2 = {\n"
70 d = {}
71 for k in list(d1.keys()) + list(d2.keys()):
72 d[k] = None
73 for k in sorted(d.keys()):
74 if k in d1:
75 if k in d2:
76 if d1[k] != d2[k]:
77 s1 = s1 + " " + repr(k) + " : " + repr(d1[k]) + "\n"
78 s2 = s2 + " " + repr(k) + " : " + repr(d2[k]) + "\n"
79 else:
80 s1 = s1 + " " + repr(k) + " : " + repr(d1[k]) + "\n"
81 elif k in d2:
82 s2 = s2 + " " + repr(k) + " : " + repr(d2[k]) + "\n"
83 s1 = s1 + "}\n"
84 s2 = s2 + "}\n"
85 return s1 + s2
87 called_it = {}
88 built_it = {}
90 class Builder(SCons.Builder.BuilderBase):
91 """A dummy Builder class for testing purposes. "Building"
92 a target is simply setting a value in the dictionary.
93 """
94 def __init__(self, name = None) -> None:
95 self.name = name
97 def __call__(self, env, target=None, source=None, **kw) -> None:
98 global called_it
99 called_it['target'] = target
100 called_it['source'] = source
101 called_it.update(kw)
103 def execute(self, target = None, **kw) -> None:
104 global built_it
105 built_it[target] = 1
109 scanned_it = {}
111 class Scanner:
112 """A dummy Scanner class for testing purposes. "Scanning"
113 a target is simply setting a value in the dictionary.
115 def __init__(self, name, skeys=[]) -> None:
116 self.name = name
117 self.skeys = skeys
119 def __call__(self, filename) -> None:
120 global scanned_it
121 scanned_it[filename] = 1
123 def __eq__(self, other):
124 try:
125 return self.__dict__ == other.__dict__
126 except AttributeError:
127 return False
129 def get_skeys(self, env):
130 return self.skeys
132 def __str__(self) -> str:
133 return self.name
136 class DummyNode:
137 def __init__(self, name) -> None:
138 self.name = name
139 def __str__(self) -> str:
140 return self.name
141 def rfile(self):
142 return self
143 def get_subst_proxy(self):
144 return self
146 def test_tool( env ) -> None:
147 env['_F77INCFLAGS'] = '${_concat(INCPREFIX, F77PATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE, affect_signature=False)}'
149 class TestEnvironmentFixture:
150 def TestEnvironment(self, *args, **kw):
151 if not kw or 'tools' not in kw:
152 kw['tools'] = [test_tool]
153 default_keys = { 'CC' : 'cc',
154 'CCFLAGS' : '-DNDEBUG',
155 'ENV' : { 'TMP' : '/tmp' } }
156 for key, value in default_keys.items():
157 if key not in kw:
158 kw[key] = value
159 if 'BUILDERS' not in kw:
160 static_obj = SCons.Builder.Builder(action = {},
161 emitter = {},
162 suffix = '.o',
163 single_source = 1)
164 kw['BUILDERS'] = {'Object' : static_obj}
165 static_obj.add_action('.cpp', 'fake action')
167 env = Environment(*args, **kw)
168 return env
170 class SubstitutionTestCase(unittest.TestCase):
172 def test___init__(self) -> None:
173 """Test initializing a SubstitutionEnvironment."""
174 env = SubstitutionEnvironment()
175 assert '__env__' not in env
177 def test___cmp__(self) -> None:
178 """Test comparing SubstitutionEnvironments."""
179 env1 = SubstitutionEnvironment(XXX = 'x')
180 env2 = SubstitutionEnvironment(XXX = 'x')
181 env3 = SubstitutionEnvironment(XXX = 'xxx')
182 env4 = SubstitutionEnvironment(XXX = 'x', YYY = 'x')
184 assert env1 == env2
185 assert env1 != env3
186 assert env1 != env4
188 def test___delitem__(self) -> None:
189 """Test deleting a variable from a SubstitutionEnvironment."""
190 env1 = SubstitutionEnvironment(XXX = 'x', YYY = 'y')
191 env2 = SubstitutionEnvironment(XXX = 'x')
192 del env1['YYY']
193 assert env1 == env2
195 def test___getitem__(self) -> None:
196 """Test fetching a variable from a SubstitutionEnvironment."""
197 env = SubstitutionEnvironment(XXX = 'x')
198 assert env['XXX'] == 'x', env['XXX']
200 def test___setitem__(self) -> None:
201 """Test setting a variable in a SubstitutionEnvironment."""
202 env1 = SubstitutionEnvironment(XXX = 'x')
203 env2 = SubstitutionEnvironment(XXX = 'x', YYY = 'y')
204 env1['YYY'] = 'y'
205 assert env1 == env2
207 def test_get(self) -> None:
208 """Test the SubstitutionEnvironment get() method."""
209 env = SubstitutionEnvironment(XXX = 'x')
210 assert env.get('XXX') == 'x', env.get('XXX')
211 assert env.get('YYY') is None, env.get('YYY')
213 def test_contains(self) -> None:
214 """Test the SubstitutionEnvironment __contains__() method."""
215 env = SubstitutionEnvironment(XXX = 'x')
216 assert 'XXX' in env
217 assert 'YYY' not in env
219 def test_keys(self) -> None:
220 """Test the SubstitutionEnvironment keys() method."""
221 testdata = {'XXX': 'x', 'YYY': 'y'}
222 env = SubstitutionEnvironment(**testdata)
223 keys = list(env.keys())
224 assert len(keys) == 2, keys
225 for k in testdata.keys():
226 assert k in keys, keys
228 def test_values(self) -> None:
229 """Test the SubstitutionEnvironment values() method."""
230 testdata = {'XXX': 'x', 'YYY': 'y'}
231 env = SubstitutionEnvironment(**testdata)
232 values = list(env.values())
233 assert len(values) == 2, values
234 for v in testdata.values():
235 assert v in values, values
237 def test_items(self) -> None:
238 """Test the SubstitutionEnvironment items() method."""
239 testdata = {'XXX': 'x', 'YYY': 'y'}
240 env = SubstitutionEnvironment(**testdata)
241 items = list(env.items())
242 assert len(items) == 2, items
243 for k, v in testdata.items():
244 assert (k, v) in items, items
246 def test_setdefault(self) -> None:
247 """Test the SubstitutionEnvironment setdefault() method."""
248 env = SubstitutionEnvironment(XXX = 'x')
249 assert env.setdefault('XXX', 'z') == 'x', env['XXX']
250 assert env.setdefault('YYY', 'y') == 'y', env['YYY']
251 assert 'YYY' in env
253 def test_arg2nodes(self) -> None:
254 """Test the arg2nodes method."""
255 env = SubstitutionEnvironment()
256 dict = {}
257 class X(SCons.Node.Node):
258 pass
259 def Factory(name, directory = None, create: int = 1, dict=dict, X=X):
260 if name not in dict:
261 dict[name] = X()
262 dict[name].name = name
263 return dict[name]
265 nodes = env.arg2nodes("Util.py UtilTests.py", Factory)
266 assert len(nodes) == 1, nodes
267 assert isinstance(nodes[0], X)
268 assert nodes[0].name == "Util.py UtilTests.py", nodes[0].name
270 nodes = env.arg2nodes(["Util.py", "UtilTests.py"], Factory)
271 assert len(nodes) == 2, nodes
272 assert isinstance(nodes[0], X)
273 assert isinstance(nodes[1], X)
274 assert nodes[0].name == "Util.py", nodes[0].name
275 assert nodes[1].name == "UtilTests.py", nodes[1].name
277 n1 = Factory("Util.py")
278 nodes = env.arg2nodes([n1, "UtilTests.py"], Factory)
279 assert len(nodes) == 2, nodes
280 assert isinstance(nodes[0], X)
281 assert isinstance(nodes[1], X)
282 assert nodes[0].name == "Util.py", nodes[0].name
283 assert nodes[1].name == "UtilTests.py", nodes[1].name
285 class SConsNode(SCons.Node.Node):
286 pass
287 nodes = env.arg2nodes(SConsNode())
288 assert len(nodes) == 1, nodes
289 assert isinstance(nodes[0], SConsNode), nodes[0]
291 class OtherNode:
292 pass
293 nodes = env.arg2nodes(OtherNode())
294 assert len(nodes) == 1, nodes
295 assert isinstance(nodes[0], OtherNode), nodes[0]
297 def lookup_a(str, F=Factory):
298 if str[0] == 'a':
299 n = F(str)
300 n.a = 1
301 return n
302 else:
303 return None
305 def lookup_b(str, F=Factory):
306 if str[0] == 'b':
307 n = F(str)
308 n.b = 1
309 return n
310 else:
311 return None
313 env_ll = SubstitutionEnvironment()
314 env_ll.lookup_list = [lookup_a, lookup_b]
316 nodes = env_ll.arg2nodes(['aaa', 'bbb', 'ccc'], Factory)
317 assert len(nodes) == 3, nodes
319 assert nodes[0].name == 'aaa', nodes[0]
320 assert nodes[0].a == 1, nodes[0]
321 assert not hasattr(nodes[0], 'b'), nodes[0]
323 assert nodes[1].name == 'bbb'
324 assert not hasattr(nodes[1], 'a'), nodes[1]
325 assert nodes[1].b == 1, nodes[1]
327 assert nodes[2].name == 'ccc'
328 assert not hasattr(nodes[2], 'a'), nodes[1]
329 assert not hasattr(nodes[2], 'b'), nodes[1]
331 def lookup_bbbb(str, F=Factory):
332 if str == 'bbbb':
333 n = F(str)
334 n.bbbb = 1
335 return n
336 else:
337 return None
339 def lookup_c(str, F=Factory):
340 if str[0] == 'c':
341 n = F(str)
342 n.c = 1
343 return n
344 else:
345 return None
347 nodes = env.arg2nodes(['bbbb', 'ccc'], Factory,
348 [lookup_c, lookup_bbbb, lookup_b])
349 assert len(nodes) == 2, nodes
351 assert nodes[0].name == 'bbbb'
352 assert not hasattr(nodes[0], 'a'), nodes[1]
353 assert not hasattr(nodes[0], 'b'), nodes[1]
354 assert nodes[0].bbbb == 1, nodes[1]
355 assert not hasattr(nodes[0], 'c'), nodes[0]
357 assert nodes[1].name == 'ccc'
358 assert not hasattr(nodes[1], 'a'), nodes[1]
359 assert not hasattr(nodes[1], 'b'), nodes[1]
360 assert not hasattr(nodes[1], 'bbbb'), nodes[0]
361 assert nodes[1].c == 1, nodes[1]
363 def test_arg2nodes_target_source(self) -> None:
364 """Test the arg2nodes method with target= and source= keywords
366 targets = [DummyNode('t1'), DummyNode('t2')]
367 sources = [DummyNode('s1'), DummyNode('s2')]
368 env = SubstitutionEnvironment()
369 nodes = env.arg2nodes(['${TARGET}-a',
370 '${SOURCE}-b',
371 '${TARGETS[1]}-c',
372 '${SOURCES[1]}-d'],
373 DummyNode,
374 target=targets,
375 source=sources)
376 names = [n.name for n in nodes]
377 assert names == ['t1-a', 's1-b', 't2-c', 's2-d'], names
379 def test_gvars(self) -> None:
380 """Test the base class gvars() method"""
381 env = SubstitutionEnvironment()
382 gvars = env.gvars()
383 assert gvars == {}, gvars
385 def test_lvars(self) -> None:
386 """Test the base class lvars() method"""
387 env = SubstitutionEnvironment()
388 lvars = env.lvars()
389 assert lvars == {}, lvars
391 def test_subst(self) -> None:
392 """Test substituting construction variables within strings
394 Check various combinations, including recursive expansion
395 of variables into other variables.
397 env = SubstitutionEnvironment(AAA = 'a', BBB = 'b')
398 mystr = env.subst("$AAA ${AAA}A $BBBB $BBB")
399 assert mystr == "a aA b", mystr
401 # Changed the tests below to reflect a bug fix in
402 # subst()
403 env = SubstitutionEnvironment(AAA = '$BBB', BBB = 'b', BBBA = 'foo')
404 mystr = env.subst("$AAA ${AAA}A ${AAA}B $BBB")
405 assert mystr == "b bA bB b", mystr
407 env = SubstitutionEnvironment(AAA = '$BBB', BBB = '$CCC', CCC = 'c')
408 mystr = env.subst("$AAA ${AAA}A ${AAA}B $BBB")
409 assert mystr == "c cA cB c", mystr
411 # Lists:
412 env = SubstitutionEnvironment(AAA = ['a', 'aa', 'aaa'])
413 mystr = env.subst("$AAA")
414 assert mystr == "a aa aaa", mystr
416 # Tuples:
417 env = SubstitutionEnvironment(AAA = ('a', 'aa', 'aaa'))
418 mystr = env.subst("$AAA")
419 assert mystr == "a aa aaa", mystr
421 t1 = DummyNode('t1')
422 t2 = DummyNode('t2')
423 s1 = DummyNode('s1')
424 s2 = DummyNode('s2')
426 env = SubstitutionEnvironment(AAA = 'aaa')
427 s = env.subst('$AAA $TARGET $SOURCES', target=[t1, t2], source=[s1, s2])
428 assert s == "aaa t1 s1 s2", s
429 s = env.subst('$AAA $TARGETS $SOURCE', target=[t1, t2], source=[s1, s2])
430 assert s == "aaa t1 t2 s1", s
432 # Test callables in the SubstitutionEnvironment
433 def foo(target, source, env, for_signature):
434 assert str(target) == 't', target
435 assert str(source) == 's', source
436 return env["FOO"]
438 env = SubstitutionEnvironment(BAR=foo, FOO='baz')
439 t = DummyNode('t')
440 s = DummyNode('s')
442 subst = env.subst('test $BAR', target=t, source=s)
443 assert subst == 'test baz', subst
445 # Test not calling callables in the SubstitutionEnvironment
446 if 0:
447 # This will take some serious surgery to subst() and
448 # subst_list(), so just leave these tests out until we can
449 # do that.
450 def bar(arg) -> None:
451 pass
453 env = SubstitutionEnvironment(BAR=bar, FOO='$BAR')
455 subst = env.subst('$BAR', call=None)
456 assert subst is bar, subst
458 subst = env.subst('$FOO', call=None)
459 assert subst is bar, subst
461 def test_subst_kw(self) -> None:
462 """Test substituting construction variables within dictionaries"""
463 env = SubstitutionEnvironment(AAA = 'a', BBB = 'b')
464 kw = env.subst_kw({'$AAA' : 'aaa', 'bbb' : '$BBB'})
465 assert len(kw) == 2, kw
466 assert kw['a'] == 'aaa', kw['a']
467 assert kw['bbb'] == 'b', kw['bbb']
469 def test_subst_list(self) -> None:
470 """Test substituting construction variables in command lists
472 env = SubstitutionEnvironment(AAA = 'a', BBB = 'b')
473 l = env.subst_list("$AAA ${AAA}A $BBBB $BBB")
474 assert l == [["a", "aA", "b"]], l
476 # Changed the tests below to reflect a bug fix in
477 # subst()
478 env = SubstitutionEnvironment(AAA = '$BBB', BBB = 'b', BBBA = 'foo')
479 l = env.subst_list("$AAA ${AAA}A ${AAA}B $BBB")
480 assert l == [["b", "bA", "bB", "b"]], l
482 env = SubstitutionEnvironment(AAA = '$BBB', BBB = '$CCC', CCC = 'c')
483 l = env.subst_list("$AAA ${AAA}A ${AAA}B $BBB")
484 assert l == [["c", "cA", "cB", "c"]], l
486 env = SubstitutionEnvironment(AAA = '$BBB', BBB = '$CCC', CCC = [ 'a', 'b\nc' ])
487 lst = env.subst_list([ "$AAA", "B $CCC" ])
488 assert lst == [[ "a", "b"], ["c", "B a", "b"], ["c"]], lst
490 t1 = DummyNode('t1')
491 t2 = DummyNode('t2')
492 s1 = DummyNode('s1')
493 s2 = DummyNode('s2')
495 env = SubstitutionEnvironment(AAA = 'aaa')
496 s = env.subst_list('$AAA $TARGET $SOURCES', target=[t1, t2], source=[s1, s2])
497 assert s == [["aaa", "t1", "s1", "s2"]], s
498 s = env.subst_list('$AAA $TARGETS $SOURCE', target=[t1, t2], source=[s1, s2])
499 assert s == [["aaa", "t1", "t2", "s1"]], s
501 # Test callables in the SubstitutionEnvironment
502 def foo(target, source, env, for_signature):
503 assert str(target) == 't', target
504 assert str(source) == 's', source
505 return env["FOO"]
507 env = SubstitutionEnvironment(BAR=foo, FOO='baz')
508 t = DummyNode('t')
509 s = DummyNode('s')
511 lst = env.subst_list('test $BAR', target=t, source=s)
512 assert lst == [['test', 'baz']], lst
514 # Test not calling callables in the SubstitutionEnvironment
515 if 0:
516 # This will take some serious surgery to subst() and
517 # subst_list(), so just leave these tests out until we can
518 # do that.
519 def bar(arg) -> None:
520 pass
522 env = SubstitutionEnvironment(BAR=bar, FOO='$BAR')
524 subst = env.subst_list('$BAR', call=None)
525 assert subst is bar, subst
527 subst = env.subst_list('$FOO', call=None)
528 assert subst is bar, subst
530 def test_subst_path(self) -> None:
531 """Test substituting a path list
533 class MyProxy:
534 def __init__(self, val) -> None:
535 self.val = val
536 def get(self):
537 return self.val + '-proxy'
539 class MyNode:
540 def __init__(self, val) -> None:
541 self.val = val
542 def get_subst_proxy(self):
543 return self
544 def __str__(self) -> str:
545 return self.val
547 class MyObj:
548 def get(self):
549 return self
551 env = SubstitutionEnvironment(FOO='foo',
552 BAR='bar',
553 LIST=['one', 'two'],
554 PROXY=MyProxy('my1'))
556 r = env.subst_path('$FOO')
557 assert r == ['foo'], r
559 r = env.subst_path(['$FOO', 'xxx', '$BAR'])
560 assert r == ['foo', 'xxx', 'bar'], r
562 r = env.subst_path(['$FOO', '$LIST', '$BAR'])
563 assert list(map(str, r)) == ['foo', 'one two', 'bar'], r
565 r = env.subst_path(['$FOO', '$TARGET', '$SOURCE', '$BAR'])
566 assert r == ['foo', '', '', 'bar'], r
568 r = env.subst_path(['$FOO', '$TARGET', '$BAR'], target=MyNode('ttt'))
569 assert list(map(str, r)) == ['foo', 'ttt', 'bar'], r
571 r = env.subst_path(['$FOO', '$SOURCE', '$BAR'], source=MyNode('sss'))
572 assert list(map(str, r)) == ['foo', 'sss', 'bar'], r
574 n = MyObj()
576 r = env.subst_path(['$PROXY', MyProxy('my2'), n])
577 assert r == ['my1-proxy', 'my2-proxy', n], r
579 class StringableObj:
580 def __init__(self, s) -> None:
581 self.s = s
582 def __str__(self) -> str:
583 return self.s
585 env = SubstitutionEnvironment(FOO=StringableObj("foo"),
586 BAR=StringableObj("bar"))
588 r = env.subst_path([ "${FOO}/bar", "${BAR}/baz" ])
589 assert r == [ "foo/bar", "bar/baz" ], r
591 r = env.subst_path([ "bar/${FOO}", "baz/${BAR}" ])
592 assert r == [ "bar/foo", "baz/bar" ], r
594 r = env.subst_path([ "bar/${FOO}/bar", "baz/${BAR}/baz" ])
595 assert r == [ "bar/foo/bar", "baz/bar/baz" ], r
597 def test_subst_target_source(self) -> None:
598 """Test the base environment subst_target_source() method"""
599 env = SubstitutionEnvironment(AAA = 'a', BBB = 'b')
600 mystr = env.subst_target_source("$AAA ${AAA}A $BBBB $BBB")
601 assert mystr == "a aA b", mystr
603 def test_backtick(self) -> None:
604 """Test the backtick() method for capturing command output"""
605 env = SubstitutionEnvironment()
607 test = TestCmd.TestCmd(workdir = '')
608 test.write('stdout.py', """\
609 import sys
610 sys.stdout.write('this came from stdout.py\\n')
611 sys.exit(0)
612 """)
613 test.write('stderr.py', """\
614 import sys
615 sys.stderr.write('this came from stderr.py\\n')
616 sys.exit(0)
617 """)
618 test.write('fail.py', """\
619 import sys
620 sys.exit(1)
621 """)
622 test.write('echo.py', """\
623 import os, sys
624 sys.stdout.write(os.environ['ECHO'] + '\\n')
625 sys.exit(0)
626 """)
628 save_stderr = sys.stderr
630 python = '"' + sys.executable + '"'
632 try:
633 sys.stderr = io.StringIO()
634 cmd = '%s %s' % (python, test.workpath('stdout.py'))
635 output = env.backtick(cmd)
636 errout = sys.stderr.getvalue()
637 assert output == 'this came from stdout.py\n', output
638 assert errout == '', errout
640 sys.stderr = io.StringIO()
641 cmd = '%s %s' % (python, test.workpath('stderr.py'))
642 output = env.backtick(cmd)
643 errout = sys.stderr.getvalue()
644 assert output == '', output
645 assert errout == 'this came from stderr.py\n', errout
647 sys.stderr = io.StringIO()
648 cmd = '%s %s' % (python, test.workpath('fail.py'))
649 try:
650 env.backtick(cmd)
651 except OSError as e:
652 assert str(e) == f'{cmd!r} exited 1', str(e)
653 else:
654 self.fail("did not catch expected OSError")
656 sys.stderr = io.StringIO()
657 cmd = '%s %s' % (python, test.workpath('echo.py'))
658 env['ENV'] = os.environ.copy()
659 env['ENV']['ECHO'] = 'this came from ECHO'
660 output = env.backtick(cmd)
661 errout = sys.stderr.getvalue()
662 assert output == 'this came from ECHO\n', output
663 assert errout == '', errout
665 finally:
666 sys.stderr = save_stderr
668 def test_AddMethod(self) -> None:
669 """Test the AddMethod() method"""
670 env = SubstitutionEnvironment(FOO = 'foo')
672 def func(self):
673 return 'func-' + self['FOO']
675 assert not hasattr(env, 'func')
676 env.AddMethod(func)
677 r = env.func()
678 assert r == 'func-foo', r
680 assert not hasattr(env, 'bar')
681 env.AddMethod(func, 'bar')
682 r = env.bar()
683 assert r == 'func-foo', r
685 def func2(self, arg: str=''):
686 return 'func2-' + self['FOO'] + arg
688 env.AddMethod(func2)
689 r = env.func2()
690 assert r == 'func2-foo', r
691 r = env.func2('-xxx')
692 assert r == 'func2-foo-xxx', r
694 env.AddMethod(func2, 'func')
695 r = env.func()
696 assert r == 'func2-foo', r
697 r = env.func('-yyy')
698 assert r == 'func2-foo-yyy', r
700 # Test that clones of clones correctly re-bind added methods.
701 env1 = Environment(FOO = '1')
702 env1.AddMethod(func2)
703 env2 = env1.Clone(FOO = '2')
704 env3 = env2.Clone(FOO = '3')
705 env4 = env3.Clone(FOO = '4')
706 r = env1.func2()
707 assert r == 'func2-1', r
708 r = env2.func2()
709 assert r == 'func2-2', r
710 r = env3.func2()
711 assert r == 'func2-3', r
712 r = env4.func2()
713 assert r == 'func2-4', r
715 # Test that clones don't re-bind an attribute that the user set.
716 env1 = Environment(FOO = '1')
717 env1.AddMethod(func2)
718 def replace_func2() -> str:
719 return 'replace_func2'
720 env1.func2 = replace_func2
721 env2 = env1.Clone(FOO = '2')
722 r = env2.func2()
723 assert r == 'replace_func2', r
725 # Test clone rebinding if using global AddMethod.
726 env1 = Environment(FOO='1')
727 SCons.Util.AddMethod(env1, func2)
728 r = env1.func2()
729 assert r == 'func2-1', r
730 r = env1.func2('-xxx')
731 assert r == 'func2-1-xxx', r
732 env2 = env1.Clone(FOO='2')
733 r = env2.func2()
734 assert r == 'func2-2', r
737 def test_Override(self) -> None:
738 """Test overriding construction variables"""
739 env = SubstitutionEnvironment(ONE=1, TWO=2, THREE=3, FOUR=4)
740 assert env['ONE'] == 1, env['ONE']
741 assert env['TWO'] == 2, env['TWO']
742 assert env['THREE'] == 3, env['THREE']
743 assert env['FOUR'] == 4, env['FOUR']
745 env2 = env.Override({'TWO' : '10',
746 'THREE' :'x $THREE y',
747 'FOUR' : ['x', '$FOUR', 'y']})
748 assert env2['ONE'] == 1, env2['ONE']
749 assert env2['TWO'] == '10', env2['TWO']
750 assert env2['THREE'] == 'x 3 y', env2['THREE']
751 assert env2['FOUR'] == ['x', 4, 'y'], env2['FOUR']
753 assert env['ONE'] == 1, env['ONE']
754 assert env['TWO'] == 2, env['TWO']
755 assert env['THREE'] == 3, env['THREE']
756 assert env['FOUR'] == 4, env['FOUR']
758 env2.Replace(ONE = "won")
759 assert env2['ONE'] == "won", env2['ONE']
760 assert env['ONE'] == 1, env['ONE']
762 def test_ParseFlags(self) -> None:
763 """Test the ParseFlags() method
765 env = SubstitutionEnvironment()
767 empty = {
768 'ASFLAGS' : [],
769 'CFLAGS' : [],
770 'CCFLAGS' : [],
771 'CXXFLAGS' : [],
772 'CPPDEFINES' : [],
773 'CPPFLAGS' : [],
774 'CPPPATH' : [],
775 'FRAMEWORKPATH' : [],
776 'FRAMEWORKS' : [],
777 'LIBPATH' : [],
778 'LIBS' : [],
779 'LINKFLAGS' : [],
780 'RPATH' : [],
783 d = env.ParseFlags(None)
784 assert d == empty, d
786 d = env.ParseFlags('')
787 assert d == empty, d
789 d = env.ParseFlags([])
790 assert d == empty, d
792 s = (
793 "-I/usr/include/fum -I bar -X "
794 '-I"C:\\Program Files\\ASCEND\\include" '
795 "-L/usr/fax -L foo -lxxx -l yyy "
796 '-L"C:\\Program Files\\ASCEND" -lascend '
797 "-Wa,-as -Wl,-link "
798 "-Wl,-rpath=rpath1 "
799 "-Wl,-R,rpath2 "
800 "-Wl,-Rrpath3 "
801 "-Wp,-cpp "
802 "-std=c99 "
803 "-std=c++0x "
804 "-framework Carbon "
805 "-frameworkdir=fwd1 "
806 "-Ffwd2 "
807 "-F fwd3 "
808 "-dylib_file foo-dylib "
809 "-pthread "
810 "-fmerge-all-constants "
811 "-fopenmp "
812 "-mno-cygwin -mwindows "
813 "-arch i386 "
814 "-isysroot /tmp "
815 "-iquote /usr/include/foo1 "
816 "-isystem /usr/include/foo2 "
817 "-idirafter /usr/include/foo3 "
818 "-imacros /usr/include/foo4 "
819 "-include /usr/include/foo5 "
820 "--param l1-cache-size=32 --param l2-cache-size=6144 "
821 "+DD64 "
822 "-DFOO -DBAR=value -D BAZ "
823 "-fsanitize=memory "
824 "-fsanitize-address-use-after-return "
827 d = env.ParseFlags(s)
829 assert d['ASFLAGS'] == ['-as'], d['ASFLAGS']
830 assert d['CFLAGS'] == ['-std=c99']
831 assert d['CCFLAGS'] == ['-X', '-Wa,-as',
832 '-pthread', '-fmerge-all-constants',
833 '-fopenmp', '-mno-cygwin',
834 ('-arch', 'i386'), ('-isysroot', '/tmp'),
835 ('-iquote', '/usr/include/foo1'),
836 ('-isystem', '/usr/include/foo2'),
837 ('-idirafter', '/usr/include/foo3'),
838 ('-imacros', env.fs.File('/usr/include/foo4')),
839 ('-include', env.fs.File('/usr/include/foo5')),
840 ('--param', 'l1-cache-size=32'), ('--param', 'l2-cache-size=6144'),
841 '+DD64',
842 '-fsanitize=memory',
843 '-fsanitize-address-use-after-return'], repr(d['CCFLAGS'])
844 assert d['CXXFLAGS'] == ['-std=c++0x'], repr(d['CXXFLAGS'])
845 assert d['CPPDEFINES'] == ['FOO', ['BAR', 'value'], 'BAZ'], d['CPPDEFINES']
846 assert d['CPPFLAGS'] == ['-Wp,-cpp'], d['CPPFLAGS']
847 assert d['CPPPATH'] == ['/usr/include/fum',
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,
1532 # except if an entry begins with LIBLITERAL
1533 e = self.TestEnvironment(
1534 PRE='pre',
1535 SUF='suf',
1536 LIST=['xxx-a', 'b.yyy', 'zzxxx-c.yyy'],
1537 LIBPREFIXES=['xxx-'],
1538 LIBSUFFIXES=['.yyy'],
1539 LIBLITERAL='zz',
1541 x = e.subst('$( ${_stripixes(PRE, LIST, SUF, LIBPREFIXES, LIBSUFFIXES,__env__, LIBLITERAL)} $)')
1542 self.assertEqual(x, 'preasuf prebsuf prezzxxx-c.yyysuf')
1544 # Test that setting literal_prefix (in this case LIBLITERAL)
1545 # same as os.pathsep disables the literal protection
1546 e['LIBLITERAL'] = os.pathsep
1547 x = e.subst('$( ${_stripixes(PRE, LIST, SUF, LIBPREFIXES, LIBSUFFIXES,__env__, LIBLITERAL)} $)')
1548 self.assertEqual(x, 'preasuf prebsuf prezzxxx-csuf')
1550 # Test that setting not settingliteral_prefix doesn't fail
1551 x = e.subst('$( ${_stripixes(PRE, LIST, SUF, LIBPREFIXES, LIBSUFFIXES,__env__)} $)')
1552 self.assertEqual(x, 'preasuf prebsuf prezzxxx-csuf')
1556 def test_gvars(self) -> None:
1557 """Test the Environment gvars() method"""
1558 env = self.TestEnvironment(XXX = 'x', YYY = 'y', ZZZ = 'z')
1559 gvars = env.gvars()
1560 assert gvars['XXX'] == 'x', gvars['XXX']
1561 assert gvars['YYY'] == 'y', gvars['YYY']
1562 assert gvars['ZZZ'] == 'z', gvars['ZZZ']
1564 def test__update(self) -> None:
1565 """Test the _update() method"""
1566 env = self.TestEnvironment(X = 'x', Y = 'y', Z = 'z')
1567 assert env['X'] == 'x', env['X']
1568 assert env['Y'] == 'y', env['Y']
1569 assert env['Z'] == 'z', env['Z']
1570 env._update({'X' : 'xxx',
1571 'TARGET' : 't',
1572 'TARGETS' : 'ttt',
1573 'SOURCE' : 's',
1574 'SOURCES' : 'sss',
1575 'Z' : 'zzz'})
1576 assert env['X'] == 'xxx', env['X']
1577 assert env['Y'] == 'y', env['Y']
1578 assert env['Z'] == 'zzz', env['Z']
1579 assert env['TARGET'] == 't', env['TARGET']
1580 assert env['TARGETS'] == 'ttt', env['TARGETS']
1581 assert env['SOURCE'] == 's', env['SOURCE']
1582 assert env['SOURCES'] == 'sss', env['SOURCES']
1584 def test_Append(self) -> None:
1585 """Test appending to construction variables in an Environment
1588 b1 = Environment()['BUILDERS']
1589 b2 = Environment()['BUILDERS']
1590 assert b1 == b2, diff_dict(b1, b2)
1592 cases = [
1593 'a1', 'A1', 'a1A1',
1594 'a2', ['A2'], ['a2', 'A2'],
1595 'a3', UL(['A3']), UL(['a', '3', 'A3']),
1596 'a4', '', 'a4',
1597 'a5', [], ['a5'],
1598 'a6', UL([]), UL(['a', '6']),
1599 'a7', [''], ['a7', ''],
1600 'a8', UL(['']), UL(['a', '8', '']),
1602 ['e1'], 'E1', ['e1', 'E1'],
1603 ['e2'], ['E2'], ['e2', 'E2'],
1604 ['e3'], UL(['E3']), UL(['e3', 'E3']),
1605 ['e4'], '', ['e4'],
1606 ['e5'], [], ['e5'],
1607 ['e6'], UL([]), UL(['e6']),
1608 ['e7'], [''], ['e7', ''],
1609 ['e8'], UL(['']), UL(['e8', '']),
1611 UL(['i1']), 'I1', UL(['i1', 'I', '1']),
1612 UL(['i2']), ['I2'], UL(['i2', 'I2']),
1613 UL(['i3']), UL(['I3']), UL(['i3', 'I3']),
1614 UL(['i4']), '', UL(['i4']),
1615 UL(['i5']), [], UL(['i5']),
1616 UL(['i6']), UL([]), UL(['i6']),
1617 UL(['i7']), [''], UL(['i7', '']),
1618 UL(['i8']), UL(['']), UL(['i8', '']),
1620 {'d1':1}, 'D1', {'d1':1, 'D1':None},
1621 {'d2':1}, ['D2'], {'d2':1, 'D2':None},
1622 {'d3':1}, UL(['D3']), {'d3':1, 'D3':None},
1623 {'d4':1}, {'D4':1}, {'d4':1, 'D4':1},
1624 {'d5':1}, UD({'D5':1}), UD({'d5':1, 'D5':1}),
1626 UD({'u1':1}), 'U1', UD({'u1':1, 'U1':None}),
1627 UD({'u2':1}), ['U2'], UD({'u2':1, 'U2':None}),
1628 UD({'u3':1}), UL(['U3']), UD({'u3':1, 'U3':None}),
1629 UD({'u4':1}), {'U4':1}, UD({'u4':1, 'U4':1}),
1630 UD({'u5':1}), UD({'U5':1}), UD({'u5':1, 'U5':1}),
1632 '', 'M1', 'M1',
1633 '', ['M2'], ['M2'],
1634 '', UL(['M3']), UL(['M3']),
1635 '', '', '',
1636 '', [], [],
1637 '', UL([]), UL([]),
1638 '', [''], [''],
1639 '', UL(['']), UL(['']),
1641 [], 'N1', ['N1'],
1642 [], ['N2'], ['N2'],
1643 [], UL(['N3']), UL(['N3']),
1644 [], '', [],
1645 [], [], [],
1646 [], UL([]), UL([]),
1647 [], [''], [''],
1648 [], UL(['']), UL(['']),
1650 UL([]), 'O1', ['O', '1'],
1651 UL([]), ['O2'], ['O2'],
1652 UL([]), UL(['O3']), UL(['O3']),
1653 UL([]), '', UL([]),
1654 UL([]), [], UL([]),
1655 UL([]), UL([]), UL([]),
1656 UL([]), [''], UL(['']),
1657 UL([]), UL(['']), UL(['']),
1659 [''], 'P1', ['', 'P1'],
1660 [''], ['P2'], ['', 'P2'],
1661 [''], UL(['P3']), UL(['', 'P3']),
1662 [''], '', [''],
1663 [''], [], [''],
1664 [''], UL([]), UL(['']),
1665 [''], [''], ['', ''],
1666 [''], UL(['']), UL(['', '']),
1668 UL(['']), 'Q1', ['', 'Q', '1'],
1669 UL(['']), ['Q2'], ['', 'Q2'],
1670 UL(['']), UL(['Q3']), UL(['', 'Q3']),
1671 UL(['']), '', UL(['']),
1672 UL(['']), [], UL(['']),
1673 UL(['']), UL([]), UL(['']),
1674 UL(['']), [''], UL(['', '']),
1675 UL(['']), UL(['']), UL(['', '']),
1678 env = Environment()
1679 failed = 0
1680 while cases:
1681 input, append, expect = cases[:3]
1682 env['XXX'] = copy.copy(input)
1683 try:
1684 env.Append(XXX = append)
1685 except Exception as e:
1686 if failed == 0: print()
1687 print(" %s Append %s exception: %s" % \
1688 (repr(input), repr(append), e))
1689 failed = failed + 1
1690 else:
1691 result = env['XXX']
1692 if result != expect:
1693 if failed == 0: print()
1694 print(" %s Append %s => %s did not match %s" % \
1695 (repr(input), repr(append), repr(result), repr(expect)))
1696 failed = failed + 1
1697 del cases[:3]
1698 assert failed == 0, "%d Append() cases failed" % failed
1700 env['UL'] = UL(['foo'])
1701 env.Append(UL = 'bar')
1702 result = env['UL']
1703 assert isinstance(result, UL), repr(result)
1704 assert result == ['foo', 'b', 'a', 'r'], result
1706 env['CLVar'] = CLVar(['foo'])
1707 env.Append(CLVar = 'bar')
1708 result = env['CLVar']
1709 assert isinstance(result, CLVar), repr(result)
1710 assert result == ['foo', 'bar'], result
1712 class C:
1713 def __init__(self, name) -> None:
1714 self.name = name
1715 def __str__(self) -> str:
1716 return self.name
1717 def __eq__(self, other):
1718 raise Exception("should not compare")
1720 ccc = C('ccc')
1722 env2 = self.TestEnvironment(CCC1 = ['c1'], CCC2 = ccc)
1723 env2.Append(CCC1 = ccc, CCC2 = ['c2'])
1724 assert env2['CCC1'][0] == 'c1', env2['CCC1']
1725 assert env2['CCC1'][1] is ccc, env2['CCC1']
1726 assert env2['CCC2'][0] is ccc, env2['CCC2']
1727 assert env2['CCC2'][1] == 'c2', env2['CCC2']
1729 env3 = self.TestEnvironment(X = {'x1' : 7})
1730 env3.Append(X = {'x1' : 8, 'x2' : 9}, Y = {'y1' : 10})
1731 assert env3['X'] == {'x1': 8, 'x2': 9}, env3['X']
1732 assert env3['Y'] == {'y1': 10}, env3['Y']
1734 z1 = Builder()
1735 z2 = Builder()
1736 env4 = self.TestEnvironment(BUILDERS = {'z1' : z1})
1737 env4.Append(BUILDERS = {'z2' : z2})
1738 assert env4['BUILDERS'] == {'z1' : z1, 'z2' : z2}, env4['BUILDERS']
1739 assert hasattr(env4, 'z1')
1740 assert hasattr(env4, 'z2')
1742 def test_AppendENVPath(self) -> None:
1743 """Test appending to an ENV path."""
1744 env1 = self.TestEnvironment(
1745 ENV={'PATH': r'C:\dir\num\one;C:\dir\num\two'},
1746 MYENV={'MYPATH': r'C:\mydir\num\one;C:\mydir\num\two'},
1748 # have to include the pathsep here so that the test will work on UNIX too.
1749 env1.AppendENVPath('PATH', r'C:\dir\num\two', sep=';')
1750 env1.AppendENVPath('PATH', r'C:\dir\num\three', sep=';')
1751 env1.AppendENVPath('MYPATH', r'C:\mydir\num\three', 'MYENV', sep=';')
1752 assert (
1753 env1['ENV']['PATH'] == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three'
1754 ), env1['ENV']['PATH']
1756 env1.AppendENVPath('MYPATH', r'C:\mydir\num\three', 'MYENV', sep=';')
1757 env1.AppendENVPath(
1758 'MYPATH', r'C:\mydir\num\one', 'MYENV', sep=';', delete_existing=1
1760 # this should do nothing since delete_existing is 0
1761 assert (
1762 env1['MYENV']['MYPATH'] == r'C:\mydir\num\two;C:\mydir\num\three;C:\mydir\num\one'
1763 ), env1['MYENV']['MYPATH']
1765 test = TestCmd.TestCmd(workdir='')
1766 test.subdir('sub1', 'sub2')
1767 p = env1['ENV']['PATH']
1768 env1.AppendENVPath('PATH', '#sub1', sep=';')
1769 env1.AppendENVPath('PATH', env1.fs.Dir('sub2'), sep=';')
1770 assert env1['ENV']['PATH'] == p + ';sub1;sub2', env1['ENV']['PATH']
1772 def test_AppendUnique(self) -> None:
1773 """Test appending to unique values to construction variables
1775 This strips values that are already present when lists are
1776 involved."""
1777 env = self.TestEnvironment(AAA1 = 'a1',
1778 AAA2 = 'a2',
1779 AAA3 = 'a3',
1780 AAA4 = 'a4',
1781 AAA5 = 'a5',
1782 BBB1 = ['b1'],
1783 BBB2 = ['b2'],
1784 BBB3 = ['b3'],
1785 BBB4 = ['b4'],
1786 BBB5 = ['b5'],
1787 CCC1 = '',
1788 CCC2 = '',
1789 DDD1 = ['a', 'b', 'c'])
1790 env['LL1'] = [env.Literal('a literal'), env.Literal('b literal')]
1791 env['LL2'] = [env.Literal('c literal'), env.Literal('b literal')]
1792 env.AppendUnique(AAA1 = 'a1',
1793 AAA2 = ['a2'],
1794 AAA3 = ['a3', 'b', 'c', 'c', 'b', 'a3'], # ignore dups
1795 AAA4 = 'a4.new',
1796 AAA5 = ['a5.new'],
1797 BBB1 = 'b1',
1798 BBB2 = ['b2'],
1799 BBB3 = ['b3', 'c', 'd', 'c', 'b3'],
1800 BBB4 = 'b4.new',
1801 BBB5 = ['b5.new'],
1802 CCC1 = 'c1',
1803 CCC2 = ['c2'],
1804 DDD1 = 'b',
1805 LL1 = env.Literal('a literal'),
1806 LL2 = env.Literal('a literal'))
1808 assert env['AAA1'] == 'a1a1', env['AAA1']
1809 assert env['AAA2'] == ['a2'], env['AAA2']
1810 assert env['AAA3'] == ['a3', 'b', 'c'], env['AAA3']
1811 assert env['AAA4'] == 'a4a4.new', env['AAA4']
1812 assert env['AAA5'] == ['a5', 'a5.new'], env['AAA5']
1813 assert env['BBB1'] == ['b1'], env['BBB1']
1814 assert env['BBB2'] == ['b2'], env['BBB2']
1815 assert env['BBB3'] == ['b3', 'c', 'd'], env['BBB3']
1816 assert env['BBB4'] == ['b4', 'b4.new'], env['BBB4']
1817 assert env['BBB5'] == ['b5', 'b5.new'], env['BBB5']
1818 assert env['CCC1'] == 'c1', env['CCC1']
1819 assert env['CCC2'] == ['c2'], env['CCC2']
1820 assert env['DDD1'] == ['a', 'b', 'c'], env['DDD1']
1821 assert env['LL1'] == [env.Literal('a literal'), env.Literal('b literal')], env['LL1']
1822 assert env['LL2'] == [env.Literal('c literal'), env.Literal('b literal'), env.Literal('a literal')], [str(x) for x in env['LL2']]
1824 env.AppendUnique(DDD1 = 'b', delete_existing=1)
1825 assert env['DDD1'] == ['a', 'c', 'b'], env['DDD1'] # b moves to end
1826 env.AppendUnique(DDD1 = ['a','b'], delete_existing=1)
1827 assert env['DDD1'] == ['c', 'a', 'b'], env['DDD1'] # a & b move to end
1828 env.AppendUnique(DDD1 = ['e','f', 'e'], delete_existing=1)
1829 assert env['DDD1'] == ['c', 'a', 'b', 'f', 'e'], env['DDD1'] # add last
1831 env['CLVar'] = CLVar([])
1832 env.AppendUnique(CLVar = 'bar')
1833 result = env['CLVar']
1834 assert isinstance(result, CLVar), repr(result)
1835 assert result == ['bar'], result
1837 env['CLVar'] = CLVar(['abc'])
1838 env.AppendUnique(CLVar = 'bar')
1839 result = env['CLVar']
1840 assert isinstance(result, CLVar), repr(result)
1841 assert result == ['abc', 'bar'], result
1843 env['CLVar'] = CLVar(['bar'])
1844 env.AppendUnique(CLVar = 'bar')
1845 result = env['CLVar']
1846 assert isinstance(result, CLVar), repr(result)
1847 assert result == ['bar'], result
1849 def test_Clone(self) -> None:
1850 """Test construction environment cloning.
1852 The clone should compare equal if there are no overrides.
1853 Update the clone independently afterwards and check that
1854 the original remains intact (that is, no dangling
1855 references point to objects in the copied environment).
1856 Clone the original with some construction variable
1857 updates and check that the original remains intact
1858 and the copy has the updated values.
1860 with self.subTest():
1861 env1 = self.TestEnvironment(XXX='x', YYY='y')
1862 env2 = env1.Clone()
1863 env1copy = env1.Clone()
1864 self.assertEqual(env1copy, env1)
1865 self.assertEqual(env2, env1)
1866 env2.Replace(YYY = 'yyy')
1867 self.assertNotEqual(env1, env2)
1868 self.assertEqual(env1, env1copy)
1870 env3 = env1.Clone(XXX='x3', ZZZ='z3')
1871 self.assertNotEqual(env3, env1)
1872 self.assertEqual(env3.Dictionary('XXX'), 'x3')
1873 self.assertEqual(env1.Dictionary('XXX'), 'x')
1874 self.assertEqual(env3.Dictionary('YYY'), 'y')
1875 self.assertEqual(env3.Dictionary('ZZZ'), 'z3')
1876 self.assertRaises(KeyError, env1.Dictionary, 'ZZZ') # leak test
1877 self.assertEqual(env1, env1copy)
1879 # Ensure that lists and dictionaries are deep copied, but not instances
1880 with self.subTest():
1882 class TestA:
1883 pass
1885 env1 = self.TestEnvironment(
1886 XXX=TestA(),
1887 YYY=[1, 2, 3],
1888 ZZZ={1: 2, 3: 4}
1890 env2 = env1.Clone()
1891 env2.Dictionary('YYY').append(4)
1892 env2.Dictionary('ZZZ')[5] = 6
1893 self.assertIs(env1.Dictionary('XXX'), env2.Dictionary('XXX'))
1894 self.assertIn(4, env2.Dictionary('YYY'))
1895 self.assertNotIn(4, env1.Dictionary('YYY'))
1896 self.assertIn(5, env2.Dictionary('ZZZ'))
1897 self.assertNotIn(5, env1.Dictionary('ZZZ'))
1899 # We also need to look at the special cases in semi_deepcopy()
1900 # used when cloning - these should not leak to the original either
1901 with self.subTest():
1902 env1 = self.TestEnvironment(
1903 XXX=deque([1, 2, 3]),
1904 YYY=UL([1, 2, 3]),
1905 ZZZ=UD({1: 2, 3: 4}),
1907 env2 = env1.Clone()
1908 env2['XXX'].append(4)
1909 env2['YYY'].append(4)
1910 env2['ZZZ'][5] = 6
1911 self.assertIn(4, env2['XXX'])
1912 self.assertNotIn(4, env1['XXX'])
1913 self.assertIn(4, env2['YYY'])
1914 self.assertNotIn(4, env1['YYY'])
1915 self.assertIn(5, env2['ZZZ'])
1916 self.assertNotIn(5, env1['ZZZ'])
1918 # BUILDERS is special...
1919 with self.subTest():
1920 env1 = self.TestEnvironment(BUILDERS={'b1': Builder()})
1921 assert hasattr(env1, 'b1'), "env1.b1 was not set"
1922 assert env1.b1.object == env1, "b1.object doesn't point to env1"
1923 env2 = env1.Clone(BUILDERS = {'b2' : Builder()})
1924 assert env2 != env1
1925 assert hasattr(env1, 'b1'), "b1 was mistakenly cleared from env1"
1926 assert env1.b1.object == env1, "b1.object was changed"
1927 assert not hasattr(env2, 'b1'), "b1 was not cleared from env2"
1928 assert hasattr(env2, 'b2'), "env2.b2 was not set"
1929 assert env2.b2.object == env2, "b2.object doesn't point to env2"
1931 # Ensure that specifying new tools in a copied environment works.
1932 with self.subTest():
1934 def foo(env) -> None:
1935 env['FOO'] = 1
1937 def bar(env) -> None:
1938 env['BAR'] = 2
1940 def baz(env) -> None:
1941 env['BAZ'] = 3
1943 env1 = self.TestEnvironment(tools=[foo])
1944 env2 = env1.Clone()
1945 env3 = env1.Clone(tools=[bar, baz])
1947 assert env1.get('FOO') == 1
1948 assert env1.get('BAR') is None
1949 assert env1.get('BAZ') is None
1950 assert env2.get('FOO') == 1
1951 assert env2.get('BAR') is None
1952 assert env2.get('BAZ') is None
1953 assert env3.get('FOO') == 1
1954 assert env3.get('BAR') == 2
1955 assert env3.get('BAZ') == 3
1957 # Ensure that recursive variable substitution when copying
1958 # environments works properly.
1959 with self.subTest():
1960 env1 = self.TestEnvironment(CCFLAGS='-DFOO', XYZ='-DXYZ')
1961 env2 = env1.Clone(
1962 CCFLAGS='$CCFLAGS -DBAR', XYZ=['-DABC', 'x $XYZ y', '-DDEF']
1964 x = env2.get('CCFLAGS')
1965 assert x == '-DFOO -DBAR', x
1966 x = env2.get('XYZ')
1967 assert x == ['-DABC', 'x -DXYZ y', '-DDEF'], x
1969 # Ensure that special properties of a class don't get
1970 # lost on copying.
1971 with self.subTest():
1972 env1 = self.TestEnvironment(FLAGS=CLVar('flag1 flag2'))
1973 x = env1.get('FLAGS')
1974 assert x == ['flag1', 'flag2'], x
1975 env2 = env1.Clone()
1976 env2.Append(FLAGS='flag3 flag4')
1977 x = env2.get('FLAGS')
1978 assert x == ['flag1', 'flag2', 'flag3', 'flag4'], x
1979 x = env1.get('FLAGS')
1980 assert x == ['flag1', 'flag2'], x
1982 # Ensure that appending directly to a copied CLVar
1983 # doesn't modify the original.
1984 with self.subTest():
1985 env1 = self.TestEnvironment(FLAGS=CLVar('flag1 flag2'))
1986 x = env1.get('FLAGS')
1987 assert x == ['flag1', 'flag2'], x
1988 env2 = env1.Clone()
1989 env2['FLAGS'] += ['flag3', 'flag4']
1990 x = env2.get('FLAGS')
1991 assert x == ['flag1', 'flag2', 'flag3', 'flag4'], x
1992 x = env1.get('FLAGS')
1993 assert x == ['flag1', 'flag2'], x
1995 # Test that the environment stores the toolpath and
1996 # re-uses it for copies.
1997 with self.subTest():
1998 test = TestCmd.TestCmd(workdir='')
2000 test.write('xxx.py', """\
2001 def exists(env):
2002 return True
2003 def generate(env):
2004 env['XXX'] = 'one'
2005 """)
2007 test.write('yyy.py', """\
2008 def exists(env):
2009 return True
2010 def generate(env):
2011 env['YYY'] = 'two'
2012 """)
2014 env = self.TestEnvironment(tools=['xxx'], toolpath=[test.workpath('')])
2015 assert env['XXX'] == 'one', env['XXX']
2016 env = env.Clone(tools=['yyy'])
2017 assert env['YYY'] == 'two', env['YYY']
2019 # Test that
2020 with self.subTest():
2021 real_value = [4]
2023 def my_tool(env, rv=real_value) -> None:
2024 assert env['KEY_THAT_I_WANT'] == rv[0]
2025 env['KEY_THAT_I_WANT'] = rv[0] + 1
2027 env = self.TestEnvironment()
2029 real_value[0] = 5
2030 env = env.Clone(KEY_THAT_I_WANT=5, tools=[my_tool])
2031 assert env['KEY_THAT_I_WANT'] == real_value[0], env['KEY_THAT_I_WANT']
2033 real_value[0] = 6
2034 env = env.Clone(KEY_THAT_I_WANT=6, tools=[my_tool])
2035 assert env['KEY_THAT_I_WANT'] == real_value[0], env['KEY_THAT_I_WANT']
2037 # test for pull request #150
2038 with self.subTest():
2039 env = self.TestEnvironment()
2040 env._dict.pop('BUILDERS')
2041 assert ('BUILDERS' in env) is False
2042 env2 = env.Clone()
2044 def test_Detect(self) -> None:
2045 """Test Detect()ing tools"""
2046 test = TestCmd.TestCmd(workdir = '')
2047 test.subdir('sub1', 'sub2')
2048 sub1 = test.workpath('sub1')
2049 sub2 = test.workpath('sub2')
2051 if sys.platform == 'win32':
2052 test.write(['sub1', 'xxx'], "sub1/xxx\n")
2053 test.write(['sub2', 'xxx'], "sub2/xxx\n")
2055 env = self.TestEnvironment(ENV = { 'PATH' : [sub1, sub2] })
2057 x = env.Detect('xxx.exe')
2058 assert x is None, x
2060 test.write(['sub2', 'xxx.exe'], "sub2/xxx.exe\n")
2062 env = self.TestEnvironment(ENV = { 'PATH' : [sub1, sub2] })
2064 x = env.Detect('xxx.exe')
2065 assert x == 'xxx.exe', x
2067 test.write(['sub1', 'xxx.exe'], "sub1/xxx.exe\n")
2069 x = env.Detect('xxx.exe')
2070 assert x == 'xxx.exe', x
2072 else:
2073 test.write(['sub1', 'xxx.exe'], "sub1/xxx.exe\n")
2074 test.write(['sub2', 'xxx.exe'], "sub2/xxx.exe\n")
2076 env = self.TestEnvironment(ENV = { 'PATH' : [sub1, sub2] })
2078 x = env.Detect('xxx.exe')
2079 assert x is None, x
2081 sub2_xxx_exe = test.workpath('sub2', 'xxx.exe')
2082 os.chmod(sub2_xxx_exe, 0o755)
2084 env = self.TestEnvironment(ENV = { 'PATH' : [sub1, sub2] })
2086 x = env.Detect('xxx.exe')
2087 assert x == 'xxx.exe', x
2089 sub1_xxx_exe = test.workpath('sub1', 'xxx.exe')
2090 os.chmod(sub1_xxx_exe, 0o755)
2092 x = env.Detect('xxx.exe')
2093 assert x == 'xxx.exe', x
2095 env = self.TestEnvironment(ENV = { 'PATH' : [] })
2096 x = env.Detect('xxx.exe')
2097 assert x is None, x
2099 def test_Dictionary(self) -> None:
2100 """Test retrieval of known construction variables
2102 Fetch them from the Dictionary and check for well-known
2103 defaults that get inserted.
2105 env = self.TestEnvironment(XXX = 'x', YYY = 'y', ZZZ = 'z')
2106 assert env.Dictionary('XXX') == 'x'
2107 assert env.Dictionary('YYY') == 'y'
2108 assert env.Dictionary('XXX', 'ZZZ') == ['x', 'z']
2109 xxx, zzz = env.Dictionary('XXX', 'ZZZ')
2110 assert xxx == 'x'
2111 assert zzz == 'z'
2112 assert 'BUILDERS' in env.Dictionary()
2113 assert 'CC' in env.Dictionary()
2114 assert 'CCFLAGS' in env.Dictionary()
2115 assert 'ENV' in env.Dictionary()
2117 assert env['XXX'] == 'x'
2118 env['XXX'] = 'foo'
2119 assert env.Dictionary('XXX') == 'foo'
2120 del env['XXX']
2121 assert 'XXX' not in env.Dictionary()
2123 def test_FindIxes(self) -> None:
2124 """Test FindIxes()"""
2125 env = self.TestEnvironment(LIBPREFIX='lib',
2126 LIBSUFFIX='.a',
2127 SHLIBPREFIX='lib',
2128 SHLIBSUFFIX='.so',
2129 PREFIX='pre',
2130 SUFFIX='post')
2132 paths = [os.path.join('dir', 'libfoo.a'),
2133 os.path.join('dir', 'libfoo.so')]
2135 assert paths[0] == env.FindIxes(paths, 'LIBPREFIX', 'LIBSUFFIX')
2136 assert paths[1] == env.FindIxes(paths, 'SHLIBPREFIX', 'SHLIBSUFFIX')
2137 assert None is env.FindIxes(paths, 'PREFIX', 'POST')
2139 paths = ['libfoo.a', 'prefoopost']
2141 assert paths[0] == env.FindIxes(paths, 'LIBPREFIX', 'LIBSUFFIX')
2142 assert None is env.FindIxes(paths, 'SHLIBPREFIX', 'SHLIBSUFFIX')
2143 assert paths[1] == env.FindIxes(paths, 'PREFIX', 'SUFFIX')
2145 def test_ParseConfig(self) -> None:
2146 """Test the ParseConfig() method"""
2147 env = self.TestEnvironment(COMMAND='command',
2148 ASFLAGS='assembler',
2149 CCFLAGS=[''],
2150 CPPDEFINES=[],
2151 CPPFLAGS=[''],
2152 CPPPATH='string',
2153 FRAMEWORKPATH=[],
2154 FRAMEWORKS=[],
2155 LIBPATH=['list'],
2156 LIBS='',
2157 LINKFLAGS=[''],
2158 RPATH=[])
2160 orig_backtick = env.backtick
2161 class my_backtick:
2162 """mocked backtick routine so command is not actually issued.
2164 Just returns the string it was given.
2166 def __init__(self, save_command, output) -> None:
2167 self.save_command = save_command
2168 self.output = output
2169 def __call__(self, command):
2170 self.save_command.append(command)
2171 return self.output
2173 try:
2174 save_command = []
2175 env.backtick = my_backtick(save_command,
2176 "-I/usr/include/fum -I bar -X\n" + \
2177 "-L/usr/fax -L foo -lxxx -l yyy " + \
2178 "-Wa,-as -Wl,-link " + \
2179 "-Wl,-rpath=rpath1 " + \
2180 "-Wl,-R,rpath2 " + \
2181 "-Wl,-Rrpath3 " + \
2182 "-Wp,-cpp abc " + \
2183 "-framework Carbon " + \
2184 "-frameworkdir=fwd1 " + \
2185 "-Ffwd2 " + \
2186 "-F fwd3 " + \
2187 "-pthread " + \
2188 "-fmerge-all-constants " + \
2189 "-mno-cygwin -mwindows " + \
2190 "-arch i386 -isysroot /tmp " + \
2191 "-iquote /usr/include/foo1 " + \
2192 "-isystem /usr/include/foo2 " + \
2193 "-idirafter /usr/include/foo3 " + \
2194 "+DD64 " + \
2195 "-DFOO -DBAR=value")
2196 env.ParseConfig("fake $COMMAND")
2197 assert save_command == ['fake command'], save_command
2198 assert env['ASFLAGS'] == ['assembler', '-as'], env['ASFLAGS']
2199 assert env['CCFLAGS'] == ['', '-X', '-Wa,-as',
2200 '-pthread', '-fmerge-all-constants', '-mno-cygwin',
2201 ('-arch', 'i386'), ('-isysroot', '/tmp'),
2202 ('-iquote', '/usr/include/foo1'),
2203 ('-isystem', '/usr/include/foo2'),
2204 ('-idirafter', '/usr/include/foo3'),
2205 '+DD64'], env['CCFLAGS']
2206 self.assertEqual(list(env['CPPDEFINES']), ['FOO', ['BAR', 'value']])
2207 assert env['CPPFLAGS'] == ['', '-Wp,-cpp'], env['CPPFLAGS']
2208 assert env['CPPPATH'] == ['string', '/usr/include/fum', 'bar'], env['CPPPATH']
2209 assert env['FRAMEWORKPATH'] == ['fwd1', 'fwd2', 'fwd3'], env['FRAMEWORKPATH']
2210 assert env['FRAMEWORKS'] == ['Carbon'], env['FRAMEWORKS']
2211 assert env['LIBPATH'] == ['list', '/usr/fax', 'foo'], env['LIBPATH']
2212 assert env['LIBS'] == ['xxx', 'yyy', env.File('abc')], env['LIBS']
2213 assert env['LINKFLAGS'] == ['', '-Wl,-link', '-pthread',
2214 '-fmerge-all-constants',
2215 '-mno-cygwin', '-mwindows',
2216 ('-arch', 'i386'),
2217 ('-isysroot', '/tmp'),
2218 '+DD64'], env['LINKFLAGS']
2219 assert env['RPATH'] == ['rpath1', 'rpath2', 'rpath3'], env['RPATH']
2221 env.backtick = my_backtick([], "-Ibar")
2222 env.ParseConfig("fake2")
2223 assert env['CPPPATH'] == ['string', '/usr/include/fum', 'bar'], env['CPPPATH']
2224 env.ParseConfig("fake2", unique=0)
2225 assert env['CPPPATH'] == ['string', '/usr/include/fum', 'bar', 'bar'], env['CPPPATH']
2226 finally:
2227 env.backtick = orig_backtick
2229 # check that we can pass our own function,
2230 # and that it works for both values of unique
2232 def my_function(myenv, flags, unique: bool=True) -> None:
2233 import json
2235 args = json.loads(flags)
2236 if unique:
2237 myenv.AppendUnique(**args)
2238 else:
2239 myenv.Append(**args)
2241 json_str = '{"LIBS": ["yyy", "xxx", "yyy"]}'
2243 env = Environment(LIBS=['xxx'])
2244 env2 = env.Clone()
2245 env.backtick = my_backtick([], json_str)
2246 env2.backtick = my_backtick([], json_str)
2248 env.ParseConfig("foo", my_function)
2249 assert env['LIBS'] == ['xxx', 'yyy'], env['LIBS']
2251 env2.ParseConfig("foo2", my_function, unique=False)
2252 assert env2['LIBS'] == ['xxx', 'yyy', 'xxx', 'yyy'], env2['LIBS']
2255 def test_ParseDepends(self) -> None:
2256 """Test the ParseDepends() method"""
2257 test = TestCmd.TestCmd(workdir = '')
2259 test.write('single', """
2260 #file: dependency
2262 f0: \
2263 d1 \
2264 d2 \
2265 d3 \
2267 """)
2269 test.write('multiple', """
2270 f1: foo
2271 f2 f3: bar
2272 f4: abc def
2273 #file: dependency
2274 f5: \
2275 ghi \
2276 jkl \
2277 mno \
2278 """)
2280 env = self.TestEnvironment(SINGLE = test.workpath('single'))
2282 tlist = []
2283 dlist = []
2284 def my_depends(target, dependency, tlist=tlist, dlist=dlist) -> None:
2285 tlist.extend(target)
2286 dlist.extend(dependency)
2288 env.Depends = my_depends
2290 env.ParseDepends(test.workpath('does_not_exist'))
2292 exc_caught = None
2293 try:
2294 env.ParseDepends(test.workpath('does_not_exist'), must_exist=1)
2295 except IOError:
2296 exc_caught = 1
2297 assert exc_caught, "did not catch expected IOError"
2299 del tlist[:]
2300 del dlist[:]
2302 env.ParseDepends('$SINGLE', only_one=1)
2303 t = list(map(str, tlist))
2304 d = list(map(str, dlist))
2305 assert t == ['f0'], t
2306 assert d == ['d1', 'd2', 'd3'], d
2308 del tlist[:]
2309 del dlist[:]
2311 env.ParseDepends(test.workpath('multiple'))
2312 t = list(map(str, tlist))
2313 d = list(map(str, dlist))
2314 assert t == ['f1', 'f2', 'f3', 'f4', 'f5'], t
2315 assert d == ['foo', 'bar', 'abc', 'def', 'ghi', 'jkl', 'mno'], d
2317 exc_caught = None
2318 try:
2319 env.ParseDepends(test.workpath('multiple'), only_one=1)
2320 except SCons.Errors.UserError:
2321 exc_caught = 1
2322 assert exc_caught, "did not catch expected UserError"
2324 def test_Platform(self) -> None:
2325 """Test the Platform() method"""
2326 env = self.TestEnvironment(WIN32='win32', NONE='no-such-platform')
2328 exc_caught = None
2329 try:
2330 env.Platform('does_not_exist')
2331 except SCons.Errors.UserError:
2332 exc_caught = 1
2333 assert exc_caught, "did not catch expected UserError"
2335 exc_caught = None
2336 try:
2337 env.Platform('$NONE')
2338 except SCons.Errors.UserError:
2339 exc_caught = 1
2340 assert exc_caught, "did not catch expected UserError"
2342 env.Platform('posix')
2343 assert env['OBJSUFFIX'] == '.o', env['OBJSUFFIX']
2345 env.Platform('$WIN32')
2346 assert env['OBJSUFFIX'] == '.obj', env['OBJSUFFIX']
2348 def test_Prepend(self) -> None:
2349 """Test prepending to construction variables in an Environment
2351 cases = [
2352 'a1', 'A1', 'A1a1',
2353 'a2', ['A2'], ['A2', 'a2'],
2354 'a3', UL(['A3']), UL(['A3', 'a', '3']),
2355 'a4', '', 'a4',
2356 'a5', [], ['a5'],
2357 'a6', UL([]), UL(['a', '6']),
2358 'a7', [''], ['', 'a7'],
2359 'a8', UL(['']), UL(['', 'a', '8']),
2361 ['e1'], 'E1', ['E1', 'e1'],
2362 ['e2'], ['E2'], ['E2', 'e2'],
2363 ['e3'], UL(['E3']), UL(['E3', 'e3']),
2364 ['e4'], '', ['e4'],
2365 ['e5'], [], ['e5'],
2366 ['e6'], UL([]), UL(['e6']),
2367 ['e7'], [''], ['', 'e7'],
2368 ['e8'], UL(['']), UL(['', 'e8']),
2370 UL(['i1']), 'I1', UL(['I', '1', 'i1']),
2371 UL(['i2']), ['I2'], UL(['I2', 'i2']),
2372 UL(['i3']), UL(['I3']), UL(['I3', 'i3']),
2373 UL(['i4']), '', UL(['i4']),
2374 UL(['i5']), [], UL(['i5']),
2375 UL(['i6']), UL([]), UL(['i6']),
2376 UL(['i7']), [''], UL(['', 'i7']),
2377 UL(['i8']), UL(['']), UL(['', 'i8']),
2379 {'d1':1}, 'D1', {'d1':1, 'D1':None},
2380 {'d2':1}, ['D2'], {'d2':1, 'D2':None},
2381 {'d3':1}, UL(['D3']), {'d3':1, 'D3':None},
2382 {'d4':1}, {'D4':1}, {'d4':1, 'D4':1},
2383 {'d5':1}, UD({'D5':1}), UD({'d5':1, 'D5':1}),
2385 UD({'u1':1}), 'U1', UD({'u1':1, 'U1':None}),
2386 UD({'u2':1}), ['U2'], UD({'u2':1, 'U2':None}),
2387 UD({'u3':1}), UL(['U3']), UD({'u3':1, 'U3':None}),
2388 UD({'u4':1}), {'U4':1}, UD({'u4':1, 'U4':1}),
2389 UD({'u5':1}), UD({'U5':1}), UD({'u5':1, 'U5':1}),
2391 '', 'M1', 'M1',
2392 '', ['M2'], ['M2'],
2393 '', UL(['M3']), UL(['M3']),
2394 '', '', '',
2395 '', [], [],
2396 '', UL([]), UL([]),
2397 '', [''], [''],
2398 '', UL(['']), UL(['']),
2400 [], 'N1', ['N1'],
2401 [], ['N2'], ['N2'],
2402 [], UL(['N3']), UL(['N3']),
2403 [], '', [],
2404 [], [], [],
2405 [], UL([]), UL([]),
2406 [], [''], [''],
2407 [], UL(['']), UL(['']),
2409 UL([]), 'O1', UL(['O', '1']),
2410 UL([]), ['O2'], UL(['O2']),
2411 UL([]), UL(['O3']), UL(['O3']),
2412 UL([]), '', UL([]),
2413 UL([]), [], UL([]),
2414 UL([]), UL([]), UL([]),
2415 UL([]), [''], UL(['']),
2416 UL([]), UL(['']), UL(['']),
2418 [''], 'P1', ['P1', ''],
2419 [''], ['P2'], ['P2', ''],
2420 [''], UL(['P3']), UL(['P3', '']),
2421 [''], '', [''],
2422 [''], [], [''],
2423 [''], UL([]), UL(['']),
2424 [''], [''], ['', ''],
2425 [''], UL(['']), UL(['', '']),
2427 UL(['']), 'Q1', UL(['Q', '1', '']),
2428 UL(['']), ['Q2'], UL(['Q2', '']),
2429 UL(['']), UL(['Q3']), UL(['Q3', '']),
2430 UL(['']), '', UL(['']),
2431 UL(['']), [], UL(['']),
2432 UL(['']), UL([]), UL(['']),
2433 UL(['']), [''], UL(['', '']),
2434 UL(['']), UL(['']), UL(['', '']),
2437 env = Environment()
2438 failed = 0
2439 while cases:
2440 input, prepend, expect = cases[:3]
2441 env['XXX'] = copy.copy(input)
2442 try:
2443 env.Prepend(XXX = prepend)
2444 except Exception as e:
2445 if failed == 0: print()
2446 print(" %s Prepend %s exception: %s" % \
2447 (repr(input), repr(prepend), e))
2448 failed = failed + 1
2449 else:
2450 result = env['XXX']
2451 if result != expect:
2452 if failed == 0: print()
2453 print(" %s Prepend %s => %s did not match %s" % \
2454 (repr(input), repr(prepend), repr(result), repr(expect)))
2455 failed = failed + 1
2456 del cases[:3]
2457 assert failed == 0, "%d Prepend() cases failed" % failed
2459 env['UL'] = UL(['foo'])
2460 env.Prepend(UL = 'bar')
2461 result = env['UL']
2462 assert isinstance(result, UL), repr(result)
2463 assert result == ['b', 'a', 'r', 'foo'], result
2465 env['CLVar'] = CLVar(['foo'])
2466 env.Prepend(CLVar = 'bar')
2467 result = env['CLVar']
2468 assert isinstance(result, CLVar), repr(result)
2469 assert result == ['bar', 'foo'], result
2471 env3 = self.TestEnvironment(X = {'x1' : 7})
2472 env3.Prepend(X = {'x1' : 8, 'x2' : 9}, Y = {'y1' : 10})
2473 assert env3['X'] == {'x1': 8, 'x2' : 9}, env3['X']
2474 assert env3['Y'] == {'y1': 10}, env3['Y']
2476 z1 = Builder()
2477 z2 = Builder()
2478 env4 = self.TestEnvironment(BUILDERS = {'z1' : z1})
2479 env4.Prepend(BUILDERS = {'z2' : z2})
2480 assert env4['BUILDERS'] == {'z1' : z1, 'z2' : z2}, env4['BUILDERS']
2481 assert hasattr(env4, 'z1')
2482 assert hasattr(env4, 'z2')
2484 def test_PrependENVPath(self) -> None:
2485 """Test prepending to an ENV path."""
2486 env1 = self.TestEnvironment(
2487 ENV={'PATH': r'C:\dir\num\one;C:\dir\num\two'},
2488 MYENV={'MYPATH': r'C:\mydir\num\one;C:\mydir\num\two'},
2490 # have to include the pathsep here so that the test will work on UNIX too.
2491 env1.PrependENVPath('PATH', r'C:\dir\num\two', sep=';')
2492 env1.PrependENVPath('PATH', r'C:\dir\num\three', sep=';')
2493 assert (
2494 env1['ENV']['PATH'] == r'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one'
2495 ), env1['ENV']['PATH']
2497 env1.PrependENVPath('MYPATH', r'C:\mydir\num\three', 'MYENV', sep=';')
2498 env1.PrependENVPath('MYPATH', r'C:\mydir\num\one', 'MYENV', sep=';')
2499 # this should do nothing since delete_existing is 0
2500 env1.PrependENVPath(
2501 'MYPATH', r'C:\mydir\num\three', 'MYENV', sep=';', delete_existing=0
2503 assert (
2504 env1['MYENV']['MYPATH'] == r'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two'
2505 ), env1['MYENV']['MYPATH']
2507 test = TestCmd.TestCmd(workdir='')
2508 test.subdir('sub1', 'sub2')
2509 p = env1['ENV']['PATH']
2510 env1.PrependENVPath('PATH', '#sub1', sep=';')
2511 env1.PrependENVPath('PATH', env1.fs.Dir('sub2'), sep=';')
2512 assert env1['ENV']['PATH'] == 'sub2;sub1;' + p, env1['ENV']['PATH']
2514 def test_PrependUnique(self) -> None:
2515 """Test prepending unique values to construction variables
2517 This strips values that are already present when lists are
2518 involved."""
2519 env = self.TestEnvironment(AAA1 = 'a1',
2520 AAA2 = 'a2',
2521 AAA3 = 'a3',
2522 AAA4 = 'a4',
2523 AAA5 = 'a5',
2524 BBB1 = ['b1'],
2525 BBB2 = ['b2'],
2526 BBB3 = ['b3'],
2527 BBB4 = ['b4'],
2528 BBB5 = ['b5'],
2529 CCC1 = '',
2530 CCC2 = '',
2531 DDD1 = ['a', 'b', 'c'])
2532 env.PrependUnique(AAA1 = 'a1',
2533 AAA2 = ['a2'],
2534 AAA3 = ['a3', 'b', 'c', 'b', 'a3'], # ignore dups
2535 AAA4 = 'a4.new',
2536 AAA5 = ['a5.new'],
2537 BBB1 = 'b1',
2538 BBB2 = ['b2'],
2539 BBB3 = ['b3', 'b', 'c', 'b3'],
2540 BBB4 = 'b4.new',
2541 BBB5 = ['b5.new'],
2542 CCC1 = 'c1',
2543 CCC2 = ['c2'],
2544 DDD1 = 'b')
2545 assert env['AAA1'] == 'a1a1', env['AAA1']
2546 assert env['AAA2'] == ['a2'], env['AAA2']
2547 assert env['AAA3'] == ['c', 'b', 'a3'], env['AAA3']
2548 assert env['AAA4'] == 'a4.newa4', env['AAA4']
2549 assert env['AAA5'] == ['a5.new', 'a5'], env['AAA5']
2550 assert env['BBB1'] == ['b1'], env['BBB1']
2551 assert env['BBB2'] == ['b2'], env['BBB2']
2552 assert env['BBB3'] == ['b', 'c', 'b3'], env['BBB3']
2553 assert env['BBB4'] == ['b4.new', 'b4'], env['BBB4']
2554 assert env['BBB5'] == ['b5.new', 'b5'], env['BBB5']
2555 assert env['CCC1'] == 'c1', env['CCC1']
2556 assert env['CCC2'] == ['c2'], env['CCC2']
2557 assert env['DDD1'] == ['a', 'b', 'c'], env['DDD1']
2559 env.PrependUnique(DDD1 = 'b', delete_existing=1)
2560 assert env['DDD1'] == ['b', 'a', 'c'], env['DDD1'] # b moves to front
2561 env.PrependUnique(DDD1 = ['a','c'], delete_existing=1)
2562 assert env['DDD1'] == ['a', 'c', 'b'], env['DDD1'] # a & c move to front
2563 env.PrependUnique(DDD1 = ['d','e','d'], delete_existing=1)
2564 assert env['DDD1'] == ['d', 'e', 'a', 'c', 'b'], env['DDD1']
2567 env['CLVar'] = CLVar([])
2568 env.PrependUnique(CLVar = 'bar')
2569 result = env['CLVar']
2570 assert isinstance(result, CLVar), repr(result)
2571 assert result == ['bar'], result
2573 env['CLVar'] = CLVar(['abc'])
2574 env.PrependUnique(CLVar = 'bar')
2575 result = env['CLVar']
2576 assert isinstance(result, CLVar), repr(result)
2577 assert result == ['bar', 'abc'], result
2579 env['CLVar'] = CLVar(['bar'])
2580 env.PrependUnique(CLVar = 'bar')
2581 result = env['CLVar']
2582 assert isinstance(result, CLVar), repr(result)
2583 assert result == ['bar'], result
2585 def test_Replace(self) -> None:
2586 """Test replacing construction variables in an Environment
2588 After creation of the Environment, of course.
2590 env1 = self.TestEnvironment(AAA = 'a', BBB = 'b')
2591 env1.Replace(BBB = 'bbb', CCC = 'ccc')
2593 env2 = self.TestEnvironment(AAA = 'a', BBB = 'bbb', CCC = 'ccc')
2594 assert env1 == env2, diff_env(env1, env2)
2596 b1 = Builder()
2597 b2 = Builder()
2598 env3 = self.TestEnvironment(BUILDERS = {'b1' : b1})
2599 assert hasattr(env3, 'b1'), "b1 was not set"
2600 env3.Replace(BUILDERS = {'b2' : b2})
2601 assert not hasattr(env3, 'b1'), "b1 was not cleared"
2602 assert hasattr(env3, 'b2'), "b2 was not set"
2604 def test_ReplaceIxes(self) -> None:
2605 """Test ReplaceIxes()"""
2606 env = self.TestEnvironment(LIBPREFIX='lib',
2607 LIBSUFFIX='.a',
2608 SHLIBPREFIX='lib',
2609 SHLIBSUFFIX='.so',
2610 PREFIX='pre',
2611 SUFFIX='post')
2613 assert 'libfoo.a' == env.ReplaceIxes('libfoo.so',
2614 'SHLIBPREFIX', 'SHLIBSUFFIX',
2615 'LIBPREFIX', 'LIBSUFFIX')
2617 assert os.path.join('dir', 'libfoo.a') == env.ReplaceIxes(os.path.join('dir', 'libfoo.so'),
2618 'SHLIBPREFIX', 'SHLIBSUFFIX',
2619 'LIBPREFIX', 'LIBSUFFIX')
2621 assert 'libfoo.a' == env.ReplaceIxes('prefoopost',
2622 'PREFIX', 'SUFFIX',
2623 'LIBPREFIX', 'LIBSUFFIX')
2625 def test_SetDefault(self) -> None:
2626 """Test the SetDefault method"""
2627 env = self.TestEnvironment(tools = [])
2628 env.SetDefault(V1 = 1)
2629 env.SetDefault(V1 = 2)
2630 assert env['V1'] == 1
2631 env['V2'] = 2
2632 env.SetDefault(V2 = 1)
2633 assert env['V2'] == 2
2635 def test_Tool(self) -> None:
2636 """Test the Tool() method"""
2637 env = self.TestEnvironment(LINK='link', NONE='no-such-tool')
2639 exc_caught = None
2640 try:
2641 tool = env.Tool('does_not_exist')
2642 except SCons.Errors.UserError:
2643 exc_caught = 1
2644 else:
2645 assert isinstance(tool, SCons.Tool.Tool)
2646 assert exc_caught, "did not catch expected UserError"
2648 exc_caught = None
2649 try:
2650 env.Tool('$NONE')
2651 except SCons.Errors.UserError:
2652 exc_caught = 1
2653 assert exc_caught, "did not catch expected UserError"
2655 # Use a non-existent toolpath directory just to make sure we
2656 # can call Tool() with the keyword argument.
2657 env.Tool('cc', toolpath=['/no/such/directory'])
2658 assert env['CC'] == 'cc', env['CC']
2660 env.Tool('$LINK')
2661 assert env['LINK'] == '$SMARTLINK', env['LINK']
2663 # Test that the environment stores the toolpath and
2664 # re-uses it for later calls.
2665 test = TestCmd.TestCmd(workdir = '')
2667 test.write('xxx.py', """\
2668 def exists(env):
2669 return True
2670 def generate(env):
2671 env['XXX'] = 'one'
2672 """)
2674 test.write('yyy.py', """\
2675 def exists(env):
2676 return True
2677 def generate(env):
2678 env['YYY'] = 'two'
2679 """)
2681 env = self.TestEnvironment(tools=['xxx'], toolpath=[test.workpath('')])
2682 assert env['XXX'] == 'one', env['XXX']
2683 env.Tool('yyy')
2684 assert env['YYY'] == 'two', env['YYY']
2686 def test_WhereIs(self) -> None:
2687 """Test the WhereIs() method"""
2688 test = TestCmd.TestCmd(workdir = '')
2690 sub1_xxx_exe = test.workpath('sub1', 'xxx.exe')
2691 sub2_xxx_exe = test.workpath('sub2', 'xxx.exe')
2692 sub3_xxx_exe = test.workpath('sub3', 'xxx.exe')
2693 sub4_xxx_exe = test.workpath('sub4', 'xxx.exe')
2695 test.subdir('subdir', 'sub1', 'sub2', 'sub3', 'sub4')
2697 if sys.platform != 'win32':
2698 test.write(sub1_xxx_exe, "\n")
2700 os.mkdir(sub2_xxx_exe)
2702 test.write(sub3_xxx_exe, "\n")
2703 os.chmod(sub3_xxx_exe, 0o777)
2705 test.write(sub4_xxx_exe, "\n")
2706 os.chmod(sub4_xxx_exe, 0o777)
2708 env_path = os.environ['PATH']
2710 pathdirs_1234 = [ test.workpath('sub1'),
2711 test.workpath('sub2'),
2712 test.workpath('sub3'),
2713 test.workpath('sub4'),
2714 ] + env_path.split(os.pathsep)
2716 pathdirs_1243 = [ test.workpath('sub1'),
2717 test.workpath('sub2'),
2718 test.workpath('sub4'),
2719 test.workpath('sub3'),
2720 ] + env_path.split(os.pathsep)
2722 path = os.pathsep.join(pathdirs_1234)
2723 env = self.TestEnvironment(ENV = {'PATH' : path})
2724 wi = env.WhereIs('')
2725 assert wi is None
2726 wi = env.WhereIs('xxx.exe')
2727 assert wi == test.workpath(sub3_xxx_exe), wi
2728 wi = env.WhereIs('xxx.exe', pathdirs_1243)
2729 assert wi == test.workpath(sub4_xxx_exe), wi
2730 wi = env.WhereIs('xxx.exe', os.pathsep.join(pathdirs_1243))
2731 assert wi == test.workpath(sub4_xxx_exe), wi
2733 wi = env.WhereIs('xxx.exe', reject = sub3_xxx_exe)
2734 assert wi == test.workpath(sub4_xxx_exe), wi
2735 wi = env.WhereIs('xxx.exe', pathdirs_1243, reject = sub3_xxx_exe)
2736 assert wi == test.workpath(sub4_xxx_exe), wi
2738 path = os.pathsep.join(pathdirs_1243)
2739 env = self.TestEnvironment(ENV = {'PATH' : path})
2740 wi = env.WhereIs('xxx.exe')
2741 assert wi == test.workpath(sub4_xxx_exe), wi
2742 wi = env.WhereIs('xxx.exe', pathdirs_1234)
2743 assert wi == test.workpath(sub3_xxx_exe), wi
2744 wi = env.WhereIs('xxx.exe', os.pathsep.join(pathdirs_1234))
2745 assert wi == test.workpath(sub3_xxx_exe), wi
2747 if sys.platform == 'win32':
2748 wi = env.WhereIs('xxx', pathext = '')
2749 assert wi is None, wi
2751 wi = env.WhereIs('xxx', pathext = '.exe')
2752 assert wi == test.workpath(sub4_xxx_exe), wi
2754 wi = env.WhereIs('xxx', path = pathdirs_1234, pathext = '.BAT;.EXE')
2755 assert wi.lower() == test.workpath(sub3_xxx_exe).lower(), wi
2757 # Test that we return a normalized path even when
2758 # the path contains forward slashes.
2759 forward_slash = test.workpath('') + '/sub3'
2760 wi = env.WhereIs('xxx', path = forward_slash, pathext = '.EXE')
2761 assert wi.lower() == test.workpath(sub3_xxx_exe).lower(), wi
2765 def test_Action(self) -> None:
2766 """Test the Action() method"""
2767 import SCons.Action
2769 env = self.TestEnvironment(FOO = 'xyzzy')
2771 a = env.Action('foo')
2772 assert a, a
2773 assert a.__class__ is SCons.Action.CommandAction, a.__class__
2775 a = env.Action('$FOO')
2776 assert a, a
2777 assert a.__class__ is SCons.Action.CommandAction, a.__class__
2779 a = env.Action('$$FOO')
2780 assert a, a
2781 assert a.__class__ is SCons.Action.LazyAction, a.__class__
2783 a = env.Action(['$FOO', 'foo'])
2784 assert a, a
2785 assert a.__class__ is SCons.Action.ListAction, a.__class__
2787 def func(arg) -> None:
2788 pass
2789 a = env.Action(func)
2790 assert a, a
2791 assert a.__class__ is SCons.Action.FunctionAction, a.__class__
2793 def test_AddPostAction(self) -> None:
2794 """Test the AddPostAction() method"""
2795 env = self.TestEnvironment(FOO='fff', BAR='bbb')
2797 n = env.AddPostAction('$FOO', lambda x: x)
2798 assert str(n[0]) == 'fff', n[0]
2800 n = env.AddPostAction(['ggg', '$BAR'], lambda x: x)
2801 assert str(n[0]) == 'ggg', n[0]
2802 assert str(n[1]) == 'bbb', n[1]
2804 def test_AddPreAction(self) -> None:
2805 """Test the AddPreAction() method"""
2806 env = self.TestEnvironment(FOO='fff', BAR='bbb')
2808 n = env.AddPreAction('$FOO', lambda x: x)
2809 assert str(n[0]) == 'fff', n[0]
2811 n = env.AddPreAction(['ggg', '$BAR'], lambda x: x)
2812 assert str(n[0]) == 'ggg', n[0]
2813 assert str(n[1]) == 'bbb', n[1]
2815 def test_Alias(self) -> None:
2816 """Test the Alias() method"""
2817 env = self.TestEnvironment(FOO='kkk', BAR='lll', EA='export_alias')
2819 tgt = env.Alias('new_alias')[0]
2820 assert str(tgt) == 'new_alias', tgt
2821 assert tgt.sources == [], tgt.sources
2822 assert not hasattr(tgt, 'builder'), tgt.builder
2824 tgt = env.Alias('None_alias', None)[0]
2825 assert str(tgt) == 'None_alias', tgt
2826 assert tgt.sources == [], tgt.sources
2828 tgt = env.Alias('empty_list', [])[0]
2829 assert str(tgt) == 'empty_list', tgt
2830 assert tgt.sources == [], tgt.sources
2832 tgt = env.Alias('export_alias', [ 'asrc1', '$FOO' ])[0]
2833 assert str(tgt) == 'export_alias', tgt
2834 assert len(tgt.sources) == 2, list(map(str, tgt.sources))
2835 assert str(tgt.sources[0]) == 'asrc1', list(map(str, tgt.sources))
2836 assert str(tgt.sources[1]) == 'kkk', list(map(str, tgt.sources))
2838 n = env.Alias(tgt, source = ['$BAR', 'asrc4'])[0]
2839 assert n is tgt, n
2840 assert len(tgt.sources) == 4, list(map(str, tgt.sources))
2841 assert str(tgt.sources[2]) == 'lll', list(map(str, tgt.sources))
2842 assert str(tgt.sources[3]) == 'asrc4', list(map(str, tgt.sources))
2844 n = env.Alias('$EA', 'asrc5')[0]
2845 assert n is tgt, n
2846 assert len(tgt.sources) == 5, list(map(str, tgt.sources))
2847 assert str(tgt.sources[4]) == 'asrc5', list(map(str, tgt.sources))
2849 t1, t2 = env.Alias(['t1', 't2'], ['asrc6', 'asrc7'])
2850 assert str(t1) == 't1', t1
2851 assert str(t2) == 't2', t2
2852 assert len(t1.sources) == 2, list(map(str, t1.sources))
2853 assert str(t1.sources[0]) == 'asrc6', list(map(str, t1.sources))
2854 assert str(t1.sources[1]) == 'asrc7', list(map(str, t1.sources))
2855 assert len(t2.sources) == 2, list(map(str, t2.sources))
2856 assert str(t2.sources[0]) == 'asrc6', list(map(str, t2.sources))
2857 assert str(t2.sources[1]) == 'asrc7', list(map(str, t2.sources))
2859 tgt = env.Alias('add', 's1')
2860 tgt = env.Alias('add', 's2')[0]
2861 s = list(map(str, tgt.sources))
2862 assert s == ['s1', 's2'], s
2863 tgt = env.Alias(tgt, 's3')[0]
2864 s = list(map(str, tgt.sources))
2865 assert s == ['s1', 's2', 's3'], s
2867 tgt = env.Alias('act', None, "action1")[0]
2868 s = str(tgt.builder.action)
2869 assert s == "action1", s
2870 tgt = env.Alias('act', None, "action2")[0]
2871 s = str(tgt.builder.action)
2872 assert s == "action1\naction2", s
2873 tgt = env.Alias(tgt, None, "action3")[0]
2874 s = str(tgt.builder.action)
2875 assert s == "action1\naction2\naction3", s
2877 def test_AlwaysBuild(self) -> None:
2878 """Test the AlwaysBuild() method"""
2879 env = self.TestEnvironment(FOO='fff', BAR='bbb')
2880 t = env.AlwaysBuild('a', 'b$FOO', ['c', 'd'], '$BAR',
2881 env.fs.Dir('dir'), env.fs.File('file'))
2882 assert t[0].__class__.__name__ == 'Entry'
2883 assert t[0].get_internal_path() == 'a'
2884 assert t[0].always_build
2885 assert t[1].__class__.__name__ == 'Entry'
2886 assert t[1].get_internal_path() == 'bfff'
2887 assert t[1].always_build
2888 assert t[2].__class__.__name__ == 'Entry'
2889 assert t[2].get_internal_path() == 'c'
2890 assert t[2].always_build
2891 assert t[3].__class__.__name__ == 'Entry'
2892 assert t[3].get_internal_path() == 'd'
2893 assert t[3].always_build
2894 assert t[4].__class__.__name__ == 'Entry'
2895 assert t[4].get_internal_path() == 'bbb'
2896 assert t[4].always_build
2897 assert t[5].__class__.__name__ == 'Dir'
2898 assert t[5].get_internal_path() == 'dir'
2899 assert t[5].always_build
2900 assert t[6].__class__.__name__ == 'File'
2901 assert t[6].get_internal_path() == 'file'
2902 assert t[6].always_build
2904 def test_VariantDir(self) -> None:
2905 """Test the VariantDir() method"""
2906 class MyFS:
2907 def Dir(self, name):
2908 return name
2909 def VariantDir(self, variant_dir, src_dir, duplicate) -> None:
2910 self.variant_dir = variant_dir
2911 self.src_dir = src_dir
2912 self.duplicate = duplicate
2914 env = self.TestEnvironment(FOO = 'fff', BAR = 'bbb')
2915 env.fs = MyFS()
2917 env.VariantDir('build', 'src')
2918 assert env.fs.variant_dir == 'build', env.fs.variant_dir
2919 assert env.fs.src_dir == 'src', env.fs.src_dir
2920 assert env.fs.duplicate == 1, env.fs.duplicate
2922 env.VariantDir('build${FOO}', '${BAR}src', 0)
2923 assert env.fs.variant_dir == 'buildfff', env.fs.variant_dir
2924 assert env.fs.src_dir == 'bbbsrc', env.fs.src_dir
2925 assert env.fs.duplicate == 0, env.fs.duplicate
2927 def test_Builder(self) -> None:
2928 """Test the Builder() method"""
2929 env = self.TestEnvironment(FOO = 'xyzzy')
2931 b = env.Builder(action = 'foo')
2932 assert b is not None, b
2934 b = env.Builder(action = '$FOO')
2935 assert b is not None, b
2937 b = env.Builder(action = ['$FOO', 'foo'])
2938 assert b is not None, b
2940 def func(arg) -> None:
2941 pass
2942 b = env.Builder(action = func)
2943 assert b is not None, b
2944 b = env.Builder(generator = func)
2945 assert b is not None, b
2947 def test_CacheDir(self) -> None:
2948 """Test the CacheDir() method"""
2950 test = TestCmd.TestCmd(workdir = '')
2952 test_cachedir = os.path.join(test.workpath(),'CacheDir')
2953 test_cachedir_config = os.path.join(test_cachedir, 'config')
2954 test_foo = os.path.join(test.workpath(), 'foo-cachedir')
2955 test_foo_config = os.path.join(test_foo,'config')
2956 test_foo1 = os.path.join(test.workpath(), 'foo1-cachedir')
2957 test_foo1_config = os.path.join(test_foo1, 'config')
2959 env = self.TestEnvironment(CD = test_cachedir)
2961 env.CacheDir(test_foo)
2962 assert env._CacheDir_path == test_foo, env._CacheDir_path
2963 assert os.path.isfile(test_foo_config), "No file %s"%test_foo_config
2965 env.CacheDir('$CD')
2966 assert env._CacheDir_path == test_cachedir, env._CacheDir_path
2967 assert os.path.isfile(test_cachedir_config), "No file %s"%test_cachedir_config
2969 # Now verify that -n/-no_exec wil prevent the CacheDir/config from being created
2970 import SCons.Action
2971 SCons.Action.execute_actions = False
2972 env.CacheDir(test_foo1)
2973 assert env._CacheDir_path == test_foo1, env._CacheDir_path
2974 assert not os.path.isfile(test_foo1_config), "No file %s"%test_foo1_config
2977 def test_Clean(self) -> None:
2978 """Test the Clean() method"""
2979 env = self.TestEnvironment(FOO = 'fff', BAR = 'bbb')
2981 CT = SCons.Environment.CleanTargets
2983 foo = env.arg2nodes('foo')[0]
2984 fff = env.arg2nodes('fff')[0]
2986 t = env.Clean('foo', 'aaa')
2987 l = list(map(str, CT[foo]))
2988 assert l == ['aaa'], l
2990 t = env.Clean(foo, ['$BAR', 'ccc'])
2991 l = list(map(str, CT[foo]))
2992 assert l == ['aaa', 'bbb', 'ccc'], l
2994 eee = env.arg2nodes('eee')[0]
2996 t = env.Clean('$FOO', 'ddd')
2997 l = list(map(str, CT[fff]))
2998 assert l == ['ddd'], l
2999 t = env.Clean(fff, [eee, 'fff'])
3000 l = list(map(str, CT[fff]))
3001 assert l == ['ddd', 'eee', 'fff'], l
3003 def test_Command(self) -> None:
3004 """Test the Command() method."""
3005 env = Environment()
3006 t = env.Command(target='foo.out', source=['foo1.in', 'foo2.in'],
3007 action='buildfoo $target $source')[0]
3008 assert t.builder is not None
3009 assert t.builder.action.__class__.__name__ == 'CommandAction'
3010 assert t.builder.action.cmd_list == 'buildfoo $target $source'
3011 assert 'foo1.in' in [x.get_internal_path() for x in t.sources]
3012 assert 'foo2.in' in [x.get_internal_path() for x in t.sources]
3014 sub = env.fs.Dir('sub')
3015 t = env.Command(target='bar.out', source='sub',
3016 action='buildbar $target $source')[0]
3017 assert 'sub' in [x.get_internal_path() for x in t.sources]
3019 def testFunc(env, target, source) -> int:
3020 assert str(target[0]) == 'foo.out'
3021 srcs = list(map(str, source))
3022 assert 'foo1.in' in srcs and 'foo2.in' in srcs, srcs
3023 return 0
3025 # avoid spurious output from action
3026 act = env.Action(testFunc, cmdstr=None)
3027 t = env.Command(target='foo.out', source=['foo1.in','foo2.in'],
3028 action=act)[0]
3029 assert t.builder is not None
3030 assert t.builder.action.__class__.__name__ == 'FunctionAction'
3031 t.build()
3032 assert 'foo1.in' in [x.get_internal_path() for x in t.sources]
3033 assert 'foo2.in' in [x.get_internal_path() for x in t.sources]
3035 x = []
3036 def test2(baz, x=x) -> None:
3037 x.append(baz)
3038 env = self.TestEnvironment(TEST2 = test2)
3039 t = env.Command(target='baz.out', source='baz.in',
3040 action='${TEST2(XYZ)}',
3041 XYZ='magic word')[0]
3042 assert t.builder is not None
3043 t.build()
3044 assert x[0] == 'magic word', x
3046 t = env.Command(target='${X}.out', source='${X}.in',
3047 action = 'foo',
3048 X = 'xxx')[0]
3049 assert str(t) == 'xxx.out', str(t)
3050 assert 'xxx.in' in [x.get_internal_path() for x in t.sources]
3052 env = self.TestEnvironment(source_scanner = 'should_not_find_this')
3053 t = env.Command(target='file.out', source='file.in',
3054 action = 'foo',
3055 source_scanner = 'fake')[0]
3056 assert t.builder.source_scanner == 'fake', t.builder.source_scanner
3058 def test_Configure(self) -> None:
3059 """Test the Configure() method"""
3060 # Configure() will write to a local temporary file.
3061 test = TestCmd.TestCmd(workdir = '')
3062 save = os.getcwd()
3064 try:
3065 os.chdir(test.workpath())
3067 env = self.TestEnvironment(FOO = 'xyzzy')
3069 def func(arg) -> None:
3070 pass
3072 c = env.Configure()
3073 assert c is not None, c
3074 c.Finish()
3076 c = env.Configure(custom_tests = {'foo' : func, '$FOO' : func})
3077 assert c is not None, c
3078 assert hasattr(c, 'foo')
3079 assert hasattr(c, 'xyzzy')
3080 c.Finish()
3081 finally:
3082 os.chdir(save)
3084 def test_Depends(self) -> None:
3085 """Test the explicit Depends method."""
3086 env = self.TestEnvironment(FOO = 'xxx', BAR='yyy')
3087 env.Dir('dir1')
3088 env.Dir('dir2')
3089 env.File('xxx.py')
3090 env.File('yyy.py')
3091 t = env.Depends(target='EnvironmentTest.py',
3092 dependency='Environment.py')[0]
3093 assert t.__class__.__name__ == 'Entry', t.__class__.__name__
3094 assert t.get_internal_path() == 'EnvironmentTest.py'
3095 assert len(t.depends) == 1
3096 d = t.depends[0]
3097 assert d.__class__.__name__ == 'Entry', d.__class__.__name__
3098 assert d.get_internal_path() == 'Environment.py'
3100 t = env.Depends(target='${FOO}.py', dependency='${BAR}.py')[0]
3101 assert t.__class__.__name__ == 'File', t.__class__.__name__
3102 assert t.get_internal_path() == 'xxx.py'
3103 assert len(t.depends) == 1
3104 d = t.depends[0]
3105 assert d.__class__.__name__ == 'File', d.__class__.__name__
3106 assert d.get_internal_path() == 'yyy.py'
3108 t = env.Depends(target='dir1', dependency='dir2')[0]
3109 assert t.__class__.__name__ == 'Dir', t.__class__.__name__
3110 assert t.get_internal_path() == 'dir1'
3111 assert len(t.depends) == 1
3112 d = t.depends[0]
3113 assert d.__class__.__name__ == 'Dir', d.__class__.__name__
3114 assert d.get_internal_path() == 'dir2'
3116 def test_Dir(self) -> None:
3117 """Test the Dir() method"""
3118 class MyFS:
3119 def Dir(self, name) -> str:
3120 return 'Dir(%s)' % name
3122 env = self.TestEnvironment(FOO = 'foodir', BAR = 'bardir')
3123 env.fs = MyFS()
3125 d = env.Dir('d')
3126 assert d == 'Dir(d)', d
3128 d = env.Dir('$FOO')
3129 assert d == 'Dir(foodir)', d
3131 d = env.Dir('${BAR}_$BAR')
3132 assert d == 'Dir(bardir_bardir)', d
3134 d = env.Dir(['dir1'])
3135 assert d == ['Dir(dir1)'], d
3137 d = env.Dir(['dir1', 'dir2'])
3138 assert d == ['Dir(dir1)', 'Dir(dir2)'], d
3140 def test_NoClean(self) -> None:
3141 """Test the NoClean() method"""
3142 env = self.TestEnvironment(FOO='ggg', BAR='hhh')
3143 env.Dir('p_hhhb')
3144 env.File('p_d')
3145 t = env.NoClean('p_a', 'p_${BAR}b', ['p_c', 'p_d'], 'p_$FOO')
3147 assert t[0].__class__.__name__ == 'Entry', t[0].__class__.__name__
3148 assert t[0].get_internal_path() == 'p_a'
3149 assert t[0].noclean
3150 assert t[1].__class__.__name__ == 'Dir', t[1].__class__.__name__
3151 assert t[1].get_internal_path() == 'p_hhhb'
3152 assert t[1].noclean
3153 assert t[2].__class__.__name__ == 'Entry', t[2].__class__.__name__
3154 assert t[2].get_internal_path() == 'p_c'
3155 assert t[2].noclean
3156 assert t[3].__class__.__name__ == 'File', t[3].__class__.__name__
3157 assert t[3].get_internal_path() == 'p_d'
3158 assert t[3].noclean
3159 assert t[4].__class__.__name__ == 'Entry', t[4].__class__.__name__
3160 assert t[4].get_internal_path() == 'p_ggg'
3161 assert t[4].noclean
3163 def test_Dump(self) -> None:
3164 """Test the Dump() method"""
3166 env = self.TestEnvironment(FOO = 'foo')
3167 assert env.Dump('FOO') == "'foo'", env.Dump('FOO')
3168 assert len(env.Dump()) > 200, env.Dump() # no args version
3170 assert env.Dump('FOO', 'json') == '"foo"' # JSON key version
3171 import json
3172 env_dict = json.loads(env.Dump(format = 'json'))
3173 assert env_dict['FOO'] == 'foo' # full JSON version
3175 try:
3176 env.Dump(format = 'markdown')
3177 except ValueError as e:
3178 assert str(e) == "Unsupported serialization format: markdown."
3179 else:
3180 self.fail("Did not catch expected ValueError.")
3182 def test_Environment(self) -> None:
3183 """Test the Environment() method"""
3184 env = self.TestEnvironment(FOO = 'xxx', BAR = 'yyy')
3186 e2 = env.Environment(X = '$FOO', Y = '$BAR')
3187 assert e2['X'] == 'xxx', e2['X']
3188 assert e2['Y'] == 'yyy', e2['Y']
3190 def test_Execute(self) -> None:
3191 """Test the Execute() method"""
3193 class MyAction:
3194 def __init__(self, *args, **kw) -> None:
3195 self.args = args
3196 def __call__(self, target, source, env) -> str:
3197 return "%s executed" % self.args
3199 env = Environment()
3200 env.Action = MyAction
3202 result = env.Execute("foo")
3203 assert result == "foo executed", result
3205 def test_Entry(self) -> None:
3206 """Test the Entry() method"""
3207 class MyFS:
3208 def Entry(self, name) -> str:
3209 return 'Entry(%s)' % name
3211 env = self.TestEnvironment(FOO = 'fooentry', BAR = 'barentry')
3212 env.fs = MyFS()
3214 e = env.Entry('e')
3215 assert e == 'Entry(e)', e
3217 e = env.Entry('$FOO')
3218 assert e == 'Entry(fooentry)', e
3220 e = env.Entry('${BAR}_$BAR')
3221 assert e == 'Entry(barentry_barentry)', e
3223 e = env.Entry(['entry1'])
3224 assert e == ['Entry(entry1)'], e
3226 e = env.Entry(['entry1', 'entry2'])
3227 assert e == ['Entry(entry1)', 'Entry(entry2)'], e
3229 def test_File(self) -> None:
3230 """Test the File() method"""
3231 class MyFS:
3232 def File(self, name) -> str:
3233 return 'File(%s)' % name
3235 env = self.TestEnvironment(FOO = 'foofile', BAR = 'barfile')
3236 env.fs = MyFS()
3238 f = env.File('f')
3239 assert f == 'File(f)', f
3241 f = env.File('$FOO')
3242 assert f == 'File(foofile)', f
3244 f = env.File('${BAR}_$BAR')
3245 assert f == 'File(barfile_barfile)', f
3247 f = env.File(['file1'])
3248 assert f == ['File(file1)'], f
3250 f = env.File(['file1', 'file2'])
3251 assert f == ['File(file1)', 'File(file2)'], f
3253 def test_FindFile(self) -> None:
3254 """Test the FindFile() method"""
3255 env = self.TestEnvironment(FOO = 'fff', BAR = 'bbb')
3257 r = env.FindFile('foo', ['no_such_directory'])
3258 assert r is None, r
3260 # XXX
3262 def test_Flatten(self) -> None:
3263 """Test the Flatten() method"""
3264 env = Environment()
3265 l = env.Flatten([1])
3266 assert l == [1]
3267 l = env.Flatten([1, [2, [3, [4]]]])
3268 assert l == [1, 2, 3, 4], l
3270 def test_GetBuildPath(self) -> None:
3271 """Test the GetBuildPath() method."""
3272 env = self.TestEnvironment(MAGIC = 'xyzzy')
3274 p = env.GetBuildPath('foo')
3275 assert p == 'foo', p
3277 p = env.GetBuildPath('$MAGIC')
3278 assert p == 'xyzzy', p
3280 def test_Ignore(self) -> None:
3281 """Test the explicit Ignore method."""
3282 env = self.TestEnvironment(FOO='yyy', BAR='zzz')
3283 env.Dir('dir1')
3284 env.Dir('dir2')
3285 env.File('yyyzzz')
3286 env.File('zzzyyy')
3288 t = env.Ignore(target='targ.py', dependency='dep.py')[0]
3289 assert t.__class__.__name__ == 'Entry', t.__class__.__name__
3290 assert t.get_internal_path() == 'targ.py'
3291 assert len(t.ignore) == 1
3292 i = t.ignore[0]
3293 assert i.__class__.__name__ == 'Entry', i.__class__.__name__
3294 assert i.get_internal_path() == 'dep.py'
3296 t = env.Ignore(target='$FOO$BAR', dependency='$BAR$FOO')[0]
3297 assert t.__class__.__name__ == 'File', t.__class__.__name__
3298 assert t.get_internal_path() == 'yyyzzz'
3299 assert len(t.ignore) == 1
3300 i = t.ignore[0]
3301 assert i.__class__.__name__ == 'File', i.__class__.__name__
3302 assert i.get_internal_path() == 'zzzyyy'
3304 t = env.Ignore(target='dir1', dependency='dir2')[0]
3305 assert t.__class__.__name__ == 'Dir', t.__class__.__name__
3306 assert t.get_internal_path() == 'dir1'
3307 assert len(t.ignore) == 1
3308 i = t.ignore[0]
3309 assert i.__class__.__name__ == 'Dir', i.__class__.__name__
3310 assert i.get_internal_path() == 'dir2'
3312 def test_Literal(self) -> None:
3313 """Test the Literal() method"""
3314 env = self.TestEnvironment(FOO='fff', BAR='bbb')
3315 list = env.subst_list([env.Literal('$FOO'), '$BAR'])[0]
3316 assert list == ['$FOO', 'bbb'], list
3317 list = env.subst_list(['$FOO', env.Literal('$BAR')])[0]
3318 assert list == ['fff', '$BAR'], list
3320 def test_Local(self) -> None:
3321 """Test the Local() method."""
3322 env = self.TestEnvironment(FOO='lll')
3324 l = env.Local(env.fs.File('fff'))
3325 assert str(l[0]) == 'fff', l[0]
3327 l = env.Local('ggg', '$FOO')
3328 assert str(l[0]) == 'ggg', l[0]
3329 assert str(l[1]) == 'lll', l[1]
3331 def test_Precious(self) -> None:
3332 """Test the Precious() method"""
3333 env = self.TestEnvironment(FOO='ggg', BAR='hhh')
3334 env.Dir('p_hhhb')
3335 env.File('p_d')
3336 t = env.Precious('p_a', 'p_${BAR}b', ['p_c', 'p_d'], 'p_$FOO')
3338 assert t[0].__class__.__name__ == 'Entry', t[0].__class__.__name__
3339 assert t[0].get_internal_path() == 'p_a'
3340 assert t[0].precious
3341 assert t[1].__class__.__name__ == 'Dir', t[1].__class__.__name__
3342 assert t[1].get_internal_path() == 'p_hhhb'
3343 assert t[1].precious
3344 assert t[2].__class__.__name__ == 'Entry', t[2].__class__.__name__
3345 assert t[2].get_internal_path() == 'p_c'
3346 assert t[2].precious
3347 assert t[3].__class__.__name__ == 'File', t[3].__class__.__name__
3348 assert t[3].get_internal_path() == 'p_d'
3349 assert t[3].precious
3350 assert t[4].__class__.__name__ == 'Entry', t[4].__class__.__name__
3351 assert t[4].get_internal_path() == 'p_ggg'
3352 assert t[4].precious
3354 def test_Pseudo(self) -> None:
3355 """Test the Pseudo() method"""
3356 env = self.TestEnvironment(FOO='ggg', BAR='hhh')
3357 env.Dir('p_hhhb')
3358 env.File('p_d')
3359 t = env.Pseudo('p_a', 'p_${BAR}b', ['p_c', 'p_d'], 'p_$FOO')
3361 assert t[0].__class__.__name__ == 'Entry', t[0].__class__.__name__
3362 assert t[0].get_internal_path() == 'p_a'
3363 assert t[0].pseudo
3364 assert t[1].__class__.__name__ == 'Dir', t[1].__class__.__name__
3365 assert t[1].get_internal_path() == 'p_hhhb'
3366 assert t[1].pseudo
3367 assert t[2].__class__.__name__ == 'Entry', t[2].__class__.__name__
3368 assert t[2].get_internal_path() == 'p_c'
3369 assert t[2].pseudo
3370 assert t[3].__class__.__name__ == 'File', t[3].__class__.__name__
3371 assert t[3].get_internal_path() == 'p_d'
3372 assert t[3].pseudo
3373 assert t[4].__class__.__name__ == 'Entry', t[4].__class__.__name__
3374 assert t[4].get_internal_path() == 'p_ggg'
3375 assert t[4].pseudo
3377 def test_Repository(self) -> None:
3378 """Test the Repository() method."""
3379 class MyFS:
3380 def __init__(self) -> None:
3381 self.list = []
3382 def Repository(self, *dirs) -> None:
3383 self.list.extend(list(dirs))
3384 def Dir(self, name):
3385 return name
3386 env = self.TestEnvironment(FOO='rrr', BAR='sss')
3387 env.fs = MyFS()
3388 env.Repository('/tmp/foo')
3389 env.Repository('/tmp/$FOO', '/tmp/$BAR/foo')
3390 expect = ['/tmp/foo', '/tmp/rrr', '/tmp/sss/foo']
3391 assert env.fs.list == expect, env.fs.list
3393 def test_Scanner(self) -> None:
3394 """Test the Scanner() method"""
3395 def scan(node, env, target, arg) -> None:
3396 pass
3398 env = self.TestEnvironment(FOO = scan)
3400 s = env.Scanner('foo')
3401 assert s is not None, s
3403 s = env.Scanner(function = 'foo')
3404 assert s is not None, s
3406 if 0:
3407 s = env.Scanner('$FOO')
3408 assert s is not None, s
3410 s = env.Scanner(function = '$FOO')
3411 assert s is not None, s
3413 def test_SConsignFile(self) -> None:
3414 """Test the SConsignFile() method"""
3415 import SCons.SConsign
3417 class MyFS:
3418 SConstruct_dir = os.sep + 'dir'
3420 env = self.TestEnvironment(FOO = 'SConsign',
3421 BAR = os.path.join(os.sep, 'File'))
3422 env.fs = MyFS()
3423 env.Execute = lambda action: None
3425 try:
3426 fnames = []
3427 dbms = []
3428 def capture(name, dbm_module, fnames=fnames, dbms=dbms) -> None:
3429 fnames.append(name)
3430 dbms.append(dbm_module)
3432 save_SConsign_File = SCons.SConsign.File
3433 SCons.SConsign.File = capture
3435 env.SConsignFile('foo')
3436 assert fnames[-1] == os.path.join(os.sep, 'dir', 'foo'), fnames
3437 assert dbms[-1] is None, dbms
3439 env.SConsignFile('$FOO')
3440 assert fnames[-1] == os.path.join(os.sep, 'dir', 'SConsign'), fnames
3441 assert dbms[-1] is None, dbms
3443 env.SConsignFile('/$FOO')
3444 assert fnames[-1] == os.sep + 'SConsign', fnames
3445 assert dbms[-1] is None, dbms
3447 env.SConsignFile(os.sep + '$FOO')
3448 assert fnames[-1] == os.sep + 'SConsign', fnames
3449 assert dbms[-1] is None, dbms
3451 env.SConsignFile('$BAR', 'x')
3452 assert fnames[-1] == os.path.join(os.sep, 'File'), fnames
3453 assert dbms[-1] == 'x', dbms
3455 env.SConsignFile('__$BAR', 7)
3456 assert fnames[-1] == os.path.join(os.sep, 'dir', '__', 'File'), fnames
3457 assert dbms[-1] == 7, dbms
3459 env.SConsignFile()
3460 assert fnames[-1] == os.path.join(os.sep, 'dir', current_sconsign_filename()), fnames
3461 assert dbms[-1] is None, dbms
3463 env.SConsignFile(None)
3464 assert fnames[-1] is None, fnames
3465 assert dbms[-1] is None, dbms
3466 finally:
3467 SCons.SConsign.File = save_SConsign_File
3469 def test_SideEffect(self) -> None:
3470 """Test the SideEffect() method"""
3471 env = self.TestEnvironment(LIB='lll', FOO='fff', BAR='bbb')
3472 env.File('mylll.pdb')
3473 env.Dir('mymmm.pdb')
3475 foo = env.Object('foo.obj', 'foo.cpp')[0]
3476 bar = env.Object('bar.obj', 'bar.cpp')[0]
3477 s = env.SideEffect('mylib.pdb', ['foo.obj', 'bar.obj'])
3478 assert len(s) == 1, len(s)
3479 s = s[0]
3480 assert s.__class__.__name__ == 'Entry', s.__class__.__name__
3481 assert s.get_internal_path() == 'mylib.pdb'
3482 assert s.side_effect
3483 assert foo.side_effects == [s]
3484 assert bar.side_effects == [s]
3486 fff = env.Object('fff.obj', 'fff.cpp')[0]
3487 bbb = env.Object('bbb.obj', 'bbb.cpp')[0]
3488 s = env.SideEffect('my${LIB}.pdb', ['${FOO}.obj', '${BAR}.obj'])
3489 assert len(s) == 1, len(s)
3490 s = s[0]
3491 assert s.__class__.__name__ == 'File', s.__class__.__name__
3492 assert s.get_internal_path() == 'mylll.pdb'
3493 assert s.side_effect
3494 assert fff.side_effects == [s], fff.side_effects
3495 assert bbb.side_effects == [s], bbb.side_effects
3497 ggg = env.Object('ggg.obj', 'ggg.cpp')[0]
3498 ccc = env.Object('ccc.obj', 'ccc.cpp')[0]
3499 s = env.SideEffect('mymmm.pdb', ['ggg.obj', 'ccc.obj'])
3500 assert len(s) == 1, len(s)
3501 s = s[0]
3502 assert s.__class__.__name__ == 'Dir', s.__class__.__name__
3503 assert s.get_internal_path() == 'mymmm.pdb'
3504 assert s.side_effect
3505 assert ggg.side_effects == [s], ggg.side_effects
3506 assert ccc.side_effects == [s], ccc.side_effects
3508 # Verify that duplicate side effects are not allowed.
3509 before = len(ggg.side_effects)
3510 s = env.SideEffect('mymmm.pdb', ggg)
3511 assert len(s) == 0, len(s)
3512 assert len(ggg.side_effects) == before, len(ggg.side_effects)
3514 def test_Split(self) -> None:
3515 """Test the Split() method"""
3516 env = self.TestEnvironment(FOO = 'fff', BAR = 'bbb')
3517 s = env.Split("foo bar")
3518 assert s == ["foo", "bar"], s
3519 s = env.Split("$FOO bar")
3520 assert s == ["fff", "bar"], s
3521 s = env.Split(["foo", "bar"])
3522 assert s == ["foo", "bar"], s
3523 s = env.Split(["foo", "${BAR}-bbb"])
3524 assert s == ["foo", "bbb-bbb"], s
3525 s = env.Split("foo")
3526 assert s == ["foo"], s
3527 s = env.Split("$FOO$BAR")
3528 assert s == ["fffbbb"], s
3531 def test_Value(self) -> None:
3532 """Test creating a Value() object
3534 env = Environment()
3535 v1 = env.Value('a')
3536 assert v1.value == 'a', v1.value
3538 value2 = 'a'
3539 v2 = env.Value(value2)
3540 assert v2.value == value2, v2.value
3541 assert v2.value is value2, v2.value
3543 assert v1 is v2
3545 v3 = env.Value('c', 'build-c')
3546 assert v3.value == 'c', v3.value
3548 v4 = env.Value(b'\x00\x0F', name='name')
3549 assert v4.value == b'\x00\x0F', v4.value
3550 assert v4.name == 'name', v4.name
3553 def test_Environment_global_variable(self) -> None:
3554 """Test setting Environment variable to an Environment.Base subclass"""
3555 class MyEnv(SCons.Environment.Base):
3556 def xxx(self, string):
3557 return self.subst(string)
3559 SCons.Environment.Environment = MyEnv
3561 env = SCons.Environment.Environment(FOO = 'foo')
3563 f = env.subst('$FOO')
3564 assert f == 'foo', f
3566 f = env.xxx('$FOO')
3567 assert f == 'foo', f
3569 def test_bad_keywords(self) -> None:
3570 """Test trying to use reserved keywords in an Environment"""
3571 added = []
3573 env = self.TestEnvironment(TARGETS = 'targets',
3574 SOURCES = 'sources',
3575 SOURCE = 'source',
3576 TARGET = 'target',
3577 CHANGED_SOURCES = 'changed_sources',
3578 CHANGED_TARGETS = 'changed_targets',
3579 UNCHANGED_SOURCES = 'unchanged_sources',
3580 UNCHANGED_TARGETS = 'unchanged_targets',
3581 INIT = 'init')
3582 bad_msg = '%s is not reserved, but got omitted; see Environment.construction_var_name_ok'
3583 added.append('INIT')
3584 for x in self.reserved_variables:
3585 assert x not in env, env[x]
3586 for x in added:
3587 assert x in env, bad_msg % x
3589 env.Append(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 APPEND = 'append')
3598 added.append('APPEND')
3599 for x in self.reserved_variables:
3600 assert x not in env, env[x]
3601 for x in added:
3602 assert x in env, bad_msg % x
3604 env.AppendUnique(TARGETS = 'targets',
3605 SOURCES = 'sources',
3606 SOURCE = 'source',
3607 TARGET = 'target',
3608 CHANGED_SOURCES = 'changed_sources',
3609 CHANGED_TARGETS = 'changed_targets',
3610 UNCHANGED_SOURCES = 'unchanged_sources',
3611 UNCHANGED_TARGETS = 'unchanged_targets',
3612 APPENDUNIQUE = 'appendunique')
3613 added.append('APPENDUNIQUE')
3614 for x in self.reserved_variables:
3615 assert x not in env, env[x]
3616 for x in added:
3617 assert x in env, bad_msg % x
3619 env.Prepend(TARGETS = 'targets',
3620 SOURCES = 'sources',
3621 SOURCE = 'source',
3622 TARGET = 'target',
3623 CHANGED_SOURCES = 'changed_sources',
3624 CHANGED_TARGETS = 'changed_targets',
3625 UNCHANGED_SOURCES = 'unchanged_sources',
3626 UNCHANGED_TARGETS = 'unchanged_targets',
3627 PREPEND = 'prepend')
3628 added.append('PREPEND')
3629 for x in self.reserved_variables:
3630 assert x not in env, env[x]
3631 for x in added:
3632 assert x in env, bad_msg % x
3634 env.Prepend(TARGETS = 'targets',
3635 SOURCES = 'sources',
3636 SOURCE = 'source',
3637 TARGET = 'target',
3638 CHANGED_SOURCES = 'changed_sources',
3639 CHANGED_TARGETS = 'changed_targets',
3640 UNCHANGED_SOURCES = 'unchanged_sources',
3641 UNCHANGED_TARGETS = 'unchanged_targets',
3642 PREPENDUNIQUE = 'prependunique')
3643 added.append('PREPENDUNIQUE')
3644 for x in self.reserved_variables:
3645 assert x not in env, env[x]
3646 for x in added:
3647 assert x in env, bad_msg % x
3649 env.Replace(TARGETS = 'targets',
3650 SOURCES = 'sources',
3651 SOURCE = 'source',
3652 TARGET = 'target',
3653 CHANGED_SOURCES = 'changed_sources',
3654 CHANGED_TARGETS = 'changed_targets',
3655 UNCHANGED_SOURCES = 'unchanged_sources',
3656 UNCHANGED_TARGETS = 'unchanged_targets',
3657 REPLACE = 'replace')
3658 added.append('REPLACE')
3659 for x in self.reserved_variables:
3660 assert x not in env, env[x]
3661 for x in added:
3662 assert x in env, bad_msg % x
3664 copy = env.Clone(TARGETS = 'targets',
3665 SOURCES = 'sources',
3666 SOURCE = 'source',
3667 TARGET = 'target',
3668 CHANGED_SOURCES = 'changed_sources',
3669 CHANGED_TARGETS = 'changed_targets',
3670 UNCHANGED_SOURCES = 'unchanged_sources',
3671 UNCHANGED_TARGETS = 'unchanged_targets',
3672 COPY = 'copy')
3673 for x in self.reserved_variables:
3674 assert x not in copy, env[x]
3675 for x in added + ['COPY']:
3676 assert x in copy, bad_msg % x
3678 over = env.Override({'TARGETS' : 'targets',
3679 'SOURCES' : 'sources',
3680 'SOURCE' : 'source',
3681 'TARGET' : 'target',
3682 'CHANGED_SOURCES' : 'changed_sources',
3683 'CHANGED_TARGETS' : 'changed_targets',
3684 'UNCHANGED_SOURCES' : 'unchanged_sources',
3685 'UNCHANGED_TARGETS' : 'unchanged_targets',
3686 'OVERRIDE' : 'override'})
3687 for x in self.reserved_variables:
3688 assert x not in over, over[x]
3689 for x in added + ['OVERRIDE']:
3690 assert x in over, bad_msg % x
3692 def test_parse_flags(self) -> None:
3693 """Test the Base class parse_flags argument"""
3694 # all we have to show is that it gets to MergeFlags internally
3695 env = Environment(tools=[], parse_flags = '-X')
3696 assert env['CCFLAGS'] == ['-X'], env['CCFLAGS']
3698 env = Environment(tools=[], CCFLAGS=None, parse_flags = '-Y')
3699 assert env['CCFLAGS'] == ['-Y'], env['CCFLAGS']
3701 env = Environment(tools=[], CPPDEFINES='FOO', parse_flags='-std=c99 -X -DBAR')
3702 assert env['CFLAGS'] == ['-std=c99'], env['CFLAGS']
3703 assert env['CCFLAGS'] == ['-X'], env['CCFLAGS']
3704 self.assertEqual(list(env['CPPDEFINES']), ['FOO', 'BAR'])
3706 def test_clone_parse_flags(self) -> None:
3707 """Test the env.Clone() parse_flags argument"""
3708 # all we have to show is that it gets to MergeFlags internally
3709 env = Environment(tools = [])
3710 env2 = env.Clone(parse_flags = '-X')
3711 assert 'CCFLAGS' not in env
3712 assert env2['CCFLAGS'] == ['-X'], env2['CCFLAGS']
3714 env = Environment(tools = [], CCFLAGS=None)
3715 env2 = env.Clone(parse_flags = '-Y')
3716 assert env['CCFLAGS'] is None, env['CCFLAGS']
3717 assert env2['CCFLAGS'] == ['-Y'], env2['CCFLAGS']
3719 env = Environment(tools = [], CPPDEFINES = 'FOO')
3720 env2 = env.Clone(parse_flags = '-std=c99 -X -DBAR')
3721 assert 'CFLAGS' not in env
3722 assert env2['CFLAGS'] == ['-std=c99'], env2['CFLAGS']
3723 assert 'CCFLAGS' not in env
3724 assert env2['CCFLAGS'] == ['-X'], env2['CCFLAGS']
3725 assert env['CPPDEFINES'] == 'FOO', env['CPPDEFINES']
3726 self.assertEqual(list(env2['CPPDEFINES']), ['FOO','BAR'])
3729 class OverrideEnvironmentTestCase(unittest.TestCase,TestEnvironmentFixture):
3731 def setUp(self) -> None:
3732 env = Environment()
3733 env._dict = {'XXX' : 'x', 'YYY' : 'y'}
3734 def verify_value(env, key, value, *args, **kwargs) -> None:
3735 """Verifies that key is value on the env this is called with."""
3736 assert env[key] == value
3737 env.AddMethod(verify_value)
3738 env2 = OverrideEnvironment(env, {'XXX' : 'x2'})
3739 env3 = OverrideEnvironment(env2, {'XXX' : 'x3', 'YYY' : 'y3', 'ZZZ' : 'z3'})
3740 self.envs = [ env, env2, env3 ]
3742 def checkpath(self, node, expect):
3743 return str(node) == os.path.normpath(expect)
3745 def test___init__(self) -> None:
3746 """Test OverrideEnvironment initialization"""
3747 env, env2, env3 = self.envs
3748 assert env['XXX'] == 'x', env['XXX']
3749 assert env2['XXX'] == 'x2', env2['XXX']
3750 assert env3['XXX'] == 'x3', env3['XXX']
3751 assert env['YYY'] == 'y', env['YYY']
3752 assert env2['YYY'] == 'y', env2['YYY']
3753 assert env3['YYY'] == 'y3', env3['YYY']
3755 def test___delitem__(self) -> None:
3756 """Test deleting variables from an OverrideEnvironment"""
3757 env, env2, env3 = self.envs
3759 del env3['XXX']
3760 assert 'XXX' not in env, "env has XXX?"
3761 assert 'XXX' not in env2, "env2 has XXX?"
3762 assert 'XXX' not in env3, "env3 has XXX?"
3764 del env3['YYY']
3765 assert 'YYY' not in env, "env has YYY?"
3766 assert 'YYY' not in env2, "env2 has YYY?"
3767 assert 'YYY' not in env3, "env3 has YYY?"
3769 del env3['ZZZ']
3770 assert 'ZZZ' not in env, "env has ZZZ?"
3771 assert 'ZZZ' not in env2, "env2 has ZZZ?"
3772 assert 'ZZZ' not in env3, "env3 has ZZZ?"
3774 def test_get(self) -> None:
3775 """Test the OverrideEnvironment get() method"""
3776 env, env2, env3 = self.envs
3777 assert env.get('XXX') == 'x', env.get('XXX')
3778 assert env2.get('XXX') == 'x2', env2.get('XXX')
3779 assert env3.get('XXX') == 'x3', env3.get('XXX')
3780 assert env.get('YYY') == 'y', env.get('YYY')
3781 assert env2.get('YYY') == 'y', env2.get('YYY')
3782 assert env3.get('YYY') == 'y3', env3.get('YYY')
3783 assert env.get('ZZZ') is None, env.get('ZZZ')
3784 assert env2.get('ZZZ') is None, env2.get('ZZZ')
3785 assert env3.get('ZZZ') == 'z3', env3.get('ZZZ')
3787 def test_contains(self) -> None:
3788 """Test the OverrideEnvironment __contains__() method"""
3789 env, env2, env3 = self.envs
3790 assert 'XXX' in env, 'XXX' in env
3791 assert 'XXX' in env2, 'XXX' in env2
3792 assert 'XXX' in env3, 'XXX' in env3
3793 assert 'YYY' in env, 'YYY' in env
3794 assert 'YYY' in env2, 'YYY' in env2
3795 assert 'YYY' in env3, 'YYY' in env3
3796 assert 'ZZZ' not in env, 'ZZZ' in env
3797 assert 'ZZZ' not in env2, 'ZZZ' in env2
3798 assert 'ZZZ' in env3, 'ZZZ' in env3
3800 def test_Dictionary(self) -> None:
3801 """Test the OverrideEnvironment Dictionary() method"""
3802 env, env2, env3 = self.envs
3803 # nothing overrriden
3804 items = env.Dictionary()
3805 assert items == {'XXX' : 'x', 'YYY' : 'y'}, items
3806 # env2 overrides XXX, YYY unchanged
3807 items = env2.Dictionary()
3808 assert items == {'XXX' : 'x2', 'YYY' : 'y'}, items
3809 # env3 overrides XXX, YYY, adds ZZZ
3810 items = env3.Dictionary()
3811 assert items == {'XXX' : 'x3', 'YYY' : 'y3', 'ZZZ' : 'z3'}, items
3812 # test one-arg and multi-arg Dictionary
3813 assert env3.Dictionary('XXX') == 'x3', env3.Dictionary('XXX')
3814 xxx, yyy = env2.Dictionary('XXX', 'YYY')
3815 assert xxx == 'x2', xxx
3816 assert yyy == 'y', yyy
3817 del env3['XXX']
3818 assert 'XXX' not in env3.Dictionary()
3819 assert 'XXX' not in env2.Dictionary()
3820 assert 'XXX' not in env.Dictionary()
3822 def test_items(self) -> None:
3823 """Test the OverrideEnvironment items() method"""
3824 env, env2, env3 = self.envs
3825 items = sorted(env.items())
3826 assert items == [('XXX', 'x'), ('YYY', 'y')], items
3827 items = sorted(env2.items())
3828 assert items == [('XXX', 'x2'), ('YYY', 'y')], items
3829 items = sorted(env3.items())
3830 assert items == [('XXX', 'x3'), ('YYY', 'y3'), ('ZZZ', 'z3')], items
3832 def test_keys(self) -> None:
3833 """Test the OverrideEnvironment keys() method"""
3834 env, env2, env3 = self.envs
3835 keys = sorted(env.keys())
3836 assert keys == ['XXX', 'YYY'], keys
3837 keys = sorted(env2.keys())
3838 assert keys == ['XXX', 'YYY'], keys
3839 keys = sorted(env3.keys())
3840 assert keys == ['XXX', 'YYY', 'ZZZ'], keys
3842 def test_values(self) -> None:
3843 """Test the OverrideEnvironment values() method"""
3844 env, env2, env3 = self.envs
3845 values = sorted(env.values())
3846 assert values == ['x', 'y'], values
3847 values = sorted(env2.values())
3848 assert values == ['x2', 'y'], values
3849 values = sorted(env3.values())
3850 assert values == ['x3', 'y3', 'z3'], values
3852 def test_setdefault(self) -> None:
3853 """Test the OverrideEnvironment setdefault() method."""
3854 env, env2, env3 = self.envs
3855 # does not set for existing key
3856 assert env2.setdefault('XXX', 'z') == 'x2', env2['XXX']
3857 # set/return using default for non-existing key
3858 assert env2.setdefault('ZZZ', 'z2') == 'z2', env2['ZZZ']
3859 # set did not leak through to base env
3860 assert 'ZZZ' not in env
3862 def test_gvars(self) -> None:
3863 """Test the OverrideEnvironment gvars() method"""
3864 env, env2, env3 = self.envs
3865 gvars = env.gvars()
3866 assert gvars == {'XXX' : 'x', 'YYY' : 'y'}, gvars
3867 gvars = env2.gvars()
3868 assert gvars == {'XXX' : 'x', 'YYY' : 'y'}, gvars
3869 gvars = env3.gvars()
3870 assert gvars == {'XXX' : 'x', 'YYY' : 'y'}, gvars
3872 def test_lvars(self) -> None:
3873 """Test the OverrideEnvironment lvars() method"""
3874 env, env2, env3 = self.envs
3875 lvars = env.lvars()
3876 assert lvars == {}, lvars
3877 lvars = env2.lvars()
3878 assert lvars == {'XXX' : 'x2'}, lvars
3879 lvars = env3.lvars()
3880 assert lvars == {'XXX' : 'x3', 'YYY' : 'y3', 'ZZZ' : 'z3'}, lvars
3882 def test_Replace(self) -> None:
3883 """Test the OverrideEnvironment Replace() method"""
3884 env, env2, env3 = self.envs
3885 assert env['XXX'] == 'x', env['XXX']
3886 assert env2['XXX'] == 'x2', env2['XXX']
3887 assert env3['XXX'] == 'x3', env3['XXX']
3888 assert env['YYY'] == 'y', env['YYY']
3889 assert env2['YYY'] == 'y', env2['YYY']
3890 assert env3['YYY'] == 'y3', env3['YYY']
3892 env.Replace(YYY = 'y4')
3894 assert env['XXX'] == 'x', env['XXX']
3895 assert env2['XXX'] == 'x2', env2['XXX']
3896 assert env3['XXX'] == 'x3', env3['XXX']
3897 assert env['YYY'] == 'y4', env['YYY']
3898 assert env2['YYY'] == 'y4', env2['YYY']
3899 assert env3['YYY'] == 'y3', env3['YYY']
3901 # Tests a number of Base methods through an OverrideEnvironment to
3902 # make sure they handle overridden constructionv variables properly.
3904 # The following Base methods also call self.subst(), and so could
3905 # theoretically be subject to problems with evaluating overridden
3906 # variables, but they're never really called that way in the rest
3907 # of our code, so we won't worry about them (at least for now):
3909 # ParseConfig()
3910 # ParseDepends()
3911 # Platform()
3912 # Tool()
3914 # Action()
3915 # Alias()
3916 # Builder()
3917 # CacheDir()
3918 # Configure()
3919 # Environment()
3920 # FindFile()
3921 # Scanner()
3923 # It's unlikely Clone() will ever be called this way, so let the
3924 # other methods test that handling overridden values works.
3925 #def test_Clone(self):
3926 # """Test the OverrideEnvironment Clone() method"""
3927 # pass
3929 def test_FindIxes(self) -> None:
3930 """Test the OverrideEnvironment FindIxes() method"""
3931 env, env2, env3 = self.envs
3932 x = env.FindIxes(['xaaay'], 'XXX', 'YYY')
3933 assert x == 'xaaay', x
3934 x = env2.FindIxes(['x2aaay'], 'XXX', 'YYY')
3935 assert x == 'x2aaay', x
3936 x = env3.FindIxes(['x3aaay3'], 'XXX', 'YYY')
3937 assert x == 'x3aaay3', x
3939 def test_ReplaceIxes(self) -> None:
3940 """Test the OverrideEnvironment ReplaceIxes() method"""
3941 env, env2, env3 = self.envs
3942 x = env.ReplaceIxes('xaaay', 'XXX', 'YYY', 'YYY', 'XXX')
3943 assert x == 'yaaax', x
3944 x = env2.ReplaceIxes('x2aaay', 'XXX', 'YYY', 'YYY', 'XXX')
3945 assert x == 'yaaax2', x
3946 x = env3.ReplaceIxes('x3aaay3', 'XXX', 'YYY', 'YYY', 'XXX')
3947 assert x == 'y3aaax3', x
3949 # It's unlikely WhereIs() will ever be called this way, so let the
3950 # other methods test that handling overridden values works.
3951 #def test_WhereIs(self):
3952 # """Test the OverrideEnvironment WhereIs() method"""
3953 # pass
3955 def test_PseudoBuilderInherits(self) -> None:
3956 """Test that pseudo-builders inherit the overrided values."""
3957 env, env2, env3 = self.envs
3958 env.verify_value('XXX', 'x')
3959 env2.verify_value('XXX', 'x2')
3960 env3.verify_value('XXX', 'x3')
3962 def test_Dir(self) -> None:
3963 """Test the OverrideEnvironment Dir() method"""
3964 env, env2, env3 = self.envs
3965 x = env.Dir('ddir/$XXX')
3966 assert self.checkpath(x, 'ddir/x'), str(x)
3967 x = env2.Dir('ddir/$XXX')
3968 assert self.checkpath(x, 'ddir/x2'), str(x)
3969 x = env3.Dir('ddir/$XXX')
3970 assert self.checkpath(x, 'ddir/x3'), str(x)
3972 def test_Entry(self) -> None:
3973 """Test the OverrideEnvironment Entry() method"""
3974 env, env2, env3 = self.envs
3975 x = env.Entry('edir/$XXX')
3976 assert self.checkpath(x, 'edir/x'), str(x)
3977 x = env2.Entry('edir/$XXX')
3978 assert self.checkpath(x, 'edir/x2'), str(x)
3979 x = env3.Entry('edir/$XXX')
3980 assert self.checkpath(x, 'edir/x3'), str(x)
3982 def test_File(self) -> None:
3983 """Test the OverrideEnvironment File() method"""
3984 env, env2, env3 = self.envs
3985 x = env.File('fdir/$XXX')
3986 assert self.checkpath(x, 'fdir/x'), str(x)
3987 x = env2.File('fdir/$XXX')
3988 assert self.checkpath(x, 'fdir/x2'), str(x)
3989 x = env3.File('fdir/$XXX')
3990 assert self.checkpath(x, 'fdir/x3'), str(x)
3992 def test_Split(self) -> None:
3993 """Test the OverrideEnvironment Split() method"""
3994 env, env2, env3 = self.envs
3995 env['AAA'] = '$XXX $YYY $ZZZ'
3996 x = env.Split('$AAA')
3997 assert x == ['x', 'y'], x
3998 x = env2.Split('$AAA')
3999 assert x == ['x2', 'y'], x
4000 x = env3.Split('$AAA')
4001 assert x == ['x3', 'y3', 'z3'], x
4003 def test_parse_flags(self) -> None:
4004 """Test the OverrideEnvironment parse_flags argument"""
4005 # all we have to show is that it gets to MergeFlags internally
4006 env = SubstitutionEnvironment()
4007 env2 = env.Override({'parse_flags' : '-X'})
4008 assert 'CCFLAGS' not in env
4009 assert env2['CCFLAGS'] == ['-X'], env2['CCFLAGS']
4011 env = SubstitutionEnvironment(CCFLAGS=None)
4012 env2 = env.Override({'parse_flags' : '-Y'})
4013 assert env['CCFLAGS'] is None, env['CCFLAGS']
4014 assert env2['CCFLAGS'] == ['-Y'], env2['CCFLAGS']
4016 env = SubstitutionEnvironment(CPPDEFINES='FOO')
4017 env2 = env.Override({'parse_flags': '-std=c99 -X -DBAR'})
4018 assert 'CFLAGS' not in env
4019 assert env2['CFLAGS'] == ['-std=c99'], env2['CFLAGS']
4020 assert 'CCFLAGS' not in env
4021 assert env2['CCFLAGS'] == ['-X'], env2['CCFLAGS']
4022 # make sure they are independent
4023 self.assertIsNot(env['CPPDEFINES'], env2['CPPDEFINES'])
4024 assert env['CPPDEFINES'] == 'FOO', env['CPPDEFINES']
4025 self.assertEqual(list(env2['CPPDEFINES']), ['FOO','BAR'])
4028 class NoSubstitutionProxyTestCase(unittest.TestCase,TestEnvironmentFixture):
4030 def test___init__(self) -> None:
4031 """Test NoSubstitutionProxy initialization"""
4032 env = self.TestEnvironment(XXX = 'x', YYY = 'y')
4033 assert env['XXX'] == 'x', env['XXX']
4034 assert env['YYY'] == 'y', env['YYY']
4036 proxy = NoSubstitutionProxy(env)
4037 assert proxy['XXX'] == 'x', proxy['XXX']
4038 assert proxy['YYY'] == 'y', proxy['YYY']
4040 def test_attributes(self) -> None:
4041 """Test getting and setting NoSubstitutionProxy attributes"""
4042 env = Environment()
4043 setattr(env, 'env_attr', 'value1')
4045 proxy = NoSubstitutionProxy(env)
4046 setattr(proxy, 'proxy_attr', 'value2')
4048 x = getattr(env, 'env_attr')
4049 assert x == 'value1', x
4050 x = getattr(proxy, 'env_attr')
4051 assert x == 'value1', x
4053 x = getattr(env, 'proxy_attr')
4054 assert x == 'value2', x
4055 x = getattr(proxy, 'proxy_attr')
4056 assert x == 'value2', x
4058 def test_subst(self) -> None:
4059 """Test the NoSubstitutionProxy.subst() method"""
4060 env = self.TestEnvironment(XXX = 'x', YYY = 'y')
4061 assert env['XXX'] == 'x', env['XXX']
4062 assert env['YYY'] == 'y', env['YYY']
4064 proxy = NoSubstitutionProxy(env)
4065 assert proxy['XXX'] == 'x', proxy['XXX']
4066 assert proxy['YYY'] == 'y', proxy['YYY']
4068 x = env.subst('$XXX')
4069 assert x == 'x', x
4070 x = proxy.subst('$XXX')
4071 assert x == '$XXX', x
4073 x = proxy.subst('$YYY', raw=7, target=None, source=None,
4074 conv=None,
4075 extra_meaningless_keyword_argument=None)
4076 assert x == '$YYY', x
4078 def test_subst_kw(self) -> None:
4079 """Test the NoSubstitutionProxy.subst_kw() method"""
4080 env = self.TestEnvironment(XXX = 'x', YYY = 'y')
4081 assert env['XXX'] == 'x', env['XXX']
4082 assert env['YYY'] == 'y', env['YYY']
4084 proxy = NoSubstitutionProxy(env)
4085 assert proxy['XXX'] == 'x', proxy['XXX']
4086 assert proxy['YYY'] == 'y', proxy['YYY']
4088 x = env.subst_kw({'$XXX':'$YYY'})
4089 assert x == {'x':'y'}, x
4090 x = proxy.subst_kw({'$XXX':'$YYY'})
4091 assert x == {'$XXX':'$YYY'}, x
4093 def test_subst_list(self) -> None:
4094 """Test the NoSubstitutionProxy.subst_list() method"""
4095 env = self.TestEnvironment(XXX = 'x', YYY = 'y')
4096 assert env['XXX'] == 'x', env['XXX']
4097 assert env['YYY'] == 'y', env['YYY']
4099 proxy = NoSubstitutionProxy(env)
4100 assert proxy['XXX'] == 'x', proxy['XXX']
4101 assert proxy['YYY'] == 'y', proxy['YYY']
4103 x = env.subst_list('$XXX')
4104 assert x == [['x']], x
4105 x = proxy.subst_list('$XXX')
4106 assert x == [[]], x
4108 x = proxy.subst_list('$YYY', raw=0, target=None, source=None, conv=None)
4109 assert x == [[]], x
4111 def test_subst_target_source(self) -> None:
4112 """Test the NoSubstitutionProxy.subst_target_source() method"""
4113 env = self.TestEnvironment(XXX = 'x', YYY = 'y')
4114 assert env['XXX'] == 'x', env['XXX']
4115 assert env['YYY'] == 'y', env['YYY']
4117 proxy = NoSubstitutionProxy(env)
4118 assert proxy['XXX'] == 'x', proxy['XXX']
4119 assert proxy['YYY'] == 'y', proxy['YYY']
4121 args = ('$XXX $TARGET $SOURCE $YYY',)
4122 kw = {'target' : DummyNode('ttt'), 'source' : DummyNode('sss')}
4123 x = env.subst_target_source(*args, **kw)
4124 assert x == 'x ttt sss y', x
4125 x = proxy.subst_target_source(*args, **kw)
4126 assert x == ' ttt sss ', x
4128 class EnvironmentVariableTestCase(unittest.TestCase):
4130 def test_is_valid_construction_var(self) -> None:
4131 """Testing is_valid_construction_var()"""
4132 r = is_valid_construction_var("_a")
4133 assert r is not None, r
4134 r = is_valid_construction_var("z_")
4135 assert r is not None, r
4136 r = is_valid_construction_var("X_")
4137 assert r is not None, r
4138 r = is_valid_construction_var("2a")
4139 assert r is None, r
4140 r = is_valid_construction_var("a2_")
4141 assert r is not None, r
4142 r = is_valid_construction_var("/")
4143 assert r is None, r
4144 r = is_valid_construction_var("_/")
4145 assert r is None, r
4146 r = is_valid_construction_var("a/")
4147 assert r is None, r
4148 r = is_valid_construction_var(".b")
4149 assert r is None, r
4150 r = is_valid_construction_var("_.b")
4151 assert r is None, r
4152 r = is_valid_construction_var("b1._")
4153 assert r is None, r
4154 r = is_valid_construction_var("-b")
4155 assert r is None, r
4156 r = is_valid_construction_var("_-b")
4157 assert r is None, r
4158 r = is_valid_construction_var("b1-_")
4159 assert r is None, r
4163 if __name__ == "__main__":
4164 unittest.main()
4166 # Local Variables:
4167 # tab-width:4
4168 # indent-tabs-mode:nil
4169 # End:
4170 # vim: set expandtab tabstop=4 shiftwidth=4: