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:
12 # The above copyright notice and this permission notice shall be included
13 # in all copies or substantial portions of the Software.
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.
24 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
32 from SCons.Util import *
42 self.buffer = self.buffer + str
45 """Simple node work-alike."""
46 def __init__(self, name):
47 self.name = os.path.normpath(name)
54 def get_subst_proxy(self):
58 def __init__(self, dict={}):
61 def Dictionary(self, key = None):
66 def __getitem__(self, key):
70 dict = self.dict.copy()
71 dict["TARGETS"] = 'tsig'
72 dict["SOURCES"] = 'ssig'
75 def cs(target=None, source=None, env=None, for_signature=None):
78 def cl(target=None, source=None, env=None, for_signature=None):
81 def CmdGen1(target, source, env, for_signature):
82 # Nifty trick...since Environment references are interpolated,
83 # instantiate an instance of a callable class with this one,
84 # which will then get evaluated.
85 assert str(target) == 't', target
86 assert str(source) == 's', source
87 return "${CMDGEN2('foo', %d)}" % for_signature
90 def __init__(self, mystr, forsig):
92 self.expect_for_signature = forsig
94 def __call__(self, target, source, env, for_signature):
95 assert str(target) == 't', target
96 assert str(source) == 's', source
97 assert for_signature == self.expect_for_signature, for_signature
98 return [ self.mystr, env.Dictionary('BAR') ]
105 return string.replace(str, '/', os.sep)
107 class UtilTestCase(unittest.TestCase):
108 def test_subst(self):
109 """Test the subst() function"""
110 class MyNode(DummyNode):
111 """Simple node work-alike with some extra stuff for testing."""
112 def __init__(self, name):
113 DummyNode.__init__(self, name)
116 self.attribute = Attribute()
117 self.attribute.attr1 = 'attr$1-' + os.path.basename(name)
118 self.attribute.attr2 = 'attr$2-' + os.path.basename(name)
119 def get_stuff(self, extra):
120 return self.name + extra
124 def __init__(self, literal):
125 self.literal = literal
128 def is_literal(self):
131 def function_foo(arg):
134 target = [ MyNode("./foo/bar.exe"),
135 MyNode("/bar/baz.obj"),
136 MyNode("../foo/baz.obj") ]
137 source = [ MyNode("./foo/blah.cpp"),
138 MyNode("/bar/ack.cpp"),
139 MyNode("../foo/ack.c") ]
155 # $XXX$HHH should expand to GGGIII, not BADNEWS.
159 'FFFIII' : 'BADNEWS',
161 'LITERAL' : TestLiteral("$XXX"),
163 # Test that we can expand to and return a function.
164 #'FUNCTION' : function_foo,
172 # Test various combinations of strings, lists and functions.
183 # Test function calls within ${}.
184 'FUNCCALL' : '${FUNC1("$AAA $FUNC2 $BBB")}',
185 'FUNC1' : lambda x: x,
186 'FUNC2' : lambda target, source, env, for_signature: ['x$CCC'],
188 # Various tests refactored from ActionTests.py.
189 'LIST' : [["This", "is", "$(", "$a", "$)", "test"]],
192 'RECURSE' : 'foo $RECURSE bar',
193 'RRR' : 'foo $SSS bar',
199 # Basic tests of substitution functionality.
201 # Basics: strings without expansions are left alone, and
202 # the simplest possible expansion to a null-string value.
206 # Test expansion of integer values.
207 "test $zero", "test 0",
208 "test $one", "test 1",
210 # Test multiple re-expansion of values.
211 "test $ONE", "test four",
213 # Test a whole bunch of $TARGET[S] and $SOURCE[S] expansions.
214 "test $TARGETS $SOURCES",
215 "test foo/bar.exe /bar/baz.obj ../foo/baz.obj foo/blah.cpp /bar/ack.cpp ../foo/ack.c",
217 "test ${TARGETS[:]} ${SOURCES[0]}",
218 "test foo/bar.exe /bar/baz.obj ../foo/baz.obj foo/blah.cpp",
220 "test ${TARGETS[1:]}v",
221 "test /bar/baz.obj ../foo/baz.objv",
226 "test $TARGET$FOO[0]",
227 "test foo/bar.exe[0]",
232 "test ${SOURCES[0:2].foo}",
238 "test ${TARGET.get_stuff('blah')}",
239 "test foo/bar.exeblah",
241 "test ${SOURCES.get_stuff('blah')}",
242 "test foo/blah.cppblah /bar/ack.cppblah ../foo/ack.cblah",
244 "test ${SOURCES[0:2].get_stuff('blah')}",
245 "test foo/blah.cppblah /bar/ack.cppblah",
247 "test ${SOURCES[0:2].get_stuff('blah')}",
248 "test foo/blah.cppblah /bar/ack.cppblah",
250 "test ${SOURCES.attribute.attr1}",
251 "test attr$1-blah.cpp attr$1-ack.cpp attr$1-ack.c",
253 "test ${SOURCES.attribute.attr2}",
254 "test attr$2-blah.cpp attr$2-ack.cpp attr$2-ack.c",
256 # Test adjacent expansions.
263 # Test that adjacent expansions don't get re-interpreted
264 # together. The correct disambiguated expansion should be:
265 # $XXX$HHH => ${FFF}III => GGGIII
267 # $XXX$HHH => ${FFFIII} => BADNEWS
268 "$XXX$HHH", "GGGIII",
270 # Test double-dollar-sign behavior.
271 "$$FFF$HHH", "$FFFIII",
273 # Test that a Literal will stop dollar-sign substitution.
274 "$XXX $LITERAL $FFF", "GGG $XXX GGG",
276 # Test that we don't blow up even if they subscript
277 # something in ways they "can't."
283 # Test various combinations of strings and lists.
303 # Test function calls within ${}.
304 '$FUNCCALL', 'a xc b',
306 # Bug reported by Christoph Wiedemann.
307 cvt('$xxx/bin'), '/bin',
310 kwargs = {'target' : target, 'source' : source}
314 input, expect = cases[:2]
316 result = apply(scons_subst, (input, env), kwargs)
318 if failed == 0: print
319 print " input %s => %s did not match %s" % (repr(input), repr(result), repr(expect))
322 assert failed == 0, "%d subst() cases failed" % failed
324 # Tests of the various SUBST_* modes of substitution.
341 "$AAA ${AAA}A $BBBB $BBB",
356 # Verify what happens with no target or source nodes.
367 # Various tests refactored from ActionTests.py.
369 "This is $( $) test",
373 ["|", "$(", "$AAA", "|", "$BBB", "$)", "|", "$CCC", 1],
374 "| $( a | b $) | c 1",
381 input, eraw, ecmd, esig = subst_cases[:4]
382 result = scons_subst(input, env, mode=SUBST_RAW)
384 if failed == 0: print
385 print " input %s => RAW %s did not match %s" % (repr(input), repr(result), repr(eraw))
387 result = scons_subst(input, env, mode=SUBST_CMD)
389 if failed == 0: print
390 print " input %s => CMD %s did not match %s" % (repr(input), repr(result), repr(ecmd))
392 result = scons_subst(input, env, mode=SUBST_SIG)
394 if failed == 0: print
395 print " input %s => SIG %s did not match %s" % (repr(input), repr(result), repr(esig))
398 assert failed == 0, "%d subst() mode cases failed" % failed
404 result = scons_subst("$TARGET $SOURCES", env,
407 assert result == "t1 s1 s2", result
408 result = scons_subst("$TARGET $SOURCES", env,
412 assert result == " ", result
414 result = scons_subst("$TARGET $SOURCES", env, target=[], source=[])
415 assert result == " ", result
416 result = scons_subst("$TARGETS $SOURCE", env, target=[], source=[])
417 assert result == " ", result
419 # Test interpolating a callable.
420 newcom = scons_subst("test $CMDGEN1 $SOURCES $TARGETS",
421 env, target=MyNode('t'), source=MyNode('s'))
422 assert newcom == "test foo baz s t", newcom
424 # Test that we handle syntax errors during expansion as expected.
426 scons_subst('$foo.bar.3.0', env)
427 except SCons.Errors.UserError, e:
428 expect1 = "Syntax error `invalid syntax' trying to evaluate `$foo.bar.3.0'"
429 expect2 = "Syntax error `invalid syntax (line 1)' trying to evaluate `$foo.bar.3.0'"
430 assert str(e) in [expect1, expect2], e
432 raise AssertionError, "did not catch expected UserError"
434 # Test how we handle overriding the internal conversion routines.
439 env = DummyEnv({'NODE' : n1})
440 node = scons_subst("$NODE", env, mode=SUBST_RAW, conv=s)
441 assert node == [n1], node
442 node = scons_subst("$NODE", env, mode=SUBST_CMD, conv=s)
443 assert node == [n1], node
444 node = scons_subst("$NODE", env, mode=SUBST_SIG, conv=s)
445 assert node == [n1], node
447 # Test returning a function.
448 #env = DummyEnv({'FUNCTION' : foo})
449 #func = scons_subst("$FUNCTION", env, mode=SUBST_RAW, call=None)
450 #assert func is function_foo, func
451 #func = scons_subst("$FUNCTION", env, mode=SUBST_CMD, call=None)
452 #assert func is function_foo, func
453 #func = scons_subst("$FUNCTION", env, mode=SUBST_SIG, call=None)
454 #assert func is function_foo, func
456 # Test supplying an overriding gvars dictionary.
457 env = DummyEnv({'XXX' : 'xxx'})
458 result = scons_subst('$XXX', env)
459 assert result == 'xxx', result
460 result = scons_subst('$XXX', env, gvars={'XXX' : 'yyy'})
461 assert result == 'yyy', result
463 def test_subst_list(self):
464 """Testing the scons_subst_list() method..."""
465 class MyNode(DummyNode):
466 """Simple node work-alike with some extra stuff for testing."""
467 def __init__(self, name):
468 DummyNode.__init__(self, name)
471 self.attribute = Attribute()
472 self.attribute.attr1 = 'attr$1-' + os.path.basename(name)
473 self.attribute.attr2 = 'attr$2-' + os.path.basename(name)
475 target = [ MyNode("./foo/bar.exe"),
476 MyNode("/bar/baz with spaces.obj"),
477 MyNode("../foo/baz.obj") ]
478 source = [ MyNode("./foo/blah with spaces.cpp"),
479 MyNode("/bar/ack.cpp"),
480 MyNode("../foo/ack.c") ]
484 'NEWLINE' : 'before\nafter',
490 'DO' : DummyNode('do something'),
491 'FOO' : DummyNode('foo.in'),
492 'BAR' : DummyNode('bar with spaces.out'),
493 'CRAZY' : DummyNode('crazy\nfile.in'),
495 # $XXX$HHH should expand to GGGIII, not BADNEWS.
499 'FFFIII' : 'BADNEWS',
504 'LITERALS' : [ Literal('foo\nwith\nnewlines'),
505 Literal('bar\nwith\nnewlines') ],
507 # Test various combinations of strings, lists and functions.
518 # Test function calls within ${}.
519 'FUNCCALL' : '${FUNC1("$AAA $FUNC2 $BBB")}',
520 'FUNC1' : lambda x: x,
521 'FUNC2' : lambda target, source, env, for_signature: ['x$CCC'],
523 # Various tests refactored from ActionTests.py.
524 'LIST' : [["This", "is", "$(", "$a", "$)", "test"]],
527 'RECURSE' : 'foo $RECURSE bar',
528 'RRR' : 'foo $SSS bar',
537 ["foo/bar.exe", "/bar/baz with spaces.obj", "../foo/baz.obj"],
540 "$SOURCES $NEWLINE $TARGETS",
542 ["foo/blah with spaces.cpp", "/bar/ack.cpp", "../foo/ack.c", "before"],
543 ["after", "foo/bar.exe", "/bar/baz with spaces.obj", "../foo/baz.obj"],
548 ["foo/blah with spaces.cpp", "/bar/ack.cpp", "../foo/ack.cbefore"],
562 "test ${SOURCES.attribute.attr1}",
564 ["test", "attr$1-blah with spaces.cpp", "attr$1-ack.cpp", "attr$1-ack.c"],
567 "test ${SOURCES.attribute.attr2}",
569 ["test", "attr$2-blah with spaces.cpp", "attr$2-ack.cpp", "attr$2-ack.c"],
572 "$DO --in=$FOO --out=$BAR",
574 ["do something", "--in=foo.in", "--out=bar with spaces.out"],
577 # This test is now fixed, and works like it should.
578 "$DO --in=$CRAZY --out=$BAR",
580 ["do something", "--in=crazy\nfile.in", "--out=bar with spaces.out"],
583 # Try passing a list to scons_subst_list().
584 [ "$SOURCES$NEWLINE", "$TARGETS", "This is a test"],
586 ["foo/blah with spaces.cpp", "/bar/ack.cpp", "../foo/ack.cbefore"],
587 ["after", "foo/bar.exe", "/bar/baz with spaces.obj", "../foo/baz.obj", "This is a test"],
590 # Test against a former bug in scons_subst_list().
596 # Test double-dollar-sign behavior.
602 # Test various combinations of strings, lists and functions.
611 ['x', 'y'], [['x', 'y']],
621 '$S z', [['x', 'y', 'z']],
622 ['$S'], [['x', 'y']],
623 ['$S z'], [['x', 'y z']], # XXX - IS THIS BEST?
624 ['$S', 'z'], [['x', 'y', 'z']],
626 '$LS z', [['x y', 'z']],
628 ['$LS z'], [['x y z']],
629 ['$LS', 'z'], [['x y', 'z']],
631 '$L z', [['x', 'y', 'z']],
632 ['$L'], [['x', 'y']],
633 ['$L z'], [['x', 'y z']], # XXX - IS THIS BEST?
634 ['$L', 'z'], [['x', 'y', 'z']],
644 # Test function calls within ${}.
645 '$FUNCCALL', [['a', 'xc', 'b']],
647 # Test handling of newlines in white space.
648 'foo\nbar', [['foo'], ['bar']],
649 'foo\n\nbar', [['foo'], ['bar']],
650 'foo \n \n bar', [['foo'], ['bar']],
651 'foo \nmiddle\n bar', [['foo'], ['middle'], ['bar']],
653 # Bug reported by Christoph Wiedemann.
654 cvt('$xxx/bin'), [['/bin']],
657 kwargs = {'target' : target, 'source' : source}
661 input, expect = cases[:2]
662 expect = map(lambda l: map(cvt, l), expect)
663 result = apply(scons_subst_list, (input, env), kwargs)
665 if failed == 0: print
666 print " input %s => %s did not match %s" % (repr(input), result, repr(expect))
669 assert failed == 0, "%d subst_list() cases failed" % failed
675 result = scons_subst_list("$TARGET $SOURCES", env,
678 assert result == [['t1', 's1', 's2']], result
679 result = scons_subst_list("$TARGET $SOURCES", env,
683 assert result == [[]], result
685 # Test interpolating a callable.
688 cmd_list = scons_subst_list("testing $CMDGEN1 $TARGETS $SOURCES",
689 env, target=_t, source=_s)
690 assert cmd_list == [['testing', 'foo', 'bar with spaces.out', 't', 's']], cmd_list
692 # Test escape functionality.
693 def escape_func(foo):
694 return '**' + foo + '**'
695 cmd_list = scons_subst_list("abc $LITERALS xyz", env)
696 assert cmd_list == [['abc',
697 'foo\nwith\nnewlines',
698 'bar\nwith\nnewlines',
700 c = cmd_list[0][0].escape(escape_func)
702 c = cmd_list[0][1].escape(escape_func)
703 assert c == '**foo\nwith\nnewlines**', c
704 c = cmd_list[0][2].escape(escape_func)
705 assert c == '**bar\nwith\nnewlines**', c
706 c = cmd_list[0][3].escape(escape_func)
709 cmd_list = scons_subst_list("abc${LITERALS}xyz", env)
710 c = cmd_list[0][0].escape(escape_func)
711 assert c == '**abcfoo\nwith\nnewlines**', c
712 c = cmd_list[0][1].escape(escape_func)
713 assert c == '**bar\nwith\nnewlinesxyz**', c
715 # Tests of the various SUBST_* modes of substitution.
728 [["test", "$(", "$)"]],
732 "$AAA ${AAA}A $BBBB $BBB",
747 # Verify what happens with no target or source nodes.
758 # Various test refactored from ActionTests.py
760 [['This', 'is', '$(', '$)', 'test']],
761 [['This', 'is', 'test']],
762 [['This', 'is', 'test']],
764 ["|", "$(", "$AAA", "|", "$BBB", "$)", "|", "$CCC", 1],
765 [["|", "$(", "a", "|", "b", "$)", "|", "c", "1"]],
766 [["|", "a", "|", "b", "|", "c", "1"]],
767 [["|", "|", "c", "1"]],
770 r = scons_subst_list("$TARGET $SOURCES", env, mode=SUBST_RAW)
774 while subst_list_cases:
775 input, eraw, ecmd, esig = subst_list_cases[:4]
776 result = scons_subst_list(input, env, mode=SUBST_RAW)
778 if failed == 0: print
779 print " input %s => RAW %s did not match %s" % (repr(input), repr(result), repr(eraw))
781 result = scons_subst_list(input, env, mode=SUBST_CMD)
783 if failed == 0: print
784 print " input %s => CMD %s did not match %s" % (repr(input), repr(result), repr(ecmd))
786 result = scons_subst_list(input, env, mode=SUBST_SIG)
788 if failed == 0: print
789 print " input %s => SIG %s did not match %s" % (repr(input), repr(result), repr(esig))
791 del subst_list_cases[:4]
792 assert failed == 0, "%d subst() mode cases failed" % failed
794 # Test that we handle syntax errors during expansion as expected.
796 scons_subst_list('$foo.bar.3.0', env)
797 except SCons.Errors.UserError, e:
798 expect1 = "Syntax error `invalid syntax' trying to evaluate `$foo.bar.3.0'"
799 expect2 = "Syntax error `invalid syntax (line 1)' trying to evaluate `$foo.bar.3.0'"
800 assert str(e) in [expect1, expect2], e
802 raise AssertionError, "did not catch expected SyntaxError"
804 # Test we handle overriding the internal conversion routines.
809 env = DummyEnv({'NODE' : n1})
810 node = scons_subst_list("$NODE", env, mode=SUBST_RAW, conv=s)
811 assert node == [[n1]], node
812 node = scons_subst_list("$NODE", env, mode=SUBST_CMD, conv=s)
813 assert node == [[n1]], node
814 node = scons_subst_list("$NODE", env, mode=SUBST_SIG, conv=s)
815 assert node == [[n1]], node
817 # Test supplying an overriding gvars dictionary.
818 env = DummyEnv({'XXX' : 'xxx'})
819 result = scons_subst_list('$XXX', env)
820 assert result == [['xxx']], result
821 result = scons_subst_list('$XXX', env, gvars={'XXX' : 'yyy'})
822 assert result == [['yyy']], result
824 def test_subst_once(self):
825 """Testing the scons_subst_once() method"""
830 'RECURSE' : 'r $RECURSE r',
831 'LIST' : ['a', 'b', 'c'],
863 ['x', 'a', 'b', 'c', 'y'],
865 ['x', 'x $LIST y', 'y'],
867 ['x', 'x a b c y', 'y'],
869 ['x', 'x $CCFLAGS y', 'y'],
871 ['x', 'x $CCFLAGS y', 'y'],
873 ['x', 'x $RECURSE y', 'y'],
875 ['x', 'x $RECURSE y', 'y'],
880 input, key, expect = cases[:3]
881 result = scons_subst_once(input, env, key)
883 if failed == 0: print
884 print " input %s (%s) => %s did not match %s" % (repr(input), repr(key), repr(result), repr(expect))
887 assert failed == 0, "%d subst() cases failed" % failed
889 def test_splitext(self):
890 assert splitext('foo') == ('foo','')
891 assert splitext('foo.bar') == ('foo','.bar')
892 assert splitext(os.path.join('foo.bar', 'blat')) == (os.path.join('foo.bar', 'blat'),'')
894 def test_quote_spaces(self):
895 """Testing the quote_spaces() method..."""
896 q = quote_spaces('x')
899 q = quote_spaces('x x')
900 assert q == '"x x"', q
902 q = quote_spaces('x\tx')
903 assert q == '"x\tx"', q
905 def test_render_tree(self):
907 def __init__(self, name, children=[]):
908 self.children = children
913 def get_children(node):
916 windows_h = Node("windows.h")
917 stdlib_h = Node("stdlib.h")
918 stdio_h = Node("stdio.h")
919 bar_c = Node("bar.c", [stdlib_h, windows_h])
920 bar_o = Node("bar.o", [bar_c])
921 foo_c = Node("foo.c", [stdio_h])
922 foo_o = Node("foo.o", [foo_c])
923 foo = Node("foo", [foo_o, bar_o])
936 actual = render_tree(foo, get_children)
937 assert expect == actual, (expect, actual)
939 bar_h = Node('bar.h', [stdlib_h])
940 blat_h = Node('blat.h', [stdlib_h])
941 blat_c = Node('blat.c', [blat_h, bar_h])
942 blat_o = Node('blat.o', [blat_c])
952 actual = render_tree(blat_o, get_children, 1)
953 assert expect == actual, (expect, actual)
955 def test_is_Dict(self):
958 assert is_Dict(UserDict.UserDict())
959 assert not is_Dict([])
960 assert not is_Dict("")
961 if hasattr(types, 'UnicodeType'):
962 exec "assert not is_Dict(u'')"
964 def test_is_List(self):
967 assert is_List(UserList.UserList())
968 assert not is_List({})
969 assert not is_List("")
970 if hasattr(types, 'UnicodeType'):
971 exec "assert not is_List(u'')"
973 def test_is_String(self):
975 if hasattr(types, 'UnicodeType'):
976 exec "assert is_String(u'')"
982 assert is_String(UserString.UserString(''))
983 assert not is_String({})
984 assert not is_String([])
986 def test_to_String(self):
987 """Test the to_String() method."""
988 assert to_String(1) == "1", to_String(1)
989 assert to_String([ 1, 2, 3]) == str([1, 2, 3]), to_String([1,2,3])
990 assert to_String("foo") == "foo", to_String("foo")
995 s1=UserString.UserString('blah')
996 assert to_String(s1) == s1, s1
997 assert to_String(s1) == 'blah', s1
999 class Derived(UserString.UserString):
1002 assert to_String(s2) == s2, s2
1003 assert to_String(s2) == 'foo', s2
1005 if hasattr(types, 'UnicodeType'):
1006 s3=UserString.UserString(unicode('bar'))
1007 assert to_String(s3) == s3, s3
1008 assert to_String(s3) == unicode('bar'), s3
1009 assert type(to_String(s3)) is types.UnicodeType, \
1014 if hasattr(types, 'UnicodeType'):
1016 assert to_String(s4) == unicode('baz'), to_String(s4)
1017 assert type(to_String(s4)) is types.UnicodeType, \
1020 def test_WhereIs(self):
1021 test = TestCmd.TestCmd(workdir = '')
1023 sub1_xxx_exe = test.workpath('sub1', 'xxx.exe')
1024 sub2_xxx_exe = test.workpath('sub2', 'xxx.exe')
1025 sub3_xxx_exe = test.workpath('sub3', 'xxx.exe')
1026 sub4_xxx_exe = test.workpath('sub4', 'xxx.exe')
1028 test.subdir('subdir', 'sub1', 'sub2', 'sub3', 'sub4')
1030 if sys.platform != 'win32':
1031 test.write(sub1_xxx_exe, "\n")
1033 os.mkdir(sub2_xxx_exe)
1035 test.write(sub3_xxx_exe, "\n")
1036 os.chmod(sub3_xxx_exe, 0777)
1038 test.write(sub4_xxx_exe, "\n")
1039 os.chmod(sub4_xxx_exe, 0777)
1041 env_path = os.environ['PATH']
1044 pathdirs_1234 = [ test.workpath('sub1'),
1045 test.workpath('sub2'),
1046 test.workpath('sub3'),
1047 test.workpath('sub4'),
1048 ] + string.split(env_path, os.pathsep)
1050 pathdirs_1243 = [ test.workpath('sub1'),
1051 test.workpath('sub2'),
1052 test.workpath('sub4'),
1053 test.workpath('sub3'),
1054 ] + string.split(env_path, os.pathsep)
1056 os.environ['PATH'] = string.join(pathdirs_1234, os.pathsep)
1057 wi = WhereIs('xxx.exe')
1058 assert wi == test.workpath(sub3_xxx_exe), wi
1059 wi = WhereIs('xxx.exe', pathdirs_1243)
1060 assert wi == test.workpath(sub4_xxx_exe), wi
1061 wi = WhereIs('xxx.exe', string.join(pathdirs_1243, os.pathsep))
1062 assert wi == test.workpath(sub4_xxx_exe), wi
1064 wi = WhereIs('xxx.exe',reject = sub3_xxx_exe)
1065 assert wi == test.workpath(sub4_xxx_exe), wi
1066 wi = WhereIs('xxx.exe', pathdirs_1243, reject = sub3_xxx_exe)
1067 assert wi == test.workpath(sub4_xxx_exe), wi
1069 os.environ['PATH'] = string.join(pathdirs_1243, os.pathsep)
1070 wi = WhereIs('xxx.exe')
1071 assert wi == test.workpath(sub4_xxx_exe), wi
1072 wi = WhereIs('xxx.exe', pathdirs_1234)
1073 assert wi == test.workpath(sub3_xxx_exe), wi
1074 wi = WhereIs('xxx.exe', string.join(pathdirs_1234, os.pathsep))
1075 assert wi == test.workpath(sub3_xxx_exe), wi
1077 if sys.platform == 'win32':
1078 wi = WhereIs('xxx', pathext = '')
1079 assert wi is None, wi
1081 wi = WhereIs('xxx', pathext = '.exe')
1082 assert wi == test.workpath(sub4_xxx_exe), wi
1084 wi = WhereIs('xxx', path = pathdirs_1234, pathext = '.BAT;.EXE')
1085 assert string.lower(wi) == string.lower(test.workpath(sub3_xxx_exe)), wi
1087 # Test that we return a normalized path even when
1088 # the path contains forward slashes.
1089 forward_slash = test.workpath('') + '/sub3'
1090 wi = WhereIs('xxx', path = forward_slash, pathext = '.EXE')
1091 assert string.lower(wi) == string.lower(test.workpath(sub3_xxx_exe)), wi
1093 del os.environ['PATH']
1094 wi = WhereIs('xxx.exe')
1095 assert wi is None, wi
1098 os.environ['PATH'] = env_path
1101 def test_is_valid_construction_var(self):
1102 """Testing is_valid_construction_var()"""
1103 r = is_valid_construction_var("_a")
1104 assert not r is None, r
1105 r = is_valid_construction_var("z_")
1106 assert not r is None, r
1107 r = is_valid_construction_var("X_")
1108 assert not r is None, r
1109 r = is_valid_construction_var("2a")
1111 r = is_valid_construction_var("a2_")
1112 assert not r is None, r
1113 r = is_valid_construction_var("/")
1115 r = is_valid_construction_var("_/")
1117 r = is_valid_construction_var("a/")
1119 r = is_valid_construction_var(".b")
1121 r = is_valid_construction_var("_.b")
1123 r = is_valid_construction_var("b1._")
1125 r = is_valid_construction_var("-b")
1127 r = is_valid_construction_var("_-b")
1129 r = is_valid_construction_var("b1-_")
1132 def test_get_env_var(self):
1133 """Testing get_environment_var()."""
1134 assert get_environment_var("$FOO") == "FOO", get_environment_var("$FOO")
1135 assert get_environment_var("${BAR}") == "BAR", get_environment_var("${BAR}")
1136 assert get_environment_var("$FOO_BAR1234") == "FOO_BAR1234", get_environment_var("$FOO_BAR1234")
1137 assert get_environment_var("${BAR_FOO1234}") == "BAR_FOO1234", get_environment_var("${BAR_FOO1234}")
1138 assert get_environment_var("${BAR}FOO") == None, get_environment_var("${BAR}FOO")
1139 assert get_environment_var("$BAR ") == None, get_environment_var("$BAR ")
1140 assert get_environment_var("FOO$BAR") == None, get_environment_var("FOO$BAR")
1141 assert get_environment_var("$FOO[0]") == None, get_environment_var("$FOO[0]")
1142 assert get_environment_var("${some('complex expression')}") == None, get_environment_var("${some('complex expression')}")
1144 def test_Proxy(self):
1145 """Test generic Proxy class."""
1155 class ProxyTest(Proxy):
1161 assert p.foo() == 1, p.foo()
1162 assert p.bar() == 4, p.bar()
1163 assert p.baz == 3, p.baz
1168 assert p.baz == 5, p.baz
1169 assert p.get() == s, p.get()
1171 def test_Literal(self):
1172 """Test the Literal() function."""
1173 input_list = [ '$FOO', Literal('$BAR') ]
1174 dummy_env = DummyEnv({ 'FOO' : 'BAZ', 'BAR' : 'BLAT' })
1176 def escape_func(cmd):
1177 return '**' + cmd + '**'
1179 cmd_list = scons_subst_list(input_list, dummy_env)
1180 cmd_list = SCons.Util.escape_list(cmd_list[0], escape_func)
1181 assert cmd_list == ['BAZ', '**$BAR**'], cmd_list
1183 def test_SpecialAttrWrapper(self):
1184 """Test the SpecialAttrWrapper() function."""
1185 input_list = [ '$FOO', SpecialAttrWrapper('$BAR', 'BLEH') ]
1186 dummy_env = DummyEnv({ 'FOO' : 'BAZ', 'BAR' : 'BLAT' })
1188 def escape_func(cmd):
1189 return '**' + cmd + '**'
1191 cmd_list = scons_subst_list(input_list, dummy_env)
1192 cmd_list = SCons.Util.escape_list(cmd_list[0], escape_func)
1193 assert cmd_list == ['BAZ', '**$BAR**'], cmd_list
1195 cmd_list = scons_subst_list(input_list, dummy_env, mode=SUBST_SIG)
1196 cmd_list = SCons.Util.escape_list(cmd_list[0], escape_func)
1197 assert cmd_list == ['BAZ', '**BLEH**'], cmd_list
1199 def test_display(self):
1200 old_stdout = sys.stdout
1201 sys.stdout = OutBuffer()
1208 assert sys.stdout.buffer == "line1\nline3\n"
1209 sys.stdout = old_stdout
1211 def test_fs_delete(self):
1212 test = TestCmd.TestCmd(workdir = '')
1213 base = test.workpath('')
1214 xxx = test.workpath('xxx.xxx')
1215 ZZZ = test.workpath('ZZZ.ZZZ')
1216 sub1_yyy = test.workpath('sub1', 'yyy.yyy')
1219 test.write(xxx, "\n")
1220 test.write(ZZZ, "\n")
1221 test.write(sub1_yyy, "\n")
1223 old_stdout = sys.stdout
1224 sys.stdout = OutBuffer()
1226 exp = "Removed " + os.path.join(base, ZZZ) + "\n" + \
1227 "Removed " + os.path.join(base, sub1_yyy) + '\n' + \
1228 "Removed directory " + os.path.join(base, 'sub1') + '\n' + \
1229 "Removed " + os.path.join(base, xxx) + '\n' + \
1230 "Removed directory " + base + '\n'
1232 fs_delete(base, remove=0)
1233 assert sys.stdout.buffer == exp, sys.stdout.buffer
1234 assert os.path.exists(sub1_yyy)
1236 sys.stdout.buffer = ""
1237 fs_delete(base, remove=1)
1238 assert sys.stdout.buffer == exp
1239 assert not os.path.exists(base)
1241 test._dirlist = None
1242 sys.stdout = old_stdout
1244 def test_get_native_path(self):
1245 """Test the get_native_path() function."""
1247 filename = tempfile.mktemp()
1248 str = '1234567890 ' + filename
1249 open(filename, 'w').write(str)
1250 assert open(get_native_path(filename)).read() == str
1252 def test_subst_dict(self):
1253 """Test substituting dictionary values in an Action
1257 d = subst_dict(target=t, source=s)
1258 assert str(d['TARGETS'][0]) == 't', d['TARGETS']
1259 assert str(d['TARGET']) == 't', d['TARGET']
1260 assert str(d['SOURCES'][0]) == 's', d['SOURCES']
1261 assert str(d['SOURCE']) == 's', d['SOURCE']
1263 t1 = DummyNode('t1')
1264 t2 = DummyNode('t2')
1265 s1 = DummyNode('s1')
1266 s2 = DummyNode('s2')
1267 d = subst_dict(target=[t1, t2], source=[s1, s2])
1268 TARGETS = map(lambda x: str(x), d['TARGETS'])
1270 assert TARGETS == ['t1', 't2'], d['TARGETS']
1271 assert str(d['TARGET']) == 't1', d['TARGET']
1272 SOURCES = map(lambda x: str(x), d['SOURCES'])
1274 assert SOURCES == ['s1', 's2'], d['SOURCES']
1275 assert str(d['SOURCE']) == 's1', d['SOURCE']
1278 def __init__(self, name):
1283 return self.__class__('rstr-' + self.name)
1284 def get_subst_proxy(self):
1288 t4 = DummyNode('t4')
1289 s3 = DummyNode('s3')
1291 d = subst_dict(target=[t3, t4], source=[s3, s4])
1292 TARGETS = map(lambda x: str(x), d['TARGETS'])
1294 assert TARGETS == ['t3', 't4'], d['TARGETS']
1295 SOURCES = map(lambda x: str(x), d['SOURCES'])
1297 assert SOURCES == ['rstr-s4', 's3'], d['SOURCES']
1299 def test_PrependPath(self):
1300 """Test prepending to a path"""
1301 p1 = r'C:\dir\num\one;C:\dir\num\two'
1302 p2 = r'C:\mydir\num\one;C:\mydir\num\two'
1303 # have to include the pathsep here so that the test will work on UNIX too.
1304 p1 = PrependPath(p1,r'C:\dir\num\two',sep = ';')
1305 p1 = PrependPath(p1,r'C:\dir\num\three',sep = ';')
1306 p2 = PrependPath(p2,r'C:\mydir\num\three',sep = ';')
1307 p2 = PrependPath(p2,r'C:\mydir\num\one',sep = ';')
1308 assert(p1 == r'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one')
1309 assert(p2 == r'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two')
1311 def test_AppendPath(self):
1312 """Test appending to a path."""
1313 p1 = r'C:\dir\num\one;C:\dir\num\two'
1314 p2 = r'C:\mydir\num\one;C:\mydir\num\two'
1315 # have to include the pathsep here so that the test will work on UNIX too.
1316 p1 = AppendPath(p1,r'C:\dir\num\two',sep = ';')
1317 p1 = AppendPath(p1,r'C:\dir\num\three',sep = ';')
1318 p2 = AppendPath(p2,r'C:\mydir\num\three',sep = ';')
1319 p2 = AppendPath(p2,r'C:\mydir\num\one',sep = ';')
1320 assert(p1 == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three')
1321 assert(p2 == r'C:\mydir\num\two;C:\mydir\num\three;C:\mydir\num\one')
1323 def test_NodeList(self):
1324 """Test NodeList class"""
1326 def __init__(self, name, child=None):
1330 return self.bar + "foo"
1334 t1 = TestClass('t1', TestClass('t1child'))
1335 t2 = TestClass('t2', TestClass('t2child'))
1336 t3 = TestClass('t3')
1338 nl = NodeList([t1, t2, t3])
1339 assert nl.foo() == [ 't1foo', 't2foo', 't3foo' ], nl.foo()
1340 assert nl.bar == [ 't1', 't2', 't3' ], nl.bar
1341 assert nl.getself().bar == [ 't1', 't2', 't3' ], nl.getself().bar
1342 assert nl[0:2].child.foo() == [ 't1childfoo', 't2childfoo' ], \
1344 assert nl[0:2].child.bar == [ 't1child', 't2child' ], \
1347 def test_CLVar(self):
1348 """Test the command-line construction variable class"""
1349 f = SCons.Util.CLVar('a b')
1352 assert isinstance(r, SCons.Util.CLVar), type(r)
1353 assert r.data == ['a', 'b', 'c', 'd'], r.data
1354 assert str(r) == 'a b c d', str(r)
1357 assert isinstance(r, SCons.Util.CLVar), type(r)
1358 assert r.data == ['a', 'b', 'c', 'd'], r.data
1359 assert str(r) == 'a b c d', str(r)
1362 assert isinstance(r, SCons.Util.CLVar), type(r)
1363 assert r.data == ['a', 'b', 'c d'], r.data
1364 assert str(r) == 'a b c d', str(r)
1367 assert isinstance(r, SCons.Util.CLVar), type(r)
1368 assert r.data == ['a', 'b', ' c d'], r.data
1369 assert str(r) == 'a b c d', str(r)
1372 assert isinstance(r, SCons.Util.CLVar), type(r)
1373 assert r.data == ['a', 'b', 'c', 'd'], r.data
1374 assert str(r) == 'a b c d', str(r)
1377 assert isinstance(r, SCons.Util.CLVar), type(r)
1378 assert r.data == ['a', 'b', ' c', 'd'], r.data
1379 assert str(r) == 'a b c d', str(r)
1381 f = SCons.Util.CLVar(['a b'])
1384 assert isinstance(r, SCons.Util.CLVar), type(r)
1385 assert r.data == ['a b', 'c', 'd'], r.data
1386 assert str(r) == 'a b c d', str(r)
1389 assert isinstance(r, SCons.Util.CLVar), type(r)
1390 assert r.data == ['a b', 'c', 'd'], r.data
1391 assert str(r) == 'a b c d', str(r)
1394 assert isinstance(r, SCons.Util.CLVar), type(r)
1395 assert r.data == ['a b', 'c d'], r.data
1396 assert str(r) == 'a b c d', str(r)
1399 assert isinstance(r, SCons.Util.CLVar), type(r)
1400 assert r.data == ['a b', ' c d'], r.data
1401 assert str(r) == 'a b c d', str(r)
1404 assert isinstance(r, SCons.Util.CLVar), type(r)
1405 assert r.data == ['a b', 'c', 'd'], r.data
1406 assert str(r) == 'a b c d', str(r)
1409 assert isinstance(r, SCons.Util.CLVar), type(r)
1410 assert r.data == ['a b', ' c', 'd'], r.data
1411 assert str(r) == 'a b c d', str(r)
1413 f = SCons.Util.CLVar(['a', 'b'])
1416 assert isinstance(r, SCons.Util.CLVar), type(r)
1417 assert r.data == ['a', 'b', 'c', 'd'], r.data
1418 assert str(r) == 'a b c d', str(r)
1421 assert isinstance(r, SCons.Util.CLVar), type(r)
1422 assert r.data == ['a', 'b', 'c', 'd'], r.data
1423 assert str(r) == 'a b c d', str(r)
1426 assert isinstance(r, SCons.Util.CLVar), type(r)
1427 assert r.data == ['a', 'b', 'c d'], r.data
1428 assert str(r) == 'a b c d', str(r)
1431 assert isinstance(r, SCons.Util.CLVar), type(r)
1432 assert r.data == ['a', 'b', ' c d'], r.data
1433 assert str(r) == 'a b c d', str(r)
1436 assert isinstance(r, SCons.Util.CLVar), type(r)
1437 assert r.data == ['a', 'b', 'c', 'd'], r.data
1438 assert str(r) == 'a b c d', str(r)
1441 assert isinstance(r, SCons.Util.CLVar), type(r)
1442 assert r.data == ['a', 'b', ' c', 'd'], r.data
1443 assert str(r) == 'a b c d', str(r)
1447 loc['BAR'] = SCons.Util.CLVar('bar')
1448 loc['CALL'] = lambda target, source, env, for_signature: 'call'
1451 cmd = SCons.Util.CLVar("test $FOO $BAR $CALL test")
1453 newcmd = scons_subst(cmd, env)
1454 assert newcmd == 'test foo bar call test', newcmd
1456 cmd_list = scons_subst_list(cmd, env)
1457 assert len(cmd_list) == 1, cmd_list
1458 assert cmd_list[0][0] == "test", cmd_list[0][0]
1459 assert cmd_list[0][1] == "foo", cmd_list[0][1]
1460 assert cmd_list[0][2] == "bar", cmd_list[0][2]
1461 assert cmd_list[0][3] == "call", cmd_list[0][3]
1462 assert cmd_list[0][4] == "test", cmd_list[0][4]
1464 def test_Selector(self):
1465 """Test the Selector class"""
1467 s = Selector({'a' : 'AAA', 'b' : 'BBB'})
1468 assert s['a'] == 'AAA', s['a']
1469 assert s['b'] == 'BBB', s['b']
1475 assert exc_caught, "should have caught a KeyError"
1477 assert s['c'] == 'CCC', s['c']
1479 class DummyEnv(UserDict.UserDict):
1480 def subst(self, key):
1482 return self[key[1:]]
1487 s = Selector({'.d' : 'DDD', '.e' : 'EEE'})
1488 ret = s(env, ['foo.d'])
1489 assert ret == 'DDD', ret
1490 ret = s(env, ['bar.e'])
1491 assert ret == 'EEE', ret
1492 ret = s(env, ['bar.x'])
1493 assert ret == None, ret
1495 ret = s(env, ['bar.x'])
1496 assert ret == 'XXX', ret
1498 env = DummyEnv({'FSUFF' : '.f', 'GSUFF' : '.g'})
1500 s = Selector({'$FSUFF' : 'FFF', '$GSUFF' : 'GGG'})
1501 ret = s(env, ['foo.f'])
1502 assert ret == 'FFF', ret
1503 ret = s(env, ['bar.g'])
1504 assert ret == 'GGG', ret
1506 def test_adjustixes(self):
1507 """Test the adjustixes() function"""
1508 r = adjustixes('file', 'pre-', '-suf')
1509 assert r == 'pre-file-suf', r
1510 r = adjustixes('pre-file', 'pre-', '-suf')
1511 assert r == 'pre-file-suf', r
1512 r = adjustixes('file-suf', 'pre-', '-suf')
1513 assert r == 'pre-file-suf', r
1514 r = adjustixes('pre-file-suf', 'pre-', '-suf')
1515 assert r == 'pre-file-suf', r
1516 r = adjustixes('pre-file.xxx', 'pre-', '-suf')
1517 assert r == 'pre-file.xxx', r
1518 r = adjustixes('dir/file', 'pre-', '-suf')
1519 assert r == os.path.join('dir', 'pre-file-suf'), r
1521 def test_containsAny(self):
1522 """Test the containsAny() function"""
1523 assert containsAny('*.py', '*?[]')
1524 assert not containsAny('file.txt', '*?[]')
1526 def test_containsAll(self):
1527 """Test the containsAll() function"""
1528 assert containsAll('43221', '123')
1529 assert not containsAll('134', '123')
1531 def test_containsOnly(self):
1532 """Test the containsOnly() function"""
1533 assert containsOnly('.83', '0123456789.')
1534 assert not containsOnly('43221', '123')
1536 if __name__ == "__main__":
1537 suite = unittest.makeSuite(UtilTestCase, 'test_')
1538 if not unittest.TextTestRunner().run(suite).wasSuccessful():