win32 test portability fixes (Anthony Roach)
[scons.git] / src / engine / SCons / UtilTests.py
1 #
2 # Copyright (c) 2001, 2002 Steven Knight
3 #
4 # Permission is hereby granted, free of charge, to any person obtaining
5 # a copy of this software and associated documentation files (the
6 # "Software"), to deal in the Software without restriction, including
7 # without limitation the rights to use, copy, modify, merge, publish,
8 # distribute, sublicense, and/or sell copies of the Software, and to
9 # permit persons to whom the Software is furnished to do so, subject to
10 # the following conditions:
11 #
12 # The above copyright notice and this permission notice shall be included
13 # in all copies or substantial portions of the Software.
14 #
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
16 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
17 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 #
23
24 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
25
26 import os
27 import os.path
28 import re
29 import string
30 import sys
31 import types
32 import unittest
33 import SCons.Node
34 import SCons.Node.FS
35 from SCons.Util import *
36 import TestCmd
37
38 class UtilTestCase(unittest.TestCase):
39     def test_subst(self):
40         """Test the subst function."""
41         loc = {}
42         loc['TARGETS'] = PathList(map(os.path.normpath, [ "./foo/bar.exe",
43                                                           "/bar/baz.obj",
44                                                           "../foo/baz.obj" ]))
45         loc['TARGET'] = loc['TARGETS'][0]
46         loc['SOURCES'] = PathList(map(os.path.normpath, [ "./foo/blah.cpp",
47                                                           "/bar/ack.cpp",
48                                                           "../foo/ack.c" ]))
49         loc['SOURCE'] = loc['SOURCES'][0]
50         loc['xxx'] = None
51         loc['zero'] = 0
52         loc['one'] = 1
53
54         if os.sep == '/':
55             def cvt(str):
56                 return str
57         else:
58             def cvt(str):
59                 return string.replace(str, '/', os.sep)
60
61         newcom = scons_subst("test $TARGETS $SOURCES", loc, {})
62         assert newcom == cvt("test foo/bar.exe /bar/baz.obj ../foo/baz.obj foo/blah.cpp /bar/ack.cpp ../foo/ack.c")
63
64         newcom = scons_subst("test ${TARGETS[:]} ${SOURCES[0]}", loc, {})
65         assert newcom == cvt("test foo/bar.exe /bar/baz.obj ../foo/baz.obj foo/blah.cpp")
66
67         newcom = scons_subst("test ${TARGETS[1:]}v", loc, {})
68         assert newcom == cvt("test /bar/baz.obj ../foo/baz.objv")
69
70         newcom = scons_subst("test $TARGET", loc, {})
71         assert newcom == cvt("test foo/bar.exe")
72
73         newcom = scons_subst("test $TARGET$FOO[0]", loc, {})
74         assert newcom == cvt("test foo/bar.exe[0]")
75
76         newcom = scons_subst("test ${TARGET.file}", loc, {})
77         assert newcom == cvt("test bar.exe")
78
79         newcom = scons_subst("test ${TARGET.filebase}", loc, {})
80         assert newcom == cvt("test bar")
81
82         newcom = scons_subst("test ${TARGET.suffix}", loc, {})
83         assert newcom == cvt("test .exe")
84
85         newcom = scons_subst("test ${TARGET.base}", loc, {})
86         assert newcom == cvt("test foo/bar")
87
88         newcom = scons_subst("test ${TARGET.dir}", loc, {})
89         assert newcom == cvt("test foo")
90
91         newcom = scons_subst("test ${TARGET.abspath}", loc, {})
92         assert newcom == cvt("test %s/foo/bar.exe"%SCons.Util.updrive(os.getcwd())), newcom
93
94         newcom = scons_subst("test ${SOURCES.abspath}", loc, {})
95         assert newcom == cvt("test %s/foo/blah.cpp %s %s/foo/ack.c"%(SCons.Util.updrive(os.getcwd()),
96                                                                      SCons.Util.updrive(os.path.abspath(os.path.normpath("/bar/ack.cpp"))),
97                                                                      SCons.Util.updrive(os.path.normpath(os.getcwd()+"/..")))), newcom
98
99         newcom = scons_subst("test ${SOURCE.abspath}", loc, {})
100         assert newcom == cvt("test %s/foo/blah.cpp"%SCons.Util.updrive(os.getcwd())), newcom
101
102         newcom = scons_subst("test $xxx", loc, {})
103         assert newcom == cvt("test"), newcom
104
105         newcom = scons_subst("test $($xxx$)", loc, {})
106         assert newcom == cvt("test $($)"), newcom
107
108         newcom = scons_subst("test $( $xxx $)", loc, {})
109         assert newcom == cvt("test $( $)"), newcom
110
111         newcom = scons_subst("test $($xxx$)", loc, {}, re.compile('\$[()]'))
112         assert newcom == cvt("test"), newcom
113
114         newcom = scons_subst("test $( $xxx $)", loc, {}, re.compile('\$[()]'))
115         assert newcom == cvt("test"), newcom
116
117         newcom = scons_subst("test $zero", loc, {})
118         assert newcom == cvt("test 0"), newcom
119
120         newcom = scons_subst("test $one", loc, {})
121         assert newcom == cvt("test 1"), newcom
122
123         newcom = scons_subst("test aXbXcXd", loc, {}, re.compile('X'))
124         assert newcom == cvt("test abcd"), newcom
125
126         glob = { 'a' : 1, 'b' : 2 }
127         loc = {'a' : 3, 'c' : 4 }
128         newcom = scons_subst("test $a $b $c $d test", glob, loc)
129         assert newcom == "test 3 2 4 test", newcom
130
131     def test_splitext(self):
132         assert splitext('foo') == ('foo','')
133         assert splitext('foo.bar') == ('foo','.bar')
134         assert splitext(os.path.join('foo.bar', 'blat')) == (os.path.join('foo.bar', 'blat'),'')
135
136     def test_subst_list(self):
137         """Testing the scons_subst_list() method..."""
138
139         class Node:
140             def __init__(self, name):
141                 self.name = name
142             def __str__(self):
143                 return self.name
144         
145         loc = {}
146         loc['TARGETS'] = PathList(map(os.path.normpath, [ "./foo/bar.exe",
147                                                           "/bar/baz with spaces.obj",
148                                                           "../foo/baz.obj" ]))
149         loc['TARGET'] = loc['TARGETS'][0]
150         loc['SOURCES'] = PathList(map(os.path.normpath, [ "./foo/blah with spaces.cpp",
151                                                           "/bar/ack.cpp",
152                                                           "../foo/ack.c" ]))
153         loc['xxx'] = None
154         loc['NEWLINE'] = 'before\nafter'
155
156         loc['DO'] = Node('do something')
157         loc['FOO'] = Node('foo.in')
158         loc['BAR'] = Node('bar with spaces.out')
159         loc['CRAZY'] = Node('crazy\nfile.in')
160
161         if os.sep == '/':
162             def cvt(str):
163                 return str
164         else:
165             def cvt(str):
166                 return string.replace(str, '/', os.sep)
167
168         cmd_list = scons_subst_list("$TARGETS", loc, {})
169         assert cmd_list[0][1] == cvt("/bar/baz with spaces.obj"), cmd_list[0][1]
170
171         cmd_list = scons_subst_list("$SOURCES $NEWLINE $TARGETS", loc, {})
172         assert len(cmd_list) == 2, cmd_list
173         assert cmd_list[0][0] == cvt('foo/blah with spaces.cpp'), cmd_list[0][0]
174         assert cmd_list[1][2] == cvt("/bar/baz with spaces.obj"), cmd_list[1]
175
176         cmd_list = scons_subst_list("$SOURCES$NEWLINE", loc, {})
177         assert len(cmd_list) == 2, cmd_list
178         assert cmd_list[1][0] == 'after', cmd_list[1][0]
179         assert cmd_list[0][2] == cvt('../foo/ack.cbefore'), cmd_list[0][2]
180
181         cmd_list = scons_subst_list("$DO --in=$FOO --out=$BAR", loc, {})
182         assert len(cmd_list) == 1, cmd_list
183         assert len(cmd_list[0]) == 3, cmd_list
184         assert cmd_list[0][0] == 'do something', cmd_list[0][0]
185         assert cmd_list[0][1] == '--in=foo.in', cmd_list[0][1]
186         assert cmd_list[0][2] == '--out=bar with spaces.out', cmd_list[0][2]
187
188         # XXX: The newline in crazy really should be interpreted as
189         #      part of the file name, and not as delimiting a new command
190         #      line
191         #      In other words the following test fragment is illustrating
192         #      a bug in variable interpolation.
193         cmd_list = scons_subst_list("$DO --in=$CRAZY --out=$BAR", loc, {})
194         assert len(cmd_list) == 2, cmd_list
195         assert len(cmd_list[0]) == 2, cmd_list
196         assert len(cmd_list[1]) == 2, cmd_list
197         assert cmd_list[0][0] == 'do something', cmd_list[0][0]
198         assert cmd_list[0][1] == '--in=crazy', cmd_list[0][1]
199         assert cmd_list[1][0] == 'file.in', cmd_list[1][0]
200         assert cmd_list[1][1] == '--out=bar with spaces.out', cmd_list[1][1]
201         
202         # Test inputting a list to scons_subst_list()
203         cmd_list = scons_subst_list([ "$SOURCES$NEWLINE", "$TARGETS",
204                                         "This is a test" ],
205                                     loc, {})
206         assert len(cmd_list) == 2, len(cmd_list)
207         assert cmd_list[0][0] == cvt('foo/blah with spaces.cpp'), cmd_list[0][0]
208         assert cmd_list[1][0] == cvt("after"), cmd_list[1]
209         assert cmd_list[1][4] == "This is a test", cmd_list[1]
210
211         glob = { 'a' : 1, 'b' : 2 }
212         loc = {'a' : 3, 'c' : 4 }
213         cmd_list = scons_subst_list("test $a $b $c $d test", glob, loc)
214         assert len(cmd_list) == 1, cmd_list
215         assert cmd_list[0] == ['test', '3', '2', '4', 'test'], cmd_list
216
217     def test_quote_spaces(self):
218         """Testing the quote_spaces() method..."""
219         q = quote_spaces('x')
220         assert q == 'x', q
221
222         q = quote_spaces('x x')
223         assert q == '"x x"', q
224
225         q = quote_spaces('x\tx')
226         assert q == '"x\tx"', q
227
228     def test_render_tree(self):
229         class Node:
230             def __init__(self, name, children=[]):
231                 self.children = children
232                 self.name = name
233             def __str__(self):
234                 return self.name
235
236         def get_children(node):
237             return node.children
238
239         windows_h = Node("windows.h")
240         stdlib_h = Node("stdlib.h")
241         stdio_h = Node("stdio.h")
242         bar_c = Node("bar.c", [stdlib_h, windows_h])
243         bar_o = Node("bar.o", [bar_c])
244         foo_c = Node("foo.c", [stdio_h])
245         foo_o = Node("foo.o", [foo_c])
246         foo = Node("foo", [foo_o, bar_o])
247
248         expect = """\
249 +-foo
250   +-foo.o
251   | +-foo.c
252   |   +-stdio.h
253   +-bar.o
254     +-bar.c
255       +-stdlib.h
256       +-windows.h
257 """
258
259         actual = render_tree(foo, get_children)
260         assert expect == actual, (expect, actual)
261
262     def test_is_Dict(self):
263         assert is_Dict({})
264         import UserDict
265         assert is_Dict(UserDict.UserDict())
266         assert not is_Dict([])
267         assert not is_Dict("")
268         if hasattr(types, 'UnicodeType'):
269             exec "assert not is_Dict(u'')"
270
271     def test_is_List(self):
272         assert is_List([])
273         import UserList
274         assert is_List(UserList.UserList())
275         assert not is_List({})
276         assert not is_List("")
277         if hasattr(types, 'UnicodeType'):
278             exec "assert not is_List(u'')"
279
280     def test_Split(self):
281         assert Split("foo bar") == ["foo", "bar"]
282         assert Split(["foo", "bar"]) == ["foo", "bar"]
283         assert Split("foo") == ["foo"]
284
285     def test_is_String(self):
286         assert is_String("")
287         if hasattr(types, 'UnicodeType'):
288             exec "assert is_String(u'')"
289         try:
290             import UserString
291         except:
292             pass
293         else:
294             assert is_String(UserString.UserString(''))
295         assert not is_String({})
296         assert not is_String([])
297
298     def test_to_String(self):
299         """Test the to_String() method."""
300         assert to_String(1) == "1", to_String(1)
301         assert to_String([ 1, 2, 3]) == str([1, 2, 3]), to_String([1,2,3])
302         assert to_String("foo") == "foo", to_String("foo")
303
304         try:
305             import UserString
306
307             s1=UserString.UserString('blah')
308             assert to_String(s1) == s1, s1
309             assert to_String(s1) == 'blah', s1
310
311             class Derived(UserString.UserString):
312                 pass
313             s2 = Derived('foo')
314             assert to_String(s2) == s2, s2
315             assert to_String(s2) == 'foo', s2
316
317             if hasattr(types, 'UnicodeType'):
318                 s3=UserString.UserString(unicode('bar'))
319                 assert to_String(s3) == s3, s3
320                 assert to_String(s3) == unicode('bar'), s3
321                 assert type(to_String(s3)) is types.UnicodeType, \
322                        type(to_String(s3))
323         except ImportError:
324             pass
325
326         if hasattr(types, 'UnicodeType'):
327             s4 = unicode('baz')
328             assert to_String(s4) == unicode('baz'), to_String(s4)
329             assert type(to_String(s4)) is types.UnicodeType, \
330                    type(to_String(s4))
331
332     def test_WhereIs(self):
333         test = TestCmd.TestCmd(workdir = '')
334
335         sub1_xxx_exe = test.workpath('sub1', 'xxx.exe')
336         sub2_xxx_exe = test.workpath('sub2', 'xxx.exe')
337         sub3_xxx_exe = test.workpath('sub3', 'xxx.exe')
338         sub4_xxx_exe = test.workpath('sub4', 'xxx.exe')
339
340         test.subdir('subdir', 'sub1', 'sub2', 'sub3', 'sub4')
341
342         if sys.platform != 'win32':
343             test.write(sub1_xxx_exe, "\n")
344
345         os.mkdir(sub2_xxx_exe)
346
347         test.write(sub3_xxx_exe, "\n")
348         os.chmod(sub3_xxx_exe, 0777)
349
350         test.write(sub4_xxx_exe, "\n")
351         os.chmod(sub4_xxx_exe, 0777)
352
353         env_path = os.environ['PATH']
354
355         pathdirs_1234 = [ test.workpath('sub1'),
356                           test.workpath('sub2'),
357                           test.workpath('sub3'),
358                           test.workpath('sub4'),
359                         ] + string.split(env_path, os.pathsep)
360
361         pathdirs_1243 = [ test.workpath('sub1'),
362                           test.workpath('sub2'),
363                           test.workpath('sub4'),
364                           test.workpath('sub3'),
365                         ] + string.split(env_path, os.pathsep)
366
367         os.environ['PATH'] = string.join(pathdirs_1234, os.pathsep)
368         wi = WhereIs('xxx.exe')
369         assert wi == test.workpath(sub3_xxx_exe), wi
370         wi = WhereIs('xxx.exe', pathdirs_1243)
371         assert wi == test.workpath(sub4_xxx_exe), wi
372         wi = WhereIs('xxx.exe', string.join(pathdirs_1243, os.pathsep))
373         assert wi == test.workpath(sub4_xxx_exe), wi
374
375         os.environ['PATH'] = string.join(pathdirs_1243, os.pathsep)
376         wi = WhereIs('xxx.exe')
377         assert wi == test.workpath(sub4_xxx_exe), wi
378         wi = WhereIs('xxx.exe', pathdirs_1234)
379         assert wi == test.workpath(sub3_xxx_exe), wi
380         wi = WhereIs('xxx.exe', string.join(pathdirs_1234, os.pathsep))
381         assert wi == test.workpath(sub3_xxx_exe), wi
382
383         if sys.platform == 'win32':
384             wi = WhereIs('xxx', pathext = '')
385             assert wi is None, wi
386
387             wi = WhereIs('xxx', pathext = '.exe')
388             assert wi == test.workpath(sub4_xxx_exe), wi
389
390             wi = WhereIs('xxx', path = pathdirs_1234, pathext = '.BAT;.EXE')
391             assert string.lower(wi) == string.lower(test.workpath(sub3_xxx_exe)), wi
392
393     def test_get_env_var(self):
394         """Testing get_environment_var()."""
395         assert get_environment_var("$FOO") == "FOO", get_environment_var("$FOO")
396         assert get_environment_var("${BAR}") == "BAR", get_environment_var("${BAR}")
397         assert get_environment_var("${BAR}FOO") == None, get_environment_var("${BAR}FOO")
398         assert get_environment_var("$BAR ") == None, get_environment_var("$BAR ")
399         assert get_environment_var("FOO$BAR") == None, get_environment_var("FOO$BAR")
400
401     def test_Proxy(self):
402         """Test generic Proxy class."""
403         class Subject:
404             def foo(self):
405                 return 1
406             def bar(self):
407                 return 2
408
409         s=Subject()
410         s.baz = 3
411
412         class ProxyTest(Proxy):
413             def bar(self):
414                 return 4
415
416         p=ProxyTest(s)
417
418         assert p.foo() == 1, p.foo()
419         assert p.bar() == 4, p.bar()
420         assert p.baz == 3, p.baz
421
422         p.baz = 5
423         s.baz = 6
424
425         assert p.baz == 5, p.baz
426
427 if __name__ == "__main__":
428     suite = unittest.makeSuite(UtilTestCase, 'test_')
429     if not unittest.TextTestRunner().run(suite).wasSuccessful():
430         sys.exit(1)