[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