[GRASS-SVN] r61109 - in sandbox/wenzeslaus/gunittest: . testsuite

svn_grass at osgeo.org svn_grass at osgeo.org
Tue Jul 1 20:54:30 PDT 2014


Author: wenzeslaus
Date: 2014-07-01 20:54:30 -0700 (Tue, 01 Jul 2014)
New Revision: 61109

Modified:
   sandbox/wenzeslaus/gunittest/case.py
   sandbox/wenzeslaus/gunittest/grass_py_static_check.py
   sandbox/wenzeslaus/gunittest/loader.py
   sandbox/wenzeslaus/gunittest/main.py
   sandbox/wenzeslaus/gunittest/testsuite/test_assertions.py
   sandbox/wenzeslaus/gunittest/testsuite/test_checkers.py
   sandbox/wenzeslaus/gunittest/testsuite/test_doctests.py
   sandbox/wenzeslaus/gunittest/testsuite/test_gmodules.py
   sandbox/wenzeslaus/gunittest/testsuite/test_module_assertions.py
Log:
gunittest: basic implementation of invoking modules (unittest-like discovery, standalone script, discovery of standalone scripts)

Modified: sandbox/wenzeslaus/gunittest/case.py
===================================================================
--- sandbox/wenzeslaus/gunittest/case.py	2014-07-01 22:01:59 UTC (rev 61108)
+++ sandbox/wenzeslaus/gunittest/case.py	2014-07-02 03:54:30 UTC (rev 61109)
@@ -23,11 +23,6 @@
                        file_md5, files_equal_md5)
 
 
-# the following lines are for code coverage
-import coverage
-cov = coverage.coverage(omit="*testsuite*")
-cov.start()
-
 class GrassTestCase(unittest.TestCase):
     # we dissable R0904 for all TestCase classes because their purpose is to
     # provide a lot of assert methods
@@ -404,13 +399,3 @@
             stdmsg = ('Running <%s> ended with zero (successful) return code'
                       ' when expecting module to fail' % module.get_python())
             self.fail(self._formatMessage(msg, stdmsg))
-
-
-# the following lines are for code coverage
-def endcov(cov):
-    cov.stop()
-    cov.html_report(directory='testcodecoverage')
-
-
-import atexit
-atexit.register(endcov, cov)

Modified: sandbox/wenzeslaus/gunittest/grass_py_static_check.py
===================================================================
--- sandbox/wenzeslaus/gunittest/grass_py_static_check.py	2014-07-01 22:01:59 UTC (rev 61108)
+++ sandbox/wenzeslaus/gunittest/grass_py_static_check.py	2014-07-02 03:54:30 UTC (rev 61109)
@@ -23,6 +23,7 @@
 import re
 
 
+# also in gunittest.main
 def ensure_dir(directory):
     if not os.path.exists(directory):
         os.makedirs(directory)

Modified: sandbox/wenzeslaus/gunittest/loader.py
===================================================================
--- sandbox/wenzeslaus/gunittest/loader.py	2014-07-01 22:01:59 UTC (rev 61108)
+++ sandbox/wenzeslaus/gunittest/loader.py	2014-07-02 03:54:30 UTC (rev 61109)
@@ -15,9 +15,59 @@
 GrassTestPythonModule = collections.namedtuple('GrassTestPythonModule',
                                                ['name', 'module',
                                                 'tested_dir',
-                                                'file_dir'])
+                                                'file_dir',
+                                                'abs_file_path'])
 
 
+def discover_modules(start_dir, file_pattern, skip_dirs, testsuite_dir,
+                     grass_location,
+                     all_locations_value, universal_location_value,
+                     import_modules):
+    modules = []
+    for root, dirs, files in os.walk(start_dir):
+        for dir_pattern in skip_dirs:
+            to_skip = fnmatch.filter(dirs, dir_pattern)
+            for skip in to_skip:
+                dirs.remove(skip)
+
+        if testsuite_dir in dirs:
+            dirs.remove(testsuite_dir)  # do not recurse to testsuite
+            full = os.path.join(root, testsuite_dir)
+            files = fnmatch.filter(os.listdir(full), file_pattern)
+            # we just ignore __init__.py
+            module_names = [f[:-3] for f in files if not f == '__init__.py']
+            for name in module_names:
+                # TODO: rewrite to use import_module and search the file if not
+                abspath = os.path.abspath(full)
+                sys.path.insert(0, abspath)
+                try:
+                    m = importlib.import_module(name)
+                    add = False
+                    if grass_location == all_locations_value:
+                        add = True
+                    else:
+                        try:
+                            locations = m.LOCATIONS
+                        except AttributeError:
+                            add = True  # test is universal
+                        else:
+                            if universal_location_value in locations:
+                                add = True  # cases when it is explicit
+                            if grass_location in locations:
+                                add = True  # standard case with given location
+                    if add:
+                        modules.append(GrassTestPythonModule(name=name,
+                                                             module=m,
+                                                             tested_dir=root,
+                                                             file_dir=full,
+                                                             abs_file_path=os.path.join(abspath, name + '.py')))
+                    # in else with some verbose we could tell about skiped test
+                except ImportError as e:
+                    raise ImportError('Cannot import module named %s in %s (%s)' % (name, full, e.message))
+                    # alternative is to create TestClass which will raise
+                    # see unittest.loader
+    return modules
+
 class GrassTestLoader(unittest.TestLoader):
 
     skip_dirs = ['.svn', 'dist.*', 'bin.*', 'OBJ.*']
@@ -30,49 +80,21 @@
     def __init__(self, grass_location):
         self.grass_location = grass_location
 
-    # TODO: we ignore all parameters
+    # TODO: what is the purpose of top_level_dir, can it be useful?
+    # probably yes, we need to know grass src or dist root
+    # TODO: not using pattern here
     def discover(self, start_dir, pattern='test*.py', top_level_dir=None):
-        modules = []
+        modules = discover_modules(start_dir=start_dir,
+                                   file_pattern=self.files_in_testsuite,
+                                   skip_dirs=self.skip_dirs,
+                                   testsuite_dir=self.testsuite_dir,
+                                   grass_location=self.grass_location,
+                                   all_locations_value=self.all_tests_value,
+                                   universal_location_value=self.universal_tests_value,
+                                   import_modules=True)
         tests = []
-        for root, dirs, files in os.walk('.'):
-            for pattern in self.skip_dirs:
-                to_skip = fnmatch.filter(dirs, pattern)
-                for skip in to_skip:
-                    dirs.remove(skip)
-
-            if self.testsuite_dir in dirs:
-                dirs.remove(self.testsuite_dir)  # do not recurse to testsuite
-                full = os.path.join(root, self.testsuite_dir)
-                files = fnmatch.filter(os.listdir(full), self.files_in_testsuite)
-                module_names = [f[:-3] for f in files if not f == '__init__.py']
-                for name in module_names:
-                    sys.path.insert(0, full)
-                    try:
-                        m = importlib.import_module(name)
-                        run = False
-                        if self.grass_location == self.all_tests_value:
-                            run = True
-                        else:
-                            try:
-                                locations = m.LOCATIONS
-                            except AttributeError:
-                                run = True  # test is universal
-                            else:
-                                if self.universal_tests_value in locations:
-                                    run = True  # cases when it is explicit
-                                if self.grass_location in locations:
-                                    run = True  # standard case with given location
-                        if run:
-                            modules.append(GrassTestPythonModule(name=name,
-                                                                      module=m,
-                                                                      tested_dir=root,
-                                                                      file_dir=full))
-                            tests.append(self.loadTestsFromModule(m))
-                        # in else with some verbose we could tell about skiped test
-                    except ImportError:
-                        raise ImportError('No module named %s in %s' % (name, full))
-                        # alternative is to create TestClass which will raise
-                        # see unittest.loader
+        for module in modules:
+            tests.append(self.loadTestsFromModule(module.module))
         return self.suiteClass(tests)
 
 

Modified: sandbox/wenzeslaus/gunittest/main.py
===================================================================
--- sandbox/wenzeslaus/gunittest/main.py	2014-07-01 22:01:59 UTC (rev 61108)
+++ sandbox/wenzeslaus/gunittest/main.py	2014-07-02 03:54:30 UTC (rev 61109)
@@ -1,18 +1,20 @@
 # -*- coding: utf-8 -*-
 
+import os
+import sys
 
 from unittest.main import TestProgram, USAGE_AS_MAIN
 TestProgram.USAGE = USAGE_AS_MAIN
 
-from loader import GrassTestLoader
+from loader import GrassTestLoader, discover_modules
 from runner import GrassTestRunner
 
 
 class GrassTestProgram(TestProgram):
 
