1#!/usr/bin/env python 2# 3# shelf_tests.py: testing shelving 4# 5# Subversion is a tool for revision control. 6# See http://subversion.apache.org for more information. 7# 8# ==================================================================== 9# Licensed to the Apache Software Foundation (ASF) under one 10# or more contributor license agreements. See the NOTICE file 11# distributed with this work for additional information 12# regarding copyright ownership. The ASF licenses this file 13# to you under the Apache License, Version 2.0 (the 14# "License"); you may not use this file except in compliance 15# with the License. You may obtain a copy of the License at 16# 17# http://www.apache.org/licenses/LICENSE-2.0 18# 19# Unless required by applicable law or agreed to in writing, 20# software distributed under the License is distributed on an 21# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 22# KIND, either express or implied. See the License for the 23# specific language governing permissions and limitations 24# under the License. 25###################################################################### 26 27# General modules 28import shutil, stat, re, os, logging 29 30logger = logging.getLogger() 31 32# Our testing module 33import svntest 34from svntest import wc 35from svntest.verify import make_diff_header, make_no_diff_deleted_header, \ 36 make_git_diff_header, make_diff_prop_header, \ 37 make_diff_prop_val, make_diff_prop_deleted, \ 38 make_diff_prop_added, make_diff_prop_modified 39 40# (abbreviation) 41Skip = svntest.testcase.Skip_deco 42SkipUnless = svntest.testcase.SkipUnless_deco 43XFail = svntest.testcase.XFail_deco 44Issues = svntest.testcase.Issues_deco 45Issue = svntest.testcase.Issue_deco 46Wimp = svntest.testcase.Wimp_deco 47Item = wc.StateItem 48 49def shelf3_enabled(): 50 v = os.getenv('SVN_EXPERIMENTAL_COMMANDS') 51 return v is not None and v.find('shelf3') >= 0 52 53#---------------------------------------------------------------------- 54 55def state_from_status(wc_dir, 56 v=True, u=True, q=True): 57 opts = () 58 if v: 59 opts += ('-v',) 60 if u: 61 opts += ('-u',) 62 if q: 63 opts += ('-q',) 64 _, output, _ = svntest.main.run_svn(None, 'status', wc_dir, *opts) 65 return svntest.wc.State.from_status(output, wc_dir) 66 67def get_wc_state(wc_dir): 68 """Return a description of the WC state. Include as much info as shelving 69 should be capable of restoring. 70 """ 71 return (state_from_status(wc_dir), 72 svntest.wc.State.from_wc(wc_dir, load_props=True), 73 ) 74 75def check_wc_state(wc_dir, expected): 76 """Check a description of the WC state. Include as much info as shelving 77 should be capable of restoring. 78 """ 79 expect_st, expect_wc = expected 80 actual_st, actual_wc = get_wc_state(wc_dir) 81 82 # Verify actual status against expected status. 83 try: 84 expect_st.compare_and_display('status', actual_st) 85 except svntest.tree.SVNTreeError: 86 svntest.actions._log_tree_state("EXPECT STATUS TREE:", expect_st.old_tree(), 87 wc_dir) 88 svntest.actions._log_tree_state("ACTUAL STATUS TREE:", actual_st.old_tree(), 89 wc_dir) 90 raise 91 92 # Verify actual WC against expected WC. 93 try: 94 expect_wc.compare_and_display('status', actual_wc) 95 except svntest.tree.SVNTreeError: 96 svntest.actions._log_tree_state("EXPECT WC TREE:", expect_wc.old_tree(), 97 wc_dir) 98 svntest.actions._log_tree_state("ACTUAL WC TREE:", actual_wc.old_tree(), 99 wc_dir) 100 raise 101 102def shelve_unshelve_verify(sbox, modifier, cannot_shelve=False): 103 """Round-trip: shelve; verify all changes are reverted; 104 unshelve; verify all changes are restored. 105 """ 106 107 wc_dir = sbox.wc_dir 108 virginal_state = get_wc_state(wc_dir) 109 110 # Make some changes to the working copy 111 modifier(sbox) 112 113 # Save the modified state 114 modified_state = get_wc_state(wc_dir) 115 116 if cannot_shelve: 117 svntest.actions.run_and_verify_svn(None, '.* could not be shelved.*', 118 'x-shelve', 'foo') 119 return 120 121 # Shelve; check there are no longer any modifications 122 svntest.actions.run_and_verify_svn(None, [], 123 'x-shelve', 'foo') 124 check_wc_state(wc_dir, virginal_state) 125 126 # List; ensure the shelf is listed 127 expected_output = svntest.verify.RegexListOutput( 128 [r'foo\s*version \d+.*', 129 r' ', 130 ]) 131 svntest.actions.run_and_verify_svn(expected_output, [], 'x-shelves') 132 133 # Diff; ensure something comes out and it doesn't crash 134 svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [], 135 'x-shelf-diff', 'foo') 136 svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [], 137 'x-shelf-diff', '--summarize', 'foo') 138 139 # Unshelve; check the original modifications are here again 140 svntest.actions.run_and_verify_svn(None, [], 141 'x-unshelve', 'foo') 142 check_wc_state(wc_dir, modified_state) 143 144#---------------------------------------------------------------------- 145 146def shelve_unshelve(sbox, modifier, cannot_shelve=False): 147 """Round-trip: build 'sbox'; apply changes by calling 'modifier(sbox)'; 148 shelve and unshelve; verify changes are fully reverted and restored. 149 """ 150 151 if not sbox.is_built(): 152 sbox.build() 153 was_cwd = os.getcwd() 154 os.chdir(sbox.wc_dir) 155 sbox.wc_dir = '' 156 157 shelve_unshelve_verify(sbox, modifier, cannot_shelve) 158 159 os.chdir(was_cwd) 160 161###################################################################### 162# Tests 163# 164# Each test must return on success or raise on failure. 165 166@SkipUnless(shelf3_enabled) 167def shelve_text_mods(sbox): 168 "shelve text mods" 169 170 def modifier(sbox): 171 sbox.simple_append('A/mu', 'appended mu text') 172 173 shelve_unshelve(sbox, modifier) 174 175#---------------------------------------------------------------------- 176 177@SkipUnless(shelf3_enabled) 178def shelve_prop_changes(sbox): 179 "shelve prop changes" 180 181 def modifier(sbox): 182 sbox.simple_propset('p', 'v', 'A') 183 sbox.simple_propset('p', 'v', 'A/mu') 184 185 shelve_unshelve(sbox, modifier) 186 187#---------------------------------------------------------------------- 188 189@SkipUnless(shelf3_enabled) 190def shelve_adds(sbox): 191 "shelve adds" 192 193 def modifier(sbox): 194 sbox.simple_add_text('A new file\n', 'A/new') 195 sbox.simple_add_text('A new file\n', 'A/new2') 196 sbox.simple_propset('p', 'v', 'A/new2') 197 198 shelve_unshelve(sbox, modifier) 199 200#---------------------------------------------------------------------- 201 202@Issue(4709) 203@SkipUnless(shelf3_enabled) 204def shelve_deletes(sbox): 205 "shelve deletes" 206 207 def modifier(sbox): 208 sbox.simple_rm('A/mu') 209 210 shelve_unshelve(sbox, modifier) 211 212#---------------------------------------------------------------------- 213 214@SkipUnless(shelf3_enabled) 215def shelve_replace(sbox): 216 "shelve replace" 217 218 def modifier(sbox): 219 sbox.simple_rm('A/mu') 220 sbox.simple_add_text('Replacement\n', 'A/mu') 221 sbox.simple_propset('p', 'v', 'A/mu') 222 223 shelve_unshelve(sbox, modifier) 224 225#---------------------------------------------------------------------- 226 227@SkipUnless(shelf3_enabled) 228def shelve_empty_adds(sbox): 229 "shelve empty adds" 230 sbox.build(empty=True) 231 232 def modifier(sbox): 233 sbox.simple_add_text('', 'empty') 234 sbox.simple_add_text('', 'empty-with-prop') 235 sbox.simple_propset('p', 'v', 'empty-with-prop') 236 237 shelve_unshelve(sbox, modifier) 238 239#---------------------------------------------------------------------- 240 241@SkipUnless(shelf3_enabled) 242def shelve_empty_deletes(sbox): 243 "shelve empty deletes" 244 sbox.build(empty=True) 245 sbox.simple_add_text('', 'empty') 246 sbox.simple_add_text('', 'empty-with-prop') 247 sbox.simple_propset('p', 'v', 'empty-with-prop') 248 sbox.simple_commit() 249 250 def modifier(sbox): 251 sbox.simple_rm('empty', 'empty-with-prop') 252 253 shelve_unshelve(sbox, modifier) 254 255#---------------------------------------------------------------------- 256 257@SkipUnless(shelf3_enabled) 258def shelve_from_inner_path(sbox): 259 "shelve from inner path" 260 261 def modifier(sbox): 262 sbox.simple_append('A/mu', 'appended mu text') 263 264 sbox.build() 265 was_cwd = os.getcwd() 266 os.chdir(sbox.ospath('A')) 267 sbox.wc_dir = '..' 268 269 shelve_unshelve_verify(sbox, modifier) 270 271 os.chdir(was_cwd) 272 273#---------------------------------------------------------------------- 274 275def save_revert_restore(sbox, modifier1, modifier2): 276 "Save 2 checkpoints; revert; restore 1st" 277 278 sbox.build() 279 was_cwd = os.getcwd() 280 os.chdir(sbox.wc_dir) 281 sbox.wc_dir = '' 282 wc_dir = '' 283 284 initial_state = get_wc_state(wc_dir) 285 286 # Make some changes to the working copy 287 modifier1(sbox) 288 289 # Remember the modified state 290 modified_state1 = get_wc_state(wc_dir) 291 292 # Save a checkpoint; check nothing changed 293 svntest.actions.run_and_verify_svn(None, [], 294 'x-shelf-save', 'foo') 295 check_wc_state(wc_dir, modified_state1) 296 297 # Modify again; remember the state; save a checkpoint 298 modifier2(sbox) 299 modified_state2 = get_wc_state(wc_dir) 300 svntest.actions.run_and_verify_svn(None, [], 301 'x-shelf-save', 'foo') 302 check_wc_state(wc_dir, modified_state2) 303 304 # Revert 305 svntest.actions.run_and_verify_svn(None, [], 306 'revert', '-R', '.') 307 check_wc_state(wc_dir, initial_state) 308 309 # Restore; check the original modifications are here again 310 svntest.actions.run_and_verify_svn(None, [], 311 'x-unshelve', 'foo', '1') 312 check_wc_state(wc_dir, modified_state1) 313 314 os.chdir(was_cwd) 315 316#---------------------------------------------------------------------- 317 318@SkipUnless(shelf3_enabled) 319def checkpoint_basic(sbox): 320 "checkpoint basic" 321 322 def modifier1(sbox): 323 sbox.simple_append('A/mu', 'appended mu text\n') 324 325 def modifier2(sbox): 326 sbox.simple_append('iota', 'appended iota text\n') 327 sbox.simple_append('A/mu', 'appended another line\n') 328 329 save_revert_restore(sbox, modifier1, modifier2) 330 331#---------------------------------------------------------------------- 332 333@Issue(3747) 334@SkipUnless(shelf3_enabled) 335def shelve_mergeinfo(sbox): 336 "shelve mergeinfo" 337 338 def modifier(sbox): 339 sbox.simple_propset('svn:mergeinfo', '/trunk/A:1-3,10', 'A') 340 sbox.simple_propset('svn:mergeinfo', '/trunk/A/mu:1-3,10', 'A/mu') 341 342 shelve_unshelve(sbox, modifier) 343 344#---------------------------------------------------------------------- 345 346@SkipUnless(shelf3_enabled) 347def unshelve_refuses_if_conflicts(sbox): 348 "unshelve refuses if conflicts" 349 350 def modifier1(sbox): 351 sbox.simple_append('alpha', 'A-mod1\nB\nC\nD\n', truncate=True) 352 sbox.simple_append('beta', 'A-mod1\nB\nC\nD\n', truncate=True) 353 354 def modifier2(sbox): 355 sbox.simple_append('beta', 'A-mod2\nB\nC\nD\n', truncate=True) 356 357 sbox.build(empty=True) 358 was_cwd = os.getcwd() 359 os.chdir(sbox.wc_dir) 360 sbox.wc_dir = '' 361 wc_dir = '' 362 363 sbox.simple_add_text('A\nB\nC\nD\n', 'alpha') 364 sbox.simple_add_text('A\nB\nC\nD\n', 'beta') 365 sbox.simple_commit() 366 initial_state = get_wc_state(wc_dir) 367 368 # Make initial mods; remember this modified state 369 modifier1(sbox) 370 modified_state1 = get_wc_state(wc_dir) 371 assert modified_state1 != initial_state 372 373 # Shelve; check there are no longer any local mods 374 svntest.actions.run_and_verify_svn(None, [], 375 'x-shelve', 'foo') 376 check_wc_state(wc_dir, initial_state) 377 378 # Make a different local mod that will conflict with the shelf 379 modifier2(sbox) 380 modified_state2 = get_wc_state(wc_dir) 381 382 # Try to unshelve; check it fails with an error about a conflict 383 svntest.actions.run_and_verify_svn(None, '.*[Cc]onflict.*', 384 'x-unshelve', 'foo') 385 # Check nothing changed in the attempt 386 check_wc_state(wc_dir, modified_state2) 387 388#---------------------------------------------------------------------- 389 390@SkipUnless(shelf3_enabled) 391def shelve_binary_file_mod(sbox): 392 "shelve binary file mod" 393 394 sbox.build(empty=True) 395 396 existing_files = ['A/B/existing'] 397 mod_files = ['bin', 'A/B/bin'] 398 399 sbox.simple_mkdir('A', 'A/B') 400 for f in existing_files + mod_files: 401 sbox.simple_add_text('\0\1\2\3\4\5', f) 402 sbox.simple_commit() 403 404 def modifier(sbox): 405 for f in mod_files: 406 sbox.simple_append(f, '\6\5\4\3\2\1\0', truncate=True) 407 408 shelve_unshelve(sbox, modifier) 409 410#---------------------------------------------------------------------- 411 412@SkipUnless(shelf3_enabled) 413def shelve_binary_file_add(sbox): 414 "shelve binary file add" 415 416 sbox.build(empty=True) 417 418 existing_files = ['A/B/existing'] 419 mod_files = ['bin', 'A/B/bin'] 420 421 sbox.simple_mkdir('A', 'A/B') 422 for f in existing_files: 423 sbox.simple_add_text('\0\1\2\3\4\5', f) 424 sbox.simple_commit() 425 426 def modifier(sbox): 427 for f in mod_files: 428 sbox.simple_add_text('\0\1\2\3\4\5', f) 429 430 shelve_unshelve(sbox, modifier) 431 432#---------------------------------------------------------------------- 433 434@SkipUnless(shelf3_enabled) 435def shelve_binary_file_del(sbox): 436 "shelve binary file del" 437 438 sbox.build(empty=True) 439 440 existing_files = ['A/B/existing'] 441 mod_files = ['bin', 'A/B/bin'] 442 443 sbox.simple_mkdir('A', 'A/B') 444 for f in existing_files + mod_files: 445 sbox.simple_add_text('\0\1\2\3\4\5', f) 446 sbox.simple_commit() 447 448 def modifier(sbox): 449 for f in mod_files: 450 sbox.simple_rm(f) 451 452 shelve_unshelve(sbox, modifier) 453 454#---------------------------------------------------------------------- 455 456@SkipUnless(shelf3_enabled) 457def shelve_binary_file_replace(sbox): 458 "shelve binary file replace" 459 460 sbox.build(empty=True) 461 462 existing_files = ['A/B/existing'] 463 mod_files = ['bin', 'A/B/bin'] 464 465 sbox.simple_mkdir('A', 'A/B') 466 for f in existing_files + mod_files: 467 sbox.simple_add_text('\0\1\2\3\4\5', f) 468 sbox.simple_commit() 469 470 def modifier(sbox): 471 for f in mod_files: 472 sbox.simple_rm(f) 473 sbox.simple_add_text('\6\5\4\3\2\1\0', f) 474 475 shelve_unshelve(sbox, modifier) 476 477#---------------------------------------------------------------------- 478 479@SkipUnless(shelf3_enabled) 480def shelve_with_log_message(sbox): 481 "shelve with log message" 482 483 sbox.build(empty=True) 484 was_cwd = os.getcwd() 485 os.chdir(sbox.wc_dir) 486 sbox.wc_dir = '' 487 488 sbox.simple_add_text('New file', 'f') 489 log_message = 'Log message for foo' 490 svntest.actions.run_and_verify_svn(None, [], 491 'x-shelve', 'foo', '-m', log_message) 492 expected_output = svntest.verify.RegexListOutput( 493 ['foo .*', 494 ' ' + log_message 495 ]) 496 svntest.actions.run_and_verify_svn(expected_output, [], 497 'x-shelf-list') 498 499 os.chdir(was_cwd) 500 501#---------------------------------------------------------------------- 502 503def run_and_verify_status(wc_dir_name, status_tree, changelists=[]): 504 """Run 'status' on WC_DIR_NAME and compare it with the 505 expected STATUS_TREE. 506 Returns on success, raises on failure.""" 507 508 if not isinstance(status_tree, wc.State): 509 raise TypeError('wc.State tree expected') 510 511 cl_opts = ('--cl=' + cl for cl in changelists) 512 exit_code, output, errput = svntest.main.run_svn(None, 'status', '-q', 513 wc_dir_name, *cl_opts) 514 515 actual_status = svntest.wc.State.from_status(output, wc_dir=wc_dir_name) 516 517 # Verify actual output against expected output. 518 try: 519 status_tree.compare_and_display('status', actual_status) 520 except svntest.tree.SVNTreeError: 521 svntest.actions._log_tree_state("ACTUAL STATUS TREE:", actual_status.old_tree(), 522 wc_dir_name) 523 raise 524 525def run_and_verify_shelf_status(wc_dir, expected_status, shelf): 526 run_and_verify_status(wc_dir, expected_status, 527 changelists=['svn:shelf:' + shelf]) 528 529@SkipUnless(shelf3_enabled) 530def shelf_status(sbox): 531 "shelf status" 532 533 sbox.build() 534 was_cwd = os.getcwd() 535 os.chdir(sbox.wc_dir) 536 sbox.wc_dir = '' 537 538 sbox.simple_add_text('New file', 'f') 539 sbox.simple_append('iota', 'New text') 540 sbox.simple_propset('p', 'v', 'A/mu') 541 sbox.simple_rm('A/B/lambda') 542 # Not yet supported: 543 #sbox.simple_rm('A/B/E') 544 expected_status = state_from_status(sbox.wc_dir, v=False, u=False, q=False) 545 run_and_verify_status(sbox.wc_dir, expected_status) 546 547 svntest.actions.run_and_verify_svn(None, [], 548 'x-shelve', 'foo') 549 run_and_verify_shelf_status(sbox.wc_dir, expected_status, shelf='foo') 550 551 os.chdir(was_cwd) 552 553#---------------------------------------------------------------------- 554 555@XFail() 556@SkipUnless(shelf3_enabled) 557def shelve_mkdir(sbox): 558 "shelve mkdir" 559 560 sbox.build() 561 562 def modifier(sbox): 563 sbox.simple_mkdir('D', 'D/D2') 564 sbox.simple_propset('p', 'v', 'D', 'D/D2') 565 566 shelve_unshelve(sbox, modifier) 567 568#---------------------------------------------------------------------- 569 570@SkipUnless(shelf3_enabled) 571def shelve_rmdir(sbox): 572 "shelve rmdir" 573 574 sbox.build() 575 sbox.simple_propset('p', 'v', 'A/C') 576 sbox.simple_commit() 577 578 def modifier(sbox): 579 sbox.simple_rm('A/C', 'A/D/G') 580 581 shelve_unshelve(sbox, modifier) 582 583#---------------------------------------------------------------------- 584 585@XFail() 586@SkipUnless(shelf3_enabled) 587def shelve_replace_dir(sbox): 588 "shelve replace dir" 589 590 sbox.build() 591 sbox.simple_propset('p', 'v', 'A/C') 592 sbox.simple_commit() 593 594 def modifier(sbox): 595 sbox.simple_rm('A/C', 'A/D/G') 596 sbox.simple_mkdir('A/C', 'A/C/D2') 597 598 shelve_unshelve(sbox, modifier) 599 600#---------------------------------------------------------------------- 601 602@SkipUnless(shelf3_enabled) 603def shelve_file_copy(sbox): 604 "shelve file copy" 605 606 sbox.build() 607 608 def modifier(sbox): 609 sbox.simple_copy('iota', 'A/ii') 610 sbox.simple_propset('p', 'v', 'A/ii') 611 612 shelve_unshelve(sbox, modifier) 613 614#---------------------------------------------------------------------- 615 616@SkipUnless(shelf3_enabled) 617def shelve_dir_copy(sbox): 618 "shelve dir copy" 619 620 sbox.build() 621 622 def modifier(sbox): 623 sbox.simple_copy('A/B', 'BB') 624 sbox.simple_propset('p', 'v', 'BB') 625 626 shelve_unshelve(sbox, modifier) 627 628#---------------------------------------------------------------------- 629 630@SkipUnless(shelf3_enabled) 631def list_shelves(sbox): 632 "list_shelves" 633 634 sbox.build() 635 was_cwd = os.getcwd() 636 os.chdir(sbox.wc_dir) 637 sbox.wc_dir = '' 638 639 # an empty list 640 svntest.actions.run_and_verify_svn([], [], 641 'x-shelf-list', '-q') 642 643 # make two shelves 644 sbox.simple_append('A/mu', 'appended mu text') 645 svntest.actions.run_and_verify_svn(None, [], 646 'x-shelf-save', 'foo') 647 sbox.simple_append('A/mu', 'appended more text') 648 svntest.actions.run_and_verify_svn(None, [], 649 'x-shelf-save', 'foo', '-m', 'log msg') 650 svntest.actions.run_and_verify_svn(None, [], 651 'x-shelf-save', 'bar', '-m', 'log msg') 652 653 # We don't check for time-ordering of the shelves. If we want to do so, we 654 # would need to sleep for timestamps to differ, between creating them. 655 656 # a quiet list 657 expected_out = svntest.verify.UnorderedRegexListOutput(['foo', 'bar']) 658 svntest.actions.run_and_verify_svn(expected_out, [], 659 'x-shelf-list', '-q') 660 661 # a detailed list 662 expected_out = svntest.verify.UnorderedRegexListOutput(['foo .* 1 path.*', 663 ' log msg', 664 'bar .* 1 path.*', 665 ' log msg']) 666 svntest.actions.run_and_verify_svn(expected_out, [], 667 'x-shelf-list') 668 669 os.chdir(was_cwd) 670 671#---------------------------------------------------------------------- 672 673@SkipUnless(shelf3_enabled) 674def refuse_to_shelve_conflict(sbox): 675 "refuse to shelve conflict" 676 677 sbox.build(empty=True) 678 was_cwd = os.getcwd() 679 os.chdir(sbox.wc_dir) 680 sbox.wc_dir = '' 681 682 # create a conflict 683 sbox.simple_mkdir('topdir') 684 sbox.simple_commit() 685 sbox.simple_update() 686 svntest.actions.run_and_verify_svn( 687 None, [], 688 'merge', '-c1', '.', '--ignore-ancestry', '--accept', 'postpone') 689 # check that we did create a conflict 690 svntest.actions.run_and_verify_svn( 691 None, 'svn: E155035:.*conflict.*', 692 'merge', '-c1', '.', '--ignore-ancestry', '--accept', 'postpone') 693 694 # attempt to shelve 695 expected_err = "svn: E155015: .* '.*topdir' remains in conflict" 696 svntest.actions.run_and_verify_svn(None, expected_err, 697 'x-shelf-save', 'foo') 698 699 os.chdir(was_cwd) 700 701#---------------------------------------------------------------------- 702 703def unshelve_with_merge(sbox, setup, modifier1, modifier2, tweak_expected_state): 704 """Run a test scenario in which 'unshelve' needs to merge some shelved 705 changes made by modifier1() with some committed changes made by 706 modifier2(). tweak_expected_state() must produce the expected WC state. 707 """ 708 sbox.build() 709 was_cwd = os.getcwd() 710 os.chdir(sbox.wc_dir) 711 sbox.wc_dir = '' 712 wc_dir = sbox.wc_dir 713 714 setup(sbox) 715 sbox.simple_commit() 716 initial_state = get_wc_state(wc_dir) 717 718 # Make some changes to the working copy 719 modifier1(sbox) 720 modified_state = get_wc_state(wc_dir) 721 722 # Shelve; check there are no longer any modifications 723 svntest.actions.run_and_verify_svn(None, [], 724 'x-shelve', 'foo') 725 check_wc_state(wc_dir, initial_state) 726 727 # Make a different change, with which we shall merge 728 modifier2(sbox) 729 sbox.simple_commit() 730 modified_state[0].tweak('A/mu', wc_rev='3') 731 732 # Unshelve; check the expected result of the merge 733 svntest.actions.run_and_verify_svn(None, [], 734 'x-unshelve', 'foo') 735 tweak_expected_state(modified_state) 736 check_wc_state(wc_dir, modified_state) 737 738 os.chdir(was_cwd) 739 740@XFail() 741@SkipUnless(shelf3_enabled) 742def unshelve_text_mod_merge(sbox): 743 "unshelve text mod merge" 744 745 orig_contents='A\nB\nC\nD\nE\n' 746 mod1_contents='A\nBB\nC\nD\nE\n' 747 mod2_contents='A\nB\nC\nDD\nE\n' 748 merged_contents='A\nBB\nC\nDD\nE\n' 749 750 def setup(sbox): 751 sbox.simple_append('A/mu', orig_contents, truncate=True) 752 753 def modifier1(sbox): 754 sbox.simple_append('A/mu', mod1_contents, truncate=True) 755 756 def modifier2(sbox): 757 sbox.simple_append('A/mu', mod2_contents, truncate=True) 758 759 def tweak_expected_state(modified_state): 760 modified_state[1].tweak('A/mu', contents=merged_contents) 761 762 unshelve_with_merge(sbox, setup, modifier1, modifier2, tweak_expected_state) 763 764#---------------------------------------------------------------------- 765 766@XFail() 767@SkipUnless(shelf3_enabled) 768def unshelve_text_mod_conflict(sbox): 769 "unshelve text mod conflict" 770 771 orig_contents='A\nB\nC\nD\nE\n' 772 mod1_contents='A\nBB\nC\nD\nE\n' 773 mod2_contents='A\nBCD\nC\nD\nE\n' 774 merged_contents = 'A\n<<<<<<< .working\nBCD\n||||||| .merge-left\nB\n=======\nBB\n>>>>>>> .merge-right\nC\nD\nE\n' 775 776 def setup(sbox): 777 sbox.simple_append('A/mu', orig_contents, truncate=True) 778 779 def modifier1(sbox): 780 sbox.simple_append('A/mu', mod1_contents, truncate=True) 781 782 def modifier2(sbox): 783 sbox.simple_append('A/mu', mod2_contents, truncate=True) 784 785 def tweak_expected_state(modified_state): 786 modified_state[0].tweak('A/mu', status='C ') 787 modified_state[1].tweak('A/mu', contents=merged_contents) 788 modified_state[1].add({ 789 'A/mu.merge-left': Item(contents=orig_contents), 790 'A/mu.merge-right': Item(contents=mod1_contents), 791 'A/mu.working': Item(contents=mod2_contents), 792 }) 793 794 unshelve_with_merge(sbox, setup, modifier1, modifier2, tweak_expected_state) 795 796#---------------------------------------------------------------------- 797 798@XFail() 799@SkipUnless(shelf3_enabled) 800def unshelve_undeclared_binary_mod_conflict(sbox): 801 "unshelve undeclared binary mod conflict" 802 803 orig_contents='\1\2\3\4\5' 804 mod1_contents='\1\2\2\3\4\5' 805 mod2_contents='\1\2\3\4\3\4\5' 806 merged_contents = '<<<<<<< .working\n' + mod2_contents + '||||||| .merge-left\n' + orig_contents + '=======\n' + mod1_contents + '>>>>>>> .merge-right\n' 807 808 def setup(sbox): 809 sbox.simple_append('A/mu', orig_contents, truncate=True) 810 811 def modifier1(sbox): 812 sbox.simple_append('A/mu', mod1_contents, truncate=True) 813 814 def modifier2(sbox): 815 sbox.simple_append('A/mu', mod2_contents, truncate=True) 816 817 def tweak_expected_state(modified_state): 818 modified_state[0].tweak('A/mu', status='C ') 819 modified_state[1].tweak('A/mu', contents=merged_contents) 820 modified_state[1].add({ 821 'A/mu.merge-left': Item(contents=orig_contents), 822 'A/mu.merge-right': Item(contents=mod1_contents), 823 'A/mu.working': Item(contents=mod2_contents), 824 }) 825 826 unshelve_with_merge(sbox, setup, modifier1, modifier2, tweak_expected_state) 827 828#---------------------------------------------------------------------- 829 830@XFail() 831@SkipUnless(shelf3_enabled) 832def unshelve_binary_mod_conflict(sbox): 833 "unshelve binary mod conflict" 834 835 orig_contents='\1\2\3\4\5' 836 mod1_contents='\1\2\2\3\4\5' 837 mod2_contents='\1\2\3\4\3\4\5' 838 839 def setup(sbox): 840 sbox.simple_append('A/mu', orig_contents, truncate=True) 841 sbox.simple_propset('svn:mime-type', 'application/octet-stream', 'A/mu') 842 843 def modifier1(sbox): 844 sbox.simple_append('A/mu', mod1_contents, truncate=True) 845 846 def modifier2(sbox): 847 sbox.simple_append('A/mu', mod2_contents, truncate=True) 848 849 def tweak_expected_state(modified_state): 850 modified_state[0].tweak('A/mu', status='C ') 851 modified_state[1].tweak('A/mu', contents=mod2_contents) 852 modified_state[1].add({ 853 'A/mu.merge-left': Item(contents=orig_contents), 854 'A/mu.merge-right': Item(contents=mod1_contents), 855 }) 856 857 unshelve_with_merge(sbox, setup, modifier1, modifier2, tweak_expected_state) 858 859#---------------------------------------------------------------------- 860 861@SkipUnless(shelf3_enabled) 862def unshelve_text_prop_merge(sbox): 863 "unshelve text prop merge" 864 865 def setup(sbox): 866 sbox.simple_propset('p1', 'v', 'A/mu') 867 sbox.simple_propset('p2', 'v', 'A/mu') 868 869 def modifier1(sbox): 870 sbox.simple_propset('p1', 'changed', 'A/mu') 871 872 def modifier2(sbox): 873 sbox.simple_propset('p2', 'changed', 'A/mu') 874 875 def tweak_expected_state(wc_state): 876 wc_state[1].tweak('A/mu', props={'p1':'changed', 877 'p2':'changed'}) 878 879 unshelve_with_merge(sbox, setup, modifier1, modifier2, tweak_expected_state) 880 881#---------------------------------------------------------------------- 882 883@XFail() 884@SkipUnless(shelf3_enabled) 885def unshelve_text_prop_conflict(sbox): 886 "unshelve text prop conflict" 887 888 orig_contents='A' 889 mod1_contents='B' 890 mod2_contents='C' 891 merged_contents='C' 892 prej_contents='''Trying to change property 'p' 893but the local property value conflicts with the incoming change. 894<<<<<<< (local property value) 895C||||||| (incoming 'changed from' value) 896A======= 897B>>>>>>> (incoming 'changed to' value) 898''' 899 900 def setup(sbox): 901 sbox.simple_propset('p', orig_contents, 'A/mu') 902 903 def modifier1(sbox): 904 sbox.simple_propset('p', mod1_contents, 'A/mu') 905 906 def modifier2(sbox): 907 sbox.simple_propset('p', mod2_contents, 'A/mu') 908 909 def tweak_expected_state(wc_state): 910 wc_state[0].tweak('A/mu', status=' C') 911 wc_state[1].tweak('A/mu', props={'p':merged_contents}) 912 wc_state[1].add({ 913 'A/mu.prej': Item(contents=prej_contents), 914 }) 915 916 unshelve_with_merge(sbox, setup, modifier1, modifier2, tweak_expected_state) 917 918#---------------------------------------------------------------------- 919 920def run_and_verify_shelf_diff_summarize(output_tree, shelf, *args): 921 """Run 'svn shelf-diff --summarize' with the arguments *ARGS. 922 923 The subcommand output will be verified against OUTPUT_TREE. Returns 924 on success, raises on failure. 925 """ 926 927 if isinstance(output_tree, wc.State): 928 output_tree = output_tree.old_tree() 929 930 exit_code, output, errput = svntest.actions.run_and_verify_svn( 931 None, [], 932 'x-shelf-diff', '--summarize', shelf, *args) 933 934 actual = svntest.tree.build_tree_from_diff_summarize(output) 935 936 # Verify actual output against expected output. 937 try: 938 svntest.tree.compare_trees("output", actual, output_tree) 939 except svntest.tree.SVNTreeError: 940 svntest.verify.display_trees(None, 'DIFF OUTPUT TREE', output_tree, actual) 941 raise 942 943#---------------------------------------------------------------------- 944 945# Exercise a very basic case of shelf-diff. 946@SkipUnless(shelf3_enabled) 947def shelf_diff_simple(sbox): 948 "shelf diff simple" 949 950 sbox.build() 951 was_cwd = os.getcwd() 952 os.chdir(sbox.wc_dir) 953 sbox.wc_dir = '' 954 wc_dir = sbox.wc_dir 955 956 def setup(sbox): 957 sbox.simple_propset('p1', 'v', 'A/mu') 958 sbox.simple_propset('p2', 'v', 'A/mu') 959 960 def modifier1(sbox): 961 sbox.simple_rm('A/B/lambda') 962 sbox.simple_add_text('This is a new file.\n', 'A/B/new') 963 sbox.simple_append('A/mu', 'New line.\n') 964 sbox.simple_propset('p1', 'changed', 'A/mu') 965 966 setup(sbox) 967 sbox.simple_commit() 968 initial_state = get_wc_state(wc_dir) 969 970 # Make some changes to the working copy 971 modifier1(sbox) 972 modified_state = get_wc_state(wc_dir) 973 974 svntest.actions.run_and_verify_svn(None, [], 975 'x-shelf-save', 'foo') 976 977 # basic svn-style diff 978 expected_output = make_diff_header('A/B/lambda', 'revision 2', 'nonexistent') + [ 979 "@@ -1 +0,0 @@\n", 980 "-This is the file 'lambda'.\n" 981 ] 982 expected_output += make_diff_header('A/B/new', 'nonexistent', 'working copy') + [ 983 "@@ -0,0 +1 @@\n", 984 "+This is a new file.\n" 985 ] 986 expected_output += make_diff_header('A/mu', 'revision 2', 'working copy') + [ 987 "@@ -1 +1,2 @@\n", 988 " This is the file 'mu'.\n", 989 "+New line.\n", 990 ] + make_diff_prop_header('A/mu') \ 991 + make_diff_prop_modified('p1', 'v', 'changed') 992 svntest.actions.run_and_verify_svn(expected_output, [], 993 'x-shelf-diff', 'foo') 994 995 # basic summary diff 996 expected_diff = svntest.wc.State(wc_dir, { 997 'A/B/lambda': Item(status='D '), 998 'A/B/new': Item(status='A '), 999 'A/mu': Item(status='MM'), 1000 }) 1001 run_and_verify_shelf_diff_summarize(expected_diff, 'foo') 1002 1003#---------------------------------------------------------------------- 1004 1005@XFail() 1006@Issue(4827) 1007@SkipUnless(shelf3_enabled) 1008def shelve_with_kw_translation(sbox): 1009 "shelve with kw translation" 1010 sbox.build(empty=True) 1011 sbox.simple_add_text('$Rev$\n', 'file') 1012 sbox.simple_propset('svn:keywords', 'rev', 'file') 1013 sbox.simple_commit() 1014 sbox.simple_update() 1015 1016 def modifier(sbox): 1017 sbox.simple_append('file', 'New line\n') 1018 1019 shelve_unshelve(sbox, modifier) 1020 1021 1022######################################################################## 1023# Run the tests 1024 1025# list all tests here, starting with None: 1026test_list = [ None, 1027 shelve_text_mods, 1028 shelve_prop_changes, 1029 shelve_adds, 1030 shelve_deletes, 1031 shelve_replace, 1032 shelve_empty_adds, 1033 shelve_empty_deletes, 1034 shelve_from_inner_path, 1035 checkpoint_basic, 1036 shelve_mergeinfo, 1037 unshelve_refuses_if_conflicts, 1038 shelve_binary_file_mod, 1039 shelve_binary_file_add, 1040 shelve_binary_file_del, 1041 shelve_binary_file_replace, 1042 shelve_with_log_message, 1043 shelf_status, 1044 shelve_mkdir, 1045 shelve_rmdir, 1046 shelve_replace_dir, 1047 shelve_file_copy, 1048 shelve_dir_copy, 1049 list_shelves, 1050 refuse_to_shelve_conflict, 1051 unshelve_text_mod_merge, 1052 unshelve_text_mod_conflict, 1053 unshelve_undeclared_binary_mod_conflict, 1054 unshelve_binary_mod_conflict, 1055 unshelve_text_prop_merge, 1056 unshelve_text_prop_conflict, 1057 shelf_diff_simple, 1058 shelve_with_kw_translation, 1059 ] 1060 1061if __name__ == '__main__': 1062 svntest.main.run_tests(test_list) 1063 # NOTREACHED 1064 1065 1066### End of file. 1067