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__"
31 import SCons.Scanner.Fortran
37 original = os.getcwd()
39 test = TestCmd.TestCmd(workdir = '')
41 os.chdir(test.workpath(''))
43 # create some source files and headers:
45 test.write('fff1.f',"""
53 test.write('fff2.f',"""
62 test.write('fff3.f',"""
64 INCLUDE 'f3.f' ; INCLUDE\t'd1/f3.f'
72 test.subdir('d1', ['d1', 'd2'])
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']
83 test.subdir('include', 'subdir', ['subdir', 'include'])
85 test.write('fff4.f',"""
92 test.write('include/f4.f', "\n")
93 test.write('subdir/include/f4.f', "\n")
95 test.write('fff5.f',"""
103 test.write('f5.f', "\n")
105 test.subdir('repository', ['repository', 'include'],
106 [ 'repository', 'src' ])
107 test.subdir('work', ['work', 'src'])
109 test.write(['repository', 'include', 'iii.f'], "\n")
111 test.write(['work', 'src', 'fff.f'], """
119 test.write([ 'work', 'src', 'aaa.f'], """
126 test.write([ 'work', 'src', 'bbb.f'], "\n")
128 test.write([ 'repository', 'src', 'ccc.f'], """
135 test.write([ 'repository', 'src', 'ddd.f'], "\n")
138 test.write('fff90a.f90',"""
141 ! Test comments - these includes should NOT be picked up
146 INCLUDE 'f1.f' ! in-line comments are valid syntax
147 INCLUDE"fi.f" ! space is significant - this should be ignored
148 INCLUDE <f2.f> ! Absoft compiler allows greater than/less than delimiters
150 ! Allow kind type parameters
151 INCLUDE kindType_"f3.f"
152 INCLUDE kind_Type_"f4.f"
154 ! Test multiple statements per line - use various spacings between semicolons
155 incLUDE 'f5.f';include "f6.f" ; include <f7.f>; include 'f8.f' ;include kindType_'f9.f'
157 ! Test various USE statement syntaxes
162 USE mOD03, ONLY : someVar
163 USE MOD04 ,only:someVar
164 USE Mod05 , ONLY: someVar ! in-line comment
165 USE Mod06,ONLY :someVar,someOtherVar
167 USE mod07;USE mod08; USE mod09 ;USE mod10 ; USE mod11 ! Test various semicolon placements
168 use mod12 ;use mod13! Test comment at end of line
171 ! USE modia ; use modib ! Scanner regexp will only ignore the first - this is a deficiency in the regexp
172 ! USE modic ; ! use modid ! Scanner regexp should ignore both modules
173 USE mod14 !; USE modi ! Only ignore the second
175 USE mod16 ! ; USE modi
177 ! Test semicolon syntax - use various spacings
180 USE ::mod19 ; USE:: mod20
182 use, non_intrinsic :: mod21, ONLY : someVar ; use,intrinsic:: mod22
183 USE, NON_INTRINSIC::mod23 ; USE ,INTRINSIC ::mod24
185 USE mod25 ! Test USE statement at the beginning of line
188 ; USE modi ! Scanner should ignore this since it isn't valid syntax
189 USEmodi ! No space in between USE and module name - ignore it
190 USE mod01 ! This one is a duplicate - there should only be one dependency to it.
196 modules = ['mod01.mod', 'mod02.mod', 'mod03.mod', 'mod04.mod', 'mod05.mod',
197 'mod06.mod', 'mod07.mod', 'mod08.mod', 'mod09.mod', 'mod10.mod',
198 'mod11.mod', 'mod12.mod', 'mod13.mod', 'mod14.mod', 'mod15.mod',
199 'mod16.mod', 'mod17.mod', 'mod18.mod', 'mod19.mod', 'mod20.mod',
200 'mod21.mod', 'mod22.mod', 'mod23.mod', 'mod24.mod', 'mod25.mod']
205 test.subdir('modules')
206 test.write(['modules', 'use.mod'], "\n")
208 # define some helpers:
210 class DummyEnvironment:
211 def __init__(self, listCppPath):
212 self.path = listCppPath
214 def Dictionary(self, *args):
216 return { 'FORTRANPATH': self.path, 'FORTRANMODSUFFIX' : ".mod" }
217 elif len(args) == 1 and args[0] == 'FORTRANPATH':
220 raise KeyError, "Dummy environment only has FORTRANPATH attribute."
222 def has_key(self, key):
223 return self.Dictionary().has_key(key)
225 def __getitem__(self,key):
226 return self.Dictionary()[key]
228 def __setitem__(self,key,value):
229 self.Dictionary()[key] = value
231 def __delitem__(self,key):
232 del self.Dictionary()[key]
234 def subst(self, arg):
239 def subst_path(self, path, target=None):
240 if type(path) != type([]):
242 return map(self.subst, path)
244 def get_calculator(self):
247 def deps_match(self, deps, headers):
248 scanned = map(os.path.normpath, map(str, deps))
249 expect = map(os.path.normpath, headers)
250 self.failUnless(scanned == expect, "expect %s != scanned %s" % (expect, scanned))
252 def make_node(filename, fs=SCons.Node.FS.default_fs):
253 return fs.File(test.workpath(filename))
257 class FortranScannerTestCase1(unittest.TestCase):
259 test.write('f1.f', "\n")
260 test.write('f2.f', " INCLUDE 'fi.f'\n")
261 env = DummyEnvironment([])
262 s = SCons.Scanner.Fortran.FortranScan()
264 fs = SCons.Node.FS.FS(original)
265 deps = s(make_node('fff1.f', fs), env, path)
266 headers = ['f1.f', 'f2.f']
267 deps_match(self, deps, map(test.workpath, headers))
271 class FortranScannerTestCase2(unittest.TestCase):
273 test.write('f1.f', "\n")
274 test.write('f2.f', " INCLUDE 'fi.f'\n")
275 env = DummyEnvironment([test.workpath("d1")])
276 s = SCons.Scanner.Fortran.FortranScan()
278 fs = SCons.Node.FS.FS(original)
279 deps = s(make_node('fff1.f', fs), env, path)
280 headers = ['f1.f', 'f2.f']
281 deps_match(self, deps, map(test.workpath, headers))
285 class FortranScannerTestCase3(unittest.TestCase):
287 env = DummyEnvironment([test.workpath("d1")])
288 s = SCons.Scanner.Fortran.FortranScan()
290 fs = SCons.Node.FS.FS(original)
291 deps = s(make_node('fff1.f', fs), env, path)
292 headers = ['d1/f1.f', 'd1/f2.f']
293 deps_match(self, deps, map(test.workpath, headers))
295 class FortranScannerTestCase4(unittest.TestCase):
297 test.write(['d1', 'f2.f'], " INCLUDE 'fi.f'\n")
298 env = DummyEnvironment([test.workpath("d1")])
299 s = SCons.Scanner.Fortran.FortranScan()
301 fs = SCons.Node.FS.FS(original)
302 deps = s(make_node('fff1.f', fs), env, path)
303 headers = ['d1/f1.f', 'd1/f2.f']
304 deps_match(self, deps, map(test.workpath, headers))
305 test.write(['d1', 'f2.f'], "\n")
307 class FortranScannerTestCase5(unittest.TestCase):
309 env = DummyEnvironment([test.workpath("d1")])
310 s = SCons.Scanner.Fortran.FortranScan()
312 fs = SCons.Node.FS.FS(original)
313 deps = s(make_node('fff2.f', fs), env, path)
314 headers = ['d1/f2.f', 'd1/d2/f2.f', 'd1/f2.f']
315 deps_match(self, deps, map(test.workpath, headers))
317 class FortranScannerTestCase6(unittest.TestCase):
319 test.write('f2.f', "\n")
320 env = DummyEnvironment([test.workpath("d1")])
321 s = SCons.Scanner.Fortran.FortranScan()
323 fs = SCons.Node.FS.FS(original)
324 deps = s(make_node('fff2.f', fs), env, path)
325 headers = ['d1/f2.f', 'd1/d2/f2.f', 'f2.f']
326 deps_match(self, deps, map(test.workpath, headers))
329 class FortranScannerTestCase7(unittest.TestCase):
331 env = DummyEnvironment([test.workpath("d1/d2"), test.workpath("d1")])
332 s = SCons.Scanner.Fortran.FortranScan()
334 fs = SCons.Node.FS.FS(original)
335 deps = s(make_node('fff2.f', fs), env, path)
336 headers = ['d1/f2.f', 'd1/d2/f2.f', 'd1/d2/f2.f']
337 deps_match(self, deps, map(test.workpath, headers))
339 class FortranScannerTestCase8(unittest.TestCase):
341 test.write('f2.f', "\n")
342 env = DummyEnvironment([test.workpath("d1/d2"), test.workpath("d1")])
343 s = SCons.Scanner.Fortran.FortranScan()
345 fs = SCons.Node.FS.FS(original)
346 deps = s(make_node('fff2.f', fs), env, path)
347 headers = ['d1/f2.f', 'd1/d2/f2.f', 'f2.f']
348 deps_match(self, deps, map(test.workpath, headers))
351 class FortranScannerTestCase9(unittest.TestCase):
353 test.write('f3.f', "\n")
354 env = DummyEnvironment([])
355 s = SCons.Scanner.Fortran.FortranScan()
358 n = make_node('fff3.f')
361 return s.old_rexists()
362 setattr(n, 'old_rexists', n.rexists)
363 setattr(n, 'rexists', my_rexists)
365 deps = s(n, env, path)
367 # Make sure rexists() got called on the file node being
368 # scanned, essential for cooperation with BuildDir functionality.
369 assert n.rexists_called
371 headers = ['d1/f3.f', 'f3.f']
372 deps_match(self, deps, map(test.workpath, headers))
375 class FortranScannerTestCase10(unittest.TestCase):
377 fs = SCons.Node.FS.FS(test.workpath(''))
378 env = DummyEnvironment(["include"])
379 s = SCons.Scanner.Fortran.FortranScan(fs = fs)
381 deps1 = s(fs.File('fff4.f'), env, path)
382 fs.chdir(fs.Dir('subdir'))
384 fs.chdir(fs.Dir('..'))
385 path = s.path(env, dir)
386 deps2 = s(fs.File('#fff4.f'), env, path)
387 headers1 = ['include/f4.f']
388 headers2 = ['subdir/include/f4.f']
389 deps_match(self, deps1, headers1)
390 deps_match(self, deps2, headers2)
392 class FortranScannerTestCase11(unittest.TestCase):
394 SCons.Warnings.enableWarningClass(SCons.Warnings.DependencyWarning)
396 def __call__(self, x):
401 SCons.Warnings._warningOut = to
402 fs = SCons.Node.FS.FS(test.workpath(''))
403 env = DummyEnvironment([])
404 s = SCons.Scanner.Fortran.FortranScan(fs=fs)
406 deps = s(fs.File('fff5.f'), env, path)
408 # Did we catch the warning from not finding not_there.f?
411 deps_match(self, deps, [ 'f5.f' ])
413 class FortranScannerTestCase12(unittest.TestCase):
415 fs = SCons.Node.FS.FS(test.workpath(''))
416 fs.chdir(fs.Dir('include'))
417 env = DummyEnvironment([])
418 s = SCons.Scanner.Fortran.FortranScan(fs=fs)
420 test.write('include/fff4.f', test.read('fff4.f'))
421 deps = s(fs.File('#include/fff4.f'), env, path)
422 fs.chdir(fs.Dir('..'))
423 deps_match(self, deps, ['include/f4.f'])
424 test.unlink('include/fff4.f')
426 class FortranScannerTestCase13(unittest.TestCase):
428 os.chdir(test.workpath('work'))
429 fs = SCons.Node.FS.FS(test.workpath('work'))
430 fs.Repository(test.workpath('repository'))
432 # Create a derived file in a directory that does not exist yet.
433 # This was a bug at one time.
434 f1=fs.File('include2/jjj.f')
436 env = DummyEnvironment(['include','include2'])
437 s = SCons.Scanner.Fortran.FortranScan(fs=fs)
439 deps = s(fs.File('src/fff.f'), env, path)
440 deps_match(self, deps, [test.workpath('repository/include/iii.f'), 'include2/jjj.f'])
441 os.chdir(test.workpath(''))
443 class FortranScannerTestCase14(unittest.TestCase):
445 os.chdir(test.workpath('work'))
446 fs = SCons.Node.FS.FS(test.workpath('work'))
447 fs.BuildDir('build1', 'src', 1)
448 fs.BuildDir('build2', 'src', 0)
449 fs.Repository(test.workpath('repository'))
450 env = DummyEnvironment([])
451 s = SCons.Scanner.Fortran.FortranScan(fs = fs)
453 deps1 = s(fs.File('build1/aaa.f'), env, path)
454 deps_match(self, deps1, [ 'build1/bbb.f' ])
455 deps2 = s(fs.File('build2/aaa.f'), env, path)
456 deps_match(self, deps2, [ 'src/bbb.f' ])
457 deps3 = s(fs.File('build1/ccc.f'), env, path)
458 deps_match(self, deps3, [ 'build1/ddd.f' ])
459 deps4 = s(fs.File('build2/ccc.f'), env, path)
460 deps_match(self, deps4, [ test.workpath('repository/src/ddd.f') ])
461 os.chdir(test.workpath(''))
463 class FortranScannerTestCase15(unittest.TestCase):
465 class SubstEnvironment(DummyEnvironment):
466 def subst(self, arg, test=test):
467 return test.workpath("d1")
468 test.write(['d1', 'f2.f'], " INCLUDE 'fi.f'\n")
469 env = SubstEnvironment(["junk"])
470 s = SCons.Scanner.Fortran.FortranScan()
472 fs = SCons.Node.FS.FS(original)
473 deps = s(make_node('fff1.f', fs), env, path)
474 headers = ['d1/f1.f', 'd1/f2.f']
475 deps_match(self, deps, map(test.workpath, headers))
476 test.write(['d1', 'f2.f'], "\n")
478 class FortranScannerTestCase16(unittest.TestCase):
480 test.write('f1.f', "\n")
481 test.write('f2.f', "\n")
482 test.write('f3.f', "\n")
483 test.write('f4.f', "\n")
484 test.write('f5.f', "\n")
485 test.write('f6.f', "\n")
486 test.write('f7.f', "\n")
487 test.write('f8.f', "\n")
488 test.write('f9.f', "\n")
489 test.write('f10.f', "\n")
490 env = DummyEnvironment([test.workpath('modules')])
491 s = SCons.Scanner.Fortran.FortranScan()
493 fs = SCons.Node.FS.FS(original)
494 deps = s(make_node('fff90a.f90', fs), env, path)
495 headers = ['f1.f', 'f2.f', 'f3.f', 'f4.f', 'f5.f', 'f6.f', 'f7.f', 'f8.f', 'f9.f']
496 modules = ['mod01.mod', 'mod02.mod', 'mod03.mod', 'mod04.mod', 'mod05.mod',
497 'mod06.mod', 'mod07.mod', 'mod08.mod', 'mod09.mod', 'mod10.mod',
498 'mod11.mod', 'mod12.mod', 'mod13.mod', 'mod14.mod', 'mod15.mod',
499 'mod16.mod', 'mod17.mod', 'mod18.mod', 'mod19.mod', 'mod20.mod',
500 'mod21.mod', 'mod22.mod', 'mod23.mod', 'mod24.mod', 'mod25.mod', 'modules/use.mod']
501 deps_expected = headers + modules
502 deps_match(self, deps, map(test.workpath, deps_expected))
515 suite = unittest.TestSuite()
516 suite.addTest(FortranScannerTestCase1())
517 suite.addTest(FortranScannerTestCase2())
518 suite.addTest(FortranScannerTestCase3())
519 suite.addTest(FortranScannerTestCase4())
520 suite.addTest(FortranScannerTestCase5())
521 suite.addTest(FortranScannerTestCase6())
522 suite.addTest(FortranScannerTestCase7())
523 suite.addTest(FortranScannerTestCase8())
524 suite.addTest(FortranScannerTestCase9())
525 suite.addTest(FortranScannerTestCase10())
526 suite.addTest(FortranScannerTestCase11())
527 suite.addTest(FortranScannerTestCase12())
528 suite.addTest(FortranScannerTestCase13())
529 suite.addTest(FortranScannerTestCase14())
530 suite.addTest(FortranScannerTestCase15())
531 suite.addTest(FortranScannerTestCase16())
534 if __name__ == "__main__":
535 runner = unittest.TextTestRunner()
536 result = runner.run(suite())
537 if not result.wasSuccessful():