Changeset 64662


Ignore:
Timestamp:
Feb 17, 2015, 8:42:58 AM (9 years ago)
Author:
wenzeslaus
Message:

gunittest: improvements to make it work better on MS Windows

  • use short, although unreadable, map and file names to overcome problems with 260 character limit (MAX_PATH) of Win32 API (GPATH_MAX is 4096)
  • override assertMultiLineEqual() to replace CRLF by LF, so that test authors can just use unix line endings
  • register assertMultiLineEqual() for strings so that the CRLF replacement happens for assertEqual() as expected
  • explicitly check for existence of a provided Location


Location:
grass/trunk/lib/python/gunittest
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • grass/trunk/lib/python/gunittest/case.py

    r64637 r64662  
    1313import subprocess
    1414import StringIO
    15 
     15import hashlib
     16import uuid
    1617import unittest
    1718
     
    4041    _temp_region = None  # to control the temporary region
    4142    html_reports = False  # output additional HTML files with failure details
     43    readable_names = False  # prefer shorter but unreadable map and file names
    4244
    4345    def __init__(self, methodName):
     
    4547        self.grass_modules = []
    4648        self.supplementary_files = []
     49        # Python unittest doc is saying that strings use assertMultiLineEqual
     50        # but only unicode type is registered
     51        # TODO: report this as a bug? is this in Python 3.x?
     52        self.addTypeEqualityFunc(str, 'assertMultiLineEqual')
    4753
    4854    def _formatMessage(self, msg, standardMsg):
     
    129135        # but we have zero chance of infuencing another test class
    130136        # since we use class-specific name for temporary region
     137
     138    def assertMultiLineEqual(self, first, second, msg=None):
     139        r"""Test that the multiline string first is equal to the string second.
     140
     141        When not equal a diff of the two strings highlighting the differences
     142        will be included in the error message. This method is used by default
     143        when comparing strings with assertEqual().
     144
     145        This method replaces ``\r\n`` by ``\n`` in both parameters. This is
     146        different from the same method implemented in Python ``unittest``
     147        package which preserves the original line endings. This removes the
     148        burden of getting the line endings right on each platfrom. You can
     149        just use ``\n`` everywhere. However, note that ``\r`` is not supported.
     150
     151        .. warning::
     152            If you need to test the actual line endings, use the standard
     153            string comparison and functions such as ``find()``.
     154        """
     155        return super(TestCase, self).assertMultiLineEqual(
     156            first=first.replace('\r\n', '\n'),
     157            second=second.replace('\r\n', '\n'),
     158            msg=None)
    131159
    132160    def assertLooksLike(self, actual, reference, msg=None):
     
    549577            self.fail(self._formatMessage(msg, stdmsg))
    550578
     579    def _get_unique_name(self, name):
     580        """Create standardized map or file name which is unique
     581
     582        If ``readable_names`` attribute is `True`, it uses the *name* string
     583        to create the unique name. Otherwise, it creates a unique name.
     584        Even if you expect ``readable_names`` to be `True`, provide *name*
     585        which is unique
     586
     587        The *name* parameter should be valid raster name, vector name and file
     588        name and should be always provided.
     589        """
     590        # TODO: possible improvement is to require some descriptive name
     591        # and ensure uniqueness by add UUID
     592        if self.readable_names:
     593            return 'tmp_' + self.id().replace('.', '_') + '_' + name
     594        else:
     595            # UUID might be overkill (and expensive) but it's safe and simple
     596            # alternative is to create hash from the readable name
     597            return 'tmp_' + str(uuid.uuid4()).replace('-', '')
     598
    551599    def _compute_difference_raster(self, first, second, name_part):
    552600        """Compute difference of two rasters (first - second)
     
    561609        :returns: name of a new raster
    562610        """
    563         diff = ('tmp_' + self.id() + '_compute_difference_raster_'
    564                 + name_part + '_' + first + '_minus_' + second)
     611        diff = self._get_unique_name('compute_difference_raster_' + name_part
     612                                    + '_' + first + '_minus_' + second)
    565613        call_module('r.mapcalc',
    566614                    stdin='"{d}" = "{f}" - "{s}"'.format(d=diff,
     
    583631        :returns: name of a new raster
    584632        """
    585         diff = ('tmp_' + self.id() + '_compute_difference_raster_'
    586                 + name_part + '_' + first + '_minus_' + second)
     633        diff = self._get_unique_name('compute_difference_raster_' + name_part
     634                                     + '_' + first + '_minus_' + second)
     635
    587636        call_module('r3.mapcalc',
    588637                    stdin='"{d}" = "{f}" - "{s}"'.format(d=diff,
     
    596645        :returns: name of a new vector
    597646        """
    598         diff = ('tmp_' + self.id() + '_compute_difference_vector_'
    599                 + name_part + '_' + ainput + '_' + alayer
    600                 + '_minus_' + binput + '_' + blayer)
     647        diff = self._get_unique_name('compute_difference_vector_' + name_part
     648                                     + '_' + ainput + '_' + alayer + '_minus_'
     649                                    + binput + '_' + blayer)
    601650        call_module('v.overlay', operator='xor', ainput=ainput, binput=binput,
    602651                    alayer=alayer, blayer=blayer,
     
    613662        :returns: name of a new vector
    614663        """
    615         import hashlib
    616664        # hash is the easiest way how to get a valied vector name
    617665        # TODO: introduce some function which will make file valid
     
    619667        hasher.update(filename)
    620668        namehash = hasher.hexdigest()
    621         vector = ('tmp_' + self.id().replace('.', '_')
    622                   + '_import_ascii_vector_'
    623                   + name_part + '_' + namehash)
     669        vector = self._get_unique_name('import_ascii_vector_' + name_part
     670                                       + '_' + namehash)
    624671        call_module('v.in.ascii', input=filename,
    625672                    output=vector, format='standard')
     
    633680        """
    634681        # TODO: perhaps we can afford just simple file name
    635         filename = ('tmp_' + self.id() + '_export_ascii_vector_'
    636                     + name_part + '_' + vector)
     682        filename = self._get_unique_name('export_ascii_vector_'
     683                                         + name_part + '_' + vector)
    637684        call_module('v.out.ascii', input=vector,
    638                     output=filename, format='standard', layer='-1', dp=digits)
     685                    output=filename, format='standard', layer='-1',
     686                    precision=digits)
    639687        return filename
    640688
  • grass/trunk/lib/python/gunittest/main.py

    r62358 r64662  
    152152                         " does not exist\n" % gisdbase)
    153153        sys.exit(1)
     154    if not os.path.exists(os.path.join(gisdbase, location)):
     155        sys.stderr.write("GRASS Location <{loc}>"
     156                         " does not exist in GRASS Database <{db}>\n".format(
     157                             location, gisdbase))
     158        sys.exit(1)
    154159    results_dir = args.output
    155160    silent_rmtree(results_dir)  # TODO: too brute force?
  • grass/trunk/lib/python/gunittest/testsuite/test_assertions.py

    r64637 r64662  
    4444                          "abc = 689.159589",
    4545                          "abc = 689....")
     46
     47    def do_all_combidnations(self, first, second):
     48        self.assertMultiLineEqual(first, first)
     49        self.assertMultiLineEqual(first, second)
     50        self.assertMultiLineEqual(second, first)
     51        self.assertMultiLineEqual(second, second)
     52
     53    def test_assertMultiLineEqual(self):
     54        unix_end = "aaa\nbbb\n"
     55        mswindows_end = "aaa\r\nbbb\r\n"
     56        self.do_all_combidnations(unix_end, mswindows_end)
     57
     58    def test_assertMultiLineEqual_raises(self):
     59        """Test mixed line endings"""
     60        self.assertRaises(self.failureException,
     61                          self.assertMultiLineEqual,
     62                          "aaa\n\rbbb\r",
     63                          "aaa\nbbb\n")
     64
     65    def test_assertEqual(self):
     66        """Test for strings (uses overwritten assertMultiLineEqual())"""
     67        unix_end = "aaa\nbbb\n"
     68        mswindows_end = "aaa\r\nbbb\r\n"
     69        self.do_all_combidnations(unix_end, mswindows_end)
     70
     71        self.assertRaises(self.failureException,
     72                          self.assertEqual,
     73                          "aaa\n\rbbb\r",
     74                          "aaa\nbbb\n")
    4675
    4776
Note: See TracChangeset for help on using the changeset viewer.