http://scons.tigris.org/issues/show_bug.cgi?id=2345
[scons.git] / src / engine / SCons / Scanner / FortranTests.py
index 03165df069eed9c8209a2623e7b24a1f891d3a1f..9ebe2e673450146885fa8bb844074f4733dc49be 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2001, 2002 Steven Knight
+# __COPYRIGHT__
 #
 # Permission is hereby granted, free of charge, to any person obtaining
 # a copy of this software and associated documentation files (the
@@ -45,7 +45,7 @@ os.chdir(test.workpath(''))
 test.write('fff1.f',"""
       PROGRAM FOO
       INCLUDE 'f1.f'
-      INCLUDE 'f2.f'
+      include 'f2.f'
       STOP
       END
 """)
@@ -53,7 +53,7 @@ test.write('fff1.f',"""
 test.write('fff2.f',"""
       PROGRAM FOO
       INCLUDE 'f2.f'
-      INCLUDE 'd1/f2.f'
+      include 'd1/f2.f'
       INCLUDE 'd2/f2.f'
       STOP
       END
@@ -134,22 +134,94 @@ test.write([ 'repository', 'src', 'ccc.f'], """
 
 test.write([ 'repository', 'src', 'ddd.f'], "\n")
 
+
+test.write('fff90a.f90',"""
+      PROGRAM FOO
+
+!  Test comments - these includes should NOT be picked up
+C     INCLUDE 'fi.f'
+#     INCLUDE 'fi.f'
+  !   INCLUDE 'fi.f'
+
+      INCLUDE 'f1.f'  ! in-line comments are valid syntax
+      INCLUDE"fi.f"   ! space is significant - this should be ignored
+      INCLUDE  <f2.f>  ! Absoft compiler allows greater than/less than delimiters
+!
+!  Allow kind type parameters
+      INCLUDE kindType_"f3.f"
+      INCLUDE kind_Type_"f4.f"
+!
+!  Test multiple statements per line - use various spacings between semicolons
+      incLUDE 'f5.f';include "f6.f"  ;  include <f7.f>; include 'f8.f' ;include kindType_'f9.f'
+!
+!  Test various USE statement syntaxes
+!
+      USE Mod01
+      use mod02
+      use use
+      USE mOD03, ONLY : someVar
+      USE MOD04 ,only:someVar
+      USE Mod05 , ONLY: someVar ! in-line comment
+      USE Mod06,ONLY :someVar,someOtherVar
+
+      USE  mod07;USE  mod08; USE mod09 ;USE mod10 ; USE mod11  ! Test various semicolon placements
+      use mod12 ;use mod13! Test comment at end of line
+
+!     USE modi
+!     USE modia ; use modib    ! Scanner regexp will only ignore the first - this is a deficiency in the regexp
+    ! USE modic ; ! use modid  ! Scanner regexp should ignore both modules
+      USE mod14 !; USE modi    ! Only ignore the second
+      USE mod15!;USE modi
+      USE mod16  !  ;  USE  modi
+
+!  Test semicolon syntax - use various spacings
+      USE :: mod17
+      USE::mod18
+      USE ::mod19 ; USE:: mod20
+
+      use, non_intrinsic :: mod21, ONLY : someVar ; use,intrinsic:: mod22
+      USE, NON_INTRINSIC::mod23 ; USE ,INTRINSIC ::mod24
+
+USE mod25  ! Test USE statement at the beginning of line
+
+
+; USE modi   ! Scanner should ignore this since it isn't valid syntax
+      USEmodi   ! No space in between USE and module name - ignore it
+      USE mod01   ! This one is a duplicate - there should only be one dependency to it.
+
+      STOP
+      END
+""")
+
+modules = ['mod01.mod', 'mod02.mod', 'mod03.mod', 'mod04.mod', 'mod05.mod',
+           'mod06.mod', 'mod07.mod', 'mod08.mod', 'mod09.mod', 'mod10.mod',
+           'mod11.mod', 'mod12.mod', 'mod13.mod', 'mod14.mod', 'mod15.mod',
+           'mod16.mod', 'mod17.mod', 'mod18.mod', 'mod19.mod', 'mod20.mod',
+           'mod21.mod', 'mod22.mod', 'mod23.mod', 'mod24.mod', 'mod25.mod']
+
+for m in modules:
+    test.write(m, "\n")
+
+test.subdir('modules')
+test.write(['modules', 'use.mod'], "\n")
+
 # define some helpers:
 
 class DummyEnvironment:
     def __init__(self, listCppPath):
         self.path = listCppPath
-        
+        self.fs = SCons.Node.FS.FS(test.workpath(''))
+
     def Dictionary(self, *args):
         if not args:
-            return { 'F77PATH': self.path }
-        elif len(args) == 1 and args[0] == 'F77PATH':
+            return { 'FORTRANPATH': self.path, 'FORTRANMODSUFFIX' : ".mod" }
+        elif len(args) == 1 and args[0] == 'FORTRANPATH':
             return self.path
         else:
-            raise KeyError, "Dummy environment only has F77PATH attribute."
+            raise KeyError("Dummy environment only has FORTRANPATH attribute.")
 
     def has_key(self, key):
-        return self.Dictionary().has_key(key)
+        return key in self.Dictionary()
 
     def __getitem__(self,key):
         return self.Dictionary()[key]
@@ -160,17 +232,33 @@ class DummyEnvironment:
     def __delitem__(self,key):
         del self.Dictionary()[key]
 
-    def subst(self, arg):
+    def subst(self, arg, target=None, source=None, conv=None):
+        if arg[0] == '$':
+            return self[arg[1:]]
         return arg
 
+    def subst_path(self, path, target=None, source=None, conv=None):
+        if not isinstance(path, list):
+            path = [path]
+        return list(map(self.subst, path))
+
+    def get_calculator(self):
+        return None
+
+    def get_factory(self, factory):
+        return factory or self.fs.File
+
+    def Dir(self, filename):
+        return self.fs.Dir(filename)
+
+    def File(self, filename):
+        return self.fs.File(filename)
+
 def deps_match(self, deps, headers):
-    scanned = map(os.path.normpath, map(str, deps))
-    expect = map(os.path.normpath, headers)
+    scanned = list(map(os.path.normpath, list(map(str, deps))))
+    expect = list(map(os.path.normpath, headers))
     self.failUnless(scanned == expect, "expect %s != scanned %s" % (expect, scanned))
 
-def make_node(filename, fs=SCons.Node.FS.default_fs):
-    return fs.File(test.workpath(filename))
-
 # define some tests:
 
 class FortranScannerTestCase1(unittest.TestCase):
@@ -180,10 +268,9 @@ class FortranScannerTestCase1(unittest.TestCase):
         env = DummyEnvironment([])
         s = SCons.Scanner.Fortran.FortranScan()
         path = s.path(env)
-        fs = SCons.Node.FS.FS(original)
-        deps = s(make_node('fff1.f', fs), env, path)
+        deps = s(env.File('fff1.f'), env, path)
         headers = ['f1.f', 'f2.f']
-        deps_match(self, deps, map(test.workpath, headers))
+        deps_match(self, deps, headers)
         test.unlink('f1.f')
         test.unlink('f2.f')
 
@@ -194,10 +281,9 @@ class FortranScannerTestCase2(unittest.TestCase):
         env = DummyEnvironment([test.workpath("d1")])
         s = SCons.Scanner.Fortran.FortranScan()
         path = s.path(env)
-        fs = SCons.Node.FS.FS(original)
-        deps = s(make_node('fff1.f', fs), env, path)
+        deps = s(env.File('fff1.f'), env, path)
         headers = ['f1.f', 'f2.f']
-        deps_match(self, deps, map(test.workpath, headers))
+        deps_match(self, deps, headers)
         test.unlink('f1.f')
         test.unlink('f2.f')
 
@@ -206,10 +292,9 @@ class FortranScannerTestCase3(unittest.TestCase):
         env = DummyEnvironment([test.workpath("d1")])
         s = SCons.Scanner.Fortran.FortranScan()
         path = s.path(env)
-        fs = SCons.Node.FS.FS(original)
-        deps = s(make_node('fff1.f', fs), env, path)
+        deps = s(env.File('fff1.f'), env, path)
         headers = ['d1/f1.f', 'd1/f2.f']
-        deps_match(self, deps, map(test.workpath, headers))
+        deps_match(self, deps, headers)
 
 class FortranScannerTestCase4(unittest.TestCase):
     def runTest(self):
@@ -217,10 +302,9 @@ class FortranScannerTestCase4(unittest.TestCase):
         env = DummyEnvironment([test.workpath("d1")])
         s = SCons.Scanner.Fortran.FortranScan()
         path = s.path(env)
-        fs = SCons.Node.FS.FS(original)
-        deps = s(make_node('fff1.f', fs), env, path)
+        deps = s(env.File('fff1.f'), env, path)
         headers = ['d1/f1.f', 'd1/f2.f']
-        deps_match(self, deps, map(test.workpath, headers))
+        deps_match(self, deps, headers)
         test.write(['d1', 'f2.f'], "\n")
 
 class FortranScannerTestCase5(unittest.TestCase):
@@ -228,10 +312,9 @@ class FortranScannerTestCase5(unittest.TestCase):
         env = DummyEnvironment([test.workpath("d1")])
         s = SCons.Scanner.Fortran.FortranScan()
         path = s.path(env)
-        fs = SCons.Node.FS.FS(original)
-        deps = s(make_node('fff2.f', fs), env, path)
-        headers = ['d1/d2/f2.f', 'd1/f2.f', 'd1/f2.f']
-        deps_match(self, deps, map(test.workpath, headers))
+        deps = s(env.File('fff2.f'), env, path)
+        headers = ['d1/f2.f', 'd1/d2/f2.f', 'd1/f2.f']
+        deps_match(self, deps, headers)
 
 class FortranScannerTestCase6(unittest.TestCase):
     def runTest(self):
@@ -239,10 +322,9 @@ class FortranScannerTestCase6(unittest.TestCase):
         env = DummyEnvironment([test.workpath("d1")])
         s = SCons.Scanner.Fortran.FortranScan()
         path = s.path(env)
-        fs = SCons.Node.FS.FS(original)
-        deps = s(make_node('fff2.f', fs), env, path)
-        headers =  ['d1/d2/f2.f', 'd1/f2.f', 'f2.f']
-        deps_match(self, deps, map(test.workpath, headers))
+        deps = s(env.File('fff2.f'), env, path)
+        headers =  ['d1/f2.f', 'd1/d2/f2.f', 'f2.f']
+        deps_match(self, deps, headers)
         test.unlink('f2.f')
 
 class FortranScannerTestCase7(unittest.TestCase):
@@ -250,10 +332,9 @@ class FortranScannerTestCase7(unittest.TestCase):
         env = DummyEnvironment([test.workpath("d1/d2"), test.workpath("d1")])
         s = SCons.Scanner.Fortran.FortranScan()
         path = s.path(env)
-        fs = SCons.Node.FS.FS(original)
-        deps = s(make_node('fff2.f', fs), env, path)
-        headers =  ['d1/d2/f2.f', 'd1/d2/f2.f', 'd1/f2.f']
-        deps_match(self, deps, map(test.workpath, headers))
+        deps = s(env.File('fff2.f'), env, path)
+        headers =  ['d1/f2.f', 'd1/d2/f2.f', 'd1/d2/f2.f']
+        deps_match(self, deps, headers)
 
 class FortranScannerTestCase8(unittest.TestCase):
     def runTest(self):
@@ -261,12 +342,11 @@ class FortranScannerTestCase8(unittest.TestCase):
         env = DummyEnvironment([test.workpath("d1/d2"), test.workpath("d1")])
         s = SCons.Scanner.Fortran.FortranScan()
         path = s.path(env)
-        fs = SCons.Node.FS.FS(original)
-        deps = s(make_node('fff2.f', fs), env, path)
-        headers =  ['d1/d2/f2.f', 'd1/f2.f', 'f2.f']
-        deps_match(self, deps, map(test.workpath, headers))
+        deps = s(env.File('fff2.f'), env, path)
+        headers =  ['d1/f2.f', 'd1/d2/f2.f', 'f2.f']
+        deps_match(self, deps, headers)
         test.unlink('f2.f')
-        
+
 class FortranScannerTestCase9(unittest.TestCase):
     def runTest(self):
         test.write('f3.f', "\n")
@@ -274,7 +354,7 @@ class FortranScannerTestCase9(unittest.TestCase):
         s = SCons.Scanner.Fortran.FortranScan()
         path = s.path(env)
 
-        n = make_node('fff3.f')
+        n = env.File('fff3.f')
         def my_rexists(s=n):
             s.rexists_called = 1
             return s.old_rexists()
@@ -282,29 +362,28 @@ class FortranScannerTestCase9(unittest.TestCase):
         setattr(n, 'rexists', my_rexists)
 
         deps = s(n, env, path)
-        
+
         # Make sure rexists() got called on the file node being
-        # scanned, essential for cooperation with BuildDir functionality.
+        # scanned, essential for cooperation with VariantDir functionality.
         assert n.rexists_called
-        
+
         headers =  ['d1/f3.f', 'f3.f']
-        deps_match(self, deps, map(test.workpath, headers))
+        deps_match(self, deps, headers)
         test.unlink('f3.f')
 
 class FortranScannerTestCase10(unittest.TestCase):
     def runTest(self):
-        fs = SCons.Node.FS.FS(test.workpath(''))
         env = DummyEnvironment(["include"])
-        s = SCons.Scanner.Fortran.FortranScan(fs = fs)
+        s = SCons.Scanner.Fortran.FortranScan()
         path = s.path(env)
-        deps1 = s(fs.File('fff4.f'), env, path)
-        fs.chdir(fs.Dir('subdir'))
-        dir = fs.getcwd()
-        fs.chdir(fs.Dir('..'))
+        deps1 = s(env.File('fff4.f'), env, path)
+        env.fs.chdir(env.Dir('subdir'))
+        dir = env.fs.getcwd()
+        env.fs.chdir(env.Dir(''))
         path = s.path(env, dir)
-        deps2 = s(fs.File('#fff4.f'), env, path)
-        headers1 =  ['include/f4.f']
-        headers2 =  ['subdir/include/f4.f']
+        deps2 = s(env.File('#fff4.f'), env, path)
+        headers1 =  list(map(test.workpath, ['include/f4.f']))
+        headers2 =  ['include/f4.f']
         deps_match(self, deps1, headers1)
         deps_match(self, deps2, headers2)
 
@@ -318,27 +397,26 @@ class FortranScannerTestCase11(unittest.TestCase):
         to = TestOut()
         to.out = None
         SCons.Warnings._warningOut = to
-        fs = SCons.Node.FS.FS(test.workpath(''))
         env = DummyEnvironment([])
-        s = SCons.Scanner.Fortran.FortranScan(fs=fs)
+        s = SCons.Scanner.Fortran.FortranScan()
         path = s.path(env)
-        deps = s(fs.File('fff5.f'), env, path)
+        deps = s(env.File('fff5.f'), env, path)
 
         # Did we catch the warning from not finding not_there.f?
         assert to.out
-        
+
         deps_match(self, deps, [ 'f5.f' ])
 
 class FortranScannerTestCase12(unittest.TestCase):
     def runTest(self):
-        fs = SCons.Node.FS.FS(test.workpath(''))
-        fs.chdir(fs.Dir('include'))
         env = DummyEnvironment([])
-        s = SCons.Scanner.Fortran.FortranScan(fs=fs)
+        env.fs.chdir(env.Dir('include'))
+        s = SCons.Scanner.Fortran.FortranScan()
         path = s.path(env)
         test.write('include/fff4.f', test.read('fff4.f'))
-        deps = s(fs.File('#include/fff4.f'), env, path)
-        deps_match(self, deps, ['include/f4.f'])
+        deps = s(env.File('#include/fff4.f'), env, path)
+        env.fs.chdir(env.Dir(''))
+        deps_match(self, deps, ['f4.f'])
         test.unlink('include/fff4.f')
 
 class FortranScannerTestCase13(unittest.TestCase):
@@ -352,7 +430,8 @@ class FortranScannerTestCase13(unittest.TestCase):
         f1=fs.File('include2/jjj.f')
         f1.builder=1
         env = DummyEnvironment(['include','include2'])
-        s = SCons.Scanner.Fortran.FortranScan(fs=fs)
+        env.fs = fs
+        s = SCons.Scanner.Fortran.FortranScan()
         path = s.path(env)
         deps = s(fs.File('src/fff.f'), env, path)
         deps_match(self, deps, [test.workpath('repository/include/iii.f'), 'include2/jjj.f'])
@@ -362,11 +441,12 @@ class FortranScannerTestCase14(unittest.TestCase):
     def runTest(self):
         os.chdir(test.workpath('work'))
         fs = SCons.Node.FS.FS(test.workpath('work'))
-        fs.BuildDir('build1', 'src', 1)
-        fs.BuildDir('build2', 'src', 0)
+        fs.VariantDir('build1', 'src', 1)
+        fs.VariantDir('build2', 'src', 0)
         fs.Repository(test.workpath('repository'))
         env = DummyEnvironment([])
-        s = SCons.Scanner.Fortran.FortranScan(fs = fs)
+        env.fs = fs
+        s = SCons.Scanner.Fortran.FortranScan()
         path = s.path(env)
         deps1 = s(fs.File('build1/aaa.f'), env, path)
         deps_match(self, deps1, [ 'build1/bbb.f' ])
@@ -381,18 +461,55 @@ class FortranScannerTestCase14(unittest.TestCase):
 class FortranScannerTestCase15(unittest.TestCase):
     def runTest(self):
         class SubstEnvironment(DummyEnvironment):
-            def subst(self, arg, test=test):
-                return test.workpath("d1")
+            def subst(self, arg, target=None, source=None, conv=None, test=test):
+                if arg == "$junk":
+                    return test.workpath("d1")
+                else:
+                    return arg
         test.write(['d1', 'f2.f'], "      INCLUDE 'fi.f'\n")
-        env = SubstEnvironment(["junk"])
+        env = SubstEnvironment(["$junk"])
         s = SCons.Scanner.Fortran.FortranScan()
         path = s.path(env)
-        fs = SCons.Node.FS.FS(original)
-        deps = s(make_node('fff1.f', fs), env, path)
+        deps = s(env.File('fff1.f'), env, path)
         headers = ['d1/f1.f', 'd1/f2.f']
-        deps_match(self, deps, map(test.workpath, headers))
+        deps_match(self, deps, headers)
         test.write(['d1', 'f2.f'], "\n")
 
+class FortranScannerTestCase16(unittest.TestCase):
+    def runTest(self):
+        test.write('f1.f', "\n")
+        test.write('f2.f', "\n")
+        test.write('f3.f', "\n")
+        test.write('f4.f', "\n")
+        test.write('f5.f', "\n")
+        test.write('f6.f', "\n")
+        test.write('f7.f', "\n")
+        test.write('f8.f', "\n")
+        test.write('f9.f', "\n")
+        test.write('f10.f', "\n")
+        env = DummyEnvironment([test.workpath('modules')])
+        s = SCons.Scanner.Fortran.FortranScan()
+        path = s.path(env)
+        deps = s(env.File('fff90a.f90'), env, path)
+        headers = ['f1.f', 'f2.f', 'f3.f', 'f4.f', 'f5.f', 'f6.f', 'f7.f', 'f8.f', 'f9.f']
+        modules = ['mod01.mod', 'mod02.mod', 'mod03.mod', 'mod04.mod', 'mod05.mod',
+                   'mod06.mod', 'mod07.mod', 'mod08.mod', 'mod09.mod', 'mod10.mod',
+                   'mod11.mod', 'mod12.mod', 'mod13.mod', 'mod14.mod', 'mod15.mod',
+                   'mod16.mod', 'mod17.mod', 'mod18.mod', 'mod19.mod', 'mod20.mod',
+                   'mod21.mod', 'mod22.mod', 'mod23.mod', 'mod24.mod', 'mod25.mod', 'modules/use.mod']
+        deps_expected = headers + modules
+        deps_match(self, deps, deps_expected)
+        test.unlink('f1.f')
+        test.unlink('f2.f')
+        test.unlink('f3.f')
+        test.unlink('f4.f')
+        test.unlink('f5.f')
+        test.unlink('f6.f')
+        test.unlink('f7.f')
+        test.unlink('f8.f')
+        test.unlink('f9.f')
+        test.unlink('f10.f')
+
 def suite():
     suite = unittest.TestSuite()
     suite.addTest(FortranScannerTestCase1())
@@ -410,6 +527,7 @@ def suite():
     suite.addTest(FortranScannerTestCase13())
     suite.addTest(FortranScannerTestCase14())
     suite.addTest(FortranScannerTestCase15())
+    suite.addTest(FortranScannerTestCase16())
     return suite
 
 if __name__ == "__main__":
@@ -417,3 +535,9 @@ if __name__ == "__main__":
     result = runner.run(suite())
     if not result.wasSuccessful():
         sys.exit(1)
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4: