Make the Fortran scanner case-insensitive. (David M. Cooke)
[scons.git] / src / engine / SCons / Scanner / FortranTests.py
1 #
2 # __COPYRIGHT__
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 sys
29 import unittest
30
31 import SCons.Scanner.Fortran
32 import SCons.Node.FS
33 import SCons.Warnings
34
35 import TestCmd
36
37 original = os.getcwd()
38
39 test = TestCmd.TestCmd(workdir = '')
40
41 os.chdir(test.workpath(''))
42
43 # create some source files and headers:
44
45 test.write('fff1.f',"""
46       PROGRAM FOO
47       INCLUDE 'f1.f'
48       include 'f2.f'
49       STOP
50       END
51 """)
52
53 test.write('fff2.f',"""
54       PROGRAM FOO
55       INCLUDE 'f2.f'
56       include 'd1/f2.f'
57       INCLUDE 'd2/f2.f'
58       STOP
59       END
60 """)
61
62 test.write('fff3.f',"""
63       PROGRAM FOO
64       INCLUDE 'f3.f' ; INCLUDE\t'd1/f3.f'
65       STOP
66       END
67 """)
68
69
70 # for Emacs -> "
71
72 test.subdir('d1', ['d1', 'd2'])
73
74 headers = ['fi.f', 'never.f',
75            'd1/f1.f', 'd1/f2.f', 'd1/f3.f', 'd1/fi.f',
76            'd1/d2/f1.f', 'd1/d2/f2.f', 'd1/d2/f3.f',
77            'd1/d2/f4.f', 'd1/d2/fi.f']
78
79 for h in headers:
80     test.write(h, "\n")
81
82
83 test.subdir('include', 'subdir', ['subdir', 'include'])
84
85 test.write('fff4.f',"""
86       PROGRAM FOO
87       INCLUDE 'f4.f'
88       STOP
89       END
90 """)
91
92 test.write('include/f4.f', "\n")
93 test.write('subdir/include/f4.f', "\n")
94
95 test.write('fff5.f',"""
96       PROGRAM FOO
97       INCLUDE 'f5.f'
98       INCLUDE 'not_there.f'
99       STOP
100       END
101 """)
102
103 test.write('f5.f', "\n")
104
105 test.subdir('repository', ['repository', 'include'],
106             [ 'repository', 'src' ])
107 test.subdir('work', ['work', 'src'])
108
109 test.write(['repository', 'include', 'iii.f'], "\n")
110
111 test.write(['work', 'src', 'fff.f'], """
112       PROGRAM FOO
113       INCLUDE 'iii.f'
114       INCLUDE 'jjj.f'
115       STOP
116       END
117 """)
118
119 test.write([ 'work', 'src', 'aaa.f'], """
120       PROGRAM FOO
121       INCLUDE 'bbb.f'
122       STOP
123       END
124 """)
125
126 test.write([ 'work', 'src', 'bbb.f'], "\n")
127
128 test.write([ 'repository', 'src', 'ccc.f'], """
129       PROGRAM FOO
130       INCLUDE 'ddd.f'
131       STOP
132       END
133 """)
134
135 test.write([ 'repository', 'src', 'ddd.f'], "\n")
136
137 # define some helpers:
138
139 class DummyEnvironment:
140     def __init__(self, listCppPath):
141         self.path = listCppPath
142         
143     def Dictionary(self, *args):
144         if not args:
145             return { 'F77PATH': self.path }
146         elif len(args) == 1 and args[0] == 'F77PATH':
147             return self.path
148         else:
149             raise KeyError, "Dummy environment only has F77PATH attribute."
150
151     def has_key(self, key):
152         return self.Dictionary().has_key(key)
153
154     def __getitem__(self,key):
155         return self.Dictionary()[key]
156
157     def __setitem__(self,key,value):
158         self.Dictionary()[key] = value
159
160     def __delitem__(self,key):
161         del self.Dictionary()[key]
162
163     def subst(self, arg):
164         return arg
165
166 def deps_match(self, deps, headers):
167     scanned = map(os.path.normpath, map(str, deps))
168     expect = map(os.path.normpath, headers)
169     self.failUnless(scanned == expect, "expect %s != scanned %s" % (expect, scanned))
170
171 def make_node(filename, fs=SCons.Node.FS.default_fs):
172     return fs.File(test.workpath(filename))
173
174 # define some tests:
175
176 class FortranScannerTestCase1(unittest.TestCase):
177     def runTest(self):
178         test.write('f1.f', "\n")
179         test.write('f2.f', "      INCLUDE 'fi.f'\n")
180         env = DummyEnvironment([])
181         s = SCons.Scanner.Fortran.FortranScan()
182         path = s.path(env)
183         fs = SCons.Node.FS.FS(original)
184         deps = s(make_node('fff1.f', fs), env, path)
185         headers = ['f1.f', 'f2.f']
186         deps_match(self, deps, map(test.workpath, headers))
187         test.unlink('f1.f')
188         test.unlink('f2.f')
189
190 class FortranScannerTestCase2(unittest.TestCase):
191     def runTest(self):
192         test.write('f1.f', "\n")
193         test.write('f2.f', "      INCLUDE 'fi.f'\n")
194         env = DummyEnvironment([test.workpath("d1")])
195         s = SCons.Scanner.Fortran.FortranScan()
196         path = s.path(env)
197         fs = SCons.Node.FS.FS(original)
198         deps = s(make_node('fff1.f', fs), env, path)
199         headers = ['f1.f', 'f2.f']
200         deps_match(self, deps, map(test.workpath, headers))
201         test.unlink('f1.f')
202         test.unlink('f2.f')
203
204 class FortranScannerTestCase3(unittest.TestCase):
205     def runTest(self):
206         env = DummyEnvironment([test.workpath("d1")])
207         s = SCons.Scanner.Fortran.FortranScan()
208         path = s.path(env)
209         fs = SCons.Node.FS.FS(original)
210         deps = s(make_node('fff1.f', fs), env, path)
211         headers = ['d1/f1.f', 'd1/f2.f']
212         deps_match(self, deps, map(test.workpath, headers))
213
214 class FortranScannerTestCase4(unittest.TestCase):
215     def runTest(self):
216         test.write(['d1', 'f2.f'], "      INCLUDE 'fi.f'\n")
217         env = DummyEnvironment([test.workpath("d1")])
218         s = SCons.Scanner.Fortran.FortranScan()
219         path = s.path(env)
220         fs = SCons.Node.FS.FS(original)
221         deps = s(make_node('fff1.f', fs), env, path)
222         headers = ['d1/f1.f', 'd1/f2.f']
223         deps_match(self, deps, map(test.workpath, headers))
224         test.write(['d1', 'f2.f'], "\n")
225
226 class FortranScannerTestCase5(unittest.TestCase):
227     def runTest(self):
228         env = DummyEnvironment([test.workpath("d1")])
229         s = SCons.Scanner.Fortran.FortranScan()
230         path = s.path(env)
231         fs = SCons.Node.FS.FS(original)
232         deps = s(make_node('fff2.f', fs), env, path)
233         headers = ['d1/d2/f2.f', 'd1/f2.f', 'd1/f2.f']
234         deps_match(self, deps, map(test.workpath, headers))
235
236 class FortranScannerTestCase6(unittest.TestCase):
237     def runTest(self):
238         test.write('f2.f', "\n")
239         env = DummyEnvironment([test.workpath("d1")])
240         s = SCons.Scanner.Fortran.FortranScan()
241         path = s.path(env)
242         fs = SCons.Node.FS.FS(original)
243         deps = s(make_node('fff2.f', fs), env, path)
244         headers =  ['d1/d2/f2.f', 'd1/f2.f', 'f2.f']
245         deps_match(self, deps, map(test.workpath, headers))
246         test.unlink('f2.f')
247
248 class FortranScannerTestCase7(unittest.TestCase):
249     def runTest(self):
250         env = DummyEnvironment([test.workpath("d1/d2"), test.workpath("d1")])
251         s = SCons.Scanner.Fortran.FortranScan()
252         path = s.path(env)
253         fs = SCons.Node.FS.FS(original)
254         deps = s(make_node('fff2.f', fs), env, path)
255         headers =  ['d1/d2/f2.f', 'd1/d2/f2.f', 'd1/f2.f']
256         deps_match(self, deps, map(test.workpath, headers))
257
258 class FortranScannerTestCase8(unittest.TestCase):
259     def runTest(self):
260         test.write('f2.f', "\n")
261         env = DummyEnvironment([test.workpath("d1/d2"), test.workpath("d1")])
262         s = SCons.Scanner.Fortran.FortranScan()
263         path = s.path(env)
264         fs = SCons.Node.FS.FS(original)
265         deps = s(make_node('fff2.f', fs), env, path)
266         headers =  ['d1/d2/f2.f', 'd1/f2.f', 'f2.f']
267         deps_match(self, deps, map(test.workpath, headers))
268         test.unlink('f2.f')
269         
270 class FortranScannerTestCase9(unittest.TestCase):
271     def runTest(self):
272         test.write('f3.f', "\n")
273         env = DummyEnvironment([])
274         s = SCons.Scanner.Fortran.FortranScan()
275         path = s.path(env)
276
277         n = make_node('fff3.f')
278         def my_rexists(s=n):
279             s.rexists_called = 1
280             return s.old_rexists()
281         setattr(n, 'old_rexists', n.rexists)
282         setattr(n, 'rexists', my_rexists)
283
284         deps = s(n, env, path)
285         
286         # Make sure rexists() got called on the file node being
287         # scanned, essential for cooperation with BuildDir functionality.
288         assert n.rexists_called
289         
290         headers =  ['d1/f3.f', 'f3.f']
291         deps_match(self, deps, map(test.workpath, headers))
292         test.unlink('f3.f')
293
294 class FortranScannerTestCase10(unittest.TestCase):
295     def runTest(self):
296         fs = SCons.Node.FS.FS(test.workpath(''))
297         env = DummyEnvironment(["include"])
298         s = SCons.Scanner.Fortran.FortranScan(fs = fs)
299         path = s.path(env)
300         deps1 = s(fs.File('fff4.f'), env, path)
301         fs.chdir(fs.Dir('subdir'))
302         dir = fs.getcwd()
303         fs.chdir(fs.Dir('..'))
304         path = s.path(env, dir)
305         deps2 = s(fs.File('#fff4.f'), env, path)
306         headers1 =  ['include/f4.f']
307         headers2 =  ['subdir/include/f4.f']
308         deps_match(self, deps1, headers1)
309         deps_match(self, deps2, headers2)
310
311 class FortranScannerTestCase11(unittest.TestCase):
312     def runTest(self):
313         SCons.Warnings.enableWarningClass(SCons.Warnings.DependencyWarning)
314         class TestOut:
315             def __call__(self, x):
316                 self.out = x
317
318         to = TestOut()
319         to.out = None
320         SCons.Warnings._warningOut = to
321         fs = SCons.Node.FS.FS(test.workpath(''))
322         env = DummyEnvironment([])
323         s = SCons.Scanner.Fortran.FortranScan(fs=fs)
324         path = s.path(env)
325         deps = s(fs.File('fff5.f'), env, path)
326
327         # Did we catch the warning from not finding not_there.f?
328         assert to.out
329         
330         deps_match(self, deps, [ 'f5.f' ])
331
332 class FortranScannerTestCase12(unittest.TestCase):
333     def runTest(self):
334         fs = SCons.Node.FS.FS(test.workpath(''))
335         fs.chdir(fs.Dir('include'))
336         env = DummyEnvironment([])
337         s = SCons.Scanner.Fortran.FortranScan(fs=fs)
338         path = s.path(env)
339         test.write('include/fff4.f', test.read('fff4.f'))
340         deps = s(fs.File('#include/fff4.f'), env, path)
341         fs.chdir(fs.Dir('..'))
342         deps_match(self, deps, ['include/f4.f'])
343         test.unlink('include/fff4.f')
344
345 class FortranScannerTestCase13(unittest.TestCase):
346     def runTest(self):
347         os.chdir(test.workpath('work'))
348         fs = SCons.Node.FS.FS(test.workpath('work'))
349         fs.Repository(test.workpath('repository'))
350
351         # Create a derived file in a directory that does not exist yet.
352         # This was a bug at one time.
353         f1=fs.File('include2/jjj.f')
354         f1.builder=1
355         env = DummyEnvironment(['include','include2'])
356         s = SCons.Scanner.Fortran.FortranScan(fs=fs)
357         path = s.path(env)
358         deps = s(fs.File('src/fff.f'), env, path)
359         deps_match(self, deps, [test.workpath('repository/include/iii.f'), 'include2/jjj.f'])
360         os.chdir(test.workpath(''))
361
362 class FortranScannerTestCase14(unittest.TestCase):
363     def runTest(self):
364         os.chdir(test.workpath('work'))
365         fs = SCons.Node.FS.FS(test.workpath('work'))
366         fs.BuildDir('build1', 'src', 1)
367         fs.BuildDir('build2', 'src', 0)
368         fs.Repository(test.workpath('repository'))
369         env = DummyEnvironment([])
370         s = SCons.Scanner.Fortran.FortranScan(fs = fs)
371         path = s.path(env)
372         deps1 = s(fs.File('build1/aaa.f'), env, path)
373         deps_match(self, deps1, [ 'build1/bbb.f' ])
374         deps2 = s(fs.File('build2/aaa.f'), env, path)
375         deps_match(self, deps2, [ 'src/bbb.f' ])
376         deps3 = s(fs.File('build1/ccc.f'), env, path)
377         deps_match(self, deps3, [ 'build1/ddd.f' ])
378         deps4 = s(fs.File('build2/ccc.f'), env, path)
379         deps_match(self, deps4, [ test.workpath('repository/src/ddd.f') ])
380         os.chdir(test.workpath(''))
381
382 class FortranScannerTestCase15(unittest.TestCase):
383     def runTest(self):
384         class SubstEnvironment(DummyEnvironment):
385             def subst(self, arg, test=test):
386                 return test.workpath("d1")
387         test.write(['d1', 'f2.f'], "      INCLUDE 'fi.f'\n")
388         env = SubstEnvironment(["junk"])
389         s = SCons.Scanner.Fortran.FortranScan()
390         path = s.path(env)
391         fs = SCons.Node.FS.FS(original)
392         deps = s(make_node('fff1.f', fs), env, path)
393         headers = ['d1/f1.f', 'd1/f2.f']
394         deps_match(self, deps, map(test.workpath, headers))
395         test.write(['d1', 'f2.f'], "\n")
396
397 def suite():
398     suite = unittest.TestSuite()
399     suite.addTest(FortranScannerTestCase1())
400     suite.addTest(FortranScannerTestCase2())
401     suite.addTest(FortranScannerTestCase3())
402     suite.addTest(FortranScannerTestCase4())
403     suite.addTest(FortranScannerTestCase5())
404     suite.addTest(FortranScannerTestCase6())
405     suite.addTest(FortranScannerTestCase7())
406     suite.addTest(FortranScannerTestCase8())
407     suite.addTest(FortranScannerTestCase9())
408     suite.addTest(FortranScannerTestCase10())
409     suite.addTest(FortranScannerTestCase11())
410     suite.addTest(FortranScannerTestCase12())
411     suite.addTest(FortranScannerTestCase13())
412     suite.addTest(FortranScannerTestCase14())
413     suite.addTest(FortranScannerTestCase15())
414     return suite
415
416 if __name__ == "__main__":
417     runner = unittest.TextTestRunner()
418     result = runner.run(suite())
419     if not result.wasSuccessful():
420         sys.exit(1)