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,
331 'gvars' : env.Dictionary()}
335 input, expect = cases[:2]
337 result = apply(scons_subst, (input, env), kwargs)
339 if failed == 0: print
340 print " input %s => %s did not match %s" % (repr(input), repr(result), repr(expect))
343 assert failed == 0, "%d subst() cases failed" % failed
345 # The expansion dictionary no longer comes from the construction
346 # environment automatically.
347 s = scons_subst('$AAA', env)
350 # Tests of the various SUBST_* modes of substitution.
367 "$AAA ${AAA}A $BBBB $BBB",
382 # Verify what happens with no target or source nodes.
393 # Various tests refactored from ActionTests.py.
395 "This is $( $) test",
399 ["|", "$(", "$AAA", "|", "$BBB", "$)", "|", "$CCC", 1],
400 "| $( a | b $) | c 1",
405 gvars = env.Dictionary()
409 input, eraw, ecmd, esig = subst_cases[:4]
410 result = scons_subst(input, env, mode=SUBST_RAW, gvars=gvars)
412 if failed == 0: print
413 print " input %s => RAW %s did not match %s" % (repr(input), repr(result), repr(eraw))
415 result = scons_subst(input, env, mode=SUBST_CMD, gvars=gvars)
417 if failed == 0: print
418 print " input %s => CMD %s did not match %s" % (repr(input), repr(result), repr(ecmd))
420 result = scons_subst(input, env, mode=SUBST_SIG, gvars=gvars)
422 if failed == 0: print
423 print " input %s => SIG %s did not match %s" % (repr(input), repr(result), repr(esig))
426 assert failed == 0, "%d subst() mode cases failed" % failed
432 result = scons_subst("$TARGET $SOURCES", env,
435 assert result == "t1 s1 s2", result
436 result = scons_subst("$TARGET $SOURCES", env,
440 assert result == "t1 s1 s2", result
442 result = scons_subst("$TARGET $SOURCES", env, target=[], source=[])
443 assert result == " ", result
444 result = scons_subst("$TARGETS $SOURCE", env, target=[], source=[])
445 assert result == " ", result
447 # Test interpolating a callable.
448 newcom = scons_subst("test $CMDGEN1 $SOURCES $TARGETS",
449 env, target=MyNode('t'), source=MyNode('s'),
451 assert newcom == "test foo baz s t", newcom
453 # Test that we handle syntax errors during expansion as expected.
455 scons_subst('$foo.bar.3.0', env)
456 except SCons.Errors.UserError, e:
457 expect1 = "Syntax error `invalid syntax' trying to evaluate `$foo.bar.3.0'"
458 expect2 = "Syntax error `invalid syntax (line 1)' trying to evaluate `$foo.bar.3.0'"
459 assert str(e) in [expect1, expect2], e
461 raise AssertionError, "did not catch expected UserError"
463 # Test how we handle overriding the internal conversion routines.
468 env = DummyEnv({'NODE' : n1})
469 gvars = env.Dictionary()
470 node = scons_subst("$NODE", env, mode=SUBST_RAW, conv=s, gvars=gvars)
471 assert node is n1, node
472 node = scons_subst("$NODE", env, mode=SUBST_CMD, conv=s, gvars=gvars)
473 assert node is n1, node
474 node = scons_subst("$NODE", env, mode=SUBST_SIG, conv=s, gvars=gvars)
475 assert node is n1, node
477 # Test returning a function.
478 #env = DummyEnv({'FUNCTION' : foo})
479 #gvars = env.Dictionary()
480 #func = scons_subst("$FUNCTION", env, mode=SUBST_RAW, call=None, gvars=gvars)
481 #assert func is function_foo, func
482 #func = scons_subst("$FUNCTION", env, mode=SUBST_CMD, call=None, gvars=gvars)
483 #assert func is function_foo, func
484 #func = scons_subst("$FUNCTION", env, mode=SUBST_SIG, call=None, gvars=gvars)
485 #assert func is function_foo, func
487 # Test supplying an overriding gvars dictionary.
488 env = DummyEnv({'XXX' : 'xxx'})
489 result = scons_subst('$XXX', env, gvars=env.Dictionary())
490 assert result == 'xxx', result
491 result = scons_subst('$XXX', env, gvars={'XXX' : 'yyy'})
492 assert result == 'yyy', result
494 def test_subst_list(self):
495 """Testing the scons_subst_list() method..."""
496 class MyNode(DummyNode):
497 """Simple node work-alike with some extra stuff for testing."""
498 def __init__(self, name):
499 DummyNode.__init__(self, name)
502 self.attribute = Attribute()
503 self.attribute.attr1 = 'attr$1-' + os.path.basename(name)
504 self.attribute.attr2 = 'attr$2-' + os.path.basename(name)
507 def __init__(self, value):
514 target = [ MyNode("./foo/bar.exe"),
515 MyNode("/bar/baz with spaces.obj"),
516 MyNode("../foo/baz.obj") ]
517 source = [ MyNode("./foo/blah with spaces.cpp"),
518 MyNode("/bar/ack.cpp"),
519 MyNode("../foo/ack.c") ]
523 'NEWLINE' : 'before\nafter',
529 'DO' : DummyNode('do something'),
530 'FOO' : DummyNode('foo.in'),
531 'BAR' : DummyNode('bar with spaces.out'),
532 'CRAZY' : DummyNode('crazy\nfile.in'),
534 # $XXX$HHH should expand to GGGIII, not BADNEWS.
538 'FFFIII' : 'BADNEWS',
543 'LITERALS' : [ Literal('foo\nwith\nnewlines'),
544 Literal('bar\nwith\nnewlines') ],
546 # Test various combinations of strings, lists and functions.
557 # Test function calls within ${}.
558 'FUNCCALL' : '${FUNC1("$AAA $FUNC2 $BBB")}',
559 'FUNC1' : lambda x: x,
560 'FUNC2' : lambda target, source, env, for_signature: ['x$CCC'],
562 # Various tests refactored from ActionTests.py.
563 'LIST' : [["This", "is", "$(", "$a", "$)", "test"]],
566 'RECURSE' : 'foo $RECURSE bar',
567 'RRR' : 'foo $SSS bar',
570 # Test callable objects that don't match our calling arguments.
571 'CALLABLE' : TestCallable('callable-2'),
579 ["foo/bar.exe", "/bar/baz with spaces.obj", "../foo/baz.obj"],
582 "$SOURCES $NEWLINE $TARGETS",
584 ["foo/blah with spaces.cpp", "/bar/ack.cpp", "../foo/ack.c", "before"],
585 ["after", "foo/bar.exe", "/bar/baz with spaces.obj", "../foo/baz.obj"],
590 ["foo/blah with spaces.cpp", "/bar/ack.cpp", "../foo/ack.cbefore"],
604 "test ${SOURCES.attribute.attr1}",
606 ["test", "attr$1-blah with spaces.cpp", "attr$1-ack.cpp", "attr$1-ack.c"],
609 "test ${SOURCES.attribute.attr2}",
611 ["test", "attr$2-blah with spaces.cpp", "attr$2-ack.cpp", "attr$2-ack.c"],
614 "$DO --in=$FOO --out=$BAR",
616 ["do something", "--in=foo.in", "--out=bar with spaces.out"],
619 # This test is now fixed, and works like it should.
620 "$DO --in=$CRAZY --out=$BAR",
622 ["do something", "--in=crazy\nfile.in", "--out=bar with spaces.out"],
625 # Try passing a list to scons_subst_list().
626 [ "$SOURCES$NEWLINE", "$TARGETS", "This is a test"],
628 ["foo/blah with spaces.cpp", "/bar/ack.cpp", "../foo/ack.cbefore"],
629 ["after", "foo/bar.exe", "/bar/baz with spaces.obj", "../foo/baz.obj", "This is a test"],
632 # Test against a former bug in scons_subst_list().
638 # Test double-dollar-sign behavior.
644 # Test various combinations of strings, lists and functions.
653 ['x', 'y'], [['x', 'y']],
663 '$S z', [['x', 'y', 'z']],
664 ['$S'], [['x', 'y']],
665 ['$S z'], [['x', 'y z']], # XXX - IS THIS BEST?
666 ['$S', 'z'], [['x', 'y', 'z']],
668 '$LS z', [['x y', 'z']],
670 ['$LS z'], [['x y z']],
671 ['$LS', 'z'], [['x y', 'z']],
673 '$L z', [['x', 'y', 'z']],
674 ['$L'], [['x', 'y']],
675 ['$L z'], [['x', 'y z']], # XXX - IS THIS BEST?
676 ['$L', 'z'], [['x', 'y', 'z']],
686 # Test function calls within ${}.
687 '$FUNCCALL', [['a', 'xc', 'b']],
689 # Test handling of newlines in white space.
690 'foo\nbar', [['foo'], ['bar']],
691 'foo\n\nbar', [['foo'], ['bar']],
692 'foo \n \n bar', [['foo'], ['bar']],
693 'foo \nmiddle\n bar', [['foo'], ['middle'], ['bar']],
695 # Bug reported by Christoph Wiedemann.
696 cvt('$xxx/bin'), [['/bin']],
698 # Test variables smooshed together with different prefixes.
699 'foo$AAA', [['fooa']],
700 '<$AAA', [['<', 'a']],
701 '>$AAA', [['>', 'a']],
702 '|$AAA', [['|', 'a']],
704 # Test callables that don't match our calling arguments.
705 '$CALLABLE', [['callable-2']],
708 gvars = env.Dictionary()
710 kwargs = {'target' : target, 'source' : source, 'gvars' : gvars}
714 input, expect = cases[:2]
715 expect = map(lambda l: map(cvt, l), expect)
716 result = apply(scons_subst_list, (input, env), kwargs)
718 if failed == 0: print
719 print " input %s => %s did not match %s" % (repr(input), result, repr(expect))
722 assert failed == 0, "%d subst_list() cases failed" % failed
724 # The expansion dictionary no longer comes from the construction
725 # environment automatically.
726 s = scons_subst_list('$AAA', env)
733 result = scons_subst_list("$TARGET $SOURCES", env,
737 assert result == [['t1', 's1', 's2']], result
738 result = scons_subst_list("$TARGET $SOURCES", env,
742 assert result == [['t1', 's1', 's2']], result
744 # Test interpolating a callable.
747 cmd_list = scons_subst_list("testing $CMDGEN1 $TARGETS $SOURCES",
748 env, target=_t, source=_s,
750 assert cmd_list == [['testing', 'foo', 'bar with spaces.out', 't', 's']], cmd_list
752 # Test escape functionality.
753 def escape_func(foo):
754 return '**' + foo + '**'
755 cmd_list = scons_subst_list("abc $LITERALS xyz", env, gvars=gvars)
756 assert cmd_list == [['abc',
757 'foo\nwith\nnewlines',
758 'bar\nwith\nnewlines',
760 c = cmd_list[0][0].escape(escape_func)
762 c = cmd_list[0][1].escape(escape_func)
763 assert c == '**foo\nwith\nnewlines**', c
764 c = cmd_list[0][2].escape(escape_func)
765 assert c == '**bar\nwith\nnewlines**', c
766 c = cmd_list[0][3].escape(escape_func)
769 cmd_list = scons_subst_list("abc${LITERALS}xyz", env, gvars=gvars)
770 c = cmd_list[0][0].escape(escape_func)
771 assert c == '**abcfoo\nwith\nnewlines**', c
772 c = cmd_list[0][1].escape(escape_func)
773 assert c == '**bar\nwith\nnewlinesxyz**', c
775 # Tests of the various SUBST_* modes of substitution.
788 [["test", "$(", "$)"]],
792 "$AAA ${AAA}A $BBBB $BBB",
807 # Verify what happens with no target or source nodes.
818 # Various test refactored from ActionTests.py
820 [['This', 'is', '$(', '$)', 'test']],
821 [['This', 'is', 'test']],
822 [['This', 'is', 'test']],
824 ["|", "$(", "$AAA", "|", "$BBB", "$)", "|", "$CCC", 1],
825 [["|", "$(", "a", "|", "b", "$)", "|", "c", "1"]],
826 [["|", "a", "|", "b", "|", "c", "1"]],
827 [["|", "|", "c", "1"]],
830 gvars = env.Dictionary()
832 r = scons_subst_list("$TARGET $SOURCES", env, mode=SUBST_RAW, gvars=gvars)
836 while subst_list_cases:
837 input, eraw, ecmd, esig = subst_list_cases[:4]
838 result = scons_subst_list(input, env, mode=SUBST_RAW, gvars=gvars)
840 if failed == 0: print
841 print " input %s => RAW %s did not match %s" % (repr(input), repr(result), repr(eraw))
843 result = scons_subst_list(input, env, mode=SUBST_CMD, gvars=gvars)
845 if failed == 0: print
846 print " input %s => CMD %s did not match %s" % (repr(input), repr(result), repr(ecmd))
848 result = scons_subst_list(input, env, mode=SUBST_SIG, gvars=gvars)
850 if failed == 0: print
851 print " input %s => SIG %s did not match %s" % (repr(input), repr(result), repr(esig))
853 del subst_list_cases[:4]
854 assert failed == 0, "%d subst() mode cases failed" % failed
856 # Test that we handle syntax errors during expansion as expected.
858 scons_subst_list('$foo.bar.3.0', env)
859 except SCons.Errors.UserError, e:
860 expect1 = "Syntax error `invalid syntax' trying to evaluate `$foo.bar.3.0'"
861 expect2 = "Syntax error `invalid syntax (line 1)' trying to evaluate `$foo.bar.3.0'"
862 assert str(e) in [expect1, expect2], e
864 raise AssertionError, "did not catch expected SyntaxError"
866 # Test we handle overriding the internal conversion routines.
871 env = DummyEnv({'NODE' : n1})
872 gvars=env.Dictionary()
873 node = scons_subst_list("$NODE", env, mode=SUBST_RAW, conv=s, gvars=gvars)
874 assert node == [[n1]], node
875 node = scons_subst_list("$NODE", env, mode=SUBST_CMD, conv=s, gvars=gvars)
876 assert node == [[n1]], node
877 node = scons_subst_list("$NODE", env, mode=SUBST_SIG, conv=s, gvars=gvars)
878 assert node == [[n1]], node
880 # Test supplying an overriding gvars dictionary.
881 env = DummyEnv({'XXX' : 'xxx'})
882 result = scons_subst_list('$XXX', env, gvars=env.Dictionary())
883 assert result == [['xxx']], result
884 result = scons_subst_list('$XXX', env, gvars={'XXX' : 'yyy'})
885 assert result == [['yyy']], result
887 def test_subst_once(self):
888 """Testing the scons_subst_once() method"""
893 'RECURSE' : 'r $RECURSE r',
894 'LIST' : ['a', 'b', 'c'],
926 ['x', 'a', 'b', 'c', 'y'],
928 ['x', 'x $LIST y', 'y'],
930 ['x', 'x a b c y', 'y'],
932 ['x', 'x $CCFLAGS y', 'y'],
934 ['x', 'x $CCFLAGS y', 'y'],
936 ['x', 'x $RECURSE y', 'y'],
938 ['x', 'x $RECURSE y', 'y'],
943 input, key, expect = cases[:3]
944 result = scons_subst_once(input, env, key)
946 if failed == 0: print
947 print " input %s (%s) => %s did not match %s" % (repr(input), repr(key), repr(result), repr(expect))
950 assert failed == 0, "%d subst() cases failed" % failed
952 def test_splitext(self):
953 assert splitext('foo') == ('foo','')
954 assert splitext('foo.bar') == ('foo','.bar')
955 assert splitext(os.path.join('foo.bar', 'blat')) == (os.path.join('foo.bar', 'blat'),'')
957 def test_quote_spaces(self):
958 """Testing the quote_spaces() method..."""
959 q = quote_spaces('x')
962 q = quote_spaces('x x')
963 assert q == '"x x"', q
965 q = quote_spaces('x\tx')
966 assert q == '"x\tx"', q
969 def __init__(self, name, children=[]):
970 self.children = children
978 def has_builder(self):
980 def has_explicit_builder(self):
982 def side_effect(self):
986 def always_build(self):
991 def tree_case_1(self):
992 """Fixture for the render_tree() and print_tree() tests."""
993 windows_h = self.Node("windows.h")
994 stdlib_h = self.Node("stdlib.h")
995 stdio_h = self.Node("stdio.h")
996 bar_c = self.Node("bar.c", [stdlib_h, windows_h])
997 bar_o = self.Node("bar.o", [bar_c])
998 foo_c = self.Node("foo.c", [stdio_h])
999 foo_o = self.Node("foo.o", [foo_c])
1000 foo = self.Node("foo", [foo_o, bar_o])
1013 lines = string.split(expect, '\n')[:-1]
1014 lines = map(lambda l: '[E BSPAC]'+l, lines)
1015 withtags = string.join(lines, '\n') + '\n'
1017 return foo, expect, withtags
1019 def tree_case_2(self):
1020 """Fixture for the render_tree() and print_tree() tests."""
1022 stdlib_h = self.Node("stdlib.h")
1023 bar_h = self.Node('bar.h', [stdlib_h])
1024 blat_h = self.Node('blat.h', [stdlib_h])
1025 blat_c = self.Node('blat.c', [blat_h, bar_h])
1026 blat_o = self.Node('blat.o', [blat_c])
1036 lines = string.split(expect, '\n')[:-1]
1037 lines = map(lambda l: '[E BSPAC]'+l, lines)
1038 withtags = string.join(lines, '\n') + '\n'
1040 return blat_o, expect, withtags
1042 def test_render_tree(self):
1043 """Test the render_tree() function"""
1044 def get_children(node):
1045 return node.children
1047 node, expect, withtags = self.tree_case_1()
1048 actual = render_tree(node, get_children)
1049 assert expect == actual, (expect, actual)
1051 node, expect, withtags = self.tree_case_2()
1052 actual = render_tree(node, get_children, 1)
1053 assert expect == actual, (expect, actual)
1055 def test_print_tree(self):
1056 """Test the print_tree() function"""
1057 def get_children(node):
1058 return node.children
1060 save_stdout = sys.stdout
1063 node, expect, withtags = self.tree_case_1()
1065 sys.stdout = StringIO.StringIO()
1066 print_tree(node, get_children)
1067 actual = sys.stdout.getvalue()
1068 assert expect == actual, (expect, actual)
1070 sys.stdout = StringIO.StringIO()
1071 print_tree(node, get_children, showtags=1)
1072 actual = sys.stdout.getvalue()
1073 assert withtags == actual, (withtags, actual)
1075 node, expect, withtags = self.tree_case_2()
1077 sys.stdout = StringIO.StringIO()
1078 print_tree(node, get_children, 1)
1079 actual = sys.stdout.getvalue()
1080 assert expect == actual, (expect, actual)
1082 sys.stdout = StringIO.StringIO()
1083 # The following call should work here:
1084 # print_tree(node, get_children, 1, showtags=1)
1085 # For some reason I don't understand, though, *this*
1086 # time that we call print_tree, the visited dictionary
1087 # is still populated with the values from the last call!
1088 # I can't see why this would be, short of a bug in Python,
1089 # and rather than continue banging my head against the
1090 # brick wall for a *test*, we're going to going with
1091 # the cheap, easy workaround:
1092 print_tree(node, get_children, 1, showtags=1, visited={})
1093 actual = sys.stdout.getvalue()
1094 assert withtags == actual, (withtags, actual)
1096 sys.stdout = save_stdout
1098 def test_is_Dict(self):
1100 assert is_Dict(UserDict())
1101 assert not is_Dict([])
1102 assert not is_Dict("")
1103 if hasattr(types, 'UnicodeType'):
1104 exec "assert not is_Dict(u'')"
1106 def test_is_List(self):
1109 assert is_List(UserList.UserList())
1110 assert not is_List({})
1111 assert not is_List("")
1112 if hasattr(types, 'UnicodeType'):
1113 exec "assert not is_List(u'')"
1115 def test_is_String(self):
1116 assert is_String("")
1117 if hasattr(types, 'UnicodeType'):
1118 exec "assert is_String(u'')"
1124 assert is_String(UserString.UserString(''))
1125 assert not is_String({})
1126 assert not is_String([])
1128 def test_to_String(self):
1129 """Test the to_String() method."""
1130 assert to_String(1) == "1", to_String(1)
1131 assert to_String([ 1, 2, 3]) == str([1, 2, 3]), to_String([1,2,3])
1132 assert to_String("foo") == "foo", to_String("foo")
1137 s1=UserString.UserString('blah')
1138 assert to_String(s1) == s1, s1
1139 assert to_String(s1) == 'blah', s1
1141 class Derived(UserString.UserString):
1144 assert to_String(s2) == s2, s2
1145 assert to_String(s2) == 'foo', s2
1147 if hasattr(types, 'UnicodeType'):
1148 s3=UserString.UserString(unicode('bar'))
1149 assert to_String(s3) == s3, s3
1150 assert to_String(s3) == unicode('bar'), s3
1151 assert type(to_String(s3)) is types.UnicodeType, \
1156 if hasattr(types, 'UnicodeType'):
1158 assert to_String(s4) == unicode('baz'), to_String(s4)
1159 assert type(to_String(s4)) is types.UnicodeType, \
1162 def test_WhereIs(self):
1163 test = TestCmd.TestCmd(workdir = '')
1165 sub1_xxx_exe = test.workpath('sub1', 'xxx.exe')
1166 sub2_xxx_exe = test.workpath('sub2', 'xxx.exe')
1167 sub3_xxx_exe = test.workpath('sub3', 'xxx.exe')
1168 sub4_xxx_exe = test.workpath('sub4', 'xxx.exe')
1170 test.subdir('subdir', 'sub1', 'sub2', 'sub3', 'sub4')
1172 if sys.platform != 'win32':
1173 test.write(sub1_xxx_exe, "\n")
1175 os.mkdir(sub2_xxx_exe)
1177 test.write(sub3_xxx_exe, "\n")
1178 os.chmod(sub3_xxx_exe, 0777)
1180 test.write(sub4_xxx_exe, "\n")
1181 os.chmod(sub4_xxx_exe, 0777)
1183 env_path = os.environ['PATH']
1186 pathdirs_1234 = [ test.workpath('sub1'),
1187 test.workpath('sub2'),
1188 test.workpath('sub3'),
1189 test.workpath('sub4'),
1190 ] + string.split(env_path, os.pathsep)
1192 pathdirs_1243 = [ test.workpath('sub1'),
1193 test.workpath('sub2'),
1194 test.workpath('sub4'),
1195 test.workpath('sub3'),
1196 ] + string.split(env_path, os.pathsep)
1198 os.environ['PATH'] = string.join(pathdirs_1234, os.pathsep)
1199 wi = WhereIs('xxx.exe')
1200 assert wi == test.workpath(sub3_xxx_exe), wi
1201 wi = WhereIs('xxx.exe', pathdirs_1243)
1202 assert wi == test.workpath(sub4_xxx_exe), wi
1203 wi = WhereIs('xxx.exe', string.join(pathdirs_1243, os.pathsep))
1204 assert wi == test.workpath(sub4_xxx_exe), wi
1206 wi = WhereIs('xxx.exe',reject = sub3_xxx_exe)
1207 assert wi == test.workpath(sub4_xxx_exe), wi
1208 wi = WhereIs('xxx.exe', pathdirs_1243, reject = sub3_xxx_exe)
1209 assert wi == test.workpath(sub4_xxx_exe), wi
1211 os.environ['PATH'] = string.join(pathdirs_1243, os.pathsep)
1212 wi = WhereIs('xxx.exe')
1213 assert wi == test.workpath(sub4_xxx_exe), wi
1214 wi = WhereIs('xxx.exe', pathdirs_1234)
1215 assert wi == test.workpath(sub3_xxx_exe), wi
1216 wi = WhereIs('xxx.exe', string.join(pathdirs_1234, os.pathsep))
1217 assert wi == test.workpath(sub3_xxx_exe), wi
1219 if sys.platform == 'win32':
1220 wi = WhereIs('xxx', pathext = '')
1221 assert wi is None, wi
1223 wi = WhereIs('xxx', pathext = '.exe')
1224 assert wi == test.workpath(sub4_xxx_exe), wi
1226 wi = WhereIs('xxx', path = pathdirs_1234, pathext = '.BAT;.EXE')
1227 assert string.lower(wi) == string.lower(test.workpath(sub3_xxx_exe)), wi
1229 # Test that we return a normalized path even when
1230 # the path contains forward slashes.
1231 forward_slash = test.workpath('') + '/sub3'
1232 wi = WhereIs('xxx', path = forward_slash, pathext = '.EXE')
1233 assert string.lower(wi) == string.lower(test.workpath(sub3_xxx_exe)), wi
1235 del os.environ['PATH']
1236 wi = WhereIs('xxx.exe')
1237 assert wi is None, wi
1240 os.environ['PATH'] = env_path
1243 def test_is_valid_construction_var(self):
1244 """Testing is_valid_construction_var()"""
1245 r = is_valid_construction_var("_a")
1246 assert not r is None, r
1247 r = is_valid_construction_var("z_")
1248 assert not r is None, r
1249 r = is_valid_construction_var("X_")
1250 assert not r is None, r
1251 r = is_valid_construction_var("2a")
1253 r = is_valid_construction_var("a2_")
1254 assert not r is None, r
1255 r = is_valid_construction_var("/")
1257 r = is_valid_construction_var("_/")
1259 r = is_valid_construction_var("a/")
1261 r = is_valid_construction_var(".b")
1263 r = is_valid_construction_var("_.b")
1265 r = is_valid_construction_var("b1._")
1267 r = is_valid_construction_var("-b")
1269 r = is_valid_construction_var("_-b")
1271 r = is_valid_construction_var("b1-_")
1274 def test_get_env_var(self):
1275 """Testing get_environment_var()."""
1276 assert get_environment_var("$FOO") == "FOO", get_environment_var("$FOO")
1277 assert get_environment_var("${BAR}") == "BAR", get_environment_var("${BAR}")
1278 assert get_environment_var("$FOO_BAR1234") == "FOO_BAR1234", get_environment_var("$FOO_BAR1234")
1279 assert get_environment_var("${BAR_FOO1234}") == "BAR_FOO1234", get_environment_var("${BAR_FOO1234}")
1280 assert get_environment_var("${BAR}FOO") == None, get_environment_var("${BAR}FOO")
1281 assert get_environment_var("$BAR ") == None, get_environment_var("$BAR ")
1282 assert get_environment_var("FOO$BAR") == None, get_environment_var("FOO$BAR")
1283 assert get_environment_var("$FOO[0]") == None, get_environment_var("$FOO[0]")
1284 assert get_environment_var("${some('complex expression')}") == None, get_environment_var("${some('complex expression')}")
1286 def test_Proxy(self):
1287 """Test generic Proxy class."""
1297 class ProxyTest(Proxy):
1303 assert p.foo() == 1, p.foo()
1304 assert p.bar() == 4, p.bar()
1305 assert p.baz == 3, p.baz
1310 assert p.baz == 5, p.baz
1311 assert p.get() == s, p.get()
1313 def test_Literal(self):
1314 """Test the Literal() function."""
1315 input_list = [ '$FOO', Literal('$BAR') ]
1316 gvars = { 'FOO' : 'BAZ', 'BAR' : 'BLAT' }
1318 def escape_func(cmd):
1319 return '**' + cmd + '**'
1321 cmd_list = scons_subst_list(input_list, None, gvars=gvars)
1322 cmd_list = SCons.Util.escape_list(cmd_list[0], escape_func)
1323 assert cmd_list == ['BAZ', '**$BAR**'], cmd_list
1325 def test_SpecialAttrWrapper(self):
1326 """Test the SpecialAttrWrapper() function."""
1327 input_list = [ '$FOO', SpecialAttrWrapper('$BAR', 'BLEH') ]
1328 gvars = { 'FOO' : 'BAZ', 'BAR' : 'BLAT' }
1330 def escape_func(cmd):
1331 return '**' + cmd + '**'
1333 cmd_list = scons_subst_list(input_list, None, gvars=gvars)
1334 cmd_list = SCons.Util.escape_list(cmd_list[0], escape_func)
1335 assert cmd_list == ['BAZ', '**$BAR**'], cmd_list
1337 cmd_list = scons_subst_list(input_list, None, mode=SUBST_SIG, gvars=gvars)
1338 cmd_list = SCons.Util.escape_list(cmd_list[0], escape_func)
1339 assert cmd_list == ['BAZ', '**BLEH**'], cmd_list
1341 def test_display(self):
1342 old_stdout = sys.stdout
1343 sys.stdout = OutBuffer()
1349 display("line4\n", append_newline=0)
1351 display("dont print1")
1352 display("dont print2\n", append_newline=0)
1354 assert sys.stdout.buffer == "line1\nline3\nline4\n"
1355 sys.stdout = old_stdout
1357 def test_fs_delete(self):
1358 test = TestCmd.TestCmd(workdir = '')
1359 base = test.workpath('')
1360 xxx = test.workpath('xxx.xxx')
1361 ZZZ = test.workpath('ZZZ.ZZZ')
1362 sub1_yyy = test.workpath('sub1', 'yyy.yyy')
1365 test.write(xxx, "\n")
1366 test.write(ZZZ, "\n")
1367 test.write(sub1_yyy, "\n")
1369 old_stdout = sys.stdout
1370 sys.stdout = OutBuffer()
1372 exp = "Removed " + os.path.join(base, ZZZ) + "\n" + \
1373 "Removed " + os.path.join(base, sub1_yyy) + '\n' + \
1374 "Removed directory " + os.path.join(base, 'sub1') + '\n' + \
1375 "Removed " + os.path.join(base, xxx) + '\n' + \
1376 "Removed directory " + base + '\n'
1378 fs_delete(base, remove=0)
1379 assert sys.stdout.buffer == exp, sys.stdout.buffer
1380 assert os.path.exists(sub1_yyy)
1382 sys.stdout.buffer = ""
1383 fs_delete(base, remove=1)
1384 assert sys.stdout.buffer == exp
1385 assert not os.path.exists(base)
1387 test._dirlist = None
1388 sys.stdout = old_stdout
1390 def test_get_native_path(self):
1391 """Test the get_native_path() function."""
1393 filename = tempfile.mktemp()
1394 str = '1234567890 ' + filename
1396 open(filename, 'w').write(str)
1397 assert open(get_native_path(filename)).read() == str
1404 def test_subst_dict(self):
1405 """Test substituting dictionary values in an Action
1409 d = subst_dict(target=t, source=s)
1410 assert str(d['TARGETS'][0]) == 't', d['TARGETS']
1411 assert str(d['TARGET']) == 't', d['TARGET']
1412 assert str(d['SOURCES'][0]) == 's', d['SOURCES']
1413 assert str(d['SOURCE']) == 's', d['SOURCE']
1415 t1 = DummyNode('t1')
1416 t2 = DummyNode('t2')
1417 s1 = DummyNode('s1')
1418 s2 = DummyNode('s2')
1419 d = subst_dict(target=[t1, t2], source=[s1, s2])
1420 TARGETS = map(lambda x: str(x), d['TARGETS'])
1422 assert TARGETS == ['t1', 't2'], d['TARGETS']
1423 assert str(d['TARGET']) == 't1', d['TARGET']
1424 SOURCES = map(lambda x: str(x), d['SOURCES'])
1426 assert SOURCES == ['s1', 's2'], d['SOURCES']
1427 assert str(d['SOURCE']) == 's1', d['SOURCE']
1430 # Fake Value node with no rfile() method.
1431 def __init__(self, name):
1434 return 'v-'+self.name
1435 def get_subst_proxy(self):
1440 return self.__class__('rstr-' + self.name)
1443 t4 = DummyNode('t4')
1445 s3 = DummyNode('s3')
1448 d = subst_dict(target=[t3, t4, t5], source=[s3, s4, s5])
1449 TARGETS = map(lambda x: str(x), d['TARGETS'])
1451 assert TARGETS == ['t4', 'v-t3', 'v-t5'], TARGETS
1452 SOURCES = map(lambda x: str(x), d['SOURCES'])
1454 assert SOURCES == ['s3', 'v-rstr-s4', 'v-s5'], SOURCES
1456 def test_PrependPath(self):
1457 """Test prepending to a path"""
1458 p1 = r'C:\dir\num\one;C:\dir\num\two'
1459 p2 = r'C:\mydir\num\one;C:\mydir\num\two'
1460 # have to include the pathsep here so that the test will work on UNIX too.
1461 p1 = PrependPath(p1,r'C:\dir\num\two',sep = ';')
1462 p1 = PrependPath(p1,r'C:\dir\num\three',sep = ';')
1463 p2 = PrependPath(p2,r'C:\mydir\num\three',sep = ';')
1464 p2 = PrependPath(p2,r'C:\mydir\num\one',sep = ';')
1465 assert(p1 == r'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one')
1466 assert(p2 == r'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two')
1468 def test_AppendPath(self):
1469 """Test appending to a path."""
1470 p1 = r'C:\dir\num\one;C:\dir\num\two'
1471 p2 = r'C:\mydir\num\one;C:\mydir\num\two'
1472 # have to include the pathsep here so that the test will work on UNIX too.
1473 p1 = AppendPath(p1,r'C:\dir\num\two',sep = ';')
1474 p1 = AppendPath(p1,r'C:\dir\num\three',sep = ';')
1475 p2 = AppendPath(p2,r'C:\mydir\num\three',sep = ';')
1476 p2 = AppendPath(p2,r'C:\mydir\num\one',sep = ';')
1477 assert(p1 == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three')
1478 assert(p2 == r'C:\mydir\num\two;C:\mydir\num\three;C:\mydir\num\one')
1480 def test_NodeList(self):
1481 """Test NodeList class"""
1483 def __init__(self, name, child=None):
1487 return self.bar + "foo"
1491 t1 = TestClass('t1', TestClass('t1child'))
1492 t2 = TestClass('t2', TestClass('t2child'))
1493 t3 = TestClass('t3')
1495 nl = NodeList([t1, t2, t3])
1496 assert nl.foo() == [ 't1foo', 't2foo', 't3foo' ], nl.foo()
1497 assert nl.bar == [ 't1', 't2', 't3' ], nl.bar
1498 assert nl.getself().bar == [ 't1', 't2', 't3' ], nl.getself().bar
1499 assert nl[0:2].child.foo() == [ 't1childfoo', 't2childfoo' ], \
1501 assert nl[0:2].child.bar == [ 't1child', 't2child' ], \
1504 def test_CLVar(self):
1505 """Test the command-line construction variable class"""
1506 f = SCons.Util.CLVar('a b')
1509 assert isinstance(r, SCons.Util.CLVar), type(r)
1510 assert r.data == ['a', 'b', 'c', 'd'], r.data
1511 assert str(r) == 'a b c d', str(r)
1514 assert isinstance(r, SCons.Util.CLVar), type(r)
1515 assert r.data == ['a', 'b', 'c', 'd'], r.data
1516 assert str(r) == 'a b c d', str(r)
1519 assert isinstance(r, SCons.Util.CLVar), type(r)
1520 assert r.data == ['a', 'b', 'c d'], r.data
1521 assert str(r) == 'a b c d', str(r)
1524 assert isinstance(r, SCons.Util.CLVar), type(r)
1525 assert r.data == ['a', 'b', ' c d'], r.data
1526 assert str(r) == 'a b c d', str(r)
1529 assert isinstance(r, SCons.Util.CLVar), type(r)
1530 assert r.data == ['a', 'b', 'c', 'd'], r.data
1531 assert str(r) == 'a b c d', str(r)
1534 assert isinstance(r, SCons.Util.CLVar), type(r)
1535 assert r.data == ['a', 'b', ' c', 'd'], r.data
1536 assert str(r) == 'a b c d', str(r)
1538 f = SCons.Util.CLVar(['a b'])
1541 assert isinstance(r, SCons.Util.CLVar), type(r)
1542 assert r.data == ['a b', 'c', 'd'], r.data
1543 assert str(r) == 'a b c d', str(r)
1546 assert isinstance(r, SCons.Util.CLVar), type(r)
1547 assert r.data == ['a b', 'c', 'd'], r.data
1548 assert str(r) == 'a b c d', str(r)
1551 assert isinstance(r, SCons.Util.CLVar), type(r)
1552 assert r.data == ['a b', 'c d'], r.data
1553 assert str(r) == 'a b c d', str(r)
1556 assert isinstance(r, SCons.Util.CLVar), type(r)
1557 assert r.data == ['a b', ' c d'], r.data
1558 assert str(r) == 'a b c d', str(r)
1561 assert isinstance(r, SCons.Util.CLVar), type(r)
1562 assert r.data == ['a b', 'c', 'd'], r.data
1563 assert str(r) == 'a b c d', str(r)
1566 assert isinstance(r, SCons.Util.CLVar), type(r)
1567 assert r.data == ['a b', ' c', 'd'], r.data
1568 assert str(r) == 'a b c d', str(r)
1570 f = SCons.Util.CLVar(['a', 'b'])
1573 assert isinstance(r, SCons.Util.CLVar), type(r)
1574 assert r.data == ['a', 'b', 'c', 'd'], r.data
1575 assert str(r) == 'a b c d', str(r)
1578 assert isinstance(r, SCons.Util.CLVar), type(r)
1579 assert r.data == ['a', 'b', 'c', 'd'], r.data
1580 assert str(r) == 'a b c d', str(r)
1583 assert isinstance(r, SCons.Util.CLVar), type(r)
1584 assert r.data == ['a', 'b', 'c d'], r.data
1585 assert str(r) == 'a b c d', str(r)
1588 assert isinstance(r, SCons.Util.CLVar), type(r)
1589 assert r.data == ['a', 'b', ' c d'], r.data
1590 assert str(r) == 'a b c d', str(r)
1593 assert isinstance(r, SCons.Util.CLVar), type(r)
1594 assert r.data == ['a', 'b', 'c', 'd'], r.data
1595 assert str(r) == 'a b c d', str(r)
1598 assert isinstance(r, SCons.Util.CLVar), type(r)
1599 assert r.data == ['a', 'b', ' c', 'd'], r.data
1600 assert str(r) == 'a b c d', str(r)
1604 loc['BAR'] = SCons.Util.CLVar('bar')
1605 loc['CALL'] = lambda target, source, env, for_signature: 'call'
1608 cmd = SCons.Util.CLVar("test $FOO $BAR $CALL test")
1610 newcmd = scons_subst(cmd, env, gvars=env.Dictionary())
1611 assert newcmd == 'test foo bar call test', newcmd
1613 cmd_list = scons_subst_list(cmd, env, gvars=env.Dictionary())
1614 assert len(cmd_list) == 1, cmd_list
1615 assert cmd_list[0][0] == "test", cmd_list[0][0]
1616 assert cmd_list[0][1] == "foo", cmd_list[0][1]
1617 assert cmd_list[0][2] == "bar", cmd_list[0][2]
1618 assert cmd_list[0][3] == "call", cmd_list[0][3]
1619 assert cmd_list[0][4] == "test", cmd_list[0][4]
1621 def test_Selector(self):
1622 """Test the Selector class"""
1624 s = Selector({'a' : 'AAA', 'b' : 'BBB'})
1625 assert s['a'] == 'AAA', s['a']
1626 assert s['b'] == 'BBB', s['b']
1632 assert exc_caught, "should have caught a KeyError"
1634 assert s['c'] == 'CCC', s['c']
1636 class DummyEnv(UserDict):
1637 def subst(self, key):
1639 return self[key[1:]]
1644 s = Selector({'.d' : 'DDD', '.e' : 'EEE'})
1646 assert ret == None, ret
1647 ret = s(env, ['foo.d'])
1648 assert ret == 'DDD', ret
1649 ret = s(env, ['bar.e'])
1650 assert ret == 'EEE', ret
1651 ret = s(env, ['bar.x'])
1652 assert ret == None, ret
1654 ret = s(env, ['bar.x'])
1655 assert ret == 'XXX', ret
1657 env = DummyEnv({'FSUFF' : '.f', 'GSUFF' : '.g'})
1659 s = Selector({'$FSUFF' : 'FFF', '$GSUFF' : 'GGG'})
1660 ret = s(env, ['foo.f'])
1661 assert ret == 'FFF', ret
1662 ret = s(env, ['bar.g'])
1663 assert ret == 'GGG', ret
1665 def test_adjustixes(self):
1666 """Test the adjustixes() function"""
1667 r = adjustixes('file', 'pre-', '-suf')
1668 assert r == 'pre-file-suf', r
1669 r = adjustixes('pre-file', 'pre-', '-suf')
1670 assert r == 'pre-file-suf', r
1671 r = adjustixes('file-suf', 'pre-', '-suf')
1672 assert r == 'pre-file-suf', r
1673 r = adjustixes('pre-file-suf', 'pre-', '-suf')
1674 assert r == 'pre-file-suf', r
1675 r = adjustixes('pre-file.xxx', 'pre-', '-suf')
1676 assert r == 'pre-file.xxx', r
1677 r = adjustixes('dir/file', 'pre-', '-suf')
1678 assert r == os.path.join('dir', 'pre-file-suf'), r
1680 def test_containsAny(self):
1681 """Test the containsAny() function"""
1682 assert containsAny('*.py', '*?[]')
1683 assert not containsAny('file.txt', '*?[]')
1685 def test_containsAll(self):
1686 """Test the containsAll() function"""
1687 assert containsAll('43221', '123')
1688 assert not containsAll('134', '123')
1690 def test_containsOnly(self):
1691 """Test the containsOnly() function"""
1692 assert containsOnly('.83', '0123456789.')
1693 assert not containsOnly('43221', '123')
1695 def test_LogicalLines(self):
1696 """Test the LogicalLines class"""
1697 fobj = StringIO.StringIO(r"""
1707 lines = LogicalLines(fobj).readlines()
1712 'bling bling \\ bling\n',
1716 if __name__ == "__main__":
1717 suite = unittest.makeSuite(UtilTestCase, 'test_')
1718 if not unittest.TextTestRunner().run(suite).wasSuccessful():