-    def __init__(self, grass_location=None, clean_outputs=True,
-                 unittest_argv=None,
-                 exit_at_end=True, verbosity=1,
+    def __init__(self, exit_at_end, grass_location, clean_outputs=True,
+                 unittest_argv=None,  module=None,
+                 verbosity=1,
                  failfast=None, catchbreak=None):
         """Prepares the tests in GRASS way and then runs the tests.
 
@@ -29,7 +31,8 @@
                                        failfast=failfast,
                                        buffer=buffer_stdout_stderr)
 
-        super(GrassTestProgram, self).__init__(module=None, argv=unittest_argv,
+        super(GrassTestProgram, self).__init__(module=module,
+                                               argv=unittest_argv,
                                                testLoader=grass_loader,
                                                testRunner=grass_runner,
                                                exit=exit_at_end,
@@ -38,5 +41,71 @@
                                                catchbreak=catchbreak,
                                                buffer=buffer_stdout_stderr)
 
+
+def main():
+    """Run a test of a module.
+    """
+    import coverage
+    cov = coverage.coverage(omit="*testsuite*")
+    cov.start()
+
+    program = GrassTestProgram(module='__main__', exit_at_end=False, grass_location='all')
+
+    cov.stop()
+    cov.html_report(directory='testcodecoverage')
+
+    sys.exit(program.result.wasSuccessful())
+
+
+test = main
+
+
+def discovery():
+    """Recursively find all tests in testsuite directories and run them
+
+    Everything is imported and runs in this process.
+
+    Runs using::
+        python main.py discovery [start_directory]
+    """
+    import coverage
+    cov = coverage.coverage(omit="*testsuite*")
+    cov.start()
+
+    program = GrassTestProgram(grass_location='nc', exit_at_end=False)
+
+    cov.stop()
+    cov.html_report(directory='testcodecoverage')
+
+    sys.exit(program.result.wasSuccessful())
+
+
+def ensure_dir(directory):
+    if not os.path.exists(directory):
+        os.makedirs(directory)
+
+
+def recursive_runs():
+    grass_location = 'nc'
+    # here should never be the same as start_dir, it leads to confusing dir tree
+    results_root = 'testresults'
+    import subprocess
+    modules = discover_modules(start_dir='.',
+                               file_pattern=GrassTestLoader.files_in_testsuite,
+                               skip_dirs=GrassTestLoader.skip_dirs,
+                               testsuite_dir=GrassTestLoader.testsuite_dir,
+                               grass_location=grass_location,
+                               all_locations_value=GrassTestLoader.all_tests_value,
+                               universal_location_value=GrassTestLoader.universal_tests_value,
+                               import_modules=False)
+    env = os.environ.copy()
+    for module in modules:
+        cwd = os.path.join(results_root, module.tested_dir, module.name)
+        ensure_dir(os.path.abspath(cwd))
+        # TODO: we might clean the directory here before test if non-empty
+        p = subprocess.Popen([sys.executable, module.abs_file_path], cwd=cwd, env=env)
+        p.wait()
+
+
 if __name__ == '__main__':
-    GrassTestProgram(grass_location='nc')
+    recursive_runs()

Modified: sandbox/wenzeslaus/gunittest/testsuite/test_assertions.py
===================================================================
--- sandbox/wenzeslaus/gunittest/testsuite/test_assertions.py	2014-07-01 22:01:59 UTC (rev 61108)
+++ sandbox/wenzeslaus/gunittest/testsuite/test_assertions.py	2014-07-02 03:54:30 UTC (rev 61109)
@@ -11,10 +11,10 @@
 import grass.script.core as gcore
 
 # import gunittest as a package so that relative imports there works
-sys.path.insert(0, os.path.split(os.path.split((os.path.dirname(__file__)))[0])[0])
+sys.path.insert(0, os.path.split(os.path.split((os.path.dirname(os.path.abspath(__file__))))[0])[0])
 from gunittest.case import GrassTestCase
+import gunittest
 
-
 class TestTextAssertions(GrassTestCase):
     # pylint: disable=R0904
     def test_assertLooksLike(self):
@@ -196,3 +196,8 @@
                           self.assertFilesEqualMd5,
                           filename=self.file_with_md5,
                           reference=self.file_with_different_content)
+
+
+if __name__ == '__main__':
+    from gunittest.main import test
+    test()

Modified: sandbox/wenzeslaus/gunittest/testsuite/test_checkers.py
===================================================================
--- sandbox/wenzeslaus/gunittest/testsuite/test_checkers.py	2014-07-01 22:01:59 UTC (rev 61108)
+++ sandbox/wenzeslaus/gunittest/testsuite/test_checkers.py	2014-07-02 03:54:30 UTC (rev 61109)
@@ -20,7 +20,7 @@
 from grass.script.core import parse_key_val
 
 # import gunittest as a package so that relative imports there works
-sys.path.insert(0, os.path.split(os.path.split((os.path.dirname(__file__)))[0])[0])
+sys.path.insert(0, os.path.split(os.path.split((os.path.dirname(os.path.abspath(__file__))))[0])[0])
 from gunittest.case import GrassTestCase
 from gunittest.checkers import (values_equal, text_to_keyvalue,
                                 compare_keyvalue,
@@ -311,3 +311,8 @@
                                          text_to_keyvalue(R_UNIVAR_ELEVATION_ROUNDED,
                                                           sep='='),
                                          precision=0.001))
+
+
+if __name__ == '__main__':
+    from gunittest.main import test
+    test()
\ No newline at end of file

Modified: sandbox/wenzeslaus/gunittest/testsuite/test_doctests.py
===================================================================
--- sandbox/wenzeslaus/gunittest/testsuite/test_doctests.py	2014-07-01 22:01:59 UTC (rev 61108)
+++ sandbox/wenzeslaus/gunittest/testsuite/test_doctests.py	2014-07-02 03:54:30 UTC (rev 61109)
@@ -8,7 +8,7 @@
 import doctest
 
 # import gunittest as a package so that relative imports there works
-sys.path.insert(0, os.path.split(os.path.split((os.path.dirname(__file__)))[0])[0])
+sys.path.insert(0, os.path.split(os.path.split((os.path.dirname(os.path.abspath(__file__))))[0])[0])
 import gunittest
 
 
@@ -30,3 +30,8 @@
     tests.addTests(doctest.DocTestSuite(gunittest.gmodules))
     tests.addTests(doctest.DocTestSuite(gunittest.checkers))
     return tests
+
+
+if __name__ == '__main__':
+    from gunittest.main import test
+    test()

Modified: sandbox/wenzeslaus/gunittest/testsuite/test_gmodules.py
===================================================================
--- sandbox/wenzeslaus/gunittest/testsuite/test_gmodules.py	2014-07-01 22:01:59 UTC (rev 61108)
+++ sandbox/wenzeslaus/gunittest/testsuite/test_gmodules.py	2014-07-02 03:54:30 UTC (rev 61109)
@@ -5,7 +5,7 @@
 import subprocess
 
 # this should be solved on the level of the testing framework
-sys.path.insert(0, os.path.split(os.path.split((os.path.dirname(__file__)))[0])[0])
+sys.path.insert(0, os.path.split(os.path.split((os.path.dirname(os.path.abspath(__file__))))[0])[0])
 
 from gunittest.case import GrassTestCase
 from gunittest.gmodules import (call_module, CalledModuleError,
@@ -122,3 +122,8 @@
         self.assertRaises(CalledModuleError,
                           write_module,
                           'm.proj', stdin='50,50', aaabbbcc='notexist')
+
+
+if __name__ == '__main__':
+    from gunittest.main import test
+    test()

Modified: sandbox/wenzeslaus/gunittest/testsuite/test_module_assertions.py
===================================================================
--- sandbox/wenzeslaus/gunittest/testsuite/test_module_assertions.py	2014-07-01 22:01:59 UTC (rev 61108)
+++ sandbox/wenzeslaus/gunittest/testsuite/test_module_assertions.py	2014-07-02 03:54:30 UTC (rev 61109)
@@ -8,7 +8,7 @@
 from grass.pygrass.modules import Module
 
 # import gunittest as a package so that relative imports there works
-sys.path.insert(0, os.path.split(os.path.split((os.path.dirname(__file__)))[0])[0])
+sys.path.insert(0, os.path.split(os.path.split((os.path.dirname(os.path.abspath(__file__))))[0])[0])
 from gunittest.case import GrassTestCase
 from gunittest.gmodules import CalledModuleError
 
@@ -39,3 +39,8 @@
         self.assertTrue(stderr)
         self.assertIn(self.wrong_map, stderr)
         self.assertRaises(self.failureException, self.assertModuleFail, self.rinfo)
+
+
+if __name__ == '__main__':
+    from gunittest.main import test
+    test()



More information about the grass-commit mailing list