source: valtobtest/subversion-1.6.2/subversion/tests/cmdline/diff_tests.py @ 3

Last change on this file since 3 was 3, checked in by valtob, 15 years ago

subversion source 1.6.2 as test

  • Property svn:executable set to *
File size: 107.0 KB
Line 
1#!/usr/bin/env python
2#
3#  diff_tests.py:  some basic diff tests
4#
5#  Subversion is a tool for revision control.
6#  See http://subversion.tigris.org for more information.
7#
8# ====================================================================
9# Copyright (c) 2000-2008 CollabNet.  All rights reserved.
10#
11# This software is licensed as described in the file COPYING, which
12# you should have received as part of this distribution.  The terms
13# are also available at http://subversion.tigris.org/license-1.html.
14# If newer versions of this license are posted there, you may use a
15# newer version instead, at your option.
16#
17######################################################################
18
19# General modules
20import sys, re, os, time
21
22# Our testing module
23import svntest
24
25# (abbreviation)
26Skip = svntest.testcase.Skip
27XFail = svntest.testcase.XFail
28Item = svntest.wc.StateItem
29
30
31######################################################################
32# Generate expected output
33
34def make_diff_header(path, old_tag, new_tag):
35  """Generate the expected diff header for file PATH, with its old and new
36  versions described in parentheses by OLD_TAG and NEW_TAG. Return the header
37  as an array of newline-terminated strings."""
38  path_as_shown = path.replace('\\', '/')
39  return [
40    "Index: " + path_as_shown + "\n",
41    "===================================================================\n",
42    "--- " + path_as_shown + "\t(" + old_tag + ")\n",
43    "+++ " + path_as_shown + "\t(" + new_tag + ")\n",
44    ]
45
46######################################################################
47# Diff output checker
48#
49# Looks for the correct filenames and a suitable number of +/- lines
50# depending on whether this is an addition, modification or deletion.
51
52def check_diff_output(diff_output, name, diff_type):
53  "check diff output"
54
55# On Windows, diffs still display / rather than \ in paths
56  if svntest.main.windows == 1:
57    name = name.replace('\\', '/')
58  i_re = re.compile('^Index:')
59  d_re = re.compile('^Index: (\\./)?' + name)
60  p_re = re.compile('^--- (\\./)?' + name)
61  add_re = re.compile('^\\+')
62  sub_re = re.compile('^-')
63
64  i = 0
65  while i < len(diff_output) - 4:
66
67    # identify a possible diff
68    if (d_re.match(diff_output[i])
69        and p_re.match(diff_output[i+2])):
70
71      # count lines added and deleted
72      i += 4
73      add_lines = 0
74      sub_lines = 0
75      while i < len(diff_output) and not i_re.match(diff_output[i]):
76        if add_re.match(diff_output[i][0]):
77          add_lines += 1
78        if sub_re.match(diff_output[i][0]):
79          sub_lines += 1
80        i += 1
81
82      #print "add:", add_lines
83      #print "sub:", sub_lines
84      # check if this looks like the right sort of diff
85      if add_lines > 0 and sub_lines == 0 and diff_type == 'A':
86        return 0
87      if sub_lines > 0 and add_lines == 0 and diff_type == 'D':
88        return 0
89      if add_lines > 0 and sub_lines > 0 and diff_type == 'M':
90        return 0
91
92    else:
93      i += 1
94
95  # no suitable diff found
96  return 1
97
98def count_diff_output(diff_output):
99  "count the number of file diffs in the output"
100
101  i_re = re.compile('Index:')
102  diff_count = 0
103  i = 0
104  while i < len(diff_output) - 4:
105    if i_re.match(diff_output[i]):
106      i += 4
107      diff_count += 1
108    else:
109      i += 1
110
111  return diff_count
112
113def verify_expected_output(diff_output, expected):
114  "verify given line exists in diff output"
115  for line in diff_output:
116    if line.find(expected) != -1:
117      break
118  else:
119    raise svntest.Failure
120
121def verify_excluded_output(diff_output, excluded):
122  "verify given line does not exist in diff output as diff line"
123  for line in diff_output:
124    if re.match("^(\\+|-)%s" % re.escape(excluded), line):
125      print('Sought: %s' % excluded)
126      print('Found:  %s' % line)
127      raise svntest.Failure
128
129def extract_diff_path(line):
130  l2 = line[(line.find("(")+1):]
131  l3 = l2[0:(l2.find(")"))]
132  return l3
133
134######################################################################
135# diff on a repository subset and check the output
136
137def diff_check_repo_subset(wc_dir, repo_subset, check_fn, do_diff_r):
138  "diff and check for part of the repository"
139
140  was_cwd = os.getcwd()
141  os.chdir(wc_dir)
142
143  exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff',
144                                                            repo_subset)
145  if check_fn(diff_output):
146    return 1
147
148  if do_diff_r:
149    exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff',
150                                                              '-r', 'HEAD',
151                                                              repo_subset)
152    if check_fn(diff_output):
153      return 1
154
155  os.chdir(was_cwd)
156
157  return 0
158
159######################################################################
160# Changes makers and change checkers
161
162def update_a_file():
163  "update a file"
164  svntest.main.file_write(os.path.join('A', 'B', 'E', 'alpha'), "new atext")
165  # svntest.main.file_append(, "new atext")
166  return 0
167
168def check_update_a_file(diff_output):
169  "check diff for update a file"
170  return check_diff_output(diff_output,
171                           os.path.join('A', 'B', 'E', 'alpha'),
172                           'M')
173
174def diff_check_update_a_file_repo_subset(wc_dir):
175  "diff and check update a file for a repository subset"
176
177  repo_subset = os.path.join('A', 'B')
178  if diff_check_repo_subset(wc_dir, repo_subset, check_update_a_file, 1):
179    return 1
180
181  repo_subset = os.path.join('A', 'B', 'E', 'alpha')
182  if diff_check_repo_subset(wc_dir, repo_subset, check_update_a_file, 1):
183    return 1
184
185  return 0
186
187
188#----------------------------------------------------------------------
189
190def add_a_file():
191  "add a file"
192  svntest.main.file_append(os.path.join('A', 'B', 'E', 'theta'), "theta")
193  svntest.main.run_svn(None, 'add', os.path.join('A', 'B', 'E', 'theta'))
194  return 0
195
196def check_add_a_file(diff_output):
197  "check diff for add a file"
198  return check_diff_output(diff_output,
199                           os.path.join('A', 'B', 'E', 'theta'),
200                           'A')
201
202def check_add_a_file_reverse(diff_output):
203  "check diff for add a file"
204  return check_diff_output(diff_output,
205                           os.path.join('A', 'B', 'E', 'theta'),
206                           'D')
207
208def diff_check_add_a_file_repo_subset(wc_dir):
209  "diff and check add a file for a repository subset"
210
211  repo_subset = os.path.join('A', 'B')
212  if diff_check_repo_subset(wc_dir, repo_subset, check_add_a_file, 1):
213    return 1
214
215  repo_subset = os.path.join('A', 'B', 'E', 'theta')
216  ### TODO: diff -r HEAD doesn't work for added file
217  if diff_check_repo_subset(wc_dir, repo_subset, check_add_a_file, 0):
218    return 1
219
220def update_added_file():
221  svntest.main.file_append(os.path.join('A', 'B', 'E', 'theta'), "net ttext")
222  "update added file"
223  return 0
224
225def check_update_added_file(diff_output):
226  "check diff for update of added file"
227  return check_diff_output(diff_output,
228                           os.path.join('A', 'B', 'E', 'theta'),
229                           'M')
230
231#----------------------------------------------------------------------
232
233def add_a_file_in_a_subdir():
234  "add a file in a subdir"
235  os.mkdir(os.path.join('A', 'B', 'T'))
236  svntest.main.run_svn(None, 'add', os.path.join('A', 'B', 'T'))
237  svntest.main.file_append(os.path.join('A', 'B', 'T', 'phi'), "phi")
238  svntest.main.run_svn(None, 'add', os.path.join('A', 'B', 'T', 'phi'))
239  return 0
240
241def check_add_a_file_in_a_subdir(diff_output):
242  "check diff for add a file in a subdir"
243  return check_diff_output(diff_output,
244                           os.path.join('A', 'B', 'T', 'phi'),
245                           'A')
246
247def check_add_a_file_in_a_subdir_reverse(diff_output):
248  "check diff for add a file in a subdir"
249  return check_diff_output(diff_output,
250                           os.path.join('A', 'B', 'T', 'phi'),
251                           'D')
252
253def diff_check_add_a_file_in_a_subdir_repo_subset(wc_dir):
254  "diff and check add a file in a subdir for a repository subset"
255
256  repo_subset = os.path.join('A', 'B', 'T')
257  ### TODO: diff -r HEAD doesn't work for added subdir
258  if diff_check_repo_subset(wc_dir, repo_subset,
259                            check_add_a_file_in_a_subdir, 0):
260    return 1
261
262  repo_subset = os.path.join('A', 'B', 'T', 'phi')
263  ### TODO: diff -r HEAD doesn't work for added file in subdir
264  if diff_check_repo_subset(wc_dir, repo_subset,
265                            check_add_a_file_in_a_subdir, 0):
266    return 1
267
268#----------------------------------------------------------------------
269
270def replace_a_file():
271  "replace a file"
272  svntest.main.run_svn(None, 'rm', os.path.join('A', 'D', 'G', 'rho'))
273  svntest.main.file_append(os.path.join('A', 'D', 'G', 'rho'), "new rho")
274  svntest.main.run_svn(None, 'add', os.path.join('A', 'D', 'G', 'rho'))
275  return 0
276
277def check_replace_a_file(diff_output):
278  "check diff for replace a file"
279  return check_diff_output(diff_output,
280                       os.path.join('A', 'D', 'G', 'rho'),
281                       'M')
282
283#----------------------------------------------------------------------
284
285def update_three_files():
286  "update three files"
287  svntest.main.file_write(os.path.join('A', 'D', 'gamma'), "new gamma")
288  svntest.main.file_write(os.path.join('A', 'D', 'G', 'tau'), "new tau")
289  svntest.main.file_write(os.path.join('A', 'D', 'H', 'psi'), "new psi")
290  return 0
291
292def check_update_three_files(diff_output):
293  "check update three files"
294  if check_diff_output(diff_output,
295                        os.path.join('A', 'D', 'gamma'),
296                        'M'):
297    return 1
298  if check_diff_output(diff_output,
299                        os.path.join('A', 'D', 'G', 'tau'),
300                        'M'):
301    return 1
302  if check_diff_output(diff_output,
303                        os.path.join('A', 'D', 'H', 'psi'),
304                        'M'):
305    return 1
306  return 0
307
308
309######################################################################
310# make a change, check the diff, commit the change, check the diff
311
312def change_diff_commit_diff(wc_dir, revision, change_fn, check_fn):
313  "make a change, diff, commit, update and diff again"
314
315  was_cwd = os.getcwd()
316  os.chdir(wc_dir)
317
318  svntest.main.run_svn(None,
319                       'up', '-r', 'HEAD')
320
321  change_fn()
322
323  # diff without revision doesn't use an editor
324  exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff')
325  if check_fn(diff_output):
326    raise svntest.Failure
327
328  # diff with revision runs an editor
329  exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff',
330                                                            '-r', 'HEAD')
331  if check_fn(diff_output):
332    raise svntest.Failure
333
334  svntest.main.run_svn(None,
335                       'ci', '-m', 'log msg')
336  svntest.main.run_svn(None,
337                       'up')
338  exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff',
339                                                            '-r', revision)
340  if check_fn(diff_output):
341    raise svntest.Failure
342
343  os.chdir(was_cwd)
344
345######################################################################
346# check the diff
347
348def just_diff(wc_dir, rev_check, check_fn):
349  "update and check that the given diff is seen"
350
351  was_cwd = os.getcwd()
352  os.chdir(wc_dir)
353
354  exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff',
355                                                            '-r', rev_check)
356  if check_fn(diff_output):
357    raise svntest.Failure
358  os.chdir(was_cwd)
359
360######################################################################
361# update, check the diff
362
363def update_diff(wc_dir, rev_up, rev_check, check_fn):
364  "update and check that the given diff is seen"
365
366  was_cwd = os.getcwd()
367  os.chdir(wc_dir)
368
369  svntest.main.run_svn(None,
370                       'up', '-r', rev_up)
371
372  os.chdir(was_cwd)
373
374  just_diff(wc_dir, rev_check, check_fn)
375
376######################################################################
377# check a pure repository rev1:rev2 diff
378
379def repo_diff(wc_dir, rev1, rev2, check_fn):
380  "check that the given pure repository diff is seen"
381
382  was_cwd = os.getcwd()
383  os.chdir(wc_dir)
384
385  exit_code, diff_output, err_output = svntest.main.run_svn(None,
386                                                            'diff', '-r',
387                                                            repr(rev2) + ':'
388                                                                   + repr(rev1))
389  if check_fn(diff_output):
390    raise svntest.Failure
391
392  os.chdir(was_cwd)
393
394######################################################################
395# Tests
396#
397
398# test 1
399def diff_update_a_file(sbox):
400  "update a file"
401
402  sbox.build()
403
404  change_diff_commit_diff(sbox.wc_dir, 1,
405                          update_a_file,
406                          check_update_a_file)
407
408# test 2
409def diff_add_a_file(sbox):
410  "add a file"
411
412  sbox.build()
413
414  change_diff_commit_diff(sbox.wc_dir, 1,
415                          add_a_file,
416                          check_add_a_file)
417
418#test 3
419def diff_add_a_file_in_a_subdir(sbox):
420  "add a file in an added directory"
421
422  sbox.build()
423
424  change_diff_commit_diff(sbox.wc_dir, 1,
425                          add_a_file_in_a_subdir,
426                          check_add_a_file_in_a_subdir)
427
428# test 4
429def diff_replace_a_file(sbox):
430  "replace a file with a file"
431
432  sbox.build()
433
434  change_diff_commit_diff(sbox.wc_dir, 1,
435                          replace_a_file,
436                          check_replace_a_file)
437
438# test 5
439def diff_multiple_reverse(sbox):
440  "multiple revisions diff'd forwards and backwards"
441
442  sbox.build()
443  wc_dir = sbox.wc_dir
444
445  # rev 2
446  change_diff_commit_diff(wc_dir, 1,
447                          add_a_file,
448                          check_add_a_file)
449
450  #rev 3
451  change_diff_commit_diff(wc_dir, 2,
452                          add_a_file_in_a_subdir,
453                          check_add_a_file_in_a_subdir)
454
455  #rev 4
456  change_diff_commit_diff(wc_dir, 3,
457                          update_a_file,
458                          check_update_a_file)
459
460  # check diffs both ways
461  update_diff(wc_dir, 4, 1, check_update_a_file)
462  just_diff(wc_dir, 1, check_add_a_file_in_a_subdir)
463  just_diff(wc_dir, 1, check_add_a_file)
464  update_diff(wc_dir, 1, 4, check_update_a_file)
465  just_diff(wc_dir, 4, check_add_a_file_in_a_subdir_reverse)
466  just_diff(wc_dir, 4, check_add_a_file_reverse)
467
468  # check pure repository diffs
469  repo_diff(wc_dir, 4, 1, check_update_a_file)
470  repo_diff(wc_dir, 4, 1, check_add_a_file_in_a_subdir)
471  repo_diff(wc_dir, 4, 1, check_add_a_file)
472  repo_diff(wc_dir, 1, 4, check_update_a_file)
473# ### TODO: directory delete doesn't work yet
474#  repo_diff(wc_dir, 1, 4, check_add_a_file_in_a_subdir_reverse)
475  repo_diff(wc_dir, 1, 4, check_add_a_file_reverse)
476
477# test 6
478def diff_non_recursive(sbox):
479  "non-recursive behaviour"
480
481  sbox.build()
482  wc_dir = sbox.wc_dir
483
484  change_diff_commit_diff(wc_dir, 1,
485                          update_three_files,
486                          check_update_three_files)
487
488  # The changes are in:   ./A/D/gamma
489  #                       ./A/D/G/tau
490  #                       ./A/D/H/psi
491  # When checking D recursively there are three changes. When checking
492  # D non-recursively there is only one change. When checking G
493  # recursively, there is only one change even though D is the anchor
494
495  # full diff has three changes
496  exit_code, diff_output, err_output = svntest.main.run_svn(
497    None, 'diff', '-r', '1', os.path.join(wc_dir, 'A', 'D'))
498
499  if count_diff_output(diff_output) != 3:
500    raise svntest.Failure
501
502  # non-recursive has one change
503  exit_code, diff_output, err_output = svntest.main.run_svn(
504    None, 'diff', '-r', '1', '-N', os.path.join(wc_dir, 'A', 'D'))
505
506  if count_diff_output(diff_output) != 1:
507    raise svntest.Failure
508
509  # diffing a directory doesn't pick up other diffs in the anchor
510  exit_code, diff_output, err_output = svntest.main.run_svn(
511    None, 'diff', '-r', '1', os.path.join(wc_dir, 'A', 'D', 'G'))
512
513  if count_diff_output(diff_output) != 1:
514    raise svntest.Failure
515
516
517# test 7
518def diff_repo_subset(sbox):
519  "diff only part of the repository"
520
521  sbox.build()
522  wc_dir = sbox.wc_dir
523
524  was_cwd = os.getcwd()
525  os.chdir(wc_dir)
526
527  update_a_file()
528  add_a_file()
529  add_a_file_in_a_subdir()
530
531  os.chdir(was_cwd)
532
533  if diff_check_update_a_file_repo_subset(wc_dir):
534    raise svntest.Failure
535
536  if diff_check_add_a_file_repo_subset(wc_dir):
537    raise svntest.Failure
538
539  if diff_check_add_a_file_in_a_subdir_repo_subset(wc_dir):
540    raise svntest.Failure
541
542
543# test 8
544def diff_non_version_controlled_file(sbox):
545  "non version controlled files"
546
547  sbox.build()
548  wc_dir = sbox.wc_dir
549
550  svntest.main.file_append(os.path.join(wc_dir, 'A', 'D', 'foo'), "a new file")
551
552  exit_code, diff_output, err_output = svntest.main.run_svn(
553    1, 'diff', os.path.join(wc_dir, 'A', 'D', 'foo'))
554
555  if count_diff_output(diff_output) != 0: raise svntest.Failure
556
557  # At one point this would crash, so we would only get a 'Segmentation Fault'
558  # error message.  The appropriate response is a few lines of errors.  I wish
559  # there was a way to figure out if svn crashed, but all run_svn gives us is
560  # the output, so here we are...
561  for line in err_output:
562    if re.search("foo' is not under version control$", line):
563      break
564  else:
565    raise svntest.Failure
566
567# test 9
568def diff_pure_repository_update_a_file(sbox):
569  "pure repository diff update a file"
570
571  sbox.build()
572  wc_dir = sbox.wc_dir
573
574  os.chdir(wc_dir)
575
576  # rev 2
577  update_a_file()
578  svntest.main.run_svn(None,
579                       'ci', '-m', 'log msg')
580
581  # rev 3
582  add_a_file_in_a_subdir()
583  svntest.main.run_svn(None,
584                       'ci', '-m', 'log msg')
585
586  # rev 4
587  add_a_file()
588  svntest.main.run_svn(None,
589                       'ci', '-m', 'log msg')
590
591  # rev 5
592  update_added_file()
593  svntest.main.run_svn(None,
594                       'ci', '-m', 'log msg')
595
596  svntest.main.run_svn(None,
597                       'up', '-r', '2')
598
599  url = sbox.repo_url
600
601  exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff',
602                                                            '-c', '2', url)
603  if check_update_a_file(diff_output): raise svntest.Failure
604
605  exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff',
606                                                            '-r', '1:2')
607  if check_update_a_file(diff_output): raise svntest.Failure
608
609  exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff',
610                                                            '-c', '3', url)
611  if check_add_a_file_in_a_subdir(diff_output): raise svntest.Failure
612
613  exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff',
614                                                            '-r', '2:3')
615  if check_add_a_file_in_a_subdir(diff_output): raise svntest.Failure
616
617  exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff',
618                                                            '-c', '5', url)
619  if check_update_added_file(diff_output): raise svntest.Failure
620
621  exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff',
622                                                            '-r', '4:5')
623  if check_update_added_file(diff_output): raise svntest.Failure
624
625  exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff',
626                                                            '-r', 'head')
627  if check_add_a_file_in_a_subdir_reverse(diff_output): raise svntest.Failure
628
629
630# test 10
631def diff_only_property_change(sbox):
632  "diff when property was changed but text was not"
633
634  sbox.build()
635  wc_dir = sbox.wc_dir
636
637  expected_output = [
638    "\n",
639    "Property changes on: iota\n",
640    "___________________________________________________________________\n",
641    "Added: svn:eol-style\n",
642    "   + native\n",
643    "\n" ]
644
645  expected_reverse_output = list(expected_output)
646  expected_reverse_output[3] = expected_reverse_output[3].replace("Added",
647                                                                  "Deleted")
648  expected_reverse_output[4] = "   - native\n"
649
650
651  os.chdir(sbox.wc_dir)
652  svntest.actions.run_and_verify_svn(None, None, [],
653                                     'propset',
654                                     'svn:eol-style', 'native', 'iota')
655
656  svntest.actions.run_and_verify_svn(None, None, [],
657                                     'ci', '-m', 'empty-msg')
658
659  svntest.actions.run_and_verify_svn(None, expected_output, [],
660                                     'diff', '-r', '1:2')
661
662  svntest.actions.run_and_verify_svn(None, expected_output, [],
663                                     'diff', '-c', '2')
664
665  svntest.actions.run_and_verify_svn(None, expected_reverse_output, [],
666                                     'diff', '-r', '2:1')
667
668  svntest.actions.run_and_verify_svn(None, expected_reverse_output, [],
669                                     'diff', '-c', '-2')
670
671  svntest.actions.run_and_verify_svn(None, expected_output, [],
672                                     'diff', '-r', '1')
673
674  svntest.actions.run_and_verify_svn(None, expected_output, [],
675                                     'diff', '-r', 'PREV', 'iota')
676
677
678
679#----------------------------------------------------------------------
680# Regression test for issue #1019: make sure we don't try to display
681# diffs when the file is marked as a binary type.  This tests all 3
682# uses of 'svn diff':  wc-wc, wc-repos, repos-repos.
683
684def dont_diff_binary_file(sbox):
685  "don't diff file marked as binary type"
686
687  sbox.build()
688  wc_dir = sbox.wc_dir
689
690  # Add a binary file to the project.
691  theta_contents = svntest.main.file_read(
692    os.path.join(sys.path[0], "theta.bin"), 'rb')
693  # Write PNG file data into 'A/theta'.
694  theta_path = os.path.join(wc_dir, 'A', 'theta')
695  svntest.main.file_write(theta_path, theta_contents, 'wb')
696
697  svntest.main.run_svn(None, 'add', theta_path)
698
699  # Created expected output tree for 'svn ci'
700  expected_output = svntest.wc.State(wc_dir, {
701    'A/theta' : Item(verb='Adding  (bin)'),
702    })
703
704  # Create expected status tree
705  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
706  expected_status.add({
707    'A/theta' : Item(status='  ', wc_rev=2),
708    })
709
710  # Commit the new binary file, creating revision 2.
711  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
712                                        expected_status, None, wc_dir)
713
714  # Update the whole working copy to HEAD (rev 2)
715  expected_output = svntest.wc.State(wc_dir, {})
716
717  expected_disk = svntest.main.greek_state.copy()
718  expected_disk.add({
719    'A/theta' : Item(theta_contents,
720                     props={'svn:mime-type' : 'application/octet-stream'}),
721    })
722
723  expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
724  expected_status.add({
725    'A/theta' : Item(status='  ', wc_rev=2),
726    })
727
728  svntest.actions.run_and_verify_update(wc_dir,
729                                        expected_output,
730                                        expected_disk,
731                                        expected_status,
732                                        None, None, None, None, None,
733                                        1)  # verify props, too.
734
735  # Make a local mod to the binary file.
736  svntest.main.file_append(theta_path, "some extra junk")
737
738  # First diff use-case: plain old 'svn diff wc' will display any
739  # local changes in the working copy.  (diffing working
740  # vs. text-base)
741
742  re_nodisplay = re.compile('^Cannot display:')
743
744  exit_code, stdout, stderr = svntest.main.run_svn(None, 'diff', wc_dir)
745
746  for line in stdout:
747    if (re_nodisplay.match(line)):
748      break
749  else:
750    raise svntest.Failure
751
752  # Second diff use-case: 'svn diff -r1 wc' compares the wc against a
753  # the first revision in the repository.
754
755  exit_code, stdout, stderr = svntest.main.run_svn(None,
756                                                   'diff', '-r', '1', wc_dir)
757
758  for line in stdout:
759    if (re_nodisplay.match(line)):
760      break
761  else:
762    raise svntest.Failure
763
764  # Now commit the local mod, creating rev 3.
765  expected_output = svntest.wc.State(wc_dir, {
766    'A/theta' : Item(verb='Sending'),
767    })
768
769  expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
770  expected_status.add({
771    'A/theta' : Item(status='  ', wc_rev=3),
772    })
773
774  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
775                                        expected_status, None, wc_dir)
776
777  # Third diff use-case: 'svn diff -r2:3 wc' will compare two
778  # repository trees.
779
780  exit_code, stdout, stderr = svntest.main.run_svn(None, 'diff',
781                                                   '-r', '2:3', wc_dir)
782
783  for line in stdout:
784    if (re_nodisplay.match(line)):
785      break
786  else:
787    raise svntest.Failure
788
789
790def diff_nonextant_urls(sbox):
791  "svn diff errors against a non-existent URL"
792
793  sbox.build(create_wc = False)
794  non_extant_url = sbox.repo_url + '/A/does_not_exist'
795  extant_url = sbox.repo_url + '/A/mu'
796
797  exit_code, diff_output, err_output = svntest.main.run_svn(
798    1, 'diff', '--old', non_extant_url, '--new', extant_url)
799
800  for line in err_output:
801    if re.search('was not found in the repository at revision', line):
802      break
803  else:
804    raise svntest.Failure
805
806  exit_code, diff_output, err_output = svntest.main.run_svn(
807    1, 'diff', '--old', extant_url, '--new', non_extant_url)
808
809  for line in err_output:
810    if re.search('was not found in the repository at revision', line):
811      break
812  else:
813    raise svntest.Failure
814
815def diff_head_of_moved_file(sbox):
816  "diff against the head of a moved file"
817
818  sbox.build()
819  mu_path = os.path.join(sbox.wc_dir, 'A', 'mu')
820  new_mu_path = mu_path + '.new'
821
822  svntest.main.run_svn(None, 'mv', mu_path, new_mu_path)
823
824  # Modify the file to ensure that the diff is non-empty.
825  svntest.main.file_append(new_mu_path, "\nActually, it's a new mu.")
826
827  svntest.actions.run_and_verify_svn(None, svntest.verify.AnyOutput, [],
828                                     'diff', '-r', 'HEAD', new_mu_path)
829
830
831
832#----------------------------------------------------------------------
833# Regression test for issue #977: make 'svn diff -r BASE:N' compare a
834# repository tree against the wc's text-bases, rather than the wc's
835# working files.  This is a long test, which checks many variations.
836
837def diff_base_to_repos(sbox):
838  "diff text-bases against repository"
839
840  sbox.build()
841  wc_dir = sbox.wc_dir
842
843  iota_path = os.path.join(sbox.wc_dir, 'iota')
844  newfile_path = os.path.join(sbox.wc_dir, 'A', 'D', 'newfile')
845  mu_path = os.path.join(sbox.wc_dir, 'A', 'mu')
846
847  # Make changes to iota, commit r2, update to HEAD (r2).
848  svntest.main.file_append(iota_path, "some rev2 iota text.\n")
849
850  expected_output = svntest.wc.State(wc_dir, {
851    'iota' : Item(verb='Sending'),
852    })
853
854  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
855  expected_status.tweak('iota', wc_rev=2)
856
857  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
858                                        expected_status, None, wc_dir)
859
860  expected_output = svntest.wc.State(wc_dir, {})
861  expected_disk = svntest.main.greek_state.copy()
862  expected_disk.tweak('iota',
863                      contents=\
864                      "This is the file 'iota'.\nsome rev2 iota text.\n")
865  expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
866  svntest.actions.run_and_verify_update(wc_dir, expected_output,
867                                        expected_disk, expected_status)
868
869  # Now make another local mod to iota.
870  svntest.main.file_append(iota_path, "an iota local mod.\n")
871
872  # If we run 'svn diff -r 1', we should see diffs that include *both*
873  # the rev2 changes and local mods.  That's because the working files
874  # are being compared to the repository.
875  exit_code, diff_output, err = svntest.actions.run_and_verify_svn(
876    None, None, [], 'diff', '-r', '1', wc_dir)
877
878  # Makes diff output look the same on all platforms.
879  def strip_eols(lines):
880    return [x.replace("\r", "").replace("\n", "") for x in lines]
881
882  expected_output_lines = make_diff_header(iota_path, "revision 1",
883                                           "working copy") + [
884    "@@ -1 +1,3 @@\n",
885    " This is the file 'iota'.\n",
886    "+some rev2 iota text.\n",
887    "+an iota local mod.\n"]
888
889  if strip_eols(diff_output) != strip_eols(expected_output_lines):
890    raise svntest.Failure
891
892  # If we run 'svn diff -r BASE:1', we should see diffs that only show
893  # the rev2 changes and NOT the local mods.  That's because the
894  # text-bases are being compared to the repository.
895  exit_code, diff_output, err = svntest.actions.run_and_verify_svn(
896    None, None, [], 'diff', '-r', 'BASE:1', wc_dir)
897
898  expected_output_lines = make_diff_header(iota_path, "working copy",
899                                           "revision 1") + [
900    "@@ -1,2 +1 @@\n",
901    " This is the file 'iota'.\n",
902    "-some rev2 iota text.\n"]
903
904  if strip_eols(diff_output) != strip_eols(expected_output_lines):
905    raise svntest.Failure
906
907  # But that's not all folks... no, no, we're just getting started
908  # here!  There are so many other tests to do.
909
910  # For example, we just ran 'svn diff -rBASE:1'.  The output should
911  # look exactly the same as 'svn diff -r2:1'.  (If you remove the
912  # header commentary)
913  exit_code, diff_output2, err = svntest.actions.run_and_verify_svn(
914    None, None, [], 'diff', '-r', '2:1', wc_dir)
915
916  diff_output[2:4] = []
917  diff_output2[2:4] = []
918
919  if (diff_output2 != diff_output):
920    raise svntest.Failure
921
922  # and similarly, does 'svn diff -r1:2' == 'svn diff -r1:BASE' ?
923  exit_code, diff_output, err = svntest.actions.run_and_verify_svn(
924    None, None, [], 'diff', '-r', '1:2', wc_dir)
925
926  exit_code, diff_output2, err = svntest.actions.run_and_verify_svn(
927    None, None, [], 'diff', '-r', '1:BASE', wc_dir)
928
929  diff_output[2:4] = []
930  diff_output2[2:4] = []
931
932  if (diff_output2 != diff_output):
933    raise svntest.Failure
934
935  # Now we schedule an addition and a deletion.
936  svntest.main.file_append(newfile_path, "Contents of newfile\n")
937  svntest.main.run_svn(None, 'add', newfile_path)
938  svntest.main.run_svn(None, 'rm', mu_path)
939
940  expected_output = svntest.actions.get_virginal_state(wc_dir, 2)
941  expected_output.add({
942    'A/D/newfile' : Item(status='A ', wc_rev=0),
943    })
944  expected_output.tweak('A/mu', status='D ')
945  expected_output.tweak('iota', status='M ')
946  svntest.actions.run_and_verify_status(wc_dir, expected_output)
947
948  # once again, verify that -r1:2 and -r1:BASE look the same, as do
949  # -r2:1 and -rBASE:1.  None of these diffs should mention the
950  # scheduled addition or deletion.
951  exit_code, diff_output, err = svntest.actions.run_and_verify_svn(
952    None, None, [], 'diff', '-r', '1:2', wc_dir)
953
954  exit_code, diff_output2, err = svntest.actions.run_and_verify_svn(
955    None, None, [], 'diff', '-r', '1:BASE', wc_dir)
956
957  exit_code, diff_output3, err = svntest.actions.run_and_verify_svn(
958    None, None, [], 'diff', '-r', '2:1', wc_dir)
959
960  exit_code, diff_output4, err = svntest.actions.run_and_verify_svn(
961    None, None, [], 'diff', '-r', 'BASE:1', wc_dir)
962
963  diff_output[2:4] = []
964  diff_output2[2:4] = []
965  diff_output3[2:4] = []
966  diff_output4[2:4] = []
967
968  if (diff_output != diff_output2):
969    raise svntest.Failure
970
971  if (diff_output3 != diff_output4):
972    raise svntest.Failure
973
974  # Great!  So far, so good.  Now we commit our three changes (a local
975  # mod, an addition, a deletion) and update to HEAD (r3).
976  expected_output = svntest.wc.State(wc_dir, {
977    'iota' : Item(verb='Sending'),
978    'A/mu' : Item(verb='Deleting'),
979    'A/D/newfile' : Item(verb='Adding')
980    })
981  expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
982  expected_status.tweak('iota', wc_rev=3)
983  expected_status.remove('A/mu')
984  expected_status.add({
985    'A/D/newfile' : Item(status='  ', wc_rev=3),
986    })
987  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
988                                        expected_status, None, wc_dir)
989
990  expected_output = svntest.wc.State(wc_dir, {})
991  expected_disk = svntest.main.greek_state.copy()
992  expected_disk.tweak('iota',
993                      contents="This is the file 'iota'.\n" + \
994                      "some rev2 iota text.\nan iota local mod.\n")
995  expected_disk.add({'A/D/newfile' : Item("Contents of newfile\n")})
996  expected_disk.remove('A/mu')
997
998  expected_status = svntest.actions.get_virginal_state(wc_dir, 3)
999  expected_status.remove('A/mu')
1000  expected_status.add({
1001    'A/D/newfile' : Item(status='  ', wc_rev=3),
1002    })
1003  svntest.actions.run_and_verify_update(wc_dir, expected_output,
1004                                        expected_disk, expected_status)
1005
1006  # Now 'svn diff -r3:2' should == 'svn diff -rBASE:2', showing the
1007  # removal of changes to iota, the adding of mu, and deletion of newfile.
1008  exit_code, diff_output, err = svntest.actions.run_and_verify_svn(
1009    None, None, [], 'diff', '-r', '3:2', wc_dir)
1010
1011  exit_code, diff_output2, err = svntest.actions.run_and_verify_svn(
1012    None, None, [], 'diff', '-r', 'BASE:2', wc_dir)
1013
1014  # to do the comparison, remove all output lines starting with +++ or ---
1015  re_infoline = re.compile('^(\+\+\+|---).*$')
1016  list1 = []
1017  list2 = []
1018
1019  for line in diff_output:
1020    if not re_infoline.match(line):
1021      list1.append(line)
1022
1023  for line in diff_output2:
1024    if not re_infoline.match(line):
1025      list2.append(line)
1026
1027  if list1 != list2:
1028    raise svntest.Failure
1029
1030
1031#----------------------------------------------------------------------
1032# This is a simple regression test for issue #891, whereby ra_neon's
1033# REPORT request would fail, because the object no longer exists in HEAD.
1034
1035def diff_deleted_in_head(sbox):
1036  "repos-repos diff on item deleted from HEAD"
1037
1038  sbox.build()
1039  wc_dir = sbox.wc_dir
1040
1041  A_path = os.path.join(sbox.wc_dir, 'A')
1042  mu_path = os.path.join(sbox.wc_dir, 'A', 'mu')
1043
1044  # Make a change to mu, commit r2, update.
1045  svntest.main.file_append(mu_path, "some rev2 mu text.\n")
1046
1047  expected_output = svntest.wc.State(wc_dir, {
1048    'A/mu' : Item(verb='Sending'),
1049    })
1050  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
1051  expected_status.tweak('A/mu', wc_rev=2)
1052
1053  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
1054                                        expected_status, None, wc_dir)
1055
1056  expected_output = svntest.wc.State(wc_dir, {})
1057  expected_disk = svntest.main.greek_state.copy()
1058  expected_disk.tweak('A/mu',
1059                      contents="This is the file 'mu'.\nsome rev2 mu text.\n")
1060  expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
1061  svntest.actions.run_and_verify_update(wc_dir, expected_output,
1062                                        expected_disk, expected_status)
1063
1064  # Now delete the whole directory 'A', and commit as r3.
1065  svntest.main.run_svn(None, 'rm', A_path)
1066  expected_output = svntest.wc.State(wc_dir, {
1067    'A' : Item(verb='Deleting'),
1068    })
1069  expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
1070  expected_status.remove('A', 'A/B', 'A/B/E', 'A/B/E/beta', 'A/B/E/alpha',
1071                         'A/B/F', 'A/B/lambda', 'A/D', 'A/D/G', 'A/D/G/rho',
1072                         'A/D/G/pi', 'A/D/G/tau', 'A/D/H', 'A/D/H/psi',
1073                         'A/D/H/omega', 'A/D/H/chi', 'A/D/gamma', 'A/mu',
1074                         'A/C')
1075
1076  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
1077                                        expected_status, None, wc_dir)
1078
1079  # Doing an 'svn diff -r1:2' on the URL of directory A should work,
1080  # especially over the DAV layer.
1081  the_url = sbox.repo_url + '/A'
1082  diff_output = svntest.actions.run_and_verify_svn(None, None, [],
1083                                                   'diff', '-r',
1084                                                   '1:2', the_url + "@2")
1085
1086
1087#----------------------------------------------------------------------
1088def diff_targets(sbox):
1089  "select diff targets"
1090
1091  sbox.build()
1092  os.chdir(sbox.wc_dir)
1093
1094  update_a_file()
1095  add_a_file()
1096
1097  update_path = os.path.join('A', 'B', 'E', 'alpha')
1098  add_path = os.path.join('A', 'B', 'E', 'theta')
1099  parent_path = os.path.join('A', 'B', 'E')
1100  update_url = sbox.repo_url + '/A/B/E/alpha'
1101  parent_url = sbox.repo_url + '/A/B/E'
1102
1103  exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff',
1104                                                            update_path,
1105                                                            add_path)
1106  if check_update_a_file(diff_output) or check_add_a_file(diff_output):
1107    raise svntest.Failure
1108
1109  exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff',
1110                                                            update_path)
1111  if check_update_a_file(diff_output) or not check_add_a_file(diff_output):
1112    raise svntest.Failure
1113
1114  exit_code, diff_output, err_output = svntest.main.run_svn(
1115    None, 'diff', '--old', parent_path, 'alpha', 'theta')
1116
1117  if check_update_a_file(diff_output) or check_add_a_file(diff_output):
1118    raise svntest.Failure
1119
1120  exit_code, diff_output, err_output = svntest.main.run_svn(
1121    None, 'diff', '--old', parent_path, 'theta')
1122
1123  if not check_update_a_file(diff_output) or check_add_a_file(diff_output):
1124    raise svntest.Failure
1125
1126  exit_code, diff_output, err_output = svntest.main.run_svn(None, 'ci',
1127                                                            '-m', 'log msg')
1128
1129  exit_code, diff_output, err_output = svntest.main.run_svn(1, 'diff', '-r1:2',
1130                                                            update_path,
1131                                                            add_path)
1132
1133  regex = 'svn: Unable to find repository location for \'.*\''
1134  for line in err_output:
1135    if re.match(regex, line):
1136      break
1137  else:
1138    raise svntest.Failure
1139
1140  exit_code, diff_output, err_output = svntest.main.run_svn(1,
1141                                                            'diff', '-r1:2',
1142                                                            add_path)
1143  for line in err_output:
1144    if re.match(regex, line):
1145      break
1146  else:
1147    raise svntest.Failure
1148
1149  exit_code, diff_output, err_output = svntest.main.run_svn(
1150    1, 'diff', '-r1:2', '--old', parent_path, 'alpha', 'theta')
1151
1152  regex = 'svn: \'.*\' was not found in the repository'
1153  for line in err_output:
1154    if re.match(regex, line):
1155      break
1156  else:
1157    raise svntest.Failure
1158
1159  exit_code, diff_output, err_output = svntest.main.run_svn(
1160    None, 'diff', '-r1:2', '--old', parent_path, 'alpha')
1161
1162  if check_update_a_file(diff_output) or not check_add_a_file(diff_output):
1163    raise svntest.Failure
1164
1165
1166#----------------------------------------------------------------------
1167def diff_branches(sbox):
1168  "diff for branches"
1169
1170  sbox.build()
1171
1172  A_url = sbox.repo_url + '/A'
1173  A2_url = sbox.repo_url + '/A2'
1174
1175  svntest.actions.run_and_verify_svn(None, None, [],
1176                                     'cp', '-m', 'log msg',
1177                                     A_url, A2_url)
1178
1179  svntest.actions.run_and_verify_svn(None, None, [],
1180                                     'up', sbox.wc_dir)
1181
1182  A_alpha = os.path.join(sbox.wc_dir, 'A', 'B', 'E', 'alpha')
1183  A2_alpha = os.path.join(sbox.wc_dir, 'A2', 'B', 'E', 'alpha')
1184
1185  svntest.main.file_append(A_alpha, "\nfoo\n")
1186  svntest.actions.run_and_verify_svn(None, None, [],
1187                                     'ci', '-m', 'log msg', sbox.wc_dir)
1188
1189  svntest.main.file_append(A2_alpha, "\nbar\n")
1190  svntest.actions.run_and_verify_svn(None, None, [],
1191                                     'ci', '-m', 'log msg', sbox.wc_dir)
1192
1193  svntest.main.file_append(A_alpha, "zig\n")
1194
1195  # Compare repository file on one branch against repository file on
1196  # another branch
1197  rel_path = os.path.join('B', 'E', 'alpha')
1198  exit_code, diff_output, err = svntest.actions.run_and_verify_svn(
1199    None, None, [], 'diff', '--old', A_url, '--new', A2_url, rel_path)
1200
1201  verify_expected_output(diff_output, "-foo")
1202  verify_expected_output(diff_output, "+bar")
1203
1204  # Same again but using whole branch
1205  exit_code, diff_output, err = svntest.actions.run_and_verify_svn(
1206    None, None, [], 'diff', '--old', A_url, '--new', A2_url)
1207
1208  verify_expected_output(diff_output, "-foo")
1209  verify_expected_output(diff_output, "+bar")
1210
1211  # Compare two repository files on different branches
1212  exit_code, diff_output, err = svntest.actions.run_and_verify_svn(
1213    None, None, [],
1214    'diff', A_url + '/B/E/alpha', A2_url + '/B/E/alpha')
1215
1216  verify_expected_output(diff_output, "-foo")
1217  verify_expected_output(diff_output, "+bar")
1218
1219  # Compare two versions of a file on a single branch
1220  exit_code, diff_output, err = svntest.actions.run_and_verify_svn(
1221    None, None, [],
1222    'diff', A_url + '/B/E/alpha@2', A_url + '/B/E/alpha@3')
1223
1224  verify_expected_output(diff_output, "+foo")
1225
1226  # Compare identical files on different branches
1227  exit_code, diff_output, err = svntest.actions.run_and_verify_svn(
1228    None, [], [],
1229    'diff', A_url + '/B/E/alpha@2', A2_url + '/B/E/alpha@3')
1230
1231
1232#----------------------------------------------------------------------
1233def diff_repos_and_wc(sbox):
1234  "diff between repos URLs and WC paths"
1235
1236  sbox.build()
1237
1238  A_url = sbox.repo_url + '/A'
1239  A2_url = sbox.repo_url + '/A2'
1240
1241  svntest.actions.run_and_verify_svn(None, None, [],
1242                                     'cp', '-m', 'log msg',
1243                                     A_url, A2_url)
1244
1245  svntest.actions.run_and_verify_svn(None, None, [],
1246                                     'up', sbox.wc_dir)
1247
1248  A_alpha = os.path.join(sbox.wc_dir, 'A', 'B', 'E', 'alpha')
1249  A2_alpha = os.path.join(sbox.wc_dir, 'A2', 'B', 'E', 'alpha')
1250
1251  svntest.main.file_append(A_alpha, "\nfoo\n")
1252  svntest.actions.run_and_verify_svn(None, None, [],
1253                                     'ci', '-m', 'log msg', sbox.wc_dir)
1254
1255  svntest.main.file_append(A2_alpha, "\nbar\n")
1256  svntest.actions.run_and_verify_svn(None, None, [],
1257                                     'ci', '-m', 'log msg', sbox.wc_dir)
1258
1259  svntest.main.file_append(A_alpha, "zig\n")
1260
1261  # Compare working file on one branch against repository file on
1262  # another branch
1263  A_path = os.path.join(sbox.wc_dir, 'A')
1264  rel_path = os.path.join('B', 'E', 'alpha')
1265  exit_code, diff_output, err = svntest.actions.run_and_verify_svn(
1266    None, None, [],
1267    'diff', '--old', A2_url, '--new', A_path, rel_path)
1268
1269  verify_expected_output(diff_output, "-bar")
1270  verify_expected_output(diff_output, "+foo")
1271  verify_expected_output(diff_output, "+zig")
1272
1273  # Same again but using whole branch
1274  exit_code, diff_output, err = svntest.actions.run_and_verify_svn(
1275    None, None, [],
1276    'diff', '--old', A2_url, '--new', A_path)
1277
1278  verify_expected_output(diff_output, "-bar")
1279  verify_expected_output(diff_output, "+foo")
1280  verify_expected_output(diff_output, "+zig")
1281
1282#----------------------------------------------------------------------
1283def diff_file_urls(sbox):
1284  "diff between two file URLs (issue #1311)"
1285
1286  sbox.build()
1287
1288  iota_path = os.path.join(sbox.wc_dir, 'iota')
1289  iota_url = sbox.repo_url + '/iota'
1290  iota_copy_path = os.path.join(sbox.wc_dir, 'A', 'iota')
1291  iota_copy_url = sbox.repo_url + '/A/iota'
1292  iota_copy2_url = sbox.repo_url + '/A/iota2'
1293
1294  # Put some different text into iota, and commit.
1295  os.remove(iota_path)
1296  svntest.main.file_append(iota_path, "foo\nbar\nsnafu\n")
1297
1298  svntest.actions.run_and_verify_svn(None, None, [],
1299                                     'ci', '-m', 'log msg', iota_path)
1300
1301  # Now, copy the file elsewhere, twice.
1302  svntest.actions.run_and_verify_svn(None, None, [],
1303                                     'cp', '-m', 'log msg',
1304                                     iota_url, iota_copy_url)
1305
1306  svntest.actions.run_and_verify_svn(None, None, [],
1307                                     'cp', '-m', 'log msg',
1308                                     iota_url, iota_copy2_url)
1309
1310  # Update (to get the copies)
1311  svntest.actions.run_and_verify_svn(None, None, [],
1312                                     'up', sbox.wc_dir)
1313
1314  # Now, make edits to one of the copies of iota, and commit.
1315  os.remove(iota_copy_path)
1316  svntest.main.file_append(iota_copy_path, "foo\nsnafu\nabcdefg\nopqrstuv\n")
1317
1318  svntest.actions.run_and_verify_svn(None, None, [],
1319                                     'ci', '-m', 'log msg', iota_copy_path)
1320
1321  # Finally, do a diff between the first and second copies of iota,
1322  # and verify that we got the expected lines.  And then do it in reverse!
1323  exit_code, out, err = svntest.actions.run_and_verify_svn(None, None, [],
1324                                                           'diff',
1325                                                           iota_copy_url,
1326                                                           iota_copy2_url)
1327
1328  verify_expected_output(out, "+bar")
1329  verify_expected_output(out, "-abcdefg")
1330  verify_expected_output(out, "-opqrstuv")
1331
1332  exit_code, out, err = svntest.actions.run_and_verify_svn(None, None, [],
1333                                                           'diff',
1334                                                           iota_copy2_url,
1335                                                           iota_copy_url)
1336
1337  verify_expected_output(out, "-bar")
1338  verify_expected_output(out, "+abcdefg")
1339  verify_expected_output(out, "+opqrstuv")
1340
1341#----------------------------------------------------------------------
1342def diff_prop_change_local_edit(sbox):
1343  "diff a property change plus a local edit"
1344
1345  sbox.build()
1346
1347  iota_path = os.path.join(sbox.wc_dir, 'iota')
1348  iota_url = sbox.repo_url + '/iota'
1349
1350  # Change a property on iota, and commit.
1351  svntest.actions.run_and_verify_svn(None, None, [],
1352                                     'propset', 'pname', 'pvalue', iota_path)
1353  svntest.actions.run_and_verify_svn(None, None, [],
1354                                     'ci', '-m', 'log msg', iota_path)
1355
1356  # Make local edits to iota.
1357  svntest.main.file_append(iota_path, "\nMore text.\n")
1358
1359  # diff r1:COMMITTED should show the property change but not the local edit.
1360  exit_code, out, err = svntest.actions.run_and_verify_svn(None, None, [],
1361                                                           'diff',
1362                                                           '-r1:COMMITTED',
1363                                                           iota_path)
1364  for line in out:
1365    if line.find("+More text.") != -1:
1366      raise svntest.Failure
1367  verify_expected_output(out, "   + pvalue")
1368
1369  # diff r1:BASE should show the property change but not the local edit.
1370  exit_code, out, err = svntest.actions.run_and_verify_svn(None, None, [],
1371                                                           'diff', '-r1:BASE',
1372                                                           iota_path)
1373  for line in out:
1374    if line.find("+More text.") != -1:
1375      raise svntest.Failure                   # fails at r7481
1376  verify_expected_output(out, "   + pvalue")  # fails at r7481
1377
1378  # diff r1:WC should show the local edit as well as the property change.
1379  exit_code, out, err = svntest.actions.run_and_verify_svn(None, None, [],
1380                                                           'diff', '-r1',
1381                                                           iota_path)
1382  verify_expected_output(out, "+More text.")  # fails at r7481
1383  verify_expected_output(out, "   + pvalue")
1384
1385#----------------------------------------------------------------------
1386def check_for_omitted_prefix_in_path_component(sbox):
1387  "check for omitted prefix in path component"
1388
1389  sbox.build()
1390  svntest.actions.do_sleep_for_timestamps()
1391
1392  prefix_path = os.path.join(sbox.wc_dir, 'prefix_mydir')
1393  svntest.actions.run_and_verify_svn(None, None, [],
1394                                     'mkdir', prefix_path)
1395  other_prefix_path = os.path.join(sbox.wc_dir, 'prefix_other')
1396  svntest.actions.run_and_verify_svn(None, None, [],
1397                                     'mkdir', other_prefix_path)
1398
1399  svntest.actions.run_and_verify_svn(None, None, [],
1400                                     'ci', '-m', 'log msg', sbox.wc_dir)
1401
1402
1403  file_path = os.path.join(prefix_path, "test.txt")
1404  svntest.main.file_write(file_path, "Hello\nThere\nIota\n")
1405
1406  svntest.actions.run_and_verify_svn(None, None, [],
1407                                     'add', file_path)
1408
1409  svntest.actions.run_and_verify_svn(None, None, [],
1410                                     'ci', '-m', 'log msg', sbox.wc_dir)
1411
1412
1413  prefix_url = sbox.repo_url + "/prefix_mydir"
1414  other_prefix_url = sbox.repo_url + "/prefix_other/mytag"
1415  svntest.actions.run_and_verify_svn(None, None, [],
1416                                     'cp', '-m', 'log msg', prefix_url,
1417                                     other_prefix_url)
1418
1419  svntest.main.file_write(file_path, "Hello\nWorld\nIota\n")
1420  svntest.actions.run_and_verify_svn(None, None, [],
1421                                     'ci', '-m', 'log msg', prefix_path)
1422
1423  exit_code, out, err = svntest.actions.run_and_verify_svn(None, None, [],
1424                                                           'diff', prefix_url,
1425                                                           other_prefix_url)
1426
1427  src = extract_diff_path(out[2])
1428  dest = extract_diff_path(out[3])
1429
1430  good_src = ".../prefix_mydir"
1431  good_dest = ".../prefix_other/mytag"
1432
1433  if ((src != good_src) or (dest != good_dest)):
1434    print("src is '%s' instead of '%s' and dest is '%s' instead of '%s'" %
1435          (src, good_src, dest, good_dest))
1436    raise svntest.Failure
1437
1438#----------------------------------------------------------------------
1439def diff_renamed_file(sbox):
1440  "diff a file that has been renamed"
1441
1442  sbox.build()
1443
1444  os.chdir(sbox.wc_dir)
1445
1446  pi_path = os.path.join('A', 'D', 'G', 'pi')
1447  pi2_path = os.path.join('A', 'D', 'pi2')
1448  svntest.main.file_write(pi_path, "new pi")
1449
1450  svntest.actions.run_and_verify_svn(None, None, [],
1451                                     'ci', '-m', 'log msg')
1452
1453  svntest.main.file_append(pi_path, "even more pi")
1454
1455  svntest.actions.run_and_verify_svn(None, None, [],
1456                                     'ci', '-m', 'log msg')
1457
1458  svntest.main.run_svn(None, 'mv', pi_path, pi2_path)
1459
1460  # Repos->WC diff of the file
1461  exit_code, diff_output, err_output = svntest.main.run_svn(None,
1462                                                            'diff', '-r', '1',
1463                                                            pi2_path)
1464
1465  if check_diff_output(diff_output,
1466                       pi2_path,
1467                       'M') :
1468    raise svntest.Failure
1469
1470  svntest.main.file_append(pi2_path, "new pi")
1471
1472  # Repos->WC of the directory
1473  exit_code, diff_output, err_output = svntest.main.run_svn(
1474    None, 'diff', '-r', '1', os.path.join('A', 'D'))
1475
1476  if check_diff_output(diff_output,
1477                       pi_path,
1478                       'D') :
1479    raise svntest.Failure
1480
1481  if check_diff_output(diff_output,
1482                       pi2_path,
1483                       'M') :
1484    raise svntest.Failure
1485
1486  # WC->WC of the file
1487  exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff',
1488                                                            pi2_path)
1489  if check_diff_output(diff_output,
1490                       pi2_path,
1491                       'M') :
1492    raise svntest.Failure
1493
1494
1495  svntest.actions.run_and_verify_svn(None, None, [],
1496                                     'ci', '-m', 'log msg')
1497
1498  # Repos->WC diff of file after the rename.
1499  exit_code, diff_output, err_output = svntest.main.run_svn(None,
1500                                                            'diff', '-r', '1',
1501                                                            pi2_path)
1502  if check_diff_output(diff_output,
1503                       pi2_path,
1504                       'M') :
1505    raise svntest.Failure
1506
1507  # Repos->repos diff after the rename.
1508  exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff',
1509                                                            '-r', '2:3',
1510                                                            pi2_path)
1511  if check_diff_output(diff_output,
1512                       os.path.join('A', 'D', 'pi'),
1513                       'M') :
1514    raise svntest.Failure
1515
1516#----------------------------------------------------------------------
1517def diff_within_renamed_dir(sbox):
1518  "diff a file within a renamed directory"
1519
1520  sbox.build()
1521
1522  os.chdir(sbox.wc_dir)
1523
1524  svntest.main.run_svn(None, 'mv', os.path.join('A', 'D', 'G'),
1525                                   os.path.join('A', 'D', 'I'))
1526  # svntest.main.run_svn(None, 'ci', '-m', 'log_msg')
1527  svntest.main.file_write(os.path.join('A', 'D', 'I', 'pi'), "new pi")
1528
1529  # Check a repos->wc diff
1530  exit_code, diff_output, err_output = svntest.main.run_svn(
1531    None, 'diff', os.path.join('A', 'D', 'I', 'pi'))
1532
1533  if check_diff_output(diff_output,
1534                       os.path.join('A', 'D', 'I', 'pi'),
1535                       'M') :
1536    raise svntest.Failure
1537
1538  svntest.actions.run_and_verify_svn(None, None, [],
1539                                     'ci', '-m', 'log msg')
1540
1541  # Check repos->wc after commit
1542  exit_code, diff_output, err_output = svntest.main.run_svn(
1543    None, 'diff', '-r', '1', os.path.join('A', 'D', 'I', 'pi'))
1544
1545  if check_diff_output(diff_output,
1546                       os.path.join('A', 'D', 'I', 'pi'),
1547                       'M') :
1548    raise svntest.Failure
1549
1550  # Test the diff while within the moved directory
1551  os.chdir(os.path.join('A','D','I'))
1552
1553  exit_code, diff_output, err_output = svntest.main.run_svn(None,
1554                                                            'diff', '-r', '1')
1555
1556  if check_diff_output(diff_output, 'pi', 'M') :
1557    raise svntest.Failure
1558
1559  # Test a repos->repos diff while within the moved directory
1560  exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff',
1561                                                            '-r', '1:2')
1562
1563  if check_diff_output(diff_output, 'pi', 'M') :
1564    raise svntest.Failure
1565
1566#----------------------------------------------------------------------
1567def diff_prop_on_named_dir(sbox):
1568  "diff a prop change on a dir named explicitly"
1569
1570  # Diff of a property change or addition should contain a "+" line.
1571  # Diff of a property change or deletion should contain a "-" line.
1572  # On a diff between repository revisions (not WC) of a dir named
1573  # explicitly, the "-" line was missing.  (For a file, and for a dir
1574  # recursed into, the result was correct.)
1575
1576  sbox.build()
1577  wc_dir = sbox.wc_dir
1578
1579  os.chdir(sbox.wc_dir)
1580
1581  svntest.actions.run_and_verify_svn(None, None, [],
1582                                     'propset', 'p', 'v', 'A')
1583  svntest.actions.run_and_verify_svn(None, None, [],
1584                                     'ci', '-m', '')
1585
1586  svntest.actions.run_and_verify_svn(None, None, [],
1587                                     'propdel', 'p', 'A')
1588  svntest.actions.run_and_verify_svn(None, None, [],
1589                                     'ci', '-m', '')
1590
1591  exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff',
1592                                                            '-r2:3', 'A')
1593  # Check that the result contains a "-" line.
1594  verify_expected_output(diff_output, "   - v")
1595
1596#----------------------------------------------------------------------
1597def diff_keywords(sbox):
1598  "ensure that diff won't show keywords"
1599
1600  sbox.build()
1601
1602  iota_path = os.path.join(sbox.wc_dir, 'iota')
1603
1604  svntest.actions.run_and_verify_svn(None, None, [],
1605                                     'ps',
1606                                     'svn:keywords',
1607                                     'Id Rev Date',
1608                                     iota_path)
1609
1610  fp = open(iota_path, 'w')
1611  fp.write("$Date$\n")
1612  fp.write("$Id$\n")
1613  fp.write("$Rev$\n")
1614  fp.write("$Date::%s$\n" % (' ' * 80))
1615  fp.write("$Id::%s$\n"   % (' ' * 80))
1616  fp.write("$Rev::%s$\n"  % (' ' * 80))
1617  fp.close()
1618
1619  svntest.actions.run_and_verify_svn(None, None, [],
1620                                     'ci', '-m', 'keywords', sbox.wc_dir)
1621
1622  svntest.main.file_append(iota_path, "bar\n")
1623  svntest.actions.run_and_verify_svn(None, None, [],
1624                                     'ci', '-m', 'added bar', sbox.wc_dir)
1625
1626  svntest.actions.run_and_verify_svn(None, None, [],
1627                                     'up', sbox.wc_dir)
1628
1629  exit_code, diff_output, err = svntest.actions.run_and_verify_svn(
1630    None, None, [], 'diff', '-r', 'prev:head', sbox.wc_dir)
1631
1632  verify_expected_output(diff_output, "+bar")
1633  verify_excluded_output(diff_output, "$Date:")
1634  verify_excluded_output(diff_output, "$Rev:")
1635  verify_excluded_output(diff_output, "$Id:")
1636
1637  exit_code, diff_output, err = svntest.actions.run_and_verify_svn(
1638    None, None, [], 'diff', '-r', 'head:prev', sbox.wc_dir)
1639
1640  verify_expected_output(diff_output, "-bar")
1641  verify_excluded_output(diff_output, "$Date:")
1642  verify_excluded_output(diff_output, "$Rev:")
1643  verify_excluded_output(diff_output, "$Id:")
1644
1645  # Check fixed length keywords will show up
1646  # when the length of keyword has changed
1647  fp = open(iota_path, 'w')
1648  fp.write("$Date$\n")
1649  fp.write("$Id$\n")
1650  fp.write("$Rev$\n")
1651  fp.write("$Date::%s$\n" % (' ' * 79))
1652  fp.write("$Id::%s$\n"   % (' ' * 79))
1653  fp.write("$Rev::%s$\n"  % (' ' * 79))
1654  fp.close()
1655
1656  svntest.actions.run_and_verify_svn(None, None, [],
1657                                     'ci', '-m', 'keywords 2', sbox.wc_dir)
1658  svntest.actions.run_and_verify_svn(None, None, [],
1659                                     'up', sbox.wc_dir)
1660
1661  exit_code, diff_output, err = svntest.actions.run_and_verify_svn(
1662    None, None, [], 'diff', '-r', 'prev:head', sbox.wc_dir)
1663
1664  # these should show up
1665  verify_expected_output(diff_output, "+$Id:: ")
1666  verify_expected_output(diff_output, "-$Id:: ")
1667  verify_expected_output(diff_output, "-$Rev:: ")
1668  verify_expected_output(diff_output, "+$Rev:: ")
1669  verify_expected_output(diff_output, "-$Date:: ")
1670  verify_expected_output(diff_output, "+$Date:: ")
1671  # ... and these won't
1672  verify_excluded_output(diff_output, "$Date: ")
1673  verify_excluded_output(diff_output, "$Rev: ")
1674  verify_excluded_output(diff_output, "$Id: ")
1675
1676
1677def diff_force(sbox):
1678  "show diffs for binary files with --force"
1679
1680  sbox.build()
1681  wc_dir = sbox.wc_dir
1682
1683  iota_path = os.path.join(wc_dir, 'iota')
1684
1685  # Append a line to iota and make it binary.
1686  svntest.main.file_append(iota_path, "new line")
1687  svntest.main.run_svn(None,
1688                       'propset', 'svn:mime-type',
1689                       'application/octet-stream', iota_path)
1690
1691  # Created expected output tree for 'svn ci'
1692  expected_output = svntest.wc.State(wc_dir, {
1693    'iota' : Item(verb='Sending'),
1694    })
1695
1696  # Create expected status tree
1697  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
1698  expected_status.add({
1699    'iota' : Item(status='  ', wc_rev=2),
1700    })
1701
1702  # Commit iota, creating revision 2.
1703  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
1704                                        expected_status, None, wc_dir)
1705
1706  # Add another line, while keeping he file as binary.
1707  svntest.main.file_append(iota_path, "another line")
1708
1709  # Commit creating rev 3.
1710  expected_output = svntest.wc.State(wc_dir, {
1711    'iota' : Item(verb='Sending'),
1712    })
1713
1714  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
1715  expected_status.add({
1716    'iota' : Item(status='  ', wc_rev=3),
1717    })
1718
1719  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
1720                                        expected_status, None, wc_dir)
1721
1722  # Check that we get diff when the first, the second and both files are
1723  # marked as binary.
1724
1725  re_nodisplay = re.compile('^Cannot display:')
1726
1727  exit_code, stdout, stderr = svntest.main.run_svn(None,
1728                                                   'diff', '-r1:2', iota_path,
1729                                                   '--force')
1730
1731  for line in stdout:
1732    if (re_nodisplay.match(line)):
1733      raise svntest.Failure
1734
1735  exit_code, stdout, stderr = svntest.main.run_svn(None,
1736                                                   'diff', '-r2:1', iota_path,
1737                                                   '--force')
1738
1739  for line in stdout:
1740    if (re_nodisplay.match(line)):
1741      raise svntest.Failure
1742
1743  exit_code, stdout, stderr = svntest.main.run_svn(None,
1744                                                   'diff', '-r2:3', iota_path,
1745                                                   '--force')
1746
1747  for line in stdout:
1748    if (re_nodisplay.match(line)):
1749      raise svntest.Failure
1750
1751#----------------------------------------------------------------------
1752# Regression test for issue #2333: Renaming a directory should produce
1753# deletion and addition diffs for each included file.
1754def diff_renamed_dir(sbox):
1755  "diff a renamed directory"
1756
1757  sbox.build()
1758
1759  os.chdir(sbox.wc_dir)
1760
1761  svntest.main.run_svn(None, 'mv', os.path.join('A', 'D', 'G'),
1762                                   os.path.join('A', 'D', 'I'))
1763
1764  # Check a repos->wc diff
1765  exit_code, diff_output, err_output = svntest.main.run_svn(
1766    None, 'diff', os.path.join('A', 'D'))
1767
1768  if check_diff_output(diff_output,
1769                       os.path.join('A', 'D', 'G', 'pi'),
1770                       'D') :
1771    raise svntest.Failure
1772  if check_diff_output(diff_output,
1773                       os.path.join('A', 'D', 'I', 'pi'),
1774                       'A') :
1775    raise svntest.Failure
1776
1777  svntest.actions.run_and_verify_svn(None, None, [],
1778                                     'ci', '-m', 'log msg')
1779
1780  # Check repos->wc after commit
1781  exit_code, diff_output, err_output = svntest.main.run_svn(
1782    None, 'diff', '-r', '1', os.path.join('A', 'D'))
1783
1784  if check_diff_output(diff_output,
1785                       os.path.join('A', 'D', 'G', 'pi'),
1786                       'D') :
1787    raise svntest.Failure
1788  if check_diff_output(diff_output,
1789                       os.path.join('A', 'D', 'I', 'pi'),
1790                       'A') :
1791    raise svntest.Failure
1792
1793  # Test a repos->repos diff after commit
1794  exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff',
1795                                                            '-r', '1:2')
1796  if check_diff_output(diff_output,
1797                       os.path.join('A', 'D', 'G', 'pi'),
1798                       'D') :
1799    raise svntest.Failure
1800  if check_diff_output(diff_output,
1801                       os.path.join('A', 'D', 'I', 'pi'),
1802                       'A') :
1803    raise svntest.Failure
1804
1805  # Test the diff while within the moved directory
1806  os.chdir(os.path.join('A','D','I'))
1807
1808  exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff',
1809                                                            '-r', '1')
1810
1811  if check_diff_output(diff_output, 'pi', 'A') :
1812    raise svntest.Failure
1813
1814  # Test a repos->repos diff while within the moved directory
1815  exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff',
1816                                                            '-r', '1:2')
1817
1818  if check_diff_output(diff_output, 'pi', 'A') :
1819    raise svntest.Failure
1820
1821
1822#----------------------------------------------------------------------
1823def diff_property_changes_to_base(sbox):
1824  "diff to BASE with local property mods"
1825
1826  sbox.build()
1827  wc_dir = sbox.wc_dir
1828
1829  expected_output_r1_r2 = [
1830    "\n",
1831    "Property changes on: A\n",
1832    "___________________________________________________________________\n",
1833    "Added: dirprop\n",
1834    "   + r2value\n",
1835    "\n",
1836    "\n",
1837    "Property changes on: iota\n",
1838    "___________________________________________________________________\n",
1839    "Added: fileprop\n",
1840    "   + r2value\n",
1841    "\n" ]
1842
1843  expected_output_r2_r1 = list(expected_output_r1_r2)
1844  expected_output_r2_r1[3] = expected_output_r2_r1[3].replace("Added",
1845                                                              "Deleted")
1846  expected_output_r2_r1[4] = "   - r2value\n"
1847  expected_output_r2_r1[9] = expected_output_r2_r1[9].replace("Added",
1848                                                              "Deleted")
1849  expected_output_r2_r1[10] = "   - r2value\n"
1850
1851
1852  os.chdir(sbox.wc_dir)
1853
1854  svntest.actions.run_and_verify_svn(None, None, [],
1855                                     'propset',
1856                                     'fileprop', 'r2value', 'iota')
1857
1858  svntest.actions.run_and_verify_svn(None, None, [],
1859                                     'propset',
1860                                     'dirprop', 'r2value', 'A')
1861
1862  svntest.actions.run_and_verify_svn(None, None, [],
1863                                     'ci', '-m', 'empty-msg')
1864
1865  # Check that forward and reverse repos-repos diffs are as expected.
1866  expected = svntest.verify.UnorderedOutput(expected_output_r1_r2)
1867  svntest.actions.run_and_verify_svn(None, expected, [],
1868                                     'diff', '-r', '1:2')
1869
1870  expected = svntest.verify.UnorderedOutput(expected_output_r2_r1)
1871  svntest.actions.run_and_verify_svn(None, expected, [],
1872                                     'diff', '-r', '2:1')
1873
1874  # Now check repos->WORKING, repos->BASE, and BASE->repos.
1875  # (BASE is r1, and WORKING has no local mods, so this should produce
1876  # the same output as above).
1877  expected = svntest.verify.UnorderedOutput(expected_output_r1_r2)
1878  svntest.actions.run_and_verify_svn(None, expected, [],
1879                                     'diff', '-r', '1')
1880
1881  svntest.actions.run_and_verify_svn(None, expected, [],
1882                                     'diff', '-r', '1:BASE')
1883
1884  expected = svntest.verify.UnorderedOutput(expected_output_r2_r1)
1885  svntest.actions.run_and_verify_svn(None, expected, [],
1886                                     'diff', '-r', 'BASE:1')
1887
1888  # Modify some properties.
1889  svntest.actions.run_and_verify_svn(None, None, [],
1890                                     'propset',
1891                                     'fileprop', 'workingvalue', 'iota')
1892
1893  svntest.actions.run_and_verify_svn(None, None, [],
1894                                     'propset',
1895                                     'dirprop', 'workingvalue', 'A')
1896
1897  svntest.actions.run_and_verify_svn(None, None, [],
1898                                     'propset',
1899                                     'fileprop', 'workingvalue', 'A/mu')
1900
1901  # Check that the earlier diffs against BASE are unaffected by the
1902  # presence of local mods.
1903  expected = svntest.verify.UnorderedOutput(expected_output_r1_r2)
1904  svntest.actions.run_and_verify_svn(None, expected, [],
1905                                     'diff', '-r', '1:BASE')
1906
1907  expected = svntest.verify.UnorderedOutput(expected_output_r2_r1)
1908  svntest.actions.run_and_verify_svn(None, expected, [],
1909                                     'diff', '-r', 'BASE:1')
1910
1911def diff_schedule_delete(sbox):
1912  "scheduled deleted"
1913
1914  sbox.build()
1915
1916  expected_output_r2_working = make_diff_header("foo", "revision 2",
1917                                                "working copy") + [
1918  "@@ -1 +0,0 @@\n",
1919  "-xxx\n"
1920  ]
1921
1922  expected_output_r2_base = make_diff_header("foo", "revision 2",
1923                                                "working copy") + [
1924  "@@ -1 +1,2 @@\n",
1925  " xxx\n",
1926  "+yyy\n"
1927  ]
1928  expected_output_base_r2 = make_diff_header("foo", "working copy",
1929                                                "revision 2") + [
1930  "@@ -1,2 +1 @@\n",
1931  " xxx\n",
1932  "-yyy\n"
1933  ]
1934
1935  expected_output_r1_base = make_diff_header("foo", "revision 0",
1936                                                "revision 3") + [
1937  "@@ -0,0 +1,2 @@\n",
1938  "+xxx\n",
1939  "+yyy\n"
1940  ]
1941  expected_output_base_r1 = make_diff_header("foo", "working copy",
1942                                                "revision 1") + [
1943  "@@ -1,2 +0,0 @@\n",
1944  "-xxx\n",
1945  "-yyy\n"
1946  ]
1947  expected_output_base_working = expected_output_base_r1[:]
1948  expected_output_base_working[2] = "--- foo\t(revision 3)\n"
1949  expected_output_base_working[3] = "+++ foo\t(working copy)\n"
1950
1951  wc_dir = sbox.wc_dir
1952  os.chdir(wc_dir)
1953
1954  svntest.main.file_append('foo', "xxx\n")
1955  svntest.main.run_svn(None, 'add', 'foo')
1956  svntest.main.run_svn(None,
1957                       'ci', '-m', 'log msg r2')
1958
1959  svntest.main.file_append('foo', "yyy\n")
1960  svntest.main.run_svn(None,
1961                       'ci', '-m', 'log msg r3')
1962
1963  # Update everyone's BASE to r3, and mark 'foo' as schedule-deleted.
1964  svntest.main.run_svn(None,
1965                       'up')
1966  svntest.main.run_svn(None, 'rm', 'foo')
1967
1968  # A file marked as schedule-delete should act as if were not present
1969  # in WORKING, but diffs against BASE should remain unaffected.
1970
1971  # 1. repos-wc diff: file not present in repos.
1972  svntest.actions.run_and_verify_svn(None, [], [],
1973                                     'diff', '-r', '1')
1974  svntest.actions.run_and_verify_svn(None, expected_output_r1_base, [],
1975                                     'diff', '-r', '1:BASE')
1976  svntest.actions.run_and_verify_svn(None, expected_output_base_r1, [],
1977                                     'diff', '-r', 'BASE:1')
1978
1979  # 2. repos-wc diff: file present in repos.
1980  svntest.actions.run_and_verify_svn(None, expected_output_r2_working, [],
1981                                     'diff', '-r', '2')
1982  svntest.actions.run_and_verify_svn(None, expected_output_r2_base, [],
1983                                     'diff', '-r', '2:BASE')
1984  svntest.actions.run_and_verify_svn(None, expected_output_base_r2, [],
1985                                     'diff', '-r', 'BASE:2')
1986
1987  # 3. wc-wc diff.
1988  svntest.actions.run_and_verify_svn(None, expected_output_base_working, [],
1989                                     'diff')
1990
1991#----------------------------------------------------------------------
1992def diff_mime_type_changes(sbox):
1993  "repos-wc diffs with local svn:mime-type prop mods"
1994
1995  sbox.build()
1996
1997  expected_output_r1_wc = make_diff_header("iota", "revision 1",
1998                                                "working copy") + [
1999    "@@ -1 +1,2 @@\n",
2000    " This is the file 'iota'.\n",
2001    "+revision 2 text.\n" ]
2002
2003  expected_output_wc_r1 = make_diff_header("iota", "working copy",
2004                                                "revision 1") + [
2005    "@@ -1,2 +1 @@\n",
2006    " This is the file 'iota'.\n",
2007    "-revision 2 text.\n" ]
2008
2009
2010  os.chdir(sbox.wc_dir)
2011
2012  # Append some text to iota (r2).
2013  svntest.main.file_append('iota', "revision 2 text.\n")
2014
2015  svntest.actions.run_and_verify_svn(None, None, [],
2016                                     'ci', '-m', 'log_msg')
2017
2018  # Check that forward and reverse repos-BASE diffs are as expected.
2019  svntest.actions.run_and_verify_svn(None, expected_output_r1_wc, [],
2020                                     'diff', '-r', '1:BASE')
2021
2022  svntest.actions.run_and_verify_svn(None, expected_output_wc_r1, [],
2023                                     'diff', '-r', 'BASE:1')
2024
2025  # Mark iota as a binary file in the working copy.
2026  svntest.actions.run_and_verify_svn(None, None, [],
2027                                     'propset', 'svn:mime-type',
2028                                     'application/octet-stream', 'iota')
2029
2030  # Check that the earlier diffs against BASE are unaffected by the
2031  # presence of local svn:mime-type property mods.
2032  svntest.actions.run_and_verify_svn(None, expected_output_r1_wc, [],
2033                                     'diff', '-r', '1:BASE')
2034
2035  svntest.actions.run_and_verify_svn(None, expected_output_wc_r1, [],
2036                                     'diff', '-r', 'BASE:1')
2037
2038  # Commit the change (r3) (so that BASE has the binary MIME type), then
2039  # mark iota as a text file again in the working copy.
2040  svntest.actions.run_and_verify_svn(None, None, [],
2041                                     'ci', '-m', 'log_msg')
2042  svntest.actions.run_and_verify_svn(None, None, [],
2043                                     'propdel', 'svn:mime-type', 'iota')
2044
2045  # Now diffs against BASE will fail, but diffs against WORKNG should be
2046  # fine.
2047  svntest.actions.run_and_verify_svn(None, expected_output_r1_wc, [],
2048                                     'diff', '-r', '1')
2049
2050
2051#----------------------------------------------------------------------
2052# Test a repos-WORKING diff, with different versions of the same property
2053# at repository, BASE, and WORKING.
2054def diff_prop_change_local_propmod(sbox):
2055  "diff a property change plus a local prop edit"
2056
2057  sbox.build()
2058
2059  expected_output_r2_wc = [
2060    "\n",
2061    "Property changes on: A\n",
2062    "___________________________________________________________________\n",
2063    "Modified: dirprop\n",
2064    "   - r2value\n",
2065    "   + workingvalue\n",
2066    "Added: newdirprop\n",
2067    "   + newworkingvalue\n",
2068    "\n",
2069    "\n",
2070    "Property changes on: iota\n",
2071    "___________________________________________________________________\n",
2072    "Modified: fileprop\n",
2073    "   - r2value\n",
2074    "   + workingvalue\n",
2075    "Added: newfileprop\n",
2076    "   + newworkingvalue\n",
2077    "\n" ]
2078
2079  os.chdir(sbox.wc_dir)
2080
2081  # Set a property on A/ and iota, and commit them (r2).
2082  svntest.actions.run_and_verify_svn(None, None, [],
2083                                     'propset', 'dirprop',
2084                                     'r2value', 'A')
2085  svntest.actions.run_and_verify_svn(None, None, [],
2086                                     'propset', 'fileprop',
2087                                     'r2value', 'iota')
2088  svntest.actions.run_and_verify_svn(None, None, [],
2089                                     'ci', '-m', 'log_msg')
2090
2091  # Change the property values on A/ and iota, and commit them (r3).
2092  svntest.actions.run_and_verify_svn(None, None, [],
2093                                     'propset', 'dirprop',
2094                                     'r3value', 'A')
2095  svntest.actions.run_and_verify_svn(None, None, [],
2096                                     'propset', 'fileprop',
2097                                     'r3value', 'iota')
2098  svntest.actions.run_and_verify_svn(None, None, [],
2099                                     'ci', '-m', 'log_msg')
2100
2101  # Finally, change the property values one last time.
2102  svntest.actions.run_and_verify_svn(None, None, [],
2103                                     'propset', 'dirprop',
2104                                     'workingvalue', 'A')
2105  svntest.actions.run_and_verify_svn(None, None, [],
2106                                     'propset', 'fileprop',
2107                                     'workingvalue', 'iota')
2108  # And also add some properties that only exist in WORKING.
2109  svntest.actions.run_and_verify_svn(None, None, [],
2110                                     'propset', 'newdirprop',
2111                                     'newworkingvalue', 'A')
2112  svntest.actions.run_and_verify_svn(None, None, [],
2113                                     'propset', 'newfileprop',
2114                                     'newworkingvalue', 'iota')
2115
2116  # Now, if we diff r2 to WORKING, we've got three property values
2117  # to consider: r2value (in the repository), r3value (in BASE), and
2118  # workingvalue (in WORKING).
2119  # The diff should only show the r2->WORKING change.
2120  #
2121  # We also need to make sure that the 'new' (WORKING only) properties
2122  # are included in the output, since they won't be listed in a simple
2123  # BASE->r2 diff.
2124  expected = svntest.verify.UnorderedOutput(expected_output_r2_wc)
2125  svntest.actions.run_and_verify_svn(None, expected, [],
2126                                     'diff', '-r', '2')
2127
2128
2129#----------------------------------------------------------------------
2130# repos->wc and BASE->repos diffs that add files or directories with
2131# properties should show the added properties.
2132def diff_repos_wc_add_with_props(sbox):
2133  "repos-wc diff showing added entries with props"
2134
2135  sbox.build()
2136
2137  expected_output_r1_r3 = make_diff_header("foo", "revision 0",
2138                                                "revision 3") + [
2139    "@@ -0,0 +1 @@\n",
2140    "+content\n",
2141    "\n",
2142    "Property changes on: foo\n",
2143    "___________________________________________________________________\n",
2144    "Added: propname\n",
2145    "   + propvalue\n",
2146    "\n",
2147    "\n",
2148    "Property changes on: X\n",
2149    "___________________________________________________________________\n",
2150    "Added: propname\n",
2151    "   + propvalue\n",
2152    "\n",
2153  ] + make_diff_header("X/bar", "revision 0", "revision 3") + [
2154    "@@ -0,0 +1 @@\n",
2155    "+content\n",
2156    "\n",
2157    "Property changes on: " + os.path.join('X', 'bar') + "\n",
2158    "___________________________________________________________________\n",
2159    "Added: propname\n",
2160    "   + propvalue\n",
2161    "\n" ]
2162  # The output from the BASE->repos diff is the same content, but in a
2163  # different order.
2164  expected_output_r1_r3_a = expected_output_r1_r3[:12] + \
2165    expected_output_r1_r3[18:] + expected_output_r1_r3[12:18]
2166
2167  os.chdir(sbox.wc_dir)
2168
2169  # Create directory X, file foo, and file X/bar, and commit them (r2).
2170  os.makedirs('X')
2171  svntest.main.file_append('foo', "content\n")
2172  svntest.main.file_append(os.path.join('X', 'bar'), "content\n")
2173  svntest.actions.run_and_verify_svn(None, None, [],
2174                                     'add', 'X', 'foo')
2175  svntest.actions.run_and_verify_svn(None, None, [],
2176                                     'ci', '-m', 'log_msg')
2177
2178  # Set a property on all three items, and commit them (r3).
2179  svntest.actions.run_and_verify_svn(None, None, [],
2180                                     'propset', 'propname',
2181                                     'propvalue', 'X', 'foo',
2182                                     os.path.join('X', 'bar'))
2183  svntest.actions.run_and_verify_svn(None, None, [],
2184                                     'ci', '-m', 'log_msg')
2185
2186  # Now, if we diff r1 to WORKING or BASE, we should see the content
2187  # addition for foo and X/bar, and property additions for all three.
2188  svntest.actions.run_and_verify_svn(None, expected_output_r1_r3, [],
2189                                     'diff', '-r', '1')
2190  svntest.actions.run_and_verify_svn(None, expected_output_r1_r3, [],
2191                                     'diff', '-r', '1:BASE')
2192
2193  # Update the BASE and WORKING revisions to r1.
2194  svntest.actions.run_and_verify_svn(None, None, [],
2195                                     'up', '-r', '1')
2196
2197  # If we diff BASE to r3, we should see the same output as above.
2198  svntest.actions.run_and_verify_svn(None, expected_output_r1_r3_a, [],
2199                                     'diff', '-r', 'BASE:3')
2200
2201
2202#----------------------------------------------------------------------
2203# repos-wc diffs on a non-recursively checked out wc that would normally
2204# (if recursively checked out) include a directory that is not present in
2205# the repos version should not segfault.
2206def diff_nonrecursive_checkout_deleted_dir(sbox):
2207  "nonrecursive diff + deleted directories"
2208  sbox.build()
2209
2210  url = sbox.repo_url
2211  A_url = url + '/A'
2212  A_prime_url = url + '/A_prime'
2213
2214  svntest.main.run_svn(None,
2215                       'cp', '-m', 'log msg', A_url, A_prime_url)
2216
2217  svntest.main.run_svn(None,
2218                       'mkdir', '-m', 'log msg', A_prime_url + '/Q')
2219
2220  wc = sbox.add_wc_path('wc')
2221
2222  svntest.main.run_svn(None,
2223                       'co', '-N', A_prime_url, wc)
2224
2225  os.chdir(wc)
2226
2227  # We don't particular care about the output here, just that it doesn't
2228  # segfault.
2229  svntest.main.run_svn(None,
2230                       'diff', '-r1')
2231
2232
2233#----------------------------------------------------------------------
2234# repos->WORKING diffs that include directories with local mods that are
2235# not present in the repos version should work as expected (and not, for
2236# example, show an extraneous BASE->WORKING diff for the added directory
2237# after the repos->WORKING output).
2238def diff_repos_working_added_dir(sbox):
2239  "repos->WORKING diff showing added modifed dir"
2240
2241  sbox.build()
2242
2243  expected_output_r1_BASE = make_diff_header("X/bar", "revision 0",
2244                                                "revision 2") + [
2245    "@@ -0,0 +1 @@\n",
2246    "+content\n" ]
2247  expected_output_r1_WORKING = make_diff_header("X/bar", "revision 0",
2248                                                "revision 2") + [
2249    "@@ -0,0 +1,2 @@\n",
2250    "+content\n",
2251    "+more content\n" ]
2252
2253  os.chdir(sbox.wc_dir)
2254
2255  # Create directory X and file X/bar, and commit them (r2).
2256  os.makedirs('X')
2257  svntest.main.file_append(os.path.join('X', 'bar'), "content\n")
2258  svntest.actions.run_and_verify_svn(None, None, [],
2259                                     'add', 'X')
2260  svntest.actions.run_and_verify_svn(None, None, [],
2261                                     'ci', '-m', 'log_msg')
2262
2263  # Make a local modification to X/bar.
2264  svntest.main.file_append(os.path.join('X', 'bar'), "more content\n")
2265
2266  # Now, if we diff r1 to WORKING or BASE, we should see the content
2267  # addition for X/bar, and (for WORKING) the local modification.
2268  svntest.actions.run_and_verify_svn(None, expected_output_r1_BASE, [],
2269                                     'diff', '-r', '1:BASE')
2270  svntest.actions.run_and_verify_svn(None, expected_output_r1_WORKING, [],
2271                                     'diff', '-r', '1')
2272
2273
2274#----------------------------------------------------------------------
2275# A base->repos diff of a moved file used to output an all-lines-deleted diff
2276def diff_base_repos_moved(sbox):
2277  "base->repos diff of moved file"
2278
2279  sbox.build()
2280
2281  os.chdir(sbox.wc_dir)
2282
2283  oldfile = 'iota'
2284  newfile = 'kappa'
2285
2286  # Move, modify and commit a file
2287  svntest.main.run_svn(None, 'mv', oldfile, newfile)
2288  svntest.main.file_write(newfile, "new content\n")
2289  svntest.actions.run_and_verify_svn(None, None, [],
2290                                     'ci', '-m', '')
2291
2292  # Check that a base->repos diff shows deleted and added lines.
2293  # It's not clear whether we expect a file-change diff or
2294  # a file-delete plus file-add.  The former is currently produced if we
2295  # explicitly request a diff of the file itself, and the latter if we
2296  # request a tree diff which just happens to contain the file.
2297  exit_code, out, err = svntest.actions.run_and_verify_svn(
2298    None, svntest.verify.AnyOutput, [], 'diff', '-rBASE:1', newfile)
2299
2300  if check_diff_output(out, newfile, 'M'):
2301    raise svntest.Failure
2302
2303  # Diff should recognise that the item's name has changed, and mention both
2304  # the current and the old name in parentheses, in the right order.
2305  if (out[2][:3] != '---' or out[2].find('kappa)') == -1 or
2306      out[3][:3] != '+++' or out[3].find('iota)') == -1):
2307    raise svntest.Failure
2308
2309
2310#----------------------------------------------------------------------
2311# A diff of an added file within an added directory should work, and
2312# shouldn't produce an error.
2313def diff_added_subtree(sbox):
2314  "wc->repos diff of added subtree"
2315
2316  sbox.build()
2317
2318  os.chdir(sbox.wc_dir)
2319
2320  # Roll the wc back to r0 (i.e. an empty wc).
2321  svntest.actions.run_and_verify_svn(None, None, [],
2322                                     'up', '-r0')
2323
2324  # We shouldn't get any errors when we request a diff showing the
2325  # addition of the greek tree.  The diff contains additions of files
2326  # and directories with parents that don't currently exist in the wc,
2327  # which is what we're testing here.
2328  svntest.actions.run_and_verify_svn(None, svntest.verify.AnyOutput, [],
2329                                     'diff', '-r', 'BASE:1')
2330
2331#----------------------------------------------------------------------
2332def basic_diff_summarize(sbox):
2333  "basic diff summarize"
2334
2335  sbox.build()
2336  wc_dir = sbox.wc_dir
2337
2338  # A content modification.
2339  svntest.main.file_append(os.path.join(wc_dir, "A", "mu"), "New mu content")
2340
2341  # A prop modification.
2342  svntest.main.run_svn(None,
2343                       "propset", "prop", "val",
2344                       os.path.join(wc_dir, 'iota'))
2345
2346  # Both content and prop mods.
2347  tau_path = os.path.join(wc_dir, "A", "D", "G", "tau")
2348  svntest.main.file_append(tau_path, "tautau")
2349  svntest.main.run_svn(None,
2350                       "propset", "prop", "val", tau_path)
2351
2352  # A file addition.
2353  newfile_path = os.path.join(wc_dir, 'newfile')
2354  svntest.main.file_append(newfile_path, 'newfile')
2355  svntest.main.run_svn(None, 'add', newfile_path)
2356
2357  # A file deletion.
2358  svntest.main.run_svn(None, "delete", os.path.join(wc_dir, 'A', 'B',
2359                                                    'lambda'))
2360
2361  expected_output = svntest.wc.State(wc_dir, {
2362    'A/mu': Item(verb='Sending'),
2363    'iota': Item(verb='Sending'),
2364    'newfile': Item(verb='Adding'),
2365    'A/D/G/tau': Item(verb='Sending'),
2366    'A/B/lambda': Item(verb='Deleting'),
2367    })
2368  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
2369  expected_status.add({
2370    'newfile': Item(status='  ', wc_rev=2),
2371    })
2372  expected_status.tweak("A/mu", "iota", "A/D/G/tau", 'newfile', wc_rev=2)
2373  expected_status.remove("A/B/lambda")
2374
2375  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
2376                                        expected_status, None, wc_dir)
2377
2378  # Get the differences between two versions of a file.
2379  expected_diff = svntest.wc.State(wc_dir, {
2380    'iota': Item(status=' M'),
2381    })
2382  svntest.actions.run_and_verify_diff_summarize(expected_diff, None,
2383                                                None, None, None, None,
2384                                                os.path.join(wc_dir, 'iota'),
2385                                                '-c2')
2386
2387  # Get the differences between two versions of an entire directory.
2388  expected_diff = svntest.wc.State(wc_dir, {
2389    'A/mu': Item(status='M '),
2390    'iota': Item(status=' M'),
2391    'A/D/G/tau': Item(status='MM'),
2392    'newfile': Item(status='A '),
2393    'A/B/lambda': Item(status='D '),
2394    })
2395  svntest.actions.run_and_verify_diff_summarize(expected_diff, None,
2396                                                None, None, None, None,
2397                                                wc_dir, '-r1:2')
2398
2399def diff_weird_author(sbox):
2400  "diff with svn:author that has < in it"
2401
2402  sbox.build()
2403
2404  svntest.actions.enable_revprop_changes(sbox.repo_dir)
2405
2406  svntest.main.file_write(os.path.join(sbox.wc_dir, 'A', 'mu'),
2407                          "new content\n")
2408
2409  expected_output = svntest.wc.State(sbox.wc_dir, {
2410    'A/mu': Item(verb='Sending'),
2411    })
2412
2413  expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1)
2414  expected_status.tweak("A/mu", wc_rev=2)
2415
2416  svntest.actions.run_and_verify_commit(sbox.wc_dir, expected_output,
2417                                        expected_status, None, sbox.wc_dir)
2418
2419  svntest.main.run_svn(None,
2420                       "propset", "--revprop", "-r", "2", "svn:author",
2421                       "J. Random <jrandom@example.com>", sbox.repo_url)
2422
2423  svntest.actions.run_and_verify_svn(None,
2424                                     ["J. Random <jrandom@example.com>\n"],
2425                                     [],
2426                                     "pget", "--revprop", "-r" "2",
2427                                     "svn:author", sbox.repo_url)
2428
2429  expected_output = make_diff_header("A/mu", "revision 1", "revision 2") + [
2430    "@@ -1 +1 @@\n",
2431    "-This is the file 'mu'.\n",
2432    "+new content\n"
2433  ]
2434
2435  svntest.actions.run_and_verify_svn(None, expected_output, [],
2436                                     'diff', '-r1:2', sbox.repo_url)
2437
2438# test for issue 2121, use -x -w option for ignoring whitespace during diff
2439def diff_ignore_whitespace(sbox):
2440  "ignore whitespace when diffing"
2441
2442  sbox.build()
2443  wc_dir = sbox.wc_dir
2444
2445  file_name = "iota"
2446  file_path = os.path.join(wc_dir, file_name)
2447
2448  svntest.main.file_write(file_path,
2449                          "Aa\n"
2450                          "Bb\n"
2451                          "Cc\n")
2452  expected_output = svntest.wc.State(wc_dir, {
2453      'iota' : Item(verb='Sending'),
2454      })
2455  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
2456                                        None, None, wc_dir)
2457
2458  # only whitespace changes, should return no changes
2459  svntest.main.file_write(file_path,
2460                          " A  a   \n"
2461                          "   B b  \n"
2462                          "    C    c    \n")
2463
2464  svntest.actions.run_and_verify_svn(None, [], [],
2465                                     'diff', '-x', '-w', file_path)
2466
2467  # some changes + whitespace
2468  svntest.main.file_write(file_path,
2469                          " A  a   \n"
2470                          "Xxxx X\n"
2471                          "   Bb b  \n"
2472                          "    C    c    \n")
2473  expected_output = make_diff_header(file_path, "revision 2",
2474                                     "working copy") + [
2475    "@@ -1,3 +1,4 @@\n",
2476    " Aa\n",
2477    "-Bb\n",
2478    "+Xxxx X\n",
2479    "+   Bb b  \n",
2480    " Cc\n" ]
2481
2482  svntest.actions.run_and_verify_svn(None, expected_output, [],
2483                                     'diff', '-x', '-w', file_path)
2484
2485def diff_ignore_eolstyle(sbox):
2486  "ignore eol styles when diffing"
2487
2488  sbox.build()
2489  wc_dir = sbox.wc_dir
2490
2491  file_name = "iota"
2492  file_path = os.path.join(wc_dir, file_name)
2493
2494  svntest.main.file_write(file_path,
2495                          "Aa\n"
2496                          "Bb\n"
2497                          "Cc\n")
2498  expected_output = svntest.wc.State(wc_dir, {
2499      'iota' : Item(verb='Sending'),
2500      })
2501  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
2502                                        None, None, wc_dir)
2503
2504  # commit only eol changes
2505  svntest.main.file_write(file_path,
2506                          "Aa\r"
2507                          "Bb\r"
2508                          "Cc")
2509
2510  expected_output = make_diff_header(file_path, "revision 2",
2511                                     "working copy") + [
2512    "@@ -1,3 +1,3 @@\n",
2513    " Aa\n",
2514    " Bb\n",
2515    "-Cc\n",
2516    "+Cc\n",
2517    "\ No newline at end of file\n" ]
2518
2519  svntest.actions.run_and_verify_svn(None, expected_output, [],
2520                                     'diff', '-x', '--ignore-eol-style',
2521                                     file_path)
2522
2523# test for issue 2600, diff revision of a file in a renamed folder
2524def diff_in_renamed_folder(sbox):
2525  "diff a revision of a file in a renamed folder"
2526
2527  sbox.build()
2528  wc_dir = sbox.wc_dir
2529
2530  C_path = os.path.join(wc_dir, "A", "C")
2531  D_path = os.path.join(wc_dir, "A", "D")
2532  kappa_path = os.path.join(D_path, "C", "kappa")
2533
2534  # add a new file to a renamed (moved in this case) folder.
2535  svntest.main.run_svn(None, 'mv', C_path, D_path)
2536
2537  svntest.main.file_append(kappa_path, "this is file kappa.\n")
2538  svntest.main.run_svn(None, 'add', kappa_path)
2539
2540  expected_output = svntest.wc.State(wc_dir, {
2541      'A/C' : Item(verb='Deleting'),
2542      'A/D/C' : Item(verb='Adding'),
2543      'A/D/C/kappa' : Item(verb='Adding'),
2544  })
2545  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
2546                                        None, None, wc_dir)
2547
2548  expected_output = svntest.wc.State(wc_dir, {
2549      'A/D/C/kappa' : Item(verb='Sending'),
2550  })
2551
2552  # modify the file two times so we have something to diff.
2553  for i in range(3, 5):
2554    svntest.main.file_append(kappa_path, str(i) + "\n")
2555    svntest.actions.run_and_verify_commit(wc_dir, expected_output,
2556                                          None, None, wc_dir)
2557
2558  expected_output = make_diff_header(kappa_path, "revision 3",
2559                                     "revision 4") + [
2560    "@@ -1,2 +1,3 @@\n",
2561    " this is file kappa.\n",
2562    " 3\n",
2563    "+4\n"
2564  ]
2565
2566  svntest.actions.run_and_verify_svn(None, expected_output, [],
2567                                     'diff', '-r3:4', kappa_path)
2568
2569def diff_with_depth(sbox):
2570  "test diffs at various depths"
2571
2572  sbox.build()
2573
2574  diff = [
2575    "\n",
2576    "Property changes on: .\n",
2577    "___________________________________________________________________\n",
2578    "Added: foo1\n",
2579    "   + bar1\n",
2580    "\n",
2581    "\n",
2582    "Property changes on: iota\n",
2583    "___________________________________________________________________\n",
2584    "Added: foo2\n",
2585    "   + bar2\n",
2586    "\n",
2587    "\n",
2588    "Property changes on: A\n",
2589    "___________________________________________________________________\n",
2590    "Added: foo3\n",
2591    "   + bar3\n",
2592    "\n",
2593    "\n",
2594    "Property changes on: " + os.path.join('A', 'B') + "\n",
2595    "___________________________________________________________________\n",
2596    "Added: foo4\n",
2597    "   + bar4\n",
2598    "\n" ]
2599
2600  expected_empty = svntest.verify.UnorderedOutput(diff[:6])
2601  expected_files = svntest.verify.UnorderedOutput(diff[:12])
2602  expected_immediates = svntest.verify.UnorderedOutput(diff[:18])
2603  expected_infinity = svntest.verify.UnorderedOutput(diff[:])
2604
2605  os.chdir(sbox.wc_dir)
2606
2607  svntest.actions.run_and_verify_svn(None, None, [],
2608                                     'propset',
2609                                     'foo1', 'bar1', '.')
2610  svntest.actions.run_and_verify_svn(None, None, [],
2611                                     'propset',
2612                                     'foo2', 'bar2', 'iota')
2613  svntest.actions.run_and_verify_svn(None, None, [],
2614                                     'propset',
2615                                     'foo3', 'bar3', 'A')
2616  svntest.actions.run_and_verify_svn(None, None, [],
2617                                     'propset',
2618                                     'foo4', 'bar4', os.path.join('A', 'B'))
2619
2620  # Test wc-wc diff.
2621  svntest.actions.run_and_verify_svn(None, expected_empty, [],
2622                                     'diff', '--depth', 'empty')
2623  svntest.actions.run_and_verify_svn(None, expected_files, [],
2624                                     'diff', '--depth', 'files')
2625  svntest.actions.run_and_verify_svn(None, expected_immediates, [],
2626                                     'diff', '--depth', 'immediates')
2627  svntest.actions.run_and_verify_svn(None, expected_infinity, [],
2628                                     'diff', '--depth', 'infinity')
2629
2630  # Commit the changes.
2631  svntest.actions.run_and_verify_svn(None, None, [],
2632                                     'ci', '-m', '')
2633
2634  # Test repos-repos diff.  Reuse the expected outputs from above.
2635  svntest.actions.run_and_verify_svn(None, expected_empty, [],
2636                                     'diff', '-c2', '--depth', 'empty')
2637  svntest.actions.run_and_verify_svn(None, expected_files, [],
2638                                     'diff', '-c2', '--depth', 'files')
2639  svntest.actions.run_and_verify_svn(None, expected_immediates, [],
2640                                     'diff', '-c2', '--depth', 'immediates')
2641  svntest.actions.run_and_verify_svn(None, expected_infinity, [],
2642                                     'diff', '-c2', '--depth', 'infinity')
2643
2644  diff_wc_repos = [
2645    "\n",
2646    "Property changes on: .\n",
2647    "___________________________________________________________________\n",
2648    "Modified: foo1\n",
2649    "   - bar1\n",
2650    "   + baz1\n",
2651    "\n",
2652    "\n",
2653    "Property changes on: iota\n",
2654    "___________________________________________________________________\n",
2655    "Modified: foo2\n",
2656    "   - bar2\n",
2657    "   + baz2\n",
2658    "\n",
2659    "\n",
2660    "Index: iota\n",
2661    "===================================================================\n",
2662    "--- iota\t(revision 2)\n",
2663    "+++ iota\t(working copy)\n",
2664    "@@ -1 +1,2 @@\n",
2665    " This is the file 'iota'.\n",
2666    "+new text\n",
2667    "Property changes on: A\n",
2668    "___________________________________________________________________\n",
2669    "Modified: foo3\n",
2670    "   - bar3\n",
2671    "   + baz3\n",
2672    "\n",
2673    "\n",
2674    "Property changes on: " + os.path.join('A', 'B') + "\n",
2675    "___________________________________________________________________\n",
2676    "Modified: foo4\n",
2677    "   - bar4\n",
2678    "   + baz4\n",
2679    "\n",
2680    "Index: A/mu\n",
2681    "===================================================================\n",
2682    "--- A/mu\t(revision 1)\n",
2683    "+++ A/mu\t(working copy)\n",
2684    "@@ -1 +1,2 @@\n",
2685    " This is the file 'mu'.\n",
2686    "+new text\n" ]
2687
2688  expected_empty = svntest.verify.UnorderedOutput(diff_wc_repos[:7])
2689  expected_files = svntest.verify.UnorderedOutput(diff_wc_repos[1:22])
2690  expected_immediates = svntest.verify.UnorderedOutput(diff_wc_repos[1:29])
2691  expected_infinity = svntest.verify.UnorderedOutput(diff_wc_repos[:])
2692
2693  svntest.actions.run_and_verify_svn(None, None, [],
2694                                     'up', '-r1')
2695
2696  svntest.actions.run_and_verify_svn(None, None, [],
2697                                     'propset',
2698                                     'foo1', 'baz1', '.')
2699  svntest.actions.run_and_verify_svn(None, None, [],
2700                                     'propset',
2701                                     'foo2', 'baz2', 'iota')
2702  svntest.actions.run_and_verify_svn(None, None, [],
2703                                     'propset',
2704                                     'foo3', 'baz3', 'A')
2705  svntest.actions.run_and_verify_svn(None, None, [],
2706                                     'propset',
2707                                     'foo4', 'baz4', os.path.join('A', 'B'))
2708  svntest.main.file_append(os.path.join('A', 'mu'), "new text\n")
2709  svntest.main.file_append('iota', "new text\n")
2710
2711  # Test wc-repos diff.
2712  svntest.actions.run_and_verify_svn(None, expected_empty, [],
2713                                     'diff', '-rHEAD', '--depth', 'empty')
2714  svntest.actions.run_and_verify_svn(None, expected_files, [],
2715                                     'diff', '-rHEAD', '--depth', 'files')
2716  svntest.actions.run_and_verify_svn(None, expected_immediates, [],
2717                                     'diff', '-rHEAD', '--depth', 'immediates')
2718  svntest.actions.run_and_verify_svn(None, expected_infinity, [],
2719                                     'diff', '-rHEAD', '--depth', 'infinity')
2720
2721# test for issue 2920: ignore eol-style on empty lines
2722def diff_ignore_eolstyle_empty_lines(sbox):
2723  "ignore eol styles when diffing empty lines"
2724
2725  sbox.build()
2726  wc_dir = sbox.wc_dir
2727
2728  file_name = "iota"
2729  file_path = os.path.join(wc_dir, file_name)
2730
2731  svntest.main.file_write(file_path,
2732                          "Aa\n"
2733                          "\n"
2734                          "Bb\n"
2735                          "\n"
2736                          "Cc\n")
2737  expected_output = svntest.wc.State(wc_dir, {
2738      'iota' : Item(verb='Sending'),
2739      })
2740  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
2741                                        None, None, wc_dir)
2742
2743  # sleep to guarantee timestamp change
2744  time.sleep(1)
2745
2746  # commit only eol changes
2747  svntest.main.file_write(file_path,
2748                          "Aa\012"
2749                          "\012"
2750                          "Bb\r"
2751                          "\r"
2752                          "Cc\012",
2753                          mode="wb")
2754
2755  svntest.actions.run_and_verify_svn(None, [], [],
2756                                     'diff', '-x', '--ignore-eol-style',
2757                                     file_path)
2758
2759def diff_backward_repos_wc_copy(sbox):
2760  "backward repos->wc diff with copied file"
2761
2762  sbox.build()
2763  wc_dir = sbox.wc_dir
2764  os.chdir(wc_dir)
2765
2766  # copy a file
2767  mu_path = os.path.join('A', 'mu')
2768  mucp_path = os.path.join('A', 'mucopy')
2769  svntest.main.run_svn(None, 'cp', mu_path, mucp_path)
2770
2771  # commit r2 and update back to r1
2772  svntest.main.run_svn(None,
2773                       'ci', '-m', 'log msg')
2774  svntest.main.run_svn(None, 'up', '-r1')
2775
2776  # diff r2 against working copy
2777  diff_repos_wc = make_diff_header("A/mucopy", "revision 2", "working copy")
2778  diff_repos_wc += [
2779    "@@ -1 +0,0 @@\n",
2780    "-This is the file 'mu'.\n",
2781  ]
2782
2783  svntest.actions.run_and_verify_svn(None, diff_repos_wc, [],
2784                                     'diff', '-r' , '2')
2785
2786#----------------------------------------------------------------------
2787
2788def diff_summarize_xml(sbox):
2789  "xml diff summarize"
2790
2791  sbox.build()
2792  wc_dir = sbox.wc_dir
2793
2794  # A content modification.
2795  svntest.main.file_append(os.path.join(wc_dir, "A", "mu"), "New mu content")
2796
2797  # A prop modification.
2798  svntest.main.run_svn(None,
2799                       "propset", "prop", "val",
2800                       os.path.join(wc_dir, 'iota'))
2801
2802  # Both content and prop mods.
2803  tau_path = os.path.join(wc_dir, "A", "D", "G", "tau")
2804  svntest.main.file_append(tau_path, "tautau")
2805  svntest.main.run_svn(None,
2806                       "propset", "prop", "val", tau_path)
2807
2808  # A file addition.
2809  newfile_path = os.path.join(wc_dir, 'newfile')
2810  svntest.main.file_append(newfile_path, 'newfile')
2811  svntest.main.run_svn(None, 'add', newfile_path)
2812
2813  # A file deletion.
2814  svntest.main.run_svn(None, "delete", os.path.join(wc_dir, 'A', 'B',
2815                                                    'lambda'))
2816
2817  # A directory addition
2818  svntest.main.run_svn(None, "mkdir", os.path.join(wc_dir, 'newdir'))
2819
2820  expected_output = svntest.wc.State(wc_dir, {
2821    'A/mu': Item(verb='Sending'),
2822    'iota': Item(verb='Sending'),
2823    'newfile': Item(verb='Adding'),
2824    'A/D/G/tau': Item(verb='Sending'),
2825    'A/B/lambda': Item(verb='Deleting'),
2826    'newdir': Item(verb='Adding'),
2827    })
2828  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
2829  expected_status.add({
2830    'newfile': Item(status='  ', wc_rev=2),
2831    'newdir': Item(status='  ', wc_rev=2),
2832    })
2833  expected_status.tweak("A/mu", "iota", "A/D/G/tau", "newfile", "newdir",
2834                        wc_rev=2)
2835  expected_status.remove("A/B/lambda")
2836
2837  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
2838                                        expected_status, None, wc_dir)
2839
2840  # 1) Test --xml without --summarize
2841  svntest.actions.run_and_verify_svn(
2842    None, None, ".*--xml' option only valid with '--summarize' option",
2843    'diff', wc_dir, '--xml')
2844
2845  # 2) Test --xml on invalid revision
2846  svntest.actions.run_and_verify_diff_summarize_xml(
2847    ".*No such revision 5555555",
2848    None, wc_dir, None, None, None, '-r0:5555555', wc_dir)
2849
2850  # 3) Test working copy summarize
2851  svntest.actions.run_and_verify_diff_summarize_xml(
2852    ".*Summarizing diff can only compare repository to repository",
2853    None, wc_dir, None, None, wc_dir)
2854
2855  # 4) Test --summarize --xml on -c2
2856  paths = ['iota',]
2857  items = ['none',]
2858  kinds = ['file',]
2859  props = ['modified',]
2860
2861  svntest.actions.run_and_verify_diff_summarize_xml(
2862    [], wc_dir, paths, items, props, kinds, '-c2',
2863    os.path.join(wc_dir, 'iota'))
2864
2865  # 5) Test --summarize --xml on -r1:2
2866  paths = ['A/mu', 'iota', 'A/D/G/tau', 'newfile', 'A/B/lambda',
2867           'newdir',]
2868  items = ['modified', 'none', 'modified', 'added', 'deleted', 'added',]
2869  kinds = ['file','file','file','file','file', 'dir',]
2870  props = ['none', 'modified', 'modified', 'none', 'none', 'none',]
2871
2872  svntest.actions.run_and_verify_diff_summarize_xml(
2873    [], wc_dir, paths, items, props, kinds, '-r1:2', wc_dir)
2874
2875  # 6) Same as test #5 but ran against a URL instead of a WC path
2876  paths = ['A/mu', 'iota', 'A/D/G/tau', 'newfile', 'A/B/lambda',
2877           'newdir',]
2878  items = ['modified', 'none', 'modified', 'added', 'deleted', 'added',]
2879  kinds = ['file','file','file','file','file', 'dir',]
2880  props = ['none', 'modified', 'modified', 'none', 'none', 'none',]
2881
2882  svntest.actions.run_and_verify_diff_summarize_xml(
2883    [], sbox.repo_url, paths, items, props, kinds, '-r1:2', sbox.repo_url)
2884
2885def diff_file_depth_empty(sbox):
2886  "svn diff --depth=empty FILE_WITH_LOCAL_MODS"
2887  # The bug was that no diff output would be generated.  Check that some is.
2888  sbox.build()
2889  iota_path = os.path.join(sbox.wc_dir, 'iota')
2890  svntest.main.file_append(iota_path, "new text in iota")
2891  exit_code, out, err = svntest.main.run_svn(None, 'diff',
2892                                             '--depth', 'empty', iota_path)
2893  if err:
2894    raise svntest.Failure
2895  if len(out) < 4:
2896    raise svntest.Failure
2897
2898# This used to abort with ra_serf.
2899def diff_wrong_extension_type(sbox):
2900  "'svn diff -x wc -r#' should return error"
2901
2902  sbox.build(read_only = True)
2903  expected_error = "(.*svn: Invalid argument .* in diff options.*)|" \
2904                   "(svn: '.' is not a working copy)"
2905  svntest.actions.run_and_verify_svn(None, [], expected_error,
2906                                     'diff', '-x', sbox.wc_dir, '-r', '1')
2907
2908# Check the order of the arguments for an external diff tool
2909def diff_external_diffcmd(sbox):
2910  "svn diff --diff-cmd provides the correct arguments"
2911
2912  sbox.build(read_only = True)
2913  os.chdir(sbox.wc_dir)
2914
2915  iota_path = 'iota'
2916  svntest.main.file_append(iota_path, "new text in iota")
2917
2918  # Create a small diff mock object that prints its arguments to stdout.
2919  # (This path needs an explicit directory component to avoid searching.)
2920  diff_script_path = os.path.join('.', 'diff')
2921  # TODO: make the create function return the actual script name, and rename
2922  # it to something more generic.
2923  svntest.main.create_python_hook_script(diff_script_path, 'import sys\n'
2924    'for arg in sys.argv[1:]:\n  print arg\n')
2925  if sys.platform == 'win32':
2926    diff_script_path = "%s.bat" % diff_script_path
2927
2928  expected_output = svntest.verify.ExpectedOutput([
2929    "Index: iota\n",
2930    "===================================================================\n",
2931    "-u\n",
2932    "-L\n",
2933    "iota\t(revision 1)\n",
2934    "-L\n",
2935    "iota\t(working copy)\n",
2936    os.path.join('.svn', 'text-base', 'iota.svn-base') + "\n",
2937    "iota\n"])
2938
2939  # Check that the output of diff corresponds with the expected arguments,
2940  # in the correct order.
2941  svntest.actions.run_and_verify_svn(None, expected_output, [],
2942                                     'diff', '--diff-cmd', diff_script_path,
2943                                     iota_path)
2944
2945
2946#----------------------------------------------------------------------
2947# Diffing an unrelated repository URL against working copy with
2948# local modifications (i.e. not committed). This is issue #3295 (diff
2949# local changes against arbitrary URL@REV ignores local add).
2950
2951# Helper
2952def make_file_edit_del_add(dir):
2953  "make a file mod (M), a deletion (D) and an addition (A)."
2954  alpha = os.path.join(dir, 'B', 'E', 'alpha')
2955  beta = os.path.join(dir, 'B', 'E', 'beta')
2956  theta = os.path.join(dir, 'B', 'E', 'theta')
2957
2958  # modify alpha, remove beta and add theta.
2959  svntest.main.file_append(alpha, "Edited file alpha.\n")
2960  svntest.main.run_svn(None, 'remove', beta)
2961  svntest.main.file_append(theta, "Created file theta.\n")
2962
2963  svntest.main.run_svn(None, 'add', theta)
2964
2965
2966def diff_url_against_local_mods(sbox):
2967  "diff URL against working copy with local mods"
2968
2969  sbox.build()
2970  os.chdir(sbox.wc_dir)
2971
2972  A = 'A'
2973  A_url = sbox.repo_url + '/A'
2974
2975  # First, just make a copy.
2976  A2 = 'A2'
2977  A2_url = sbox.repo_url + '/A2'
2978
2979  svntest.actions.run_and_verify_svn(None, None, [],
2980                                     'cp', '-m', 'log msg',
2981                                     A_url, A2_url)
2982
2983  svntest.actions.run_and_verify_svn(None, None, [],
2984                                     'up')
2985
2986  # In A, add, remove and change a file, and commit.
2987  make_file_edit_del_add(A);
2988  svntest.actions.run_and_verify_svn(None, None, [],
2989                                     'ci', '-m', 'committing A')
2990
2991  # In A2, do the same changes but leave uncommitted.
2992  make_file_edit_del_add(A2);
2993
2994  # Diff URL of A against working copy of A2. Output should be empty.
2995  expected_output = []
2996  svntest.actions.run_and_verify_svn(None, expected_output, [],
2997                                     'diff', '--old', A_url, '--new', A2)
2998
2999
3000#----------------------------------------------------------------------
3001# Diff rev against working copy of a removed and locally re-added file.
3002# This is issue #1675 ("svn diff -rN added-file" has odd behavior).
3003
3004def diff_preexisting_rev_against_local_add(sbox):
3005  "diff -r1 of removed file to its local addition"
3006  sbox.build()
3007  os.chdir(sbox.wc_dir)
3008
3009  beta = os.path.join('A', 'B', 'E', 'beta')
3010
3011  # remove
3012  svntest.main.run_svn(None, 'remove', beta)
3013  svntest.actions.run_and_verify_svn(None, None, [],
3014                                     'ci', '-m', 'removing beta')
3015
3016  # re-add, without committing
3017  svntest.main.file_append(beta, "Re-created file beta.\n")
3018  svntest.main.run_svn(None, 'add', beta)
3019
3020  # diff against -r1, the diff should show both removal and re-addition
3021  exit_code, diff_output, err_output = svntest.main.run_svn(
3022                        None, 'diff', '-r1', 'A')
3023
3024  verify_expected_output(diff_output, "-This is the file 'beta'.")
3025  verify_expected_output(diff_output, "+Re-created file beta.")
3026
3027
3028########################################################################
3029#Run the tests
3030
3031
3032# list all tests here, starting with None:
3033test_list = [ None,
3034              diff_update_a_file,
3035              diff_add_a_file,
3036              diff_add_a_file_in_a_subdir,
3037              diff_replace_a_file,
3038              diff_multiple_reverse,
3039              diff_non_recursive,
3040              diff_repo_subset,
3041              diff_non_version_controlled_file,
3042              diff_pure_repository_update_a_file,
3043              diff_only_property_change,
3044              dont_diff_binary_file,
3045              diff_nonextant_urls,
3046              diff_head_of_moved_file,
3047              diff_base_to_repos,
3048              diff_deleted_in_head,
3049              diff_targets,
3050              diff_branches,
3051              diff_repos_and_wc,
3052              diff_file_urls,
3053              diff_prop_change_local_edit,
3054              check_for_omitted_prefix_in_path_component,
3055              diff_renamed_file,
3056              diff_within_renamed_dir,
3057              diff_prop_on_named_dir,
3058              diff_keywords,
3059              diff_force,
3060              diff_schedule_delete,
3061              XFail(diff_renamed_dir),
3062              diff_property_changes_to_base,
3063              diff_mime_type_changes,
3064              diff_prop_change_local_propmod,
3065              diff_repos_wc_add_with_props,
3066              diff_nonrecursive_checkout_deleted_dir,
3067              diff_repos_working_added_dir,
3068              diff_base_repos_moved,
3069              diff_added_subtree,
3070              basic_diff_summarize,
3071              diff_weird_author,
3072              diff_ignore_whitespace,
3073              diff_ignore_eolstyle,
3074              diff_in_renamed_folder,
3075              diff_with_depth,
3076              diff_ignore_eolstyle_empty_lines,
3077              diff_backward_repos_wc_copy,
3078              diff_summarize_xml,
3079              diff_file_depth_empty,
3080              diff_wrong_extension_type,
3081              diff_external_diffcmd,
3082              XFail(diff_url_against_local_mods),
3083              XFail(diff_preexisting_rev_against_local_add),
3084              ]
3085
3086if __name__ == '__main__':
3087  svntest.main.run_tests(test_list)
3088  # NOTREACHED
3089
3090
3091### End of file.
Note: See TracBrowser for help on using the repository browser.