Escape path names to fix regular expression matches on Windows
[scons.git] / test / builderrors.py
1 #!/usr/bin/env python
2 #
3 # __COPYRIGHT__
4 #
5 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to
10 # permit persons to whom the Software is furnished to do so, subject to
11 # the following conditions:
12 #
13 # The above copyright notice and this permission notice shall be included
14 # in all copies or substantial portions of the Software.
15 #
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
17 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
18 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 #
24
25 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
26
27 import os
28 import string
29 import sys
30 import TestSCons
31
32 _python_ = TestSCons._python_
33
34 test = TestSCons.TestSCons()
35
36 test.subdir('one', 'two', 'three')
37
38 test.write('build.py', r"""
39 import sys
40 exitval = int(sys.argv[1])
41 if exitval == 0:
42     contents = open(sys.argv[3], 'rb').read()
43     file = open(sys.argv[2], 'wb')
44     file.write(contents)
45     file.close()
46 sys.exit(exitval)
47 """)
48
49 test.write(['one', 'SConstruct'], """
50 B0 = Builder(action = r'%(_python_)s ../build.py 0 $TARGET $SOURCES')
51 B1 = Builder(action = r'%(_python_)s ../build.py 1 $TARGET $SOURCES')
52 env = Environment(BUILDERS = { 'B0' : B0, 'B1' : B1 })
53 env.B1(target = 'f1.out', source = 'f1.in')
54 env.B0(target = 'f2.out', source = 'f2.in')
55 env.B0(target = 'f3.out', source = 'f3.in')
56 """ % locals())
57
58 test.write(['one', 'f1.in'], "one/f1.in\n")
59 test.write(['one', 'f2.in'], "one/f2.in\n")
60 test.write(['one', 'f3.in'], "one/f3.in\n")
61
62 test.run(chdir = 'one', arguments = "f1.out f2.out f3.out",
63          stderr = "scons: *** [f1.out] Error 1\n", status = 2)
64
65 test.fail_test(os.path.exists(test.workpath('f1.out')))
66 test.fail_test(os.path.exists(test.workpath('f2.out')))
67 test.fail_test(os.path.exists(test.workpath('f3.out')))
68
69 test.write(['two', 'SConstruct'], """
70 B0 = Builder(action = r'%(_python_)s ../build.py 0 $TARGET $SOURCES')
71 B1 = Builder(action = r'%(_python_)s ../build.py 1 $TARGET $SOURCES')
72 env = Environment(BUILDERS = { 'B0': B0, 'B1' : B1 })
73 env.B0(target = 'f1.out', source = 'f1.in')
74 env.B1(target = 'f2.out', source = 'f2.in')
75 env.B0(target = 'f3.out', source = 'f3.in')
76 """ % locals())
77
78 test.write(['two', 'f1.in'], "two/f1.in\n")
79 test.write(['two', 'f2.in'], "two/f2.in\n")
80 test.write(['two', 'f3.in'], "two/f3.in\n")
81
82 test.run(chdir = 'two', arguments = "f1.out f2.out f3.out",
83          stderr = "scons: *** [f2.out] Error 1\n", status = 2)
84
85 test.fail_test(test.read(['two', 'f1.out']) != "two/f1.in\n")
86 test.fail_test(os.path.exists(test.workpath('f2.out')))
87 test.fail_test(os.path.exists(test.workpath('f3.out')))
88
89 test.write(['three', 'SConstruct'], """
90 B0 = Builder(action = r'%(_python_)s ../build.py 0 $TARGET $SOURCES')
91 B1 = Builder(action = r'%(_python_)s ../build.py 1 $TARGET $SOURCES')
92 env = Environment(BUILDERS = { 'B0' : B0, 'B1': B1 })
93 env.B0(target = 'f1.out', source = 'f1.in')
94 env.B0(target = 'f2.out', source = 'f2.in')
95 env.B1(target = 'f3.out', source = 'f3.in')
96 """ % locals())
97
98 test.write(['three', 'f1.in'], "three/f1.in\n")
99 test.write(['three', 'f2.in'], "three/f2.in\n")
100 test.write(['three', 'f3.in'], "three/f3.in\n")
101
102 test.run(chdir = 'three', arguments = "f1.out f2.out f3.out",
103          stderr = "scons: *** [f3.out] Error 1\n", status = 2)
104
105 test.fail_test(test.read(['three', 'f1.out']) != "three/f1.in\n")
106 test.fail_test(test.read(['three', 'f2.out']) != "three/f2.in\n")
107 test.fail_test(os.path.exists(test.workpath('f3.out')))
108
109 test.write('SConstruct', """
110 env=Environment()
111 if env['PLATFORM'] == 'posix':
112     from SCons.Platform.posix import fork_spawn
113     env['SPAWN'] = fork_spawn
114 env['ENV']['PATH'] = ''
115 env.Command(target='foo.out', source=[], action='not_a_program')
116 """)
117
118 test.run(status=2, stderr=None)
119 err = test.stderr()
120 test.fail_test(string.find(err, 'Exception') != -1 or \
121                string.find(err, 'Traceback') != -1)
122
123
124 # Test ETOOLONG (arg list too long).  This is not in exitvalmap,
125 # but that shouldn't cause a scons traceback.
126 long_cmd = 'xyz ' + "foobarxyz" * 100000
127 test.write('SConstruct', """
128 env=Environment()
129 if env['PLATFORM'] == 'posix':
130     from SCons.Platform.posix import fork_spawn
131     env['SPAWN'] = fork_spawn
132 env.Command(target='longcmd.out', source=[], action='echo %s')
133 """%long_cmd)
134
135 test.run(status=2, stderr=None)
136 err = test.stderr()
137 test.fail_test(string.find(err, 'Exception') != -1 or \
138                string.find(err, 'Traceback') != -1)
139 # Python 1.5.2 on a FC3 system doesn't even get to the exitvalmap
140 # because it fails with "No such file or directory."  Just comment
141 # this out for now, there are plenty of other good tests below.
142 #test.fail_test(string.find(err, "too long") == -1 and # posix
143 #              string.find(err, "nvalid argument") == -1) # win32
144
145
146 # Test bad shell ('./one' is a dir, so it can't be used as a shell).
147 # This will also give an exit status not in exitvalmap,
148 # with error "Permission denied" or "No such file or directory".
149 test.write('SConstruct', """
150 env=Environment()
151 if env['PLATFORM'] in ('posix', 'darwin'):
152     from SCons.Platform.posix import fork_spawn
153     env['SPAWN'] = fork_spawn
154 env['SHELL'] = 'one'
155 env.Command(target='badshell.out', source=[], action='foo')
156 """)
157
158 test.run(status=2, stderr=None)
159 err = test.stderr()
160 if string.find(err, 'Exception') != -1 or string.find(err, 'Traceback') != -1:
161     print "Exception or Traceback found in the following error output:"
162     print err
163     test.fail_test()
164 if string.find(err, 'ermission') == -1 and string.find(err, 'such file') == -1:
165     print "Missing '[Pp]ermission' or 'such file' string in the following error output:"
166     print err
167     test.fail_test()
168
169
170 # Test command with exit status -1.
171 # Should not give traceback.
172 test.write('SConstruct', """
173 import os
174 env = Environment(ENV = os.environ)
175 env.Command('dummy.txt', None, ['python -c "import sys; sys.exit(-1)"'])
176 """)
177
178 test.run(status=2, stderr=None)
179 err = test.stderr()
180 test.fail_test(string.find(err, 'Exception') != -1 or \
181                string.find(err, 'Traceback') != -1)
182
183
184 # Test SConscript with errors and an atexit function.
185 # Should not give traceback; the task error should get converted
186 # to a BuildError.
187 test.write('SConstruct', """
188 import atexit
189
190 env = Environment()
191 env2 = env.Clone()
192
193 env.Install("target", "dir1/myFile")
194 env2.Install("target", "dir2/myFile")
195
196 def print_build_failures():
197     from SCons.Script import GetBuildFailures
198     for bf in GetBuildFailures():
199         print bf.action
200
201 atexit.register(print_build_failures)
202 """)
203
204 test.run(status=2, stderr=None)
205 err = test.stderr()
206 test.fail_test(string.find(err, 'Exception') != -1 or \
207                string.find(err, 'Traceback') != -1)
208
209
210 # No tests failed; OK.
211 test.pass_test()