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

Re: [PATCH] v7 #3460

From: Stefan Sperling <stsp_at_elego.de>
Date: Thu, 28 Jan 2010 22:35:50 +0100

On Thu, Jan 28, 2010 at 07:28:59PM +0100, Stefan Sperling wrote:
> On Thu, Jan 28, 2010 at 07:18:15PM +0100, Daniel Näslund wrote:
> > On Thu, Jan 28, 2010 at 06:29:41PM +0100, Stefan Sperling wrote:
> > > We could rename it to emit_hunk(), flush_hunk(), hunk_done(), or something
> > > similar, signifying that the function is responsible for dealing with
> > > a hunk which has been processed.
> > >
> > > The function itself can figure out what to do with the hunk, based on
> > > information in the hunk_info_t, rather than having the caller figure it out.
> >
> >
> > Fixed, but with doubts. Passing only hi instead of (hi, n, fuzz) was
> > fine but only passing target made it harder to understand why the caller
> > calls copy_hunk(). But I've done it so I couldn't have been totally
> > against it.
>
> Yes, copy_hunk() is a bad name now that this function does so much
> mroe than just copying. Hence my suggestion to rename the function
> to something more general.
>
> But that's a trivial change I can make, too. You don't need to post
> another revision of this diff. I think it is very good now, thanks! :)

