6d916209c8f07ea60597e9162752c9df9e7c2011
[scons.git] / src / engine / SCons / EnvironmentTests.py
1 #
2 # __COPYRIGHT__
3 #
4 # Permission is hereby granted, free of charge, to any person obtaining
5 # a copy of this software and associated documentation files (the
6 # "Software"), to deal in the Software without restriction, including
7 # without limitation the rights to use, copy, modify, merge, publish,
8 # distribute, sublicense, and/or sell copies of the Software, and to
9 # permit persons to whom the Software is furnished to do so, subject to
10 # the following conditions:
11 #
12 # The above copyright notice and this permission notice shall be included
13 # in all copies or substantial portions of the Software.
14 #
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
16 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
17 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 #
23
24 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
25
26 import copy
27 import os
28 import string
29 import StringIO
30 import sys
31 import TestCmd
32 import unittest
33 import UserList
34
35 from SCons.Environment import *
36 import SCons.Warnings
37
38 def diff_env(env1, env2):
39     s1 = "env1 = {\n"
40     s2 = "env2 = {\n"
41     d = {}
42     for k in env1._dict.keys() + env2._dict.keys():
43         d[k] = None
44     keys = d.keys()
45     keys.sort()
46     for k in keys:
47         if env1.has_key(k):
48            if env2.has_key(k):
49                if env1[k] != env2[k]:
50                    s1 = s1 + "    " + repr(k) + " : " + repr(env1[k]) + "\n"
51                    s2 = s2 + "    " + repr(k) + " : " + repr(env2[k]) + "\n"
52            else:
53                s1 = s1 + "    " + repr(k) + " : " + repr(env1[k]) + "\n"
54         elif env2.has_key(k):
55            s2 = s2 + "    " + repr(k) + " : " + repr(env2[k]) + "\n"
56     s1 = s1 + "}\n"
57     s2 = s2 + "}\n"
58     return s1 + s2
59
60 def diff_dict(d1, d2):
61     s1 = "d1 = {\n"
62     s2 = "d2 = {\n"
63     d = {}
64     for k in d1.keys() + d2.keys():
65         d[k] = None
66     keys = d.keys()
67     keys.sort()
68     for k in keys:
69         if d1.has_key(k):
70            if d2.has_key(k):
71                if d1[k] != d2[k]:
72                    s1 = s1 + "    " + repr(k) + " : " + repr(d1[k]) + "\n"
73                    s2 = s2 + "    " + repr(k) + " : " + repr(d2[k]) + "\n"
74            else:
75                s1 = s1 + "    " + repr(k) + " : " + repr(d1[k]) + "\n"
76         elif env2.has_key(k):
77            s2 = s2 + "    " + repr(k) + " : " + repr(d2[k]) + "\n"
78     s1 = s1 + "}\n"
79     s2 = s2 + "}\n"
80     return s1 + s2
81
82 called_it = {}
83 built_it = {}
84
85 class Builder:
86     """A dummy Builder class for testing purposes.  "Building"
87     a target is simply setting a value in the dictionary.
88     """
89     def __init__(self, name = None):
90         self.name = name
91
92     def __call__(self, env, target=None, source=None, **kw):
93         global called_it
94         called_it['target'] = target
95         called_it['source'] = source
96         called_it.update(kw)
97
98     def execute(self, target = None, **kw):
99         global built_it
100         built_it[target] = 1
101
102
103
104 scanned_it = {}
105
106 class Scanner:
107     """A dummy Scanner class for testing purposes.  "Scanning"
108     a target is simply setting a value in the dictionary.
109     """
110     def __init__(self, name, skeys=[]):
111         self.name = name
112         self.skeys = skeys
113
114     def __call__(self, filename):
115         global scanned_it
116         scanned_it[filename] = 1
117
118     def __cmp__(self, other):
119         try:
120             return cmp(self.__dict__, other.__dict__)
121         except AttributeError:
122             return 1
123
124     def get_skeys(self, env):
125         return self.skeys
126
127     def __str__(self):
128         return self.name
129
130
131
132 class CLVar(UserList.UserList):
133     def __init__(self, seq):
134         if type(seq) == type(''):
135             seq = string.split(seq)
136         UserList.UserList.__init__(self, seq)
137     def __add__(self, other):
138         return UserList.UserList.__add__(self, CLVar(other))
139     def __radd__(self, other):
140         return UserList.UserList.__radd__(self, CLVar(other))
141     def __coerce__(self, other):
142         return (self, CLVar(other))
143
144
145
146 class DummyNode:
147     def __init__(self, name):
148         self.name = name
149     def __str__(self):
150         return self.name
151     def rfile(self):
152         return self
153     def get_subst_proxy(self):
154         return self
155
156 def test_tool( env ):
157     env['_F77INCFLAGS'] = '$( ${_concat(INCPREFIX, F77PATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)'
158
159 class TestEnvironmentFixture:
160     def TestEnvironment(self, *args, **kw):
161         if not kw or not kw.has_key('tools'):
162             kw['tools'] = [test_tool]
163         default_keys = { 'CC' : 'cc',
164                          'CCFLAGS' : '-DNDEBUG',
165                          'ENV' : { 'TMP' : '/tmp' } }
166         for key, value in default_keys.items():
167             if not kw.has_key(key):
168                 kw[key] = value
169         if not kw.has_key('BUILDERS'):
170             static_obj = SCons.Builder.Builder(action = {},
171                                                emitter = {},
172                                                suffix = '.o',
173                                                single_source = 1)
174             kw['BUILDERS'] = {'Object' : static_obj}
175             static_obj.add_action('.cpp', 'fake action')
176             
177         env = apply(Environment, args, kw)
178         return env
179
180 class SubstitutionTestCase(unittest.TestCase):
181
182     def test___init__(self):
183         """Test initializing a SubstitutionEnvironment
184         """
185         env = SubstitutionEnvironment()
186         assert not env.has_key('__env__')
187
188     def test___cmp__(self):
189         """Test comparing SubstitutionEnvironments
190         """
191
192         env1 = SubstitutionEnvironment(XXX = 'x')
193         env2 = SubstitutionEnvironment(XXX = 'x')
194         env3 = SubstitutionEnvironment(XXX = 'xxx')
195         env4 = SubstitutionEnvironment(XXX = 'x', YYY = 'x')
196
197         assert env1 == env2
198         assert env1 != env3
199         assert env1 != env4
200
201     def test___delitem__(self):
202         """Test deleting a variable from a SubstitutionEnvironment
203         """
204         env1 = SubstitutionEnvironment(XXX = 'x', YYY = 'y')
205         env2 = SubstitutionEnvironment(XXX = 'x')
206         del env1['YYY']
207         assert env1 == env2
208
209     def test___getitem__(self):
210         """Test fetching a variable from a SubstitutionEnvironment
211         """
212         env = SubstitutionEnvironment(XXX = 'x')
213         assert env['XXX'] == 'x', env['XXX']
214
215     def test___setitem__(self):
216         """Test setting a variable in a SubstitutionEnvironment
217         """
218         env1 = SubstitutionEnvironment(XXX = 'x')
219         env2 = SubstitutionEnvironment(XXX = 'x', YYY = 'y')
220         env1['YYY'] = 'y'
221         assert env1 == env2
222
223     def test_get(self):
224         """Test the SubstitutionEnvironment get() method
225         """
226         env = SubstitutionEnvironment(XXX = 'x')
227         assert env.get('XXX') == 'x', env.get('XXX')
228         assert env.get('YYY') is None, env.get('YYY')
229
230     def test_has_key(self):
231         """Test the SubstitutionEnvironment has_key() method
232         """
233         env = SubstitutionEnvironment(XXX = 'x')
234         assert env.has_key('XXX')
235         assert not env.has_key('YYY')
236
237     def test_contains(self):
238         """Test the SubstitutionEnvironment __contains__() method
239         """
240         try:
241             'x' in {'x':1}
242         except TypeError:
243             # TODO(1.5)
244             # An early version of Python that doesn't support "in"
245             # on dictionaries.  Just pass the test.
246             pass
247         else:
248             env = SubstitutionEnvironment(XXX = 'x')
249             assert 'XXX' in env
250             assert not 'YYY' in env
251
252     def test_items(self):
253         """Test the SubstitutionEnvironment items() method
254         """
255         env = SubstitutionEnvironment(XXX = 'x', YYY = 'y')
256         items = env.items()
257         assert items == [('XXX','x'), ('YYY','y')], items
258
259     def test_arg2nodes(self):
260         """Test the arg2nodes method
261         """
262         env = SubstitutionEnvironment()
263         dict = {}
264         class X(SCons.Node.Node):
265             pass
266         def Factory(name, directory = None, create = 1, dict=dict, X=X):
267             if not dict.has_key(name):
268                 dict[name] = X()
269                 dict[name].name = name
270             return dict[name]
271
272         nodes = env.arg2nodes("Util.py UtilTests.py", Factory)
273         assert len(nodes) == 1, nodes
274         assert isinstance(nodes[0], X)
275         assert nodes[0].name == "Util.py UtilTests.py"
276
277         import types
278         if hasattr(types, 'UnicodeType'):
279             code = """if 1:
280                 nodes = env.arg2nodes(u"Util.py UtilTests.py", Factory)
281                 assert len(nodes) == 1, nodes
282                 assert isinstance(nodes[0], X)
283                 assert nodes[0].name == u"Util.py UtilTests.py"
284                 \n"""
285             exec code in globals(), locals()
286
287         nodes = env.arg2nodes(["Util.py", "UtilTests.py"], Factory)
288         assert len(nodes) == 2, nodes
289         assert isinstance(nodes[0], X)
290         assert isinstance(nodes[1], X)
291         assert nodes[0].name == "Util.py"
292         assert nodes[1].name == "UtilTests.py"
293
294         n1 = Factory("Util.py")
295         nodes = env.arg2nodes([n1, "UtilTests.py"], Factory)
296         assert len(nodes) == 2, nodes
297         assert isinstance(nodes[0], X)
298         assert isinstance(nodes[1], X)
299         assert nodes[0].name == "Util.py"
300         assert nodes[1].name == "UtilTests.py"
301
302         class SConsNode(SCons.Node.Node):
303             pass
304         nodes = env.arg2nodes(SConsNode())
305         assert len(nodes) == 1, nodes
306         assert isinstance(nodes[0], SConsNode), node
307
308         class OtherNode:
309             pass
310         nodes = env.arg2nodes(OtherNode())
311         assert len(nodes) == 1, nodes
312         assert isinstance(nodes[0], OtherNode), node
313
314         def lookup_a(str, F=Factory):
315             if str[0] == 'a':
316                 n = F(str)
317                 n.a = 1
318                 return n
319             else:
320                 return None
321
322         def lookup_b(str, F=Factory):
323             if str[0] == 'b':
324                 n = F(str)
325                 n.b = 1
326                 return n
327             else:
328                 return None
329
330         env_ll = SubstitutionEnvironment()
331         env_ll.lookup_list = [lookup_a, lookup_b]
332
333         nodes = env_ll.arg2nodes(['aaa', 'bbb', 'ccc'], Factory)
334         assert len(nodes) == 3, nodes
335
336         assert nodes[0].name == 'aaa', nodes[0]
337         assert nodes[0].a == 1, nodes[0]
338         assert not hasattr(nodes[0], 'b'), nodes[0]
339
340         assert nodes[1].name == 'bbb'
341         assert not hasattr(nodes[1], 'a'), nodes[1]
342         assert nodes[1].b == 1, nodes[1]
343
344         assert nodes[2].name == 'ccc'
345         assert not hasattr(nodes[2], 'a'), nodes[1]
346         assert not hasattr(nodes[2], 'b'), nodes[1]
347
348         def lookup_bbbb(str, F=Factory):
349             if str == 'bbbb':
350                 n = F(str)
351                 n.bbbb = 1
352                 return n
353             else:
354                 return None
355
356         def lookup_c(str, F=Factory):
357             if str[0] == 'c':
358                 n = F(str)
359                 n.c = 1
360                 return n
361             else:
362                 return None
363
364         nodes = env.arg2nodes(['bbbb', 'ccc'], Factory,
365                                      [lookup_c, lookup_bbbb, lookup_b])
366         assert len(nodes) == 2, nodes
367
368         assert nodes[0].name == 'bbbb'
369         assert not hasattr(nodes[0], 'a'), nodes[1]
370         assert not hasattr(nodes[0], 'b'), nodes[1]
371         assert nodes[0].bbbb == 1, nodes[1]
372         assert not hasattr(nodes[0], 'c'), nodes[0]
373
374         assert nodes[1].name == 'ccc'
375         assert not hasattr(nodes[1], 'a'), nodes[1]
376         assert not hasattr(nodes[1], 'b'), nodes[1]
377         assert not hasattr(nodes[1], 'bbbb'), nodes[0]
378         assert nodes[1].c == 1, nodes[1]
379
380     def test_arg2nodes_target_source(self):
381         """Test the arg2nodes method with target= and source= keywords
382         """
383         targets = [DummyNode('t1'), DummyNode('t2')]
384         sources = [DummyNode('s1'), DummyNode('s2')]
385         env = SubstitutionEnvironment()
386         nodes = env.arg2nodes(['${TARGET}-a',
387                                '${SOURCE}-b',
388                                '${TARGETS[1]}-c',
389                                '${SOURCES[1]}-d'],
390                               DummyNode,
391                               target=targets,
392                               source=sources)
393         names = map(lambda n: n.name, nodes)
394         assert names == ['t1-a', 's1-b', 't2-c', 's2-d'], names
395
396     def test_gvars(self):
397         """Test the base class gvars() method"""
398         env = SubstitutionEnvironment()
399         gvars = env.gvars()
400         assert gvars == {}, gvars
401
402     def test_lvars(self):
403         """Test the base class lvars() method"""
404         env = SubstitutionEnvironment()
405         lvars = env.lvars()
406         assert lvars == {}, lvars
407
408     def test_subst(self):
409         """Test substituting construction variables within strings
410
411         Check various combinations, including recursive expansion
412         of variables into other variables.
413         """
414         env = SubstitutionEnvironment(AAA = 'a', BBB = 'b')
415         mystr = env.subst("$AAA ${AAA}A $BBBB $BBB")
416         assert mystr == "a aA b", mystr
417
418         # Changed the tests below to reflect a bug fix in
419         # subst()
420         env = SubstitutionEnvironment(AAA = '$BBB', BBB = 'b', BBBA = 'foo')
421         mystr = env.subst("$AAA ${AAA}A ${AAA}B $BBB")
422         assert mystr == "b bA bB b", mystr
423
424         env = SubstitutionEnvironment(AAA = '$BBB', BBB = '$CCC', CCC = 'c')
425         mystr = env.subst("$AAA ${AAA}A ${AAA}B $BBB")
426         assert mystr == "c cA cB c", mystr
427
428         # Lists:
429         env = SubstitutionEnvironment(AAA = ['a', 'aa', 'aaa'])
430         mystr = env.subst("$AAA")
431         assert mystr == "a aa aaa", mystr
432
433         # Tuples:
434         env = SubstitutionEnvironment(AAA = ('a', 'aa', 'aaa'))
435         mystr = env.subst("$AAA")
436         assert mystr == "a aa aaa", mystr
437
438         t1 = DummyNode('t1')
439         t2 = DummyNode('t2')
440         s1 = DummyNode('s1')
441         s2 = DummyNode('s2')
442
443         env = SubstitutionEnvironment(AAA = 'aaa')
444         s = env.subst('$AAA $TARGET $SOURCES', target=[t1, t2], source=[s1, s2])
445         assert s == "aaa t1 s1 s2", s
446         s = env.subst('$AAA $TARGETS $SOURCE', target=[t1, t2], source=[s1, s2])
447         assert s == "aaa t1 t2 s1", s
448
449         # Test callables in the SubstitutionEnvironment
450         def foo(target, source, env, for_signature):
451             assert str(target) == 't', target
452             assert str(source) == 's', source
453             return env["FOO"]
454
455         env = SubstitutionEnvironment(BAR=foo, FOO='baz')
456         t = DummyNode('t')
457         s = DummyNode('s')
458
459         subst = env.subst('test $BAR', target=t, source=s)
460         assert subst == 'test baz', subst
461
462         # Test not calling callables in the SubstitutionEnvironment
463         if 0:
464             # This will take some serious surgery to subst() and
465             # subst_list(), so just leave these tests out until we can
466             # do that.
467             def bar(arg):
468                 pass
469
470             env = SubstitutionEnvironment(BAR=bar, FOO='$BAR')
471
472             subst = env.subst('$BAR', call=None)
473             assert subst is bar, subst
474
475             subst = env.subst('$FOO', call=None)
476             assert subst is bar, subst
477
478     def test_subst_kw(self):
479         """Test substituting construction variables within dictionaries"""
480         env = SubstitutionEnvironment(AAA = 'a', BBB = 'b')
481         kw = env.subst_kw({'$AAA' : 'aaa', 'bbb' : '$BBB'})
482         assert len(kw) == 2, kw
483         assert kw['a'] == 'aaa', kw['a']
484         assert kw['bbb'] == 'b', kw['bbb']
485
486     def test_subst_list(self):
487         """Test substituting construction variables in command lists
488         """
489         env = SubstitutionEnvironment(AAA = 'a', BBB = 'b')
490         l = env.subst_list("$AAA ${AAA}A $BBBB $BBB")
491         assert l == [["a", "aA", "b"]], l
492
493         # Changed the tests below to reflect a bug fix in
494         # subst()
495         env = SubstitutionEnvironment(AAA = '$BBB', BBB = 'b', BBBA = 'foo')
496         l = env.subst_list("$AAA ${AAA}A ${AAA}B $BBB")
497         assert l == [["b", "bA", "bB", "b"]], l
498
499         env = SubstitutionEnvironment(AAA = '$BBB', BBB = '$CCC', CCC = 'c')
500         l = env.subst_list("$AAA ${AAA}A ${AAA}B $BBB")
501         assert l == [["c", "cA", "cB", "c"]], mystr
502
503         env = SubstitutionEnvironment(AAA = '$BBB', BBB = '$CCC', CCC = [ 'a', 'b\nc' ])
504         lst = env.subst_list([ "$AAA", "B $CCC" ])
505         assert lst == [[ "a", "b"], ["c", "B a", "b"], ["c"]], lst
506
507         t1 = DummyNode('t1')
508         t2 = DummyNode('t2')
509         s1 = DummyNode('s1')
510         s2 = DummyNode('s2')
511
512         env = SubstitutionEnvironment(AAA = 'aaa')
513         s = env.subst_list('$AAA $TARGET $SOURCES', target=[t1, t2], source=[s1, s2])
514         assert s == [["aaa", "t1", "s1", "s2"]], s
515         s = env.subst_list('$AAA $TARGETS $SOURCE', target=[t1, t2], source=[s1, s2])
516         assert s == [["aaa", "t1", "t2", "s1"]], s
517
518         # Test callables in the SubstitutionEnvironment
519         def foo(target, source, env, for_signature):
520             assert str(target) == 't', target
521             assert str(source) == 's', source
522             return env["FOO"]
523
524         env = SubstitutionEnvironment(BAR=foo, FOO='baz')
525         t = DummyNode('t')
526         s = DummyNode('s')
527
528         lst = env.subst_list('test $BAR', target=t, source=s)
529         assert lst == [['test', 'baz']], lst
530
531         # Test not calling callables in the SubstitutionEnvironment
532         if 0:
533             # This will take some serious surgery to subst() and
534             # subst_list(), so just leave these tests out until we can
535             # do that.
536             def bar(arg):
537                 pass
538
539             env = SubstitutionEnvironment(BAR=bar, FOO='$BAR')
540
541             subst = env.subst_list('$BAR', call=None)
542             assert subst is bar, subst
543
544             subst = env.subst_list('$FOO', call=None)
545             assert subst is bar, subst
546
547     def test_subst_path(self):
548         """Test substituting a path list
549         """
550         class MyProxy:
551             def __init__(self, val):
552                 self.val = val
553             def get(self):
554                 return self.val + '-proxy'
555
556         class MyNode:
557             def __init__(self, val):
558                 self.val = val
559             def get_subst_proxy(self):
560                 return self
561             def __str__(self):
562                 return self.val
563
564         class MyObj:
565             def get(self):
566                 return self
567
568         env = SubstitutionEnvironment(FOO='foo',
569                                       BAR='bar',
570                                       LIST=['one', 'two'],
571                                       PROXY=MyProxy('my1'))
572
573         r = env.subst_path('$FOO')
574         assert r == ['foo'], r
575
576         r = env.subst_path(['$FOO', 'xxx', '$BAR'])
577         assert r == ['foo', 'xxx', 'bar'], r
578
579         r = env.subst_path(['$FOO', '$LIST', '$BAR'])
580         assert map(str, r) == ['foo', 'one two', 'bar'], r
581
582         r = env.subst_path(['$FOO', '$TARGET', '$SOURCE', '$BAR'])
583         assert r == ['foo', '', '', 'bar'], r
584
585         r = env.subst_path(['$FOO', '$TARGET', '$BAR'], target=MyNode('ttt'))
586         assert map(str, r) == ['foo', 'ttt', 'bar'], r
587
588         r = env.subst_path(['$FOO', '$SOURCE', '$BAR'], source=MyNode('sss'))
589         assert map(str, r) == ['foo', 'sss', 'bar'], r
590
591         n = MyObj()
592
593         r = env.subst_path(['$PROXY', MyProxy('my2'), n])
594         assert r == ['my1-proxy', 'my2-proxy', n], r
595
596         class StringableObj:
597             def __init__(self, s):
598                 self.s = s
599             def __str__(self):
600                 return self.s
601
602         env = SubstitutionEnvironment(FOO=StringableObj("foo"),
603                           BAR=StringableObj("bar"))
604
605         r = env.subst_path([ "${FOO}/bar", "${BAR}/baz" ])
606         assert r == [ "foo/bar", "bar/baz" ], r
607
608         r = env.subst_path([ "bar/${FOO}", "baz/${BAR}" ])
609         assert r == [ "bar/foo", "baz/bar" ], r
610
611         r = env.subst_path([ "bar/${FOO}/bar", "baz/${BAR}/baz" ])
612         assert r == [ "bar/foo/bar", "baz/bar/baz" ], r
613
614     def test_subst_target_source(self):
615         """Test the base environment subst_target_source() method"""
616         env = SubstitutionEnvironment(AAA = 'a', BBB = 'b')
617         mystr = env.subst_target_source("$AAA ${AAA}A $BBBB $BBB")
618         assert mystr == "a aA b", mystr
619
620     def test_backtick(self):
621         """Test the backtick() method for capturing command output"""
622         env = SubstitutionEnvironment()
623
624         test = TestCmd.TestCmd(workdir = '')
625         test.write('stdout.py', """\
626 import sys
627 sys.stdout.write('this came from stdout.py\\n')
628 sys.exit(0)
629 """)
630         test.write('stderr.py', """\
631 import sys
632 sys.stderr.write('this came from stderr.py\\n')
633 sys.exit(0)
634 """)
635         test.write('fail.py', """\
636 import sys
637 sys.exit(1)
638 """)
639         test.write('echo.py', """\
640 import os, sys
641 sys.stdout.write(os.environ['ECHO'] + '\\n')
642 sys.exit(0)
643 """)
644
645         save_stderr = sys.stderr
646
647         python = '"' + sys.executable + '"'
648
649         try:
650             sys.stderr = StringIO.StringIO()
651             cmd = '%s %s' % (python, test.workpath('stdout.py'))
652             output = env.backtick(cmd)
653             errout = sys.stderr.getvalue()
654             assert output == 'this came from stdout.py\n', output
655             assert errout == '', errout
656
657             sys.stderr = StringIO.StringIO()
658             cmd = '%s %s' % (python, test.workpath('stderr.py'))
659             output = env.backtick(cmd)
660             errout = sys.stderr.getvalue()
661             assert output == '', output
662             assert errout == 'this came from stderr.py\n', errout
663
664             sys.stderr = StringIO.StringIO()
665             cmd = '%s %s' % (python, test.workpath('fail.py'))
666             try:
667                 env.backtick(cmd)
668             except OSError, e:
669                 assert str(e) == "'%s' exited 1" % cmd, str(e)
670             else:
671                 self.fail("did not catch expected OSError")
672
673             sys.stderr = StringIO.StringIO()
674             cmd = '%s %s' % (python, test.workpath('echo.py'))
675             env['ENV'] = os.environ.copy()
676             env['ENV']['ECHO'] = 'this came from ECHO'
677             output = env.backtick(cmd)
678             errout = sys.stderr.getvalue()
679             assert output == 'this came from ECHO\n', output
680             assert errout == '', errout
681
682         finally:
683             sys.stderr = save_stderr
684
685     def test_AddMethod(self):
686         """Test the AddMethod() method"""
687         env = SubstitutionEnvironment(FOO = 'foo')
688
689         def func(self):
690             return 'func-' + self['FOO']
691
692         assert not hasattr(env, 'func')
693         env.AddMethod(func)
694         r = env.func()
695         assert r == 'func-foo', r
696
697         assert not hasattr(env, 'bar')
698         env.AddMethod(func, 'bar')
699         r = env.bar()
700         assert r == 'func-foo', r
701
702         def func2(self, arg=''):
703             return 'func2-' + self['FOO'] + arg
704
705         env.AddMethod(func2)
706         r = env.func2()
707         assert r == 'func2-foo', r
708         r = env.func2('-xxx')
709         assert r == 'func2-foo-xxx', r
710
711         env.AddMethod(func2, 'func')
712         r = env.func()
713         assert r == 'func2-foo', r
714         r = env.func('-yyy')
715         assert r == 'func2-foo-yyy', r
716
717         # Test that clones of clones correctly re-bind added methods.
718         env1 = Environment(FOO = '1')
719         env1.AddMethod(func2)
720         env2 = env1.Clone(FOO = '2')
721         env3 = env2.Clone(FOO = '3')
722         env4 = env3.Clone(FOO = '4')
723         r = env1.func2()
724         assert r == 'func2-1', r
725         r = env2.func2()
726         assert r == 'func2-2', r
727         r = env3.func2()
728         assert r == 'func2-3', r
729         r = env4.func2()
730         assert r == 'func2-4', r
731
732         # Test that clones don't re-bind an attribute that the user
733         env1 = Environment(FOO = '1')
734         env1.AddMethod(func2)
735         def replace_func2():
736             return 'replace_func2'
737         env1.func2 = replace_func2
738         env2 = env1.Clone(FOO = '2')
739         r = env2.func2()
740         assert r == 'replace_func2', r
741
742     def test_Override(self):
743         "Test overriding construction variables"
744         env = SubstitutionEnvironment(ONE=1, TWO=2, THREE=3, FOUR=4)
745         assert env['ONE'] == 1, env['ONE']
746         assert env['TWO'] == 2, env['TWO']
747         assert env['THREE'] == 3, env['THREE']
748         assert env['FOUR'] == 4, env['FOUR']
749
750         env2 = env.Override({'TWO'   : '10',
751                              'THREE' :'x $THREE y',
752                              'FOUR'  : ['x', '$FOUR', 'y']})
753         assert env2['ONE'] == 1, env2['ONE']
754         assert env2['TWO'] == '10', env2['TWO']
755         assert env2['THREE'] == 'x 3 y', env2['THREE']
756         assert env2['FOUR'] == ['x', 4, 'y'], env2['FOUR']
757
758         assert env['ONE'] == 1, env['ONE']
759         assert env['TWO'] == 2, env['TWO']
760         assert env['THREE'] == 3, env['THREE']
761         assert env['FOUR'] == 4, env['FOUR']
762
763         env2.Replace(ONE = "won")
764         assert env2['ONE'] == "won", env2['ONE']
765         assert env['ONE'] == 1, env['ONE']
766
767     def test_ParseFlags(self):
768         """Test the ParseFlags() method
769         """
770         env = SubstitutionEnvironment()
771
772         empty = {
773             'ASFLAGS'       : [],
774             'CFLAGS'        : [],
775             'CCFLAGS'       : [],
776             'CPPDEFINES'    : [],
777             'CPPFLAGS'      : [],
778             'CPPPATH'       : [],
779             'FRAMEWORKPATH' : [],
780             'FRAMEWORKS'    : [],
781             'LIBPATH'       : [],
782             'LIBS'          : [],
783             'LINKFLAGS'     : [],
784             'RPATH'         : [],
785         }
786
787         d = env.ParseFlags(None)
788         assert d == empty, d
789
790         d = env.ParseFlags('')
791         assert d == empty, d
792
793         d = env.ParseFlags([])
794         assert d == empty, d
795
796         s = "-I/usr/include/fum -I bar -X\n" + \
797             '-I"C:\\Program Files\\ASCEND\\include" ' + \
798             "-L/usr/fax -L foo -lxxx -l yyy " + \
799             '-L"C:\\Program Files\\ASCEND" -lascend ' + \
800             "-Wa,-as -Wl,-link " + \
801             "-Wl,-rpath=rpath1 " + \
802             "-Wl,-R,rpath2 " + \
803             "-Wl,-Rrpath3 " + \
804             "-Wp,-cpp " + \
805             "-std=c99 " + \
806             "-framework Carbon " + \
807             "-frameworkdir=fwd1 " + \
808             "-Ffwd2 " + \
809             "-F fwd3 " + \
810             "-pthread " + \
811             "-mno-cygwin -mwindows " + \
812             "-arch i386 -isysroot /tmp +DD64 " + \
813             "-DFOO -DBAR=value -D BAZ "
814
815         d = env.ParseFlags(s)
816
817         assert d['ASFLAGS'] == ['-as'], d['ASFLAGS']
818         assert d['CFLAGS']  == ['-std=c99']
819         assert d['CCFLAGS'] == ['-X', '-Wa,-as',
820                                   '-pthread', '-mno-cygwin',
821                                   ('-arch', 'i386'), ('-isysroot', '/tmp'),
822                                   '+DD64'], d['CCFLAGS']
823         assert d['CPPDEFINES'] == ['FOO', ['BAR', 'value'], 'BAZ'], d['CPPDEFINES']
824         assert d['CPPFLAGS'] == ['-Wp,-cpp'], d['CPPFLAGS']
825         assert d['CPPPATH'] == ['/usr/include/fum',
826                                 'bar',
827                                 'C:\\Program Files\\ASCEND\\include'], d['CPPPATH']
828         assert d['FRAMEWORKPATH'] == ['fwd1', 'fwd2', 'fwd3'], d['FRAMEWORKPATH']
829         assert d['FRAMEWORKS'] == ['Carbon'], d['FRAMEWORKS']
830         assert d['LIBPATH'] == ['/usr/fax',
831                                 'foo',
832                                 'C:\\Program Files\\ASCEND'], d['LIBPATH']
833         LIBS = map(str, d['LIBS'])
834         assert LIBS == ['xxx', 'yyy', 'ascend'], (d['LIBS'], LIBS)
835         assert d['LINKFLAGS'] == ['-Wl,-link', '-pthread',
836                                   '-mno-cygwin', '-mwindows',
837                                   ('-arch', 'i386'),
838                                   ('-isysroot', '/tmp'),
839                                   '+DD64'], d['LINKFLAGS']
840         assert d['RPATH'] == ['rpath1', 'rpath2', 'rpath3'], d['RPATH']
841
842
843     def test_MergeFlags(self):
844         """Test the MergeFlags() method
845         """
846         env = SubstitutionEnvironment()
847         env.MergeFlags('')
848         assert not env.has_key('CCFLAGS'), env['CCFLAGS']
849         env.MergeFlags('-X')
850         assert env['CCFLAGS'] == ['-X'], env['CCFLAGS']
851         env.MergeFlags('-X')
852         assert env['CCFLAGS'] == ['-X'], env['CCFLAGS']
853
854         env = SubstitutionEnvironment(CCFLAGS=None)
855         env.MergeFlags('-Y')
856         assert env['CCFLAGS'] == ['-Y'], env['CCFLAGS']
857
858         env = SubstitutionEnvironment()
859         env.MergeFlags({'A':['aaa'], 'B':['bbb']})
860         assert env['A'] == ['aaa'], env['A']
861         assert env['B'] == ['bbb'], env['B']
862
863 #     def test_MergeShellPaths(self):
864 #         """Test the MergeShellPaths() method
865 #         """
866 #         env = Environment()
867 #         env.MergeShellPaths({})
868 #         assert not env['ENV'].has_key('INCLUDE'), env['INCLUDE']
869 #         env.MergeShellPaths({'INCLUDE': r'c:\Program Files\Stuff'})
870 #         assert env['ENV']['INCLUDE'] == r'c:\Program Files\Stuff', env['ENV']['INCLUDE']
871 #         env.MergeShellPaths({'INCLUDE': r'c:\Program Files\Stuff'})
872 #         assert env['ENV']['INCLUDE'] == r'c:\Program Files\Stuff', env['ENV']['INCLUDE']
873 #         env.MergeShellPaths({'INCLUDE': r'xyz'})
874 #         assert env['ENV']['INCLUDE'] == r'xyz%sc:\Program Files\Stuff'%os.pathsep, env['ENV']['INCLUDE']
875
876 #         env = Environment()
877 #         env['ENV']['INCLUDE'] = 'xyz'
878 #         env.MergeShellPaths({'INCLUDE':['c:/inc1', 'c:/inc2']} )
879 #         assert env['ENV']['INCLUDE'] == r'c:/inc1%sc:/inc2%sxyz'%(os.pathsep, os.pathsep), env['ENV']['INCLUDE']
880
881 #         # test prepend=0
882 #         env = Environment()
883 #         env.MergeShellPaths({'INCLUDE': r'c:\Program Files\Stuff'}, prepend=0)
884 #         assert env['ENV']['INCLUDE'] == r'c:\Program Files\Stuff', env['ENV']['INCLUDE']
885 #         env.MergeShellPaths({'INCLUDE': r'xyz'}, prepend=0)
886 #         assert env['ENV']['INCLUDE'] == r'c:\Program Files\Stuff%sxyz'%os.pathsep, env['ENV']['INCLUDE']
887
888
889 class BaseTestCase(unittest.TestCase,TestEnvironmentFixture):
890
891     reserved_variables = [
892         'CHANGED_SOURCES',
893         'CHANGED_TARGETS',
894         'SOURCE',
895         'SOURCES',
896         'TARGET',
897         'TARGETS',
898         'UNCHANGED_SOURCES',
899         'UNCHANGED_TARGETS',
900     ]
901
902     def test___init__(self):
903         """Test construction Environment creation
904
905         Create two with identical arguments and check that
906         they compare the same.
907         """
908         env1 = self.TestEnvironment(XXX = 'x', YYY = 'y')
909         env2 = self.TestEnvironment(XXX = 'x', YYY = 'y')
910         assert env1 == env2, diff_env(env1, env2)
911
912         assert not env1.has_key('__env__')
913         assert not env2.has_key('__env__')
914
915     def test_variables(self):
916         """Test that variables only get applied once."""
917         class FakeOptions:
918             def __init__(self, key, val):
919                 self.calls = 0
920                 self.key = key
921                 self.val = val
922             def keys(self):
923                 return [self.key]
924             def Update(self, env):
925                 env[self.key] = self.val
926                 self.calls = self.calls + 1
927
928         o = FakeOptions('AAA', 'fake_opt')
929         env = Environment(variables=o, AAA='keyword_arg')
930         assert o.calls == 1, o.calls
931         assert env['AAA'] == 'fake_opt', env['AAA']
932
933     def test_get(self):
934         """Test the get() method."""
935         env = self.TestEnvironment(aaa = 'AAA')
936
937         x = env.get('aaa')
938         assert x == 'AAA', x
939         x = env.get('aaa', 'XXX')
940         assert x == 'AAA', x
941         x = env.get('bbb')
942         assert x is None, x
943         x = env.get('bbb', 'XXX')
944         assert x == 'XXX', x
945
946     def test_Builder_calls(self):
947         """Test Builder calls through different environments
948         """
949         global called_it
950
951         b1 = Builder()
952         b2 = Builder()
953
954         env = Environment()
955         env.Replace(BUILDERS = { 'builder1' : b1,
956                                  'builder2' : b2 })
957         called_it = {}
958         env.builder1('in1')
959         assert called_it['target'] is None, called_it
960         assert called_it['source'] == ['in1'], called_it
961
962         called_it = {}
963         env.builder2(source = 'in2', xyzzy = 1)
964         assert called_it['target'] is None, called_it
965         assert called_it['source'] == ['in2'], called_it
966         assert called_it['xyzzy'] == 1, called_it
967
968         called_it = {}
969         env.builder1(foo = 'bar')
970         assert called_it['foo'] == 'bar', called_it
971         assert called_it['target'] is None, called_it
972         assert called_it['source'] is None, called_it
973
974     def test_BuilderWrapper_attributes(self):
975         """Test getting and setting of BuilderWrapper attributes
976         """
977         b1 = Builder()
978         b2 = Builder()
979         e1 = Environment()
980         e2 = Environment()
981
982         e1.Replace(BUILDERS = {'b' : b1})
983         bw = e1.b
984
985         assert bw.env is e1
986         bw.env = e2
987         assert bw.env is e2
988
989         assert bw.builder is b1
990         bw.builder = b2
991         assert bw.builder is b2
992
993         self.assertRaises(AttributeError, getattr, bw, 'foobar')
994         bw.foobar = 42
995         assert bw.foobar is 42
996
997     # This unit test is currently disabled because we don't think the
998     # underlying method it tests (Environment.BuilderWrapper.execute())
999     # is necessary, but we're leaving the code here for now in case
1000     # that's mistaken.
1001     def _DO_NOT_test_Builder_execs(self):
1002         """Test Builder execution through different environments
1003
1004         One environment is initialized with a single
1005         Builder object, one with a list of a single Builder
1006         object, and one with a list of two Builder objects.
1007         """
1008         global built_it
1009
1010         b1 = Builder()
1011         b2 = Builder()
1012
1013         built_it = {}
1014         env3 = Environment()
1015         env3.Replace(BUILDERS = { 'builder1' : b1,
1016                                   'builder2' : b2 })
1017         env3.builder1.execute(target = 'out1')
1018         env3.builder2.execute(target = 'out2')
1019         env3.builder1.execute(target = 'out3')
1020         assert built_it['out1']
1021         assert built_it['out2']
1022         assert built_it['out3']
1023
1024         env4 = env3.Clone()
1025         assert env4.builder1.env is env4, "builder1.env (%s) == env3 (%s)?" % (
1026 env4.builder1.env, env3)
1027         assert env4.builder2.env is env4, "builder2.env (%s) == env3 (%s)?" % (
1028 env4.builder1.env, env3)
1029
1030         # Now test BUILDERS as a dictionary.
1031         built_it = {}
1032         env5 = self.TestEnvironment(BUILDERS={ 'foo' : b1 })
1033         env5['BUILDERS']['bar'] = b2
1034         env5.foo.execute(target='out1')
1035         env5.bar.execute(target='out2')
1036         assert built_it['out1']
1037         assert built_it['out2']
1038
1039         built_it = {}
1040         env6 = Environment()
1041         env6['BUILDERS'] = { 'foo' : b1,
1042                              'bar' : b2 }
1043         env6.foo.execute(target='out1')
1044         env6.bar.execute(target='out2')
1045         assert built_it['out1']
1046         assert built_it['out2']
1047
1048
1049
1050     def test_Scanners(self):
1051         """Test setting SCANNERS in various ways
1052
1053         One environment is initialized with a single
1054         Scanner object, one with a list of a single Scanner
1055         object, and one with a list of two Scanner objects.
1056         """
1057         global scanned_it
1058
1059         s1 = Scanner(name = 'scanner1', skeys = [".c", ".cc"])
1060         s2 = Scanner(name = 'scanner2', skeys = [".m4"])
1061         s3 = Scanner(name = 'scanner3', skeys = [".m4", ".m5"])
1062         s4 = Scanner(name = 'scanner4', skeys = [None])
1063
1064 #        XXX Tests for scanner execution through different environments,
1065 #        XXX if we ever want to do that some day
1066 #        scanned_it = {}
1067 #        env1 = self.TestEnvironment(SCANNERS = s1)
1068 #        env1.scanner1(filename = 'out1')
1069 #        assert scanned_it['out1']
1070 #
1071 #        scanned_it = {}
1072 #        env2 = self.TestEnvironment(SCANNERS = [s1])
1073 #        env1.scanner1(filename = 'out1')
1074 #        assert scanned_it['out1']
1075 #
1076 #        scanned_it = {}
1077 #        env3 = Environment()
1078 #        env3.Replace(SCANNERS = [s1])
1079 #        env3.scanner1(filename = 'out1')
1080 #        env3.scanner2(filename = 'out2')
1081 #        env3.scanner1(filename = 'out3')
1082 #        assert scanned_it['out1']
1083 #        assert scanned_it['out2']
1084 #        assert scanned_it['out3']
1085
1086         suffixes = [".c", ".cc", ".cxx", ".m4", ".m5"]
1087
1088         env = Environment()
1089         try: del env['SCANNERS']
1090         except KeyError: pass
1091         s = map(env.get_scanner, suffixes)
1092         assert s == [None, None, None, None, None], s
1093
1094         env = self.TestEnvironment(SCANNERS = [])
1095         s = map(env.get_scanner, suffixes)
1096         assert s == [None, None, None, None, None], s
1097
1098         env.Replace(SCANNERS = [s1])
1099         s = map(env.get_scanner, suffixes)
1100         assert s == [s1, s1, None, None, None], s
1101
1102         env.Append(SCANNERS = [s2])
1103         s = map(env.get_scanner, suffixes)
1104         assert s == [s1, s1, None, s2, None], s
1105
1106         env.AppendUnique(SCANNERS = [s3])
1107         s = map(env.get_scanner, suffixes)
1108         assert s == [s1, s1, None, s2, s3], s
1109
1110         env = env.Clone(SCANNERS = [s2])
1111         s = map(env.get_scanner, suffixes)
1112         assert s == [None, None, None, s2, None], s
1113
1114         env['SCANNERS'] = [s1]
1115         s = map(env.get_scanner, suffixes)
1116         assert s == [s1, s1, None, None, None], s
1117
1118         env.PrependUnique(SCANNERS = [s2, s1])
1119         s = map(env.get_scanner, suffixes)
1120         assert s == [s1, s1, None, s2, None], s
1121
1122         env.Prepend(SCANNERS = [s3])
1123         s = map(env.get_scanner, suffixes)
1124         assert s == [s1, s1, None, s3, s3], s
1125
1126         # Verify behavior of case-insensitive suffix matches on Windows.
1127         uc_suffixes = map(string.upper, suffixes)
1128
1129         env = Environment(SCANNERS = [s1, s2, s3],
1130                           PLATFORM = 'linux')
1131
1132         s = map(env.get_scanner, suffixes)
1133         assert s == [s1, s1, None, s2, s3], s
1134
1135         s = map(env.get_scanner, uc_suffixes)
1136         assert s == [None, None, None, None, None], s
1137
1138         env['PLATFORM'] = 'win32'
1139
1140         s = map(env.get_scanner, uc_suffixes)
1141         assert s == [s1, s1, None, s2, s3], s
1142
1143         # Verify behavior for a scanner returning None (on Windows
1144         # where we might try to perform case manipulation on None).
1145         env.Replace(SCANNERS = [s4])
1146         s = map(env.get_scanner, suffixes)
1147         assert s == [None, None, None, None, None], s
1148
1149     def test_ENV(self):
1150         """Test setting the external ENV in Environments
1151         """
1152         env = Environment()
1153         assert env.Dictionary().has_key('ENV')
1154
1155         env = self.TestEnvironment(ENV = { 'PATH' : '/foo:/bar' })
1156         assert env.Dictionary('ENV')['PATH'] == '/foo:/bar'
1157
1158     def test_ReservedVariables(self):
1159         """Test warning generation when reserved variable names are set"""
1160
1161         reserved_variables = [
1162             'CHANGED_SOURCES',
1163             'CHANGED_TARGETS',
1164             'SOURCE',
1165             'SOURCES',
1166             'TARGET',
1167             'TARGETS',
1168             'UNCHANGED_SOURCES',
1169             'UNCHANGED_TARGETS',
1170         ]
1171
1172         warning = SCons.Warnings.ReservedVariableWarning
1173         SCons.Warnings.enableWarningClass(warning)
1174         old = SCons.Warnings.warningAsException(1)
1175
1176         try:
1177             env4 = Environment()
1178             for kw in self.reserved_variables:
1179                 exc_caught = None
1180                 try:
1181                     env4[kw] = 'xyzzy'
1182                 except warning:
1183                     exc_caught = 1
1184                 assert exc_caught, "Did not catch ReservedVariableWarning for `%s'" % kw
1185                 assert not env4.has_key(kw), "`%s' variable was incorrectly set" % kw
1186         finally:
1187             SCons.Warnings.warningAsException(old)
1188
1189     def test_FutureReservedVariables(self):
1190         """Test warning generation when future reserved variable names are set"""
1191
1192         future_reserved_variables = []
1193
1194         warning = SCons.Warnings.FutureReservedVariableWarning
1195         SCons.Warnings.enableWarningClass(warning)
1196         old = SCons.Warnings.warningAsException(1)
1197
1198         try:
1199             env4 = Environment()
1200             for kw in future_reserved_variables:
1201                 exc_caught = None
1202                 try:
1203                     env4[kw] = 'xyzzy'
1204                 except warning:
1205                     exc_caught = 1
1206                 assert exc_caught, "Did not catch FutureReservedVariableWarning for `%s'" % kw
1207                 assert env4.has_key(kw), "`%s' variable was not set" % kw
1208         finally:
1209             SCons.Warnings.warningAsException(old)
1210
1211     def test_IllegalVariables(self):
1212         """Test that use of illegal variables raises an exception"""
1213         env = Environment()
1214         def test_it(var, env=env):
1215             exc_caught = None
1216             try:
1217                 env[var] = 1
1218             except SCons.Errors.UserError:
1219                 exc_caught = 1
1220             assert exc_caught, "did not catch UserError for '%s'" % var
1221         env['aaa'] = 1
1222         assert env['aaa'] == 1, env['aaa']
1223         test_it('foo/bar')
1224         test_it('foo.bar')
1225         test_it('foo-bar')
1226
1227     def test_autogenerate(dict):
1228         """Test autogenerating variables in a dictionary."""
1229
1230         drive, p = os.path.splitdrive(os.getcwd())
1231         def normalize_path(path, drive=drive):
1232             if path[0] in '\\/':
1233                 path = drive + path
1234             path = os.path.normpath(path)
1235             drive, path = os.path.splitdrive(path)
1236             return string.lower(drive) + path
1237
1238         env = dict.TestEnvironment(LIBS = [ 'foo', 'bar', 'baz' ],
1239                           LIBLINKPREFIX = 'foo',
1240                           LIBLINKSUFFIX = 'bar')
1241
1242         def RDirs(pathlist, fs=env.fs):
1243             return fs.Dir('xx').Rfindalldirs(pathlist)
1244
1245         env['RDirs'] = RDirs
1246         flags = env.subst_list('$_LIBFLAGS', 1)[0]
1247         assert flags == ['foobar', 'foobar', 'foobazbar'], flags
1248
1249         blat = env.fs.Dir('blat')
1250
1251         env.Replace(CPPPATH = [ 'foo', '$FOO/bar', blat ],
1252                     INCPREFIX = 'foo ',
1253                     INCSUFFIX = 'bar',
1254                     FOO = 'baz')
1255         flags = env.subst_list('$_CPPINCFLAGS', 1)[0]
1256         expect = [ '$(',
1257                    normalize_path('foo'),
1258                    normalize_path('xx/foobar'),
1259                    normalize_path('foo'),
1260                    normalize_path('xx/baz/bar'),
1261                    normalize_path('foo'),
1262                    normalize_path('blatbar'),
1263                    '$)',
1264         ]
1265         assert flags == expect, flags
1266
1267         env.Replace(F77PATH = [ 'foo', '$FOO/bar', blat ],
1268                     INCPREFIX = 'foo ',
1269                     INCSUFFIX = 'bar',
1270                     FOO = 'baz')
1271         flags = env.subst_list('$_F77INCFLAGS', 1)[0]
1272         expect = [ '$(',
1273                    normalize_path('foo'),
1274                    normalize_path('xx/foobar'),
1275                    normalize_path('foo'),
1276                    normalize_path('xx/baz/bar'),
1277                    normalize_path('foo'),
1278                    normalize_path('blatbar'),
1279                    '$)',
1280         ]
1281         assert flags == expect, flags
1282
1283         env.Replace(CPPPATH = '', F77PATH = '', LIBPATH = '')
1284         l = env.subst_list('$_CPPINCFLAGS')
1285         assert l == [[]], l
1286         l = env.subst_list('$_F77INCFLAGS')
1287         assert l == [[]], l
1288         l = env.subst_list('$_LIBDIRFLAGS')
1289         assert l == [[]], l
1290
1291         env.fs.Repository('/rep1')
1292         env.fs.Repository('/rep2')
1293         env.Replace(CPPPATH = [ 'foo', '/a/b', '$FOO/bar', blat],
1294                     INCPREFIX = '-I ',
1295                     INCSUFFIX = 'XXX',
1296                     FOO = 'baz')
1297         flags = env.subst_list('$_CPPINCFLAGS', 1)[0]
1298         expect = [ '$(',
1299                    '-I', normalize_path('xx/fooXXX'),
1300                    '-I', normalize_path('/rep1/xx/fooXXX'),
1301                    '-I', normalize_path('/rep2/xx/fooXXX'),
1302                    '-I', normalize_path('/a/bXXX'),
1303                    '-I', normalize_path('xx/baz/barXXX'),
1304                    '-I', normalize_path('/rep1/xx/baz/barXXX'),
1305                    '-I', normalize_path('/rep2/xx/baz/barXXX'),
1306                    '-I', normalize_path('blatXXX'),
1307                    '$)'
1308         ]
1309         def normalize_if_path(arg, np=normalize_path):
1310             if arg not in ('$(','$)','-I'):
1311                 return np(str(arg))
1312             return arg
1313         flags = map(normalize_if_path, flags)
1314         assert flags == expect, flags
1315
1316     def test_platform(self):
1317         """Test specifying a platform callable when instantiating."""
1318         class platform:
1319             def __str__(self):        return "TestPlatform"
1320             def __call__(self, env):  env['XYZZY'] = 777
1321
1322         def tool(env):
1323             env['SET_TOOL'] = 'initialized'
1324             assert env['PLATFORM'] == "TestPlatform"
1325
1326         env = self.TestEnvironment(platform = platform(), tools = [tool])
1327         assert env['XYZZY'] == 777, env
1328         assert env['PLATFORM'] == "TestPlatform"
1329         assert env['SET_TOOL'] == "initialized"
1330
1331     def test_Default_PLATFORM(self):
1332         """Test overriding the default PLATFORM variable"""
1333         class platform:
1334             def __str__(self):        return "DefaultTestPlatform"
1335             def __call__(self, env):  env['XYZZY'] = 888
1336
1337         def tool(env):
1338             env['SET_TOOL'] = 'abcde'
1339             assert env['PLATFORM'] == "DefaultTestPlatform"
1340
1341         import SCons.Defaults
1342         save = SCons.Defaults.ConstructionEnvironment.copy()
1343         try:
1344             import SCons.Defaults
1345             SCons.Defaults.ConstructionEnvironment.update({
1346                 'PLATFORM' : platform(),
1347             })
1348             env = self.TestEnvironment(tools = [tool])
1349             assert env['XYZZY'] == 888, env
1350             assert env['PLATFORM'] == "DefaultTestPlatform"
1351             assert env['SET_TOOL'] == "abcde"
1352         finally:
1353             SCons.Defaults.ConstructionEnvironment = save
1354
1355     def test_tools(self):
1356         """Test specifying a tool callable when instantiating."""
1357         def t1(env):
1358             env['TOOL1'] = 111
1359         def t2(env):
1360             env['TOOL2'] = 222
1361         def t3(env):
1362             env['AAA'] = env['XYZ']
1363         def t4(env):
1364             env['TOOL4'] = 444
1365         env = self.TestEnvironment(tools = [t1, t2, t3], XYZ = 'aaa')
1366         assert env['TOOL1'] == 111, env['TOOL1']
1367         assert env['TOOL2'] == 222, env
1368         assert env['AAA'] == 'aaa', env
1369         t4(env)
1370         assert env['TOOL4'] == 444, env
1371
1372         test = TestCmd.TestCmd(workdir = '')
1373         test.write('faketool.py', """\
1374 def generate(env, **kw):
1375     for k, v in kw.items():
1376         env[k] = v
1377
1378 def exists(env):
1379     return 1
1380 """)
1381
1382         env = self.TestEnvironment(tools = [('faketool', {'a':1, 'b':2, 'c':3})],
1383                           toolpath = [test.workpath('')])
1384         assert env['a'] == 1, env['a']
1385         assert env['b'] == 2, env['b']
1386         assert env['c'] == 3, env['c']
1387
1388     def test_Default_TOOLS(self):
1389         """Test overriding the default TOOLS variable"""
1390         def t5(env):
1391             env['TOOL5'] = 555
1392         def t6(env):
1393             env['TOOL6'] = 666
1394         def t7(env):
1395             env['BBB'] = env['XYZ']
1396         def t8(env):
1397             env['TOOL8'] = 888
1398
1399         import SCons.Defaults
1400         save = SCons.Defaults.ConstructionEnvironment.copy()
1401         try:
1402             SCons.Defaults.ConstructionEnvironment.update({
1403                 'TOOLS' : [t5, t6, t7],
1404             })
1405             env = Environment(XYZ = 'bbb')
1406             assert env['TOOL5'] == 555, env['TOOL5']
1407             assert env['TOOL6'] == 666, env
1408             assert env['BBB'] == 'bbb', env
1409             t8(env)
1410             assert env['TOOL8'] == 888, env
1411         finally:
1412             SCons.Defaults.ConstructionEnvironment = save
1413
1414     def test_null_tools(self):
1415         """Test specifying a tool of None is OK."""
1416         def t1(env):
1417             env['TOOL1'] = 111
1418         def t2(env):
1419             env['TOOL2'] = 222
1420         env = self.TestEnvironment(tools = [t1, None, t2], XYZ = 'aaa')
1421         assert env['TOOL1'] == 111, env['TOOL1']
1422         assert env['TOOL2'] == 222, env
1423         assert env['XYZ'] == 'aaa', env
1424         env = self.TestEnvironment(tools = [None], XYZ = 'xyz')
1425         assert env['XYZ'] == 'xyz', env
1426         env = self.TestEnvironment(tools = [t1, '', t2], XYZ = 'ddd')
1427         assert env['TOOL1'] == 111, env['TOOL1']
1428         assert env['TOOL2'] == 222, env
1429         assert env['XYZ'] == 'ddd', env
1430
1431     def test_concat(self):
1432         "Test _concat()"
1433         e1 = self.TestEnvironment(PRE='pre', SUF='suf', STR='a b', LIST=['a', 'b'])
1434         s = e1.subst
1435         x = s("${_concat('', '', '', __env__)}")
1436         assert x == '', x
1437         x = s("${_concat('', [], '', __env__)}")
1438         assert x == '', x
1439         x = s("${_concat(PRE, '', SUF, __env__)}")
1440         assert x == '', x
1441         x = s("${_concat(PRE, STR, SUF, __env__)}")
1442         assert x == 'prea bsuf', x
1443         x = s("${_concat(PRE, LIST, SUF, __env__)}")
1444         assert x == 'preasuf prebsuf', x
1445
1446     def test_gvars(self):
1447         """Test the Environment gvars() method"""
1448         env = self.TestEnvironment(XXX = 'x', YYY = 'y', ZZZ = 'z')
1449         gvars = env.gvars()
1450         assert gvars['XXX'] == 'x', gvars['XXX']
1451         assert gvars['YYY'] == 'y', gvars['YYY']
1452         assert gvars['ZZZ'] == 'z', gvars['ZZZ']
1453
1454     def test__update(self):
1455         """Test the _update() method"""
1456         env = self.TestEnvironment(X = 'x', Y = 'y', Z = 'z')
1457         assert env['X'] == 'x', env['X']
1458         assert env['Y'] == 'y', env['Y']
1459         assert env['Z'] == 'z', env['Z']
1460         env._update({'X'       : 'xxx',
1461                      'TARGET'  : 't',
1462                      'TARGETS' : 'ttt',
1463                      'SOURCE'  : 's',
1464                      'SOURCES' : 'sss',
1465                      'Z'       : 'zzz'})
1466         assert env['X'] == 'xxx', env['X']
1467         assert env['Y'] == 'y', env['Y']
1468         assert env['Z'] == 'zzz', env['Z']
1469         assert env['TARGET'] == 't', env['TARGET']
1470         assert env['TARGETS'] == 'ttt', env['TARGETS']
1471         assert env['SOURCE'] == 's', env['SOURCE']
1472         assert env['SOURCES'] == 'sss', env['SOURCES']
1473
1474
1475
1476     def test_Append(self):
1477         """Test appending to construction variables in an Environment
1478         """
1479
1480         b1 = Environment()['BUILDERS']
1481         b2 = Environment()['BUILDERS']
1482         assert b1 == b2, diff_dict(b1, b2)
1483
1484         import UserDict
1485         UD = UserDict.UserDict
1486         import UserList
1487         UL = UserList.UserList
1488
1489         cases = [
1490             'a1',       'A1',           'a1A1',
1491             'a2',       ['A2'],         ['a2', 'A2'],
1492             'a3',       UL(['A3']),     UL(['a', '3', 'A3']),
1493             'a4',       '',             'a4',
1494             'a5',       [],             ['a5'],
1495             'a6',       UL([]),         UL(['a', '6']),
1496             'a7',       [''],           ['a7', ''],
1497             'a8',       UL(['']),       UL(['a', '8', '']),
1498
1499             ['e1'],     'E1',           ['e1', 'E1'],
1500             ['e2'],     ['E2'],         ['e2', 'E2'],
1501             ['e3'],     UL(['E3']),     UL(['e3', 'E3']),
1502             ['e4'],     '',             ['e4'],
1503             ['e5'],     [],             ['e5'],
1504             ['e6'],     UL([]),         UL(['e6']),
1505             ['e7'],     [''],           ['e7', ''],
1506             ['e8'],     UL(['']),       UL(['e8', '']),
1507
1508             UL(['i1']), 'I1',           UL(['i1', 'I', '1']),
1509             UL(['i2']), ['I2'],         UL(['i2', 'I2']),
1510             UL(['i3']), UL(['I3']),     UL(['i3', 'I3']),
1511             UL(['i4']), '',             UL(['i4']),
1512             UL(['i5']), [],             UL(['i5']),
1513             UL(['i6']), UL([]),         UL(['i6']),
1514             UL(['i7']), [''],           UL(['i7', '']),
1515             UL(['i8']), UL(['']),       UL(['i8', '']),
1516
1517             {'d1':1},   'D1',           {'d1':1, 'D1':None},
1518             {'d2':1},   ['D2'],         {'d2':1, 'D2':None},
1519             {'d3':1},   UL(['D3']),     {'d3':1, 'D3':None},
1520             {'d4':1},   {'D4':1},       {'d4':1, 'D4':1},
1521             {'d5':1},   UD({'D5':1}),   UD({'d5':1, 'D5':1}),
1522
1523             UD({'u1':1}), 'U1',         UD({'u1':1, 'U1':None}),
1524             UD({'u2':1}), ['U2'],       UD({'u2':1, 'U2':None}),
1525             UD({'u3':1}), UL(['U3']),   UD({'u3':1, 'U3':None}),
1526             UD({'u4':1}), {'U4':1},     UD({'u4':1, 'U4':1}),
1527             UD({'u5':1}), UD({'U5':1}), UD({'u5':1, 'U5':1}),
1528
1529             '',         'M1',           'M1',
1530             '',         ['M2'],         ['M2'],
1531             '',         UL(['M3']),     UL(['M3']),
1532             '',         '',             '',
1533             '',         [],             [],
1534             '',         UL([]),         UL([]),
1535             '',         [''],           [''],
1536             '',         UL(['']),       UL(['']),
1537
1538             [],         'N1',           ['N1'],
1539             [],         ['N2'],         ['N2'],
1540             [],         UL(['N3']),     UL(['N3']),
1541             [],         '',             [],
1542             [],         [],             [],
1543             [],         UL([]),         UL([]),
1544             [],         [''],           [''],
1545             [],         UL(['']),       UL(['']),
1546
1547             UL([]),     'O1',           ['O', '1'],
1548             UL([]),     ['O2'],         ['O2'],
1549             UL([]),     UL(['O3']),     UL(['O3']),
1550             UL([]),     '',             UL([]),
1551             UL([]),     [],             UL([]),
1552             UL([]),     UL([]),         UL([]),
1553             UL([]),     [''],           UL(['']),
1554             UL([]),     UL(['']),       UL(['']),
1555
1556             [''],       'P1',           ['', 'P1'],
1557             [''],       ['P2'],         ['', 'P2'],
1558             [''],       UL(['P3']),     UL(['', 'P3']),
1559             [''],       '',             [''],
1560             [''],       [],             [''],
1561             [''],       UL([]),         UL(['']),
1562             [''],       [''],           ['', ''],
1563             [''],       UL(['']),       UL(['', '']),
1564
1565             UL(['']),   'Q1',           ['', 'Q', '1'],
1566             UL(['']),   ['Q2'],         ['', 'Q2'],
1567             UL(['']),   UL(['Q3']),     UL(['', 'Q3']),
1568             UL(['']),   '',             UL(['']),
1569             UL(['']),   [],             UL(['']),
1570             UL(['']),   UL([]),         UL(['']),
1571             UL(['']),   [''],           UL(['', '']),
1572             UL(['']),   UL(['']),       UL(['', '']),
1573         ]
1574
1575         env = Environment()
1576         failed = 0
1577         while cases:
1578             input, append, expect = cases[:3]
1579             env['XXX'] = copy.copy(input)
1580             try:
1581                 env.Append(XXX = append)
1582             except Exception, e:
1583                 if failed == 0: print
1584                 print "    %s Append %s exception: %s" % \
1585                       (repr(input), repr(append), e)
1586                 failed = failed + 1
1587             else:
1588                 result = env['XXX']
1589                 if result != expect:
1590                     if failed == 0: print
1591                     print "    %s Append %s => %s did not match %s" % \
1592                           (repr(input), repr(append), repr(result), repr(expect))
1593                     failed = failed + 1
1594             del cases[:3]
1595         assert failed == 0, "%d Append() cases failed" % failed
1596
1597         env['UL'] = UL(['foo'])
1598         env.Append(UL = 'bar')
1599         result = env['UL']
1600         assert isinstance(result, UL), repr(result)
1601         assert result == ['foo', 'b', 'a', 'r'], result
1602
1603         env['CLVar'] = CLVar(['foo'])
1604         env.Append(CLVar = 'bar')
1605         result = env['CLVar']
1606         assert isinstance(result, CLVar), repr(result)
1607         assert result == ['foo', 'bar'], result
1608
1609         class C:
1610             def __init__(self, name):
1611                 self.name = name
1612             def __str__(self):
1613                 return self.name
1614             def __cmp__(self, other):
1615                 raise "should not compare"
1616
1617         ccc = C('ccc')
1618
1619         env2 = self.TestEnvironment(CCC1 = ['c1'], CCC2 = ccc)
1620         env2.Append(CCC1 = ccc, CCC2 = ['c2'])
1621         assert env2['CCC1'][0] == 'c1', env2['CCC1']
1622         assert env2['CCC1'][1] is ccc, env2['CCC1']
1623         assert env2['CCC2'][0] is ccc, env2['CCC2']
1624         assert env2['CCC2'][1] == 'c2', env2['CCC2']
1625
1626         env3 = self.TestEnvironment(X = {'x1' : 7})
1627         env3.Append(X = {'x1' : 8, 'x2' : 9}, Y = {'y1' : 10})
1628         assert env3['X'] == {'x1': 8, 'x2': 9}, env3['X']
1629         assert env3['Y'] == {'y1': 10}, env3['Y']
1630
1631         env4 = self.TestEnvironment(BUILDERS = {'z1' : 11})
1632         env4.Append(BUILDERS = {'z2' : 12})
1633         assert env4['BUILDERS'] == {'z1' : 11, 'z2' : 12}, env4['BUILDERS']
1634         assert hasattr(env4, 'z1')
1635         assert hasattr(env4, 'z2')
1636
1637     def test_AppendENVPath(self):
1638         """Test appending to an ENV path."""
1639         env1 = self.TestEnvironment(ENV = {'PATH': r'C:\dir\num\one;C:\dir\num\two'},
1640                            MYENV = {'MYPATH': r'C:\mydir\num\one;C:\mydir\num\two'})
1641         # have to include the pathsep here so that the test will work on UNIX too.
1642         env1.AppendENVPath('PATH',r'C:\dir\num\two', sep = ';')
1643         env1.AppendENVPath('PATH',r'C:\dir\num\three', sep = ';')
1644         env1.AppendENVPath('MYPATH',r'C:\mydir\num\three','MYENV', sep = ';')
1645         env1.AppendENVPath('MYPATH',r'C:\mydir\num\one','MYENV', sep = ';')
1646         # this should do nothing since delete_existing is 0
1647         env1.AppendENVPath('MYPATH',r'C:\mydir\num\three','MYENV', sep = ';', delete_existing=0)
1648         assert(env1['ENV']['PATH'] == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three')
1649         assert(env1['MYENV']['MYPATH'] == r'C:\mydir\num\two;C:\mydir\num\three;C:\mydir\num\one')
1650
1651         test = TestCmd.TestCmd(workdir = '')
1652         test.subdir('sub1', 'sub2')
1653         p=env1['ENV']['PATH']
1654         env1.AppendENVPath('PATH','#sub1', sep = ';')
1655         env1.AppendENVPath('PATH',env1.fs.Dir('sub2'), sep = ';')
1656         assert env1['ENV']['PATH'] == p + ';sub1;sub2', env1['ENV']['PATH']
1657
1658     def test_AppendUnique(self):
1659         """Test appending to unique values to construction variables
1660
1661         This strips values that are already present when lists are
1662         involved."""
1663         env = self.TestEnvironment(AAA1 = 'a1',
1664                           AAA2 = 'a2',
1665                           AAA3 = 'a3',
1666                           AAA4 = 'a4',
1667                           AAA5 = 'a5',
1668                           BBB1 = ['b1'],
1669                           BBB2 = ['b2'],
1670                           BBB3 = ['b3'],
1671                           BBB4 = ['b4'],
1672                           BBB5 = ['b5'],
1673                           CCC1 = '',
1674                           CCC2 = '',
1675                           DDD1 = ['a', 'b', 'c'])
1676         env.AppendUnique(AAA1 = 'a1',
1677                          AAA2 = ['a2'],
1678                          AAA3 = ['a3', 'b', 'c', 'c', 'b', 'a3'], # ignore dups
1679                          AAA4 = 'a4.new',
1680                          AAA5 = ['a5.new'],
1681                          BBB1 = 'b1',
1682                          BBB2 = ['b2'],
1683                          BBB3 = ['b3', 'c', 'd', 'c', 'b3'],
1684                          BBB4 = 'b4.new',
1685                          BBB5 = ['b5.new'],
1686                          CCC1 = 'c1',
1687                          CCC2 = ['c2'],
1688                          DDD1 = 'b')
1689
1690         assert env['AAA1'] == 'a1a1', env['AAA1']
1691         assert env['AAA2'] == ['a2'], env['AAA2']
1692         assert env['AAA3'] == ['a3', 'b', 'c'], env['AAA3']
1693         assert env['AAA4'] == 'a4a4.new', env['AAA4']
1694         assert env['AAA5'] == ['a5', 'a5.new'], env['AAA5']
1695         assert env['BBB1'] == ['b1'], env['BBB1']
1696         assert env['BBB2'] == ['b2'], env['BBB2']
1697         assert env['BBB3'] == ['b3', 'c', 'd'], env['BBB3']
1698         assert env['BBB4'] == ['b4', 'b4.new'], env['BBB4']
1699         assert env['BBB5'] == ['b5', 'b5.new'], env['BBB5']
1700         assert env['CCC1'] == 'c1', env['CCC1']
1701         assert env['CCC2'] == ['c2'], env['CCC2']
1702         assert env['DDD1'] == ['a', 'b', 'c'], env['DDD1']
1703
1704         env.AppendUnique(DDD1 = 'b', delete_existing=1)
1705         assert env['DDD1'] == ['a', 'c', 'b'], env['DDD1'] # b moves to end
1706         env.AppendUnique(DDD1 = ['a','b'], delete_existing=1)
1707         assert env['DDD1'] == ['c', 'a', 'b'], env['DDD1'] # a & b move to end
1708         env.AppendUnique(DDD1 = ['e','f', 'e'], delete_existing=1)
1709         assert env['DDD1'] == ['c', 'a', 'b', 'f', 'e'], env['DDD1'] # add last
1710         
1711         env['CLVar'] = CLVar([])
1712         env.AppendUnique(CLVar = 'bar')
1713         result = env['CLVar']
1714         if sys.version[0] == '1' or sys.version[:3] == '2.0':
1715             # Python 2.0 and before have a quirky behavior where CLVar([])
1716             # actually matches '' and [] due to different __coerce__()
1717             # semantics in the UserList implementation.  It isn't worth a
1718             # lot of effort to get this corner case to work identically
1719             # (support for Python 1.5 support will die soon anyway),
1720             # so just treat it separately for now.
1721             assert result == 'bar', result
1722         else:
1723             assert isinstance(result, CLVar), repr(result)
1724             assert result == ['bar'], result
1725
1726         env['CLVar'] = CLVar(['abc'])
1727         env.AppendUnique(CLVar = 'bar')
1728         result = env['CLVar']
1729         assert isinstance(result, CLVar), repr(result)
1730         assert result == ['abc', 'bar'], result
1731
1732         env['CLVar'] = CLVar(['bar'])
1733         env.AppendUnique(CLVar = 'bar')
1734         result = env['CLVar']
1735         assert isinstance(result, CLVar), repr(result)
1736         assert result == ['bar'], result
1737
1738     def test_Clone(self):
1739         """Test construction environment copying
1740
1741         Update the copy independently afterwards and check that
1742         the original remains intact (that is, no dangling
1743         references point to objects in the copied environment).
1744         Clone the original with some construction variable
1745         updates and check that the original remains intact
1746         and the copy has the updated values.
1747         """
1748         env1 = self.TestEnvironment(XXX = 'x', YYY = 'y')
1749         env2 = env1.Clone()
1750         env1copy = env1.Clone()
1751         assert env1copy == env1copy
1752         assert env2 == env2
1753         env2.Replace(YYY = 'yyy')
1754         assert env2 == env2
1755         assert env1 != env2
1756         assert env1 == env1copy
1757
1758         env3 = env1.Clone(XXX = 'x3', ZZZ = 'z3')
1759         assert env3 == env3
1760         assert env3.Dictionary('XXX') == 'x3'
1761         assert env3.Dictionary('YYY') == 'y'
1762         assert env3.Dictionary('ZZZ') == 'z3'
1763         assert env1 == env1copy
1764
1765         # Ensure that lists and dictionaries are
1766         # deep copied, but not instances.
1767         class TestA:
1768             pass
1769         env1 = self.TestEnvironment(XXX=TestA(), YYY = [ 1, 2, 3 ],
1770                            ZZZ = { 1:2, 3:4 })
1771         env2=env1.Clone()
1772         env2.Dictionary('YYY').append(4)
1773         env2.Dictionary('ZZZ')[5] = 6
1774         assert env1.Dictionary('XXX') is env2.Dictionary('XXX')
1775         assert 4 in env2.Dictionary('YYY')
1776         assert not 4 in env1.Dictionary('YYY')
1777         assert env2.Dictionary('ZZZ').has_key(5)
1778         assert not env1.Dictionary('ZZZ').has_key(5)
1779
1780         #
1781         env1 = self.TestEnvironment(BUILDERS = {'b1' : 1})
1782         assert hasattr(env1, 'b1'), "env1.b1 was not set"
1783         assert env1.b1.object == env1, "b1.object doesn't point to env1"
1784         env2 = env1.Clone(BUILDERS = {'b2' : 2})
1785         assert env2 is env2
1786         assert env2 == env2
1787         assert hasattr(env1, 'b1'), "b1 was mistakenly cleared from env1"
1788         assert env1.b1.object == env1, "b1.object was changed"
1789         assert not hasattr(env2, 'b1'), "b1 was not cleared from env2"
1790         assert hasattr(env2, 'b2'), "env2.b2 was not set"
1791         assert env2.b2.object == env2, "b2.object doesn't point to env2"
1792
1793         # Ensure that specifying new tools in a copied environment
1794         # works.
1795         def foo(env): env['FOO'] = 1
1796         def bar(env): env['BAR'] = 2
1797         def baz(env): env['BAZ'] = 3
1798         env1 = self.TestEnvironment(tools=[foo])
1799         env2 = env1.Clone()
1800         env3 = env1.Clone(tools=[bar, baz])
1801
1802         assert env1.get('FOO') is 1
1803         assert env1.get('BAR') is None
1804         assert env1.get('BAZ') is None
1805         assert env2.get('FOO') is 1
1806         assert env2.get('BAR') is None
1807         assert env2.get('BAZ') is None
1808         assert env3.get('FOO') is 1
1809         assert env3.get('BAR') is 2
1810         assert env3.get('BAZ') is 3
1811
1812         # Ensure that recursive variable substitution when copying
1813         # environments works properly.
1814         env1 = self.TestEnvironment(CCFLAGS = '-DFOO', XYZ = '-DXYZ')
1815         env2 = env1.Clone(CCFLAGS = '$CCFLAGS -DBAR',
1816                          XYZ = ['-DABC', 'x $XYZ y', '-DDEF'])
1817         x = env2.get('CCFLAGS')
1818         assert x == '-DFOO -DBAR', x
1819         x = env2.get('XYZ')
1820         assert x == ['-DABC', 'x -DXYZ y', '-DDEF'], x
1821
1822         # Ensure that special properties of a class don't get
1823         # lost on copying.
1824         env1 = self.TestEnvironment(FLAGS = CLVar('flag1 flag2'))
1825         x = env1.get('FLAGS')
1826         assert x == ['flag1', 'flag2'], x
1827         env2 = env1.Clone()
1828         env2.Append(FLAGS = 'flag3 flag4')
1829         x = env2.get('FLAGS')
1830         assert x == ['flag1', 'flag2', 'flag3', 'flag4'], x
1831
1832         # Test that the environment stores the toolpath and
1833         # re-uses it for copies.
1834         test = TestCmd.TestCmd(workdir = '')
1835
1836         test.write('xxx.py', """\
1837 def exists(env):
1838     1
1839 def generate(env):
1840     env['XXX'] = 'one'
1841 """)
1842
1843         test.write('yyy.py', """\
1844 def exists(env):
1845     1
1846 def generate(env):
1847     env['YYY'] = 'two'
1848 """)
1849
1850         env = self.TestEnvironment(tools=['xxx'], toolpath=[test.workpath('')])
1851         assert env['XXX'] == 'one', env['XXX']
1852         env = env.Clone(tools=['yyy'])
1853         assert env['YYY'] == 'two', env['YYY']
1854
1855
1856         # Test that
1857         real_value = [4]
1858
1859         def my_tool(env, rv=real_value):
1860             assert env['KEY_THAT_I_WANT'] == rv[0]
1861             env['KEY_THAT_I_WANT'] = rv[0] + 1
1862
1863         env = self.TestEnvironment()
1864
1865         real_value[0] = 5
1866         env = env.Clone(KEY_THAT_I_WANT=5, tools=[my_tool])
1867         assert env['KEY_THAT_I_WANT'] == real_value[0], env['KEY_THAT_I_WANT']
1868
1869         real_value[0] = 6
1870         env = env.Clone(KEY_THAT_I_WANT=6, tools=[my_tool])
1871         assert env['KEY_THAT_I_WANT'] == real_value[0], env['KEY_THAT_I_WANT']
1872
1873
1874     def test_Copy(self):
1875         """Test copying using the old env.Copy() method"""
1876         env1 = self.TestEnvironment(XXX = 'x', YYY = 'y')
1877         env2 = env1.Copy()
1878         env1copy = env1.Copy()
1879         assert env1copy == env1copy
1880         assert env2 == env2
1881         env2.Replace(YYY = 'yyy')
1882         assert env2 == env2
1883         assert env1 != env2
1884         assert env1 == env1copy
1885
1886     def test_Detect(self):
1887         """Test Detect()ing tools"""
1888         test = TestCmd.TestCmd(workdir = '')
1889         test.subdir('sub1', 'sub2')
1890         sub1 = test.workpath('sub1')
1891         sub2 = test.workpath('sub2')
1892
1893         if sys.platform == 'win32':
1894             test.write(['sub1', 'xxx'], "sub1/xxx\n")
1895             test.write(['sub2', 'xxx'], "sub2/xxx\n")
1896
1897             env = self.TestEnvironment(ENV = { 'PATH' : [sub1, sub2] })
1898
1899             x = env.Detect('xxx.exe')
1900             assert x is None, x
1901
1902             test.write(['sub2', 'xxx.exe'], "sub2/xxx.exe\n")
1903
1904             env = self.TestEnvironment(ENV = { 'PATH' : [sub1, sub2] })
1905
1906             x = env.Detect('xxx.exe')
1907             assert x == 'xxx.exe', x
1908
1909             test.write(['sub1', 'xxx.exe'], "sub1/xxx.exe\n")
1910
1911             x = env.Detect('xxx.exe')
1912             assert x == 'xxx.exe', x
1913
1914         else:
1915             test.write(['sub1', 'xxx.exe'], "sub1/xxx.exe\n")
1916             test.write(['sub2', 'xxx.exe'], "sub2/xxx.exe\n")
1917
1918             env = self.TestEnvironment(ENV = { 'PATH' : [sub1, sub2] })
1919
1920             x = env.Detect('xxx.exe')
1921             assert x is None, x
1922
1923             sub2_xxx_exe = test.workpath('sub2', 'xxx.exe')
1924             os.chmod(sub2_xxx_exe, 0755)
1925
1926             env = self.TestEnvironment(ENV = { 'PATH' : [sub1, sub2] })
1927
1928             x = env.Detect('xxx.exe')
1929             assert x == 'xxx.exe', x
1930
1931             sub1_xxx_exe = test.workpath('sub1', 'xxx.exe')
1932             os.chmod(sub1_xxx_exe, 0755)
1933
1934             x = env.Detect('xxx.exe')
1935             assert x == 'xxx.exe', x
1936
1937         env = self.TestEnvironment(ENV = { 'PATH' : [] })
1938         x = env.Detect('xxx.exe')
1939         assert x is None, x
1940
1941     def test_Dictionary(self):
1942         """Test retrieval of known construction variables
1943
1944         Fetch them from the Dictionary and check for well-known
1945         defaults that get inserted.
1946         """
1947         env = self.TestEnvironment(XXX = 'x', YYY = 'y', ZZZ = 'z')
1948         assert env.Dictionary('XXX') == 'x'
1949         assert env.Dictionary('YYY') == 'y'
1950         assert env.Dictionary('XXX', 'ZZZ') == ['x', 'z']
1951         xxx, zzz = env.Dictionary('XXX', 'ZZZ')
1952         assert xxx == 'x'
1953         assert zzz == 'z'
1954         assert env.Dictionary().has_key('BUILDERS')
1955         assert env.Dictionary().has_key('CC')
1956         assert env.Dictionary().has_key('CCFLAGS')
1957         assert env.Dictionary().has_key('ENV')
1958
1959         assert env['XXX'] == 'x'
1960         env['XXX'] = 'foo'
1961         assert env.Dictionary('XXX') == 'foo'
1962         del env['XXX']
1963         assert not env.Dictionary().has_key('XXX')
1964
1965     def test_FindIxes(self):
1966         "Test FindIxes()"
1967         env = self.TestEnvironment(LIBPREFIX='lib',
1968                           LIBSUFFIX='.a',
1969                           SHLIBPREFIX='lib',
1970                           SHLIBSUFFIX='.so',
1971                           PREFIX='pre',
1972                           SUFFIX='post')
1973
1974         paths = [os.path.join('dir', 'libfoo.a'),
1975                  os.path.join('dir', 'libfoo.so')]
1976
1977         assert paths[0] == env.FindIxes(paths, 'LIBPREFIX', 'LIBSUFFIX')
1978         assert paths[1] == env.FindIxes(paths, 'SHLIBPREFIX', 'SHLIBSUFFIX')
1979         assert None is env.FindIxes(paths, 'PREFIX', 'POST')
1980
1981         paths = ['libfoo.a', 'prefoopost']
1982
1983         assert paths[0] == env.FindIxes(paths, 'LIBPREFIX', 'LIBSUFFIX')
1984         assert None is env.FindIxes(paths, 'SHLIBPREFIX', 'SHLIBSUFFIX')
1985         assert paths[1] == env.FindIxes(paths, 'PREFIX', 'SUFFIX')
1986
1987     def test_ParseConfig(self):
1988         """Test the ParseConfig() method"""
1989         env = self.TestEnvironment(COMMAND='command',
1990                           ASFLAGS='assembler',
1991                           CCFLAGS=[''],
1992                           CPPDEFINES=[],
1993                           CPPFLAGS=[''],
1994                           CPPPATH='string',
1995                           FRAMEWORKPATH=[],
1996                           FRAMEWORKS=[],
1997                           LIBPATH=['list'],
1998                           LIBS='',
1999                           LINKFLAGS=[''],
2000                           RPATH=[])
2001
2002         orig_backtick = env.backtick
2003         class my_backtick:
2004             def __init__(self, save_command, output):
2005                 self.save_command = save_command
2006                 self.output = output
2007             def __call__(self, command):
2008                 self.save_command.append(command)
2009                 return self.output
2010
2011         try:
2012             save_command = []
2013             env.backtick = my_backtick(save_command, 
2014                                  "-I/usr/include/fum -I bar -X\n" + \
2015                                  "-L/usr/fax -L foo -lxxx -l yyy " + \
2016                                  "-Wa,-as -Wl,-link " + \
2017                                  "-Wl,-rpath=rpath1 " + \
2018                                  "-Wl,-R,rpath2 " + \
2019                                  "-Wl,-Rrpath3 " + \
2020                                  "-Wp,-cpp abc " + \
2021                                  "-framework Carbon " + \
2022                                  "-frameworkdir=fwd1 " + \
2023                                  "-Ffwd2 " + \
2024                                  "-F fwd3 " + \
2025                                  "-pthread " + \
2026                                  "-mno-cygwin -mwindows " + \
2027                                  "-arch i386 -isysroot /tmp +DD64 " + \
2028                                  "-DFOO -DBAR=value")
2029             env.ParseConfig("fake $COMMAND")
2030             assert save_command == ['fake command'], save_command
2031             assert env['ASFLAGS'] == ['assembler', '-as'], env['ASFLAGS']
2032             assert env['CCFLAGS'] == ['', '-X', '-Wa,-as',
2033                                       '-pthread', '-mno-cygwin',
2034                                       ('-arch', 'i386'), ('-isysroot', '/tmp'),
2035                                       '+DD64'], env['CCFLAGS']
2036             assert env['CPPDEFINES'] == ['FOO', ['BAR', 'value']], env['CPPDEFINES']
2037             assert env['CPPFLAGS'] == ['', '-Wp,-cpp'], env['CPPFLAGS']
2038             assert env['CPPPATH'] == ['string', '/usr/include/fum', 'bar'], env['CPPPATH']
2039             assert env['FRAMEWORKPATH'] == ['fwd1', 'fwd2', 'fwd3'], env['FRAMEWORKPATH']
2040             assert env['FRAMEWORKS'] == ['Carbon'], env['FRAMEWORKS']
2041             assert env['LIBPATH'] == ['list', '/usr/fax', 'foo'], env['LIBPATH']
2042             assert env['LIBS'] == ['xxx', 'yyy', env.File('abc')], env['LIBS']
2043             assert env['LINKFLAGS'] == ['', '-Wl,-link', '-pthread',
2044                                         '-mno-cygwin', '-mwindows',
2045                                         ('-arch', 'i386'),
2046                                         ('-isysroot', '/tmp'),
2047                                         '+DD64'], env['LINKFLAGS']
2048             assert env['RPATH'] == ['rpath1', 'rpath2', 'rpath3'], env['RPATH']
2049
2050             env.backtick = my_backtick([], "-Ibar")
2051             env.ParseConfig("fake2")
2052             assert env['CPPPATH'] == ['string', '/usr/include/fum', 'bar'], env['CPPPATH']
2053             env.ParseConfig("fake2", unique=0)
2054             assert env['CPPPATH'] == ['string', '/usr/include/fum', 'bar', 'bar'], env['CPPPATH']
2055         finally:
2056             env.backtick = orig_backtick
2057
2058     def test_ParseDepends(self):
2059         """Test the ParseDepends() method"""
2060         test = TestCmd.TestCmd(workdir = '')
2061
2062         test.write('single', """
2063 #file: dependency
2064
2065 f0: \
2066    d1 \
2067    d2 \
2068    d3 \
2069
2070 """)
2071
2072         test.write('multiple', """
2073 f1: foo
2074 f2 f3: bar
2075 f4: abc def
2076 #file: dependency
2077 f5: \
2078    ghi \
2079    jkl \
2080    mno \
2081 """)
2082
2083         env = self.TestEnvironment(SINGLE = test.workpath('single'))
2084
2085         tlist = []
2086         dlist = []
2087         def my_depends(target, dependency, tlist=tlist, dlist=dlist):
2088             tlist.extend(target)
2089             dlist.extend(dependency)
2090
2091         env.Depends = my_depends
2092
2093         env.ParseDepends(test.workpath('does_not_exist'))
2094
2095         exc_caught = None
2096         try:
2097             env.ParseDepends(test.workpath('does_not_exist'), must_exist=1)
2098         except IOError:
2099             exc_caught = 1
2100         assert exc_caught, "did not catch expected IOError"
2101
2102         del tlist[:]
2103         del dlist[:]
2104
2105         env.ParseDepends('$SINGLE', only_one=1)
2106         t = map(str, tlist)
2107         d = map(str, dlist)
2108         assert t == ['f0'], t
2109         assert d == ['d1', 'd2', 'd3'], d
2110
2111         del tlist[:]
2112         del dlist[:]
2113
2114         env.ParseDepends(test.workpath('multiple'))
2115         t = map(str, tlist)
2116         d = map(str, dlist)
2117         assert t == ['f1', 'f2', 'f3', 'f4', 'f5'], t
2118         assert d == ['foo', 'bar', 'abc', 'def', 'ghi', 'jkl', 'mno'], d
2119
2120         exc_caught = None
2121         try:
2122             env.ParseDepends(test.workpath('multiple'), only_one=1)
2123         except SCons.Errors.UserError:
2124             exc_caught = 1
2125         assert exc_caught, "did not catch expected UserError"
2126
2127     def test_Platform(self):
2128         """Test the Platform() method"""
2129         env = self.TestEnvironment(WIN32='win32', NONE='no-such-platform')
2130
2131         exc_caught = None
2132         try:
2133             env.Platform('does_not_exist')
2134         except SCons.Errors.UserError:
2135             exc_caught = 1
2136         assert exc_caught, "did not catch expected UserError"
2137
2138         exc_caught = None
2139         try:
2140             env.Platform('$NONE')
2141         except SCons.Errors.UserError:
2142             exc_caught = 1
2143         assert exc_caught, "did not catch expected UserError"
2144
2145         env.Platform('posix')
2146         assert env['OBJSUFFIX'] == '.o', env['OBJSUFFIX']
2147
2148         env.Platform('$WIN32')
2149         assert env['OBJSUFFIX'] == '.obj', env['OBJSUFFIX']
2150
2151     def test_Prepend(self):
2152         """Test prepending to construction variables in an Environment
2153         """
2154         import UserDict
2155         UD = UserDict.UserDict
2156         import UserList
2157         UL = UserList.UserList
2158
2159         cases = [
2160             'a1',       'A1',           'A1a1',
2161             'a2',       ['A2'],         ['A2', 'a2'],
2162             'a3',       UL(['A3']),     UL(['A3', 'a', '3']),
2163             'a4',       '',             'a4',
2164             'a5',       [],             ['a5'],
2165             'a6',       UL([]),         UL(['a', '6']),
2166             'a7',       [''],           ['', 'a7'],
2167             'a8',       UL(['']),       UL(['', 'a', '8']),
2168
2169             ['e1'],     'E1',           ['E1', 'e1'],
2170             ['e2'],     ['E2'],         ['E2', 'e2'],
2171             ['e3'],     UL(['E3']),     UL(['E3', 'e3']),
2172             ['e4'],     '',             ['e4'],
2173             ['e5'],     [],             ['e5'],
2174             ['e6'],     UL([]),         UL(['e6']),
2175             ['e7'],     [''],           ['', 'e7'],
2176             ['e8'],     UL(['']),       UL(['', 'e8']),
2177
2178             UL(['i1']), 'I1',           UL(['I', '1', 'i1']),
2179             UL(['i2']), ['I2'],         UL(['I2', 'i2']),
2180             UL(['i3']), UL(['I3']),     UL(['I3', 'i3']),
2181             UL(['i4']), '',             UL(['i4']),
2182             UL(['i5']), [],             UL(['i5']),
2183             UL(['i6']), UL([]),         UL(['i6']),
2184             UL(['i7']), [''],           UL(['', 'i7']),
2185             UL(['i8']), UL(['']),       UL(['', 'i8']),
2186
2187             {'d1':1},   'D1',           {'d1':1, 'D1':None},
2188             {'d2':1},   ['D2'],         {'d2':1, 'D2':None},
2189             {'d3':1},   UL(['D3']),     {'d3':1, 'D3':None},
2190             {'d4':1},   {'D4':1},       {'d4':1, 'D4':1},
2191             {'d5':1},   UD({'D5':1}),   UD({'d5':1, 'D5':1}),
2192
2193             UD({'u1':1}), 'U1',         UD({'u1':1, 'U1':None}),
2194             UD({'u2':1}), ['U2'],       UD({'u2':1, 'U2':None}),
2195             UD({'u3':1}), UL(['U3']),   UD({'u3':1, 'U3':None}),
2196             UD({'u4':1}), {'U4':1},     UD({'u4':1, 'U4':1}),
2197             UD({'u5':1}), UD({'U5':1}), UD({'u5':1, 'U5':1}),
2198
2199             '',         'M1',           'M1',
2200             '',         ['M2'],         ['M2'],
2201             '',         UL(['M3']),     UL(['M3']),
2202             '',         '',             '',
2203             '',         [],             [],
2204             '',         UL([]),         UL([]),
2205             '',         [''],           [''],
2206             '',         UL(['']),       UL(['']),
2207
2208             [],         'N1',           ['N1'],
2209             [],         ['N2'],         ['N2'],
2210             [],         UL(['N3']),     UL(['N3']),
2211             [],         '',             [],
2212             [],         [],             [],
2213             [],         UL([]),         UL([]),
2214             [],         [''],           [''],
2215             [],         UL(['']),       UL(['']),
2216
2217             UL([]),     'O1',           UL(['O', '1']),
2218             UL([]),     ['O2'],         UL(['O2']),
2219             UL([]),     UL(['O3']),     UL(['O3']),
2220             UL([]),     '',             UL([]),
2221             UL([]),     [],             UL([]),
2222             UL([]),     UL([]),         UL([]),
2223             UL([]),     [''],           UL(['']),
2224             UL([]),     UL(['']),       UL(['']),
2225
2226             [''],       'P1',           ['P1', ''],
2227             [''],       ['P2'],         ['P2', ''],
2228             [''],       UL(['P3']),     UL(['P3', '']),
2229             [''],       '',             [''],
2230             [''],       [],             [''],
2231             [''],       UL([]),         UL(['']),
2232             [''],       [''],           ['', ''],
2233             [''],       UL(['']),       UL(['', '']),
2234
2235             UL(['']),   'Q1',           UL(['Q', '1', '']),
2236             UL(['']),   ['Q2'],         UL(['Q2', '']),
2237             UL(['']),   UL(['Q3']),     UL(['Q3', '']),
2238             UL(['']),   '',             UL(['']),
2239             UL(['']),   [],             UL(['']),
2240             UL(['']),   UL([]),         UL(['']),
2241             UL(['']),   [''],           UL(['', '']),
2242             UL(['']),   UL(['']),       UL(['', '']),
2243         ]
2244
2245         env = Environment()
2246         failed = 0
2247         while cases:
2248             input, prepend, expect = cases[:3]
2249             env['XXX'] = copy.copy(input)
2250             try:
2251                 env.Prepend(XXX = prepend)
2252             except Exception, e:
2253                 if failed == 0: print
2254                 print "    %s Prepend %s exception: %s" % \
2255                       (repr(input), repr(prepend), e)
2256                 failed = failed + 1
2257             else:
2258                 result = env['XXX']
2259                 if result != expect:
2260                     if failed == 0: print
2261                     print "    %s Prepend %s => %s did not match %s" % \
2262                           (repr(input), repr(prepend), repr(result), repr(expect))
2263                     failed = failed + 1
2264             del cases[:3]
2265         assert failed == 0, "%d Prepend() cases failed" % failed
2266
2267         env['UL'] = UL(['foo'])
2268         env.Prepend(UL = 'bar')
2269         result = env['UL']
2270         assert isinstance(result, UL), repr(result)
2271         assert result == ['b', 'a', 'r', 'foo'], result
2272
2273         env['CLVar'] = CLVar(['foo'])
2274         env.Prepend(CLVar = 'bar')
2275         result = env['CLVar']
2276         assert isinstance(result, CLVar), repr(result)
2277         assert result == ['bar', 'foo'], result
2278
2279         env3 = self.TestEnvironment(X = {'x1' : 7})
2280         env3.Prepend(X = {'x1' : 8, 'x2' : 9}, Y = {'y1' : 10})
2281         assert env3['X'] == {'x1': 8, 'x2' : 9}, env3['X']
2282         assert env3['Y'] == {'y1': 10}, env3['Y']
2283
2284         env4 = self.TestEnvironment(BUILDERS = {'z1' : 11})
2285         env4.Prepend(BUILDERS = {'z2' : 12})
2286         assert env4['BUILDERS'] == {'z1' : 11, 'z2' : 12}, env4['BUILDERS']
2287         assert hasattr(env4, 'z1')
2288         assert hasattr(env4, 'z2')
2289
2290     def test_PrependENVPath(self):
2291         """Test prepending to an ENV path."""
2292         env1 = self.TestEnvironment(ENV = {'PATH': r'C:\dir\num\one;C:\dir\num\two'},
2293                            MYENV = {'MYPATH': r'C:\mydir\num\one;C:\mydir\num\two'})
2294         # have to include the pathsep here so that the test will work on UNIX too.
2295         env1.PrependENVPath('PATH',r'C:\dir\num\two',sep = ';')
2296         env1.PrependENVPath('PATH',r'C:\dir\num\three',sep = ';')
2297         env1.PrependENVPath('MYPATH',r'C:\mydir\num\three','MYENV',sep = ';')
2298         env1.PrependENVPath('MYPATH',r'C:\mydir\num\one','MYENV',sep = ';')
2299         # this should do nothing since delete_existing is 0
2300         env1.PrependENVPath('MYPATH',r'C:\mydir\num\three','MYENV', sep = ';', delete_existing=0)
2301         assert(env1['ENV']['PATH'] == r'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one')
2302         assert(env1['MYENV']['MYPATH'] == r'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two')
2303
2304         test = TestCmd.TestCmd(workdir = '')
2305         test.subdir('sub1', 'sub2')
2306         p=env1['ENV']['PATH']
2307         env1.PrependENVPath('PATH','#sub1', sep = ';')
2308         env1.PrependENVPath('PATH',env1.fs.Dir('sub2'), sep = ';')
2309         assert env1['ENV']['PATH'] == 'sub2;sub1;' + p, env1['ENV']['PATH']
2310
2311     def test_PrependUnique(self):
2312         """Test prepending unique values to construction variables
2313
2314         This strips values that are already present when lists are
2315         involved."""
2316         env = self.TestEnvironment(AAA1 = 'a1',
2317                           AAA2 = 'a2',
2318                           AAA3 = 'a3',
2319                           AAA4 = 'a4',
2320                           AAA5 = 'a5',
2321                           BBB1 = ['b1'],
2322                           BBB2 = ['b2'],
2323                           BBB3 = ['b3'],
2324                           BBB4 = ['b4'],
2325                           BBB5 = ['b5'],
2326                           CCC1 = '',
2327                           CCC2 = '',
2328                           DDD1 = ['a', 'b', 'c'])
2329         env.PrependUnique(AAA1 = 'a1',
2330                           AAA2 = ['a2'],
2331                           AAA3 = ['a3', 'b', 'c', 'b', 'a3'], # ignore dups
2332                           AAA4 = 'a4.new',
2333                           AAA5 = ['a5.new'],
2334                           BBB1 = 'b1',
2335                           BBB2 = ['b2'],
2336                           BBB3 = ['b3', 'b', 'c', 'b3'],
2337                           BBB4 = 'b4.new',
2338                           BBB5 = ['b5.new'],
2339                           CCC1 = 'c1',
2340                           CCC2 = ['c2'],
2341                           DDD1 = 'b')
2342         assert env['AAA1'] == 'a1a1', env['AAA1']
2343         assert env['AAA2'] == ['a2'], env['AAA2']
2344         assert env['AAA3'] == ['c', 'b', 'a3'], env['AAA3']
2345         assert env['AAA4'] == 'a4.newa4', env['AAA4']
2346         assert env['AAA5'] == ['a5.new', 'a5'], env['AAA5']
2347         assert env['BBB1'] == ['b1'], env['BBB1']
2348         assert env['BBB2'] == ['b2'], env['BBB2']
2349         assert env['BBB3'] == ['b', 'c', 'b3'], env['BBB3']
2350         assert env['BBB4'] == ['b4.new', 'b4'], env['BBB4']
2351         assert env['BBB5'] == ['b5.new', 'b5'], env['BBB5']
2352         assert env['CCC1'] == 'c1', env['CCC1']
2353         assert env['CCC2'] == ['c2'], env['CCC2']
2354         assert env['DDD1'] == ['a', 'b', 'c'], env['DDD1']
2355
2356         env.PrependUnique(DDD1 = 'b', delete_existing=1)
2357         assert env['DDD1'] == ['b', 'a', 'c'], env['DDD1'] # b moves to front
2358         env.PrependUnique(DDD1 = ['a','c'], delete_existing=1)
2359         assert env['DDD1'] == ['a', 'c', 'b'], env['DDD1'] # a & c move to front
2360         env.PrependUnique(DDD1 = ['d','e','d'], delete_existing=1)
2361         assert env['DDD1'] == ['d', 'e', 'a', 'c', 'b'], env['DDD1'] 
2362
2363
2364         env['CLVar'] = CLVar([])
2365         env.PrependUnique(CLVar = 'bar')
2366         result = env['CLVar']
2367         if sys.version[0] == '1' or sys.version[:3] == '2.0':
2368             # Python 2.0 and before have a quirky behavior where CLVar([])
2369             # actually matches '' and [] due to different __coerce__()
2370             # semantics in the UserList implementation.  It isn't worth a
2371             # lot of effort to get this corner case to work identically
2372             # (support for Python 1.5 support will die soon anyway),
2373             # so just treat it separately for now.
2374             assert result == 'bar', result
2375         else:
2376             assert isinstance(result, CLVar), repr(result)
2377             assert result == ['bar'], result
2378
2379         env['CLVar'] = CLVar(['abc'])
2380         env.PrependUnique(CLVar = 'bar')
2381         result = env['CLVar']
2382         assert isinstance(result, CLVar), repr(result)
2383         assert result == ['bar', 'abc'], result
2384
2385         env['CLVar'] = CLVar(['bar'])
2386         env.PrependUnique(CLVar = 'bar')
2387         result = env['CLVar']
2388         assert isinstance(result, CLVar), repr(result)
2389         assert result == ['bar'], result
2390
2391     def test_Replace(self):
2392         """Test replacing construction variables in an Environment
2393
2394         After creation of the Environment, of course.
2395         """
2396         env1 = self.TestEnvironment(AAA = 'a', BBB = 'b')
2397         env1.Replace(BBB = 'bbb', CCC = 'ccc')
2398
2399         env2 = self.TestEnvironment(AAA = 'a', BBB = 'bbb', CCC = 'ccc')
2400         assert env1 == env2, diff_env(env1, env2)
2401
2402         env3 = self.TestEnvironment(BUILDERS = {'b1' : 1})
2403         assert hasattr(env3, 'b1'), "b1 was not set"
2404         env3.Replace(BUILDERS = {'b2' : 2})
2405         assert not hasattr(env3, 'b1'), "b1 was not cleared"
2406         assert hasattr(env3, 'b2'), "b2 was not set"
2407
2408     def test_ReplaceIxes(self):
2409         "Test ReplaceIxes()"
2410         env = self.TestEnvironment(LIBPREFIX='lib',
2411                           LIBSUFFIX='.a',
2412                           SHLIBPREFIX='lib',
2413                           SHLIBSUFFIX='.so',
2414                           PREFIX='pre',
2415                           SUFFIX='post')
2416
2417         assert 'libfoo.a' == env.ReplaceIxes('libfoo.so',
2418                                              'SHLIBPREFIX', 'SHLIBSUFFIX',
2419                                              'LIBPREFIX', 'LIBSUFFIX')
2420
2421         assert os.path.join('dir', 'libfoo.a') == env.ReplaceIxes(os.path.join('dir', 'libfoo.so'),
2422                                                                    'SHLIBPREFIX', 'SHLIBSUFFIX',
2423                                                                    'LIBPREFIX', 'LIBSUFFIX')
2424
2425         assert 'libfoo.a' == env.ReplaceIxes('prefoopost',
2426                                              'PREFIX', 'SUFFIX',
2427                                              'LIBPREFIX', 'LIBSUFFIX')
2428
2429     def test_SetDefault(self):
2430         """Test the SetDefault method"""
2431         env = self.TestEnvironment(tools = [])
2432         env.SetDefault(V1 = 1)
2433         env.SetDefault(V1 = 2)
2434         assert env['V1'] == 1
2435         env['V2'] = 2
2436         env.SetDefault(V2 = 1)
2437         assert env['V2'] == 2
2438
2439     def test_Tool(self):
2440         """Test the Tool() method"""
2441         env = self.TestEnvironment(LINK='link', NONE='no-such-tool')
2442
2443         exc_caught = None
2444         try:
2445             env.Tool('does_not_exist')
2446         except SCons.Errors.EnvironmentError:
2447             exc_caught = 1
2448         assert exc_caught, "did not catch expected EnvironmentError"
2449
2450         exc_caught = None
2451         try:
2452             env.Tool('$NONE')
2453         except SCons.Errors.EnvironmentError:
2454             exc_caught = 1
2455         assert exc_caught, "did not catch expected EnvironmentError"
2456
2457         # Use a non-existent toolpath directory just to make sure we
2458         # can call Tool() with the keyword argument.
2459         env.Tool('cc', toolpath=['/no/such/directory'])
2460         assert env['CC'] == 'cc', env['CC']
2461
2462         env.Tool('$LINK')
2463         assert env['LINK'] == '$SMARTLINK', env['LINK']
2464
2465         # Test that the environment stores the toolpath and
2466         # re-uses it for later calls.
2467         test = TestCmd.TestCmd(workdir = '')
2468
2469         test.write('xxx.py', """\
2470 def exists(env):
2471     1
2472 def generate(env):
2473     env['XXX'] = 'one'
2474 """)
2475
2476         test.write('yyy.py', """\
2477 def exists(env):
2478     1
2479 def generate(env):
2480     env['YYY'] = 'two'
2481 """)
2482
2483         env = self.TestEnvironment(tools=['xxx'], toolpath=[test.workpath('')])
2484         assert env['XXX'] == 'one', env['XXX']
2485         env.Tool('yyy')
2486         assert env['YYY'] == 'two', env['YYY']
2487
2488     def test_WhereIs(self):
2489         """Test the WhereIs() method"""
2490         test = TestCmd.TestCmd(workdir = '')
2491
2492         sub1_xxx_exe = test.workpath('sub1', 'xxx.exe')
2493         sub2_xxx_exe = test.workpath('sub2', 'xxx.exe')
2494         sub3_xxx_exe = test.workpath('sub3', 'xxx.exe')
2495         sub4_xxx_exe = test.workpath('sub4', 'xxx.exe')
2496
2497         test.subdir('subdir', 'sub1', 'sub2', 'sub3', 'sub4')
2498
2499         if sys.platform != 'win32':
2500             test.write(sub1_xxx_exe, "\n")
2501
2502         os.mkdir(sub2_xxx_exe)
2503
2504         test.write(sub3_xxx_exe, "\n")
2505         os.chmod(sub3_xxx_exe, 0777)
2506
2507         test.write(sub4_xxx_exe, "\n")
2508         os.chmod(sub4_xxx_exe, 0777)
2509
2510         env_path = os.environ['PATH']
2511
2512         pathdirs_1234 = [ test.workpath('sub1'),
2513                           test.workpath('sub2'),
2514                           test.workpath('sub3'),
2515                           test.workpath('sub4'),
2516                         ] + string.split(env_path, os.pathsep)
2517
2518         pathdirs_1243 = [ test.workpath('sub1'),
2519                           test.workpath('sub2'),
2520                           test.workpath('sub4'),
2521                           test.workpath('sub3'),
2522                         ] + string.split(env_path, os.pathsep)
2523
2524         path = string.join(pathdirs_1234, os.pathsep)
2525         env = self.TestEnvironment(ENV = {'PATH' : path})
2526         wi = env.WhereIs('xxx.exe')
2527         assert wi == test.workpath(sub3_xxx_exe), wi
2528         wi = env.WhereIs('xxx.exe', pathdirs_1243)
2529         assert wi == test.workpath(sub4_xxx_exe), wi
2530         wi = env.WhereIs('xxx.exe', string.join(pathdirs_1243, os.pathsep))
2531         assert wi == test.workpath(sub4_xxx_exe), wi
2532
2533         wi = env.WhereIs('xxx.exe', reject = sub3_xxx_exe)
2534         assert wi == test.workpath(sub4_xxx_exe), wi
2535         wi = env.WhereIs('xxx.exe', pathdirs_1243, reject = sub3_xxx_exe)
2536         assert wi == test.workpath(sub4_xxx_exe), wi
2537
2538         path = string.join(pathdirs_1243, os.pathsep)
2539         env = self.TestEnvironment(ENV = {'PATH' : path})
2540         wi = env.WhereIs('xxx.exe')
2541         assert wi == test.workpath(sub4_xxx_exe), wi
2542         wi = env.WhereIs('xxx.exe', pathdirs_1234)
2543         assert wi == test.workpath(sub3_xxx_exe), wi
2544         wi = env.WhereIs('xxx.exe', string.join(pathdirs_1234, os.pathsep))
2545         assert wi == test.workpath(sub3_xxx_exe), wi
2546
2547         if sys.platform == 'win32':
2548             wi = env.WhereIs('xxx', pathext = '')
2549             assert wi is None, wi
2550
2551             wi = env.WhereIs('xxx', pathext = '.exe')
2552             assert wi == test.workpath(sub4_xxx_exe), wi
2553
2554             wi = env.WhereIs('xxx', path = pathdirs_1234, pathext = '.BAT;.EXE')
2555             assert string.lower(wi) == string.lower(test.workpath(sub3_xxx_exe)), wi
2556
2557             # Test that we return a normalized path even when
2558             # the path contains forward slashes.
2559             forward_slash = test.workpath('') + '/sub3'
2560             wi = env.WhereIs('xxx', path = forward_slash, pathext = '.EXE')
2561             assert string.lower(wi) == string.lower(test.workpath(sub3_xxx_exe)), wi
2562
2563
2564
2565     def test_Action(self):
2566         """Test the Action() method"""
2567         import SCons.Action
2568
2569         env = self.TestEnvironment(FOO = 'xyzzy')
2570
2571         a = env.Action('foo')
2572         assert a, a
2573         assert a.__class__ is SCons.Action.CommandAction, a.__class__
2574
2575         a = env.Action('$FOO')
2576         assert a, a
2577         assert a.__class__ is SCons.Action.CommandAction, a.__class__
2578
2579         a = env.Action('$$FOO')
2580         assert a, a
2581         assert a.__class__ is SCons.Action.LazyAction, a.__class__
2582
2583         a = env.Action(['$FOO', 'foo'])
2584         assert a, a
2585         assert a.__class__ is SCons.Action.ListAction, a.__class__
2586
2587         def func(arg):
2588             pass
2589         a = env.Action(func)
2590         assert a, a
2591         assert a.__class__ is SCons.Action.FunctionAction, a.__class__
2592
2593     def test_AddPostAction(self):
2594         """Test the AddPostAction() method"""
2595         env = self.TestEnvironment(FOO='fff', BAR='bbb')
2596
2597         n = env.AddPostAction('$FOO', lambda x: x)
2598         assert str(n[0]) == 'fff', n[0]
2599
2600         n = env.AddPostAction(['ggg', '$BAR'], lambda x: x)
2601         assert str(n[0]) == 'ggg', n[0]
2602         assert str(n[1]) == 'bbb', n[1]
2603
2604     def test_AddPreAction(self):
2605         """Test the AddPreAction() method"""
2606         env = self.TestEnvironment(FOO='fff', BAR='bbb')
2607
2608         n = env.AddPreAction('$FOO', lambda x: x)
2609         assert str(n[0]) == 'fff', n[0]
2610
2611         n = env.AddPreAction(['ggg', '$BAR'], lambda x: x)
2612         assert str(n[0]) == 'ggg', n[0]
2613         assert str(n[1]) == 'bbb', n[1]
2614
2615     def test_Alias(self):
2616         """Test the Alias() method"""
2617         env = self.TestEnvironment(FOO='kkk', BAR='lll', EA='export_alias')
2618
2619         tgt = env.Alias('new_alias')[0]
2620         assert str(tgt) == 'new_alias', tgt
2621         assert tgt.sources == [], tgt.sources
2622         assert not hasattr(tgt, 'builder'), tgt.builder
2623
2624         tgt = env.Alias('None_alias', None)[0]
2625         assert str(tgt) == 'None_alias', tgt
2626         assert tgt.sources == [], tgt.sources
2627
2628         tgt = env.Alias('empty_list', [])[0]
2629         assert str(tgt) == 'empty_list', tgt
2630         assert tgt.sources == [], tgt.sources
2631
2632         tgt = env.Alias('export_alias', [ 'asrc1', '$FOO' ])[0]
2633         assert str(tgt) == 'export_alias', tgt
2634         assert len(tgt.sources) == 2, map(str, tgt.sources)
2635         assert str(tgt.sources[0]) == 'asrc1', map(str, tgt.sources)
2636         assert str(tgt.sources[1]) == 'kkk', map(str, tgt.sources)
2637
2638         n = env.Alias(tgt, source = ['$BAR', 'asrc4'])[0]
2639         assert n is tgt, n
2640         assert len(tgt.sources) == 4, map(str, tgt.sources)
2641         assert str(tgt.sources[2]) == 'lll', map(str, tgt.sources)
2642         assert str(tgt.sources[3]) == 'asrc4', map(str, tgt.sources)
2643
2644         n = env.Alias('$EA', 'asrc5')[0]
2645         assert n is tgt, n
2646         assert len(tgt.sources) == 5, map(str, tgt.sources)
2647         assert str(tgt.sources[4]) == 'asrc5', map(str, tgt.sources)
2648
2649         t1, t2 = env.Alias(['t1', 't2'], ['asrc6', 'asrc7'])
2650         assert str(t1) == 't1', t1
2651         assert str(t2) == 't2', t2
2652         assert len(t1.sources) == 2, map(str, t1.sources)
2653         assert str(t1.sources[0]) == 'asrc6', map(str, t1.sources)
2654         assert str(t1.sources[1]) == 'asrc7', map(str, t1.sources)
2655         assert len(t2.sources) == 2, map(str, t2.sources)
2656         assert str(t2.sources[0]) == 'asrc6', map(str, t2.sources)
2657         assert str(t2.sources[1]) == 'asrc7', map(str, t2.sources)
2658
2659         tgt = env.Alias('add', 's1')
2660         tgt = env.Alias('add', 's2')[0]
2661         s = map(str, tgt.sources)
2662         assert s == ['s1', 's2'], s
2663         tgt = env.Alias(tgt, 's3')[0]
2664         s = map(str, tgt.sources)
2665         assert s == ['s1', 's2', 's3'], s
2666
2667         tgt = env.Alias('act', None, "action1")[0]
2668         s = str(tgt.builder.action)
2669         assert s == "action1", s
2670         tgt = env.Alias('act', None, "action2")[0]
2671         s = str(tgt.builder.action)
2672         assert s == "action1\naction2", s
2673         tgt = env.Alias(tgt, None, "action3")[0]
2674         s = str(tgt.builder.action)
2675         assert s == "action1\naction2\naction3", s
2676
2677     def test_AlwaysBuild(self):
2678         """Test the AlwaysBuild() method"""
2679         env = self.TestEnvironment(FOO='fff', BAR='bbb')
2680         t = env.AlwaysBuild('a', 'b$FOO', ['c', 'd'], '$BAR',
2681                             env.fs.Dir('dir'), env.fs.File('file'))
2682         assert t[0].__class__.__name__ == 'Entry'
2683         assert t[0].path == 'a'
2684         assert t[0].always_build
2685         assert t[1].__class__.__name__ == 'Entry'
2686         assert t[1].path == 'bfff'
2687         assert t[1].always_build
2688         assert t[2].__class__.__name__ == 'Entry'
2689         assert t[2].path == 'c'
2690         assert t[2].always_build
2691         assert t[3].__class__.__name__ == 'Entry'
2692         assert t[3].path == 'd'
2693         assert t[3].always_build
2694         assert t[4].__class__.__name__ == 'Entry'
2695         assert t[4].path == 'bbb'
2696         assert t[4].always_build
2697         assert t[5].__class__.__name__ == 'Dir'
2698         assert t[5].path == 'dir'
2699         assert t[5].always_build
2700         assert t[6].__class__.__name__ == 'File'
2701         assert t[6].path == 'file'
2702         assert t[6].always_build
2703
2704     def test_VariantDir(self):
2705         """Test the VariantDir() method"""
2706         class MyFS:
2707              def Dir(self, name):
2708                  return name
2709              def VariantDir(self, variant_dir, src_dir, duplicate):
2710                  self.variant_dir = variant_dir
2711                  self.src_dir = src_dir
2712                  self.duplicate = duplicate
2713
2714         env = self.TestEnvironment(FOO = 'fff', BAR = 'bbb')
2715         env.fs = MyFS()
2716
2717         env.VariantDir('build', 'src')
2718         assert env.fs.variant_dir == 'build', env.fs.variant_dir
2719         assert env.fs.src_dir == 'src', env.fs.src_dir
2720         assert env.fs.duplicate == 1, env.fs.duplicate
2721
2722         env.VariantDir('build${FOO}', '${BAR}src', 0)
2723         assert env.fs.variant_dir == 'buildfff', env.fs.variant_dir
2724         assert env.fs.src_dir == 'bbbsrc', env.fs.src_dir
2725         assert env.fs.duplicate == 0, env.fs.duplicate
2726
2727     def test_Builder(self):
2728         """Test the Builder() method"""
2729         env = self.TestEnvironment(FOO = 'xyzzy')
2730
2731         b = env.Builder(action = 'foo')
2732         assert b is not None, b
2733
2734         b = env.Builder(action = '$FOO')
2735         assert b is not None, b
2736
2737         b = env.Builder(action = ['$FOO', 'foo'])
2738         assert b is not None, b
2739
2740         def func(arg):
2741             pass
2742         b = env.Builder(action = func)
2743         assert b is not None, b
2744         b = env.Builder(generator = func)
2745         assert b is not None, b
2746
2747     def test_CacheDir(self):
2748         """Test the CacheDir() method"""
2749         env = self.TestEnvironment(CD = 'CacheDir')
2750
2751         env.CacheDir('foo')
2752         assert env._CacheDir_path == 'foo', env._CacheDir_path
2753
2754         env.CacheDir('$CD')
2755         assert env._CacheDir_path == 'CacheDir', env._CacheDir_path
2756
2757     def test_Clean(self):
2758         """Test the Clean() method"""
2759         env = self.TestEnvironment(FOO = 'fff', BAR = 'bbb')
2760
2761         CT = SCons.Environment.CleanTargets
2762
2763         foo = env.arg2nodes('foo')[0]
2764         fff = env.arg2nodes('fff')[0]
2765
2766         t = env.Clean('foo', 'aaa')
2767         l = map(str, CT[foo])
2768         assert l == ['aaa'], l
2769
2770         t = env.Clean(foo, ['$BAR', 'ccc'])
2771         l = map(str, CT[foo])
2772         assert l == ['aaa', 'bbb', 'ccc'], l
2773
2774         eee = env.arg2nodes('eee')[0]
2775
2776         t = env.Clean('$FOO', 'ddd')
2777         l = map(str, CT[fff])
2778         assert l == ['ddd'], l
2779         t = env.Clean(fff, [eee, 'fff'])
2780         l = map(str, CT[fff])
2781         assert l == ['ddd', 'eee', 'fff'], l
2782
2783     def test_Command(self):
2784         """Test the Command() method."""
2785         env = Environment()
2786         t = env.Command(target='foo.out', source=['foo1.in', 'foo2.in'],
2787                         action='buildfoo $target $source')[0]
2788         assert t.builder is not None
2789         assert t.builder.action.__class__.__name__ == 'CommandAction'
2790         assert t.builder.action.cmd_list == 'buildfoo $target $source'
2791         assert 'foo1.in' in map(lambda x: x.path, t.sources)
2792         assert 'foo2.in' in map(lambda x: x.path, t.sources)
2793
2794         sub = env.fs.Dir('sub')
2795         t = env.Command(target='bar.out', source='sub',
2796                         action='buildbar $target $source')[0]
2797         assert 'sub' in map(lambda x: x.path, t.sources)
2798
2799         def testFunc(env, target, source):
2800             assert str(target[0]) == 'foo.out'
2801             assert 'foo1.in' in map(str, source) and 'foo2.in' in map(str, source), map(str, source)
2802             return 0
2803         t = env.Command(target='foo.out', source=['foo1.in','foo2.in'],
2804                         action=testFunc)[0]
2805         assert t.builder is not None
2806         assert t.builder.action.__class__.__name__ == 'FunctionAction'
2807         t.build()
2808         assert 'foo1.in' in map(lambda x: x.path, t.sources)
2809         assert 'foo2.in' in map(lambda x: x.path, t.sources)
2810
2811         x = []
2812         def test2(baz, x=x):
2813             x.append(baz)
2814         env = self.TestEnvironment(TEST2 = test2)
2815         t = env.Command(target='baz.out', source='baz.in',
2816                         action='${TEST2(XYZ)}',
2817                         XYZ='magic word')[0]
2818         assert t.builder is not None
2819         t.build()
2820         assert x[0] == 'magic word', x
2821
2822         t = env.Command(target='${X}.out', source='${X}.in',
2823                         action = 'foo',
2824                         X = 'xxx')[0]
2825         assert str(t) == 'xxx.out', str(t)
2826         assert 'xxx.in' in map(lambda x: x.path, t.sources)
2827
2828         env = self.TestEnvironment(source_scanner = 'should_not_find_this')
2829         t = env.Command(target='file.out', source='file.in',
2830                         action = 'foo',
2831                         source_scanner = 'fake')[0]
2832         assert t.builder.source_scanner == 'fake', t.builder.source_scanner
2833
2834     def test_Configure(self):
2835         """Test the Configure() method"""
2836         # Configure() will write to a local temporary file.
2837         test = TestCmd.TestCmd(workdir = '')
2838         save = os.getcwd()
2839
2840         try:
2841             os.chdir(test.workpath())
2842
2843             env = self.TestEnvironment(FOO = 'xyzzy')
2844
2845             def func(arg):
2846                 pass
2847
2848             c = env.Configure()
2849             assert c is not None, c
2850             c.Finish()
2851
2852             c = env.Configure(custom_tests = {'foo' : func, '$FOO' : func})
2853             assert c is not None, c
2854             assert hasattr(c, 'foo')
2855             assert hasattr(c, 'xyzzy')
2856             c.Finish()
2857         finally:
2858             os.chdir(save)
2859
2860     def test_Depends(self):
2861         """Test the explicit Depends method."""
2862         env = self.TestEnvironment(FOO = 'xxx', BAR='yyy')
2863         env.Dir('dir1')
2864         env.Dir('dir2')
2865         env.File('xxx.py')
2866         env.File('yyy.py')
2867         t = env.Depends(target='EnvironmentTest.py',
2868                         dependency='Environment.py')[0]
2869         assert t.__class__.__name__ == 'Entry', t.__class__.__name__
2870         assert t.path == 'EnvironmentTest.py'
2871         assert len(t.depends) == 1
2872         d = t.depends[0]
2873         assert d.__class__.__name__ == 'Entry', d.__class__.__name__
2874         assert d.path == 'Environment.py'
2875
2876         t = env.Depends(target='${FOO}.py', dependency='${BAR}.py')[0]
2877         assert t.__class__.__name__ == 'File', t.__class__.__name__
2878         assert t.path == 'xxx.py'
2879         assert len(t.depends) == 1
2880         d = t.depends[0]
2881         assert d.__class__.__name__ == 'File', d.__class__.__name__
2882         assert d.path == 'yyy.py'
2883
2884         t = env.Depends(target='dir1', dependency='dir2')[0]
2885         assert t.__class__.__name__ == 'Dir', t.__class__.__name__
2886         assert t.path == 'dir1'
2887         assert len(t.depends) == 1
2888         d = t.depends[0]
2889         assert d.__class__.__name__ == 'Dir', d.__class__.__name__
2890         assert d.path == 'dir2'
2891
2892     def test_Dir(self):
2893         """Test the Dir() method"""
2894         class MyFS:
2895             def Dir(self, name):
2896                 return 'Dir(%s)' % name
2897
2898         env = self.TestEnvironment(FOO = 'foodir', BAR = 'bardir')
2899         env.fs = MyFS()
2900
2901         d = env.Dir('d')
2902         assert d == 'Dir(d)', d
2903
2904         d = env.Dir('$FOO')
2905         assert d == 'Dir(foodir)', d
2906
2907         d = env.Dir('${BAR}_$BAR')
2908         assert d == 'Dir(bardir_bardir)', d
2909
2910         d = env.Dir(['dir1'])
2911         assert d == ['Dir(dir1)'], d
2912
2913         d = env.Dir(['dir1', 'dir2'])
2914         assert d == ['Dir(dir1)', 'Dir(dir2)'], d
2915
2916     def test_NoClean(self):
2917         """Test the NoClean() method"""
2918         env = self.TestEnvironment(FOO='ggg', BAR='hhh')
2919         env.Dir('p_hhhb')
2920         env.File('p_d')
2921         t = env.NoClean('p_a', 'p_${BAR}b', ['p_c', 'p_d'], 'p_$FOO')
2922
2923         assert t[0].__class__.__name__ == 'Entry', t[0].__class__.__name__
2924         assert t[0].path == 'p_a'
2925         assert t[0].noclean
2926         assert t[1].__class__.__name__ == 'Dir', t[1].__class__.__name__
2927         assert t[1].path == 'p_hhhb'
2928         assert t[1].noclean
2929         assert t[2].__class__.__name__ == 'Entry', t[2].__class__.__name__
2930         assert t[2].path == 'p_c'
2931         assert t[2].noclean
2932         assert t[3].__class__.__name__ == 'File', t[3].__class__.__name__
2933         assert t[3].path == 'p_d'
2934         assert t[3].noclean
2935         assert t[4].__class__.__name__ == 'Entry', t[4].__class__.__name__
2936         assert t[4].path == 'p_ggg'
2937         assert t[4].noclean
2938
2939     def test_Dump(self):
2940         """Test the Dump() method"""
2941
2942         env = self.TestEnvironment(FOO = 'foo')
2943         assert env.Dump('FOO') == "'foo'", env.Dump('FOO')
2944         assert len(env.Dump()) > 200, env.Dump()    # no args version
2945
2946     def test_Environment(self):
2947         """Test the Environment() method"""
2948         env = self.TestEnvironment(FOO = 'xxx', BAR = 'yyy')
2949
2950         e2 = env.Environment(X = '$FOO', Y = '$BAR')
2951         assert e2['X'] == 'xxx', e2['X']
2952         assert e2['Y'] == 'yyy', e2['Y']
2953
2954     def test_Execute(self):
2955         """Test the Execute() method"""
2956
2957         class MyAction:
2958             def __init__(self, *args, **kw):
2959                 self.args = args
2960             def __call__(self, target, source, env):
2961                 return "%s executed" % self.args
2962
2963         env = Environment()
2964         env.Action = MyAction
2965
2966         result = env.Execute("foo")
2967         assert result == "foo executed", result
2968
2969     def test_Entry(self):
2970         """Test the Entry() method"""
2971         class MyFS:
2972             def Entry(self, name):
2973                 return 'Entry(%s)' % name
2974
2975         env = self.TestEnvironment(FOO = 'fooentry', BAR = 'barentry')
2976         env.fs = MyFS()
2977
2978         e = env.Entry('e')
2979         assert e == 'Entry(e)', e
2980
2981         e = env.Entry('$FOO')
2982         assert e == 'Entry(fooentry)', e
2983
2984         e = env.Entry('${BAR}_$BAR')
2985         assert e == 'Entry(barentry_barentry)', e
2986
2987         e = env.Entry(['entry1'])
2988         assert e == ['Entry(entry1)'], e
2989
2990         e = env.Entry(['entry1', 'entry2'])
2991         assert e == ['Entry(entry1)', 'Entry(entry2)'], e
2992
2993     def test_File(self):
2994         """Test the File() method"""
2995         class MyFS:
2996             def File(self, name):
2997                 return 'File(%s)' % name
2998
2999         env = self.TestEnvironment(FOO = 'foofile', BAR = 'barfile')
3000         env.fs = MyFS()
3001
3002         f = env.File('f')
3003         assert f == 'File(f)', f
3004
3005         f = env.File('$FOO')
3006         assert f == 'File(foofile)', f
3007
3008         f = env.File('${BAR}_$BAR')
3009         assert f == 'File(barfile_barfile)', f
3010
3011         f = env.File(['file1'])
3012         assert f == ['File(file1)'], f
3013
3014         f = env.File(['file1', 'file2'])
3015         assert f == ['File(file1)', 'File(file2)'], f
3016
3017     def test_FindFile(self):
3018         """Test the FindFile() method"""
3019         env = self.TestEnvironment(FOO = 'fff', BAR = 'bbb')
3020
3021         r = env.FindFile('foo', ['no_such_directory'])
3022         assert r is None, r
3023
3024         # XXX
3025
3026     def test_Flatten(self):
3027         """Test the Flatten() method"""
3028         env = Environment()
3029         l = env.Flatten([1])
3030         assert l == [1]
3031         l = env.Flatten([1, [2, [3, [4]]]])
3032         assert l == [1, 2, 3, 4], l
3033
3034     def test_GetBuildPath(self):
3035         """Test the GetBuildPath() method."""
3036         env = self.TestEnvironment(MAGIC = 'xyzzy')
3037
3038         p = env.GetBuildPath('foo')
3039         assert p == 'foo', p
3040
3041         p = env.GetBuildPath('$MAGIC')
3042         assert p == 'xyzzy', p
3043
3044     def test_Ignore(self):
3045         """Test the explicit Ignore method."""
3046         env = self.TestEnvironment(FOO='yyy', BAR='zzz')
3047         env.Dir('dir1')
3048         env.Dir('dir2')
3049         env.File('yyyzzz')
3050         env.File('zzzyyy')
3051
3052         t = env.Ignore(target='targ.py', dependency='dep.py')[0]
3053         assert t.__class__.__name__ == 'Entry', t.__class__.__name__
3054         assert t.path == 'targ.py'
3055         assert len(t.ignore) == 1
3056         i = t.ignore[0]
3057         assert i.__class__.__name__ == 'Entry', i.__class__.__name__
3058         assert i.path == 'dep.py'
3059
3060         t = env.Ignore(target='$FOO$BAR', dependency='$BAR$FOO')[0]
3061         assert t.__class__.__name__ == 'File', t.__class__.__name__
3062         assert t.path == 'yyyzzz'
3063         assert len(t.ignore) == 1
3064         i = t.ignore[0]
3065         assert i.__class__.__name__ == 'File', i.__class__.__name__
3066         assert i.path == 'zzzyyy'
3067
3068         t = env.Ignore(target='dir1', dependency='dir2')[0]
3069         assert t.__class__.__name__ == 'Dir', t.__class__.__name__
3070         assert t.path == 'dir1'
3071         assert len(t.ignore) == 1
3072         i = t.ignore[0]
3073         assert i.__class__.__name__ == 'Dir', i.__class__.__name__
3074         assert i.path == 'dir2'
3075
3076     def test_Literal(self):
3077         """Test the Literal() method"""
3078         env = self.TestEnvironment(FOO='fff', BAR='bbb')
3079         list = env.subst_list([env.Literal('$FOO'), '$BAR'])[0]
3080         assert list == ['$FOO', 'bbb'], list
3081         list = env.subst_list(['$FOO', env.Literal('$BAR')])[0]
3082         assert list == ['fff', '$BAR'], list
3083
3084     def test_Local(self):
3085         """Test the Local() method."""
3086         env = self.TestEnvironment(FOO='lll')
3087
3088         l = env.Local(env.fs.File('fff'))
3089         assert str(l[0]) == 'fff', l[0]
3090
3091         l = env.Local('ggg', '$FOO')
3092         assert str(l[0]) == 'ggg', l[0]
3093         assert str(l[1]) == 'lll', l[1]
3094
3095     def test_Precious(self):
3096         """Test the Precious() method"""
3097         env = self.TestEnvironment(FOO='ggg', BAR='hhh')
3098         env.Dir('p_hhhb')
3099         env.File('p_d')
3100         t = env.Precious('p_a', 'p_${BAR}b', ['p_c', 'p_d'], 'p_$FOO')
3101
3102         assert t[0].__class__.__name__ == 'Entry', t[0].__class__.__name__
3103         assert t[0].path == 'p_a'
3104         assert t[0].precious
3105         assert t[1].__class__.__name__ == 'Dir', t[1].__class__.__name__
3106         assert t[1].path == 'p_hhhb'
3107         assert t[1].precious
3108         assert t[2].__class__.__name__ == 'Entry', t[2].__class__.__name__
3109         assert t[2].path == 'p_c'
3110         assert t[2].precious
3111         assert t[3].__class__.__name__ == 'File', t[3].__class__.__name__
3112         assert t[3].path == 'p_d'
3113         assert t[3].precious
3114         assert t[4].__class__.__name__ == 'Entry', t[4].__class__.__name__
3115         assert t[4].path == 'p_ggg'
3116         assert t[4].precious
3117
3118     def test_Repository(self):
3119         """Test the Repository() method."""
3120         class MyFS:
3121             def __init__(self):
3122                 self.list = []
3123             def Repository(self, *dirs):
3124                 self.list.extend(list(dirs))
3125             def Dir(self, name):
3126                 return name
3127         env = self.TestEnvironment(FOO='rrr', BAR='sss')
3128         env.fs = MyFS()
3129         env.Repository('/tmp/foo')
3130         env.Repository('/tmp/$FOO', '/tmp/$BAR/foo')
3131         expect = ['/tmp/foo', '/tmp/rrr', '/tmp/sss/foo']
3132         assert env.fs.list == expect, env.fs.list
3133
3134     def test_Scanner(self):
3135         """Test the Scanner() method"""
3136         def scan(node, env, target, arg):
3137             pass
3138
3139         env = self.TestEnvironment(FOO = scan)
3140
3141         s = env.Scanner('foo')
3142         assert s is not None, s
3143
3144         s = env.Scanner(function = 'foo')
3145         assert s is not None, s
3146
3147         if 0:
3148             s = env.Scanner('$FOO')
3149             assert s is not None, s
3150
3151             s = env.Scanner(function = '$FOO')
3152             assert s is not None, s
3153
3154     def test_SConsignFile(self):
3155         """Test the SConsignFile() method"""
3156         import SCons.SConsign
3157
3158         class MyFS:
3159             SConstruct_dir = os.sep + 'dir'
3160
3161         env = self.TestEnvironment(FOO = 'SConsign',
3162                           BAR = os.path.join(os.sep, 'File'))
3163         env.fs = MyFS()
3164         env.Execute = lambda action: None
3165
3166         try:
3167             fnames = []
3168             dbms = []
3169             def capture(name, dbm_module, fnames=fnames, dbms=dbms):
3170                 fnames.append(name)
3171                 dbms.append(dbm_module)
3172
3173             save_SConsign_File = SCons.SConsign.File
3174             SCons.SConsign.File = capture
3175
3176             env.SConsignFile('foo')
3177             assert fnames[-1] == os.path.join(os.sep, 'dir', 'foo'), fnames
3178             assert dbms[-1] is None, dbms
3179
3180             env.SConsignFile('$FOO')
3181             assert fnames[-1] == os.path.join(os.sep, 'dir', 'SConsign'), fnames
3182             assert dbms[-1] is None, dbms
3183
3184             env.SConsignFile('/$FOO')
3185             assert fnames[-1] == os.sep + 'SConsign', fnames
3186             assert dbms[-1] is None, dbms
3187
3188             env.SConsignFile(os.sep + '$FOO')
3189             assert fnames[-1] == os.sep + 'SConsign', fnames
3190             assert dbms[-1] is None, dbms
3191
3192             env.SConsignFile('$BAR', 'x')
3193             assert fnames[-1] == os.path.join(os.sep, 'File'), fnames
3194             assert dbms[-1] == 'x', dbms
3195
3196             env.SConsignFile('__$BAR', 7)
3197             assert fnames[-1] == os.path.join(os.sep, 'dir', '__', 'File'), fnames
3198             assert dbms[-1] == 7, dbms
3199
3200             env.SConsignFile()
3201             assert fnames[-1] == os.path.join(os.sep, 'dir', '.sconsign'), fnames
3202             assert dbms[-1] is None, dbms
3203
3204             env.SConsignFile(None)
3205             assert fnames[-1] is None, fnames
3206             assert dbms[-1] is None, dbms
3207         finally:
3208             SCons.SConsign.File = save_SConsign_File
3209
3210     def test_SideEffect(self):
3211         """Test the SideEffect() method"""
3212         env = self.TestEnvironment(LIB='lll', FOO='fff', BAR='bbb')
3213         env.File('mylll.pdb')
3214         env.Dir('mymmm.pdb')
3215
3216         foo = env.Object('foo.obj', 'foo.cpp')[0]
3217         bar = env.Object('bar.obj', 'bar.cpp')[0]
3218         s = env.SideEffect('mylib.pdb', ['foo.obj', 'bar.obj'])[0]
3219         assert s.__class__.__name__ == 'Entry', s.__class__.__name__
3220         assert s.path == 'mylib.pdb'
3221         assert s.side_effect
3222         assert foo.side_effects == [s]
3223         assert bar.side_effects == [s]
3224
3225         fff = env.Object('fff.obj', 'fff.cpp')[0]
3226         bbb = env.Object('bbb.obj', 'bbb.cpp')[0]
3227         s = env.SideEffect('my${LIB}.pdb', ['${FOO}.obj', '${BAR}.obj'])[0]
3228         assert s.__class__.__name__ == 'File', s.__class__.__name__
3229         assert s.path == 'mylll.pdb'
3230         assert s.side_effect
3231         assert fff.side_effects == [s], fff.side_effects
3232         assert bbb.side_effects == [s], bbb.side_effects
3233
3234         ggg = env.Object('ggg.obj', 'ggg.cpp')[0]
3235         ccc = env.Object('ccc.obj', 'ccc.cpp')[0]
3236         s = env.SideEffect('mymmm.pdb', ['ggg.obj', 'ccc.obj'])[0]
3237         assert s.__class__.__name__ == 'Dir', s.__class__.__name__
3238         assert s.path == 'mymmm.pdb'
3239         assert s.side_effect
3240         assert ggg.side_effects == [s], ggg.side_effects
3241         assert ccc.side_effects == [s], ccc.side_effects
3242
3243     def test_SourceCode(self):
3244         """Test the SourceCode() method."""
3245         env = self.TestEnvironment(FOO='mmm', BAR='nnn')
3246         e = env.SourceCode('foo', None)[0]
3247         assert e.path == 'foo'
3248         s = e.src_builder()
3249         assert s is None, s
3250
3251         b = Builder()
3252         e = env.SourceCode(e, b)[0]
3253         assert e.path == 'foo'
3254         s = e.src_builder()
3255         assert s is b, s
3256
3257         e = env.SourceCode('$BAR$FOO', None)[0]
3258         assert e.path == 'nnnmmm'
3259         s = e.src_builder()
3260         assert s is None, s
3261
3262     def test_SourceSignatures(type):
3263         """Test the SourceSignatures() method"""
3264         import SCons.Errors
3265
3266         env = type.TestEnvironment(M = 'MD5', T = 'timestamp')
3267
3268         exc_caught = None
3269         try:
3270             env.SourceSignatures('invalid_type')
3271         except SCons.Errors.UserError:
3272             exc_caught = 1
3273         assert exc_caught, "did not catch expected UserError"
3274
3275         env.SourceSignatures('MD5')
3276         assert env.src_sig_type == 'MD5', env.src_sig_type
3277
3278         env.SourceSignatures('$M')
3279         assert env.src_sig_type == 'MD5', env.src_sig_type
3280
3281         env.SourceSignatures('timestamp')
3282         assert env.src_sig_type == 'timestamp', env.src_sig_type
3283
3284         env.SourceSignatures('$T')
3285         assert env.src_sig_type == 'timestamp', env.src_sig_type
3286
3287         try:
3288             import SCons.Util
3289             save_md5 = SCons.Util.md5
3290             SCons.Util.md5 = None
3291             try:
3292                 env.SourceSignatures('MD5')
3293             except SCons.Errors.UserError:
3294                 pass
3295             else:
3296                 self.fail('Did not catch expected UserError')
3297         finally:
3298             SCons.Util.md5 = save_md5
3299
3300     def test_Split(self):
3301         """Test the Split() method"""
3302         env = self.TestEnvironment(FOO='fff', BAR='bbb')
3303         s = env.Split("foo bar")
3304         assert s == ["foo", "bar"], s
3305         s = env.Split("$FOO bar")
3306         assert s == ["fff", "bar"], s
3307         s = env.Split(["foo", "bar"])
3308         assert s == ["foo", "bar"], s
3309         s = env.Split(["foo", "${BAR}-bbb"])
3310         assert s == ["foo", "bbb-bbb"], s
3311         s = env.Split("foo")
3312         assert s == ["foo"], s
3313         s = env.Split("$FOO$BAR")
3314         assert s == ["fffbbb"], s
3315
3316     def test_TargetSignatures(type):
3317         """Test the TargetSignatures() method"""
3318         import SCons.Errors
3319
3320         env = type.TestEnvironment(B = 'build', C = 'content')
3321
3322         exc_caught = None
3323         try:
3324             env.TargetSignatures('invalid_type')
3325         except SCons.Errors.UserError:
3326             exc_caught = 1
3327         assert exc_caught, "did not catch expected UserError"
3328         assert not hasattr(env, '_build_signature')
3329
3330         env.TargetSignatures('build')
3331         assert env.tgt_sig_type == 'build', env.tgt_sig_type
3332
3333         env.TargetSignatures('$B')
3334         assert env.tgt_sig_type == 'build', env.tgt_sig_type
3335
3336         env.TargetSignatures('content')
3337         assert env.tgt_sig_type == 'content', env.tgt_sig_type
3338
3339         env.TargetSignatures('$C')
3340         assert env.tgt_sig_type == 'content', env.tgt_sig_type
3341
3342         env.TargetSignatures('MD5')
3343         assert env.tgt_sig_type == 'MD5', env.tgt_sig_type
3344
3345         env.TargetSignatures('timestamp')
3346         assert env.tgt_sig_type == 'timestamp', env.tgt_sig_type
3347
3348         try:
3349             import SCons.Util
3350             save_md5 = SCons.Util.md5
3351             SCons.Util.md5 = None
3352             try:
3353                 env.TargetSignatures('MD5')
3354             except SCons.Errors.UserError:
3355                 pass
3356             else:
3357                 self.fail('Did not catch expected UserError')
3358             try:
3359                 env.TargetSignatures('content')
3360             except SCons.Errors.UserError:
3361                 pass
3362             else:
3363                 self.fail('Did not catch expected UserError')
3364         finally:
3365             SCons.Util.md5 = save_md5
3366
3367     def test_Value(self):
3368         """Test creating a Value() object
3369         """
3370         env = Environment()
3371         v1 = env.Value('a')
3372         assert v1.value == 'a', v1.value
3373
3374         value2 = 'a'
3375         v2 = env.Value(value2)
3376         assert v2.value == value2, v2.value
3377         assert v2.value is value2, v2.value
3378
3379         assert not v1 is v2
3380         assert v1.value == v2.value
3381
3382         v3 = env.Value('c', 'build-c')
3383         assert v3.value == 'c', v3.value
3384
3385
3386
3387     def test_Environment_global_variable(type):
3388         """Test setting Environment variable to an Environment.Base subclass"""
3389         class MyEnv(SCons.Environment.Base):
3390             def xxx(self, string):
3391                 return self.subst(string)
3392
3393         SCons.Environment.Environment = MyEnv
3394
3395         env = SCons.Environment.Environment(FOO = 'foo')
3396
3397         f = env.subst('$FOO')
3398         assert f == 'foo', f
3399
3400         f = env.xxx('$FOO')
3401         assert f == 'foo', f
3402
3403     def test_bad_keywords(self):
3404         """Test trying to use reserved keywords in an Environment"""
3405         added = []
3406
3407         env = self.TestEnvironment(TARGETS = 'targets',
3408                                    SOURCES = 'sources',
3409                                    SOURCE = 'source',
3410                                    TARGET = 'target',
3411                                    CHANGED_SOURCES = 'changed_sources',
3412                                    CHANGED_TARGETS = 'changed_targets',
3413                                    UNCHANGED_SOURCES = 'unchanged_sources',
3414                                    UNCHANGED_TARGETS = 'unchanged_targets',
3415                                    INIT = 'init')
3416         bad_msg = '%s is not reserved, but got omitted; see Environment.construction_var_name_ok'
3417         added.append('INIT')
3418         for x in self.reserved_variables:
3419             assert not env.has_key(x), env[x]
3420         for x in added:
3421             assert env.has_key(x), bad_msg % x
3422
3423         env.Append(TARGETS = 'targets',
3424                    SOURCES = 'sources',
3425                    SOURCE = 'source',
3426                    TARGET = 'target',
3427                    CHANGED_SOURCES = 'changed_sources',
3428                    CHANGED_TARGETS = 'changed_targets',
3429                    UNCHANGED_SOURCES = 'unchanged_sources',
3430                    UNCHANGED_TARGETS = 'unchanged_targets',
3431                    APPEND = 'append')
3432         added.append('APPEND')
3433         for x in self.reserved_variables:
3434             assert not env.has_key(x), env[x]
3435         for x in added:
3436             assert env.has_key(x), bad_msg % x
3437
3438         env.AppendUnique(TARGETS = 'targets',
3439                          SOURCES = 'sources',
3440                          SOURCE = 'source',
3441                          TARGET = 'target',
3442                          CHANGED_SOURCES = 'changed_sources',
3443                          CHANGED_TARGETS = 'changed_targets',
3444                          UNCHANGED_SOURCES = 'unchanged_sources',
3445                          UNCHANGED_TARGETS = 'unchanged_targets',
3446                          APPENDUNIQUE = 'appendunique')
3447         added.append('APPENDUNIQUE')
3448         for x in self.reserved_variables:
3449             assert not env.has_key(x), env[x]
3450         for x in added:
3451             assert env.has_key(x), bad_msg % x
3452
3453         env.Prepend(TARGETS = 'targets',
3454                     SOURCES = 'sources',
3455                     SOURCE = 'source',
3456                     TARGET = 'target',
3457                     CHANGED_SOURCES = 'changed_sources',
3458                     CHANGED_TARGETS = 'changed_targets',
3459                     UNCHANGED_SOURCES = 'unchanged_sources',
3460                     UNCHANGED_TARGETS = 'unchanged_targets',
3461                     PREPEND = 'prepend')
3462         added.append('PREPEND')
3463         for x in self.reserved_variables:
3464             assert not env.has_key(x), env[x]
3465         for x in added:
3466             assert env.has_key(x), bad_msg % x
3467
3468         env.Prepend(TARGETS = 'targets',
3469                     SOURCES = 'sources',
3470                     SOURCE = 'source',
3471                     TARGET = 'target',
3472                     CHANGED_SOURCES = 'changed_sources',
3473                     CHANGED_TARGETS = 'changed_targets',
3474                     UNCHANGED_SOURCES = 'unchanged_sources',
3475                     UNCHANGED_TARGETS = 'unchanged_targets',
3476                     PREPENDUNIQUE = 'prependunique')
3477         added.append('PREPENDUNIQUE')
3478         for x in self.reserved_variables:
3479             assert not env.has_key(x), env[x]
3480         for x in added:
3481             assert env.has_key(x), bad_msg % x
3482
3483         env.Replace(TARGETS = 'targets',
3484                     SOURCES = 'sources',
3485                     SOURCE = 'source',
3486                     TARGET = 'target',
3487                     CHANGED_SOURCES = 'changed_sources',
3488                     CHANGED_TARGETS = 'changed_targets',
3489                     UNCHANGED_SOURCES = 'unchanged_sources',
3490                     UNCHANGED_TARGETS = 'unchanged_targets',
3491                     REPLACE = 'replace')
3492         added.append('REPLACE')
3493         for x in self.reserved_variables:
3494             assert not env.has_key(x), env[x]
3495         for x in added:
3496             assert env.has_key(x), bad_msg % x
3497
3498         copy = env.Clone(TARGETS = 'targets',
3499                          SOURCES = 'sources',
3500                          SOURCE = 'source',
3501                          TARGET = 'target',
3502                          CHANGED_SOURCES = 'changed_sources',
3503                          CHANGED_TARGETS = 'changed_targets',
3504                          UNCHANGED_SOURCES = 'unchanged_sources',
3505                          UNCHANGED_TARGETS = 'unchanged_targets',
3506                          COPY = 'copy')
3507         for x in self.reserved_variables:
3508             assert not copy.has_key(x), env[x]
3509         for x in added + ['COPY']:
3510             assert copy.has_key(x), bad_msg % x
3511
3512         over = env.Override({'TARGETS' : 'targets',
3513                              'SOURCES' : 'sources',
3514                              'SOURCE' : 'source',
3515                              'TARGET' : 'target',
3516                              'CHANGED_SOURCES' : 'changed_sources',
3517                              'CHANGED_TARGETS' : 'changed_targets',
3518                              'UNCHANGED_SOURCES' : 'unchanged_sources',
3519                              'UNCHANGED_TARGETS' : 'unchanged_targets',
3520                              'OVERRIDE' : 'override'})
3521         for x in self.reserved_variables:
3522             assert not over.has_key(x), over[x]
3523         for x in added + ['OVERRIDE']:
3524             assert over.has_key(x), bad_msg % x
3525
3526     def test_parse_flags(self):
3527         '''Test the Base class parse_flags argument'''
3528         # all we have to show is that it gets to MergeFlags internally
3529         env = Environment(tools=[], parse_flags = '-X')
3530         assert env['CCFLAGS'] == ['-X'], env['CCFLAGS']
3531
3532         env = Environment(tools=[], CCFLAGS=None, parse_flags = '-Y')
3533         assert env['CCFLAGS'] == ['-Y'], env['CCFLAGS']
3534
3535         env = Environment(tools=[], CPPDEFINES = 'FOO', parse_flags = '-std=c99 -X -DBAR')
3536         assert env['CFLAGS']  == ['-std=c99'], env['CFLAGS']
3537         assert env['CCFLAGS'] == ['-X'], env['CCFLAGS']
3538         assert env['CPPDEFINES'] == ['FOO', 'BAR'], env['CPPDEFINES']
3539
3540     def test_clone_parse_flags(self):
3541         '''Test the env.Clone() parse_flags argument'''
3542         # all we have to show is that it gets to MergeFlags internally
3543         env = Environment(tools = [])
3544         env2 = env.Clone(parse_flags = '-X')
3545         assert not env.has_key('CCFLAGS')
3546         assert env2['CCFLAGS'] == ['-X'], env2['CCFLAGS']
3547
3548         env = Environment(tools = [], CCFLAGS=None)
3549         env2 = env.Clone(parse_flags = '-Y')
3550         assert env['CCFLAGS'] is None, env['CCFLAGS']
3551         assert env2['CCFLAGS'] == ['-Y'], env2['CCFLAGS']
3552
3553         env = Environment(tools = [], CPPDEFINES = 'FOO')
3554         env2 = env.Clone(parse_flags = '-std=c99 -X -DBAR')
3555         assert not env.has_key('CFLAGS')
3556         assert env2['CFLAGS']  == ['-std=c99'], env2['CFLAGS']
3557         assert not env.has_key('CCFLAGS')
3558         assert env2['CCFLAGS'] == ['-X'], env2['CCFLAGS']
3559         assert env['CPPDEFINES'] == 'FOO', env['CPPDEFINES']
3560         assert env2['CPPDEFINES'] == ['FOO','BAR'], env2['CPPDEFINES']
3561
3562
3563
3564 class OverrideEnvironmentTestCase(unittest.TestCase,TestEnvironmentFixture):
3565
3566     def setUp(self):
3567         env = Environment()
3568         env._dict = {'XXX' : 'x', 'YYY' : 'y'}
3569         env2 = OverrideEnvironment(env, {'XXX' : 'x2'})
3570         env3 = OverrideEnvironment(env2, {'XXX' : 'x3', 'YYY' : 'y3', 'ZZZ' : 'z3'})
3571         self.envs = [ env, env2, env3 ]
3572
3573     def checkpath(self, node, expect):
3574         return str(node) == os.path.normpath(expect)
3575
3576     def test___init__(self):
3577         """Test OverrideEnvironment initialization"""
3578         env, env2, env3 = self.envs
3579         assert env['XXX'] == 'x', env['XXX']
3580         assert env2['XXX'] == 'x2', env2['XXX']
3581         assert env3['XXX'] == 'x3', env3['XXX']
3582         assert env['YYY'] == 'y', env['YYY']
3583         assert env2['YYY'] == 'y', env2['YYY']
3584         assert env3['YYY'] == 'y3', env3['YYY']
3585
3586     def test___delitem__(self):
3587         """Test deleting variables from an OverrideEnvironment"""
3588         env, env2, env3 = self.envs
3589
3590         del env3['XXX']
3591         assert not env.has_key('XXX'), "env has XXX?"
3592         assert not env2.has_key('XXX'), "env2 has XXX?"
3593         assert not env3.has_key('XXX'), "env3 has XXX?"
3594
3595         del env3['YYY']
3596         assert not env.has_key('YYY'), "env has YYY?"
3597         assert not env2.has_key('YYY'), "env2 has YYY?"
3598         assert not env3.has_key('YYY'), "env3 has YYY?"
3599
3600         del env3['ZZZ']
3601         assert not env.has_key('ZZZ'), "env has ZZZ?"
3602         assert not env2.has_key('ZZZ'), "env2 has ZZZ?"
3603         assert not env3.has_key('ZZZ'), "env3 has ZZZ?"
3604
3605     def test_get(self):
3606         """Test the OverrideEnvironment get() method"""
3607         env, env2, env3 = self.envs
3608         assert env.get('XXX') == 'x', env.get('XXX')
3609         assert env2.get('XXX') == 'x2', env2.get('XXX')
3610         assert env3.get('XXX') == 'x3', env3.get('XXX')
3611         assert env.get('YYY') == 'y', env.get('YYY')
3612         assert env2.get('YYY') == 'y', env2.get('YYY')
3613         assert env3.get('YYY') == 'y3', env3.get('YYY')
3614         assert env.get('ZZZ') is None, env.get('ZZZ')
3615         assert env2.get('ZZZ') is None, env2.get('ZZZ')
3616         assert env3.get('ZZZ') == 'z3', env3.get('ZZZ')
3617
3618     def test_has_key(self):
3619         """Test the OverrideEnvironment has_key() method"""
3620         env, env2, env3 = self.envs
3621         assert env.has_key('XXX'), env.has_key('XXX')
3622         assert env2.has_key('XXX'), env2.has_key('XXX')
3623         assert env3.has_key('XXX'), env3.has_key('XXX')
3624         assert env.has_key('YYY'), env.has_key('YYY')
3625         assert env2.has_key('YYY'), env2.has_key('YYY')
3626         assert env3.has_key('YYY'), env3.has_key('YYY')
3627         assert not env.has_key('ZZZ'), env.has_key('ZZZ')
3628         assert not env2.has_key('ZZZ'), env2.has_key('ZZZ')
3629         assert env3.has_key('ZZZ'), env3.has_key('ZZZ')
3630
3631     def test_contains(self):
3632         """Test the OverrideEnvironment __contains__() method"""
3633         try:
3634             'x' in {'x':1}
3635         except TypeError:
3636             # TODO(1.5)
3637             # An early version of Python that doesn't support "in"
3638             # on dictionaries.  Just pass the test.
3639             pass
3640         else:
3641             env, env2, env3 = self.envs
3642             assert 'XXX' in env
3643             assert 'XXX' in env2
3644             assert 'XXX' in env3
3645             assert 'YYY' in env
3646             assert 'YYY' in env2
3647             assert 'YYY' in env3
3648             assert not 'ZZZ' in env
3649             assert not 'ZZZ' in env2
3650             assert 'ZZZ' in env3
3651
3652     def test_items(self):
3653         """Test the OverrideEnvironment Dictionary() method"""
3654         env, env2, env3 = self.envs
3655         items = env.Dictionary()
3656         assert items == {'XXX' : 'x', 'YYY' : 'y'}, items
3657         items = env2.Dictionary()
3658         assert items == {'XXX' : 'x2', 'YYY' : 'y'}, items
3659         items = env3.Dictionary()
3660         assert items == {'XXX' : 'x3', 'YYY' : 'y3', 'ZZZ' : 'z3'}, items
3661
3662     def test_items(self):
3663         """Test the OverrideEnvironment items() method"""
3664         env, env2, env3 = self.envs
3665         items = env.items()
3666         items.sort()
3667         assert items == [('XXX', 'x'), ('YYY', 'y')], items
3668         items = env2.items()
3669         items.sort()
3670         assert items == [('XXX', 'x2'), ('YYY', 'y')], items
3671         items = env3.items()
3672         items.sort()
3673         assert items == [('XXX', 'x3'), ('YYY', 'y3'), ('ZZZ', 'z3')], items
3674
3675     def test_gvars(self):
3676         """Test the OverrideEnvironment gvars() method"""
3677         env, env2, env3 = self.envs
3678         gvars = env.gvars()
3679         assert gvars == {'XXX' : 'x', 'YYY' : 'y'}, gvars
3680         gvars = env2.gvars()
3681         assert gvars == {'XXX' : 'x', 'YYY' : 'y'}, gvars
3682         gvars = env3.gvars()
3683         assert gvars == {'XXX' : 'x', 'YYY' : 'y'}, gvars
3684
3685     def test_lvars(self):
3686         """Test the OverrideEnvironment lvars() method"""
3687         env, env2, env3 = self.envs
3688         lvars = env.lvars()
3689         assert lvars == {}, lvars
3690         lvars = env2.lvars()
3691         assert lvars == {'XXX' : 'x2'}, lvars
3692         lvars = env3.lvars()
3693         assert lvars == {'XXX' : 'x3', 'YYY' : 'y3', 'ZZZ' : 'z3'}, lvars
3694
3695     def test_Replace(self):
3696         """Test the OverrideEnvironment Replace() method"""
3697         env, env2, env3 = self.envs
3698         assert env['XXX'] == 'x', env['XXX']
3699         assert env2['XXX'] == 'x2', env2['XXX']
3700         assert env3['XXX'] == 'x3', env3['XXX']
3701         assert env['YYY'] == 'y', env['YYY']
3702         assert env2['YYY'] == 'y', env2['YYY']
3703         assert env3['YYY'] == 'y3', env3['YYY']
3704
3705         env.Replace(YYY = 'y4')
3706
3707         assert env['XXX'] == 'x', env['XXX']
3708         assert env2['XXX'] == 'x2', env2['XXX']
3709         assert env3['XXX'] == 'x3', env3['XXX']
3710         assert env['YYY'] == 'y4', env['YYY']
3711         assert env2['YYY'] == 'y4', env2['YYY']
3712         assert env3['YYY'] == 'y3', env3['YYY']
3713
3714     # Tests a number of Base methods through an OverrideEnvironment to
3715     # make sure they handle overridden constructionv variables properly.
3716     #
3717     # The following Base methods also call self.subst(), and so could
3718     # theoretically be subject to problems with evaluating overridden
3719     # variables, but they're never really called that way in the rest
3720     # of our code, so we won't worry about them (at least for now):
3721     #
3722     # ParseConfig()
3723     # ParseDepends()
3724     # Platform()
3725     # Tool()
3726     #
3727     # Action()
3728     # Alias()
3729     # Builder()
3730     # CacheDir()
3731     # Configure()
3732     # Environment()
3733     # FindFile()
3734     # Scanner()
3735     # SourceSignatures()
3736     # TargetSignatures()
3737
3738     # It's unlikely Clone() will ever be called this way, so let the
3739     # other methods test that handling overridden values works.
3740     #def test_Clone(self):
3741     #    """Test the OverrideEnvironment Clone() method"""
3742     #    pass
3743
3744     def test_FindIxes(self):
3745         """Test the OverrideEnvironment FindIxes() method"""
3746         env, env2, env3 = self.envs
3747         x = env.FindIxes(['xaaay'], 'XXX', 'YYY')
3748         assert x == 'xaaay', x
3749         x = env2.FindIxes(['x2aaay'], 'XXX', 'YYY')
3750         assert x == 'x2aaay', x
3751         x = env3.FindIxes(['x3aaay3'], 'XXX', 'YYY')
3752         assert x == 'x3aaay3', x
3753
3754     def test_ReplaceIxes(self):
3755         """Test the OverrideEnvironment ReplaceIxes() method"""
3756         env, env2, env3 = self.envs
3757         x = env.ReplaceIxes('xaaay', 'XXX', 'YYY', 'YYY', 'XXX')
3758         assert x == 'yaaax', x
3759         x = env2.ReplaceIxes('x2aaay', 'XXX', 'YYY', 'YYY', 'XXX')
3760         assert x == 'yaaax2', x
3761         x = env3.ReplaceIxes('x3aaay3', 'XXX', 'YYY', 'YYY', 'XXX')
3762         assert x == 'y3aaax3', x
3763
3764     # It's unlikely WhereIs() will ever be called this way, so let the
3765     # other methods test that handling overridden values works.
3766     #def test_WhereIs(self):
3767     #    """Test the OverrideEnvironment WhereIs() method"""
3768     #    pass
3769
3770     def test_Dir(self):
3771         """Test the OverrideEnvironment Dir() method"""
3772         env, env2, env3 = self.envs
3773         x = env.Dir('ddir/$XXX')
3774         assert self.checkpath(x, 'ddir/x'), str(x)
3775         x = env2.Dir('ddir/$XXX')
3776         assert self.checkpath(x, 'ddir/x2'), str(x)
3777         x = env3.Dir('ddir/$XXX')
3778         assert self.checkpath(x, 'ddir/x3'), str(x)
3779
3780     def test_Entry(self):
3781         """Test the OverrideEnvironment Entry() method"""
3782         env, env2, env3 = self.envs
3783         x = env.Entry('edir/$XXX')
3784         assert self.checkpath(x, 'edir/x'), str(x)
3785         x = env2.Entry('edir/$XXX')
3786         assert self.checkpath(x, 'edir/x2'), str(x)
3787         x = env3.Entry('edir/$XXX')
3788         assert self.checkpath(x, 'edir/x3'), str(x)
3789
3790     def test_File(self):
3791         """Test the OverrideEnvironment File() method"""
3792         env, env2, env3 = self.envs
3793         x = env.File('fdir/$XXX')
3794         assert self.checkpath(x, 'fdir/x'), str(x)
3795         x = env2.File('fdir/$XXX')
3796         assert self.checkpath(x, 'fdir/x2'), str(x)
3797         x = env3.File('fdir/$XXX')
3798         assert self.checkpath(x, 'fdir/x3'), str(x)
3799
3800     def test_Split(self):
3801         """Test the OverrideEnvironment Split() method"""
3802         env, env2, env3 = self.envs
3803         env['AAA'] = '$XXX $YYY $ZZZ'
3804         x = env.Split('$AAA')
3805         assert x == ['x', 'y'], x
3806         x = env2.Split('$AAA')
3807         assert x == ['x2', 'y'], x
3808         x = env3.Split('$AAA')
3809         assert x == ['x3', 'y3', 'z3'], x
3810
3811     def test_parse_flags(self):
3812         '''Test the OverrideEnvironment parse_flags argument'''
3813         # all we have to show is that it gets to MergeFlags internally
3814         env = SubstitutionEnvironment()
3815         env2 = env.Override({'parse_flags' : '-X'})
3816         assert not env.has_key('CCFLAGS')
3817         assert env2['CCFLAGS'] == ['-X'], env2['CCFLAGS']
3818
3819         env = SubstitutionEnvironment(CCFLAGS=None)
3820         env2 = env.Override({'parse_flags' : '-Y'})
3821         assert env['CCFLAGS'] is None, env['CCFLAGS']
3822         assert env2['CCFLAGS'] == ['-Y'], env2['CCFLAGS']
3823
3824         env = SubstitutionEnvironment(CPPDEFINES = 'FOO')
3825         env2 = env.Override({'parse_flags' : '-std=c99 -X -DBAR'})
3826         assert not env.has_key('CFLAGS')
3827         assert env2['CFLAGS']  == ['-std=c99'], env2['CFLAGS']
3828         assert not env.has_key('CCFLAGS')
3829         assert env2['CCFLAGS'] == ['-X'], env2['CCFLAGS']
3830         assert env['CPPDEFINES'] == 'FOO', env['CPPDEFINES']
3831         assert env2['CPPDEFINES'] == ['FOO','BAR'], env2['CPPDEFINES']
3832
3833
3834
3835 class NoSubstitutionProxyTestCase(unittest.TestCase,TestEnvironmentFixture):
3836
3837     def test___init__(self):
3838         """Test NoSubstitutionProxy initialization"""
3839         env = self.TestEnvironment(XXX = 'x', YYY = 'y')
3840         assert env['XXX'] == 'x', env['XXX']
3841         assert env['YYY'] == 'y', env['YYY']
3842
3843         proxy = NoSubstitutionProxy(env)
3844         assert proxy['XXX'] == 'x', proxy['XXX']
3845         assert proxy['YYY'] == 'y', proxy['YYY']
3846
3847     def test_attributes(self):
3848         """Test getting and setting NoSubstitutionProxy attributes"""
3849         env = Environment()
3850         setattr(env, 'env_attr', 'value1')
3851
3852         proxy = NoSubstitutionProxy(env)
3853         setattr(proxy, 'proxy_attr', 'value2')
3854
3855         x = getattr(env, 'env_attr')
3856         assert x == 'value1', x
3857         x = getattr(proxy, 'env_attr')
3858         assert x == 'value1', x
3859
3860         x = getattr(env, 'proxy_attr')
3861         assert x == 'value2', x
3862         x = getattr(proxy, 'proxy_attr')
3863         assert x == 'value2', x
3864
3865     def test_subst(self):
3866         """Test the NoSubstitutionProxy.subst() method"""
3867         env = self.TestEnvironment(XXX = 'x', YYY = 'y')
3868         assert env['XXX'] == 'x', env['XXX']
3869         assert env['YYY'] == 'y', env['YYY']
3870
3871         proxy = NoSubstitutionProxy(env)
3872         assert proxy['XXX'] == 'x', proxy['XXX']
3873         assert proxy['YYY'] == 'y', proxy['YYY']
3874
3875         x = env.subst('$XXX')
3876         assert x == 'x', x
3877         x = proxy.subst('$XXX')
3878         assert x == '$XXX', x
3879
3880         x = proxy.subst('$YYY', raw=7, target=None, source=None,
3881                         conv=None,
3882                         extra_meaningless_keyword_argument=None)
3883         assert x == '$YYY', x
3884
3885     def test_subst_kw(self):
3886         """Test the NoSubstitutionProxy.subst_kw() method"""
3887         env = self.TestEnvironment(XXX = 'x', YYY = 'y')
3888         assert env['XXX'] == 'x', env['XXX']
3889         assert env['YYY'] == 'y', env['YYY']
3890
3891         proxy = NoSubstitutionProxy(env)
3892         assert proxy['XXX'] == 'x', proxy['XXX']
3893         assert proxy['YYY'] == 'y', proxy['YYY']
3894
3895         x = env.subst_kw({'$XXX':'$YYY'})
3896         assert x == {'x':'y'}, x
3897         x = proxy.subst_kw({'$XXX':'$YYY'})
3898         assert x == {'$XXX':'$YYY'}, x
3899
3900     def test_subst_list(self):
3901         """Test the NoSubstitutionProxy.subst_list() method"""
3902         env = self.TestEnvironment(XXX = 'x', YYY = 'y')
3903         assert env['XXX'] == 'x', env['XXX']
3904         assert env['YYY'] == 'y', env['YYY']
3905
3906         proxy = NoSubstitutionProxy(env)
3907         assert proxy['XXX'] == 'x', proxy['XXX']
3908         assert proxy['YYY'] == 'y', proxy['YYY']
3909
3910         x = env.subst_list('$XXX')
3911         assert x == [['x']], x
3912         x = proxy.subst_list('$XXX')
3913         assert x == [[]], x
3914
3915         x = proxy.subst_list('$YYY', raw=0, target=None, source=None, conv=None)
3916         assert x == [[]], x
3917
3918     def test_subst_target_source(self):
3919         """Test the NoSubstitutionProxy.subst_target_source() method"""
3920         env = self.TestEnvironment(XXX = 'x', YYY = 'y')
3921         assert env['XXX'] == 'x', env['XXX']
3922         assert env['YYY'] == 'y', env['YYY']
3923
3924         proxy = NoSubstitutionProxy(env)
3925         assert proxy['XXX'] == 'x', proxy['XXX']
3926         assert proxy['YYY'] == 'y', proxy['YYY']
3927
3928         args = ('$XXX $TARGET $SOURCE $YYY',)
3929         kw = {'target' : DummyNode('ttt'), 'source' : DummyNode('sss')}
3930         x = apply(env.subst_target_source, args, kw)
3931         assert x == 'x ttt sss y', x
3932         x = apply(proxy.subst_target_source, args, kw)
3933         assert x == ' ttt sss ', x
3934
3935 class EnvironmentVariableTestCase(unittest.TestCase):
3936
3937     def test_is_valid_construction_var(self):
3938         """Testing is_valid_construction_var()"""
3939         r = is_valid_construction_var("_a")
3940         assert r is not None, r
3941         r = is_valid_construction_var("z_")
3942         assert r is not None, r
3943         r = is_valid_construction_var("X_")
3944         assert r is not None, r
3945         r = is_valid_construction_var("2a")
3946         assert r is None, r
3947         r = is_valid_construction_var("a2_")
3948         assert r is not None, r
3949         r = is_valid_construction_var("/")
3950         assert r is None, r
3951         r = is_valid_construction_var("_/")
3952         assert r is None, r
3953         r = is_valid_construction_var("a/")
3954         assert r is None, r
3955         r = is_valid_construction_var(".b")
3956         assert r is None, r
3957         r = is_valid_construction_var("_.b")
3958         assert r is None, r
3959         r = is_valid_construction_var("b1._")
3960         assert r is None, r
3961         r = is_valid_construction_var("-b")
3962         assert r is None, r
3963         r = is_valid_construction_var("_-b")
3964         assert r is None, r
3965         r = is_valid_construction_var("b1-_")
3966         assert r is None, r
3967
3968
3969
3970 if __name__ == "__main__":
3971     suite = unittest.TestSuite()
3972     tclasses = [ SubstitutionTestCase,
3973                  BaseTestCase,
3974                  OverrideEnvironmentTestCase,
3975                  NoSubstitutionProxyTestCase,
3976                  EnvironmentVariableTestCase ]
3977     for tclass in tclasses:
3978         names = unittest.getTestCaseNames(tclass, 'test_')
3979         suite.addTests(map(tclass, names))
3980     if not unittest.TextTestRunner().run(suite).wasSuccessful():
3981         sys.exit(1)
3982
3983 # Local Variables:
3984 # tab-width:4
3985 # indent-tabs-mode:nil
3986 # End:
3987 # vim: set expandtab tabstop=4 shiftwidth=4: