[GRASS-SVN] r60948 - in sandbox/wenzeslaus/gunittest: . testsuite
svn_grass at osgeo.org
svn_grass at osgeo.org
Tue Jun 24 12:16:28 PDT 2014
Author: wenzeslaus
Date: 2014-06-24 12:16:28 -0700 (Tue, 24 Jun 2014)
New Revision: 60948
Modified:
sandbox/wenzeslaus/gunittest/case.py
sandbox/wenzeslaus/gunittest/checkers.py
sandbox/wenzeslaus/gunittest/grass_py_static_check.py
sandbox/wenzeslaus/gunittest/testsuite/test_assertions.py
sandbox/wenzeslaus/gunittest/testsuite/test_checkers.py
Log:
gunittest: sunset option for keyvalue comparison, keyvalue difference, and functions for comparing raster maps using r.univar output
Modified: sandbox/wenzeslaus/gunittest/case.py
===================================================================
--- sandbox/wenzeslaus/gunittest/case.py 2014-06-24 18:24:05 UTC (rev 60947)
+++ sandbox/wenzeslaus/gunittest/case.py 2014-06-24 19:16:28 UTC (rev 60948)
@@ -16,10 +16,22 @@
import unittest
from unittest.util import safe_repr
-from .checkers import check_text_ellipsis
+import grass.script.core as gcore
+from .checkers import (check_text_ellipsis,
+ text_to_keyvalue, compare_keyvalue, diff_keyvalue)
+
+# 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
+ # pylint: disable=R0904
def assertLooksLike(self, actual, reference, msg=None):
self.assert_(isinstance(actual, basestring), (
@@ -27,18 +39,34 @@
self.assert_(isinstance(reference, basestring), (
'reference argument is not a string'))
if not check_text_ellipsis(actual=actual, reference=reference):
- standardMsg = self._formatMessage(msg, '"%s" does not correspond with "%s"'
- % (safe_repr(actual),
- safe_repr(reference)))
+ standardMsg = '"%s" does not correspond with "%s"' % (safe_repr(actual),
+ safe_repr(reference))
self.fail(self._formatMessage(msg, standardMsg))
+ def assertRasterFitsUnivar(self, raster, reference_univar, msg=None):
+ if isinstance(reference_univar, basestring):
+ reference_univar = text_to_keyvalue(reference_univar, sep='=')
+ stdout = gcore.read_command('r.univar',
+ map=raster, separator='=', flags='ge')
+ raster_univar = text_to_keyvalue(stdout, sep='=')
+ if not compare_keyvalue(dict_a=reference_univar, dict_b=raster_univar,
+ a_is_subset=True):
+ unused, missing, mismatch = diff_keyvalue(dict_a=reference_univar,
+ dict_b=raster_univar,
+ a_is_subset=True)
+ standardMsg = "r.univar difference:\n"
+ if mismatch:
+ standardMsg += "mismatch values: %s\n" % mismatch
+ if missing:
+ raise ValueError("r.univar output does not contain"
+ " the following keys"
+ " provided in reference_univar"
+ ": %s\n" % missing)
+ self.fail(self._formatMessage(msg, standardMsg))
-# the following lines are for code coverage
-import coverage
-cov = coverage.coverage(omit="*testsuite*")
-cov.start()
+# the following lines are for code coverage
def endcov(cov):
cov.stop()
cov.html_report(directory='testcodecoverage')
Modified: sandbox/wenzeslaus/gunittest/checkers.py
===================================================================
--- sandbox/wenzeslaus/gunittest/checkers.py 2014-06-24 18:24:05 UTC (rev 60947)
+++ sandbox/wenzeslaus/gunittest/checkers.py 2014-06-24 19:16:28 UTC (rev 60948)
@@ -243,8 +243,10 @@
return True
+# TODO: rename to equals
def compare_keyvalue(dict_a, dict_b, precision=0.000001,
- def_equal=values_equal, key_equal=None):
+ def_equal=values_equal, key_equal=None,
+ a_is_subset=False):
"""Compare two dictionaries
This method will print a warning in case keys that are present in the first
@@ -252,6 +254,9 @@
The comparison method tries to convert the values into their native format
(float, int or string) to allow correct comparison.
+ Always use keyword arguments for all parameters with defaults. It is a good
+ idea to use keyword arguments also for the first two parameters.
+
An example key-value text file may have this content:
>>> compare_keyvalue(text_to_keyvalue('''a: Hello
@@ -271,16 +276,23 @@
@param precision precision with which the floating point values are compared
@param proj True if it has to check some information about projection system
@param units True if it has to check some information about units
+ :param callable def_equal: function used for comparison by default
+ :param dict key_equal: dictionary of functions used for comparison of specific keys
@return True if full or almost identical, False if different
"""
key_equal = {} if key_equal is None else key_equal
- if sorted(dict_a.keys()) != sorted(dict_b.keys()):
+ if not a_is_subset and sorted(dict_a.keys()) != sorted(dict_b.keys()):
return False
+ b_keys = dict_b.keys() if a_is_subset else None
- # We compare matching keys
+ # iterate over subset or just any if not a_is_subset
+ # check for missing keys in superset
+ # compare matching keys
for key in dict_a.keys():
+ if a_is_subset and key not in b_keys:
+ return False
equal_fun = key_equal.get(key, def_equal)
if not equal_fun(dict_a[key], dict_b[key], precision):
return False
@@ -296,6 +308,47 @@
return True
+# TODO: should the retrun depend on the a_is_subset parameter?
+# must have the same interface and behavior as compare_keyvalue
+def diff_keyvalue(dict_a, dict_b, precision=0.000001,
+ def_equal=values_equal, key_equal=None,
+ a_is_subset=False):
+ """
+
+ >>> a = {'c': 2, 'b': 3, 'a': 4}
+ >>> b = {'c': 1, 'b': 3, 'd': 5}
+ >>> diff_keyvalue(a, b)
+ (['d'], ['a'], [('c', 2, 1)])
+ >>> diff_keyvalue(a, b, a_is_subset=True)
+ ([], ['a'], [('c', 2, 1)])
+ """
+ key_equal = {} if key_equal is None else key_equal
+
+ a_keys = dict_a.keys()
+ b_keys = dict_b.keys()
+
+ missing_in_a = []
+ missing_in_b = []
+ mismatched = []
+
+ if not a_is_subset:
+ for key in b_keys:
+ if key not in a_keys:
+ missing_in_a.append(key)
+
+ # iterate over a, so we know that it is in a
+ for key in a_keys:
+ # check if it is in b
+ if key not in b_keys:
+ missing_in_b.append(key)
+ else:
+ equal_fun = key_equal.get(key, def_equal)
+ if not equal_fun(dict_a[key], dict_b[key], precision):
+ mismatched.append((key, dict_a[key], dict_b[key]))
+
+ return sorted(missing_in_a), sorted(missing_in_b), sorted(mismatched)
+
+
def proj_info_equals(text_a, text_b):
def compare_sums(list_a, list_b, precision):
# We compare the sum of the entries
Modified: sandbox/wenzeslaus/gunittest/grass_py_static_check.py
===================================================================
--- sandbox/wenzeslaus/gunittest/grass_py_static_check.py 2014-06-24 18:24:05 UTC (rev 60947)
+++ sandbox/wenzeslaus/gunittest/grass_py_static_check.py 2014-06-24 19:16:28 UTC (rev 60948)
@@ -32,6 +32,12 @@
cmd = ['pylint', '--rcfile=tools/pylintrc.txt', '--output-format=html',
'--ignore=.svn']
cmd = cmd + [target]
+ # graph options:
+ # --import-graph=<file.dot>
+ # --ext-import-graph=<file.dot>
+ # --int-import-graph=<file.dot>
+ # also we can call pylint directly as a package and create our own HTML
+ # report with message ids and perhaps even symbolic message names
# result
ensure_dir(output_dir)
output_file = open(output_dir + '/pylint_report.html', 'w')
Modified: sandbox/wenzeslaus/gunittest/testsuite/test_assertions.py
===================================================================
--- sandbox/wenzeslaus/gunittest/testsuite/test_assertions.py 2014-06-24 18:24:05 UTC (rev 60947)
+++ sandbox/wenzeslaus/gunittest/testsuite/test_assertions.py 2014-06-24 19:16:28 UTC (rev 60948)
@@ -14,9 +14,34 @@
class TestTextAssertions(GrassTestCase):
+ # pylint: disable=R0904
def test_assertLooksLike(self):
self.assertLooksLike("Generated map is <elevation>",
"Generated map is <...>")
self.assertRaises(self.failureException,
self.assertLooksLike, "Generated map is elevation.",
"Generated map is <...>")
+
+
+R_UNIVAR_ELEVATION_SUBSET = """n=2025000
+null_cells=0
+min=55.5787925720215
+max=156.329864501953
+"""
+
+RANDOM_KEYVALUES = """abc=2025000
+aaa=55.5787925720215
+bbb=156.329864501953
+"""
+
+
+class TestRasterMapAssertations(GrassTestCase):
+ # pylint: disable=R0904
+ def test_assertRasterFitsUnivar(self):
+ self.assertRasterFitsUnivar('elevation', R_UNIVAR_ELEVATION_SUBSET)
+ self.assertRaises(self.failureException,
+ self.assertRasterFitsUnivar,
+ 'aspect', R_UNIVAR_ELEVATION_SUBSET)
+ self.assertRaises(ValueError,
+ self.assertRasterFitsUnivar,
+ 'elevation', RANDOM_KEYVALUES)
Modified: sandbox/wenzeslaus/gunittest/testsuite/test_checkers.py
===================================================================
--- sandbox/wenzeslaus/gunittest/testsuite/test_checkers.py 2014-06-24 18:24:05 UTC (rev 60947)
+++ sandbox/wenzeslaus/gunittest/testsuite/test_checkers.py 2014-06-24 19:16:28 UTC (rev 60948)
@@ -23,6 +23,7 @@
sys.path.insert(0, os.path.split(os.path.split((os.path.dirname(__file__)))[0])[0])
from gunittest.case import GrassTestCase
from gunittest.checkers import (values_equal, text_to_keyvalue,
+ compare_keyvalue,
proj_info_equals, proj_units_equals)
@@ -235,4 +236,78 @@
self.assertDictEqual(parse_key_val(R_UNIVAR_KEYVAL_INT, val_type=int),
R_UNIVAR_KEYVAL_INT_DICT)
-
\ No newline at end of file
+
+R_UNIVAR_ELEVATION = """n=2025000
+null_cells=57995100
+cells=60020100
+min=55.5787925720215
+max=156.329864501953
+range=100.751071929932
+mean=110.375440275606
+mean_of_abs=110.375440275606
+stddev=20.3153233205981
+variance=412.712361620436
+coeff_var=18.4056555243368
+sum=223510266.558102
+first_quartile=94.79
+median=108.88
+third_quartile=126.792
+percentile_90=138.66
+"""
+
+R_UNIVAR_ELEVATION_ROUNDED = """n=2025000
+null_cells=57995100
+cells=60020100
+min=55.5788
+max=156.33
+range=100.751
+mean=110.375
+mean_of_abs=110.375
+stddev=20.3153
+variance=412.712
+coeff_var=18.4057
+sum=223510266.558
+first_quartile=94.79
+median=108.88
+third_quartile=126.792
+percentile_90=138.66
+"""
+
+R_UNIVAR_ELEVATION_SUBSET = """n=2025000
+null_cells=57995100
+cells=60020100
+min=55.5787925720215
+max=156.329864501953
+"""
+
+
+class TestRasterMapComparisons(GrassTestCase):
+
+ def test_compare_univars(self):
+ self.assertTrue(compare_keyvalue(text_to_keyvalue(R_UNIVAR_ELEVATION,
+ sep='='),
+ text_to_keyvalue(R_UNIVAR_ELEVATION,
+ sep='=')))
+ self.assertFalse(compare_keyvalue(text_to_keyvalue(R_UNIVAR_ELEVATION,
+ sep='='),
+ text_to_keyvalue(R_UNIVAR_ELEVATION_SUBSET,
+ sep='=')))
+
+ def test_compare_univars_subset(self):
+ self.assertTrue(compare_keyvalue(text_to_keyvalue(R_UNIVAR_ELEVATION_SUBSET,
+ sep='='),
+ text_to_keyvalue(R_UNIVAR_ELEVATION,
+ sep='='),
+ a_is_subset=True))
+ self.assertFalse(compare_keyvalue(text_to_keyvalue(R_UNIVAR_ELEVATION,
+ sep='='),
+ text_to_keyvalue(R_UNIVAR_ELEVATION_SUBSET,
+ sep='='),
+ a_is_subset=True))
+
+ def test_compare_univars_rounded(self):
+ self.assertTrue(compare_keyvalue(text_to_keyvalue(R_UNIVAR_ELEVATION,
+ sep='='),
+ text_to_keyvalue(R_UNIVAR_ELEVATION_ROUNDED,
+ sep='='),
+ precision=0.001))
More information about the grass-commit
mailing list