Changeset 64734


Ignore:
Timestamp:
Feb 24, 2015, 8:49:29 PM (9 years ago)
Author:
wenzeslaus
Message:

gunittest: support text files for MD5 sum comparisons in multiplatform way

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

Legend:

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

    r62358 r64734  
    1212by Vaclav Petras as a student and Soeren Gebbert as a mentor.
    1313"""
     14
     15# TODO: consider removing all from here before the backport or release
    1416
    1517from __future__ import print_function
  • grass/trunk/lib/python/gunittest/case.py

    r64683 r64734  
    2323from .checkers import (check_text_ellipsis,
    2424                       text_to_keyvalue, keyvalue_equals, diff_keyvalue,
    25                        file_md5, files_equal_md5)
     25                       file_md5, text_file_md5, files_equal_md5)
    2626from .utils import safe_repr
    2727from .gutils import is_map_in_mapset
     
    3636    Always use keyword arguments for all parameters other than first two. For
    3737    the first two, it is recommended to use keyword arguments but not required.
     38    Be especially careful and always use keyword argument syntax for *msg*
     39    parameter.
    3840    """
    3941    longMessage = True  # to get both standard and custom message
     
    544546            self.fail(self._formatMessage(msg, stdmsg))
    545547
    546     def assertFileMd5(self, filename, md5, msg=None):
    547         """Test that file MD5 sum is equal to the provided sum.
     548    def assertFileMd5(self, filename, md5, text=False, msg=None):
     549        r"""Test that file MD5 sum is equal to the provided sum.
     550
     551        Usually, this function is used to test binary files or large text files
     552        which cannot be tested in some other way. Text files can be usually
     553        tested by some finer method.
     554
     555        To test text files with this function, you should always use parameter
     556        *text* set to ``True``. Note that function ``checkers.text_file_md5()``
     557        offers additional parameters which might be advantageous when testing
     558        text files.
    548559
    549560        The typical workflow is that you create a file in a way you
     
    551562        sum of the file. And provide the sum in a test as a string::
    552563
    553             self.assertFileMd5('result.txt', md5='807bba4ffa...')
     564            self.assertFileMd5('result.png', md5='807bba4ffa...')
    554565
    555566        Use `file_md5()` function from this package::
    556567
    557             file_md5('original_result.txt')
     568            file_md5('original_result.png')
    558569
    559570        Or in command line, use ``md5sum`` command if available:
     
    561572        .. code-block:: sh
    562573
    563             md5sum some_file.txt
     574            md5sum some_file.png
    564575
    565576        Finaly, you can use Python ``hashlib`` to obtain MD5::
     
    568579            hasher = hashlib.md5()
    569580            # expecting the file to fit into memory
    570             hasher.update(open('original_result.txt', 'rb').read())
     581            hasher.update(open('original_result.png', 'rb').read())
    571582            hasher.hexdigest()
     583
     584        .. note:
     585            For text files, always create MD5 sum using ``\n`` (LF)
     586            as newline characters for consistency. Also use newline
     587            at the end of file (as for example, Git or PEP8 requires).
    572588        """
    573589        self.assertFileExists(filename, msg=msg)
    574         actual = file_md5(filename)
     590        if text:
     591            actual = text_file_md5(filename)
     592        else:
     593            actual = file_md5(filename)
    575594        if not actual == md5:
    576595            standardMsg = ('File <{name}> does not have the right MD5 sum.\n'
  • grass/trunk/lib/python/gunittest/checkers.py

    r62358 r64734  
    1010"""
    1111
     12import os
    1213import sys
    1314import re
     
    571572
    572573
    573 def text_file_md5(filename, exclude_lines=None,
     574def text_file_md5(filename, exclude_lines=None, exclude_re=None,
    574575                  prepend_lines=None, append_lines=None):
    575576    """Get a MD5 (check) sum of a text file.
    576577
    577     Works in the same way as `file_md5()` function but allows to
    578     exclude lines from the file as well as prepend or append them.
    579 
    580     .. todo::
    581         Implement this function.
    582     """
    583     raise NotImplementedError("Implement, or use file_md5() function instead")
     578    Works in the same way as `file_md5()` function but ignores newlines
     579    characters and excludes lines from the file as well as prepend or
     580    append them if requested.
     581
     582    :param exclude_lines: list of strings to be excluded
     583        (newline characters should not be part of the strings)
     584    :param exclude_re: regular expression string;
     585        lines matching this regular expression will not be considered
     586    :param prepend_lines: list of lines to be prepended to the file
     587        before computing the sum
     588    :param append_lines: list of lines  to be appended to the file
     589        before computing the sum
     590    """
     591    hasher = hashlib.md5()
     592    if exclude_re:
     593        regexp = re.compile(exclude_re)
     594    if prepend_lines:
     595        for line in prepend_lines:
     596            hasher.update(line)
     597    with open(filename, 'r') as f:
     598        for line in f:
     599            # replace platform newlines by standard newline
     600            if os.linesep != '\n':
     601                line = line.rstrip(os.linesep) + '\n'
     602            if exclude_lines and line in exclude_lines:
     603                continue
     604            if exclude_re and regexp.match(line):
     605                continue
     606            hasher.update(line)
     607    if append_lines:
     608        for line in append_lines:
     609            hasher.update(line)
     610    return hasher.hexdigest()
    584611
    585612
  • grass/trunk/lib/python/gunittest/testsuite/test_checkers.py

    r61887 r64734  
    1515
    1616
    17 from grass.script.utils import parse_key_val
     17from grass.script.utils import parse_key_val, try_remove
    1818
    1919import grass.gunittest
    20 from grass.gunittest.checkers import (values_equal, text_to_keyvalue,
    21     keyvalue_equals, proj_info_equals, proj_units_equals)
     20from grass.gunittest.checkers import (
     21    values_equal, text_to_keyvalue,
     22    keyvalue_equals, proj_info_equals, proj_units_equals,
     23    file_md5, text_file_md5)
     24
    2225
    2326
     
    309312                                         precision=0.001))
    310313
     314CORRECT_LINES = [
     315    "null_cells=57995100",
     316    "cells=60020100",
     317    "min=55.5787925720215",
     318    "max=156.329864501953"
     319]
     320
     321INCORRECT_LINES = [
     322    "null_cells=579951",
     323    "cells=60020100",
     324    "min=5.5787925720215",
     325    "max=156.329864501953"
     326]
     327
     328
     329class TestMd5Sums(grass.gunittest.TestCase):
     330    r"""
     331
     332    To create MD5 which is used for testing use:
     333
     334    .. code: sh
     335    $ cat > test.txt << EOF
     336    null_cells=57995100
     337    cells=60020100
     338    min=55.5787925720215
     339    max=156.329864501953
     340    EOF
     341    $ md5sum test.txt
     342    9dd6c4bb9d2cf6051b12f4b5f9d70523  test.txt
     343    """
     344
     345    correct_md5sum = '9dd6c4bb9d2cf6051b12f4b5f9d70523'
     346    correct_file_name_platform_nl = 'md5_sum_correct_file_platform_nl'
     347    correct_file_name_unix_nl = 'md5_sum_correct_file_unix_nl'
     348    wrong_file_name = 'md5_sum_wrong_file'
     349
     350    @classmethod
     351    def setUpClass(cls):
     352        with open(cls.correct_file_name_platform_nl, 'w') as f:
     353            for line in CORRECT_LINES:
     354                # \n should be converted to platform newline
     355                f.write(line + '\n')
     356        with open(cls.correct_file_name_unix_nl, 'wb') as f:
     357            for line in CORRECT_LINES:
     358                # binary mode will write pure \n
     359                f.write(line + '\n')
     360        with open(cls.wrong_file_name, 'w') as f:
     361            for line in INCORRECT_LINES:
     362                # \n should be converted to platform newline
     363                f.write(line + '\n')
     364
     365    @classmethod
     366    def tearDownClass(cls):
     367        try_remove(cls.correct_file_name_platform_nl)
     368        try_remove(cls.correct_file_name_unix_nl)
     369        try_remove(cls.wrong_file_name)
     370
     371    def test_text_file_binary(self):
     372        r"""File with ``\n`` (LF) newlines as binary (MD5 has ``\n``)."""
     373        self.assertEquals(file_md5(self.correct_file_name_unix_nl),
     374                          self.correct_md5sum,
     375                          msg="MD5 sums different")
     376
     377    def test_text_file_platfrom(self):
     378        r"""Text file with platform dependent newlines"""
     379        self.assertEquals(text_file_md5(self.correct_file_name_platform_nl),
     380                          self.correct_md5sum,
     381                          msg="MD5 sums different")
     382
     383    def test_text_file_unix(self):
     384        r"""Text file with ``\n`` (LF) newlines"""
     385        self.assertEquals(text_file_md5(self.correct_file_name_unix_nl),
     386                          self.correct_md5sum,
     387                          msg="MD5 sums different")
     388
     389    def test_text_file_different(self):
     390        r"""Text file with ``\n`` (LF) newlines"""
     391        self.assertNotEquals(text_file_md5(self.wrong_file_name),
     392                             self.correct_md5sum,
     393                             msg="MD5 sums must be different")
     394
    311395
    312396if __name__ == '__main__':
Note: See TracChangeset for help on using the changeset viewer.