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