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
213 self.fs = SCons.Node.FS.FS(test.workpath(''))
215 def Dictionary(self, *args):
217 return { 'FORTRANPATH': self.path, 'FORTRANMODSUFFIX' : ".mod" }
218 elif len(args) == 1 and args[0] == 'FORTRANPATH':
221 raise KeyError, "Dummy environment only has FORTRANPATH attribute."
223 def has_key(self, key):
224 return key in self.Dictionary()
226 def __getitem__(self,key):
227 return self.Dictionary()[key]
229 def __setitem__(self,key,value):
230 self.Dictionary()[key] = value
232 def __delitem__(self,key):
233 del self.Dictionary()[key]
235 def subst(self, arg, target=None, source=None, conv=None):
240 def subst_path(self, path, target=None, source=None, conv=None):
241 if not isinstance(path, list):
243 return list(map(self.subst, path))
245 def get_calculator(self):
248 def get_factory(self, factory):
249 return factory or self.fs.File
251 def Dir(self, filename):
252 return self.fs.Dir(filename)
254 def File(self, filename):
255 return self.fs.File(filename)
257 def deps_match(self, deps, headers):
258 scanned = list(map(os.path.normpath, list(map(str, deps))))
259 expect = list(map(os.path.normpath, headers))
260 self.failUnless(scanned == expect, "expect %s != scanned %s" % (expect, scanned))
264 class FortranScannerTestCase1(unittest.TestCase):
266 test.write('f1.f', "\n")
267 test.write('f2.f', " INCLUDE 'fi.f'\n")
268 env = DummyEnvironment([])
269 s = SCons.Scanner.Fortran.FortranScan()
271 deps = s(env.File('fff1.f'), env, path)
272 headers = ['f1.f', 'f2.f']
273 deps_match(self, deps, headers)
277 class FortranScannerTestCase2(unittest.TestCase):
279 test.write('f1.f', "\n")
280 test.write('f2.f', " INCLUDE 'fi.f'\n")
281 env = DummyEnvironment([test.workpath("d1")])
282 s = SCons.Scanner.Fortran.FortranScan()
284 deps = s(env.File('fff1.f'), env, path)
285 headers = ['f1.f', 'f2.f']
286 deps_match(self, deps, headers)
290 class FortranScannerTestCase3(unittest.TestCase):
292 env = DummyEnvironment([test.workpath("d1")])
293 s = SCons.Scanner.Fortran.FortranScan()
295 deps = s(env.File('fff1.f'), env, path)
296 headers = ['d1/f1.f', 'd1/f2.f']
297 deps_match(self, deps, headers)
299 class FortranScannerTestCase4(unittest.TestCase):
301 test.write(['d1', 'f2.f'], " INCLUDE 'fi.f'\n")
302 env = DummyEnvironment([test.workpath("d1")])
303 s = SCons.Scanner.Fortran.FortranScan()
305 deps = s(env.File('fff1.f'), env, path)
306 headers = ['d1/f1.f', 'd1/f2.f']
307 deps_match(self, deps, headers)
308 test.write(['d1', 'f2.f'], "\n")
310 class FortranScannerTestCase5(unittest.TestCase):
312 env = DummyEnvironment([test.workpath("d1")])
313 s = SCons.Scanner.Fortran.FortranScan()
315 deps = s(env.File('fff2.f'), env, path)
316 headers = ['d1/f2.f', 'd1/d2/f2.f', 'd1/f2.f']
317 deps_match(self, deps, headers)
319 class FortranScannerTestCase6(unittest.TestCase):
321 test.write('f2.f', "\n")
322 env = DummyEnvironment([test.workpath("d1")])
323 s = SCons.Scanner.Fortran.FortranScan()
325 deps = s(env.File('fff2.f'), env, path)
326 headers = ['d1/f2.f', 'd1/d2/f2.f', 'f2.f']
327 deps_match(self, deps, headers)
330 class FortranScannerTestCase7(unittest.TestCase):
332 env = DummyEnvironment([test.workpath("d1/d2"), test.workpath("d1")])
333 s = SCons.Scanner.Fortran.FortranScan()
335 deps = s(env.File('fff2.f'), env, path)
336 headers = ['d1/f2.f', 'd1/d2/f2.f', 'd1/d2/f2.f']
337 deps_match(self, deps, 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 deps = s(env.File('fff2.f'), env, path)
346 headers = ['d1/f2.f', 'd1/d2/f2.f', 'f2.f']
347 deps_match(self, deps, headers)
350 class FortranScannerTestCase9(unittest.TestCase):
352 test.write('f3.f', "\n")
353 env = DummyEnvironment([])
354 s = SCons.Scanner.Fortran.FortranScan()
357 n = env.File('fff3.f')
360 return s.old_rexists()
361 setattr(n, 'old_rexists', n.rexists)
362 setattr(n, 'rexists', my_rexists)
364 deps = s(n, env, path)
366 # Make sure rexists() got called on the file node being
367 # scanned, essential for cooperation with VariantDir functionality.
368 assert n.rexists_called
370 headers = ['d1/f3.f', 'f3.f']
371 deps_match(self, deps, headers)
374 class FortranScannerTestCase10(unittest.TestCase):
376 env = DummyEnvironment(["include"])
377 s = SCons.Scanner.Fortran.FortranScan()
379 deps1 = s(env.File('fff4.f'), env, path)
380 env.fs.chdir(env.Dir('subdir'))
381 dir = env.fs.getcwd()
382 env.fs.chdir(env.Dir(''))
383 path = s.path(env, dir)
384 deps2 = s(env.File('#fff4.f'), env, path)
385 headers1 = list(map(test.workpath, ['include/f4.f']))
386 headers2 = ['include/f4.f']
387 deps_match(self, deps1, headers1)
388 deps_match(self, deps2, headers2)
390 class FortranScannerTestCase11(unittest.TestCase):
392 SCons.Warnings.enableWarningClass(SCons.Warnings.DependencyWarning)
394 def __call__(self, x):
399 SCons.Warnings._warningOut = to
400 env = DummyEnvironment([])
401 s = SCons.Scanner.Fortran.FortranScan()
403 deps = s(env.File('fff5.f'), env, path)
405 # Did we catch the warning from not finding not_there.f?
408 deps_match(self, deps, [ 'f5.f' ])
410 class FortranScannerTestCase12(unittest.TestCase):
412 env = DummyEnvironment([])
413 env.fs.chdir(env.Dir('include'))
414 s = SCons.Scanner.Fortran.FortranScan()
416 test.write('include/fff4.f', test.read('fff4.f'))
417 deps = s(env.File('#include/fff4.f'), env, path)
418 env.fs.chdir(env.Dir(''))
419 deps_match(self, deps, ['f4.f'])
420 test.unlink('include/fff4.f')
422 class FortranScannerTestCase13(unittest.TestCase):
424 os.chdir(test.workpath('work'))
425 fs = SCons.Node.FS.FS(test.workpath('work'))
426 fs.Repository(test.workpath('repository'))
428 # Create a derived file in a directory that does not exist yet.
429 # This was a bug at one time.
430 f1=fs.File('include2/jjj.f')
432 env = DummyEnvironment(['include','include2'])
434 s = SCons.Scanner.Fortran.FortranScan()
436 deps = s(fs.File('src/fff.f'), env, path)
437 deps_match(self, deps, [test.workpath('repository/include/iii.f'), 'include2/jjj.f'])
438 os.chdir(test.workpath(''))
440 class FortranScannerTestCase14(unittest.TestCase):
442 os.chdir(test.workpath('work'))
443 fs = SCons.Node.FS.FS(test.workpath('work'))
444 fs.VariantDir('build1', 'src', 1)
445 fs.VariantDir('build2', 'src', 0)
446 fs.Repository(test.workpath('repository'))
447 env = DummyEnvironment([])
449 s = SCons.Scanner.Fortran.FortranScan()
451 deps1 = s(fs.File('build1/aaa.f'), env, path)
452 deps_match(self, deps1, [ 'build1/bbb.f' ])
453 deps2 = s(fs.File('build2/aaa.f'), env, path)
454 deps_match(self, deps2, [ 'src/bbb.f' ])
455 deps3 = s(fs.File('build1/ccc.f'), env, path)
456 deps_match(self, deps3, [ 'build1/ddd.f' ])
457 deps4 = s(fs.File('build2/ccc.f'), env, path)
458 deps_match(self, deps4, [ test.workpath('repository/src/ddd.f') ])
459 os.chdir(test.workpath(''))
461 class FortranScannerTestCase15(unittest.TestCase):
463 class SubstEnvironment(DummyEnvironment):
464 def subst(self, arg, target=None, source=None, conv=None, test=test):
466 return test.workpath("d1")
469 test.write(['d1', 'f2.f'], " INCLUDE 'fi.f'\n")
470 env = SubstEnvironment(["$junk"])
471 s = SCons.Scanner.Fortran.FortranScan()
473 deps = s(env.File('fff1.f'), env, path)
474 headers = ['d1/f1.f', 'd1/f2.f']
475 deps_match(self, deps, 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 deps = s(env.File('fff90a.f90'), env, path)
494 headers = ['f1.f', 'f2.f', 'f3.f', 'f4.f', 'f5.f', 'f6.f', 'f7.f', 'f8.f', 'f9.f']
495 modules = ['mod01.mod', 'mod02.mod', 'mod03.mod', 'mod04.mod', 'mod05.mod',
496 'mod06.mod', 'mod07.mod', 'mod08.mod', 'mod09.mod', 'mod10.mod',
497 'mod11.mod', 'mod12.mod', 'mod13.mod', 'mod14.mod', 'mod15.mod',
498 'mod16.mod', 'mod17.mod', 'mod18.mod', 'mod19.mod', 'mod20.mod',
499 'mod21.mod', 'mod22.mod', 'mod23.mod', 'mod24.mod', 'mod25.mod', 'modules/use.mod']
500 deps_expected = headers + modules
501 deps_match(self, deps, deps_expected)
514 suite = unittest.TestSuite()
515 suite.addTest(FortranScannerTestCase1())
516 suite.addTest(FortranScannerTestCase2())
517 suite.addTest(FortranScannerTestCase3())
518 suite.addTest(FortranScannerTestCase4())
519 suite.addTest(FortranScannerTestCase5())
520 suite.addTest(FortranScannerTestCase6())
521 suite.addTest(FortranScannerTestCase7())
522 suite.addTest(FortranScannerTestCase8())
523 suite.addTest(FortranScannerTestCase9())
524 suite.addTest(FortranScannerTestCase10())
525 suite.addTest(FortranScannerTestCase11())
526 suite.addTest(FortranScannerTestCase12())
527 suite.addTest(FortranScannerTestCase13())
528 suite.addTest(FortranScannerTestCase14())
529 suite.addTest(FortranScannerTestCase15())
530 suite.addTest(FortranScannerTestCase16())
533 if __name__ == "__main__":
534 runner = unittest.TextTestRunner()
535 result = runner.run(suite())
536 if not result.wasSuccessful():
541 # indent-tabs-mode:nil
543 # vim: set expandtab tabstop=4 shiftwidth=4: