[GRASS-SVN] r61003 - sandbox/wenzeslaus/gunittest

svn_grass at osgeo.org svn_grass at osgeo.org
Thu Jun 26 20:30:25 PDT 2014


Author: wenzeslaus
Date: 2014-06-26 20:30:25 -0700 (Thu, 26 Jun 2014)
New Revision: 61003

Modified:
   sandbox/wenzeslaus/gunittest/case.py
   sandbox/wenzeslaus/gunittest/checkers.py
   sandbox/wenzeslaus/gunittest/gmodules.py
Log:
gunittest: MD5 sums for files (not tested); declarations for special run modules functions

Modified: sandbox/wenzeslaus/gunittest/case.py
===================================================================
--- sandbox/wenzeslaus/gunittest/case.py	2014-06-27 00:44:19 UTC (rev 61002)
+++ sandbox/wenzeslaus/gunittest/case.py	2014-06-27 03:30:25 UTC (rev 61003)
@@ -12,13 +12,14 @@
 @author Vaclav Petras
 """
 
-
+import os
 import unittest
 from unittest.util import safe_repr
 
 from .gmodules import call_module
 from .checkers import (check_text_ellipsis,
-                       text_to_keyvalue, compare_keyvalue, diff_keyvalue)
+                       text_to_keyvalue, compare_keyvalue, diff_keyvalue,
+                       file_md5, files_equal_md5)
 
 
 # the following lines are for code coverage
@@ -47,6 +48,7 @@
                                                                   reference)
             self.fail(self._formatMessage(msg, standardMsg))
 
+    # TODO: we can have also more general function without the subset reference
     def assertCommandKeyValue(self, module, parameters, reference, sep,
                               msg=None):
         if isinstance(reference, basestring):
@@ -100,6 +102,89 @@
                                    parameters=parameters,
                                    reference=reference, msg=msg, sep='=')
 
+    def assertFileExists(self, filename, msg=None, skip_size_check=False):
+        """
+
+        .. note:
+            By default this also checks if the file size is greater than 0
+            since we rarely want a file to be empty.
+        """
+        if not os.path.isfile(filename):
+            standardMsg = 'File %s does not exist' % filename
+            self.fail(self._formatMessage(msg, standardMsg))
+        if not os.path.getsize(filename):
+            standardMsg = 'File %s is empty' % filename
+            self.fail(self._formatMessage(msg, standardMsg))
+
+    def assertFileMd5(self, filename, md5, msg=None):
+        self.assertFileExists(filename, msg=msg)
+        if not file_md5(filename) == md5:
+            standardMsg = 'File %s does not have the right MD5 sum' % filename
+            self.fail(self._formatMessage(msg, standardMsg))
+
+    def assertFilesEqualMd5(self, filename, reference_filename, msg=None):
+        self.assertFileExists(filename, msg=msg)
+        # nothing for ref, missing ref_filename is an error not a test failure
+        if not files_equal_md5(filename, reference_filename):
+            stdmsg = 'Files %s and %s don\'t have the same MD5 sums' % (filename,
+                                                                        reference_filename)
+            self.fail(self._formatMessage(msg, stdmsg))
+
+    # TODO: this function might be useful but it is questionable if it is really needed
+    # TODO: name run_module/test_module/assert_module/call_module?
+    # TODO: implemet this function
+    # TODO: this should be the function used for valgrind or profiling or debug
+    # TODO: how these functions will behave when doing some benchmark with stdin/stdout?
+    # TODO: should call fail instead of raising? probably not, it is not assert but...
+    # maybe we should measure time but the real benchmarks with stdin/stdout
+    # should be done by some other function
+    # can accept stdin
+    # logs merged stdout and stderr
+    # raises when modules returns non-zero (should raise after logging)
+    def run_module(self, module, stdin=None, **kwargs):
+        """Run module and save stdout and stderr.
+
+        This function should be used when you expect the module to succeed
+        and you are testing outputs of the module other than stdout.
+        For example, if you are interested in raster map it produced.
+        The advantage of this function is that it gives you a posibility to
+        examine the output of the module.
+
+        This is not appropriate for the cases when you want module standard output.
+        For this cases use call_module function which will give you stdout
+        separated without stderr and will raise an exception with stderr in
+        case of error.
+
+        .. note::
+            There should be only one call of this method per test method.
+
+        :returns: None
+        """
+        # this probably will not not use call_module because it should
+        # enable valgrid, profiling, debug for the module, ...
+        # for now call_module is good enough
+        output = call_module(module, stdin, merge_stderr=True, **kwargs)
+        # TODO: log output (stdout+stderr) to some file
+        # TODO: log also stdin and parameters
+
+    # can accept stdin
+    # returns stdout
+    # logs stderr
+    # raises when modules returns non-zero (should raise after logging)
+    def read_module(self, module, stdin=None, **kwargs):
+        """
+
+        Similar to `run_module` but returns stdout. It logs only stderr.
+
+        .. note::
+            There should be only one call of this method per test method.
+        """
+        # TODO: this cannot be implemented using call_module for sure
+        # since it needs to get stdout and stderr separately
+        # for now call_module is good enough
+        output = call_module(module, stdin, merge_stderr=False, **kwargs)
+        return output
+
 # the following lines are for code coverage
 def endcov(cov):
     cov.stop()

Modified: sandbox/wenzeslaus/gunittest/checkers.py
===================================================================
--- sandbox/wenzeslaus/gunittest/checkers.py	2014-06-27 00:44:19 UTC (rev 61002)
+++ sandbox/wenzeslaus/gunittest/checkers.py	2014-06-27 03:30:25 UTC (rev 61003)
@@ -489,6 +489,32 @@
                                 optionflags=doctest.ELLIPSIS)
 
 
+import hashlib
+
+# optimal size depends on file system and maybe on hasher.block_size
+_BUFFER_SIZE = 2**16
+
+
+# TODO: accept also open file object
+def file_md5(filename):
+    hasher = hashlib.md5()
+    with open(filename, 'rb') as f:
+        buf = f.read(_BUFFER_SIZE)
+        while len(buf) > 0:
+            hasher.update(buf)
+            buf = f.read(_BUFFER_SIZE)
+    return hasher.hexdigest()
+
+
+def text_file_md5(filename, exclude_lines=None,
+                  prepend_lines=None, append_lines=None):
+    raise NotImplementedError("Implement, or use file_md5() function instead")
+
+
+def files_equal_md5(filename_a, filename_b):
+    return file_md5(filename_a) == file_md5(filename_b)
+
+
 def main():  # pragma: no cover
     ret = doctest.testmod()
     return ret.failed

Modified: sandbox/wenzeslaus/gunittest/gmodules.py
===================================================================
--- sandbox/wenzeslaus/gunittest/gmodules.py	2014-06-27 00:44:19 UTC (rev 61002)
+++ sandbox/wenzeslaus/gunittest/gmodules.py	2014-06-27 03:30:25 UTC (rev 61003)
@@ -115,6 +115,10 @@
 
     :raises CalledModuleError: if module return code is non-zero
     :raises ValueError: if the parameters are not correct
+
+    .. note::
+        The data read is buffered in memory, so do not use this method
+        if the data size is large or unlimited.
     """
     # TODO: remove this:
     do_doctest_gettext_workaround()



More information about the grass-commit mailing list