Well... looking at this in detail made me realise that my idea
to do all of this in a single function was pretty stupid. Sorry :(

Still, I think we can make the code cleaner by splitting the old
copy_hunk_lines() interface into two distinct reject_hunk() and
apply_hunk() interfaces. Both copy lines from some hunk text to some
target stream, but do so in very different ways and I think a little
code duplication is justified and even increases readability of the code.

What do you think of the diff below, based on yours?
I've updated the log message, too. Patch tests pass.

Stefan

[[[
Fix #3460 - svn patch is not fuzzy when applying unidiffs.

* subversion/include/private/svn_diff_private.h
  (svn_hunk_t): Add fields leading_context and trailing_context. They are
    used for determining if there is enough context to apply a patch
    with fuzz.

* subversion/libsvn_client/patch.c
  (hunk_info_t): Add field FUZZ.
  (match_hunk): Add new parameter FUZZ, specifying how many lines
   at the beginning and end of the hunk will always match.
   Ignore FUZZ if there isn't enough context to do fuzzy matching.
  (scan_for_match): Add new parameter FUZZ. Call match_hunk() with FUZZ.
  (get_hunk_info): Add new parameter FUZZ. Call scan_for_match() with
   FUZZ. Save FUZZ in HI for later use. Set HI->rejected to TRUE
   if no line can be found where the hunk applies.
  (copy_hunk_text): Remove. This interface cannot cope well enough
   with hunks applied with fuzz.
  (reject_hunk): Re-implement parts of copy_hunk_text() inline,
   copying lines from the hunk to the target's reject stream.
  (apply_one_hunk): Rename to ...
  (apply_hunk): ... this, because it is the brother in-law of reject_hunk().
   Re-implement parts of copy_hunk_text inline, copying hunk's modified
   text to the patched result. Except lines which matched with fuzz, because
   those must be copied verbatim from the target to retain the local changes
   which made fuzzy matching necessary.
  (apply_one_patch): Call get_hunk_info() repeatedly with increasing
   fuzz factor until either the hunk matches or the maximum fuzz
   factor is reached. Track renaming and removal of functions.

* subversion/libsvn_diff/parse-diff.c
  (parse_next_hunk): Count number of lines of context at start and end
   of hunk and save the information in hunk. Refactored some if
   statements for increased readability.

* subversion/tests/cmdline/patch_tests.py
  (patch_with_fuzz): New.
  (test_list): Add new test.

Patch by: Daniel Näslund <daniel{_AT_}longitudo.com>
          me
Review by: julianfoad (older version)
]]]

Index: subversion/include/private/svn_diff_private.h
===================================================================
--- subversion/include/private/svn_diff_private.h (revision 904168)
+++ subversion/include/private/svn_diff_private.h (working copy)
@@ -81,6 +81,12 @@ typedef struct svn_hunk_t {
   svn_linenum_t original_length;
   svn_linenum_t modified_start;
   svn_linenum_t modified_length;
+
+ /* Number of lines starting with ' ' before first '+' or '-'. */
+ svn_linenum_t leading_context;
+
+ /* Number of lines starting with ' ' after last '+' or '-'. */
+ svn_linenum_t trailing_context;
 } svn_hunk_t;
 
 /* Data type to manage parsing of patches. */
Index: subversion/libsvn_client/patch.c
===================================================================
--- subversion/libsvn_client/patch.c (revision 904186)
+++ subversion/libsvn_client/patch.c (working copy)
@@ -52,6 +52,10 @@ typedef struct {
 
   /* Whether this hunk has been rejected. */
   svn_boolean_t rejected;
+
+ /* The fuzz factor used when matching this hunk, i.e. how many
+ * lines of leading and trailing context to ignore during matching. */
+ int fuzz;
 } hunk_info_t;
 
 typedef struct {
@@ -587,18 +591,19 @@ seek_to_line(patch_target_t *target, svn_linenum_t
   return SVN_NO_ERROR;
 }
 
-/* Indicate in *MATCHED whether the original text of HUNK
- * matches the patch TARGET at its current line.
- * When this function returns, neither TARGET->CURRENT_LINE nor the
- * file offset in the target file will have changed.
- * HUNK->ORIGINAL_TEXT will be reset.
- * Do temporary allocations in POOL. */
+/* Indicate in *MATCHED whether the original text of HUNK matches the patch
+ * TARGET at its current line. Lines within FUZZ lines of the start or end
+ * of HUNK will always match. When this function returns, neither
+ * TARGET->CURRENT_LINE nor the file offset in the target file will have
+ * changed. HUNK->ORIGINAL_TEXT will be reset. Do temporary allocations in
+ * POOL. */
 static svn_error_t *
 match_hunk(svn_boolean_t *matched, patch_target_t *target,
- const svn_hunk_t *hunk, apr_pool_t *pool)
+ const svn_hunk_t *hunk, int fuzz, apr_pool_t *pool)
 {
   svn_stringbuf_t *hunk_line;
   const char *target_line;
+ svn_linenum_t lines_read;
   svn_linenum_t saved_line;
   svn_boolean_t hunk_eof;
   svn_boolean_t lines_matched;
@@ -610,6 +615,7 @@ match_hunk(svn_boolean_t *matched, patch_target_t
     return SVN_NO_ERROR;
 
   saved_line = target->current_line;
+ lines_read = 0;
   lines_matched = FALSE;
   SVN_ERR(svn_stream_reset(hunk->original_text));
   iterpool = svn_pool_create(pool);
@@ -629,9 +635,18 @@ match_hunk(svn_boolean_t *matched, patch_target_t
                                            eol_str, FALSE,
                                            target->keywords, FALSE,
                                            iterpool));
+ lines_read++;
       SVN_ERR(read_line(target, &target_line, iterpool, iterpool));
       if (! hunk_eof)
- lines_matched = ! strcmp(hunk_line_translated, target_line);
+ {
+ if (lines_read <= fuzz && hunk->leading_context > fuzz)
+ lines_matched = TRUE;
+ else if (lines_read > hunk->original_length - fuzz &&
+ hunk->trailing_context > fuzz)
+ lines_matched = TRUE;
+ else
+ lines_matched = ! strcmp(hunk_line_translated, target_line);
+ }
     }
   while (lines_matched && ! (hunk_eof || target->eof));
 
@@ -657,7 +672,7 @@ match_hunk(svn_boolean_t *matched, patch_target_t
 }
 
 /* Scan lines of TARGET for a match of the original text of HUNK,
- * up to but not including the specified UPPER_LINE.
+ * up to but not including the specified UPPER_LINE. Use fuzz factor FUZZ.
  * If UPPER_LINE is zero scan until EOF occurs when reading from TARGET.
  * Return the line at which HUNK was matched in *MATCHED_LINE.
  * If the hunk did not match at all, set *MATCHED_LINE to zero.
@@ -669,7 +684,7 @@ match_hunk(svn_boolean_t *matched, patch_target_t
 static svn_error_t *
 scan_for_match(svn_linenum_t *matched_line, patch_target_t *target,
                const svn_hunk_t *hunk, svn_boolean_t match_first,
- svn_linenum_t upper_line, apr_pool_t *pool)
+ svn_linenum_t upper_line, int fuzz, apr_pool_t *pool)
 {
   apr_pool_t *iterpool;
 
@@ -683,7 +698,7 @@ scan_for_match(svn_linenum_t *matched_line, patch_
 
       svn_pool_clear(iterpool);
 
- SVN_ERR(match_hunk(&matched, target, hunk, iterpool));
+ SVN_ERR(match_hunk(&matched, target, hunk, fuzz, iterpool));
       if (matched)
         {
           svn_boolean_t taken = FALSE;
@@ -719,14 +734,14 @@ scan_for_match(svn_linenum_t *matched_line, patch_
 
 /* Determine the line at which a HUNK applies to the TARGET file,
  * and return an appropriate hunk_info object in *HI, allocated from
- * RESULT_POOL. If no correct line can be determined,
- * set HI->MATCHED_LINE to zero.
- * When this function returns, neither TARGET->CURRENT_LINE nor the
- * file offset in the target file will have changed.
+ * RESULT_POOL. Use fuzz factor FUZZ. Set HI->FUZZ to FUZZ. If no correct
+ * line can be determined, set HI->REJECTED to TRUE.
+ * When this function returns, neither TARGET->CURRENT_LINE nor the file
+ * offset in the target file will have changed.
  * Do temporary allocations in POOL. */
 static svn_error_t *
 get_hunk_info(hunk_info_t **hi, patch_target_t *target,
- const svn_hunk_t *hunk, apr_pool_t *result_pool,
+ const svn_hunk_t *hunk, int fuzz, apr_pool_t *result_pool,
               apr_pool_t *scratch_pool)
 {
   svn_linenum_t matched_line;
@@ -745,7 +760,7 @@ get_hunk_info(hunk_info_t **hi, patch_target_t *ta
        * should be going. */
       SVN_ERR(seek_to_line(target, hunk->original_start, scratch_pool));
       SVN_ERR(scan_for_match(&matched_line, target, hunk, TRUE,
- hunk->original_start + 1, scratch_pool));
+ hunk->original_start + 1, fuzz, scratch_pool));
       if (matched_line != hunk->original_start)
         {
           /* Scan the whole file again from the start. */
@@ -754,7 +769,7 @@ get_hunk_info(hunk_info_t **hi, patch_target_t *ta
           /* Scan forward towards the hunk's line and look for a line
            * where the hunk matches. */
           SVN_ERR(scan_for_match(&matched_line, target, hunk, FALSE,
- hunk->original_start, scratch_pool));
+ hunk->original_start, fuzz, scratch_pool));
 
           /* In tie-break situations, we arbitrarily prefer early matches
            * to save us from scanning the rest of the file. */
@@ -763,7 +778,7 @@ get_hunk_info(hunk_info_t **hi, patch_target_t *ta
               /* Scan forward towards the end of the file and look
                * for a line where the hunk matches. */
               SVN_ERR(scan_for_match(&matched_line, target, hunk, TRUE, 0,
- scratch_pool));
+ fuzz, scratch_pool));
             }
         }
 
