blob: cbb0d177eb086bd42aed2f9e7822852e3e7f8c3e [file] [log] [blame]
#!/usr/bin/env python
#
# copy_tests.py: testing the many uses of 'svn cp' and 'svn mv'
#
# Subversion is a tool for revision control.
# See http://subversion.tigris.org for more information.
#
# ====================================================================
# Copyright (c) 2000-2001 CollabNet. All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at http://subversion.tigris.org/license-1.html.
# If newer versions of this license are posted there, you may use a
# newer version instead, at your option.
#
######################################################################
# General modules
import string, sys, os
# Our testing module
import svntest
# (abbreviation)
path_index = svntest.actions.path_index
######################################################################
# Utilities
#
######################################################################
# Tests
#
# Each test must return 0 on success or non-zero on failure.
# (Taken from notes/copy-planz.txt:)
#
# We have four use cases for 'svn cp' now.
#
# A. svn cp wc_path1 wc_path2
#
# This duplicates a path in the working copy, and schedules it
# for addition with history. (This is partially implemented in
# 0.6 already.)
#
# B. svn cp URL [-r rev] wc_path
#
# This "checks out" URL (in REV) into the working copy at
# wc_path, integrates it, and schedules it for addition with
# history.
#
# C. svn cp wc_path URL
#
# This immediately commits wc_path to URL on the server; the
# commit will be an addition with history. The commit will not
# change the working copy at all.
#
# D. svn cp URL1 [-r rev] URL2
#
# This causes a server-side copy to happen immediately; no
# working copy is required.
# TESTS THAT NEED TO BE WRITTEN
#
# Use Cases A & C
#
# -- single files, with/without local mods, as both 'cp' and 'mv'.
# (need to verify commit worked by updating a 2nd working copy
# to see the local mods)
#
# -- dir copy, has mixed revisions
#
# -- dir copy, has local mods (an edit, an add, a delete, and a replace)
#
# -- dir copy, has mixed revisions AND local mods
#
# -- dir copy, has mixed revisions AND another previously-made copy!
# (perhaps done as two nested 'mv' commands!)
#
# Use Case D
#
# By the time the copy setup algorithm is complete, the copy
# operation will have four parts: SRC-DIR, SRC-BASENAME, DST-DIR,
# DST-BASENAME. In all cases, SRC-DIR/SRC-BASENAME and DST_DIR must
# already exist before the operation, but DST_DIR/DST_BASENAME must
# NOT exist.
#
# Besides testing things that don't meet the above criteria, we want to
# also test valid cases:
#
# - where SRC-DIR/SRC-BASENAME is a file or a dir.
# - where SRC-DIR (or SRC-DIR/SRC-BASENAME) is a parent/grandparent
# directory of DST-DIR
# - where SRC-DIR (or SRC-DIR/SRC-BASENAME) is a child/grandchild
# directory of DST-DIR
# - where SRC-DIR (or SRC-DIR/SRC-BASENAME) is not in the lineage
# of DST-DIR at all
#----------------------------------------------------------------------
def basic_copy_and_move_files(sbox):
"basic copy and move commands -- on files only"
if sbox.build():
return 1
wc_dir = sbox.wc_dir
mu_path = os.path.join(wc_dir, 'A', 'mu')
iota_path = os.path.join(wc_dir, 'iota')
rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho')
D_path = os.path.join(wc_dir, 'A', 'D')
C_path = os.path.join(wc_dir, 'A', 'C')
alpha_path = os.path.join(wc_dir, 'A', 'B', 'E', 'alpha')
H_path = os.path.join(wc_dir, 'A', 'D', 'H')
F_path = os.path.join(wc_dir, 'A', 'B', 'F')
new_mu_path = os.path.join(H_path, 'mu')
new_iota_path = os.path.join(F_path, 'iota')
rho_copy_path = os.path.join(D_path, 'rho')
alpha2_path = os.path.join(C_path, 'alpha2')
# Make local mods to mu and rho
svntest.main.file_append (mu_path, 'appended mu text')
svntest.main.file_append (rho_path, 'new appended text for rho')
# Copy rho to D -- local mods
svntest.main.run_svn(None, 'cp', rho_path, D_path)
# Copy alpha to C -- no local mods, and rename it to 'alpha2' also
svntest.main.run_svn(None, 'cp', alpha_path, alpha2_path)
# Move mu to H -- local mods
svntest.main.run_svn(None, 'mv', mu_path, H_path)
# Move iota to F -- no local mods
svntest.main.run_svn(None, 'mv', iota_path, F_path)
# Created expected output tree for 'svn ci':
# We should see four adds, two deletes, and one change in total.
output_list = [ [rho_path, None, {}, {'verb' : 'Sending' }],
[rho_copy_path, None, {}, {'verb' : 'Adding' }],
[alpha2_path, None, {}, {'verb' : 'Adding' }],
[new_mu_path, None, {}, {'verb' : 'Adding' }],
[new_iota_path, None, {}, {'verb' : 'Adding' }],
[mu_path, None, {}, {'verb' : 'Deleting' }],
[iota_path, None, {}, {'verb' : 'Deleting' }], ]
expected_output_tree = svntest.tree.build_generic_tree(output_list)
# Create expected status tree; all local revisions should be at 1,
# but several files should be at revision 2. Also, two files should
# be missing.
status_list = svntest.actions.get_virginal_status_list(wc_dir, '2')
for item in status_list:
item[3]['wc_rev'] = '1'
if (item[0] == rho_path) or (item[0] == mu_path):
item[3]['wc_rev'] = '2'
# New items in the status tree:
status_list.append([rho_copy_path, None, {},
{'status' : '_ ',
'wc_rev' : '2',
'repos_rev' : '2'}])
status_list.append([alpha2_path, None, {},
{'status' : '_ ',
'wc_rev' : '2',
'repos_rev' : '2'}])
status_list.append([new_mu_path, None, {},
{'status' : '_ ',
'wc_rev' : '2',
'repos_rev' : '2'}])
status_list.append([new_iota_path, None, {},
{'status' : '_ ',
'wc_rev' : '2',
'repos_rev' : '2'}])
# Items that are gone:
status_list.pop(path_index(status_list, mu_path))
status_list.pop(path_index(status_list, iota_path))
expected_status_tree = svntest.tree.build_generic_tree(status_list)
return svntest.actions.run_and_verify_commit (wc_dir,
expected_output_tree,
expected_status_tree,
None,
None, None,
None, None,
wc_dir)
def mv_unversioned_file(sbox):
"Test fix for 'svn mv unversioned_file some_dst'"
##################### Here is the bug Lars saw ######################
#
# From: Lars Kellogg-Stedman <lars@larsshack.org>
# Subject: svn mv segfault
# To: dev@subversion.tigris.org
# Date: Tue, 29 Jan 2002 15:40:00 -0500
#
# Here's a new one. And this one's reliable :).
#
# I tried performing the following operation:
#
# $ svn mv src/config.h.in .
#
# But src/config.h.in wasn't in the repository. This should have
# generated an error, right around line 141 in libsvn_wc/copy.c. But
# instead it's segfaulting.
#
# This is in copy_file_administratively(), in the following section:
#
# SVN_ERR (svn_wc_entry (&src_entry, src_path, pool));
# if ((src_entry->schedule == svn_wc_schedule_add)
# || (! src_entry->url))
# return svn_error_createf
# (SVN_ERR_UNSUPPORTED_FEATURE, 0, NULL, pool,
# "Not allowed to copy or move '%s' -- it's not in the
# repository yet.\n"
# "Try committing first.",
# src_path->data);
#
# The first thing svn_wc_entry() does is set src_entry to NULL, so upon
# our return from svn_wc_entry(), when we try to look at
# src_entry->schedule, we're attempting to dereference a NULL pointer.
# Ouch!
#
# It looks like the real failure may be in svn_wc_entry(), here:
#
# /* ### it would be nice to avoid reading all of these. or maybe read
# ### them into a subpool and copy the one that we need up to the
# ### specified pool. */
# SVN_ERR (svn_wc_entries_read (&entries, dir, pool));
#
# *entry = apr_hash_get (entries, basename->data, basename->len);
#
# Since the file isn't under revision control, that hash lookup is
# probably going to fail, so src_entry never gets set to anything but
# NULL.
#
# Cheers,
#
# -- Lars
if sbox.build():
return 1
wc_dir = sbox.wc_dir
unver_path = os.path.join(wc_dir, 'A', 'unversioned')
dst_path = os.path.join(wc_dir, 'A', 'hypothetical-dest')
svntest.main.file_append(unver_path, "an unversioned file")
output, errput = svntest.main.run_svn(1, 'mv', unver_path, dst_path)
for line in errput:
if string.find(line, "not under revision control") != -1:
return 0
return 1
########################################################################
# Run the tests
# list all tests here, starting with None:
test_list = [ None,
basic_copy_and_move_files,
mv_unversioned_file,
]
if __name__ == '__main__':
svntest.main.run_tests(test_list)
# NOTREACHED
### End of file.
# local variables:
# eval: (load-file "../../../../tools/dev/svn-dev.el")
# end: