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):
67 dict = self.dict.copy()
68 dict["TARGETS"] = 'tsig'
69 dict["SOURCES"] = 'ssig'
72 def cs(target=None, source=None, env=None, for_signature=None):
75 def cl(target=None, source=None, env=None, for_signature=None):
78 def CmdGen1(target, source, env, for_signature):
79 # Nifty trick...since Environment references are interpolated,
80 # instantiate an instance of a callable class with this one,
81 # which will then get evaluated.
82 assert str(target) == 't', target
83 assert str(source) == 's', source
84 return "${CMDGEN2('foo', %d)}" % for_signature
87 def __init__(self, mystr, forsig):
89 self.expect_for_signature = forsig
91 def __call__(self, target, source, env, for_signature):
92 assert str(target) == 't', target
93 assert str(source) == 's', source
94 assert for_signature == self.expect_for_signature, for_signature
95 return [ self.mystr, env.Dictionary('BAR') ]
102 return string.replace(str, '/', os.sep)
104 class UtilTestCase(unittest.TestCase):
105 def test_subst(self):
106 """Test the subst() function"""
107 class MyNode(DummyNode):
108 """Simple node work-alike with some extra stuff for testing."""
109 def __init__(self, name):
110 DummyNode.__init__(self, name)
113 self.attribute = Attribute()
114 self.attribute.attr1 = 'attr$1-' + os.path.basename(name)
115 self.attribute.attr2 = 'attr$2-' + os.path.basename(name)
116 def get_stuff(self, extra):
117 return self.name + extra
121 def __init__(self, literal):
122 self.literal = literal
125 def is_literal(self):
128 def function_foo(arg):
131 target = [ MyNode("./foo/bar.exe"),
132 MyNode("/bar/baz.obj"),
133 MyNode("../foo/baz.obj") ]
134 source = [ MyNode("./foo/blah.cpp"),
135 MyNode("/bar/ack.cpp"),
136 MyNode("../foo/ack.c") ]
152 # $XXX$HHH should expand to GGGIII, not BADNEWS.
156 'FFFIII' : 'BADNEWS',
158 'LITERAL' : TestLiteral("$XXX"),
160 # Test that we can expand to and return a function.
161 #'FUNCTION' : function_foo,
169 # Test various combinations of strings, lists and functions.
180 # Test function calls within ${}.
181 'FUNCCALL' : '${FUNC1("$AAA $FUNC2 $BBB")}',
182 'FUNC1' : lambda x: x,
183 'FUNC2' : lambda target, source, env, for_signature: ['x$CCC'],
185 # Various tests refactored from ActionTests.py.
186 'LIST' : [["This", "is", "$(", "$a", "$)", "test"]],
189 'RECURSE' : 'foo $RECURSE bar',
190 'RRR' : 'foo $SSS bar',
196 # Basic tests of substitution functionality.
198 # Basics: strings without expansions are left alone, and
199 # the simplest possible expansion to a null-string value.
203 # Test expansion of integer values.
204 "test $zero", "test 0",
205 "test $one", "test 1",
207 # Test multiple re-expansion of values.
208 "test $ONE", "test four",
210 # Test a whole bunch of $TARGET[S] and $SOURCE[S] expansions.
211 "test $TARGETS $SOURCES",
212 "test foo/bar.exe /bar/baz.obj ../foo/baz.obj foo/blah.cpp /bar/ack.cpp ../foo/ack.c",
214 "test ${TARGETS[:]} ${SOURCES[0]}",
215 "test foo/bar.exe /bar/baz.obj ../foo/baz.obj foo/blah.cpp",
217 "test ${TARGETS[1:]}v",
218 "test /bar/baz.obj ../foo/baz.objv",
223 "test $TARGET$FOO[0]",
224 "test foo/bar.exe[0]",
229 "test ${SOURCES[0:2].foo}",
235 "test ${TARGET.get_stuff('blah')}",
236 "test foo/bar.exeblah",
238 "test ${SOURCES.get_stuff('blah')}",
239 "test foo/blah.cppblah /bar/ack.cppblah ../foo/ack.cblah",
241 "test ${SOURCES[0:2].get_stuff('blah')}",
242 "test foo/blah.cppblah /bar/ack.cppblah",
244 "test ${SOURCES[0:2].get_stuff('blah')}",
245 "test foo/blah.cppblah /bar/ack.cppblah",
247 "test ${SOURCES.attribute.attr1}",
248 "test attr$1-blah.cpp attr$1-ack.cpp attr$1-ack.c",
250 "test ${SOURCES.attribute.attr2}",
251 "test attr$2-blah.cpp attr$2-ack.cpp attr$2-ack.c",
253 # Test adjacent expansions.
260 # Test that adjacent expansions don't get re-interpreted
261 # together. The correct disambiguated expansion should be:
262 # $XXX$HHH => ${FFF}III => GGGIII
264 # $XXX$HHH => ${FFFIII} => BADNEWS
265 "$XXX$HHH", "GGGIII",
267 # Test double-dollar-sign behavior.
268 "$$FFF$HHH", "$FFFIII",
270 # Test that a Literal will stop dollar-sign substitution.
271 "$XXX $LITERAL $FFF", "GGG $XXX GGG",
273 # Test that we don't blow up even if they subscript
274 # something in ways they "can't."
280 # Test various combinations of strings and lists.
297 # Test function calls within ${}.
298 '$FUNCCALL', 'a xc b',
300 # Bug reported by Christoph Wiedemann.
301 cvt('$xxx/bin'), '/bin',
304 kwargs = {'target' : target, 'source' : source}
308 input, expect = cases[:2]
310 result = apply(scons_subst, (input, env), kwargs)
312 if failed == 0: print
313 print " input %s => %s did not match %s" % (repr(input), repr(result), repr(expect))
316 assert failed == 0, "%d subst() cases failed" % failed
318 # Tests of the various SUBST_* modes of substitution.
335 "$AAA ${AAA}A $BBBB $BBB",
350 # Verify what happens with no target or source nodes.
361 # Various tests refactored from ActionTests.py.
363 "This is $( $) test",
367 ["|", "$(", "$AAA", "|", "$BBB", "$)", "|", "$CCC", 1],
368 "| $( a | b $) | c 1",
375 input, eraw, ecmd, esig = subst_cases[:4]
376 result = scons_subst(input, env, mode=SUBST_RAW)
378 if failed == 0: print
379 print " input %s => RAW %s did not match %s" % (repr(input), repr(result), repr(eraw))
381 result = scons_subst(input, env, mode=SUBST_CMD)
383 if failed == 0: print
384 print " input %s => CMD %s did not match %s" % (repr(input), repr(result), repr(ecmd))
386 result = scons_subst(input, env, mode=SUBST_SIG)
388 if failed == 0: print
389 print " input %s => SIG %s did not match %s" % (repr(input), repr(result), repr(esig))
392 assert failed == 0, "%d subst() mode cases failed" % failed
398 result = scons_subst("$TARGET $SOURCES", env,
401 assert result == "t1 s1 s2", result
402 result = scons_subst("$TARGET $SOURCES", env,
406 assert result == " ", result
408 result = scons_subst("$TARGET $SOURCES", env, target=[], source=[])
409 assert result == " ", result
410 result = scons_subst("$TARGETS $SOURCE", env, target=[], source=[])
411 assert result == " ", result
413 # Test interpolating a callable.
414 newcom = scons_subst("test $CMDGEN1 $SOURCES $TARGETS",
415 env, target=MyNode('t'), source=MyNode('s'))
416 assert newcom == "test foo baz s t", newcom
418 # Test that we handle syntax errors during expansion as expected.
420 scons_subst('$foo.bar.3.0', env)
421 except SCons.Errors.UserError, e:
422 assert str(e) == "Syntax error trying to evaluate `$foo.bar.3.0'", e
424 raise AssertionError, "did not catch expected UserError"
426 # Test returning a function.
427 #env = DummyEnv({'FUNCTION' : foo})
428 #func = scons_subst("$FUNCTION", env, mode=SUBST_RAW, call=None)
429 #assert func is function_foo, func
430 #func = scons_subst("$FUNCTION", env, mode=SUBST_CMD, call=None)
431 #assert func is function_foo, func
432 #func = scons_subst("$FUNCTION", env, mode=SUBST_SIG, call=None)
433 #assert func is function_foo, func
435 def test_subst_list(self):
436 """Testing the scons_subst_list() method..."""
437 class MyNode(DummyNode):
438 """Simple node work-alike with some extra stuff for testing."""
439 def __init__(self, name):
440 DummyNode.__init__(self, name)
443 self.attribute = Attribute()
444 self.attribute.attr1 = 'attr$1-' + os.path.basename(name)
445 self.attribute.attr2 = 'attr$2-' + os.path.basename(name)
447 target = [ MyNode("./foo/bar.exe"),
448 MyNode("/bar/baz with spaces.obj"),
449 MyNode("../foo/baz.obj") ]
450 source = [ MyNode("./foo/blah with spaces.cpp"),
451 MyNode("/bar/ack.cpp"),
452 MyNode("../foo/ack.c") ]
456 'NEWLINE' : 'before\nafter',
462 'DO' : DummyNode('do something'),
463 'FOO' : DummyNode('foo.in'),
464 'BAR' : DummyNode('bar with spaces.out'),
465 'CRAZY' : DummyNode('crazy\nfile.in'),
467 # $XXX$HHH should expand to GGGIII, not BADNEWS.
471 'FFFIII' : 'BADNEWS',
476 'LITERALS' : [ Literal('foo\nwith\nnewlines'),
477 Literal('bar\nwith\nnewlines') ],
479 # Test various combinations of strings, lists and functions.
490 # Test function calls within ${}.
491 'FUNCCALL' : '${FUNC1("$AAA $FUNC2 $BBB")}',
492 'FUNC1' : lambda x: x,
493 'FUNC2' : lambda target, source, env, for_signature: ['x$CCC'],
495 # Various tests refactored from ActionTests.py.
496 'LIST' : [["This", "is", "$(", "$a", "$)", "test"]],
499 'RECURSE' : 'foo $RECURSE bar',
500 'RRR' : 'foo $SSS bar',
509 ["foo/bar.exe", "/bar/baz with spaces.obj", "../foo/baz.obj"],
512 "$SOURCES $NEWLINE $TARGETS",
514 ["foo/blah with spaces.cpp", "/bar/ack.cpp", "../foo/ack.c", "before"],
515 ["after", "foo/bar.exe", "/bar/baz with spaces.obj", "../foo/baz.obj"],
520 ["foo/blah with spaces.cpp", "/bar/ack.cpp", "../foo/ack.cbefore"],
534 "test ${SOURCES.attribute.attr1}",
536 ["test", "attr$1-blah with spaces.cpp", "attr$1-ack.cpp", "attr$1-ack.c"],
539 "test ${SOURCES.attribute.attr2}",
541 ["test", "attr$2-blah with spaces.cpp", "attr$2-ack.cpp", "attr$2-ack.c"],
544 "$DO --in=$FOO --out=$BAR",
546 ["do something", "--in=foo.in", "--out=bar with spaces.out"],
549 # This test is now fixed, and works like it should.
550 "$DO --in=$CRAZY --out=$BAR",
552 ["do something", "--in=crazy\nfile.in", "--out=bar with spaces.out"],
555 # Try passing a list to scons_subst_list().
556 [ "$SOURCES$NEWLINE", "$TARGETS", "This is a test"],
558 ["foo/blah with spaces.cpp", "/bar/ack.cpp", "../foo/ack.cbefore"],
559 ["after", "foo/bar.exe", "/bar/baz with spaces.obj", "../foo/baz.obj", "This is a test"],
562 # Test against a former bug in scons_subst_list().
568 # Test double-dollar-sign behavior.
574 # Test various combinations of strings, lists and functions.
583 ['x', 'y'], [['x', 'y']],
593 ['$S'], [['x', 'y']],
597 ['$L'], [['x', 'y']],
607 # Test function calls within ${}.
608 '$FUNCCALL', [['a', 'xc', 'b']],
610 # Test handling of newlines in white space.
611 'foo\nbar', [['foo'], ['bar']],
612 'foo\n\nbar', [['foo'], ['bar']],
613 'foo \n \n bar', [['foo'], ['bar']],
614 'foo \nmiddle\n bar', [['foo'], ['middle'], ['bar']],
616 # Bug reported by Christoph Wiedemann.
617 cvt('$xxx/bin'), [['/bin']],
620 kwargs = {'target' : target, 'source' : source}
624 input, expect = cases[:2]
625 expect = map(lambda l: map(cvt, l), expect)
626 result = apply(scons_subst_list, (input, env), kwargs)
628 if failed == 0: print
629 print " input %s => %s did not match %s" % (repr(input), result, repr(expect))
632 assert failed == 0, "%d subst_list() cases failed" % failed
638 result = scons_subst_list("$TARGET $SOURCES", env,
641 assert result == [['t1', 's1', 's2']], result
642 result = scons_subst_list("$TARGET $SOURCES", env,
646 assert result == [[]], result
648 # Test interpolating a callable.
651 cmd_list = scons_subst_list("testing $CMDGEN1 $TARGETS $SOURCES",
652 env, target=_t, source=_s)
653 assert cmd_list == [['testing', 'foo', 'bar with spaces.out', 't', 's']], cmd_list
655 # Test escape functionality.
656 def escape_func(foo):
657 return '**' + foo + '**'
658 cmd_list = scons_subst_list("abc $LITERALS xyz", env)
659 assert cmd_list == [['abc',
660 'foo\nwith\nnewlines',
661 'bar\nwith\nnewlines',
663 c = cmd_list[0][0].escape(escape_func)
665 c = cmd_list[0][1].escape(escape_func)
666 assert c == '**foo\nwith\nnewlines**', c
667 c = cmd_list[0][2].escape(escape_func)
668 assert c == '**bar\nwith\nnewlines**', c
669 c = cmd_list[0][3].escape(escape_func)
672 # Tests of the various SUBST_* modes of substitution.
685 [["test", "$(", "$)"]],
689 "$AAA ${AAA}A $BBBB $BBB",
704 # Verify what happens with no target or source nodes.
715 # Various test refactored from ActionTests.py
717 [['This', 'is', '$(', '$)', 'test']],
718 [['This', 'is', 'test']],
719 [['This', 'is', 'test']],
721 ["|", "$(", "$AAA", "|", "$BBB", "$)", "|", "$CCC", 1],
722 [["|", "$(", "a", "|", "b", "$)", "|", "c", "1"]],
723 [["|", "a", "|", "b", "|", "c", "1"]],
724 [["|", "|", "c", "1"]],
727 r = scons_subst_list("$TARGET $SOURCES", env, mode=SUBST_RAW)
731 while subst_list_cases:
732 input, eraw, ecmd, esig = subst_list_cases[:4]
733 result = scons_subst_list(input, env, mode=SUBST_RAW)
735 if failed == 0: print
736 print " input %s => RAW %s did not match %s" % (repr(input), repr(result), repr(eraw))
738 result = scons_subst_list(input, env, mode=SUBST_CMD)
740 if failed == 0: print
741 print " input %s => CMD %s did not match %s" % (repr(input), repr(result), repr(ecmd))
743 result = scons_subst_list(input, env, mode=SUBST_SIG)
745 if failed == 0: print
746 print " input %s => SIG %s did not match %s" % (repr(input), repr(result), repr(esig))
748 del subst_list_cases[:4]
749 assert failed == 0, "%d subst() mode cases failed" % failed
751 # Test that we handle syntax errors during expansion as expected.
753 scons_subst_list('$foo.bar.3.0', env)
754 except SCons.Errors.UserError, e:
755 assert str(e) == "Syntax error trying to evaluate `$foo.bar.3.0'", e
757 raise AssertionError, "did not catch expected SyntaxError"
759 def test_splitext(self):
760 assert splitext('foo') == ('foo','')
761 assert splitext('foo.bar') == ('foo','.bar')
762 assert splitext(os.path.join('foo.bar', 'blat')) == (os.path.join('foo.bar', 'blat'),'')
764 def test_quote_spaces(self):
765 """Testing the quote_spaces() method..."""
766 q = quote_spaces('x')
769 q = quote_spaces('x x')
770 assert q == '"x x"', q
772 q = quote_spaces('x\tx')
773 assert q == '"x\tx"', q
775 def test_render_tree(self):
777 def __init__(self, name, children=[]):
778 self.children = children
783 def get_children(node):
786 windows_h = Node("windows.h")
787 stdlib_h = Node("stdlib.h")
788 stdio_h = Node("stdio.h")
789 bar_c = Node("bar.c", [stdlib_h, windows_h])
790 bar_o = Node("bar.o", [bar_c])
791 foo_c = Node("foo.c", [stdio_h])
792 foo_o = Node("foo.o", [foo_c])
793 foo = Node("foo", [foo_o, bar_o])
806 actual = render_tree(foo, get_children)
807 assert expect == actual, (expect, actual)
809 bar_h = Node('bar.h', [stdlib_h])
810 blat_h = Node('blat.h', [stdlib_h])
811 blat_c = Node('blat.c', [blat_h, bar_h])
812 blat_o = Node('blat.o', [blat_c])
822 actual = render_tree(blat_o, get_children, 1)
823 assert expect == actual, (expect, actual)
825 def test_is_Dict(self):
828 assert is_Dict(UserDict.UserDict())
829 assert not is_Dict([])
830 assert not is_Dict("")
831 if hasattr(types, 'UnicodeType'):
832 exec "assert not is_Dict(u'')"
834 def test_is_List(self):
837 assert is_List(UserList.UserList())
838 assert not is_List({})
839 assert not is_List("")
840 if hasattr(types, 'UnicodeType'):
841 exec "assert not is_List(u'')"
843 def test_is_String(self):
845 if hasattr(types, 'UnicodeType'):
846 exec "assert is_String(u'')"
852 assert is_String(UserString.UserString(''))
853 assert not is_String({})
854 assert not is_String([])
856 def test_to_String(self):
857 """Test the to_String() method."""
858 assert to_String(1) == "1", to_String(1)
859 assert to_String([ 1, 2, 3]) == str([1, 2, 3]), to_String([1,2,3])
860 assert to_String("foo") == "foo", to_String("foo")
865 s1=UserString.UserString('blah')
866 assert to_String(s1) == s1, s1
867 assert to_String(s1) == 'blah', s1
869 class Derived(UserString.UserString):
872 assert to_String(s2) == s2, s2
873 assert to_String(s2) == 'foo', s2
875 if hasattr(types, 'UnicodeType'):
876 s3=UserString.UserString(unicode('bar'))
877 assert to_String(s3) == s3, s3
878 assert to_String(s3) == unicode('bar'), s3
879 assert type(to_String(s3)) is types.UnicodeType, \
884 if hasattr(types, 'UnicodeType'):
886 assert to_String(s4) == unicode('baz'), to_String(s4)
887 assert type(to_String(s4)) is types.UnicodeType, \
890 def test_WhereIs(self):
891 test = TestCmd.TestCmd(workdir = '')
893 sub1_xxx_exe = test.workpath('sub1', 'xxx.exe')
894 sub2_xxx_exe = test.workpath('sub2', 'xxx.exe')
895 sub3_xxx_exe = test.workpath('sub3', 'xxx.exe')
896 sub4_xxx_exe = test.workpath('sub4', 'xxx.exe')
898 test.subdir('subdir', 'sub1', 'sub2', 'sub3', 'sub4')
900 if sys.platform != 'win32':
901 test.write(sub1_xxx_exe, "\n")
903 os.mkdir(sub2_xxx_exe)
905 test.write(sub3_xxx_exe, "\n")
906 os.chmod(sub3_xxx_exe, 0777)
908 test.write(sub4_xxx_exe, "\n")
909 os.chmod(sub4_xxx_exe, 0777)
911 env_path = os.environ['PATH']
913 pathdirs_1234 = [ test.workpath('sub1'),
914 test.workpath('sub2'),
915 test.workpath('sub3'),
916 test.workpath('sub4'),
917 ] + string.split(env_path, os.pathsep)
919 pathdirs_1243 = [ test.workpath('sub1'),
920 test.workpath('sub2'),
921 test.workpath('sub4'),
922 test.workpath('sub3'),
923 ] + string.split(env_path, os.pathsep)
925 os.environ['PATH'] = string.join(pathdirs_1234, os.pathsep)
926 wi = WhereIs('xxx.exe')
927 assert wi == test.workpath(sub3_xxx_exe), wi
928 wi = WhereIs('xxx.exe', pathdirs_1243)
929 assert wi == test.workpath(sub4_xxx_exe), wi
930 wi = WhereIs('xxx.exe', string.join(pathdirs_1243, os.pathsep))
931 assert wi == test.workpath(sub4_xxx_exe), wi
933 os.environ['PATH'] = string.join(pathdirs_1243, os.pathsep)
934 wi = WhereIs('xxx.exe')
935 assert wi == test.workpath(sub4_xxx_exe), wi
936 wi = WhereIs('xxx.exe', pathdirs_1234)
937 assert wi == test.workpath(sub3_xxx_exe), wi
938 wi = WhereIs('xxx.exe', string.join(pathdirs_1234, os.pathsep))
939 assert wi == test.workpath(sub3_xxx_exe), wi
941 if sys.platform == 'win32':
942 wi = WhereIs('xxx', pathext = '')
943 assert wi is None, wi
945 wi = WhereIs('xxx', pathext = '.exe')
946 assert wi == test.workpath(sub4_xxx_exe), wi
948 wi = WhereIs('xxx', path = pathdirs_1234, pathext = '.BAT;.EXE')
949 assert string.lower(wi) == string.lower(test.workpath(sub3_xxx_exe)), wi
951 # Test that we return a normalized path even when
952 # the path contains forward slashes.
953 forward_slash = test.workpath('') + '/sub3'
954 wi = WhereIs('xxx', path = forward_slash, pathext = '.EXE')
955 assert string.lower(wi) == string.lower(test.workpath(sub3_xxx_exe)), wi
957 def test_is_valid_construction_var(self):
958 """Testing is_valid_construction_var()"""
959 r = is_valid_construction_var("_a")
960 assert not r is None, r
961 r = is_valid_construction_var("z_")
962 assert not r is None, r
963 r = is_valid_construction_var("X_")
964 assert not r is None, r
965 r = is_valid_construction_var("2a")
967 r = is_valid_construction_var("a2_")
968 assert not r is None, r
969 r = is_valid_construction_var("/")
971 r = is_valid_construction_var("_/")
973 r = is_valid_construction_var("a/")
975 r = is_valid_construction_var(".b")
977 r = is_valid_construction_var("_.b")
979 r = is_valid_construction_var("b1._")
981 r = is_valid_construction_var("-b")
983 r = is_valid_construction_var("_-b")
985 r = is_valid_construction_var("b1-_")
988 def test_get_env_var(self):
989 """Testing get_environment_var()."""
990 assert get_environment_var("$FOO") == "FOO", get_environment_var("$FOO")
991 assert get_environment_var("${BAR}") == "BAR", get_environment_var("${BAR}")
992 assert get_environment_var("$FOO_BAR1234") == "FOO_BAR1234", get_environment_var("$FOO_BAR1234")
993 assert get_environment_var("${BAR_FOO1234}") == "BAR_FOO1234", get_environment_var("${BAR_FOO1234}")
994 assert get_environment_var("${BAR}FOO") == None, get_environment_var("${BAR}FOO")
995 assert get_environment_var("$BAR ") == None, get_environment_var("$BAR ")
996 assert get_environment_var("FOO$BAR") == None, get_environment_var("FOO$BAR")
997 assert get_environment_var("$FOO[0]") == None, get_environment_var("$FOO[0]")
998 assert get_environment_var("${some('complex expression')}") == None, get_environment_var("${some('complex expression')}")
1000 def test_Proxy(self):
1001 """Test generic Proxy class."""
1011 class ProxyTest(Proxy):
1017 assert p.foo() == 1, p.foo()
1018 assert p.bar() == 4, p.bar()
1019 assert p.baz == 3, p.baz
1024 assert p.baz == 5, p.baz
1025 assert p.get() == s, p.get()
1027 def test_Literal(self):
1028 """Test the Literal() function."""
1029 input_list = [ '$FOO', Literal('$BAR') ]
1030 dummy_env = DummyEnv({ 'FOO' : 'BAZ', 'BAR' : 'BLAT' })
1032 def escape_func(cmd):
1033 return '**' + cmd + '**'
1035 cmd_list = scons_subst_list(input_list, dummy_env)
1036 cmd_list = SCons.Util.escape_list(cmd_list[0], escape_func)
1037 assert cmd_list == ['BAZ', '**$BAR**'], cmd_list
1039 def test_SpecialAttrWrapper(self):
1040 """Test the SpecialAttrWrapper() function."""
1041 input_list = [ '$FOO', SpecialAttrWrapper('$BAR', 'BLEH') ]
1042 dummy_env = DummyEnv({ 'FOO' : 'BAZ', 'BAR' : 'BLAT' })
1044 def escape_func(cmd):
1045 return '**' + cmd + '**'
1047 cmd_list = scons_subst_list(input_list, dummy_env)
1048 cmd_list = SCons.Util.escape_list(cmd_list[0], escape_func)
1049 assert cmd_list == ['BAZ', '**$BAR**'], cmd_list
1051 cmd_list = scons_subst_list(input_list, dummy_env, mode=SUBST_SIG)
1052 cmd_list = SCons.Util.escape_list(cmd_list[0], escape_func)
1053 assert cmd_list == ['BAZ', '**BLEH**'], cmd_list
1055 def test_mapPaths(self):
1056 """Test the mapPaths function"""
1058 def __init__(self, path):
1063 dir=MyFileNode('foo')
1064 file=MyFileNode('bar/file')
1067 def subst(self, arg):
1070 res = mapPaths([ file, 'baz', 'blat/boo', '#test' ], dir)
1071 assert res[0] == file, res[0]
1072 assert res[1] == os.path.join('foo', 'baz'), res[1]
1073 assert res[2] == os.path.join('foo', 'blat/boo'), res[2]
1074 assert res[3] == '#test', res[3]
1077 res=mapPaths('bleh', dir, env)
1078 assert res[0] == os.path.normpath('foo/bar'), res[1]
1080 def test_display(self):
1081 old_stdout = sys.stdout
1082 sys.stdout = OutBuffer()
1089 assert sys.stdout.buffer == "line1\nline3\n"
1090 sys.stdout = old_stdout
1092 def test_fs_delete(self):
1093 test = TestCmd.TestCmd(workdir = '')
1094 base = test.workpath('')
1095 xxx = test.workpath('xxx.xxx')
1096 ZZZ = test.workpath('ZZZ.ZZZ')
1097 sub1_yyy = test.workpath('sub1', 'yyy.yyy')
1100 test.write(xxx, "\n")
1101 test.write(ZZZ, "\n")
1102 test.write(sub1_yyy, "\n")
1104 old_stdout = sys.stdout
1105 sys.stdout = OutBuffer()
1107 exp = "Removed " + os.path.join(base, ZZZ) + "\n" + \
1108 "Removed " + os.path.join(base, sub1_yyy) + '\n' + \
1109 "Removed directory " + os.path.join(base, 'sub1') + '\n' + \
1110 "Removed " + os.path.join(base, xxx) + '\n' + \
1111 "Removed directory " + base + '\n'
1113 fs_delete(base, remove=0)
1114 assert sys.stdout.buffer == exp, sys.stdout.buffer
1115 assert os.path.exists(sub1_yyy)
1117 sys.stdout.buffer = ""
1118 fs_delete(base, remove=1)
1119 assert sys.stdout.buffer == exp
1120 assert not os.path.exists(base)
1122 test._dirlist = None
1123 sys.stdout = old_stdout
1125 def test_get_native_path(self):
1126 """Test the get_native_path() function."""
1128 filename = tempfile.mktemp()
1129 str = '1234567890 ' + filename
1130 open(filename, 'w').write(str)
1131 assert open(get_native_path(filename)).read() == str
1133 def test_subst_dict(self):
1134 """Test substituting dictionary values in an Action
1138 d = subst_dict(target=t, source=s)
1139 assert str(d['TARGETS'][0]) == 't', d['TARGETS']
1140 assert str(d['TARGET']) == 't', d['TARGET']
1141 assert str(d['SOURCES'][0]) == 's', d['SOURCES']
1142 assert str(d['SOURCE']) == 's', d['SOURCE']
1144 t1 = DummyNode('t1')
1145 t2 = DummyNode('t2')
1146 s1 = DummyNode('s1')
1147 s2 = DummyNode('s2')
1148 d = subst_dict(target=[t1, t2], source=[s1, s2])
1149 TARGETS = map(lambda x: str(x), d['TARGETS'])
1151 assert TARGETS == ['t1', 't2'], d['TARGETS']
1152 assert str(d['TARGET']) == 't1', d['TARGET']
1153 SOURCES = map(lambda x: str(x), d['SOURCES'])
1155 assert SOURCES == ['s1', 's2'], d['SOURCES']
1156 assert str(d['SOURCE']) == 's1', d['SOURCE']
1159 def __init__(self, name):
1164 return self.__class__('rstr-' + self.name)
1165 def get_subst_proxy(self):
1169 t4 = DummyNode('t4')
1170 s3 = DummyNode('s3')
1172 d = subst_dict(target=[t3, t4], source=[s3, s4])
1173 TARGETS = map(lambda x: str(x), d['TARGETS'])
1175 assert TARGETS == ['t3', 't4'], d['TARGETS']
1176 SOURCES = map(lambda x: str(x), d['SOURCES'])
1178 assert SOURCES == ['rstr-s4', 's3'], d['SOURCES']
1180 def test_PrependPath(self):
1181 """Test prepending to a path"""
1182 p1 = r'C:\dir\num\one;C:\dir\num\two'
1183 p2 = r'C:\mydir\num\one;C:\mydir\num\two'
1184 # have to include the pathsep here so that the test will work on UNIX too.
1185 p1 = PrependPath(p1,r'C:\dir\num\two',sep = ';')
1186 p1 = PrependPath(p1,r'C:\dir\num\three',sep = ';')
1187 p2 = PrependPath(p2,r'C:\mydir\num\three',sep = ';')
1188 p2 = PrependPath(p2,r'C:\mydir\num\one',sep = ';')
1189 assert(p1 == r'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one')
1190 assert(p2 == r'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two')
1192 def test_AppendPath(self):
1193 """Test appending to a path."""
1194 p1 = r'C:\dir\num\one;C:\dir\num\two'
1195 p2 = r'C:\mydir\num\one;C:\mydir\num\two'
1196 # have to include the pathsep here so that the test will work on UNIX too.
1197 p1 = AppendPath(p1,r'C:\dir\num\two',sep = ';')
1198 p1 = AppendPath(p1,r'C:\dir\num\three',sep = ';')
1199 p2 = AppendPath(p2,r'C:\mydir\num\three',sep = ';')
1200 p2 = AppendPath(p2,r'C:\mydir\num\one',sep = ';')
1201 assert(p1 == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three')
1202 assert(p2 == r'C:\mydir\num\two;C:\mydir\num\three;C:\mydir\num\one')
1204 def test_NodeList(self):
1205 """Test NodeList class"""
1207 def __init__(self, name, child=None):
1211 return self.bar + "foo"
1215 t1 = TestClass('t1', TestClass('t1child'))
1216 t2 = TestClass('t2', TestClass('t2child'))
1217 t3 = TestClass('t3')
1219 nl = NodeList([t1, t2, t3])
1220 assert nl.foo() == [ 't1foo', 't2foo', 't3foo' ], nl.foo()
1221 assert nl.bar == [ 't1', 't2', 't3' ], nl.bar
1222 assert nl.getself().bar == [ 't1', 't2', 't3' ], nl.getself().bar
1223 assert nl[0:2].child.foo() == [ 't1childfoo', 't2childfoo' ], \
1225 assert nl[0:2].child.bar == [ 't1child', 't2child' ], \
1228 def test_Selector(self):
1229 """Test the Selector class"""
1231 s = Selector({'a' : 'AAA', 'b' : 'BBB'})
1232 assert s['a'] == 'AAA', s['a']
1233 assert s['b'] == 'BBB', s['b']
1239 assert exc_caught, "should have caught a KeyError"
1241 assert s['c'] == 'CCC', s['c']
1243 class DummyEnv(UserDict.UserDict):
1244 def subst(self, key):
1246 return self[key[1:]]
1251 s = Selector({'.d' : 'DDD', '.e' : 'EEE'})
1252 ret = s(env, ['foo.d'])
1253 assert ret == 'DDD', ret
1254 ret = s(env, ['bar.e'])
1255 assert ret == 'EEE', ret
1256 ret = s(env, ['bar.x'])
1257 assert ret == None, ret
1259 ret = s(env, ['bar.x'])
1260 assert ret == 'XXX', ret
1262 env = DummyEnv({'FSUFF' : '.f', 'GSUFF' : '.g'})
1264 s = Selector({'$FSUFF' : 'FFF', '$GSUFF' : 'GGG'})
1265 ret = s(env, ['foo.f'])
1266 assert ret == 'FFF', ret
1267 ret = s(env, ['bar.g'])
1268 assert ret == 'GGG', ret
1270 def test_adjustixes(self):
1271 """Test the adjustixes() function"""
1272 r = adjustixes('file', 'pre-', '-suf')
1273 assert r == 'pre-file-suf', r
1274 r = adjustixes('pre-file', 'pre-', '-suf')
1275 assert r == 'pre-file-suf', r
1276 r = adjustixes('file-suf', 'pre-', '-suf')
1277 assert r == 'pre-file-suf', r
1278 r = adjustixes('pre-file-suf', 'pre-', '-suf')
1279 assert r == 'pre-file-suf', r
1280 r = adjustixes('pre-file.xxx', 'pre-', '-suf')
1281 assert r == 'pre-file.xxx', r
1282 r = adjustixes('dir/file', 'pre-', '-suf')
1283 assert r == os.path.join('dir', 'pre-file-suf'), r
1285 if __name__ == "__main__":
1286 suite = unittest.makeSuite(UtilTestCase, 'test_')
1287 if not unittest.TextTestRunner().run(suite).wasSuccessful():