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__"
33 from UserDict import UserDict
35 from SCons.Util import *
45 self.buffer = self.buffer + str
48 """Simple node work-alike."""
49 def __init__(self, name):
50 self.name = os.path.normpath(name)
57 def get_subst_proxy(self):
61 def __init__(self, dict={}):
64 def Dictionary(self, key = None):
69 def __getitem__(self, key):
72 def get(self, key, default):
73 return self.dict.get(key, default)
76 dict = self.dict.copy()
77 dict["TARGETS"] = 'tsig'
78 dict["SOURCES"] = 'ssig'
81 def cs(target=None, source=None, env=None, for_signature=None):
84 def cl(target=None, source=None, env=None, for_signature=None):
87 def CmdGen1(target, source, env, for_signature):
88 # Nifty trick...since Environment references are interpolated,
89 # instantiate an instance of a callable class with this one,
90 # which will then get evaluated.
91 assert str(target) == 't', target
92 assert str(source) == 's', source
93 return "${CMDGEN2('foo', %d)}" % for_signature
96 def __init__(self, mystr, forsig):
98 self.expect_for_signature = forsig
100 def __call__(self, target, source, env, for_signature):
101 assert str(target) == 't', target
102 assert str(source) == 's', source
103 assert for_signature == self.expect_for_signature, for_signature
104 return [ self.mystr, env.Dictionary('BAR') ]
111 return string.replace(str, '/', os.sep)
113 class UtilTestCase(unittest.TestCase):
114 def test_subst(self):
115 """Test the subst() function"""
116 class MyNode(DummyNode):
117 """Simple node work-alike with some extra stuff for testing."""
118 def __init__(self, name):
119 DummyNode.__init__(self, name)
122 self.attribute = Attribute()
123 self.attribute.attr1 = 'attr$1-' + os.path.basename(name)
124 self.attribute.attr2 = 'attr$2-' + os.path.basename(name)
125 def get_stuff(self, extra):
126 return self.name + extra
130 def __init__(self, literal):
131 self.literal = literal
134 def is_literal(self):
138 def __init__(self, value):
145 def function_foo(arg):
148 target = [ MyNode("./foo/bar.exe"),
149 MyNode("/bar/baz.obj"),
150 MyNode("../foo/baz.obj") ]
151 source = [ MyNode("./foo/blah.cpp"),
152 MyNode("/bar/ack.cpp"),
153 MyNode("../foo/ack.c") ]
169 # $XXX$HHH should expand to GGGIII, not BADNEWS.
173 'FFFIII' : 'BADNEWS',
175 'LITERAL' : TestLiteral("$XXX"),
177 # Test that we can expand to and return a function.
178 #'FUNCTION' : function_foo,
186 # Test various combinations of strings, lists and functions.
197 # Test function calls within ${}.
198 'FUNCCALL' : '${FUNC1("$AAA $FUNC2 $BBB")}',
199 'FUNC1' : lambda x: x,
200 'FUNC2' : lambda target, source, env, for_signature: ['x$CCC'],
202 # Various tests refactored from ActionTests.py.
203 'LIST' : [["This", "is", "$(", "$a", "$)", "test"]],
206 'RECURSE' : 'foo $RECURSE bar',
207 'RRR' : 'foo $SSS bar',
210 # Test callables that don't match the calling arguments.
211 'CALLABLE' : TestCallable('callable-1'),
216 # Basic tests of substitution functionality.
218 # Basics: strings without expansions are left alone, and
219 # the simplest possible expansion to a null-string value.
223 # Test expansion of integer values.
224 "test $zero", "test 0",
225 "test $one", "test 1",
227 # Test multiple re-expansion of values.
228 "test $ONE", "test four",
230 # Test a whole bunch of $TARGET[S] and $SOURCE[S] expansions.
231 "test $TARGETS $SOURCES",
232 "test foo/bar.exe /bar/baz.obj ../foo/baz.obj foo/blah.cpp /bar/ack.cpp ../foo/ack.c",
234 "test ${TARGETS[:]} ${SOURCES[0]}",
235 "test foo/bar.exe /bar/baz.obj ../foo/baz.obj foo/blah.cpp",
237 "test ${TARGETS[1:]}v",
238 "test /bar/baz.obj ../foo/baz.objv",
243 "test $TARGET$FOO[0]",
244 "test foo/bar.exe[0]",
249 "test ${SOURCES[0:2].foo}",
255 "test ${TARGET.get_stuff('blah')}",
256 "test foo/bar.exeblah",
258 "test ${SOURCES.get_stuff('blah')}",
259 "test foo/blah.cppblah /bar/ack.cppblah ../foo/ack.cblah",
261 "test ${SOURCES[0:2].get_stuff('blah')}",
262 "test foo/blah.cppblah /bar/ack.cppblah",
264 "test ${SOURCES[0:2].get_stuff('blah')}",
265 "test foo/blah.cppblah /bar/ack.cppblah",
267 "test ${SOURCES.attribute.attr1}",
268 "test attr$1-blah.cpp attr$1-ack.cpp attr$1-ack.c",
270 "test ${SOURCES.attribute.attr2}",
271 "test attr$2-blah.cpp attr$2-ack.cpp attr$2-ack.c",
273 # Test adjacent expansions.
280 # Test that adjacent expansions don't get re-interpreted
281 # together. The correct disambiguated expansion should be:
282 # $XXX$HHH => ${FFF}III => GGGIII
284 # $XXX$HHH => ${FFFIII} => BADNEWS
285 "$XXX$HHH", "GGGIII",
287 # Test double-dollar-sign behavior.
288 "$$FFF$HHH", "$FFFIII",
290 # Test that a Literal will stop dollar-sign substitution.
291 "$XXX $LITERAL $FFF", "GGG $XXX GGG",
293 # Test that we don't blow up even if they subscript
294 # something in ways they "can't."
300 # Test various combinations of strings and lists.
320 # Test function calls within ${}.
321 '$FUNCCALL', 'a xc b',
323 # Bug reported by Christoph Wiedemann.
324 cvt('$xxx/bin'), '/bin',
326 # Tests callables that don't match our calling arguments.
327 '$CALLABLE', 'callable-1',
330 kwargs = {'target' : target, 'source' : source}
334 input, expect = cases[:2]
336 result = apply(scons_subst, (input, env), kwargs)
338 if failed == 0: print
339 print " input %s => %s did not match %s" % (repr(input), repr(result), repr(expect))
342 assert failed == 0, "%d subst() cases failed" % failed
344 # Tests of the various SUBST_* modes of substitution.
361 "$AAA ${AAA}A $BBBB $BBB",
376 # Verify what happens with no target or source nodes.
387 # Various tests refactored from ActionTests.py.
389 "This is $( $) test",
393 ["|", "$(", "$AAA", "|", "$BBB", "$)", "|", "$CCC", 1],
394 "| $( a | b $) | c 1",
401 input, eraw, ecmd, esig = subst_cases[:4]
402 result = scons_subst(input, env, mode=SUBST_RAW)
404 if failed == 0: print
405 print " input %s => RAW %s did not match %s" % (repr(input), repr(result), repr(eraw))
407 result = scons_subst(input, env, mode=SUBST_CMD)
409 if failed == 0: print
410 print " input %s => CMD %s did not match %s" % (repr(input), repr(result), repr(ecmd))
412 result = scons_subst(input, env, mode=SUBST_SIG)
414 if failed == 0: print
415 print " input %s => SIG %s did not match %s" % (repr(input), repr(result), repr(esig))
418 assert failed == 0, "%d subst() mode cases failed" % failed
424 result = scons_subst("$TARGET $SOURCES", env,
427 assert result == "t1 s1 s2", result
428 result = scons_subst("$TARGET $SOURCES", env,
432 assert result == " ", result
434 result = scons_subst("$TARGET $SOURCES", env, target=[], source=[])
435 assert result == " ", result
436 result = scons_subst("$TARGETS $SOURCE", env, target=[], source=[])
437 assert result == " ", result
439 # Test interpolating a callable.
440 newcom = scons_subst("test $CMDGEN1 $SOURCES $TARGETS",
441 env, target=MyNode('t'), source=MyNode('s'))
442 assert newcom == "test foo baz s t", newcom
444 # Test that we handle syntax errors during expansion as expected.
446 scons_subst('$foo.bar.3.0', env)
447 except SCons.Errors.UserError, e:
448 expect1 = "Syntax error `invalid syntax' trying to evaluate `$foo.bar.3.0'"
449 expect2 = "Syntax error `invalid syntax (line 1)' trying to evaluate `$foo.bar.3.0'"
450 assert str(e) in [expect1, expect2], e
452 raise AssertionError, "did not catch expected UserError"
454 # Test how we handle overriding the internal conversion routines.
459 env = DummyEnv({'NODE' : n1})
460 node = scons_subst("$NODE", env, mode=SUBST_RAW, conv=s)
461 assert node is n1, node
462 node = scons_subst("$NODE", env, mode=SUBST_CMD, conv=s)
463 assert node is n1, node
464 node = scons_subst("$NODE", env, mode=SUBST_SIG, conv=s)
465 assert node is n1, node
467 # Test returning a function.
468 #env = DummyEnv({'FUNCTION' : foo})
469 #func = scons_subst("$FUNCTION", env, mode=SUBST_RAW, call=None)
470 #assert func is function_foo, func
471 #func = scons_subst("$FUNCTION", env, mode=SUBST_CMD, call=None)
472 #assert func is function_foo, func
473 #func = scons_subst("$FUNCTION", env, mode=SUBST_SIG, call=None)
474 #assert func is function_foo, func
476 # Test supplying an overriding gvars dictionary.
477 env = DummyEnv({'XXX' : 'xxx'})
478 result = scons_subst('$XXX', env)
479 assert result == 'xxx', result
480 result = scons_subst('$XXX', env, gvars={'XXX' : 'yyy'})
481 assert result == 'yyy', result
483 def test_subst_list(self):
484 """Testing the scons_subst_list() method..."""
485 class MyNode(DummyNode):
486 """Simple node work-alike with some extra stuff for testing."""
487 def __init__(self, name):
488 DummyNode.__init__(self, name)
491 self.attribute = Attribute()
492 self.attribute.attr1 = 'attr$1-' + os.path.basename(name)
493 self.attribute.attr2 = 'attr$2-' + os.path.basename(name)
496 def __init__(self, value):
503 target = [ MyNode("./foo/bar.exe"),
504 MyNode("/bar/baz with spaces.obj"),
505 MyNode("../foo/baz.obj") ]
506 source = [ MyNode("./foo/blah with spaces.cpp"),
507 MyNode("/bar/ack.cpp"),
508 MyNode("../foo/ack.c") ]
512 'NEWLINE' : 'before\nafter',
518 'DO' : DummyNode('do something'),
519 'FOO' : DummyNode('foo.in'),
520 'BAR' : DummyNode('bar with spaces.out'),
521 'CRAZY' : DummyNode('crazy\nfile.in'),
523 # $XXX$HHH should expand to GGGIII, not BADNEWS.
527 'FFFIII' : 'BADNEWS',
532 'LITERALS' : [ Literal('foo\nwith\nnewlines'),
533 Literal('bar\nwith\nnewlines') ],
535 # Test various combinations of strings, lists and functions.
546 # Test function calls within ${}.
547 'FUNCCALL' : '${FUNC1("$AAA $FUNC2 $BBB")}',
548 'FUNC1' : lambda x: x,
549 'FUNC2' : lambda target, source, env, for_signature: ['x$CCC'],
551 # Various tests refactored from ActionTests.py.
552 'LIST' : [["This", "is", "$(", "$a", "$)", "test"]],
555 'RECURSE' : 'foo $RECURSE bar',
556 'RRR' : 'foo $SSS bar',
559 # Test callable objects that don't match our calling arguments.
560 'CALLABLE' : TestCallable('callable-2'),
568 ["foo/bar.exe", "/bar/baz with spaces.obj", "../foo/baz.obj"],
571 "$SOURCES $NEWLINE $TARGETS",
573 ["foo/blah with spaces.cpp", "/bar/ack.cpp", "../foo/ack.c", "before"],
574 ["after", "foo/bar.exe", "/bar/baz with spaces.obj", "../foo/baz.obj"],
579 ["foo/blah with spaces.cpp", "/bar/ack.cpp", "../foo/ack.cbefore"],
593 "test ${SOURCES.attribute.attr1}",
595 ["test", "attr$1-blah with spaces.cpp", "attr$1-ack.cpp", "attr$1-ack.c"],
598 "test ${SOURCES.attribute.attr2}",
600 ["test", "attr$2-blah with spaces.cpp", "attr$2-ack.cpp", "attr$2-ack.c"],
603 "$DO --in=$FOO --out=$BAR",
605 ["do something", "--in=foo.in", "--out=bar with spaces.out"],
608 # This test is now fixed, and works like it should.
609 "$DO --in=$CRAZY --out=$BAR",
611 ["do something", "--in=crazy\nfile.in", "--out=bar with spaces.out"],
614 # Try passing a list to scons_subst_list().
615 [ "$SOURCES$NEWLINE", "$TARGETS", "This is a test"],
617 ["foo/blah with spaces.cpp", "/bar/ack.cpp", "../foo/ack.cbefore"],
618 ["after", "foo/bar.exe", "/bar/baz with spaces.obj", "../foo/baz.obj", "This is a test"],
621 # Test against a former bug in scons_subst_list().
627 # Test double-dollar-sign behavior.
633 # Test various combinations of strings, lists and functions.
642 ['x', 'y'], [['x', 'y']],
652 '$S z', [['x', 'y', 'z']],
653 ['$S'], [['x', 'y']],
654 ['$S z'], [['x', 'y z']], # XXX - IS THIS BEST?
655 ['$S', 'z'], [['x', 'y', 'z']],
657 '$LS z', [['x y', 'z']],
659 ['$LS z'], [['x y z']],
660 ['$LS', 'z'], [['x y', 'z']],
662 '$L z', [['x', 'y', 'z']],
663 ['$L'], [['x', 'y']],
664 ['$L z'], [['x', 'y z']], # XXX - IS THIS BEST?
665 ['$L', 'z'], [['x', 'y', 'z']],
675 # Test function calls within ${}.
676 '$FUNCCALL', [['a', 'xc', 'b']],
678 # Test handling of newlines in white space.
679 'foo\nbar', [['foo'], ['bar']],
680 'foo\n\nbar', [['foo'], ['bar']],
681 'foo \n \n bar', [['foo'], ['bar']],
682 'foo \nmiddle\n bar', [['foo'], ['middle'], ['bar']],
684 # Bug reported by Christoph Wiedemann.
685 cvt('$xxx/bin'), [['/bin']],
687 # Test variables smooshed together with different prefixes.
688 'foo$AAA', [['fooa']],
689 '<$AAA', [['<', 'a']],
690 '>$AAA', [['>', 'a']],
691 '|$AAA', [['|', 'a']],
693 # Test callables that don't match our calling arguments.
694 '$CALLABLE', [['callable-2']],
697 kwargs = {'target' : target, 'source' : source}
701 input, expect = cases[:2]
702 expect = map(lambda l: map(cvt, l), expect)
703 result = apply(scons_subst_list, (input, env), kwargs)
705 if failed == 0: print
706 print " input %s => %s did not match %s" % (repr(input), result, repr(expect))
709 assert failed == 0, "%d subst_list() cases failed" % failed
715 result = scons_subst_list("$TARGET $SOURCES", env,
718 assert result == [['t1', 's1', 's2']], result
719 result = scons_subst_list("$TARGET $SOURCES", env,
723 assert result == [[]], result
725 # Test interpolating a callable.
728 cmd_list = scons_subst_list("testing $CMDGEN1 $TARGETS $SOURCES",
729 env, target=_t, source=_s)
730 assert cmd_list == [['testing', 'foo', 'bar with spaces.out', 't', 's']], cmd_list
732 # Test escape functionality.
733 def escape_func(foo):
734 return '**' + foo + '**'
735 cmd_list = scons_subst_list("abc $LITERALS xyz", env)
736 assert cmd_list == [['abc',
737 'foo\nwith\nnewlines',
738 'bar\nwith\nnewlines',
740 c = cmd_list[0][0].escape(escape_func)
742 c = cmd_list[0][1].escape(escape_func)
743 assert c == '**foo\nwith\nnewlines**', c
744 c = cmd_list[0][2].escape(escape_func)
745 assert c == '**bar\nwith\nnewlines**', c
746 c = cmd_list[0][3].escape(escape_func)
749 cmd_list = scons_subst_list("abc${LITERALS}xyz", env)
750 c = cmd_list[0][0].escape(escape_func)
751 assert c == '**abcfoo\nwith\nnewlines**', c
752 c = cmd_list[0][1].escape(escape_func)
753 assert c == '**bar\nwith\nnewlinesxyz**', c
755 # Tests of the various SUBST_* modes of substitution.
768 [["test", "$(", "$)"]],
772 "$AAA ${AAA}A $BBBB $BBB",
787 # Verify what happens with no target or source nodes.
798 # Various test refactored from ActionTests.py
800 [['This', 'is', '$(', '$)', 'test']],
801 [['This', 'is', 'test']],
802 [['This', 'is', 'test']],
804 ["|", "$(", "$AAA", "|", "$BBB", "$)", "|", "$CCC", 1],
805 [["|", "$(", "a", "|", "b", "$)", "|", "c", "1"]],
806 [["|", "a", "|", "b", "|", "c", "1"]],
807 [["|", "|", "c", "1"]],
810 r = scons_subst_list("$TARGET $SOURCES", env, mode=SUBST_RAW)
814 while subst_list_cases:
815 input, eraw, ecmd, esig = subst_list_cases[:4]
816 result = scons_subst_list(input, env, mode=SUBST_RAW)
818 if failed == 0: print
819 print " input %s => RAW %s did not match %s" % (repr(input), repr(result), repr(eraw))
821 result = scons_subst_list(input, env, mode=SUBST_CMD)
823 if failed == 0: print
824 print " input %s => CMD %s did not match %s" % (repr(input), repr(result), repr(ecmd))
826 result = scons_subst_list(input, env, mode=SUBST_SIG)
828 if failed == 0: print
829 print " input %s => SIG %s did not match %s" % (repr(input), repr(result), repr(esig))
831 del subst_list_cases[:4]
832 assert failed == 0, "%d subst() mode cases failed" % failed
834 # Test that we handle syntax errors during expansion as expected.
836 scons_subst_list('$foo.bar.3.0', env)
837 except SCons.Errors.UserError, e:
838 expect1 = "Syntax error `invalid syntax' trying to evaluate `$foo.bar.3.0'"
839 expect2 = "Syntax error `invalid syntax (line 1)' trying to evaluate `$foo.bar.3.0'"
840 assert str(e) in [expect1, expect2], e
842 raise AssertionError, "did not catch expected SyntaxError"
844 # Test we handle overriding the internal conversion routines.
849 env = DummyEnv({'NODE' : n1})
850 node = scons_subst_list("$NODE", env, mode=SUBST_RAW, conv=s)
851 assert node == [[n1]], node
852 node = scons_subst_list("$NODE", env, mode=SUBST_CMD, conv=s)
853 assert node == [[n1]], node
854 node = scons_subst_list("$NODE", env, mode=SUBST_SIG, conv=s)
855 assert node == [[n1]], node
857 # Test supplying an overriding gvars dictionary.
858 env = DummyEnv({'XXX' : 'xxx'})
859 result = scons_subst_list('$XXX', env)
860 assert result == [['xxx']], result
861 result = scons_subst_list('$XXX', env, gvars={'XXX' : 'yyy'})
862 assert result == [['yyy']], result
864 def test_subst_once(self):
865 """Testing the scons_subst_once() method"""
870 'RECURSE' : 'r $RECURSE r',
871 'LIST' : ['a', 'b', 'c'],
903 ['x', 'a', 'b', 'c', 'y'],
905 ['x', 'x $LIST y', 'y'],
907 ['x', 'x a b c y', 'y'],
909 ['x', 'x $CCFLAGS y', 'y'],
911 ['x', 'x $CCFLAGS y', 'y'],
913 ['x', 'x $RECURSE y', 'y'],
915 ['x', 'x $RECURSE y', 'y'],
920 input, key, expect = cases[:3]
921 result = scons_subst_once(input, env, key)
923 if failed == 0: print
924 print " input %s (%s) => %s did not match %s" % (repr(input), repr(key), repr(result), repr(expect))
927 assert failed == 0, "%d subst() cases failed" % failed
929 def test_splitext(self):
930 assert splitext('foo') == ('foo','')
931 assert splitext('foo.bar') == ('foo','.bar')
932 assert splitext(os.path.join('foo.bar', 'blat')) == (os.path.join('foo.bar', 'blat'),'')
934 def test_quote_spaces(self):
935 """Testing the quote_spaces() method..."""
936 q = quote_spaces('x')
939 q = quote_spaces('x x')
940 assert q == '"x x"', q
942 q = quote_spaces('x\tx')
943 assert q == '"x\tx"', q
945 def tree_case_1(self):
946 """Fixture for the render_tree() and print_tree() tests."""
948 def __init__(self, name, children=[]):
949 self.children = children
954 windows_h = Node("windows.h")
955 stdlib_h = Node("stdlib.h")
956 stdio_h = Node("stdio.h")
957 bar_c = Node("bar.c", [stdlib_h, windows_h])
958 bar_o = Node("bar.o", [bar_c])
959 foo_c = Node("foo.c", [stdio_h])
960 foo_o = Node("foo.o", [foo_c])
961 foo = Node("foo", [foo_o, bar_o])
976 def tree_case_2(self):
977 """Fixture for the render_tree() and print_tree() tests."""
979 def __init__(self, name, children=[]):
980 self.children = children
985 stdlib_h = Node("stdlib.h")
986 bar_h = Node('bar.h', [stdlib_h])
987 blat_h = Node('blat.h', [stdlib_h])
988 blat_c = Node('blat.c', [blat_h, bar_h])
989 blat_o = Node('blat.o', [blat_c])
999 return blat_o, expect
1001 def test_render_tree(self):
1002 """Test the render_tree() function"""
1003 def get_children(node):
1004 return node.children
1006 node, expect = self.tree_case_1()
1007 actual = render_tree(node, get_children)
1008 assert expect == actual, (expect, actual)
1010 node, expect = self.tree_case_2()
1011 actual = render_tree(node, get_children, 1)
1012 assert expect == actual, (expect, actual)
1014 def test_print_tree(self):
1015 """Test the print_tree() function"""
1016 def get_children(node):
1017 return node.children
1019 save_stdout = sys.stdout
1022 sys.stdout = StringIO.StringIO()
1023 node, expect = self.tree_case_1()
1024 print_tree(node, get_children)
1025 actual = sys.stdout.getvalue()
1026 assert expect == actual, (expect, actual)
1028 sys.stdout = StringIO.StringIO()
1029 node, expect = self.tree_case_2()
1030 print_tree(node, get_children, 1)
1031 actual = sys.stdout.getvalue()
1032 assert expect == actual, (expect, actual)
1034 sys.stdout = save_stdout
1036 def test_is_Dict(self):
1038 assert is_Dict(UserDict())
1039 assert not is_Dict([])
1040 assert not is_Dict("")
1041 if hasattr(types, 'UnicodeType'):
1042 exec "assert not is_Dict(u'')"
1044 def test_is_List(self):
1047 assert is_List(UserList.UserList())
1048 assert not is_List({})
1049 assert not is_List("")
1050 if hasattr(types, 'UnicodeType'):
1051 exec "assert not is_List(u'')"
1053 def test_is_String(self):
1054 assert is_String("")
1055 if hasattr(types, 'UnicodeType'):
1056 exec "assert is_String(u'')"
1062 assert is_String(UserString.UserString(''))
1063 assert not is_String({})
1064 assert not is_String([])
1066 def test_to_String(self):
1067 """Test the to_String() method."""
1068 assert to_String(1) == "1", to_String(1)
1069 assert to_String([ 1, 2, 3]) == str([1, 2, 3]), to_String([1,2,3])
1070 assert to_String("foo") == "foo", to_String("foo")
1075 s1=UserString.UserString('blah')
1076 assert to_String(s1) == s1, s1
1077 assert to_String(s1) == 'blah', s1
1079 class Derived(UserString.UserString):
1082 assert to_String(s2) == s2, s2
1083 assert to_String(s2) == 'foo', s2
1085 if hasattr(types, 'UnicodeType'):
1086 s3=UserString.UserString(unicode('bar'))
1087 assert to_String(s3) == s3, s3
1088 assert to_String(s3) == unicode('bar'), s3
1089 assert type(to_String(s3)) is types.UnicodeType, \
1094 if hasattr(types, 'UnicodeType'):
1096 assert to_String(s4) == unicode('baz'), to_String(s4)
1097 assert type(to_String(s4)) is types.UnicodeType, \
1100 def test_WhereIs(self):
1101 test = TestCmd.TestCmd(workdir = '')
1103 sub1_xxx_exe = test.workpath('sub1', 'xxx.exe')
1104 sub2_xxx_exe = test.workpath('sub2', 'xxx.exe')
1105 sub3_xxx_exe = test.workpath('sub3', 'xxx.exe')
1106 sub4_xxx_exe = test.workpath('sub4', 'xxx.exe')
1108 test.subdir('subdir', 'sub1', 'sub2', 'sub3', 'sub4')
1110 if sys.platform != 'win32':
1111 test.write(sub1_xxx_exe, "\n")
1113 os.mkdir(sub2_xxx_exe)
1115 test.write(sub3_xxx_exe, "\n")
1116 os.chmod(sub3_xxx_exe, 0777)
1118 test.write(sub4_xxx_exe, "\n")
1119 os.chmod(sub4_xxx_exe, 0777)
1121 env_path = os.environ['PATH']
1124 pathdirs_1234 = [ test.workpath('sub1'),
1125 test.workpath('sub2'),
1126 test.workpath('sub3'),
1127 test.workpath('sub4'),
1128 ] + string.split(env_path, os.pathsep)
1130 pathdirs_1243 = [ test.workpath('sub1'),
1131 test.workpath('sub2'),
1132 test.workpath('sub4'),
1133 test.workpath('sub3'),
1134 ] + string.split(env_path, os.pathsep)
1136 os.environ['PATH'] = string.join(pathdirs_1234, os.pathsep)
1137 wi = WhereIs('xxx.exe')
1138 assert wi == test.workpath(sub3_xxx_exe), wi
1139 wi = WhereIs('xxx.exe', pathdirs_1243)
1140 assert wi == test.workpath(sub4_xxx_exe), wi
1141 wi = WhereIs('xxx.exe', string.join(pathdirs_1243, os.pathsep))
1142 assert wi == test.workpath(sub4_xxx_exe), wi
1144 wi = WhereIs('xxx.exe',reject = sub3_xxx_exe)
1145 assert wi == test.workpath(sub4_xxx_exe), wi
1146 wi = WhereIs('xxx.exe', pathdirs_1243, reject = sub3_xxx_exe)
1147 assert wi == test.workpath(sub4_xxx_exe), wi
1149 os.environ['PATH'] = string.join(pathdirs_1243, os.pathsep)
1150 wi = WhereIs('xxx.exe')
1151 assert wi == test.workpath(sub4_xxx_exe), wi
1152 wi = WhereIs('xxx.exe', pathdirs_1234)
1153 assert wi == test.workpath(sub3_xxx_exe), wi
1154 wi = WhereIs('xxx.exe', string.join(pathdirs_1234, os.pathsep))
1155 assert wi == test.workpath(sub3_xxx_exe), wi
1157 if sys.platform == 'win32':
1158 wi = WhereIs('xxx', pathext = '')
1159 assert wi is None, wi
1161 wi = WhereIs('xxx', pathext = '.exe')
1162 assert wi == test.workpath(sub4_xxx_exe), wi
1164 wi = WhereIs('xxx', path = pathdirs_1234, pathext = '.BAT;.EXE')
1165 assert string.lower(wi) == string.lower(test.workpath(sub3_xxx_exe)), wi
1167 # Test that we return a normalized path even when
1168 # the path contains forward slashes.
1169 forward_slash = test.workpath('') + '/sub3'
1170 wi = WhereIs('xxx', path = forward_slash, pathext = '.EXE')
1171 assert string.lower(wi) == string.lower(test.workpath(sub3_xxx_exe)), wi
1173 del os.environ['PATH']
1174 wi = WhereIs('xxx.exe')
1175 assert wi is None, wi
1178 os.environ['PATH'] = env_path
1181 def test_is_valid_construction_var(self):
1182 """Testing is_valid_construction_var()"""
1183 r = is_valid_construction_var("_a")
1184 assert not r is None, r
1185 r = is_valid_construction_var("z_")
1186 assert not r is None, r
1187 r = is_valid_construction_var("X_")
1188 assert not r is None, r
1189 r = is_valid_construction_var("2a")
1191 r = is_valid_construction_var("a2_")
1192 assert not r is None, r
1193 r = is_valid_construction_var("/")
1195 r = is_valid_construction_var("_/")
1197 r = is_valid_construction_var("a/")
1199 r = is_valid_construction_var(".b")
1201 r = is_valid_construction_var("_.b")
1203 r = is_valid_construction_var("b1._")
1205 r = is_valid_construction_var("-b")
1207 r = is_valid_construction_var("_-b")
1209 r = is_valid_construction_var("b1-_")
1212 def test_get_env_var(self):
1213 """Testing get_environment_var()."""
1214 assert get_environment_var("$FOO") == "FOO", get_environment_var("$FOO")
1215 assert get_environment_var("${BAR}") == "BAR", get_environment_var("${BAR}")
1216 assert get_environment_var("$FOO_BAR1234") == "FOO_BAR1234", get_environment_var("$FOO_BAR1234")
1217 assert get_environment_var("${BAR_FOO1234}") == "BAR_FOO1234", get_environment_var("${BAR_FOO1234}")
1218 assert get_environment_var("${BAR}FOO") == None, get_environment_var("${BAR}FOO")
1219 assert get_environment_var("$BAR ") == None, get_environment_var("$BAR ")
1220 assert get_environment_var("FOO$BAR") == None, get_environment_var("FOO$BAR")
1221 assert get_environment_var("$FOO[0]") == None, get_environment_var("$FOO[0]")
1222 assert get_environment_var("${some('complex expression')}") == None, get_environment_var("${some('complex expression')}")
1224 def test_Proxy(self):
1225 """Test generic Proxy class."""
1235 class ProxyTest(Proxy):
1241 assert p.foo() == 1, p.foo()
1242 assert p.bar() == 4, p.bar()
1243 assert p.baz == 3, p.baz
1248 assert p.baz == 5, p.baz
1249 assert p.get() == s, p.get()
1251 def test_Literal(self):
1252 """Test the Literal() function."""
1253 input_list = [ '$FOO', Literal('$BAR') ]
1254 dummy_env = DummyEnv({ 'FOO' : 'BAZ', 'BAR' : 'BLAT' })
1256 def escape_func(cmd):
1257 return '**' + cmd + '**'
1259 cmd_list = scons_subst_list(input_list, dummy_env)
1260 cmd_list = SCons.Util.escape_list(cmd_list[0], escape_func)
1261 assert cmd_list == ['BAZ', '**$BAR**'], cmd_list
1263 def test_SpecialAttrWrapper(self):
1264 """Test the SpecialAttrWrapper() function."""
1265 input_list = [ '$FOO', SpecialAttrWrapper('$BAR', 'BLEH') ]
1266 dummy_env = DummyEnv({ 'FOO' : 'BAZ', 'BAR' : 'BLAT' })
1268 def escape_func(cmd):
1269 return '**' + cmd + '**'
1271 cmd_list = scons_subst_list(input_list, dummy_env)
1272 cmd_list = SCons.Util.escape_list(cmd_list[0], escape_func)
1273 assert cmd_list == ['BAZ', '**$BAR**'], cmd_list
1275 cmd_list = scons_subst_list(input_list, dummy_env, mode=SUBST_SIG)
1276 cmd_list = SCons.Util.escape_list(cmd_list[0], escape_func)
1277 assert cmd_list == ['BAZ', '**BLEH**'], cmd_list
1279 def test_display(self):
1280 old_stdout = sys.stdout
1281 sys.stdout = OutBuffer()
1287 display("line4\n", append_newline=0)
1289 display("dont print1")
1290 display("dont print2\n", append_newline=0)
1292 assert sys.stdout.buffer == "line1\nline3\nline4\n"
1293 sys.stdout = old_stdout
1295 def test_fs_delete(self):
1296 test = TestCmd.TestCmd(workdir = '')
1297 base = test.workpath('')
1298 xxx = test.workpath('xxx.xxx')
1299 ZZZ = test.workpath('ZZZ.ZZZ')
1300 sub1_yyy = test.workpath('sub1', 'yyy.yyy')
1303 test.write(xxx, "\n")
1304 test.write(ZZZ, "\n")
1305 test.write(sub1_yyy, "\n")
1307 old_stdout = sys.stdout
1308 sys.stdout = OutBuffer()
1310 exp = "Removed " + os.path.join(base, ZZZ) + "\n" + \
1311 "Removed " + os.path.join(base, sub1_yyy) + '\n' + \
1312 "Removed directory " + os.path.join(base, 'sub1') + '\n' + \
1313 "Removed " + os.path.join(base, xxx) + '\n' + \
1314 "Removed directory " + base + '\n'
1316 fs_delete(base, remove=0)
1317 assert sys.stdout.buffer == exp, sys.stdout.buffer
1318 assert os.path.exists(sub1_yyy)
1320 sys.stdout.buffer = ""
1321 fs_delete(base, remove=1)
1322 assert sys.stdout.buffer == exp
1323 assert not os.path.exists(base)
1325 test._dirlist = None
1326 sys.stdout = old_stdout
1328 def test_get_native_path(self):
1329 """Test the get_native_path() function."""
1331 filename = tempfile.mktemp()
1332 str = '1234567890 ' + filename
1334 open(filename, 'w').write(str)
1335 assert open(get_native_path(filename)).read() == str
1342 def test_subst_dict(self):
1343 """Test substituting dictionary values in an Action
1347 d = subst_dict(target=t, source=s)
1348 assert str(d['TARGETS'][0]) == 't', d['TARGETS']
1349 assert str(d['TARGET']) == 't', d['TARGET']
1350 assert str(d['SOURCES'][0]) == 's', d['SOURCES']
1351 assert str(d['SOURCE']) == 's', d['SOURCE']
1353 t1 = DummyNode('t1')
1354 t2 = DummyNode('t2')
1355 s1 = DummyNode('s1')
1356 s2 = DummyNode('s2')
1357 d = subst_dict(target=[t1, t2], source=[s1, s2])
1358 TARGETS = map(lambda x: str(x), d['TARGETS'])
1360 assert TARGETS == ['t1', 't2'], d['TARGETS']
1361 assert str(d['TARGET']) == 't1', d['TARGET']
1362 SOURCES = map(lambda x: str(x), d['SOURCES'])
1364 assert SOURCES == ['s1', 's2'], d['SOURCES']
1365 assert str(d['SOURCE']) == 's1', d['SOURCE']
1368 def __init__(self, name):
1373 return self.__class__('rstr-' + self.name)
1374 def get_subst_proxy(self):
1378 t4 = DummyNode('t4')
1379 s3 = DummyNode('s3')
1381 d = subst_dict(target=[t3, t4], source=[s3, s4])
1382 TARGETS = map(lambda x: str(x), d['TARGETS'])
1384 assert TARGETS == ['t3', 't4'], d['TARGETS']
1385 SOURCES = map(lambda x: str(x), d['SOURCES'])
1387 assert SOURCES == ['rstr-s4', 's3'], d['SOURCES']
1389 def test_PrependPath(self):
1390 """Test prepending to a path"""
1391 p1 = r'C:\dir\num\one;C:\dir\num\two'
1392 p2 = r'C:\mydir\num\one;C:\mydir\num\two'
1393 # have to include the pathsep here so that the test will work on UNIX too.
1394 p1 = PrependPath(p1,r'C:\dir\num\two',sep = ';')
1395 p1 = PrependPath(p1,r'C:\dir\num\three',sep = ';')
1396 p2 = PrependPath(p2,r'C:\mydir\num\three',sep = ';')
1397 p2 = PrependPath(p2,r'C:\mydir\num\one',sep = ';')
1398 assert(p1 == r'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one')
1399 assert(p2 == r'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two')
1401 def test_AppendPath(self):
1402 """Test appending to a path."""
1403 p1 = r'C:\dir\num\one;C:\dir\num\two'
1404 p2 = r'C:\mydir\num\one;C:\mydir\num\two'
1405 # have to include the pathsep here so that the test will work on UNIX too.
1406 p1 = AppendPath(p1,r'C:\dir\num\two',sep = ';')
1407 p1 = AppendPath(p1,r'C:\dir\num\three',sep = ';')
1408 p2 = AppendPath(p2,r'C:\mydir\num\three',sep = ';')
1409 p2 = AppendPath(p2,r'C:\mydir\num\one',sep = ';')
1410 assert(p1 == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three')
1411 assert(p2 == r'C:\mydir\num\two;C:\mydir\num\three;C:\mydir\num\one')
1413 def test_NodeList(self):
1414 """Test NodeList class"""
1416 def __init__(self, name, child=None):
1420 return self.bar + "foo"
1424 t1 = TestClass('t1', TestClass('t1child'))
1425 t2 = TestClass('t2', TestClass('t2child'))
1426 t3 = TestClass('t3')
1428 nl = NodeList([t1, t2, t3])
1429 assert nl.foo() == [ 't1foo', 't2foo', 't3foo' ], nl.foo()
1430 assert nl.bar == [ 't1', 't2', 't3' ], nl.bar
1431 assert nl.getself().bar == [ 't1', 't2', 't3' ], nl.getself().bar
1432 assert nl[0:2].child.foo() == [ 't1childfoo', 't2childfoo' ], \
1434 assert nl[0:2].child.bar == [ 't1child', 't2child' ], \
1437 def test_CLVar(self):
1438 """Test the command-line construction variable class"""
1439 f = SCons.Util.CLVar('a b')
1442 assert isinstance(r, SCons.Util.CLVar), type(r)
1443 assert r.data == ['a', 'b', 'c', 'd'], r.data
1444 assert str(r) == 'a b c d', str(r)
1447 assert isinstance(r, SCons.Util.CLVar), type(r)
1448 assert r.data == ['a', 'b', 'c', 'd'], r.data
1449 assert str(r) == 'a b c d', str(r)
1452 assert isinstance(r, SCons.Util.CLVar), type(r)
1453 assert r.data == ['a', 'b', 'c d'], r.data
1454 assert str(r) == 'a b c d', str(r)
1457 assert isinstance(r, SCons.Util.CLVar), type(r)
1458 assert r.data == ['a', 'b', ' c d'], r.data
1459 assert str(r) == 'a b c d', str(r)
1462 assert isinstance(r, SCons.Util.CLVar), type(r)
1463 assert r.data == ['a', 'b', 'c', 'd'], r.data
1464 assert str(r) == 'a b c d', str(r)
1467 assert isinstance(r, SCons.Util.CLVar), type(r)
1468 assert r.data == ['a', 'b', ' c', 'd'], r.data
1469 assert str(r) == 'a b c d', str(r)
1471 f = SCons.Util.CLVar(['a b'])
1474 assert isinstance(r, SCons.Util.CLVar), type(r)
1475 assert r.data == ['a b', 'c', 'd'], r.data
1476 assert str(r) == 'a b c d', str(r)
1479 assert isinstance(r, SCons.Util.CLVar), type(r)
1480 assert r.data == ['a b', 'c', 'd'], r.data
1481 assert str(r) == 'a b c d', str(r)
1484 assert isinstance(r, SCons.Util.CLVar), type(r)
1485 assert r.data == ['a b', 'c d'], r.data
1486 assert str(r) == 'a b c d', str(r)
1489 assert isinstance(r, SCons.Util.CLVar), type(r)
1490 assert r.data == ['a b', ' c d'], r.data
1491 assert str(r) == 'a b c d', str(r)
1494 assert isinstance(r, SCons.Util.CLVar), type(r)
1495 assert r.data == ['a b', 'c', 'd'], r.data
1496 assert str(r) == 'a b c d', str(r)
1499 assert isinstance(r, SCons.Util.CLVar), type(r)
1500 assert r.data == ['a b', ' c', 'd'], r.data
1501 assert str(r) == 'a b c d', str(r)
1503 f = SCons.Util.CLVar(['a', 'b'])
1506 assert isinstance(r, SCons.Util.CLVar), type(r)
1507 assert r.data == ['a', 'b', 'c', 'd'], r.data
1508 assert str(r) == 'a b c d', str(r)
1511 assert isinstance(r, SCons.Util.CLVar), type(r)
1512 assert r.data == ['a', 'b', 'c', 'd'], r.data
1513 assert str(r) == 'a b c d', str(r)
1516 assert isinstance(r, SCons.Util.CLVar), type(r)
1517 assert r.data == ['a', 'b', 'c d'], r.data
1518 assert str(r) == 'a b c d', str(r)
1521 assert isinstance(r, SCons.Util.CLVar), type(r)
1522 assert r.data == ['a', 'b', ' c d'], r.data
1523 assert str(r) == 'a b c d', str(r)
1526 assert isinstance(r, SCons.Util.CLVar), type(r)
1527 assert r.data == ['a', 'b', 'c', 'd'], r.data
1528 assert str(r) == 'a b c d', str(r)
1531 assert isinstance(r, SCons.Util.CLVar), type(r)
1532 assert r.data == ['a', 'b', ' c', 'd'], r.data
1533 assert str(r) == 'a b c d', str(r)
1537 loc['BAR'] = SCons.Util.CLVar('bar')
1538 loc['CALL'] = lambda target, source, env, for_signature: 'call'
1541 cmd = SCons.Util.CLVar("test $FOO $BAR $CALL test")
1543 newcmd = scons_subst(cmd, env)
1544 assert newcmd == 'test foo bar call test', newcmd
1546 cmd_list = scons_subst_list(cmd, env)
1547 assert len(cmd_list) == 1, cmd_list
1548 assert cmd_list[0][0] == "test", cmd_list[0][0]
1549 assert cmd_list[0][1] == "foo", cmd_list[0][1]
1550 assert cmd_list[0][2] == "bar", cmd_list[0][2]
1551 assert cmd_list[0][3] == "call", cmd_list[0][3]
1552 assert cmd_list[0][4] == "test", cmd_list[0][4]
1554 def test_Selector(self):
1555 """Test the Selector class"""
1557 s = Selector({'a' : 'AAA', 'b' : 'BBB'})
1558 assert s['a'] == 'AAA', s['a']
1559 assert s['b'] == 'BBB', s['b']
1565 assert exc_caught, "should have caught a KeyError"
1567 assert s['c'] == 'CCC', s['c']
1569 class DummyEnv(UserDict):
1570 def subst(self, key):
1572 return self[key[1:]]
1577 s = Selector({'.d' : 'DDD', '.e' : 'EEE'})
1579 assert ret == None, ret
1580 ret = s(env, ['foo.d'])
1581 assert ret == 'DDD', ret
1582 ret = s(env, ['bar.e'])
1583 assert ret == 'EEE', ret
1584 ret = s(env, ['bar.x'])
1585 assert ret == None, ret
1587 ret = s(env, ['bar.x'])
1588 assert ret == 'XXX', ret
1590 env = DummyEnv({'FSUFF' : '.f', 'GSUFF' : '.g'})
1592 s = Selector({'$FSUFF' : 'FFF', '$GSUFF' : 'GGG'})
1593 ret = s(env, ['foo.f'])
1594 assert ret == 'FFF', ret
1595 ret = s(env, ['bar.g'])
1596 assert ret == 'GGG', ret
1598 def test_adjustixes(self):
1599 """Test the adjustixes() function"""
1600 r = adjustixes('file', 'pre-', '-suf')
1601 assert r == 'pre-file-suf', r
1602 r = adjustixes('pre-file', 'pre-', '-suf')
1603 assert r == 'pre-file-suf', r
1604 r = adjustixes('file-suf', 'pre-', '-suf')
1605 assert r == 'pre-file-suf', r
1606 r = adjustixes('pre-file-suf', 'pre-', '-suf')
1607 assert r == 'pre-file-suf', r
1608 r = adjustixes('pre-file.xxx', 'pre-', '-suf')
1609 assert r == 'pre-file.xxx', r
1610 r = adjustixes('dir/file', 'pre-', '-suf')
1611 assert r == os.path.join('dir', 'pre-file-suf'), r
1613 def test_containsAny(self):
1614 """Test the containsAny() function"""
1615 assert containsAny('*.py', '*?[]')
1616 assert not containsAny('file.txt', '*?[]')
1618 def test_containsAll(self):
1619 """Test the containsAll() function"""
1620 assert containsAll('43221', '123')
1621 assert not containsAll('134', '123')
1623 def test_containsOnly(self):
1624 """Test the containsOnly() function"""
1625 assert containsOnly('.83', '0123456789.')
1626 assert not containsOnly('43221', '123')
1628 def test_LogicalLines(self):
1629 """Test the LogicalLines class"""
1630 fobj = StringIO.StringIO(r"""
1640 lines = LogicalLines(fobj).readlines()
1645 'bling bling \\ bling\n',
1649 if __name__ == "__main__":
1650 suite = unittest.makeSuite(UtilTestCase, 'test_')
1651 if not unittest.TextTestRunner().run(suite).wasSuccessful():