Fix compiler warning due to missing function prototype.
[svn.git] / subversion / tests / cmdline / revert_tests.py
blob5f4928b696ba31f56d14c6c8b86cef63cd14ecd8
1 #!/usr/bin/env python
3 # revert_tests.py: testing 'svn revert'.
5 # Subversion is a tool for revision control.
6 # See http://subversion.tigris.org for more information.
8 # ====================================================================
9 # Copyright (c) 2000-2007 CollabNet. All rights reserved.
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.
17 ######################################################################
19 # General modules
20 import re, os
22 # Our testing module
23 import svntest
24 from svntest import wc
27 # (abbreviation)
28 Skip = svntest.testcase.Skip
29 XFail = svntest.testcase.XFail
30 Item = svntest.wc.StateItem
33 ######################################################################
34 # Helpers
36 def revert_replacement_with_props(sbox, wc_copy):
37 """Helper implementing the core of
38 revert_{repos,wc}_to_wc_replace_with_props().
40 Uses a working copy (when wc_copy == True) or a URL (when wc_copy ==
41 False) source to copy from."""
43 sbox.build()
44 wc_dir = sbox.wc_dir
46 # Use a temp file to set properties with wildcards in their values
47 # otherwise Win32/VS2005 will expand them
48 prop_path = os.path.join(wc_dir, 'proptmp')
49 svntest.main.file_append(prop_path, '*')
51 # Set props on file which is copy-source later on
52 pi_path = os.path.join(wc_dir, 'A', 'D', 'G', 'pi')
53 rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho')
54 svntest.actions.run_and_verify_svn(None, None, [],
55 'ps', 'phony-prop', '-F', prop_path,
56 pi_path)
57 os.remove(prop_path)
58 svntest.actions.run_and_verify_svn(None, None, [],
59 'ps', 'svn:eol-style', 'LF', rho_path)
61 # Verify props having been set
62 expected_disk = svntest.main.greek_state.copy()
63 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
64 expected_disk.tweak('A/D/G/pi',
65 props={ 'phony-prop': '*' })
66 expected_disk.tweak('A/D/G/rho',
67 props={ 'svn:eol-style': 'LF' })
69 actual_disk = svntest.tree.build_tree_from_wc(wc_dir, 1)
70 svntest.tree.compare_trees("disk", actual_disk, expected_disk.old_tree())
72 # Commit props
73 expected_output = svntest.wc.State(wc_dir, {
74 'A/D/G/pi': Item(verb='Sending'),
75 'A/D/G/rho': Item(verb='Sending'),
77 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
78 expected_status.tweak('A/D/G/pi', wc_rev='2')
79 expected_status.tweak('A/D/G/rho', wc_rev='2')
80 svntest.actions.run_and_verify_commit(wc_dir,
81 expected_output,
82 expected_status,
83 None, wc_dir)
85 # Bring wc into sync
86 svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
88 # File scheduled for deletion
89 svntest.actions.run_and_verify_svn(None, None, [], 'rm', rho_path)
91 # Status before attempting copies
92 expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
93 expected_status.tweak('A/D/G/rho', status='D ')
94 svntest.actions.run_and_verify_status(wc_dir, expected_status)
96 # The copy shouldn't fail
97 if wc_copy:
98 pi_src = os.path.join(wc_dir, 'A', 'D', 'G', 'pi')
99 else:
100 pi_src = sbox.repo_url + '/A/D/G/pi'
102 svntest.actions.run_and_verify_svn(None, None, [],
103 'cp', pi_src, rho_path)
105 # Verify both content and props have been copied
106 if wc_copy:
107 props = { 'phony-prop' : '*',
108 'svn:mergeinfo' : '' }
109 else:
110 props = { 'phony-prop' : '*' }
112 expected_disk.tweak('A/D/G/rho',
113 contents="This is the file 'pi'.\n",
114 props=props)
115 actual_disk = svntest.tree.build_tree_from_wc(wc_dir, 1)
116 svntest.tree.compare_trees("disk", actual_disk, expected_disk.old_tree())
118 # Now revert
119 expected_status.tweak('A/D/G/rho', status='R ', copied='+', wc_rev='-')
120 svntest.actions.run_and_verify_status(wc_dir, expected_status)
122 expected_status.tweak('A/D/G/rho', status=' ', copied=None, wc_rev='2')
123 expected_output = ["Reverted '" + rho_path + "'\n"]
124 svntest.actions.run_and_verify_svn(None, expected_output, [],
125 'revert', '-R', wc_dir)
126 svntest.actions.run_and_verify_status(wc_dir, expected_status)
128 # Check disk status
129 expected_disk = svntest.main.greek_state.copy()
130 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
131 expected_disk.tweak('A/D/G/pi',
132 props={ 'phony-prop': '*' })
133 expected_disk.tweak('A/D/G/rho',
134 props={ 'svn:eol-style': 'LF' })
135 actual_disk = svntest.tree.build_tree_from_wc(wc_dir, 1)
136 svntest.tree.compare_trees("disk", actual_disk, expected_disk.old_tree())
141 ######################################################################
142 # Tests
144 # Each test must return on success or raise on failure.
147 #----------------------------------------------------------------------
149 def revert_from_wc_root(sbox):
150 "revert relative to wc root"
152 sbox.build(read_only = True)
153 wc_dir = sbox.wc_dir
155 os.chdir(wc_dir)
157 # Mostly taken from basic_revert
158 # Modify some files and props.
159 beta_path = os.path.join('A', 'B', 'E', 'beta')
160 gamma_path = os.path.join('A', 'D', 'gamma')
161 iota_path = 'iota'
162 rho_path = os.path.join('A', 'D', 'G', 'rho')
163 zeta_path = os.path.join('A', 'D', 'H', 'zeta')
164 svntest.main.file_append(beta_path, "Added some text to 'beta'.\n")
165 svntest.main.file_append(iota_path, "Added some text to 'iota'.\n")
166 svntest.main.file_append(rho_path, "Added some text to 'rho'.\n")
167 svntest.main.file_append(zeta_path, "Added some text to 'zeta'.\n")
169 svntest.actions.run_and_verify_svn("Add command", None, [],
170 'add', zeta_path)
171 svntest.actions.run_and_verify_svn("Add prop command", None, [],
172 'ps', 'random-prop', 'propvalue',
173 gamma_path)
174 svntest.actions.run_and_verify_svn("Add prop command", None, [],
175 'ps', 'random-prop', 'propvalue',
176 iota_path)
177 svntest.actions.run_and_verify_svn("Add prop command", None, [],
178 'ps', 'random-prop', 'propvalue',
179 '.')
180 svntest.actions.run_and_verify_svn("Add prop command", None, [],
181 'ps', 'random-prop', 'propvalue',
182 'A')
184 # Verify modified status.
185 expected_output = svntest.actions.get_virginal_state('', 1)
186 expected_output.tweak('A/B/E/beta', 'A/D/G/rho', status='M ')
187 expected_output.tweak('iota', status='MM')
188 expected_output.tweak('', 'A/D/gamma', 'A', status=' M')
189 expected_output.add({
190 'A/D/H/zeta' : Item(status='A ', wc_rev=0),
193 svntest.actions.run_and_verify_status('', expected_output)
195 # Run revert
196 svntest.actions.run_and_verify_svn("Revert command", None, [],
197 'revert', beta_path)
199 svntest.actions.run_and_verify_svn("Revert command", None, [],
200 'revert', gamma_path)
202 svntest.actions.run_and_verify_svn("Revert command", None, [],
203 'revert', iota_path)
205 svntest.actions.run_and_verify_svn("Revert command", None, [],
206 'revert', rho_path)
208 svntest.actions.run_and_verify_svn("Revert command", None, [],
209 'revert', zeta_path)
211 svntest.actions.run_and_verify_svn("Revert command", None, [],
212 'revert', '.')
214 svntest.actions.run_and_verify_svn("Revert command", None, [],
215 'revert', 'A')
217 # Verify unmodified status.
218 expected_output = svntest.actions.get_virginal_state('', 1)
220 svntest.actions.run_and_verify_status('', expected_output)
223 def revert_reexpand_keyword(sbox):
224 "revert reexpands manually contracted keyword"
226 # This is for issue #1663. The bug is that if the only difference
227 # between a locally modified working file and the base version of
228 # same was that the former had a contracted keyword that would be
229 # expanded in the latter, then 'svn revert' wouldn't notice the
230 # difference, and therefore wouldn't revert. And why wouldn't it
231 # notice? Since text bases are always stored with keywords
232 # contracted, and working files are contracted before comparison
233 # with text base, there would appear to be no difference when the
234 # contraction is the only difference. For most commands, this is
235 # correct -- but revert's job is to restore the working file, not
236 # the text base.
238 sbox.build()
239 wc_dir = sbox.wc_dir
240 newfile_path = os.path.join(wc_dir, "newfile")
241 unexpanded_contents = "This is newfile: $Rev$.\n"
243 # Put an unexpanded keyword into iota.
244 svntest.main.file_write(newfile_path, unexpanded_contents)
246 # Commit, without svn:keywords property set.
247 svntest.main.run_svn(None, 'add', newfile_path)
248 svntest.main.run_svn(None,
249 'commit', '-m', 'r2', newfile_path)
251 # Set the property and commit. This should expand the keyword.
252 svntest.main.run_svn(None, 'propset', 'svn:keywords', 'rev', newfile_path)
253 svntest.main.run_svn(None,
254 'commit', '-m', 'r3', newfile_path)
256 # Verify that the keyword got expanded.
257 def check_expanded(path):
258 fp = open(path, 'r')
259 lines = fp.readlines()
260 fp.close()
261 if lines[0] != "This is newfile: $Rev: 3 $.\n":
262 raise svntest.Failure
264 check_expanded(newfile_path)
266 # Now un-expand the keyword again.
267 svntest.main.file_write(newfile_path, unexpanded_contents)
269 fp = open(newfile_path, 'r')
270 lines = fp.readlines()
271 fp.close()
273 # Revert the file. The keyword should reexpand.
274 svntest.main.run_svn(None, 'revert', newfile_path)
276 # Verify that the keyword got re-expanded.
277 check_expanded(newfile_path)
280 #----------------------------------------------------------------------
281 # Regression test for issue #1775:
282 # Should be able to revert a file with no properties i.e. no prop-base
283 def revert_replaced_file_without_props(sbox):
284 "revert a replaced file with no properties"
286 sbox.build()
287 wc_dir = sbox.wc_dir
289 file1_path = os.path.join(wc_dir, 'file1')
291 # Add a new file, file1, that has no prop-base
292 svntest.main.file_append(file1_path, "This is the file 'file1' revision 2.")
293 svntest.actions.run_and_verify_svn(None, None, [], 'add', file1_path)
295 # commit file1
296 expected_output = svntest.wc.State(wc_dir, {
297 'file1' : Item(verb='Adding')
300 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
301 expected_status.add({
302 'file1' : Item(status=' ', wc_rev=2),
305 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
306 expected_status, None, wc_dir)
308 # delete file1
309 svntest.actions.run_and_verify_svn(None, None, [], 'rm', file1_path)
311 # test that file1 is scheduled for deletion.
312 expected_status.tweak('file1', status='D ')
313 svntest.actions.run_and_verify_status(wc_dir, expected_status)
315 # recreate and add file1
316 svntest.main.file_append(file1_path, "This is the file 'file1' revision 3.")
317 svntest.actions.run_and_verify_svn(None, None, [], 'add', file1_path)
319 # Test to see if file1 is schedule for replacement
320 expected_status.tweak('file1', status='R ')
321 svntest.actions.run_and_verify_status(wc_dir, expected_status)
323 # revert file1
324 svntest.actions.run_and_verify_svn(None, ["Reverted '" + file1_path + "'\n"],
325 [], 'revert', file1_path)
327 # test that file1 really was reverted
328 expected_status.tweak('file1', status=' ', wc_rev=2)
329 svntest.actions.run_and_verify_status(wc_dir, expected_status)
331 #----------------------------------------------------------------------
332 # Regression test for issue #876:
333 # svn revert of an svn move'd file does not revert the file
334 def revert_moved_file(sbox):
335 "revert a moved file"
337 sbox.build(read_only = True)
338 wc_dir = sbox.wc_dir
339 iota_path = os.path.join(wc_dir, 'iota')
340 iota_path_moved = os.path.join(wc_dir, 'iota_moved')
342 svntest.actions.run_and_verify_svn(None, None, [], 'mv', iota_path,
343 iota_path_moved)
344 expected_output = svntest.actions.get_virginal_state(wc_dir, 1)
345 expected_output.tweak('iota', status='D ')
346 expected_output.add({
347 'iota_moved' : Item(status='A ', copied='+', wc_rev='-'),
349 svntest.actions.run_and_verify_status(wc_dir, expected_output)
351 # now revert the file iota
352 svntest.actions.run_and_verify_svn(None,
353 ["Reverted '" + iota_path + "'\n"], [], 'revert', iota_path)
355 # at this point, svn status on iota_path_moved should return nothing
356 # since it should disappear on reverting the move, and since svn status
357 # on a non-existent file returns nothing.
359 svntest.actions.run_and_verify_svn(None, [], [],
360 'status', '-v', iota_path_moved)
363 #----------------------------------------------------------------------
364 # Test for issue 2135
366 # It is like merge_file_replace (in merge_tests.py), but reverts file
367 # instead of commit.
369 def revert_file_merge_replace_with_history(sbox):
370 "revert a merge replacement of file with history"
372 sbox.build()
373 wc_dir = sbox.wc_dir
375 # File scheduled for deletion
376 rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho')
377 svntest.actions.run_and_verify_svn(None, None, [], 'rm', rho_path)
379 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
380 expected_status.tweak('A/D/G/rho', status='D ')
381 svntest.actions.run_and_verify_status(wc_dir, expected_status)
383 expected_output = svntest.wc.State(wc_dir, {
384 'A/D/G/rho': Item(verb='Deleting'),
387 expected_status.remove('A/D/G/rho')
389 # Commit rev 2
390 svntest.actions.run_and_verify_commit(wc_dir,
391 expected_output,
392 expected_status,
393 None, wc_dir)
394 # create new rho file
395 svntest.main.file_write(rho_path, "new rho\n")
397 # Add the new file
398 svntest.actions.run_and_verify_svn(None, None, [], 'add', rho_path)
400 # Commit revsion 3
401 expected_status.add({
402 'A/D/G/rho' : Item(status='A ', wc_rev='0')
404 svntest.actions.run_and_verify_status(wc_dir, expected_status)
405 expected_output = svntest.wc.State(wc_dir, {
406 'A/D/G/rho': Item(verb='Adding'),
409 svntest.actions.run_and_verify_commit(wc_dir,
410 expected_output,
411 None, None, wc_dir)
413 # Update working copy
414 expected_output = svntest.wc.State(wc_dir, {})
415 expected_disk = svntest.main.greek_state.copy()
416 expected_disk.tweak('A/D/G/rho', contents='new rho\n' )
417 expected_status.tweak(wc_rev='3')
418 expected_status.tweak('A/D/G/rho', status=' ')
420 svntest.actions.run_and_verify_update(wc_dir,
421 expected_output,
422 expected_disk,
423 expected_status)
425 # merge changes from r3:1
426 expected_output = svntest.wc.State(wc_dir, {
427 'A/D/G/rho': Item(status='R ')
429 expected_status.tweak('A/D/G/rho', status='R ', copied='+', wc_rev='-')
430 expected_skip = wc.State(wc_dir, { })
431 expected_disk.tweak('A/D/G/rho', contents="This is the file 'rho'.\n")
432 svntest.actions.run_and_verify_merge(wc_dir, '3', '1',
433 sbox.repo_url,
434 expected_output,
435 expected_disk,
436 expected_status,
437 expected_skip)
439 # Now revert
440 svntest.actions.run_and_verify_svn(None,
441 None,
442 [], 'revert', rho_path)
444 # test that rho really was reverted
445 expected_status.tweak('A/D/G/rho', copied=None, status=' ', wc_rev=3)
446 svntest.actions.run_and_verify_status(wc_dir, expected_status)
448 actual_disk = svntest.tree.build_tree_from_wc(wc_dir, 1)
449 expected_disk.tweak('A/D/G/rho', contents="new rho\n")
450 svntest.tree.compare_trees("disk", actual_disk, expected_disk.old_tree())
452 # Make sure the revert removed the copy from information.
453 exit_code, output, err = svntest.actions.run_and_verify_svn(None, None, [],
454 'info', rho_path)
455 for line in output:
456 if line.find("Copied") != -1:
457 print "Error: Revert didn't get rid of copy from information"
458 raise svntest.Failure
460 def revert_wc_to_wc_replace_with_props(sbox):
461 "revert svn cp PATH PATH replace file with props"
463 revert_replacement_with_props(sbox, 1)
465 def revert_repos_to_wc_replace_with_props(sbox):
466 "revert svn cp URL PATH replace file with props"
468 revert_replacement_with_props(sbox, 0)
470 def revert_after_second_replace(sbox):
471 "revert file after second replace"
473 sbox.build(read_only = True)
474 wc_dir = sbox.wc_dir
476 # File scheduled for deletion
477 rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho')
478 svntest.actions.run_and_verify_svn(None, None, [], 'rm', rho_path)
480 # Status before attempting copy
481 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
482 expected_status.tweak('A/D/G/rho', status='D ')
483 svntest.actions.run_and_verify_status(wc_dir, expected_status)
485 # Replace file for the first time
486 pi_src = os.path.join(wc_dir, 'A', 'D', 'G', 'pi')
488 svntest.actions.run_and_verify_svn(None, None, [],
489 'cp', pi_src, rho_path)
491 expected_status.tweak('A/D/G/rho', status='R ', copied='+', wc_rev='-')
492 svntest.actions.run_and_verify_status(wc_dir, expected_status)
494 # Now delete replaced file.
495 svntest.actions.run_and_verify_svn(None, None, [], 'rm', '--force', rho_path)
497 # Status should be same as after first delete
498 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
499 expected_status.tweak('A/D/G/rho', status='D ')
500 svntest.actions.run_and_verify_status(wc_dir, expected_status)
502 # Replace file for the second time
503 pi_src = os.path.join(wc_dir, 'A', 'D', 'G', 'pi')
505 svntest.actions.run_and_verify_svn(None, None, [], 'cp', pi_src, rho_path)
507 expected_status.tweak('A/D/G/rho', status='R ', copied='+', wc_rev='-')
508 svntest.actions.run_and_verify_status(wc_dir, expected_status)
510 # Now revert
511 svntest.actions.run_and_verify_svn(None, None, [],
512 'revert', '-R', wc_dir)
514 # Check disk status
515 expected_disk = svntest.main.greek_state.copy()
516 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
517 actual_disk = svntest.tree.build_tree_from_wc(wc_dir, 1)
518 svntest.tree.compare_trees("disk", actual_disk, expected_disk.old_tree())
521 #----------------------------------------------------------------------
522 # Tests for issue #2517.
524 # Manual conflict resolution leads to spurious revert report.
526 def revert_after_manual_conflict_resolution__text(sbox):
527 "revert after manual text-conflict resolution"
529 # Make two working copies
530 sbox.build()
531 wc_dir_1 = sbox.wc_dir
532 wc_dir_2 = sbox.add_wc_path('other')
533 svntest.actions.duplicate_dir(wc_dir_1, wc_dir_2)
535 # Cause a (text) conflict
536 iota_path_1 = os.path.join(wc_dir_1, 'iota')
537 iota_path_2 = os.path.join(wc_dir_2, 'iota')
538 svntest.main.file_write(iota_path_1, 'Modified iota text')
539 svntest.main.file_write(iota_path_2, 'Conflicting iota text')
540 svntest.main.run_svn(None,
541 'commit', '-m', 'r2', wc_dir_1)
542 svntest.main.run_svn(None,
543 'update', wc_dir_2)
545 # Resolve the conflict "manually"
546 svntest.main.file_write(iota_path_2, 'Modified iota text')
547 os.remove(iota_path_2 + '.mine')
548 os.remove(iota_path_2 + '.r1')
549 os.remove(iota_path_2 + '.r2')
551 # Verify no output from status, diff, or revert
552 svntest.actions.run_and_verify_svn(None, [], [], "status", wc_dir_2)
553 svntest.actions.run_and_verify_svn(None, [], [], "diff", wc_dir_2)
554 svntest.actions.run_and_verify_svn(None, [], [], "revert", "-R", wc_dir_2)
556 def revert_after_manual_conflict_resolution__prop(sbox):
557 "revert after manual property-conflict resolution"
559 # Make two working copies
560 sbox.build()
561 wc_dir_1 = sbox.wc_dir
562 wc_dir_2 = sbox.add_wc_path('other')
563 svntest.actions.duplicate_dir(wc_dir_1, wc_dir_2)
565 # Cause a (property) conflict
566 iota_path_1 = os.path.join(wc_dir_1, 'iota')
567 iota_path_2 = os.path.join(wc_dir_2, 'iota')
568 svntest.main.run_svn(None, 'propset', 'foo', '1', iota_path_1)
569 svntest.main.run_svn(None, 'propset', 'foo', '2', iota_path_2)
570 svntest.main.run_svn(None,
571 'commit', '-m', 'r2', wc_dir_1)
572 svntest.main.run_svn(None,
573 'update', wc_dir_2)
575 # Resolve the conflict "manually"
576 svntest.main.run_svn(None, 'propset', 'foo', '1', iota_path_2)
577 os.remove(iota_path_2 + '.prej')
579 # Verify no output from status, diff, or revert
580 svntest.actions.run_and_verify_svn(None, [], [], "status", wc_dir_2)
581 svntest.actions.run_and_verify_svn(None, [], [], "diff", wc_dir_2)
582 svntest.actions.run_and_verify_svn(None, [], [], "revert", "-R", wc_dir_2)
584 def revert_propset__dir(sbox):
585 "revert a simple propset on a dir"
587 sbox.build(read_only = True)
588 wc_dir = sbox.wc_dir
589 a_path = os.path.join(wc_dir, 'A')
590 svntest.main.run_svn(None, 'propset', 'foo', 'x', a_path)
591 expected_output = re.escape("Reverted '" + a_path + "'")
592 svntest.actions.run_and_verify_svn(None, expected_output, [], "revert",
593 a_path)
595 def revert_propset__file(sbox):
596 "revert a simple propset on a file"
598 sbox.build(read_only = True)
599 wc_dir = sbox.wc_dir
600 iota_path = os.path.join(wc_dir, 'iota')
601 svntest.main.run_svn(None, 'propset', 'foo', 'x', iota_path)
602 expected_output = re.escape("Reverted '" + iota_path + "'")
603 svntest.actions.run_and_verify_svn(None, expected_output, [], "revert",
604 iota_path)
606 def revert_propdel__dir(sbox):
607 "revert a simple propdel on a dir"
609 sbox.build()
610 wc_dir = sbox.wc_dir
611 a_path = os.path.join(wc_dir, 'A')
612 svntest.main.run_svn(None, 'propset', 'foo', 'x', a_path)
613 svntest.main.run_svn(None,
614 'commit', '-m', 'ps', a_path)
615 svntest.main.run_svn(None, 'propdel', 'foo', a_path)
616 expected_output = re.escape("Reverted '" + a_path + "'")
617 svntest.actions.run_and_verify_svn(None, expected_output, [], "revert",
618 a_path)
620 def revert_propdel__file(sbox):
621 "revert a simple propdel on a file"
623 sbox.build()
624 wc_dir = sbox.wc_dir
625 iota_path = os.path.join(wc_dir, 'iota')
626 svntest.main.run_svn(None, 'propset', 'foo', 'x', iota_path)
627 svntest.main.run_svn(None,
628 'commit', '-m', 'ps', iota_path)
629 svntest.main.run_svn(None, 'propdel', 'foo', iota_path)
630 expected_output = re.escape("Reverted '" + iota_path + "'")
631 svntest.actions.run_and_verify_svn(None, expected_output, [], "revert",
632 iota_path)
634 def revert_replaced_with_history_file_1(sbox):
635 "revert a committed replace-with-history == no-op"
637 sbox.build()
638 wc_dir = sbox.wc_dir
639 iota_path = os.path.join(wc_dir, 'iota')
640 mu_path = os.path.join(wc_dir, 'A', 'mu')
642 # Remember the original text of 'mu'
643 exit_code, text_r1, err = svntest.actions.run_and_verify_svn(None, None, [],
644 'cat', mu_path)
645 # delete mu and replace it with a copy of iota
646 svntest.main.run_svn(None, 'rm', mu_path)
647 svntest.main.run_svn(None, 'mv', iota_path, mu_path)
649 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
650 expected_status.tweak('A/mu', status=' ', wc_rev=2)
651 expected_status.remove('iota')
652 expected_output = svntest.wc.State(wc_dir, {
653 'iota': Item(verb='Deleting'),
654 'A/mu': Item(verb='Replacing'),
656 svntest.actions.run_and_verify_commit(wc_dir,
657 expected_output,
658 expected_status,
659 None, wc_dir)
661 # update the working copy
662 svntest.main.run_svn(None, 'up', wc_dir)
664 # now revert back to the state in r1
665 expected_output = svntest.wc.State(wc_dir, {
666 'A/mu': Item(status='R '),
667 'iota': Item(status='A ')
669 expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
670 expected_status.tweak('A/mu', status='R ', copied='+', wc_rev='-')
671 expected_status.tweak('iota', status='A ', copied='+', wc_rev='-')
672 expected_skip = wc.State(wc_dir, { })
673 expected_disk = svntest.main.greek_state.copy()
674 svntest.actions.run_and_verify_merge(wc_dir, '2', '1',
675 sbox.repo_url,
676 expected_output,
677 expected_disk,
678 expected_status,
679 expected_skip)
681 # and commit in r3
682 expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
683 expected_status.tweak('A/mu', status=' ', wc_rev=3)
684 expected_status.tweak('iota', status=' ', wc_rev=3)
685 expected_output = svntest.wc.State(wc_dir, {
686 'iota': Item(verb='Adding'),
687 'A/mu': Item(verb='Replacing'),
689 svntest.actions.run_and_verify_commit(wc_dir,
690 expected_output,
691 expected_status,
692 None, wc_dir)
694 # Verify the content of 'mu'
695 svntest.actions.run_and_verify_svn(None, text_r1, [], 'cat', mu_path)
697 # situation: no local modifications, mu has its original content again.
699 # revert 'mu' locally, shouldn't change a thing.
700 svntest.actions.run_and_verify_svn(None, [], [], "revert",
701 mu_path)
703 # Verify the content of 'mu'
704 svntest.actions.run_and_verify_svn(None, text_r1, [], 'cat', mu_path)
706 #----------------------------------------------------------------------
707 # Test for issue #2804.
708 def status_of_missing_dir_after_revert(sbox):
709 "status after schedule-delete, revert, and local rm"
711 sbox.build(read_only = True)
712 wc_dir = sbox.wc_dir
713 A_D_G_path = os.path.join(wc_dir, "A", "D", "G")
715 svntest.actions.run_and_verify_svn(None, None, [], "rm", A_D_G_path)
716 expected_output = re.escape("Reverted '" + A_D_G_path + "'")
717 svntest.actions.run_and_verify_svn(None, expected_output, [], "revert",
718 A_D_G_path)
720 expected_output = svntest.verify.UnorderedOutput(
721 ["D " + os.path.join(A_D_G_path, "pi") + "\n",
722 "D " + os.path.join(A_D_G_path, "rho") + "\n",
723 "D " + os.path.join(A_D_G_path, "tau") + "\n"])
724 svntest.actions.run_and_verify_svn(None, expected_output, [],
725 "status", wc_dir)
727 svntest.main.safe_rmtree(A_D_G_path)
729 expected_output = svntest.verify.UnorderedOutput(
730 ["! " + A_D_G_path + "\n"])
731 svntest.actions.run_and_verify_svn(None, expected_output, [], "status",
732 wc_dir)
734 #----------------------------------------------------------------------
735 # Test for issue #2804 with replaced directory
736 def status_of_missing_dir_after_revert_replaced_with_history_dir(sbox):
737 "status after replace+, revert, and local rm"
739 sbox.build()
740 wc_dir = sbox.wc_dir
741 repo_url = sbox.repo_url
743 # delete A/D/G and commit
744 G_path = os.path.join(wc_dir, "A", "D", "G")
745 svntest.actions.run_and_verify_svn(None, None, [], "rm", G_path)
746 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
747 expected_status.remove('A/D/G', 'A/D/G/rho', 'A/D/G/pi', 'A/D/G/tau')
748 expected_output = svntest.wc.State(wc_dir, {
749 'A/D/G': Item(verb='Deleting'),
751 svntest.actions.run_and_verify_commit(wc_dir,
752 expected_output,
753 expected_status,
754 None, wc_dir)
756 # copy A/D/G from A/B/E and commit
757 E_path = os.path.join(wc_dir, "A", "B", "E")
758 svntest.actions.run_and_verify_svn(None, None, [], "cp", E_path, G_path)
759 expected_status.add({
760 'A/D/G' : Item(status=' ', wc_rev='3'),
761 'A/D/G/alpha' : Item(status=' ', wc_rev='3'),
762 'A/D/G/beta' : Item(status=' ', wc_rev='3')
764 expected_output = svntest.wc.State(wc_dir, {
765 'A/D/G': Item(verb='Adding'),
767 svntest.actions.run_and_verify_commit(wc_dir,
768 expected_output,
769 expected_status,
770 None, wc_dir)
772 # update the working copy
773 svntest.main.run_svn(None, 'up', wc_dir)
775 # now rollback to r1, thereby reinstating the old 'G'
776 ### Eventually, expected output for 'A/D/G' should be 'R '
777 ### (replaced) instead of 'A ' (added). See issue #571 for details.
778 expected_output = svntest.wc.State(wc_dir, {
779 'A/D/G': Item(status='R '),
780 'A/D/G/rho': Item(status='A '),
781 'A/D/G/pi': Item(status='A '),
782 'A/D/G/tau': Item(status='A '),
784 expected_status = svntest.actions.get_virginal_state(wc_dir, 3)
785 expected_status.tweak('A/D/G', status='R ', copied='+', wc_rev='-')
786 expected_status.tweak('A/D/G/rho', status='A ', copied='+', wc_rev='-')
787 expected_status.tweak('A/D/G/pi', status='A ', copied='+', wc_rev='-')
788 expected_status.tweak('A/D/G/tau', status='A ', copied='+', wc_rev='-')
789 expected_status.add({
790 'A/D/G/alpha' : Item(status='D ', copied='+', wc_rev='-'),
791 'A/D/G/beta' : Item(status='D ', copied='+', wc_rev='-')
793 expected_skip = wc.State(wc_dir, { })
794 expected_disk = svntest.main.greek_state.copy()
795 svntest.actions.run_and_verify_merge(wc_dir, '3', '1',
796 sbox.repo_url,
797 expected_output,
798 expected_disk,
799 expected_status,
800 expected_skip,
801 dry_run = 0)
803 # now test if the revert works ok
804 expected_output = svntest.verify.UnorderedOutput(
805 ["Reverted '" + G_path + "'\n",
806 "Reverted '" + os.path.join(G_path, 'pi') + "'\n",
807 "Reverted '" + os.path.join(G_path, 'rho') + "'\n",
808 "Reverted '" + os.path.join(G_path, 'tau') + "'\n",
809 "Reverted '" + os.path.join(G_path, 'alpha') + "'\n",
810 "Reverted '" + os.path.join(G_path, 'beta') + "'\n"])
812 svntest.actions.run_and_verify_svn(None, expected_output, [], "revert", "-R",
813 G_path)
815 expected_output = svntest.verify.UnorderedOutput(
816 ["? " + os.path.join(G_path, "pi") + "\n",
817 "? " + os.path.join(G_path, "rho") + "\n",
818 "? " + os.path.join(G_path, "tau") + "\n"])
819 svntest.actions.run_and_verify_svn(None, expected_output, [],
820 "status", wc_dir)
822 svntest.main.safe_rmtree(G_path)
824 expected_output = svntest.verify.UnorderedOutput(
825 ["! " + G_path + "\n"])
826 svntest.actions.run_and_verify_svn(None, expected_output, [], "status",
827 wc_dir)
829 # Test for issue #2928.
830 def revert_replaced_with_history_file_2(sbox):
831 "reverted replace with history restores checksum"
833 sbox.build()
834 wc_dir = sbox.wc_dir
835 iota_path = os.path.join(wc_dir, 'iota')
836 mu_path = os.path.join(wc_dir, 'A', 'mu')
838 # Delete mu and replace it with a copy of iota
839 svntest.main.run_svn(None, 'rm', mu_path)
840 svntest.main.run_svn(None, 'cp', iota_path, mu_path)
842 # Revert mu.
843 svntest.main.run_svn(None, 'revert', mu_path)
845 # If we make local mods to the reverted mu the commit will
846 # fail if the checksum is incorrect.
847 svntest.main.file_write(mu_path, "new text")
848 expected_output = svntest.wc.State(wc_dir, {
849 'A/mu': Item(verb='Sending'),
851 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
852 expected_status.tweak('A/mu', status=' ', wc_rev=2)
853 svntest.actions.run_and_verify_commit(wc_dir,
854 expected_output,
855 expected_status,
856 None, wc_dir)
858 ########################################################################
859 # Run the tests
862 # list all tests here, starting with None:
863 test_list = [ None,
864 revert_from_wc_root,
865 revert_reexpand_keyword,
866 revert_replaced_file_without_props,
867 XFail(revert_moved_file),
868 revert_wc_to_wc_replace_with_props,
869 revert_file_merge_replace_with_history,
870 revert_repos_to_wc_replace_with_props,
871 revert_after_second_replace,
872 revert_after_manual_conflict_resolution__text,
873 revert_after_manual_conflict_resolution__prop,
874 revert_propset__dir,
875 revert_propset__file,
876 revert_propdel__dir,
877 revert_propdel__file,
878 revert_replaced_with_history_file_1,
879 status_of_missing_dir_after_revert,
880 status_of_missing_dir_after_revert_replaced_with_history_dir,
881 revert_replaced_with_history_file_2,
884 if __name__ == '__main__':
885 svntest.main.run_tests(test_list)
886 # NOTREACHED
889 ### End of file.