Refactor env.Append() and env.Prepend().
[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 os
27 import string
28 import sys
29 import TestCmd
30 import unittest
31
32 from SCons.Environment import *
33 import SCons.Warnings
34
35 def diff_env(env1, env2):
36     s1 = "env1 = {\n"
37     s2 = "env2 = {\n"
38     d = {}
39     for k in env1._dict.keys() + env2._dict.keys():
40         d[k] = None
41     keys = d.keys()
42     keys.sort()
43     for k in keys:
44         if env1.has_key(k):
45            if env2.has_key(k):
46                if env1[k] != env2[k]:
47                    s1 = s1 + "    " + repr(k) + " : " + repr(env1[k]) + "\n"
48                    s2 = s2 + "    " + repr(k) + " : " + repr(env2[k]) + "\n"
49            else:
50                s1 = s1 + "    " + repr(k) + " : " + repr(env1[k]) + "\n"
51         elif env2.has_key(k):
52            s2 = s2 + "    " + repr(k) + " : " + repr(env2[k]) + "\n"
53     s1 = s1 + "}\n"
54     s2 = s2 + "}\n"
55     return s1 + s2
56
57 def diff_dict(d1, d2):
58     s1 = "d1 = {\n"
59     s2 = "d2 = {\n"
60     d = {}
61     for k in d1.keys() + d2.keys():
62         d[k] = None
63     keys = d.keys()
64     keys.sort()
65     for k in keys:
66         if d1.has_key(k):
67            if d2.has_key(k):
68                if d1[k] != d2[k]:
69                    s1 = s1 + "    " + repr(k) + " : " + repr(d1[k]) + "\n"
70                    s2 = s2 + "    " + repr(k) + " : " + repr(d2[k]) + "\n"
71            else:
72                s1 = s1 + "    " + repr(k) + " : " + repr(d1[k]) + "\n"
73         elif env2.has_key(k):
74            s2 = s2 + "    " + repr(k) + " : " + repr(d2[k]) + "\n"
75     s1 = s1 + "}\n"
76     s2 = s2 + "}\n"
77     return s1 + s2
78
79 called_it = {}
80 built_it = {}
81
82 class Builder:
83     """A dummy Builder class for testing purposes.  "Building"
84     a target is simply setting a value in the dictionary.
85     """
86     def __init__(self, name = None):
87         self.name = name
88
89     def __call__(self, env, **kw):
90         global called_it
91         called_it.update(kw)
92
93     def execute(self, target = None, **kw):
94         global built_it
95         built_it[target] = 1
96
97
98
99 scanned_it = {}
100
101 class Scanner:
102     """A dummy Scanner class for testing purposes.  "Scanning"
103     a target is simply setting a value in the dictionary.
104     """
105     def __init__(self, name, skeys=[]):
106         self.name = name
107         self.skeys = skeys
108
109     def __call__(self, filename):
110         scanned_it[filename] = 1
111
112     def __cmp__(self, other):
113         return cmp(self.__dict__, other.__dict__)
114
115
116
117 class EnvironmentTestCase(unittest.TestCase):
118
119     def test___init__(self):
120         """Test construction Environment creation
121
122         Create two with identical arguments and check that
123         they compare the same.
124         """
125         env1 = Environment(XXX = 'x', YYY = 'y')
126         env2 = Environment(XXX = 'x', YYY = 'y')
127         assert env1 == env2, diff_env(env1, env2)
128
129         assert env1['__env__'] is env1, env1['__env__']
130         assert env2['__env__'] is env2, env2['__env__']
131
132     def test_get(self):
133         """Test the get() method."""
134         env = Environment(aaa = 'AAA')
135
136         x = env.get('aaa')
137         assert x == 'AAA', x
138         x = env.get('aaa', 'XXX')
139         assert x == 'AAA', x
140         x = env.get('bbb')
141         assert x is None, x
142         x = env.get('bbb', 'XXX')
143         assert x == 'XXX', x
144
145     def test_arg2nodes(self):
146         """Test the arg2nodes method
147         """
148         env = Environment()
149         dict = {}
150         class X(SCons.Node.Node):
151             pass
152         def Factory(name, directory = None, create = 1, dict=dict, X=X):
153             if not dict.has_key(name):
154                 dict[name] = X()
155                 dict[name].name = name
156             return dict[name]
157
158         nodes = env.arg2nodes("Util.py UtilTests.py", Factory)
159         assert len(nodes) == 1, nodes
160         assert isinstance(nodes[0], X)
161         assert nodes[0].name == "Util.py UtilTests.py"
162
163         import types
164         if hasattr(types, 'UnicodeType'):
165             code = """if 1:
166                 nodes = env.arg2nodes(u"Util.py UtilTests.py", Factory)
167                 assert len(nodes) == 1, nodes
168                 assert isinstance(nodes[0], X)
169                 assert nodes[0].name == u"Util.py UtilTests.py"
170                 \n"""
171             exec code in globals(), locals()
172
173         nodes = env.arg2nodes(["Util.py", "UtilTests.py"], Factory)
174         assert len(nodes) == 2, nodes
175         assert isinstance(nodes[0], X)
176         assert isinstance(nodes[1], X)
177         assert nodes[0].name == "Util.py"
178         assert nodes[1].name == "UtilTests.py"
179
180         n1 = Factory("Util.py")
181         nodes = env.arg2nodes([n1, "UtilTests.py"], Factory)
182         assert len(nodes) == 2, nodes
183         assert isinstance(nodes[0], X)
184         assert isinstance(nodes[1], X)
185         assert nodes[0].name == "Util.py"
186         assert nodes[1].name == "UtilTests.py"
187
188         class SConsNode(SCons.Node.Node):
189             pass
190         nodes = env.arg2nodes(SConsNode())
191         assert len(nodes) == 1, nodes
192         assert isinstance(nodes[0], SConsNode), node
193
194         class OtherNode:
195             pass
196         nodes = env.arg2nodes(OtherNode())
197         assert len(nodes) == 1, nodes
198         assert isinstance(nodes[0], OtherNode), node
199
200         def lookup_a(str, F=Factory):
201             if str[0] == 'a':
202                 n = F(str)
203                 n.a = 1
204                 return n
205             else:
206                 return None
207
208         def lookup_b(str, F=Factory):
209             if str[0] == 'b':
210                 n = F(str)
211                 n.b = 1
212                 return n
213             else:
214                 return None
215
216         env_ll = env.Copy()
217         env_ll.lookup_list = [lookup_a, lookup_b]
218
219         nodes = env_ll.arg2nodes(['aaa', 'bbb', 'ccc'], Factory)
220         assert len(nodes) == 3, nodes
221
222         assert nodes[0].name == 'aaa', nodes[0]
223         assert nodes[0].a == 1, nodes[0]
224         assert not hasattr(nodes[0], 'b'), nodes[0]
225
226         assert nodes[1].name == 'bbb'
227         assert not hasattr(nodes[1], 'a'), nodes[1]
228         assert nodes[1].b == 1, nodes[1]
229
230         assert nodes[2].name == 'ccc'
231         assert not hasattr(nodes[2], 'a'), nodes[1]
232         assert not hasattr(nodes[2], 'b'), nodes[1]
233
234         def lookup_bbbb(str, F=Factory):
235             if str == 'bbbb':
236                 n = F(str)
237                 n.bbbb = 1
238                 return n
239             else:
240                 return None
241
242         def lookup_c(str, F=Factory):
243             if str[0] == 'c':
244                 n = F(str)
245                 n.c = 1
246                 return n
247             else:
248                 return None
249
250         nodes = env.arg2nodes(['bbbb', 'ccc'], Factory,
251                                      [lookup_c, lookup_bbbb, lookup_b])
252         assert len(nodes) == 2, nodes
253
254         assert nodes[0].name == 'bbbb'
255         assert not hasattr(nodes[0], 'a'), nodes[1]
256         assert not hasattr(nodes[0], 'b'), nodes[1]
257         assert nodes[0].bbbb == 1, nodes[1]
258         assert not hasattr(nodes[0], 'c'), nodes[0]
259
260         assert nodes[1].name == 'ccc'
261         assert not hasattr(nodes[1], 'a'), nodes[1]
262         assert not hasattr(nodes[1], 'b'), nodes[1]
263         assert not hasattr(nodes[1], 'bbbb'), nodes[0]
264         assert nodes[1].c == 1, nodes[1]
265
266     def test_subst(self):
267         """Test substituting construction variables within strings
268
269         Check various combinations, including recursive expansion
270         of variables into other variables.
271         """
272         env = Environment(AAA = 'a', BBB = 'b')
273         mystr = env.subst("$AAA ${AAA}A $BBBB $BBB")
274         assert mystr == "a aA b", mystr
275
276         # Changed the tests below to reflect a bug fix in
277         # subst()
278         env = Environment(AAA = '$BBB', BBB = 'b', BBBA = 'foo')
279         mystr = env.subst("$AAA ${AAA}A ${AAA}B $BBB")
280         assert mystr == "b bA bB b", mystr
281
282         env = Environment(AAA = '$BBB', BBB = '$CCC', CCC = 'c')
283         mystr = env.subst("$AAA ${AAA}A ${AAA}B $BBB")
284         assert mystr == "c cA cB c", mystr
285
286         class DummyNode:
287             def __init__(self, name):
288                 self.name = name
289             def __str__(self):
290                 return self.name
291             def rfile(self):
292                 return self
293             def get_subst_proxy(self):
294                 return self
295
296         t1 = DummyNode('t1')
297         t2 = DummyNode('t2')
298         s1 = DummyNode('s1')
299         s2 = DummyNode('s2')
300
301         env = Environment(AAA = 'aaa')
302         s = env.subst('$AAA $TARGET $SOURCES', target=[t1, t2], source=[s1, s2])
303         assert s == "aaa t1 s1 s2", s
304         s = env.subst('$AAA $TARGETS $SOURCE', target=[t1, t2], source=[s1, s2])
305         assert s == "aaa t1 t2 s1", s
306         s = env.subst('$AAA $TARGETS $SOURCE', target=[t1, t2], source=[s1, s2], dict={})
307         assert s == "aaa", s
308
309         # Test callables in the Environment
310         def foo(target, source, env, for_signature):
311             assert str(target) == 't', target
312             assert str(source) == 's', source
313             return env["FOO"]
314
315         env = Environment(BAR=foo, FOO='baz')
316         t = DummyNode('t')
317         s = DummyNode('s')
318
319         subst = env.subst('test $BAR', target=t, source=s)
320         assert subst == 'test baz', subst
321
322         # Test not calling callables in the Environment
323         if 0:
324             # This will take some serious surgery to subst() and
325             # subst_list(), so just leave these tests out until we can
326             # do that.
327             def bar(arg):
328                 pass
329
330             env = Environment(BAR=bar, FOO='$BAR')
331
332             subst = env.subst('$BAR', call=None)
333             assert subst is bar, subst
334
335             subst = env.subst('$FOO', call=None)
336             assert subst is bar, subst
337
338     def test_subst_kw(self):
339         """Test substituting construction variables within dictionaries"""
340         env = Environment(AAA = 'a', BBB = 'b')
341         kw = env.subst_kw({'$AAA' : 'aaa', 'bbb' : '$BBB'})
342         assert len(kw) == 2, kw
343         assert kw['a'] == 'aaa', kw['a']
344         assert kw['bbb'] == 'b', kw['bbb']
345
346     def test_subst_list(self):
347         """Test substituting construction variables in command lists
348         """
349         env = Environment(AAA = 'a', BBB = 'b')
350         l = env.subst_list("$AAA ${AAA}A $BBBB $BBB")
351         assert l == [["a", "aA", "b"]], l
352
353         # Changed the tests below to reflect a bug fix in
354         # subst()
355         env = Environment(AAA = '$BBB', BBB = 'b', BBBA = 'foo')
356         l = env.subst_list("$AAA ${AAA}A ${AAA}B $BBB")
357         assert l == [["b", "bA", "bB", "b"]], l
358
359         env = Environment(AAA = '$BBB', BBB = '$CCC', CCC = 'c')
360         l = env.subst_list("$AAA ${AAA}A ${AAA}B $BBB")
361         assert l == [["c", "cA", "cB", "c"]], mystr
362
363         env = Environment(AAA = '$BBB', BBB = '$CCC', CCC = [ 'a', 'b\nc' ])
364         lst = env.subst_list([ "$AAA", "B $CCC" ])
365         assert lst == [[ "a", "b"], ["c", "B a", "b"], ["c"]], lst
366
367         class DummyNode:
368             def __init__(self, name):
369                 self.name = name
370             def __str__(self):
371                 return self.name
372             def rfile(self):
373                 return self
374             def get_subst_proxy(self):
375                 return self
376
377         t1 = DummyNode('t1')
378         t2 = DummyNode('t2')
379         s1 = DummyNode('s1')
380         s2 = DummyNode('s2')
381
382         env = Environment(AAA = 'aaa')
383         s = env.subst_list('$AAA $TARGET $SOURCES', target=[t1, t2], source=[s1, s2])
384         assert s == [["aaa", "t1", "s1", "s2"]], s
385         s = env.subst_list('$AAA $TARGETS $SOURCE', target=[t1, t2], source=[s1, s2])
386         assert s == [["aaa", "t1", "t2", "s1"]], s
387         s = env.subst_list('$AAA $TARGETS $SOURCE', target=[t1, t2], source=[s1, s2], dict={})
388         assert s == [["aaa"]], s
389
390         # Test callables in the Environment
391         def foo(target, source, env, for_signature):
392             assert str(target) == 't', target
393             assert str(source) == 's', source
394             return env["FOO"]
395
396         env = Environment(BAR=foo, FOO='baz')
397         t = DummyNode('t')
398         s = DummyNode('s')
399
400         lst = env.subst_list('test $BAR', target=t, source=s)
401         assert lst == [['test', 'baz']], lst
402
403         # Test not calling callables in the Environment
404         if 0:
405             # This will take some serious surgery to subst() and
406             # subst_list(), so just leave these tests out until we can
407             # do that.
408             def bar(arg):
409                 pass
410
411             env = Environment(BAR=bar, FOO='$BAR')
412
413             subst = env.subst_list('$BAR', call=None)
414             assert subst is bar, subst
415
416             subst = env.subst_list('$FOO', call=None)
417             assert subst is bar, subst
418
419     def test_subst_path(self):
420         """Test substituting a path list
421         """
422         class MyProxy:
423             def __init__(self, val):
424                 self.val = val
425             def get(self):
426                 return self.val + '-proxy'
427
428         class MyObj:
429             pass
430
431         env = Environment(FOO='foo', BAR='bar', PROXY=MyProxy('my1'))
432
433         r = env.subst_path('$FOO')
434         assert r == ['foo'], r
435
436         r = env.subst_path(['$FOO', 'xxx', '$BAR'])
437         assert r == ['foo', 'xxx', 'bar'], r
438
439         n = MyObj()
440
441         r = env.subst_path(['$PROXY', MyProxy('my2'), n])
442         assert r == ['my1-proxy', 'my2-proxy', n], r
443
444     def test_Builder_calls(self):
445         """Test Builder calls through different environments
446         """
447         global called_it
448
449         b1 = Builder()
450         b2 = Builder()
451
452         env = Environment()
453         env.Replace(BUILDERS = { 'builder1' : b1,
454                                  'builder2' : b2 })
455         called_it = {}
456         env.builder1(target = 'out1')
457         assert called_it['target'] == 'out1', called_it
458         assert not called_it.has_key('source')
459
460         called_it = {}
461         env.builder2(target = 'out2', xyzzy = 1)
462         assert called_it['target'] == 'out2', called_it
463         assert called_it['xyzzy'] == 1, called_it
464         assert not called_it.has_key('source')
465
466         called_it = {}
467         env.builder1(foo = 'bar')
468         assert called_it['foo'] == 'bar', called_it
469         assert not called_it.has_key('target')
470         assert not called_it.has_key('source')
471
472
473
474     def test_Builder_execs(self):
475         """Test Builder execution through different environments
476
477         One environment is initialized with a single
478         Builder object, one with a list of a single Builder
479         object, and one with a list of two Builder objects.
480         """
481         global built_it
482
483         b1 = Builder()
484         b2 = Builder()
485
486         built_it = {}
487         env3 = Environment()
488         env3.Replace(BUILDERS = { 'builder1' : b1,
489                                   'builder2' : b2 })
490         env3.builder1.execute(target = 'out1')
491         env3.builder2.execute(target = 'out2')
492         env3.builder1.execute(target = 'out3')
493         assert built_it['out1']
494         assert built_it['out2']
495         assert built_it['out3']
496
497         env4 = env3.Copy()
498         assert env4.builder1.env is env4, "builder1.env (%s) == env3 (%s)?" % (env4.builder1.env, env3)
499         assert env4.builder2.env is env4, "builder2.env (%s) == env3 (%s)?" % (env4.builder1.env, env3)
500
501         # Now test BUILDERS as a dictionary.
502         built_it = {}
503         env5 = Environment(BUILDERS={ 'foo' : b1 })
504         env5['BUILDERS']['bar'] = b2
505         env5.foo.execute(target='out1')
506         env5.bar.execute(target='out2')
507         assert built_it['out1']
508         assert built_it['out2']
509
510         built_it = {}
511         env6 = Environment()
512         env6['BUILDERS'] = { 'foo' : b1,
513                              'bar' : b2 }
514         env6.foo.execute(target='out1')
515         env6.bar.execute(target='out2')
516         assert built_it['out1']
517         assert built_it['out2']
518
519     def test_Scanners(self):
520         """Test Scanner execution through different environments
521
522         One environment is initialized with a single
523         Scanner object, one with a list of a single Scanner
524         object, and one with a list of two Scanner objects.
525         """
526 #        global scanned_it
527 #
528 #       s1 = Scanner(name = 'scanner1', skeys = [".c", ".cc"])
529 #       s2 = Scanner(name = 'scanner2', skeys = [".m4"])
530 #
531 #       scanned_it = {}
532 #       env1 = Environment(SCANNERS = s1)
533 #        env1.scanner1(filename = 'out1')
534 #       assert scanned_it['out1']
535 #
536 #       scanned_it = {}
537 #       env2 = Environment(SCANNERS = [s1])
538 #        env1.scanner1(filename = 'out1')
539 #       assert scanned_it['out1']
540 #
541 #       scanned_it = {}
542 #        env3 = Environment()
543 #        env3.Replace(SCANNERS = [s1, s2])
544 #        env3.scanner1(filename = 'out1')
545 #        env3.scanner2(filename = 'out2')
546 #        env3.scanner1(filename = 'out3')
547 #       assert scanned_it['out1']
548 #       assert scanned_it['out2']
549 #       assert scanned_it['out3']
550 #
551 #       s = env3.get_scanner(".c")
552 #       assert s == s1, s
553 #       s = env3.get_scanner(skey=".m4")
554 #       assert s == s2, s
555 #       s = env3.get_scanner(".cxx")
556 #       assert s == None, s
557
558     def test_ENV(self):
559         """Test setting the external ENV in Environments
560         """
561         env = Environment()
562         assert env.Dictionary().has_key('ENV')
563
564         env = Environment(ENV = { 'PATH' : '/foo:/bar' })
565         assert env.Dictionary('ENV')['PATH'] == '/foo:/bar'
566
567     def test_ReservedVariables(self):
568         """Test generation of warnings when reserved variable names
569         are set in an environment."""
570
571         SCons.Warnings.enableWarningClass(SCons.Warnings.ReservedVariableWarning)
572         old = SCons.Warnings.warningAsException(1)
573
574         try:
575             env4 = Environment()
576             for kw in ['TARGET', 'TARGETS', 'SOURCE', 'SOURCES']:
577                 exc_caught = None
578                 try:
579                     env4[kw] = 'xyzzy'
580                 except SCons.Warnings.ReservedVariableWarning:
581                     exc_caught = 1
582                 assert exc_caught, "Did not catch ReservedVariableWarning for `%s'" % kw
583                 assert not env4.has_key(kw), "`%s' variable was incorrectly set" % kw
584         finally:
585             SCons.Warnings.warningAsException(old)
586
587     def test_IllegalVariables(self):
588         """Test that use of illegal variables raises an exception"""
589         env = Environment()
590         def test_it(var, env=env):
591             exc_caught = None
592             try:
593                 env[var] = 1
594             except SCons.Errors.UserError:
595                 exc_caught = 1
596             assert exc_caught, "did not catch UserError for '%s'" % var
597         env['aaa'] = 1
598         assert env['aaa'] == 1, env['aaa']
599         test_it('foo/bar')
600         test_it('foo.bar')
601         test_it('foo-bar')
602
603     def test_autogenerate(dict):
604         """Test autogenerating variables in a dictionary."""
605
606         def RDirs(pathlist):
607             return SCons.Node.FS.default_fs.Rsearchall(pathlist,
608                                                        clazz=SCons.Node.FS.Dir,
609                                                        must_exist=0,
610                                                        cwd=SCons.Node.FS.default_fs.Dir('xx'))
611
612         env = Environment(LIBS = [ 'foo', 'bar', 'baz' ],
613                           LIBLINKPREFIX = 'foo',
614                           LIBLINKSUFFIX = 'bar',
615                           RDirs=RDirs)
616         flags = env.subst_list('$_LIBFLAGS', 1)[0]
617         assert len(flags) == 3, flags
618         assert flags[0] == 'foobar', \
619                flags[0]
620         assert flags[1] == 'foobar', \
621                flags[1]
622         assert flags[2] == 'foobazbar', \
623                flags[2]
624
625         blat = SCons.Node.FS.default_fs.Dir('blat')
626
627         env = Environment(CPPPATH = [ 'foo', '$FOO/bar', blat ],
628                           INCPREFIX = 'foo ',
629                           INCSUFFIX = 'bar',
630                           FOO = 'baz',
631                           RDirs=RDirs)
632         flags = env.subst_list('$_CPPINCFLAGS', 1)[0]
633         assert len(flags) == 8, flags
634         assert flags[0] == '$(', \
635                flags[0]
636         assert flags[1] == os.path.normpath('foo'), \
637                flags[1]
638         assert flags[2] == os.path.normpath('xx/foobar'), \
639                flags[2]
640         assert flags[3] == os.path.normpath('foo'), \
641                flags[3]
642         assert flags[4] == os.path.normpath('xx/baz/bar'), \
643                flags[4]
644         assert flags[5] == os.path.normpath('foo'), \
645                flags[5]
646         assert flags[6] == os.path.normpath('blatbar'), \
647                flags[6]
648         assert flags[7] == '$)', \
649                flags[7]
650
651         env = Environment(F77PATH = [ 'foo', '$FOO/bar', blat ],
652                           INCPREFIX = 'foo ',
653                           INCSUFFIX = 'bar',
654                           FOO = 'baz',
655                           RDirs=RDirs)
656         flags = env.subst_list('$_F77INCFLAGS', 1)[0]
657         assert len(flags) == 8, flags
658         assert flags[0] == '$(', \
659                flags[0]
660         assert flags[1] == os.path.normpath('foo'), \
661                flags[1]
662         assert flags[2] == os.path.normpath('xx/foobar'), \
663                flags[2]
664         assert flags[3] == os.path.normpath('foo'), \
665                flags[3]
666         assert flags[4] == os.path.normpath('xx/baz/bar'), \
667                flags[4]
668         assert flags[5] == os.path.normpath('foo'), \
669                flags[5]
670         assert flags[6] == os.path.normpath('blatbar'), \
671                flags[6]
672         assert flags[7] == '$)', \
673                flags[7]
674
675         env = Environment(CPPPATH = '', F77PATH = '', LIBPATH = '',
676                           RDirs=RDirs)
677         l = env.subst_list('$_CPPINCFLAGS')
678         assert len(l[0]) == 0, l[0]
679         l = env.subst_list('$_F77INCFLAGS')
680         assert len(l[0]) == 0, l[0]
681         l = env.subst_list('$_LIBDIRFLAGS')
682         assert len(l[0]) == 0, l[0]
683
684         SCons.Node.FS.default_fs.Repository('/rep1')
685         SCons.Node.FS.default_fs.Repository('/rep2')
686         env = Environment(CPPPATH = [ 'foo', '/a/b', '$FOO/bar', blat],
687                           INCPREFIX = '-I ',
688                           INCSUFFIX = 'XXX',
689                           FOO = 'baz',
690                           RDirs=RDirs)
691         flags = env.subst_list('$_CPPINCFLAGS', 1)[0]
692         assert flags[0] == '$(', \
693                flags[0]
694         assert flags[1] == '-I', \
695                flags[1]
696         assert flags[2] == os.path.normpath('xx/fooXXX'), \
697                flags[2]
698         assert flags[3] == '-I', \
699                flags[3]
700         assert flags[4] == os.path.normpath('/rep1/xx/fooXXX'), \
701                flags[4]
702         assert flags[5] == '-I', \
703                flags[5]
704         assert flags[6] == os.path.normpath('/rep2/xx/fooXXX'), \
705                flags[6]
706         assert flags[7] == '-I', \
707                flags[7]
708         assert flags[8] == os.path.normpath('/a/bXXX'), \
709                flags[8]
710         assert flags[9] == '-I', \
711                flags[9]
712         assert flags[10] == os.path.normpath('xx/baz/barXXX'), \
713                flags[10]
714         assert flags[11] == '-I', \
715                flags[11]
716         assert flags[12] == os.path.normpath('/rep1/xx/baz/barXXX'), \
717                flags[12]
718         assert flags[13] == '-I', \
719                flags[13]
720         assert flags[14] == os.path.normpath('/rep2/xx/baz/barXXX'), \
721                flags[14]
722         assert flags[15] == '-I', \
723                flags[15]
724         assert flags[16] == os.path.normpath('blatXXX'), \
725                flags[16]
726         assert flags[17] == '$)', \
727                flags[17]
728
729     def test_platform(self):
730         """Test specifying a platform callable when instantiating."""
731         class platform:
732             def __str__(self):        return "TestPlatform"
733             def __call__(self, env):  env['XYZZY'] = 777
734
735         def tool(env):
736             env['SET_TOOL'] = 'initialized'
737             assert env['PLATFORM'] == "TestPlatform"
738
739         env = Environment(platform = platform(), tools = [tool])
740         assert env['XYZZY'] == 777, env
741         assert env['PLATFORM'] == "TestPlatform"
742         assert env['SET_TOOL'] == "initialized"
743
744     def test_Default_PLATFORM(self):
745         """Test overriding the default PLATFORM variable"""
746         class platform:
747             def __str__(self):        return "DefaultTestPlatform"
748             def __call__(self, env):  env['XYZZY'] = 888
749
750         def tool(env):
751             env['SET_TOOL'] = 'abcde'
752             assert env['PLATFORM'] == "DefaultTestPlatform"
753
754         import SCons.Defaults
755         save = SCons.Defaults.ConstructionEnvironment.copy()
756         try:
757             import SCons.Defaults
758             SCons.Defaults.ConstructionEnvironment.update({
759                 'PLATFORM' : platform(),
760             })
761             env = Environment(tools = [tool])
762             assert env['XYZZY'] == 888, env
763             assert env['PLATFORM'] == "DefaultTestPlatform"
764             assert env['SET_TOOL'] == "abcde"
765         finally:
766             SCons.Defaults.ConstructionEnvironment = save
767
768     def test_tools(self):
769         """Test specifying a tool callable when instantiating."""
770         def t1(env):
771             env['TOOL1'] = 111
772         def t2(env):
773             env['TOOL2'] = 222
774         def t3(env):
775             env['AAA'] = env['XYZ']
776         def t4(env):
777             env['TOOL4'] = 444
778         env = Environment(tools = [t1, t2, t3], XYZ = 'aaa')
779         assert env['TOOL1'] == 111, env['TOOL1']
780         assert env['TOOL2'] == 222, env
781         assert env['AAA'] == 'aaa', env
782         t4(env)
783         assert env['TOOL4'] == 444, env
784
785     def test_Default_TOOLS(self):
786         """Test overriding the default TOOLS variable"""
787         def t5(env):
788             env['TOOL5'] = 555
789         def t6(env):
790             env['TOOL6'] = 666
791         def t7(env):
792             env['BBB'] = env['XYZ']
793         def t8(env):
794             env['TOOL8'] = 888
795
796         import SCons.Defaults
797         save = SCons.Defaults.ConstructionEnvironment.copy()
798         try:
799             SCons.Defaults.ConstructionEnvironment.update({
800                 'TOOLS' : [t5, t6, t7],
801             })
802             env = Environment(XYZ = 'bbb')
803             assert env['TOOL5'] == 555, env['TOOL5']
804             assert env['TOOL6'] == 666, env
805             assert env['BBB'] == 'bbb', env
806             t8(env)
807             assert env['TOOL8'] == 888, env
808         finally:
809             SCons.Defaults.ConstructionEnvironment = save
810
811     def test_concat(self):
812         "Test _concat()"
813         e1 = Environment(PRE='pre', SUF='suf', STR='a b', LIST=['a', 'b'])
814         s = e1.subst
815         x = s("${_concat('', '', '', __env__)}")
816         assert x == '', x
817         x = s("${_concat('', [], '', __env__)}")
818         assert x == '', x
819         x = s("${_concat(PRE, '', SUF, __env__)}")
820         assert x == '', x
821         x = s("${_concat(PRE, STR, SUF, __env__)}")
822         assert x == 'prea bsuf', x
823         x = s("${_concat(PRE, LIST, SUF, __env__)}")
824         assert x == 'preasuf prebsuf', x
825
826     def test__update(self):
827         """Test the _update() method"""
828         env = Environment(X = 'x', Y = 'y', Z = 'z')
829         assert env['X'] == 'x', env['X']
830         assert env['Y'] == 'y', env['Y']
831         assert env['Z'] == 'z', env['Z']
832         env._update({'X'       : 'xxx',
833                      'TARGET'  : 't',
834                      'TARGETS' : 'ttt',
835                      'SOURCE'  : 's',
836                      'SOURCES' : 'sss',
837                      'Z'       : 'zzz'})
838         assert env['X'] == 'xxx', env['X']
839         assert env['Y'] == 'y', env['Y']
840         assert env['Z'] == 'zzz', env['Z']
841         assert env['TARGET'] == 't', env['TARGET']
842         assert env['TARGETS'] == 'ttt', env['TARGETS']
843         assert env['SOURCE'] == 's', env['SOURCE']
844         assert env['SOURCES'] == 'sss', env['SOURCES']
845
846
847
848     def test_Append(self):
849         """Test appending to construction variables in an Environment
850         """
851
852         b1 = Environment()['BUILDERS']
853         b2 = Environment()['BUILDERS']
854         assert b1 == b2, diff_dict(b1, b2)
855
856         import UserList
857         UL = UserList.UserList
858
859         cases = [
860             'a1',       'A1',           'a1A1',
861             'a2',       ['A2'],         ['a2', 'A2'],
862             'a3',       UL(['A3']),     UL(['a3', 'A3']),
863             'a4',       '',             'a4',
864             'a5',       [],             ['a5'],
865             'a6',       UL([]),         UL(['a6']),
866             'a7',       [''],           ['a7', ''],
867             'a8',       UL(['']),       UL(['a8', '']),
868
869             ['e1'],     'E1',           ['e1', 'E1'],
870             ['e2'],     ['E2'],         ['e2', 'E2'],
871             ['e3'],     UL(['E3']),     UL(['e3', 'E3']),
872             ['e4'],     '',             ['e4'],
873             ['e5'],     [],             ['e5'],
874             ['e6'],     UL([]),         UL(['e6']),
875             ['e7'],     [''],           ['e7', ''],
876             ['e8'],     UL(['']),       UL(['e8', '']),
877
878             UL(['i1']), 'I1',           UL(['i1', 'I', '1']),
879             UL(['i2']), ['I2'],         UL(['i2', 'I2']),
880             UL(['i3']), UL(['I3']),     UL(['i3', 'I3']),
881             UL(['i4']), '',             UL(['i4']),
882             UL(['i5']), [],             UL(['i5']),
883             UL(['i6']), UL([]),         UL(['i6']),
884             UL(['i7']), [''],           UL(['i7', '']),
885             UL(['i8']), UL(['']),       UL(['i8', '']),
886
887             '',         'M1',           'M1',
888             '',         ['M2'],         ['M2'],
889             '',         UL(['M3']),     UL(['M3']),
890             '',         '',             '',
891             '',         [],             [],
892             '',         UL([]),         UL([]),
893             '',         [''],           [''],
894             '',         UL(['']),       UL(['']),
895
896             [],         'N1',           ['N1'],
897             [],         ['N2'],         ['N2'],
898             [],         UL(['N3']),     UL(['N3']),
899             [],         '',             [],
900             [],         [],             [],
901             [],         UL([]),         UL([]),
902             [],         [''],           [''],
903             [],         UL(['']),       UL(['']),
904
905             UL([]),     'O1',           ['O', '1'],
906             UL([]),     ['O2'],         ['O2'],
907             UL([]),     UL(['O3']),     UL(['O3']),
908             UL([]),     '',             UL([]),
909             UL([]),     [],             UL([]),
910             UL([]),     UL([]),         UL([]),
911             UL([]),     [''],           UL(['']),
912             UL([]),     UL(['']),       UL(['']),
913
914             [''],       'P1',           ['', 'P1'],
915             [''],       ['P2'],         ['', 'P2'],
916             [''],       UL(['P3']),     UL(['', 'P3']),
917             [''],       '',             [''],
918             [''],       [],             [''],
919             [''],       UL([]),         UL(['']),
920             [''],       [''],           ['', ''],
921             [''],       UL(['']),       UL(['', '']),
922
923             UL(['']),   'Q1',           ['', 'Q', '1'],
924             UL(['']),   ['Q2'],         ['', 'Q2'],
925             UL(['']),   UL(['Q3']),     UL(['', 'Q3']),
926             UL(['']),   '',             UL(['']),
927             UL(['']),   [],             UL(['']),
928             UL(['']),   UL([]),         UL(['']),
929             UL(['']),   [''],           UL(['', '']),
930             UL(['']),   UL(['']),       UL(['', '']),
931         ]
932
933         env = Environment()
934         failed = 0
935         while cases:
936             input, append, expect = cases[:3]
937             env['XXX'] = input
938             env.Append(XXX = append)
939             result = env['XXX']
940             if result != expect:
941                 if failed == 0: print
942                 print "    %s Append %s => %s did not match %s" % \
943                       (repr(input), repr(append), repr(result), repr(expect))
944                 failed = failed + 1
945             del cases[:3]
946         assert failed == 0, "%d Append() cases failed" % failed
947
948         class C:
949             def __init__(self, name):
950                 self.name = name
951             def __str__(self):
952                 return self.name
953             def __cmp__(self, other):
954                 raise "should not compare"
955
956         ccc = C('ccc')
957
958         env2 = Environment(CCC1 = ['c1'], CCC2 = ccc)
959         env2.Append(CCC1 = ccc, CCC2 = ['c2'])
960         assert env2['CCC1'][0] == 'c1', env2['CCC1']
961         assert env2['CCC1'][1] is ccc, env2['CCC1']
962         assert env2['CCC2'][0] is ccc, env2['CCC2']
963         assert env2['CCC2'][1] == 'c2', env2['CCC2']
964
965         env3 = Environment(X = {'x1' : 7})
966         env3.Append(X = {'x1' : 8, 'x2' : 9}, Y = {'y1' : 10})
967         assert env3['X'] == {'x1': 8, 'x2': 9}, env3['X']
968         assert env3['Y'] == {'y1': 10}, env3['Y']
969
970         env4 = Environment(BUILDERS = {'z1' : 11})
971         env4.Append(BUILDERS = {'z2' : 12})
972         assert env4['BUILDERS'] == {'z1' : 11, 'z2' : 12}, env4['BUILDERS']
973         assert hasattr(env4, 'z1')
974         assert hasattr(env4, 'z2')
975
976     def test_AppendENVPath(self):
977         """Test appending to an ENV path."""
978         env1 = Environment(ENV = {'PATH': r'C:\dir\num\one;C:\dir\num\two'},
979                            MYENV = {'MYPATH': r'C:\mydir\num\one;C:\mydir\num\two'})
980         # have to include the pathsep here so that the test will work on UNIX too.
981         env1.AppendENVPath('PATH',r'C:\dir\num\two', sep = ';')
982         env1.AppendENVPath('PATH',r'C:\dir\num\three', sep = ';')
983         env1.AppendENVPath('MYPATH',r'C:\mydir\num\three','MYENV', sep = ';')
984         env1.AppendENVPath('MYPATH',r'C:\mydir\num\one','MYENV', sep = ';')
985         assert(env1['ENV']['PATH'] == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three')
986         assert(env1['MYENV']['MYPATH'] == r'C:\mydir\num\two;C:\mydir\num\three;C:\mydir\num\one')
987
988     def test_AppendUnique(self):
989         """Test appending to unique values to construction variables
990
991         This strips values that are already present when lists are
992         involved."""
993         env = Environment(AAA1 = 'a1',
994                           AAA2 = 'a2',
995                           AAA3 = 'a3',
996                           BBB1 = ['b1'],
997                           BBB2 = ['b2'],
998                           BBB3 = ['b3'])
999         env.AppendUnique(AAA1 = 'a1',
1000                          AAA2 = ['a2'],
1001                          AAA3 = ['a3', 'b', 'c', 'a3'],
1002                          BBB1 = 'b1',
1003                          BBB2 = ['b2'],
1004                          BBB3 = ['b3', 'c', 'd', 'b3'])
1005         assert env['AAA1'] == 'a1a1', env['AAA1']
1006         assert env['AAA2'] == ['a2'], env['AAA2']
1007         assert env['AAA3'] == ['a3', 'b', 'c'], env['AAA3']
1008         assert env['BBB1'] == ['b1'], env['BBB1']
1009         assert env['BBB2'] == ['b2'], env['BBB2']
1010         assert env['BBB3'] == ['b3', 'c', 'd'], env['BBB3']
1011
1012     def test_Copy(self):
1013         """Test construction Environment copying
1014
1015         Update the copy independently afterwards and check that
1016         the original remains intact (that is, no dangling
1017         references point to objects in the copied environment).
1018         Copy the original with some construction variable
1019         updates and check that the original remains intact
1020         and the copy has the updated values.
1021         """
1022         env1 = Environment(XXX = 'x', YYY = 'y')
1023         env2 = env1.Copy()
1024         env1copy = env1.Copy()
1025         env2.Replace(YYY = 'yyy')
1026         assert env1 != env2
1027         assert env1 == env1copy
1028
1029         env3 = env1.Copy(XXX = 'x3', ZZZ = 'z3')
1030         assert env3.Dictionary('XXX') == 'x3'
1031         assert env3.Dictionary('YYY') == 'y'
1032         assert env3.Dictionary('ZZZ') == 'z3'
1033         assert env1 == env1copy
1034
1035         assert env1['__env__'] is env1, env1['__env__']
1036         assert env2['__env__'] is env2, env2['__env__']
1037         assert env3['__env__'] is env3, env3['__env__']
1038
1039         # Ensure that lists and dictionaries are
1040         # deep copied, but not instances.
1041         class TestA:
1042             pass
1043         env1 = Environment(XXX=TestA(), YYY = [ 1, 2, 3 ],
1044                            ZZZ = { 1:2, 3:4 })
1045         env2=env1.Copy()
1046         env2.Dictionary('YYY').append(4)
1047         env2.Dictionary('ZZZ')[5] = 6
1048         assert env1.Dictionary('XXX') is env2.Dictionary('XXX')
1049         assert 4 in env2.Dictionary('YYY')
1050         assert not 4 in env1.Dictionary('YYY')
1051         assert env2.Dictionary('ZZZ').has_key(5)
1052         assert not env1.Dictionary('ZZZ').has_key(5)
1053
1054         #
1055         env1 = Environment(BUILDERS = {'b1' : 1})
1056         assert hasattr(env1, 'b1'), "env1.b1 was not set"
1057         assert env1.b1.env == env1, "b1.env doesn't point to env1"
1058         env2 = env1.Copy(BUILDERS = {'b2' : 2})
1059         assert hasattr(env1, 'b1'), "b1 was mistakenly cleared from env1"
1060         assert env1.b1.env == env1, "b1.env was changed"
1061         assert not hasattr(env2, 'b1'), "b1 was not cleared from env2"
1062         assert hasattr(env2, 'b2'), "env2.b2 was not set"
1063         assert env2.b2.env == env2, "b2.env doesn't point to env2"
1064
1065         # Ensure that specifying new tools in a copied environment
1066         # works.
1067         def foo(env): env['FOO'] = 1
1068         def bar(env): env['BAR'] = 2
1069         def baz(env): env['BAZ'] = 3
1070         env1 = Environment(tools=[foo])
1071         env2 = env1.Copy()
1072         env3 = env1.Copy(tools=[bar, baz])
1073
1074         assert env1.get('FOO') is 1
1075         assert env1.get('BAR') is None
1076         assert env1.get('BAZ') is None
1077         assert env2.get('FOO') is 1
1078         assert env2.get('BAR') is None
1079         assert env2.get('BAZ') is None
1080         assert env3.get('FOO') is 1
1081         assert env3.get('BAR') is 2
1082         assert env3.get('BAZ') is 3
1083
1084         # Ensure that recursive variable substitution when copying
1085         # environments works properly.
1086         env1 = Environment(CCFLAGS = '-DFOO', XYZ = '-DXYZ')
1087         env2 = env1.Copy(CCFLAGS = '$CCFLAGS -DBAR',
1088                          XYZ = ['-DABC', 'x $XYZ y', '-DDEF'])
1089         x = env2.get('CCFLAGS')
1090         assert x == '-DFOO -DBAR', x
1091         x = env2.get('XYZ')
1092         assert x == ['-DABC', 'x -DXYZ y', '-DDEF'], x
1093
1094     def test_Detect(self):
1095         """Test Detect()ing tools"""
1096         test = TestCmd.TestCmd(workdir = '')
1097         test.subdir('sub1', 'sub2')
1098         sub1 = test.workpath('sub1')
1099         sub2 = test.workpath('sub2')
1100
1101         if sys.platform == 'win32':
1102             test.write(['sub1', 'xxx'], "sub1/xxx\n")
1103             test.write(['sub2', 'xxx'], "sub2/xxx\n")
1104
1105             env = Environment(ENV = { 'PATH' : [sub1, sub2] })
1106
1107             x = env.Detect('xxx.exe')
1108             assert x is None, x
1109
1110             test.write(['sub2', 'xxx.exe'], "sub2/xxx.exe\n")
1111
1112             env = Environment(ENV = { 'PATH' : [sub1, sub2] })
1113
1114             x = env.Detect('xxx.exe')
1115             assert x == 'xxx.exe', x
1116
1117             test.write(['sub1', 'xxx.exe'], "sub1/xxx.exe\n")
1118
1119             x = env.Detect('xxx.exe')
1120             assert x == 'xxx.exe', x
1121
1122         else:
1123             test.write(['sub1', 'xxx.exe'], "sub1/xxx.exe\n")
1124             test.write(['sub2', 'xxx.exe'], "sub2/xxx.exe\n")
1125
1126             env = Environment(ENV = { 'PATH' : [sub1, sub2] })
1127
1128             x = env.Detect('xxx.exe')
1129             assert x is None, x
1130
1131             sub2_xxx_exe = test.workpath('sub2', 'xxx.exe')
1132             os.chmod(sub2_xxx_exe, 0755)
1133
1134             env = Environment(ENV = { 'PATH' : [sub1, sub2] })
1135
1136             x = env.Detect('xxx.exe')
1137             assert x == 'xxx.exe', x
1138
1139             sub1_xxx_exe = test.workpath('sub1', 'xxx.exe')
1140             os.chmod(sub1_xxx_exe, 0755)
1141
1142             x = env.Detect('xxx.exe')
1143             assert x == 'xxx.exe', x
1144
1145         env = Environment(ENV = { 'PATH' : [] })
1146         x = env.Detect('xxx.exe')
1147         assert x is None, x
1148
1149     def test_Dictionary(self):
1150         """Test retrieval of known construction variables
1151
1152         Fetch them from the Dictionary and check for well-known
1153         defaults that get inserted.
1154         """
1155         env = Environment(XXX = 'x', YYY = 'y', ZZZ = 'z')
1156         assert env.Dictionary('XXX') == 'x'
1157         assert env.Dictionary('YYY') == 'y'
1158         assert env.Dictionary('XXX', 'ZZZ') == ['x', 'z']
1159         xxx, zzz = env.Dictionary('XXX', 'ZZZ')
1160         assert xxx == 'x'
1161         assert zzz == 'z'
1162         assert env.Dictionary().has_key('BUILDERS')
1163         assert env.Dictionary().has_key('CC')
1164         assert env.Dictionary().has_key('CCFLAGS')
1165         assert env.Dictionary().has_key('ENV')
1166
1167         assert env['XXX'] == 'x'
1168         env['XXX'] = 'foo'
1169         assert env.Dictionary('XXX') == 'foo'
1170         del env['XXX']
1171         assert not env.Dictionary().has_key('XXX')
1172
1173     def test_FindIxes(self):
1174         "Test FindIxes()"
1175         env = Environment(LIBPREFIX='lib',
1176                           LIBSUFFIX='.a',
1177                           SHLIBPREFIX='lib',
1178                           SHLIBSUFFIX='.so',
1179                           PREFIX='pre',
1180                           SUFFIX='post')
1181
1182         paths = [os.path.join('dir', 'libfoo.a'),
1183                  os.path.join('dir', 'libfoo.so')]
1184
1185         assert paths[0] == env.FindIxes(paths, 'LIBPREFIX', 'LIBSUFFIX')
1186         assert paths[1] == env.FindIxes(paths, 'SHLIBPREFIX', 'SHLIBSUFFIX')
1187         assert None == env.FindIxes(paths, 'PREFIX', 'POST')
1188
1189         paths = ['libfoo.a', 'prefoopost']
1190
1191         assert paths[0] == env.FindIxes(paths, 'LIBPREFIX', 'LIBSUFFIX')
1192         assert None == env.FindIxes(paths, 'SHLIBPREFIX', 'SHLIBSUFFIX')
1193         assert paths[1] == env.FindIxes(paths, 'PREFIX', 'SUFFIX')
1194
1195     def test_Override(self):
1196         "Test overriding construction variables"
1197         env = Environment(ONE=1, TWO=2, THREE=3, FOUR=4)
1198         assert env['ONE'] == 1, env['ONE']
1199         assert env['TWO'] == 2, env['TWO']
1200         assert env['THREE'] == 3, env['THREE']
1201         assert env['FOUR'] == 4, env['FOUR']
1202
1203         env2 = env.Override({'TWO'   : '10',
1204                              'THREE' :'x $THREE y',
1205                              'FOUR'  : ['x', '$FOUR', 'y']})
1206         assert env2['ONE'] == 1, env2['ONE']
1207         assert env2['TWO'] == '10', env2['TWO']
1208         assert env2['THREE'] == 'x 3 y', env2['THREE']
1209         assert env2['FOUR'] == ['x', 4, 'y'], env2['FOUR']
1210
1211         assert env['ONE'] == 1, env['ONE']
1212         assert env['TWO'] == 2, env['TWO']
1213         assert env['THREE'] == 3, env['THREE']
1214         assert env['FOUR'] == 4, env['FOUR']
1215
1216         env2.Replace(ONE = "won")
1217         assert env2['ONE'] == "won", env2['ONE']
1218         assert env['ONE'] == 1, env['ONE']
1219
1220         assert env['__env__'] is env, env['__env__']
1221         assert env2['__env__'] is env2, env2['__env__']
1222
1223     def test_ParseConfig(self):
1224         """Test the ParseConfig() method"""
1225         env = Environment(COMMAND='command',
1226                           CPPPATH='string',
1227                           LIBPATH=['list'],
1228                           LIBS='',
1229                           CCFLAGS=[''])
1230         save_command = []
1231         orig_popen = os.popen
1232         def my_popen(command, save_command=save_command):
1233             save_command.append(command)
1234             class fake_file:
1235                 def read(self):
1236                     return "-I/usr/include/fum -Ibar -X\n" + \
1237                            "-L/usr/fax -Lfoo -lxxx abc"
1238             return fake_file()
1239         try:
1240             os.popen = my_popen
1241             libs = env.ParseConfig("fake $COMMAND")
1242             assert save_command == ['fake command'], save_command
1243             assert libs == ['abc'], libs
1244             assert env['CPPPATH'] == ['string', '/usr/include/fum', 'bar'], env['CPPPATH']
1245             assert env['LIBPATH'] == ['list', '/usr/fax', 'foo'], env['LIBPATH']
1246             assert env['LIBS'] == ['xxx'], env['LIBS']
1247             assert env['CCFLAGS'] == ['', '-X'], env['CCFLAGS']
1248         finally:
1249             os.popen = orig_popen
1250
1251     def test_Platform(self):
1252         """Test the Platform() method"""
1253         env = Environment(WIN32='win32', NONE='no-such-platform')
1254
1255         exc_caught = None
1256         try:
1257             env.Platform('does_not_exist')
1258         except SCons.Errors.UserError:
1259             exc_caught = 1
1260         assert exc_caught, "did not catch expected UserError"
1261
1262         exc_caught = None
1263         try:
1264             env.Platform('$NONE')
1265         except SCons.Errors.UserError:
1266             exc_caught = 1
1267         assert exc_caught, "did not catch expected UserError"
1268
1269         env.Platform('posix')
1270         assert env['OBJSUFFIX'] == '.o', env['OBJSUFFIX']
1271
1272         env.Platform('$WIN32')
1273         assert env['OBJSUFFIX'] == '.obj', env['OBJSUFFIX']
1274
1275     def test_Prepend(self):
1276         """Test prepending to construction variables in an Environment
1277         """
1278         import UserList
1279         UL = UserList.UserList
1280
1281         cases = [
1282             'a1',       'A1',           'A1a1',
1283             'a2',       ['A2'],         ['A2', 'a2'],
1284             'a3',       UL(['A3']),     UL(['A3', 'a3']),
1285             'a4',       '',             'a4',
1286             'a5',       [],             ['a5'],
1287             'a6',       UL([]),         UL(['a6']),
1288             'a7',       [''],           ['', 'a7'],
1289             'a8',       UL(['']),       UL(['', 'a8']),
1290
1291             ['e1'],     'E1',           ['E1', 'e1'],
1292             ['e2'],     ['E2'],         ['E2', 'e2'],
1293             ['e3'],     UL(['E3']),     UL(['E3', 'e3']),
1294             ['e4'],     '',             ['e4'],
1295             ['e5'],     [],             ['e5'],
1296             ['e6'],     UL([]),         UL(['e6']),
1297             ['e7'],     [''],           ['', 'e7'],
1298             ['e8'],     UL(['']),       UL(['', 'e8']),
1299
1300             UL(['i1']), 'I1',           UL(['I', '1', 'i1']),
1301             UL(['i2']), ['I2'],         UL(['I2', 'i2']),
1302             UL(['i3']), UL(['I3']),     UL(['I3', 'i3']),
1303             UL(['i4']), '',             UL(['i4']),
1304             UL(['i5']), [],             UL(['i5']),
1305             UL(['i6']), UL([]),         UL(['i6']),
1306             UL(['i7']), [''],           UL(['', 'i7']),
1307             UL(['i8']), UL(['']),       UL(['', 'i8']),
1308
1309             '',         'M1',           'M1',
1310             '',         ['M2'],         ['M2'],
1311             '',         UL(['M3']),     UL(['M3']),
1312             '',         '',             '',
1313             '',         [],             [],
1314             '',         UL([]),         UL([]),
1315             '',         [''],           [''],
1316             '',         UL(['']),       UL(['']),
1317
1318             [],         'N1',           ['N1'],
1319             [],         ['N2'],         ['N2'],
1320             [],         UL(['N3']),     UL(['N3']),
1321             [],         '',             [],
1322             [],         [],             [],
1323             [],         UL([]),         UL([]),
1324             [],         [''],           [''],
1325             [],         UL(['']),       UL(['']),
1326
1327             UL([]),     'O1',           UL(['O', '1']),
1328             UL([]),     ['O2'],         UL(['O2']),
1329             UL([]),     UL(['O3']),     UL(['O3']),
1330             UL([]),     '',             UL([]),
1331             UL([]),     [],             UL([]),
1332             UL([]),     UL([]),         UL([]),
1333             UL([]),     [''],           UL(['']),
1334             UL([]),     UL(['']),       UL(['']),
1335
1336             [''],       'P1',           ['P1', ''],
1337             [''],       ['P2'],         ['P2', ''],
1338             [''],       UL(['P3']),     UL(['P3', '']),
1339             [''],       '',             [''],
1340             [''],       [],             [''],
1341             [''],       UL([]),         UL(['']),
1342             [''],       [''],           ['', ''],
1343             [''],       UL(['']),       UL(['', '']),
1344
1345             UL(['']),   'Q1',           UL(['Q', '1', '']),
1346             UL(['']),   ['Q2'],         UL(['Q2', '']),
1347             UL(['']),   UL(['Q3']),     UL(['Q3', '']),
1348             UL(['']),   '',             UL(['']),
1349             UL(['']),   [],             UL(['']),
1350             UL(['']),   UL([]),         UL(['']),
1351             UL(['']),   [''],           UL(['', '']),
1352             UL(['']),   UL(['']),       UL(['', '']),
1353         ]
1354
1355         env = Environment()
1356         failed = 0
1357         while cases:
1358             input, prepend, expect = cases[:3]
1359             env['XXX'] = input
1360             env.Prepend(XXX = prepend)
1361             result = env['XXX']
1362             if result != expect:
1363                 if failed == 0: print
1364                 print "    %s Prepend %s => %s did not match %s" % \
1365                       (repr(input), repr(prepend), repr(result), repr(expect))
1366                 failed = failed + 1
1367             del cases[:3]
1368         assert failed == 0, "%d subst() cases failed" % failed
1369
1370         env3 = Environment(X = {'x1' : 7})
1371         env3.Prepend(X = {'x1' : 8, 'x2' : 9}, Y = {'y1' : 10})
1372         assert env3['X'] == {'x1': 8, 'x2' : 9}, env3['X']
1373         assert env3['Y'] == {'y1': 10}, env3['Y']
1374
1375         env4 = Environment(BUILDERS = {'z1' : 11})
1376         env4.Prepend(BUILDERS = {'z2' : 12})
1377         assert env4['BUILDERS'] == {'z1' : 11, 'z2' : 12}, env4['BUILDERS']
1378         assert hasattr(env4, 'z1')
1379         assert hasattr(env4, 'z2')
1380
1381     def test_PrependENVPath(self):
1382         """Test prepending to an ENV path."""
1383         env1 = Environment(ENV = {'PATH': r'C:\dir\num\one;C:\dir\num\two'},
1384                            MYENV = {'MYPATH': r'C:\mydir\num\one;C:\mydir\num\two'})
1385         # have to include the pathsep here so that the test will work on UNIX too.
1386         env1.PrependENVPath('PATH',r'C:\dir\num\two',sep = ';')
1387         env1.PrependENVPath('PATH',r'C:\dir\num\three',sep = ';')
1388         env1.PrependENVPath('MYPATH',r'C:\mydir\num\three','MYENV',sep = ';')
1389         env1.PrependENVPath('MYPATH',r'C:\mydir\num\one','MYENV',sep = ';')
1390         assert(env1['ENV']['PATH'] == r'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one')
1391         assert(env1['MYENV']['MYPATH'] == r'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two')
1392
1393     def test_PrependENVPath(self):
1394         """Test prepending to an ENV path."""
1395         env1 = Environment(ENV = {'PATH': r'C:\dir\num\one;C:\dir\num\two'},
1396                            MYENV = {'MYPATH': r'C:\mydir\num\one;C:\mydir\num\two'})
1397         # have to include the pathsep here so that the test will work on UNIX too.
1398         env1.PrependENVPath('PATH',r'C:\dir\num\two',sep = ';')
1399         env1.PrependENVPath('PATH',r'C:\dir\num\three',sep = ';')
1400         env1.PrependENVPath('MYPATH',r'C:\mydir\num\three','MYENV',sep = ';')
1401         env1.PrependENVPath('MYPATH',r'C:\mydir\num\one','MYENV',sep = ';')
1402         assert(env1['ENV']['PATH'] == r'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one')
1403         assert(env1['MYENV']['MYPATH'] == r'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two')
1404
1405     def test_PrependUnique(self):
1406         """Test prepending unique values to construction variables
1407
1408         This strips values that are already present when lists are
1409         involved."""
1410         env = Environment(AAA1 = 'a1',
1411                           AAA2 = 'a2',
1412                           AAA3 = 'a3',
1413                           BBB1 = ['b1'],
1414                           BBB2 = ['b2'],
1415                           BBB3 = ['b3'])
1416         env.PrependUnique(AAA1 = 'a1',
1417                           AAA2 = ['a2'],
1418                           AAA3 = ['a3', 'b', 'c', 'a3'],
1419                           BBB1 = 'b1',
1420                           BBB2 = ['b2'],
1421                           BBB3 = ['b3', 'b', 'c', 'b3'])
1422         assert env['AAA1'] == 'a1a1', env['AAA1']
1423         assert env['AAA2'] == ['a2'], env['AAA2']
1424         assert env['AAA3'] == ['b', 'c', 'a3'], env['AAA3']
1425         assert env['BBB1'] == ['b1'], env['BBB1']
1426         assert env['BBB2'] == ['b2'], env['BBB2']
1427         assert env['BBB3'] == ['b', 'c', 'b3'], env['BBB3']
1428
1429     def test_Replace(self):
1430         """Test replacing construction variables in an Environment
1431
1432         After creation of the Environment, of course.
1433         """
1434         env1 = Environment(AAA = 'a', BBB = 'b')
1435         env1.Replace(BBB = 'bbb', CCC = 'ccc')
1436
1437         env2 = Environment(AAA = 'a', BBB = 'bbb', CCC = 'ccc')
1438         assert env1 == env2, diff_env(env1, env2)
1439
1440         env3 = Environment(BUILDERS = {'b1' : 1})
1441         assert hasattr(env3, 'b1'), "b1 was not set"
1442         env3.Replace(BUILDERS = {'b2' : 2})
1443         assert not hasattr(env3, 'b1'), "b1 was not cleared"
1444         assert hasattr(env3, 'b2'), "b2 was not set"
1445
1446     def test_ReplaceIxes(self):
1447         "Test ReplaceIxes()"
1448         env = Environment(LIBPREFIX='lib',
1449                           LIBSUFFIX='.a',
1450                           SHLIBPREFIX='lib',
1451                           SHLIBSUFFIX='.so',
1452                           PREFIX='pre',
1453                           SUFFIX='post')
1454
1455         assert 'libfoo.a' == env.ReplaceIxes('libfoo.so',
1456                                              'SHLIBPREFIX', 'SHLIBSUFFIX',
1457                                              'LIBPREFIX', 'LIBSUFFIX')
1458
1459         assert os.path.join('dir', 'libfoo.a') == env.ReplaceIxes(os.path.join('dir', 'libfoo.so'),
1460                                                                    'SHLIBPREFIX', 'SHLIBSUFFIX',
1461                                                                    'LIBPREFIX', 'LIBSUFFIX')
1462
1463         assert 'libfoo.a' == env.ReplaceIxes('prefoopost',
1464                                              'PREFIX', 'SUFFIX',
1465                                              'LIBPREFIX', 'LIBSUFFIX')
1466
1467     def test_Tool(self):
1468         """Test the Tool() method"""
1469         env = Environment(LINK='link', NONE='no-such-tool')
1470
1471         exc_caught = None
1472         try:
1473             env.Tool('does_not_exist')
1474         except SCons.Errors.UserError:
1475             exc_caught = 1
1476         assert exc_caught, "did not catch expected UserError"
1477
1478         exc_caught = None
1479         try:
1480             env.Tool('$NONE')
1481         except SCons.Errors.UserError:
1482             exc_caught = 1
1483         assert exc_caught, "did not catch expected UserError"
1484
1485         # Use a non-existent toolpath directory just to make sure we
1486         # can call Tool() with the keyword argument.
1487         env.Tool('cc', toolpath=['/no/such/directory'])
1488         assert env['CC'] == 'cc', env['CC']
1489
1490         env.Tool('$LINK')
1491         assert env['LINK'] == '$SMARTLINK', env['LINK']
1492
1493     def test_WhereIs(self):
1494         """Test the WhereIs() method"""
1495         test = TestCmd.TestCmd(workdir = '')
1496
1497         sub1_xxx_exe = test.workpath('sub1', 'xxx.exe')
1498         sub2_xxx_exe = test.workpath('sub2', 'xxx.exe')
1499         sub3_xxx_exe = test.workpath('sub3', 'xxx.exe')
1500         sub4_xxx_exe = test.workpath('sub4', 'xxx.exe')
1501
1502         test.subdir('subdir', 'sub1', 'sub2', 'sub3', 'sub4')
1503
1504         if sys.platform != 'win32':
1505             test.write(sub1_xxx_exe, "\n")
1506
1507         os.mkdir(sub2_xxx_exe)
1508
1509         test.write(sub3_xxx_exe, "\n")
1510         os.chmod(sub3_xxx_exe, 0777)
1511
1512         test.write(sub4_xxx_exe, "\n")
1513         os.chmod(sub4_xxx_exe, 0777)
1514
1515         env_path = os.environ['PATH']
1516
1517         pathdirs_1234 = [ test.workpath('sub1'),
1518                           test.workpath('sub2'),
1519                           test.workpath('sub3'),
1520                           test.workpath('sub4'),
1521                         ] + string.split(env_path, os.pathsep)
1522
1523         pathdirs_1243 = [ test.workpath('sub1'),
1524                           test.workpath('sub2'),
1525                           test.workpath('sub4'),
1526                           test.workpath('sub3'),
1527                         ] + string.split(env_path, os.pathsep)
1528
1529         path = string.join(pathdirs_1234, os.pathsep)
1530         env = Environment(ENV = {'PATH' : path})
1531         wi = env.WhereIs('xxx.exe')
1532         assert wi == test.workpath(sub3_xxx_exe), wi
1533         wi = env.WhereIs('xxx.exe', pathdirs_1243)
1534         assert wi == test.workpath(sub4_xxx_exe), wi
1535         wi = env.WhereIs('xxx.exe', string.join(pathdirs_1243, os.pathsep))
1536         assert wi == test.workpath(sub4_xxx_exe), wi
1537
1538         path = string.join(pathdirs_1243, os.pathsep)
1539         env = Environment(ENV = {'PATH' : path})
1540         wi = env.WhereIs('xxx.exe')
1541         assert wi == test.workpath(sub4_xxx_exe), wi
1542         wi = env.WhereIs('xxx.exe', pathdirs_1234)
1543         assert wi == test.workpath(sub3_xxx_exe), wi
1544         wi = env.WhereIs('xxx.exe', string.join(pathdirs_1234, os.pathsep))
1545         assert wi == test.workpath(sub3_xxx_exe), wi
1546
1547         if sys.platform == 'win32':
1548             wi = env.WhereIs('xxx', pathext = '')
1549             assert wi is None, wi
1550
1551             wi = env.WhereIs('xxx', pathext = '.exe')
1552             assert wi == test.workpath(sub4_xxx_exe), wi
1553
1554             wi = env.WhereIs('xxx', path = pathdirs_1234, pathext = '.BAT;.EXE')
1555             assert string.lower(wi) == string.lower(test.workpath(sub3_xxx_exe)), wi
1556
1557             # Test that we return a normalized path even when
1558             # the path contains forward slashes.
1559             forward_slash = test.workpath('') + '/sub3'
1560             wi = env.WhereIs('xxx', path = forward_slash, pathext = '.EXE')
1561             assert string.lower(wi) == string.lower(test.workpath(sub3_xxx_exe)), wi
1562
1563
1564
1565     def test_Action(self):
1566         """Test the Action() method"""
1567         import SCons.Action
1568
1569         env = Environment(FOO = 'xyzzy')
1570
1571         a = env.Action('foo')
1572         assert a, a
1573         assert a.__class__ is SCons.Action.CommandAction, a
1574
1575         a = env.Action('$FOO')
1576         assert a, a
1577         assert a.__class__ is SCons.Action.CommandGeneratorAction, a
1578
1579         a = env.Action(['$FOO', 'foo'])
1580         assert a, a
1581         assert a.__class__ is SCons.Action.ListAction, a
1582
1583         def func(arg):
1584             pass
1585         a = env.Action(func)
1586         assert a, a
1587         assert a.__class__ is SCons.Action.FunctionAction, a
1588
1589     def test_AddPostAction(self):
1590         """Test the AddPostAction() method"""
1591         env = Environment(FOO='fff', BAR='bbb')
1592
1593         n = env.AddPostAction('$FOO', lambda x: x)
1594         assert str(n[0]) == 'fff', n[0]
1595
1596         n = env.AddPostAction(['ggg', '$BAR'], lambda x: x)
1597         assert str(n[0]) == 'ggg', n[0]
1598         assert str(n[1]) == 'bbb', n[1]
1599
1600     def test_AddPreAction(self):
1601         """Test the AddPreAction() method"""
1602         env = Environment(FOO='fff', BAR='bbb')
1603
1604         n = env.AddPreAction('$FOO', lambda x: x)
1605         assert str(n[0]) == 'fff', n[0]
1606
1607         n = env.AddPreAction(['ggg', '$BAR'], lambda x: x)
1608         assert str(n[0]) == 'ggg', n[0]
1609         assert str(n[1]) == 'bbb', n[1]
1610
1611     def test_Alias(self):
1612         """Test the Alias() method"""
1613         env = Environment(FOO='kkk', BAR='lll', EA='export_alias')
1614
1615         tgt = env.Alias('new_alias')
1616         assert str(tgt) == 'new_alias', tgt
1617         assert tgt.sources == [], tgt.sources
1618
1619         tgt = env.Alias('None_alias', None)
1620         assert str(tgt) == 'None_alias', tgt
1621         assert tgt.sources == [], tgt.sources
1622
1623         tgt = env.Alias('empty_list', [])
1624         assert str(tgt) == 'empty_list', tgt
1625         assert tgt.sources == [], tgt.sources
1626
1627         tgt = env.Alias('export_alias', [ 'asrc1', '$FOO' ])
1628         assert str(tgt) == 'export_alias', tgt
1629         assert len(tgt.sources) == 2, map(str, tgt.sources)
1630         assert str(tgt.sources[0]) == 'asrc1', map(str, tgt.sources)
1631         assert str(tgt.sources[1]) == 'kkk', map(str, tgt.sources)
1632
1633         n = env.Alias(tgt, source = ['$BAR', 'asrc4'])
1634         assert n is tgt, n
1635         assert len(tgt.sources) == 4, map(str, tgt.sources)
1636         assert str(tgt.sources[2]) == 'lll', map(str, tgt.sources)
1637         assert str(tgt.sources[3]) == 'asrc4', map(str, tgt.sources)
1638
1639         n = env.Alias('$EA', 'asrc5')
1640         assert n is tgt, n
1641         assert len(tgt.sources) == 5, map(str, tgt.sources)
1642         assert str(tgt.sources[4]) == 'asrc5', map(str, tgt.sources)
1643
1644         t1, t2 = env.Alias(['t1', 't2'], ['asrc6', 'asrc7'])
1645         assert str(t1) == 't1', t1
1646         assert str(t2) == 't2', t2
1647         assert len(t1.sources) == 2, map(str, t1.sources)
1648         assert str(t1.sources[0]) == 'asrc6', map(str, t1.sources)
1649         assert str(t1.sources[1]) == 'asrc7', map(str, t1.sources)
1650         assert len(t2.sources) == 2, map(str, t2.sources)
1651         assert str(t2.sources[0]) == 'asrc6', map(str, t2.sources)
1652         assert str(t2.sources[1]) == 'asrc7', map(str, t2.sources)
1653
1654     def test_AlwaysBuild(self):
1655         """Test the AlwaysBuild() method"""
1656         env = Environment(FOO='fff', BAR='bbb')
1657         t = env.AlwaysBuild('a', 'b$FOO', ['c', 'd'], '$BAR')
1658         assert t[0].__class__.__name__ == 'File'
1659         assert t[0].path == 'a'
1660         assert t[0].always_build
1661         assert t[1].__class__.__name__ == 'File'
1662         assert t[1].path == 'bfff'
1663         assert t[1].always_build
1664         assert t[2].__class__.__name__ == 'File'
1665         assert t[2].path == 'c'
1666         assert t[2].always_build
1667         assert t[3].__class__.__name__ == 'File'
1668         assert t[3].path == 'd'
1669         assert t[3].always_build
1670         assert t[4].__class__.__name__ == 'File'
1671         assert t[4].path == 'bbb'
1672         assert t[4].always_build
1673
1674     def test_BuildDir(self):
1675         """Test the BuildDir() method"""
1676         class MyFS:
1677              def Dir(self, name):
1678                  return name
1679              def BuildDir(self, build_dir, src_dir, duplicate):
1680                  self.build_dir = build_dir
1681                  self.src_dir = src_dir
1682                  self.duplicate = duplicate
1683
1684         env = Environment(FOO = 'fff', BAR = 'bbb')
1685         env.fs = MyFS()
1686
1687         env.BuildDir('build', 'src')
1688         assert env.fs.build_dir == 'build', env.fs.build_dir
1689         assert env.fs.src_dir == 'src', env.fs.src_dir
1690         assert env.fs.duplicate == 1, env.fs.duplicate
1691
1692         env.BuildDir('build${FOO}', '${BAR}src', 0)
1693         assert env.fs.build_dir == 'buildfff', env.fs.build_dir
1694         assert env.fs.src_dir == 'bbbsrc', env.fs.src_dir
1695         assert env.fs.duplicate == 0, env.fs.duplicate
1696
1697     def test_Builder(self):
1698         """Test the Builder() method"""
1699         env = Environment(FOO = 'xyzzy')
1700
1701         b = env.Builder(action = 'foo')
1702         assert not b is None, b
1703
1704         b = env.Builder(action = '$FOO')
1705         assert not b is None, b
1706
1707         b = env.Builder(action = ['$FOO', 'foo'])
1708         assert not b is None, b
1709
1710         def func(arg):
1711             pass
1712         b = env.Builder(action = func)
1713         assert not b is None, b
1714         b = env.Builder(generator = func)
1715         assert not b is None, b
1716
1717     def test_CacheDir(self):
1718         """Test the CacheDir() method"""
1719         class MyFS:
1720             def CacheDir(self, path):
1721                 self.CD = path
1722
1723         env = Environment(CD = 'CacheDir')
1724         env.fs = MyFS()
1725
1726         env.CacheDir('foo')
1727         assert env.fs.CD == 'foo', env.fs.CD
1728
1729         env.CacheDir('$CD')
1730         assert env.fs.CD == 'CacheDir', env.fs.CD
1731
1732     def test_Clean(self):
1733         """Test the Clean() method"""
1734         env = Environment(FOO = 'fff', BAR = 'bbb')
1735
1736         CT = SCons.Environment.CleanTargets
1737
1738         foo = env.arg2nodes('foo')[0]
1739         fff = env.arg2nodes('fff')[0]
1740
1741         t = env.Clean('foo', 'aaa')
1742         l = map(str, CT[foo])
1743         assert l == ['aaa'], l
1744
1745         t = env.Clean(foo, ['$BAR', 'ccc'])
1746         l = map(str, CT[foo])
1747         assert l == ['aaa', 'bbb', 'ccc'], l
1748
1749         eee = env.arg2nodes('eee')[0]
1750
1751         t = env.Clean('$FOO', 'ddd')
1752         l = map(str, CT[fff])
1753         assert l == ['ddd'], l
1754         t = env.Clean(fff, [eee, 'fff'])
1755         l = map(str, CT[fff])
1756         assert l == ['ddd', 'eee', 'fff'], l
1757
1758     def test_Command(self):
1759         """Test the Command() method."""
1760         env = Environment()
1761         t = env.Command(target='foo.out', source=['foo1.in', 'foo2.in'],
1762                         action='buildfoo $target $source')
1763         assert not t.builder is None
1764         assert t.builder.action.__class__.__name__ == 'CommandAction'
1765         assert t.builder.action.cmd_list == 'buildfoo $target $source'
1766         assert 'foo1.in' in map(lambda x: x.path, t.sources)
1767         assert 'foo2.in' in map(lambda x: x.path, t.sources)
1768
1769         sub = SCons.Node.FS.default_fs.Dir('sub')
1770         t = env.Command(target='bar.out', source='sub',
1771                         action='buildbar $target $source')
1772         assert 'sub' in map(lambda x: x.path, t.sources)
1773
1774         def testFunc(env, target, source):
1775             assert str(target[0]) == 'foo.out'
1776             assert 'foo1.in' in map(str, source) and 'foo2.in' in map(str, source), map(str, source)
1777             return 0
1778         t = env.Command(target='foo.out', source=['foo1.in','foo2.in'],
1779                         action=testFunc)
1780         assert not t.builder is None
1781         assert t.builder.action.__class__.__name__ == 'FunctionAction'
1782         t.build()
1783         assert 'foo1.in' in map(lambda x: x.path, t.sources)
1784         assert 'foo2.in' in map(lambda x: x.path, t.sources)
1785
1786         x = []
1787         def test2(baz, x=x):
1788             x.append(baz)
1789         env = Environment(TEST2 = test2)
1790         t = env.Command(target='baz.out', source='baz.in',
1791                         action='${TEST2(XYZ)}',
1792                         XYZ='magic word')
1793         assert not t.builder is None
1794         t.build()
1795         assert x[0] == 'magic word', x
1796
1797     def test_Configure(self):
1798         """Test the Configure() method"""
1799         # Configure() will write to a local temporary file.
1800         test = TestCmd.TestCmd(workdir = '')
1801         save = os.getcwd()
1802         # Configure() will test, if we are reading a SConscript file
1803         import SCons.Script.SConscript
1804         SCons.Script.SConscript.sconscript_reading = 1
1805
1806         try:
1807             os.chdir(test.workpath())
1808
1809             env = Environment(FOO = 'xyzzy')
1810
1811             def func(arg):
1812                 pass
1813
1814             c = env.Configure()
1815             assert not c is None, c
1816             c.Finish()
1817
1818             c = env.Configure(custom_tests = {'foo' : func, '$FOO' : func})
1819             assert not c is None, c
1820             assert hasattr(c, 'foo')
1821             assert hasattr(c, 'xyzzy')
1822             c.Finish()
1823         finally:
1824             os.chdir(save)
1825
1826     def test_Depends(self):
1827         """Test the explicit Depends method."""
1828         env = Environment(FOO = 'xxx', BAR='yyy')
1829         env.Dir('dir1')
1830         env.Dir('dir2')
1831         env.File('xxx.py')
1832         env.File('yyy.py')
1833         t = env.Depends(target='EnvironmentTest.py', dependency='Environment.py')
1834         assert t.__class__.__name__ == 'Entry', t.__class__.__name__
1835         assert t.path == 'EnvironmentTest.py'
1836         assert len(t.depends) == 1
1837         d = t.depends[0]
1838         assert d.__class__.__name__ == 'Entry', d.__class__.__name__
1839         assert d.path == 'Environment.py'
1840
1841         t = env.Depends(target='${FOO}.py', dependency='${BAR}.py')
1842         assert t.__class__.__name__ == 'File', t.__class__.__name__
1843         assert t.path == 'xxx.py'
1844         assert len(t.depends) == 1
1845         d = t.depends[0]
1846         assert d.__class__.__name__ == 'File', d.__class__.__name__
1847         assert d.path == 'yyy.py'
1848
1849         t = env.Depends(target='dir1', dependency='dir2')
1850         assert t.__class__.__name__ == 'Dir', t.__class__.__name__
1851         assert t.path == 'dir1'
1852         assert len(t.depends) == 1
1853         d = t.depends[0]
1854         assert d.__class__.__name__ == 'Dir', d.__class__.__name__
1855         assert d.path == 'dir2'
1856
1857     def test_Dir(self):
1858         """Test the Dir() method"""
1859         class MyFS:
1860             def Dir(self, name):
1861                 return 'Dir(%s)' % name
1862
1863         env = Environment(FOO = 'foodir', BAR = 'bardir')
1864         env.fs = MyFS()
1865
1866         d = env.Dir('d')
1867         assert d == 'Dir(d)', d
1868
1869         d = env.Dir('$FOO')
1870         assert d == 'Dir(foodir)', d
1871
1872         d = env.Dir('${BAR}_$BAR')
1873         assert d == 'Dir(bardir_bardir)', d
1874
1875     def test_Environment(self):
1876         """Test the Environment() method"""
1877         env = Environment(FOO = 'xxx', BAR = 'yyy')
1878
1879         e2 = env.Environment(X = '$FOO', Y = '$BAR')
1880         assert e2['X'] == 'xxx', e2['X']
1881         assert e2['Y'] == 'yyy', e2['Y']
1882
1883     def test_Execute(self):
1884         """Test the Execute() method"""
1885
1886         class MyAction:
1887             def __init__(self, *args, **kw):
1888                 self.args = args
1889             def __call__(self, target, source, env):
1890                 return "%s executed" % self.args
1891
1892         env = Environment()
1893         env.Action = MyAction
1894
1895         result = env.Execute("foo")
1896         assert result == "foo executed", result
1897
1898     def test_File(self):
1899         """Test the File() method"""
1900         class MyFS:
1901             def File(self, name):
1902                 return 'File(%s)' % name
1903
1904         env = Environment(FOO = 'foofile', BAR = 'barfile')
1905         env.fs = MyFS()
1906
1907         f = env.File('f')
1908         assert f == 'File(f)', f
1909
1910         f = env.File('$FOO')
1911         assert f == 'File(foofile)', f
1912
1913         f = env.File('${BAR}_$BAR')
1914         assert f == 'File(barfile_barfile)', f
1915
1916     def test_FindFile(self):
1917         """Test the FindFile() method"""
1918         env = Environment(FOO = 'fff', BAR = 'bbb')
1919
1920         r = env.FindFile('foo', ['no_such_directory'])
1921         assert r is None, r
1922
1923         # XXX
1924
1925     def test_GetBuildPath(self):
1926         """Test the GetBuildPath() method."""
1927         env = Environment(MAGIC = 'xyzzy')
1928
1929         p = env.GetBuildPath('foo')
1930         assert p == 'foo', p
1931
1932         p = env.GetBuildPath('$MAGIC')
1933         assert p == 'xyzzy', p
1934
1935     def test_Ignore(self):
1936         """Test the explicit Ignore method."""
1937         env = Environment(FOO='yyy', BAR='zzz')
1938         env.Dir('dir1')
1939         env.Dir('dir2')
1940         env.File('yyyzzz')
1941         env.File('zzzyyy')
1942
1943         t = env.Ignore(target='targ.py', dependency='dep.py')
1944         assert t.__class__.__name__ == 'Entry', t.__class__.__name__
1945         assert t.path == 'targ.py'
1946         assert len(t.ignore) == 1
1947         i = t.ignore[0]
1948         assert i.__class__.__name__ == 'Entry', i.__class__.__name__
1949         assert i.path == 'dep.py'
1950
1951         t = env.Ignore(target='$FOO$BAR', dependency='$BAR$FOO')
1952         assert t.__class__.__name__ == 'File', t.__class__.__name__
1953         assert t.path == 'yyyzzz'
1954         assert len(t.ignore) == 1
1955         i = t.ignore[0]
1956         assert i.__class__.__name__ == 'File', i.__class__.__name__
1957         assert i.path == 'zzzyyy'
1958
1959         t = env.Ignore(target='dir1', dependency='dir2')
1960         assert t.__class__.__name__ == 'Dir', t.__class__.__name__
1961         assert t.path == 'dir1'
1962         assert len(t.ignore) == 1
1963         i = t.ignore[0]
1964         assert i.__class__.__name__ == 'Dir', i.__class__.__name__
1965         assert i.path == 'dir2'
1966
1967     def test_Install(self):
1968         """Test the Install method"""
1969         env = Environment(FOO='iii', BAR='jjj')
1970
1971         tgt = env.Install('export', [ 'build/foo1', 'build/foo2' ])
1972         paths = map(str, tgt)
1973         paths.sort()
1974         expect = map(os.path.normpath, [ 'export/foo1', 'export/foo2' ])
1975         assert paths == expect, paths
1976         for tnode in tgt:
1977             assert tnode.builder == InstallBuilder
1978
1979         tgt = env.Install('$FOO', [ 'build/${BAR}1', 'build/${BAR}2' ])
1980         paths = map(str, tgt)
1981         paths.sort()
1982         expect = map(os.path.normpath, [ 'iii/jjj1', 'iii/jjj2' ])
1983         assert paths == expect, paths
1984         for tnode in tgt:
1985             assert tnode.builder == InstallBuilder
1986
1987         exc_caught = None
1988         try:
1989             tgt = env.Install('export', 'export')
1990         except SCons.Errors.UserError, e:
1991             exc_caught = 1
1992         assert exc_caught, "UserError should be thrown when Install() target is not a file."
1993         match = str(e) == "Source `export' of Install() is not a file.  Install() source must be one or more files."
1994         assert match, e
1995
1996         exc_caught = None
1997         try:
1998             tgt = env.Install('export', ['export', 'build/foo1'])
1999         except SCons.Errors.UserError, e:
2000             exc_caught = 1
2001         assert exc_caught, "UserError should be thrown when Install() target containins non-files."
2002         match = str(e) == "Source `['export', 'build/foo1']' of Install() contains one or more non-files.  Install() source must be one or more files."
2003         assert match, e
2004
2005         exc_caught = None
2006         try:
2007             tgt = env.Install('export/foo1', 'build/foo1')
2008         except SCons.Errors.UserError, e:
2009             exc_caught = 1
2010         assert exc_caught, "UserError should be thrown reversing the order of Install() targets."
2011         match = str(e) == "Target `export/foo1' of Install() is a file, but should be a directory.  Perhaps you have the Install() arguments backwards?"
2012         assert match, e
2013
2014     def test_InstallAs(self):
2015         """Test the InstallAs method"""
2016         env = Environment(FOO='iii', BAR='jjj')
2017
2018         tgt = env.InstallAs(target=string.split('foo1 foo2'),
2019                             source=string.split('bar1 bar2'))
2020         assert len(tgt) == 2, len(tgt)
2021         paths = map(lambda x: str(x.sources[0]), tgt)
2022         paths.sort()
2023         expect = map(os.path.normpath, [ 'bar1', 'bar2' ])
2024         assert paths == expect, paths
2025         for tnode in tgt:
2026             assert tnode.builder == InstallBuilder
2027
2028         tgt = env.InstallAs(target='${FOO}.t', source='${BAR}.s')
2029         assert tgt.path == 'iii.t'
2030         assert tgt.sources[0].path == 'jjj.s'
2031         assert tgt.builder == InstallBuilder
2032
2033     def test_Literal(self):
2034         """Test the Literal() method"""
2035         env = Environment(FOO='fff', BAR='bbb')
2036         list = env.subst_list([env.Literal('$FOO'), '$BAR'])[0]
2037         assert list == ['$FOO', 'bbb'], list
2038         list = env.subst_list(['$FOO', env.Literal('$BAR')])[0]
2039         assert list == ['fff', '$BAR'], list
2040
2041     def test_Local(self):
2042         """Test the Local() method."""
2043         env = Environment(FOO='lll')
2044
2045         l = env.Local(env.fs.File('fff'))
2046         assert str(l[0]) == 'fff', l[0]
2047
2048         l = env.Local('ggg', '$FOO')
2049         assert str(l[0]) == 'ggg', l[0]
2050         assert str(l[1]) == 'lll', l[1]
2051
2052     def test_Precious(self):
2053         """Test the Precious() method"""
2054         env = Environment(FOO='ggg', BAR='hhh')
2055         env.Dir('p_hhhb')
2056         env.File('p_d')
2057         t = env.Precious('p_a', 'p_${BAR}b', ['p_c', 'p_d'], 'p_$FOO')
2058
2059         assert t[0].__class__.__name__ == 'Entry', t[0].__class__.__name__
2060         assert t[0].path == 'p_a'
2061         assert t[0].precious
2062         assert t[1].__class__.__name__ == 'Dir', t[1].__class__.__name__
2063         assert t[1].path == 'p_hhhb'
2064         assert t[1].precious
2065         assert t[2].__class__.__name__ == 'Entry', t[2].__class__.__name__
2066         assert t[2].path == 'p_c'
2067         assert t[2].precious
2068         assert t[3].__class__.__name__ == 'File', t[3].__class__.__name__
2069         assert t[3].path == 'p_d'
2070         assert t[3].precious
2071         assert t[4].__class__.__name__ == 'Entry', t[4].__class__.__name__
2072         assert t[4].path == 'p_ggg'
2073         assert t[4].precious
2074
2075     def test_Repository(self):
2076         """Test the Repository() method."""
2077         class MyFS:
2078             def __init__(self):
2079                 self.list = []
2080             def Repository(self, *dirs):
2081                 self.list.extend(list(dirs))
2082             def Dir(self, name):
2083                 return name
2084         env = Environment(FOO='rrr', BAR='sss')
2085         env.fs = MyFS()
2086         env.Repository('/tmp/foo')
2087         env.Repository('/tmp/$FOO', '/tmp/$BAR/foo')
2088         expect = ['/tmp/foo', '/tmp/rrr', '/tmp/sss/foo']
2089         assert env.fs.list == expect, env.fs.list
2090
2091     def test_Scanner(self):
2092         """Test the Scanner() method"""
2093         def scan(node, env, target, arg):
2094             pass
2095
2096         env = Environment(FOO = scan)
2097
2098         s = env.Scanner('foo')
2099         assert not s is None, s
2100
2101         s = env.Scanner(function = 'foo')
2102         assert not s is None, s
2103
2104         if 0:
2105             s = env.Scanner('$FOO')
2106             assert not s is None, s
2107
2108             s = env.Scanner(function = '$FOO')
2109             assert not s is None, s
2110
2111     def test_SConsignFile(self):
2112         """Test the SConsignFile() method"""
2113         import SCons.Sig
2114
2115         class MyFS:
2116             SConstruct_dir = os.sep + 'dir'
2117
2118         env = Environment(FOO = 'SConsign',
2119                           BAR = os.path.join(os.sep, 'File'))
2120         env.fs = MyFS()
2121
2122         try:
2123             fnames = []
2124             dbms = []
2125             def capture(name, dbm_module, fnames=fnames, dbms=dbms):
2126                 fnames.append(name)
2127                 dbms.append(dbm_module)
2128
2129             save_Sig_SConsignFile = SCons.Sig.SConsignFile
2130             SCons.Sig.SConsignFile = capture
2131
2132             env.SConsignFile('foo')
2133             assert fnames[0] == os.path.join(os.sep, 'dir', 'foo'), fnames
2134             assert dbms[0] == None, dbms
2135
2136             env.SConsignFile('$FOO')
2137             assert fnames[1] == os.path.join(os.sep, 'dir', 'SConsign'), fnames
2138             assert dbms[1] == None, dbms
2139
2140             env.SConsignFile('/$FOO')
2141             assert fnames[2] == '/SConsign', fnames
2142             assert dbms[2] == None, dbms
2143
2144             env.SConsignFile('$BAR', 'x')
2145             assert fnames[3] == os.path.join(os.sep, 'File'), fnames
2146             assert dbms[3] == 'x', dbms
2147
2148             env.SConsignFile('__$BAR', 7)
2149             assert fnames[4] == os.path.join(os.sep, 'dir', '__', 'File'), fnames
2150             assert dbms[4] == 7, dbms
2151         finally:
2152             SCons.Sig.SConsignFile = save_Sig_SConsignFile
2153
2154     def test_SideEffect(self):
2155         """Test the SideEffect() method"""
2156         env = Environment(LIB='lll', FOO='fff', BAR='bbb')
2157         env.File('mylll.pdb')
2158         env.Dir('mymmm.pdb')
2159
2160         foo = env.Object('foo.obj', 'foo.cpp')
2161         bar = env.Object('bar.obj', 'bar.cpp')
2162         s = env.SideEffect('mylib.pdb', ['foo.obj', 'bar.obj'])
2163         assert s.__class__.__name__ == 'Entry', s.__class__.__name__
2164         assert s.path == 'mylib.pdb'
2165         assert s.side_effect
2166         assert foo.side_effects == [s]
2167         assert bar.side_effects == [s]
2168         assert s.depends_on([bar])
2169         assert s.depends_on([foo])
2170
2171         fff = env.Object('fff.obj', 'fff.cpp')
2172         bbb = env.Object('bbb.obj', 'bbb.cpp')
2173         s = env.SideEffect('my${LIB}.pdb', ['${FOO}.obj', '${BAR}.obj'])
2174         assert s.__class__.__name__ == 'File', s.__class__.__name__
2175         assert s.path == 'mylll.pdb'
2176         assert s.side_effect
2177         assert fff.side_effects == [s], fff.side_effects
2178         assert bbb.side_effects == [s], bbb.side_effects
2179         assert s.depends_on([bbb])
2180         assert s.depends_on([fff])
2181
2182         ggg = env.Object('ggg.obj', 'ggg.cpp')
2183         ccc = env.Object('ccc.obj', 'ccc.cpp')
2184         s = env.SideEffect('mymmm.pdb', ['ggg.obj', 'ccc.obj'])
2185         assert s.__class__.__name__ == 'Dir', s.__class__.__name__
2186         assert s.path == 'mymmm.pdb'
2187         assert s.side_effect
2188         assert ggg.side_effects == [s], ggg.side_effects
2189         assert ccc.side_effects == [s], ccc.side_effects
2190         assert s.depends_on([ccc])
2191         assert s.depends_on([ggg])
2192
2193     def test_SourceCode(self):
2194         """Test the SourceCode() method."""
2195         env = Environment(FOO='mmm', BAR='nnn')
2196         e = env.SourceCode('foo', None)
2197         assert e.path == 'foo'
2198         s = e.src_builder()
2199         assert s is None, s
2200
2201         b = Builder()
2202         e = env.SourceCode(e, b)
2203         assert e.path == 'foo'
2204         s = e.src_builder()
2205         assert s is b, s
2206
2207         e = env.SourceCode('$BAR$FOO', None)
2208         assert e.path == 'nnnmmm'
2209         s = e.src_builder()
2210         assert s is None, s
2211
2212     def test_SourceSignatures(type):
2213         """Test the SourceSignatures() method"""
2214         env = Environment(M = 'MD5', T = 'timestamp')
2215
2216         exc_caught = None
2217         try:
2218             env.SourceSignatures('invalid_type')
2219         except SCons.Errors.UserError:
2220             exc_caught = 1
2221         assert exc_caught, "did not catch expected UserError"
2222         assert not hasattr(env, '_calc_module')
2223
2224         env.SourceSignatures('MD5')
2225         m = env._calc_module
2226
2227         env.SourceSignatures('$M')
2228         assert env._calc_module is m
2229
2230         env.SourceSignatures('timestamp')
2231         t = env._calc_module
2232
2233         env.SourceSignatures('$T')
2234         assert env._calc_module is t
2235
2236     def test_Split(self):
2237         """Test the Split() method"""
2238         env = Environment(FOO='fff', BAR='bbb')
2239         s = env.Split("foo bar")
2240         assert s == ["foo", "bar"], s
2241         s = env.Split("$FOO bar")
2242         assert s == ["fff", "bar"], s
2243         s = env.Split(["foo", "bar"])
2244         assert s == ["foo", "bar"], s
2245         s = env.Split(["foo", "${BAR}-bbb"])
2246         assert s == ["foo", "bbb-bbb"], s
2247         s = env.Split("foo")
2248         assert s == ["foo"], s
2249         s = env.Split("$FOO$BAR")
2250         assert s == ["fffbbb"], s
2251
2252     def test_TargetSignatures(type):
2253         """Test the TargetSignatures() method"""
2254         env = Environment(B = 'build', C = 'content')
2255
2256         exc_caught = None
2257         try:
2258             env.TargetSignatures('invalid_type')
2259         except SCons.Errors.UserError:
2260             exc_caught = 1
2261         assert exc_caught, "did not catch expected UserError"
2262         assert not hasattr(env, '_build_signature')
2263
2264         env.TargetSignatures('build')
2265         assert env._build_signature == 1, env._build_signature
2266
2267         env.TargetSignatures('content')
2268         assert env._build_signature == 0, env._build_signature
2269
2270         env.TargetSignatures('$B')
2271         assert env._build_signature == 1, env._build_signature
2272
2273         env.TargetSignatures('$C')
2274         assert env._build_signature == 0, env._build_signature
2275
2276     def test_Value(self):
2277         """Test creating a Value() object
2278         """
2279         env = Environment()
2280         v1 = env.Value('a')
2281         assert v1.value == 'a', v1.value
2282
2283         value2 = 'a'
2284         v2 = env.Value(value2)
2285         assert v2.value == value2, v2.value
2286         assert v2.value is value2, v2.value
2287
2288         assert not v1 is v2
2289         assert v1.value == v2.value
2290
2291
2292
2293     def test_Environment_global_variable(type):
2294         """Test setting Environment variable to an Environment.Base subclass"""
2295         class MyEnv(SCons.Environment.Base):
2296             def xxx(self, string):
2297                 return self.subst(string)
2298
2299         SCons.Environment.Environment = MyEnv
2300
2301         env = SCons.Environment.Environment(FOO = 'foo')
2302
2303         f = env.subst('$FOO')
2304         assert f == 'foo', f
2305
2306         f = env.xxx('$FOO')
2307         assert f == 'foo', f
2308
2309
2310 if __name__ == "__main__":
2311     suite = unittest.makeSuite(EnvironmentTestCase, 'test_')
2312     if not unittest.TextTestRunner().run(suite).wasSuccessful():
2313         sys.exit(1)