[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: [PATCH] Infrastructure to exclude comparing lines

From: Daniel Shahaf <d.s_at_daniel.shahaf.name>
Date: Mon, 20 Sep 2010 04:55:57 +0100

Ramkumar Ramachandra wrote on Sun, Sep 19, 2010 at 17:53:12 +0530:
> Hi,
>
> I thought this patch might need a little bit of special attention. Let
> me know quickly if something is obviously wrong with it- as far as I
> know, all tests pass and this patch works as expected. I'm going ahead
> and adding lots of tests and fixing whatever bugs there may be shortly.
>
> [[[
> Add some testing infrastructure to exclude comparison of certain lines
> specified by a regular expression so that svnrdump dump tests can
> report actual failures. Exercise this infrastructure in
> svnrdump_tests.py. This is necessary because there is some mismatch
> between the headers that `svnadmin dump` and `svnrdump dump` are able
> to provide.
>
> * subversion/tests/cmdline/svntest/verify.py
>
> (ExpectedOutput.matches_except): Write new function that resembling
> ExpectedOutput.display_lines with an extra except_re argument. It
> compares EXPECTED and ACTUAL on an exact line-by-line basis,
> excluding lines that match the regular expression specified in
> except_re.
>
> (ExceptedOutput.matches): Modify function to accept one more
> optional argument: except_re. Call matches_except if except_re is
> not None.
>
> (compare_and_display_lines): Take an extra argument except_re that
> defaults to None, and call ExcpectedOutput.matches with this
> argument.
>
> * subversion/tests/cmdline/svnrdump_tests.py
>
> (mismatched_headers_re): Declare a new global string that specifies
> the headers in which a mismatch is expected during a dumping
> operation.
>
> (run_dump_test): Pass the above regular expression string to
> svntest.verify.compare_and_display_lines).
>
> (test_list): Mark copy_and_modify_dump as a passing test.
> ]]]
>
> Index: subversion/tests/cmdline/svnrdump_tests.py
> ===================================================================
> --- subversion/tests/cmdline/svnrdump_tests.py (revision 998490)
> +++ subversion/tests/cmdline/svnrdump_tests.py (working copy)
> @@ -41,6 +41,11 @@ XFail = svntest.testcase.XFail
> Item = svntest.wc.StateItem
> Wimp = svntest.testcase.Wimp
>
> +# Mismatched headers during dumping operation
> +mismatched_headers_re = \
> + "Prop-delta: |Text-content-sha1: |Text-copy-source-md5: |" \
> + "Text-copy-source-sha1: |Text-delta-base-sha1: .*"
> +

So:

* ignore sha1 because RA doesn't provide it yet
* ignore Text-copy-source-md5... why? for the same reason?
* ignore Prop-delta... why?

(It would be good to have the answer in a comment, I think.)

> ######################################################################
> # Helper routines
>
> @@ -80,7 +85,8 @@ def run_dump_test(sbox, dumpfile_name):
>
> # Compare the output from stdout
> svntest.verify.compare_and_display_lines(
> - "Dump files", "DUMP", svnadmin_dumpfile, svnrdump_dumpfile)
> + "Dump files", "DUMP", svnadmin_dumpfile, svnrdump_dumpfile,
> + None, mismatched_headers_re)
>
> def run_load_test(sbox, dumpfile_name):
> """Load a dumpfile using 'svnrdump load', dump it with 'svnadmin
> @@ -177,7 +183,7 @@ test_list = [ None,
> revision_0_load,
> skeleton_load,
> copy_and_modify_load,
> - Wimp("Need to fix headers in RA layer", copy_and_modify_dump),
> + copy_and_modify_dump,
> ]
>
> if __name__ == '__main__':
> Index: subversion/tests/cmdline/svntest/verify.py
> ===================================================================
> --- subversion/tests/cmdline/svntest/verify.py (revision 998490)
> +++ subversion/tests/cmdline/svntest/verify.py (working copy)
> @@ -108,7 +108,7 @@ class ExpectedOutput:
> def __cmp__(self, other):
> raise 'badness'
>
> - def matches(self, other):
> + def matches(self, other, except_re=None):
> """Return whether SELF.output matches OTHER (which may be a list
> of newline-terminated lines, or a single string). Either value
> may be None."""
> @@ -126,8 +126,32 @@ class ExpectedOutput:
> if not isinstance(expected, list):
> expected = [expected]
>
> - return self.is_equivalent_list(expected, actual)
> + if except_re:
> + return self.matches_except(expected, actual, except_re)
> + else:
> + return self.is_equivalent_list(expected, actual)
>

Couldn't you redefine one of these two functions (matches_except() and
is_equivalent_list()) such that they share more code?

For example:

    def matches_except(self, expected, actual, except_re):
        # TODO: possibly use a slightly different error message
        # if an exception is thrown
        return self.is_equivalent_list(
                      filter(lambda x: not re.match(except_re, x), expected),
                      filter(lambda x: not re.match(except_re, x), actual))

... or add some sort of optional argument to is_equivalent_list(), such
that the functionalities of both functions can be achieved by varying
the value of the optional argument.

In second thought: you could make except_re a lambda expression
(taking a single argument, the line) instead of a regex; i.e.,

    s/foo('Text-sha1:')/foo(lambda line: 'Text-sha1' not in line)/

?

> + def matches_except(self, expected, actual, except_re):
> + "Return whether EXPECTED and ACTUAL match except for except_re."
> + if not self.is_regex:
> + i_expected = 0
> + i_actual = 0
> + while i_expected < len(expected) and i_actual < len(actual):
> + if re.match(except_re, actual[i_actual]):
> + i_actual += 1
> + elif re.match(except_re, expected[i_expected]):
> + i_expected += 1
> + elif expected[i_expected] == actual[i_actual]:
> + i_expected += 1
> + i_actual += 1
> + else:
> + return False
> + if i_expected == len(expected) and i_actual == len(actual):
> + return True
> + return False
> + else:
> + raise "self.is_regex and except_re are mutually exclusive"
> +
> def is_equivalent_list(self, expected, actual):
> "Return whether EXPECTED and ACTUAL are equivalent."
> if not self.is_regex:
> @@ -308,7 +332,7 @@ def display_lines(message, label, expected, actual
> sys.stdout.write(x)
>
> def compare_and_display_lines(message, label, expected, actual,
> - raisable=None):
> + raisable=None, except_re=None):
> """Compare two sets of output lines, and print them if they differ,
> preceded by MESSAGE iff not None. EXPECTED may be an instance of
> ExpectedOutput (and if not, it is wrapped as such). RAISABLE is an
> @@ -325,7 +349,7 @@ def compare_and_display_lines(message, label, expe
> actual = [actual]
> actual = [line for line in actual if not line.startswith('DBG:')]
>
> - if not expected.matches(actual):
> + if not expected.matches(actual, except_re):
> expected.display_differences(message, label, actual)
> raise raisable
>
Received on 2010-09-20 05:57:17 CEST

This is an archived mail posted to the Subversion Dev mailing list.