@@ -774,7 +789,8 @@ get_hunk_info(hunk_info_t **hi, patch_target_t *ta
   (*hi) = apr_palloc(result_pool, sizeof(hunk_info_t));
   (*hi)->hunk = hunk;
   (*hi)->matched_line = matched_line;
- (*hi)->rejected = FALSE;
+ (*hi)->rejected = (matched_line == 0);
+ (*hi)->fuzz = fuzz;
 
   return SVN_NO_ERROR;
 }
@@ -827,97 +843,110 @@ copy_lines_to_target(patch_target_t *target, svn_l
   return SVN_NO_ERROR;
 }
 
-/* Copy HUNK_TEXT into TARGET, line by line, such that the line filter
- * and transformation callbacks set on HUNK_TEXT by the diff parsing
- * code in libsvn_diff will trigger. ABSPATH is the absolute path to the
- * file underlying TARGET. */
+/* Write the diff text of the hunk described by HI to the
+ * reject stream of TARGET, and mark TARGET as having had rejects.
+ * Do temporary allocations in POOL. */
 static svn_error_t *
-copy_hunk_text(svn_stream_t *hunk_text, svn_stream_t *target,
- const char *abspath, apr_pool_t *scratch_pool)
+reject_hunk(patch_target_t *target, hunk_info_t *hi, apr_pool_t *pool)
 {
+ const char *hunk_header;
+ apr_size_t len;
   svn_boolean_t eof;
   apr_pool_t *iterpool;
 
- iterpool = svn_pool_create(scratch_pool);
+ hunk_header = apr_psprintf(pool, "@@ -%lu,%lu +%lu,%lu @@%s",
+ hi->hunk->original_start,
+ hi->hunk->original_length,
+ hi->hunk->modified_start,
+ hi->hunk->modified_length,
+ target->eol_str);
+ len = strlen(hunk_header);
+ SVN_ERR(svn_stream_write(target->reject, hunk_header, &len));
+
+ iterpool = svn_pool_create(pool);
   do
     {
- svn_stringbuf_t *line;
+ svn_stringbuf_t *hunk_line;
       const char *eol_str;
 
       svn_pool_clear(iterpool);
 
- SVN_ERR(svn_stream_readline_detect_eol(hunk_text, &line, &eol_str,
- &eof, iterpool));
+ SVN_ERR(svn_stream_readline_detect_eol(hi->hunk->diff_text, &hunk_line,
+ &eol_str, &eof, iterpool));
       if (! eof)
         {
- if (line->len >= 1)
- SVN_ERR(try_stream_write(target, abspath, line->data, line->len,
+ if (hunk_line->len >= 1)
+ SVN_ERR(try_stream_write(target->reject, target->reject_path,
+ hunk_line->data, hunk_line->len,
                                      iterpool));
           if (eol_str)
- SVN_ERR(try_stream_write(target, abspath, eol_str, strlen(eol_str),
- iterpool));
+ SVN_ERR(try_stream_write(target->reject, target->reject_path,
+ eol_str, strlen(eol_str), iterpool));
         }
     }
   while (! eof);
   svn_pool_destroy(iterpool);
 
- return SVN_NO_ERROR;
-}
-
-
-/* Write a hunk described by hunk info HI to the reject stream of TARGET,
- * mark the hunk as rejected, and mark TARGET as having had rejects.
- * Do all allocations in POOL. */
-static svn_error_t *
-reject_hunk(patch_target_t *target, hunk_info_t *hi, apr_pool_t *pool)
-{
- const char *hunk_header;
- apr_size_t len;
-
- hunk_header = apr_psprintf(pool, "@@ -%lu,%lu +%lu,%lu @@%s",
- hi->hunk->original_start,
- hi->hunk->original_length,
- hi->hunk->modified_start,
- hi->hunk->modified_length,
- target->eol_str);
- len = strlen(hunk_header);
- SVN_ERR(svn_stream_write(target->reject, hunk_header, &len));
-
- SVN_ERR(copy_hunk_text(hi->hunk->diff_text, target->reject,
- target->reject_path, pool));
-
   target->had_rejects = TRUE;
- hi->rejected = TRUE;
 
   return SVN_NO_ERROR;
 }
 
-/* Apply a hunk described by hunk info HI to a patch TARGET.
- * Do all allocations in POOL. */
+/* Write the modified text of hunk described by HI to the patched
+ * stream of TARGET. Do temporary allocations in POOL. */
 static svn_error_t *
-apply_one_hunk(patch_target_t *target, hunk_info_t *hi, apr_pool_t *pool)
+apply_hunk(patch_target_t *target, hunk_info_t *hi, apr_pool_t *pool)
 {
+ svn_linenum_t lines_read;
+ svn_boolean_t eof;
+ apr_pool_t *iterpool;
+
   if (target->kind == svn_node_file)
     {
- /* Move forward to the hunk's line, copying data as we go. */
- SVN_ERR(copy_lines_to_target(target, hi->matched_line, pool));
- if (target->eof)
- {
- /* File is shorter than it should be. */
- SVN_ERR(reject_hunk(target, hi, pool));
- return SVN_NO_ERROR;
- }
+ /* Move forward to the hunk's line, copying data as we go.
+ * Also write leading lines of context which matched with fuzz.
+ * The target has changed on the fuzzy-matched lines,
+ * so we should retain the target's version of those lines. */
+ SVN_ERR(copy_lines_to_target(target, hi->matched_line + hi->fuzz,
+ pool));
 
       /* Skip the target's version of the hunk. */
- SVN_ERR(seek_to_line(target,
- target->current_line + hi->hunk->original_length,
+ SVN_ERR(seek_to_line(target, target->current_line +
+ hi->hunk->original_length - (2 * hi->fuzz),
                            pool));
     }
 
- /* Copy the patched hunk text into the patched stream. */
- SVN_ERR(copy_hunk_text(hi->hunk->modified_text, target->patched,
- target->patched_path, pool));
+ /* Write the hunk's version to the patched result.
+ * Don't write the lines which matched with fuzz. */
+ lines_read = 0;
+ iterpool = svn_pool_create(pool);
+ do
+ {
+ svn_stringbuf_t *hunk_line;
+ const char *eol_str;
 
+ svn_pool_clear(iterpool);
+
+ /* Read a line from the hunk. */
+ SVN_ERR(svn_stream_readline_detect_eol(hi->hunk->modified_text,
+ &hunk_line, &eol_str,
+ &eof, iterpool));
+ lines_read++;
+ if (! eof && lines_read > hi->fuzz &&
+ lines_read <= hi->hunk->modified_length - hi->fuzz)
+ {
+ if (hunk_line->len >= 1)
+ SVN_ERR(try_stream_write(target->patched, target->patched_path,
+ hunk_line->data, hunk_line->len,
+ iterpool));
+ if (eol_str)
+ SVN_ERR(try_stream_write(target->patched, target->patched_path,
+ eol_str, strlen(eol_str), iterpool));
+ }
+ }
+ while (! eof);
+ svn_pool_destroy(iterpool);
+
   return SVN_NO_ERROR;
 }
 
@@ -1023,6 +1052,7 @@ apply_one_patch(svn_patch_t *patch, const char *ab
   apr_finfo_t working_file;
   apr_finfo_t patched_file;
   int i;
+ static const int MAX_FUZZ = 2;
 
   SVN_ERR(init_patch_target(&target, patch, abs_wc_path, ctx, strip_count,
                             pool, pool));
@@ -1041,22 +1071,25 @@ apply_one_patch(svn_patch_t *patch, const char *ab
     {
       svn_hunk_t *hunk;
       hunk_info_t *hi;
+ int fuzz = 0;
 
       svn_pool_clear(iterpool);
 
       hunk = APR_ARRAY_IDX(patch->hunks, i, svn_hunk_t *);
 
- /* Determine the line the hunk should be applied at. */
- SVN_ERR(get_hunk_info(&hi, target, hunk, pool, iterpool));
- if (hi->matched_line == 0)
+ /* Determine the line the hunk should be applied at.
+ * If no match is found initially, try with fuzz. */
+ do
         {
- /* The hunk does not apply, reject it. */
- SVN_ERR(reject_hunk(target, hi, iterpool));
+ SVN_ERR(get_hunk_info(&hi, target, hunk, fuzz, pool, iterpool));
+ fuzz++;
         }
+ while (hi->rejected && fuzz <= MAX_FUZZ);
+
       APR_ARRAY_PUSH(target->hunks, hunk_info_t *) = hi;
     }
 
- /* Apply hunks. */
+ /* Apply or reject hunks. */
   for (i = 0; i < target->hunks->nelts; i++)
     {
       hunk_info_t *hi;
@@ -1064,8 +1097,10 @@ apply_one_patch(svn_patch_t *patch, const char *ab
       svn_pool_clear(iterpool);
 
       hi = APR_ARRAY_IDX(target->hunks, i, hunk_info_t *);
- if (! hi->rejected)
- SVN_ERR(apply_one_hunk(target, hi, iterpool));
+ if (hi->rejected)
+ SVN_ERR(reject_hunk(target, hi, iterpool));
+ else
+ SVN_ERR(apply_hunk(target, hi, iterpool));
     }
   svn_pool_destroy(iterpool);
 
Index: subversion/libsvn_diff/parse-diff.c
===================================================================
--- subversion/libsvn_diff/parse-diff.c (revision 904168)
+++ subversion/libsvn_diff/parse-diff.c (working copy)
@@ -224,6 +224,9 @@ parse_next_hunk(svn_hunk_t **hunk,
   svn_stream_t *original_text;
   svn_stream_t *modified_text;
   svn_linenum_t original_lines;
+ svn_linenum_t leading_context;
+ svn_linenum_t trailing_context;
+ svn_boolean_t changed_line_seen;
   apr_pool_t *iterpool;
 
   if (apr_file_eof(patch->patch_file) == APR_EOF)
@@ -235,6 +238,9 @@ parse_next_hunk(svn_hunk_t **hunk,
 
   in_hunk = FALSE;
   hunk_seen = FALSE;
+ leading_context = 0;
+ trailing_context = 0;
+ changed_line_seen = FALSE;
   *hunk = apr_pcalloc(result_pool, sizeof(**hunk));
 
   /* Get current seek position -- APR has no ftell() :( */
@@ -278,21 +284,29 @@ parse_next_hunk(svn_hunk_t **hunk,
             }
 
           c = line->data[0];
- if (original_lines > 0 && (c == ' ' || c == '-'))
+ /* Tolerate chopped leading spaces on empty lines. */
+ if (original_lines > 0 && (c == ' ' || (! eof && line->len == 0)))
             {
               hunk_seen = TRUE;
               original_lines--;
+ if (changed_line_seen)
+ trailing_context++;
+ else
+ leading_context++;
             }
- else if (c == '+')
+ else if (c == '+' || c == '-')
             {
               hunk_seen = TRUE;
+ changed_line_seen = TRUE;
+
+ /* A hunk may have context in the middle. We only want the
+ last lines of context. */
+ if (trailing_context > 0)
+ trailing_context = 0;
+
+ if (original_lines > 0 && c == '-')
+ original_lines--;
             }
- /* Tolerate chopped leading spaces on empty lines. */
- else if (original_lines > 0 && ! eof && line->len == 0)
- {
- hunk_seen = TRUE;
- original_lines--;
- }
           else
             {
               in_hunk = FALSE;
@@ -363,6 +377,8 @@ parse_next_hunk(svn_hunk_t **hunk,
       (*hunk)->diff_text = diff_text;
       (*hunk)->original_text = original_text;
       (*hunk)->modified_text = modified_text;
+ (*hunk)->leading_context = leading_context;
+ (*hunk)->trailing_context = trailing_context;
     }
   else
     /* Something went wrong, just discard the result. */
Index: subversion/tests/cmdline/patch_tests.py
===================================================================
--- subversion/tests/cmdline/patch_tests.py (revision 904186)
+++ subversion/tests/cmdline/patch_tests.py (working copy)
@@ -967,7 +967,137 @@ def patch_reject(sbox):
                                        None, # expected err
                                        1, # check-props
                                        1) # dry-run
+def patch_with_fuzz(sbox):
+ "apply a patch with fuzz"
 
+ sbox.build()
+ wc_dir = sbox.wc_dir
+ patch_file_path = tempfile.mkstemp(dir=os.path.abspath(svntest.main.temp_dir))[1]
+
+ mu_path = os.path.join(wc_dir, 'A', 'mu')
+
+ # We have replaced a couple of lines to cause fuzz. Those lines contains
+ # the word fuzz
+ mu_contents = [
+ "Line replaced for fuzz = 1\n",
+ "\n",
+ "We wish to congratulate you over your email success in our computer\n",
+ "Balloting. This is a Millennium Scientific Electronic Computer Draw\n",
+ "in which email addresses were used. All participants were selected\n",
+ "through a computer ballot system drawn from over 100,000 company\n",
+ "and 50,000,000 individual email addresses from all over the world.\n",
+ "Line replaced for fuzz = 2 with only the second context line changed\n",
+ "Your email address drew and have won the sum of 750,000 Euros\n",
+ "( Seven Hundred and Fifty Thousand Euros) in cash credited to\n",
+ "file with\n",
+ " REFERENCE NUMBER: ESP/WIN/008/05/10/MA;\n",
+ " WINNING NUMBER : 14-17-24-34-37-45-16\n",
+ " BATCH NUMBERS :\n",
+ " EULO/1007/444/606/08;\n",
+ " SERIAL NUMBER: 45327\n",
+ "and PROMOTION DATE: 13th June. 2009\n",
+ "\n",
+ "To claim your winning prize, you are to contact the appointed\n",
+ "agent below as soon as possible for the immediate release of your\n",
+ "winnings with the below details.\n",
+ "\n",
+ "Line replaced for fuzz = 2\n",
+ "Line replaced for fuzz = 2\n",
+ ]
+
+ # Set mu contents
+ svntest.main.file_write(mu_path, ''.join(mu_contents))
+ expected_output = svntest.wc.State(wc_dir, {
+ 'A/mu' : Item(verb='Sending'),
+ })
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.tweak('A/mu', wc_rev=2)
+ svntest.actions.run_and_verify_commit(wc_dir, expected_output,
+ expected_status, None, wc_dir)
+
+ unidiff_patch = [
+ "Index: mu\n",
+ "===================================================================\n",
+ "--- A/mu\t(revision 0)\n",
+ "+++ A/mu\t(revision 0)\n",
+ "@@ -1,6 +1,7 @@\n",
+ " Dear internet user,\n",
+ " \n",
+ " We wish to congratulate you over your email success in our computer\n",
+ "+A new line here\n",
+ " Balloting. This is a Millennium Scientific Electronic Computer Draw\n",
+ " in which email addresses were used. All participants were selected\n",
+ " through a computer ballot system drawn from over 100,000 company\n",
+ "@@ -7,6 +8,7 @@\n",
+ " and 50,000,000 individual email addresses from all over the world.\n",
+ " \n",
+ " Your email address drew and have won the sum of 750,000 Euros\n",
+ "+Another new line\n",
+ " ( Seven Hundred and Fifty Thousand Euros) in cash credited to\n",
+ " file with\n",
+ " REFERENCE NUMBER: ESP/WIN/008/05/10/MA;\n",
+ "@@ -19,6 +20,7 @@\n",
+ " To claim your winning prize, you are to contact the appointed\n",
+ " agent below as soon as possible for the immediate release of your\n",
+ " winnings with the below details.\n",
+ "+A third new line\n",
+ " \n",
+ " Again, we wish to congratulate you over your email success in our\n"
+ " computer Balloting.\n"
+ ]
+
+ svntest.main.file_write(patch_file_path, ''.join(unidiff_patch))
+
+ mu_contents = [
+ "Line replaced for fuzz = 1\n",
+ "\n",
+ "We wish to congratulate you over your email success in our computer\n",
+ "A new line here\n",
+ "Balloting. This is a Millennium Scientific Electronic Computer Draw\n",
+ "in which email addresses were used. All participants were selected\n",
+ "through a computer ballot system drawn from over 100,000 company\n",
+ "and 50,000,000 individual email addresses from all over the world.\n",
+ "Line replaced for fuzz = 2 with only the second context line changed\n",
+ "Your email address drew and have won the sum of 750,000 Euros\n",
+ "Another new line\n",
+ "( Seven Hundred and Fifty Thousand Euros) in cash credited to\n",
+ "file with\n",
+ " REFERENCE NUMBER: ESP/WIN/008/05/10/MA;\n",
+ " WINNING NUMBER : 14-17-24-34-37-45-16\n",
+ " BATCH NUMBERS :\n",
+ " EULO/1007/444/606/08;\n",
+ " SERIAL NUMBER: 45327\n",
+ "and PROMOTION DATE: 13th June. 2009\n",
+ "\n",
+ "To claim your winning prize, you are to contact the appointed\n",
+ "agent below as soon as possible for the immediate release of your\n",
+ "winnings with the below details.\n",
+ "A third new line\n",
+ "\n",
+ "Line replaced for fuzz = 2\n",
+ "Line replaced for fuzz = 2\n",
+ ]
+
+ expected_output = [
+ 'U %s\n' % os.path.join(wc_dir, 'A', 'mu'),
+ ]
+ expected_disk = svntest.main.greek_state.copy()
+ expected_disk.tweak('A/mu', contents=''.join(mu_contents))
+
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.tweak('A/mu', status='M ', wc_rev=2)
+
+ expected_skip = wc.State('', { })
+
+ svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path),
+ expected_output,
+ expected_disk,
+ expected_status,
+ expected_skip,
+ None, # expected err
+ 1, # check-props
+ 1) # dry-run
+
 def patch_keywords(sbox):
   "apply a patch containing keywords"
 
@@ -1042,6 +1172,7 @@ test_list = [ None,
               patch_add_new_dir,
               patch_reject,
               patch_keywords,
+ patch_with_fuzz,
             ]
 
 if __name__ == '__main__':
Received on 2010-01-28 22:36:40 CET

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