You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by pb...@apache.org on 2010/11/15 19:50:41 UTC

svn commit: r1035404 [15/15] - in /subversion/branches/issue-3668-3669: ./ build/ build/generator/ build/generator/templates/ build/win32/ subversion/bindings/javahl/native/ subversion/bindings/javahl/src/org/apache/subversion/javahl/ subversion/bindin...

Modified: subversion/branches/issue-3668-3669/subversion/svn/changelist-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3668-3669/subversion/svn/changelist-cmd.c?rev=1035404&r1=1035403&r2=1035404&view=diff
==============================================================================
--- subversion/branches/issue-3668-3669/subversion/svn/changelist-cmd.c (original)
+++ subversion/branches/issue-3668-3669/subversion/svn/changelist-cmd.c Mon Nov 15 18:50:38 2010
@@ -55,9 +55,6 @@ svn_cl__changelist(apr_getopt_t *os,
       apr_array_header_t *args;
       SVN_ERR(svn_opt_parse_num_args(&args, os, 1, pool));
       changelist_name = APR_ARRAY_IDX(args, 0, const char *);
-      if (changelist_name[0] == '\0')
-        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
-                                _("Changelist names must not be empty"));
       SVN_ERR(svn_utf_cstring_to_utf8(&changelist_name,
                                       changelist_name, pool));
     }

Modified: subversion/branches/issue-3668-3669/subversion/svn/main.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3668-3669/subversion/svn/main.c?rev=1035404&r1=1035403&r2=1035404&view=diff
==============================================================================
--- subversion/branches/issue-3668-3669/subversion/svn/main.c (original)
+++ subversion/branches/issue-3668-3669/subversion/svn/main.c Mon Nov 15 18:50:38 2010
@@ -367,6 +367,7 @@ const apr_getopt_option_t svn_cl__option
   {"iw",            opt_ignore_whitespace, 0, NULL},
   {"idiff",         opt_internal_diff, 0, NULL},
   {"keep-locks",    opt_no_unlock, 0, NULL},
+  {"keep-cl",       opt_keep_changelists, 0, NULL},
 
   {0,               0, 0, 0},
 };
@@ -1168,10 +1169,17 @@ const svn_opt_subcommand_desc2_t svn_cl_
      "  are applied to the obstructing path.  Obstructing paths are reported\n"
      "  in the first column with code 'E'.\n"
      "\n"
+     "  If the specified update target is missing from the working copy but its\n"
+     "  immediate parent directory is present, checkout the target into its\n"
+     "  parent directory at the specified depth.  If --parents is specified,\n"
+     "  create any missing parent directories of the target by checking them\n"
+     "  out, too, at depth=empty.\n"
+     "\n"
      "  Use the --set-depth option to set a new working copy depth on the\n"
      "  targets of this operation.\n"),
     {'r', 'N', opt_depth, opt_set_depth, 'q', opt_merge_cmd, opt_force,
-     opt_ignore_externals, opt_changelist, opt_editor_cmd, opt_accept} },
+     opt_ignore_externals, opt_changelist, opt_editor_cmd, opt_accept,
+     opt_parents} },
 
   { "upgrade", svn_cl__upgrade, {0}, N_
     ("Upgrade the metadata storage format for a working copy.\n"

Modified: subversion/branches/issue-3668-3669/subversion/svn/patch-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3668-3669/subversion/svn/patch-cmd.c?rev=1035404&r1=1035403&r2=1035404&view=diff
==============================================================================
--- subversion/branches/issue-3668-3669/subversion/svn/patch-cmd.c (original)
+++ subversion/branches/issue-3668-3669/subversion/svn/patch-cmd.c Mon Nov 15 18:50:38 2010
@@ -48,29 +48,43 @@ svn_cl__patch(apr_getopt_t *os,
 {
   svn_cl__opt_state_t *opt_state;
   svn_client_ctx_t *ctx;
-  apr_array_header_t *args;
   apr_array_header_t *targets;
   const char *abs_patch_path;
+  const char *patch_path;
   const char *abs_target_path;
+  const char *target_path;
 
   opt_state = ((svn_cl__cmd_baton_t *)baton)->opt_state;
   ctx = ((svn_cl__cmd_baton_t *)baton)->ctx;
 
-  SVN_ERR(svn_opt_parse_num_args(&args, os, 1, pool));
-  SVN_ERR(svn_dirent_get_absolute(&abs_patch_path,
-                                  APR_ARRAY_IDX(args, 0, const char *),
-                                  pool));
-
-  SVN_ERR(svn_client_args_to_target_array(&targets, os, opt_state->targets,
-                                          ctx, pool));
-  if (targets->nelts > 1)
+  SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
+                                                      opt_state->targets,
+                                                      ctx, pool));
+  SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, pool));
+
+  if (targets->nelts > 2)
     return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, 0, NULL);
 
-  svn_opt_push_implicit_dot_target(targets, pool);
-  SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, pool));
-  SVN_ERR(svn_dirent_get_absolute(&abs_target_path,
-                                  APR_ARRAY_IDX(targets, 0, const char *),
-                                  pool));
+  patch_path = APR_ARRAY_IDX(targets, 0, const char *);
+  if (svn_path_is_url(patch_path))
+    return svn_error_return(svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR,
+                                              NULL,
+                                              _("'%s' is not a local path"),
+                                              patch_path));
+  SVN_ERR(svn_dirent_get_absolute(&abs_patch_path, patch_path, pool));
+
+  if (targets->nelts == 1)
+    target_path = ""; /* "" is the canonical form of "." */
+  else
+    {
+      target_path = APR_ARRAY_IDX(targets, 1, const char *);
+      if (svn_path_is_url(target_path))
+        return svn_error_return(svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR,
+                                                  NULL,
+                                                  _("'%s' is not a local path"),
+                                                  target_path));
+    }
+  SVN_ERR(svn_dirent_get_absolute(&abs_target_path, target_path, pool));
 
   SVN_ERR(svn_client_patch(abs_patch_path, abs_target_path,
                            opt_state->dry_run, opt_state->strip,

Modified: subversion/branches/issue-3668-3669/subversion/svn/unlock-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3668-3669/subversion/svn/unlock-cmd.c?rev=1035404&r1=1035403&r2=1035404&view=diff
==============================================================================
--- subversion/branches/issue-3668-3669/subversion/svn/unlock-cmd.c (original)
+++ subversion/branches/issue-3668-3669/subversion/svn/unlock-cmd.c Mon Nov 15 18:50:38 2010
@@ -27,6 +27,7 @@
 
 /*** Includes. ***/
 
+#include "svn_path.h"
 #include "svn_pools.h"
 #include "svn_client.h"
 #include "svn_error_codes.h"
@@ -48,6 +49,8 @@ svn_cl__unlock(apr_getopt_t *os,
   svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
   svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
   apr_array_header_t *targets;
+  svn_boolean_t wc_present = FALSE, url_present = FALSE;
+  int i;
 
   SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
                                                       opt_state->targets,
@@ -59,6 +62,23 @@ svn_cl__unlock(apr_getopt_t *os,
 
   SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, scratch_pool));
 
+  /* Check to see if at least one of our paths is a working copy
+   * path or a repository url. */
+  for (i = 0; i < targets->nelts; ++i)
+    {
+      const char *target = APR_ARRAY_IDX(targets, i, const char *);
+
+      if (! svn_path_is_url(target))
+        wc_present = TRUE;
+      else
+        url_present = TRUE;
+    }
+
+  if (url_present && wc_present)
+    return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                             _("Cannot mix repository and working copy "
+                               "targets"));
+
   return svn_error_return(
     svn_client_unlock(targets, opt_state->force, ctx, scratch_pool));
 }

Modified: subversion/branches/issue-3668-3669/subversion/svn/update-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3668-3669/subversion/svn/update-cmd.c?rev=1035404&r1=1035403&r2=1035404&view=diff
==============================================================================
--- subversion/branches/issue-3668-3669/subversion/svn/update-cmd.c (original)
+++ subversion/branches/issue-3668-3669/subversion/svn/update-cmd.c Mon Nov 15 18:50:38 2010
@@ -92,11 +92,11 @@ svn_cl__update(apr_getopt_t *os,
   ctx->notify_func2 = svn_cl__check_externals_failed_notify_wrapper;
   ctx->notify_baton2 = &nwb;
   
-  SVN_ERR(svn_client_update3(NULL, targets,
+  SVN_ERR(svn_client_update4(NULL, targets,
                              &(opt_state->start_revision),
                              depth, depth_is_sticky,
                              opt_state->ignore_externals,
-                             opt_state->force,
+                             opt_state->force, opt_state->parents,
                              ctx, scratch_pool));
 
   if (! opt_state->quiet)

Modified: subversion/branches/issue-3668-3669/subversion/tests/cmdline/depth_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3668-3669/subversion/tests/cmdline/depth_tests.py?rev=1035404&r1=1035403&r2=1035404&view=diff
==============================================================================
--- subversion/branches/issue-3668-3669/subversion/tests/cmdline/depth_tests.py (original)
+++ subversion/branches/issue-3668-3669/subversion/tests/cmdline/depth_tests.py Mon Nov 15 18:50:38 2010
@@ -2718,6 +2718,90 @@ def update_depth_empty_root_of_infinite_
                                         None, None,
                                         None, None, None, None, wc_dir)
 
+def sparse_update_with_dash_dash_parents(sbox):
+  """update --parents"""
+
+  sbox.build(create_wc = False)
+  sbox.add_test_path(sbox.wc_dir, True)
+  alpha_path = os.path.join(sbox.wc_dir, 'A', 'B', 'E', 'alpha')
+  pi_path = os.path.join(sbox.wc_dir, 'A', 'D', 'G', 'pi')
+  omega_path = os.path.join(sbox.wc_dir, 'A', 'D', 'H', 'omega')
+  
+  # Start with a depth=empty root checkout.
+  svntest.actions.run_and_verify_svn(
+      "Unexpected error from co --depth=empty",
+      svntest.verify.AnyOutput, [],
+      "co", "--depth", "empty", sbox.repo_url, sbox.wc_dir)
+
+  # Now, let's use --parents to pull in some scattered file children.
+  expected_output = svntest.wc.State(sbox.wc_dir, {
+    'A'            : Item(status='A '),
+    'A/B'          : Item(status='A '),
+    'A/B/E'        : Item(status='A '),
+    'A/B/E/alpha'  : Item(status='A '),
+    })
+  expected_disk = svntest.wc.State('', {
+    'A'            : Item(contents=None),
+    'A/B'          : Item(contents=None),
+    'A/B/E'        : Item(contents=None),
+    'A/B/E/alpha'  : Item(contents="This is the file 'alpha'.\n"),
+    })
+  expected_status = svntest.wc.State(sbox.wc_dir, {
+    ''             : Item(status='  ', wc_rev=1),
+    'A'            : Item(status='  ', wc_rev=1),
+    'A/B'          : Item(status='  ', wc_rev=1),
+    'A/B/E'        : Item(status='  ', wc_rev=1),
+    'A/B/E/alpha'  : Item(status='  ', wc_rev=1),
+    })
+  svntest.actions.run_and_verify_update(sbox.wc_dir,
+                                        expected_output,
+                                        expected_disk,
+                                        expected_status,
+                                        None, None, None, None, None, False,
+                                        '--parents', alpha_path)
+
+  expected_output = svntest.wc.State(sbox.wc_dir, {
+    'A/D'          : Item(status='A '),
+    'A/D/G'        : Item(status='A '),
+    'A/D/G/pi'     : Item(status='A '),
+    })
+  expected_disk.add({
+    'A/D'          : Item(contents=None),
+    'A/D/G'        : Item(contents=None),
+    'A/D/G/pi'     : Item(contents="This is the file 'pi'.\n"),
+    })
+  expected_status.add({
+    'A/D'          : Item(status='  ', wc_rev=1),
+    'A/D/G'        : Item(status='  ', wc_rev=1),
+    'A/D/G/pi'     : Item(status='  ', wc_rev=1),
+    })    
+  svntest.actions.run_and_verify_update(sbox.wc_dir,
+                                        expected_output,
+                                        expected_disk,
+                                        expected_status,
+                                        None, None, None, None, None, False,
+                                        '--parents', pi_path)
+                    
+  expected_output = svntest.wc.State(sbox.wc_dir, {
+    'A/D/H'        : Item(status='A '),
+    'A/D/H/omega'  : Item(status='A '),
+    })
+  expected_disk.add({
+    'A/D/H'        : Item(contents=None),
+    'A/D/H/omega'  : Item(contents="This is the file 'omega'.\n"),
+    })
+  expected_status.add({
+    'A/D/H'        : Item(status='  ', wc_rev=1),
+    'A/D/H/omega'  : Item(status='  ', wc_rev=1),
+    })    
+  svntest.actions.run_and_verify_update(sbox.wc_dir,
+                                        expected_output,
+                                        expected_disk,
+                                        expected_status,
+                                        None, None, None, None, None, False,
+                                        '--parents', omega_path)
+  
+
 #----------------------------------------------------------------------
 # list all tests here, starting with None:
 test_list = [ None,
@@ -2763,6 +2847,7 @@ test_list = [ None,
               tree_conflicts_resolved_depth_infinity,
               update_excluded_path_sticky_depths,
               update_depth_empty_root_of_infinite_children,
+              sparse_update_with_dash_dash_parents,
               ]
 
 if __name__ == "__main__":

Modified: subversion/branches/issue-3668-3669/subversion/tests/cmdline/input_validation_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3668-3669/subversion/tests/cmdline/input_validation_tests.py?rev=1035404&r1=1035403&r2=1035404&view=diff
==============================================================================
--- subversion/branches/issue-3668-3669/subversion/tests/cmdline/input_validation_tests.py (original)
+++ subversion/branches/issue-3668-3669/subversion/tests/cmdline/input_validation_tests.py Mon Nov 15 18:50:38 2010
@@ -201,6 +201,13 @@ def invalid_lock_targets(sbox):
     run_and_verify_svn_in_wc(sbox, "svn: Cannot mix repository and working "
                              "copy targets", 'lock', target1, target2)
 
+def invalid_unlock_targets(sbox):
+  "wc paths and repo URL target mixture for 'unlock'"
+  sbox.build(read_only=True)
+  for (target1, target2) in [("iota", "^/"), ("file://", "iota")]:
+    run_and_verify_svn_in_wc(sbox, "svn: Cannot mix repository and working "
+                             "copy targets", 'unlock', target1, target2)
+
 def invalid_status_targets(sbox):
   "non-working copy paths for 'status'"
   sbox.build(read_only=True)
@@ -208,6 +215,13 @@ def invalid_status_targets(sbox):
     run_and_verify_svn_in_wc(sbox, "svn:.*is not a local path", 'status',
                              target)
 
+def invalid_patch_targets(sbox):
+  "non-working copy paths for 'patch'"
+  sbox.build(read_only=True)
+  for (target1, target2) in [("foo", "^/"), ("^/", "^/"), ("^/", "foo")]:
+    run_and_verify_svn_in_wc(sbox, "svn:.*is not a local path", 'patch',
+                             target1, target2)
+
 ########################################################################
 # Run the tests
 
@@ -230,7 +244,9 @@ test_list = [ None,
               invalid_resolved_targets,
               invalid_revert_targets,
               invalid_lock_targets,
+              invalid_unlock_targets,
               invalid_status_targets,
+              invalid_patch_targets,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/issue-3668-3669/subversion/tests/cmdline/patch_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3668-3669/subversion/tests/cmdline/patch_tests.py?rev=1035404&r1=1035403&r2=1035404&view=diff
==============================================================================
--- subversion/branches/issue-3668-3669/subversion/tests/cmdline/patch_tests.py (original)
+++ subversion/branches/issue-3668-3669/subversion/tests/cmdline/patch_tests.py Mon Nov 15 18:50:38 2010
@@ -3414,6 +3414,10 @@ def patch_one_property(sbox, trailing_eo
                                        1, # dry-run
                                        '--strip', '3')
 
+  if is_os_windows():
+    # On Windows 'svn pg' uses \r\n as EOL.
+    value = value.replace('\n', '\r\n')
+
   svntest.actions.check_prop('k', wc_dir, [value])
 
 def patch_strip_cwd(sbox):
@@ -3508,7 +3512,7 @@ test_list = [ None,
               patch_reverse_revert,
               patch_strip_cwd,
               XFail(patch_set_prop_no_eol),
-              patch_add_symlink,
+              SkipUnless(patch_add_symlink, svntest.main.is_posix_os),
             ]
 
 if __name__ == '__main__':

Modified: subversion/branches/issue-3668-3669/subversion/tests/cmdline/update_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3668-3669/subversion/tests/cmdline/update_tests.py?rev=1035404&r1=1035403&r2=1035404&view=diff
==============================================================================
--- subversion/branches/issue-3668-3669/subversion/tests/cmdline/update_tests.py (original)
+++ subversion/branches/issue-3668-3669/subversion/tests/cmdline/update_tests.py Mon Nov 15 18:50:38 2010
@@ -5317,7 +5317,24 @@ def update_with_file_lock_and_keywords_p
   if (mu_ts_before_update != mu_ts_after_update):
     print("The timestamp of 'mu' before and after update does not match.")
     raise svntest.Failure
-  
+
+#----------------------------------------------------------------------
+# Updating a nonexistent or deleted path should be a successful no-op,
+# when there is no incoming change.  In trunk@1035343, such an update
+# within a copied directory triggered an assertion failure.
+def update_nonexistent_child_of_copy(sbox):
+  """update a nonexistent child of a copied dir"""
+  sbox.build()
+  os.chdir(sbox.wc_dir)
+
+  svntest.main.run_svn(None, 'copy', 'A', 'A2')
+
+  # Try updating a nonexistent path in the copied dir.
+  svntest.main.run_svn(None, 'update', os.path.join('A2', 'nonexistent'))
+
+  # Try updating a deleted path in the copied dir.
+  svntest.main.run_svn(None, 'delete', os.path.join('A2', 'mu'))
+  svntest.main.run_svn(None, 'update', os.path.join('A2', 'mu'))
 
 #######################################################################
 # Run the tests
@@ -5382,7 +5399,8 @@ test_list = [ None,
               XFail(update_empty_hides_entries),
               mergeinfo_updates_merge_with_local_mods,
               update_with_excluded_subdir,
-              XFail(update_with_file_lock_and_keywords_property_set)
+              XFail(update_with_file_lock_and_keywords_property_set),
+              XFail(update_nonexistent_child_of_copy),
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/issue-3668-3669/subversion/tests/libsvn_wc/op-depth-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3668-3669/subversion/tests/libsvn_wc/op-depth-test.c?rev=1035404&r1=1035403&r2=1035404&view=diff
==============================================================================
--- subversion/branches/issue-3668-3669/subversion/tests/libsvn_wc/op-depth-test.c (original)
+++ subversion/branches/issue-3668-3669/subversion/tests/libsvn_wc/op-depth-test.c Mon Nov 15 18:50:38 2010
@@ -37,6 +37,8 @@
 
 #include "private/svn_wc_private.h"
 #include "private/svn_sqlite.h"
+#include "../../libsvn_wc/wc.h"
+#include "../../libsvn_wc/wc_db.h"
 
 #include "../svn_test.h"
 
@@ -320,7 +322,7 @@ typedef struct {
  * Append an error message to BATON->errors if they differ or are not both
  * present.
  *
- * If the ACTUAL row has field values that should have been elided
+ * If the FOUND row has field values that should have been elided
  * (because they match the parent row), then do so now.  We want to ignore
  * any such lack of elision, for the purposes of these tests, because the
  * method of copying in use (at the time this tweak is introduced) does
@@ -335,8 +337,9 @@ compare_nodes_rows(const void *key, apr_
   comparison_baton_t *b = baton;
   nodes_row_t *expected = apr_hash_get(b->expected_hash, key, klen);
   nodes_row_t *found = apr_hash_get(b->found_hash, key, klen);
+  nodes_row_t elided;
 
-  /* If the ACTUAL row has field values that should have been elided
+  /* If the FOUND row has field values that should have been elided
    * (because they match the parent row), then do so now. */
   if (found && found->op_depth > 0 && found->repo_relpath)
     {
@@ -351,11 +354,16 @@ compare_nodes_rows(const void *key, apr_
                                   APR_HASH_KEY_STRING);
       if (parent_found && parent_found->op_depth > 0
           && parent_found->repo_relpath
+          && found->op_depth == parent_found->op_depth
+          && found->repo_revnum == parent_found->repo_revnum
           && strcmp(found->repo_relpath,
                     svn_relpath_join(parent_found->repo_relpath, name,
-                                     b->scratch_pool)) == 0
-          && found->repo_revnum == parent_found->repo_revnum)
+                                     b->scratch_pool)) == 0)
         {
+          /* Iterating in hash order, which is arbitrary, so only make
+             changes in a local copy */
+          elided = *found;
+          found = &elided;
           found->repo_relpath = NULL;
           found->repo_revnum = SVN_INVALID_REVNUM;
         }
@@ -415,7 +423,9 @@ check_db_rows(wc_baton_t *b,
   SVN_ERR(open_wc_db(&sdb, b->wc_abspath, b->pool, b->pool));
   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_NODES_INFO));
   SVN_ERR(svn_sqlite__bindf(stmt, "ss", base_relpath,
-                            apr_psprintf(b->pool, "%s/%%", base_relpath)));
+                            (base_relpath[0]
+                             ? apr_psprintf(b->pool, "%s/%%", base_relpath)
+                             : "_%")));
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
   while (have_row)
     {
@@ -1155,6 +1165,519 @@ test_delete_with_update(const svn_test_o
   return SVN_NO_ERROR;
 }
 
+
+static svn_error_t *
+insert_dirs(wc_baton_t *b,
+            nodes_row_t *nodes)
+{
+  svn_sqlite__db_t *sdb;
+  svn_sqlite__stmt_t *stmt;
+  const char *dbpath = svn_dirent_join_many(b->pool,
+                                            b->wc_abspath, ".svn", "wc.db",
+                                            NULL);
+  const char * const statements[] = {
+    "DELETE FROM nodes;",
+    "INSERT INTO nodes (local_relpath, op_depth, presence, repos_path,"
+    "                   revision, wc_id, repos_id, kind, depth)"
+    "           VALUES (?1, ?2, ?3, ?4, ?5, 1, 1, 'dir', 'infinity');",
+    "INSERT INTO nodes (local_relpath, op_depth, presence, repos_path,"
+    "                   revision, parent_relpath, wc_id, repos_id, kind, depth)"
+    "           VALUES (?1, ?2, ?3, ?4, ?5, ?6, 1, 1, 'dir', 'infinity');",
+    NULL,
+  };
+
+  SVN_ERR(svn_sqlite__open(&sdb, dbpath, svn_sqlite__mode_readwrite,
+                           statements, 0, NULL,
+                           b->pool, b->pool));
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, 0));
+  SVN_ERR(svn_sqlite__step_done(stmt));
+
+  while(nodes->local_relpath)
+    {
+      if (nodes->local_relpath[0])
+        {
+          SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, 2));
+          SVN_ERR(svn_sqlite__bindf(stmt, "sissrs",
+                                    nodes->local_relpath,
+                                    (apr_int64_t)nodes->op_depth,
+                                    nodes->presence,
+                                    nodes->repo_relpath,
+                                    nodes->repo_revnum,
+                                    svn_relpath_dirname(nodes->local_relpath,
+                                                        b->pool)));
+        }
+      else
+        {
+          SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, 1));
+          SVN_ERR(svn_sqlite__bindf(stmt, "sissr",
+                                    nodes->local_relpath,
+                                    (apr_int64_t)nodes->op_depth,
+                                    nodes->presence,
+                                    nodes->repo_relpath,
+                                    nodes->repo_revnum));
+        }
+
+      SVN_ERR(svn_sqlite__step_done(stmt));
+      ++nodes;
+    }
+
+  SVN_ERR(svn_sqlite__close(sdb));
+
+  return SVN_NO_ERROR;
+}
+
+static int count_rows(nodes_row_t *rows)
+{
+  nodes_row_t *first = rows;
+  while(rows->local_relpath)
+    ++rows;
+  return rows - first;
+}
+
+static svn_error_t *
+base_dir_insert_remove(wc_baton_t *b,
+                       const char *local_relpath,
+                       svn_revnum_t revision,
+                       nodes_row_t *before,
+                       nodes_row_t *added)
+{
+  nodes_row_t *after;
+  const char *dir_abspath = svn_path_join(b->wc_abspath, local_relpath,
+                                          b->pool);
+  int i, num_before = count_rows(before), num_added = count_rows(added);
+
+  SVN_ERR(insert_dirs(b, before));
+
+  SVN_ERR(svn_wc__db_base_add_directory(b->wc_ctx->db, dir_abspath,
+                                        local_relpath, b->repos_url,
+                                        "not-even-a-uuid", revision,
+                                        apr_hash_make(b->pool), revision,
+                                        0, NULL, NULL, svn_depth_infinity,
+                                        NULL, NULL, NULL, b->pool));
+
+  after = apr_palloc(b->pool, sizeof(*after) * (num_before + num_added + 1));
+  for (i = 0; i < num_before; ++i)
+    after[i] = before[i];
+  for (i = 0; i < num_added; ++i)
+    after[num_before+i] = added[i];
+  after[num_before+num_added].local_relpath = NULL;
+
+  SVN_ERR(check_db_rows(b, "", after));
+
+  SVN_ERR(svn_wc__db_base_remove(b->wc_ctx->db, dir_abspath, b->pool));
+
+  SVN_ERR(check_db_rows(b, "", before));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_base_dir_insert_remove(const svn_test_opts_t *opts, apr_pool_t *pool)
+{
+  wc_baton_t b;
+
+  b.pool = pool;
+  SVN_ERR(svn_test__create_repos_and_wc(&b.repos_url, &b.wc_abspath,
+                                        "base_dir_insert_remove", opts, pool));
+  SVN_ERR(svn_wc_context_create(&b.wc_ctx, NULL, pool, pool));
+
+  {
+    /* /  normal                     /    normal
+       A  normal                     A    normal
+                                     A/B  normal
+    */
+    nodes_row_t before[] = {
+      { 0, "",  "normal", 2, "" },
+      { 0, "A", "normal", 2, "A" },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B", "normal", 2, "A/B" },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B", 2, before, added));
+  }
+  {
+    /* /  normal                      /    normal
+       A  normal  base-del            A    normal  base-del
+                                      A/B  normal  base-del
+    */
+    nodes_row_t before[] = {
+      { 0, "",  "normal",       2, "" },
+      { 0, "A", "normal",       2, "A" },
+      { 1, "A", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B", "normal",       2, "A/B" },
+      { 1, "A/B", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B", 2, before, added));
+  }
+  {
+    /* /  normal                       /    normal
+       A  normal  normal               A    normal  normal
+                                       A/B  normal  base-del
+     */
+    nodes_row_t before[] = {
+      { 0, "",  "normal", 2, "" },
+      { 0, "A", "normal", 2, "A" },
+      { 1, "A", "normal", 1, "X" },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B", "normal",       2, "A/B" },
+      { 1, "A/B", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B", 2, before, added));
+  }
+  {
+    /* /    normal                     /      normal
+       A    normal  normal             A      normal  normal
+       A/B  normal  not-pres           A/B    normal  not-pres
+                                       A/B/C  normal  base-del
+     */
+    nodes_row_t before[] = {
+      { 0, "",    "normal",      2, "" },
+      { 0, "A",   "normal",      2, "A" },
+      { 0, "A/B", "normal",      2, "A/B" },
+      { 1, "A",   "normal",      1, "X" },
+      { 1, "A/B", "not-present", NO_COPY_FROM },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B/C", "normal",       2, "A/B/C" },
+      { 1, "A/B/C", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B/C", 2, before, added));
+  }
+  {
+    /* /    normal                      /    normal
+       A    normal  normal              A    normal  normal
+       A/B          normal              A/B  normal  normal
+     */
+    nodes_row_t before[] = {
+      { 0, "",    "normal", 2, "" },
+      { 0, "A",   "normal", 2, "A" },
+      { 1, "A",   "normal", 1, "X" },
+      { 1, "A/B", "normal", NO_COPY_FROM },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B", "normal",       2, "A/B" },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B", 2, before, added));
+  }
+  {
+    /* /    normal                       /    normal
+       A    normal  normal               A    normal  normal
+       A/B          not-pres             A/B  normal  not-pres
+     */
+    nodes_row_t before[] = {
+      { 0, "",    "normal",      2, "" },
+      { 0, "A",   "normal",      2, "A" },
+      { 1, "A",   "normal",      1, "X" },
+      { 1, "A/B", "not-present", NO_COPY_FROM },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B", "normal",       2, "A/B" },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B", 2, before, added));
+  }
+  {
+    /* /    normal                       /    normal
+       A    normal  normal               A    normal  normal
+       A/B                  normal       A/B  normal  base-del  normal
+     */
+    nodes_row_t before[] = {
+      { 0, "",    "normal",      2, "" },
+      { 0, "A",   "normal",      2, "A" },
+      { 1, "A",   "normal",      1, "X" },
+      { 2, "A/B", "normal",      1, "Y" },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B", "normal",       2, "A/B" },
+      { 1, "A/B", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B", 2, before, added));
+  }
+  {
+    /* /      normal                          /      normal
+       A      normal  normal                  A      normal  normal
+       A/B    normal  base-del  normal        A/B    normal  base-del  normal
+       A/B/C                    normal        A/B/C  normal  base-del  normal
+     */
+    nodes_row_t before[] = {
+      { 0, "",    "normal",       2, "" },
+      { 0, "A",   "normal",       2, "A" },
+      { 0, "A/B", "normal",       2, "A/B" },
+      { 1, "A",   "normal",       1, "X" },
+      { 1, "A/B", "base-deleted", NO_COPY_FROM },
+      { 2, "A/B", "normal",       1, "Y" },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B/C", "normal",       2, "A/B/C" },
+      { 1, "A/B/C", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B/C", 2, before, added));
+  }
+  {
+    /* /      normal                          /      normal
+       A      normal  normal                  A      normal  normal
+       A/B    normal  not-pres  normal        A/B    normal  not-pres  normal
+       A/B/C                    normal        A/B/C  normal  base-del  normal
+     */
+    nodes_row_t before[] = {
+      { 0, "",      "normal",      2, "" },
+      { 0, "A",     "normal",      2, "A" },
+      { 0, "A/B",   "normal",      2, "A/B" },
+      { 1, "A",     "normal",      1, "X" },
+      { 1, "A/B",   "not-present", NO_COPY_FROM },
+      { 2, "A/B",   "normal",      1, "Y" },
+      { 2, "A/B/C", "normal",      NO_COPY_FROM },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B/C", "normal",       2, "A/B/C" },
+      { 1, "A/B/C", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B/C", 2, before, added));
+  }
+  {
+    /*  /      normal                         /
+        A      normal  normal                 A      normal  normal
+        A/B    normal  base-del  normal       A/B    normal  base-del  normal
+        A/B/C                    not-pres     A/B/C  normal  base-del  not-pres
+     */
+    nodes_row_t before[] = {
+      { 0, "",      "normal",       2, "" },
+      { 0, "A",     "normal",       2, "A" },
+      { 0, "A/B",   "normal",       2, "A/B" },
+      { 1, "A",     "normal",       1, "X" },
+      { 1, "A/B",   "base-deleted", NO_COPY_FROM },
+      { 2, "A/B",   "normal",       1, "Y" },
+      { 2, "A/B/C", "not-present",  NO_COPY_FROM },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B/C", "normal",       2, "A/B/C" },
+      { 1, "A/B/C", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B/C", 2, before, added));
+  }
+  {
+    /*  /      normal                         /
+        A      normal  normal                 A      normal  normal
+        A/B    normal  not-pres  normal       A/B    normal  not-pres  normal
+        A/B/C                    not-pres     A/B/C  normal  base-del  not-pres
+     */
+    nodes_row_t before[] = {
+      { 0, "",      "normal",      2, "" },
+      { 0, "A",     "normal",      2, "A" },
+      { 0, "A/B",   "normal",      2, "A/B" },
+      { 1, "A",     "normal",      1, "X" },
+      { 1, "A/B",   "not-present", NO_COPY_FROM },
+      { 2, "A/B",   "normal",      1, "Y" },
+      { 2, "A/B/C", "not-present", NO_COPY_FROM },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B/C", "normal",       2, "A/B/C" },
+      { 1, "A/B/C", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B/C", 2, before, added));
+  }
+  {
+    /*  /      norm                       /
+        A      norm  norm                 A      norm  norm
+        A/B    norm  not-p  norm          A/B    norm  not-p  norm
+        A/B/C                     norm    A/B/C  norm  b-del        norm
+     */
+    nodes_row_t before[] = {
+      { 0, "",      "normal",      2, "" },
+      { 0, "A",     "normal",      2, "A" },
+      { 0, "A/B",   "normal",      2, "A/B" },
+      { 1, "A",     "normal",      1, "X" },
+      { 1, "A/B",   "not-present", NO_COPY_FROM },
+      { 2, "A/B",   "normal",      1, "Y" },
+      { 3, "A/B/C", "normal",      NO_COPY_FROM },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B/C", "normal",       2, "A/B/C" },
+      { 1, "A/B/C", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B/C", 2, before, added));
+  }
+  {
+    /* /      norm                     /        norm
+       A      norm                     A        norm
+       A/B    norm                     A/B      norm
+       A/B/C  norm  -  -  norm         A/B/C    norm   -  -  norm
+                                       A/B/C/D  norm   -  -  b-del
+    */
+    nodes_row_t before[] = {
+      { 0, "",      "normal", 2, "" },
+      { 0, "A",     "normal", 2, "A" },
+      { 0, "A/B",   "normal", 2, "A/B" },
+      { 0, "A/B/C", "normal", 2, "A/B/C" },
+      { 3, "A/B/C", "normal", NO_COPY_FROM },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B/C/D", "normal",       2, "A/B/C/D" },
+      { 3, "A/B/C/D", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B/C/D", 2, before, added));
+  }
+  {
+    /* /      norm                     /        norm
+       A      norm                     A        norm
+       A/B    norm                     A/B      norm
+       A/B/C  norm  -  -  norm         A/B/C    norm   -  -  norm
+       A/B/C/D                  norm   A/B/C/D  norm   -  -  b-del  norm
+    */
+    nodes_row_t before[] = {
+      { 0, "",        "normal", 2, "" },
+      { 0, "A",       "normal", 2, "A" },
+      { 0, "A/B",     "normal", 2, "A/B" },
+      { 0, "A/B/C",   "normal", 2, "A/B/C" },
+      { 3, "A/B/C",   "normal", NO_COPY_FROM },
+      { 4, "A/B/C/D", "normal", NO_COPY_FROM },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B/C/D", "normal",       2, "A/B/C/D" },
+      { 3, "A/B/C/D", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B/C/D", 2, before, added));
+  }
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+temp_op_make_copy(wc_baton_t *b,
+                  const char *local_relpath,
+                  nodes_row_t *before,
+                  nodes_row_t *after)
+{
+  const char *dir_abspath = svn_path_join(b->wc_abspath, local_relpath,
+                                          b->pool);
+
+  SVN_ERR(insert_dirs(b, before));
+
+  SVN_ERR(svn_wc__db_temp_op_make_copy(b->wc_ctx->db, dir_abspath, b->pool));
+
+  SVN_ERR(check_db_rows(b, "", after));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_temp_op_make_copy(const svn_test_opts_t *opts, apr_pool_t *pool)
+{
+  wc_baton_t b;
+
+  b.pool = pool;
+  SVN_ERR(svn_test__create_repos_and_wc(&b.repos_url, &b.wc_abspath,
+                                        "base_dir_insert_remove", opts, pool));
+  SVN_ERR(svn_wc_context_create(&b.wc_ctx, NULL, pool, pool));
+
+  {
+    /*  /           norm        -
+        A           norm        -
+        A/B         norm        -       norm
+        A/B/C       norm        -       base-del    norm
+        A/F         norm        -       norm
+        A/F/G       norm        -       norm
+        A/F/H       norm        -       not-pres
+        A/F/E       norm        -       base-del
+        A/X         norm        -
+        A/X/Y       incomplete  -
+    */
+    nodes_row_t before[] = {
+      { 0, "",      "normal",       2, "" },
+      { 0, "A",     "normal",       2, "A" },
+      { 0, "A/B",   "normal",       2, "A/B" },
+      { 0, "A/B/C", "normal",       2, "A/B/C" },
+      { 0, "A/F",   "normal",       2, "A/F" },
+      { 0, "A/F/G", "normal",       2, "A/F/G" },
+      { 0, "A/F/H", "normal",       2, "A/F/H" },
+      { 0, "A/F/E", "normal",       2, "A/F/E" },
+      { 0, "A/X",   "normal",       2, "A/X" },
+      { 0, "A/X/Y", "incomplete",   2, "A/X/Y" },
+      { 2, "A/B",   "normal",       NO_COPY_FROM },
+      { 2, "A/B/C", "base-deleted", NO_COPY_FROM },
+      { 3, "A/B/C", "normal",       NO_COPY_FROM },
+      { 2, "A/F",   "normal",       1, "S2" },
+      { 2, "A/F/G", "normal",       NO_COPY_FROM },
+      { 2, "A/F/H", "not-present",  NO_COPY_FROM },
+      { 2, "A/F/E", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    /*  /           norm        -
+        A           norm        norm
+        A/B         norm        base-del    norm
+        A/B/C       norm        base-del                norm
+        A/F         norm        base-del    norm
+        A/F/G       norm        base-del    norm
+        A/F/H       norm        base-del    not-pres
+        A/F/E       norm        base-del
+        A/X         norm        norm
+        A/X/Y       incomplete  incomplete
+    */
+    nodes_row_t after[] = {
+      { 0, "",      "normal",       2, "" },
+      { 0, "A",     "normal",       2, "A" },
+      { 0, "A/B",   "normal",       2, "A/B" },
+      { 0, "A/B/C", "normal",       2, "A/B/C" },
+      { 0, "A/F",   "normal",       2, "A/F" },
+      { 0, "A/F/G", "normal",       2, "A/F/G" },
+      { 0, "A/F/H", "normal",       2, "A/F/H" },
+      { 0, "A/F/E", "normal",       2, "A/F/E" },
+      { 0, "A/X",   "normal",       2, "A/X" },
+      { 0, "A/X/Y", "incomplete",   2, "A/X/Y" },
+      { 1, "A",     "normal",       2, "A" },
+      { 1, "A/B",   "base-deleted", NO_COPY_FROM },
+      { 1, "A/B/C", "base-deleted", NO_COPY_FROM },
+      { 1, "A/F",   "base-deleted", NO_COPY_FROM },
+      { 1, "A/F/G", "base-deleted", NO_COPY_FROM },
+      { 1, "A/F/H", "base-deleted", NO_COPY_FROM },
+      { 1, "A/F/E", "base-deleted", NO_COPY_FROM },
+      { 1, "A/X",   "normal",       NO_COPY_FROM },
+      { 1, "A/X/Y", "incomplete",   NO_COPY_FROM },
+      { 2, "A/B",   "normal",       NO_COPY_FROM },
+      { 3, "A/B/C", "normal",       NO_COPY_FROM },
+      { 2, "A/F",   "normal",       1, "S2" },
+      { 2, "A/F/G", "normal",       NO_COPY_FROM },
+      { 2, "A/F/H", "not-present",  NO_COPY_FROM },
+      { 0 }
+    };
+
+    SVN_ERR(temp_op_make_copy(&b, "A", before, after));
+  }
+
+  return SVN_NO_ERROR;
+}
+
 /* ---------------------------------------------------------------------- */
 /* The list of test functions */
 
@@ -1188,5 +1711,11 @@ struct svn_test_descriptor_t test_funcs[
     SVN_TEST_OPTS_WIMP(test_adds_change_kind,
                        "test_adds_change_kind",
                        "needs op_depth"),
+    SVN_TEST_OPTS_WIMP(test_base_dir_insert_remove,
+                       "test_base_dir_insert_remove",
+                       "needs op_depth"),
+    SVN_TEST_OPTS_WIMP(test_temp_op_make_copy,
+                       "test_temp_op_make_copy",
+                       "needs op_depth"),
     SVN_TEST_NULL
   };

Modified: subversion/branches/issue-3668-3669/subversion/tests/libsvn_wc/tree-conflict-data-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3668-3669/subversion/tests/libsvn_wc/tree-conflict-data-test.c?rev=1035404&r1=1035403&r2=1035404&view=diff
==============================================================================
--- subversion/branches/issue-3668-3669/subversion/tests/libsvn_wc/tree-conflict-data-test.c (original)
+++ subversion/branches/issue-3668-3669/subversion/tests/libsvn_wc/tree-conflict-data-test.c Mon Nov 15 18:50:38 2010
@@ -53,15 +53,14 @@ fail(apr_pool_t *pool, const char *fmt, 
 static svn_error_t *
 test_read_tree_conflict(apr_pool_t *pool)
 {
-  svn_wc_conflict_description2_t *conflict;
-  apr_hash_t *conflicts;
+  const svn_wc_conflict_description2_t *conflict;
   svn_wc_conflict_description2_t *exp_conflict;
   const char *tree_conflict_data;
-  apr_hash_index_t *hi;
   const char *local_abspath;
+  const svn_skel_t *skel;
 
-  tree_conflict_data = "((conflict Foo.c file update deleted edited "
-                         "(version 0  2 -1 0  0 ) (version 0  2 -1 0  0 )))";
+  tree_conflict_data = "(conflict Foo.c file update deleted edited "
+                        "(version 0  2 -1 0  0 ) (version 0  2 -1 0  0 ))";
 
   SVN_ERR(svn_dirent_get_absolute(&local_abspath, "Foo.c", pool));
   exp_conflict = svn_wc_conflict_description_create_tree2(
@@ -70,11 +69,8 @@ test_read_tree_conflict(apr_pool_t *pool
   exp_conflict->action = svn_wc_conflict_action_delete;
   exp_conflict->reason = svn_wc_conflict_reason_edited;
 
-  SVN_ERR(svn_wc__read_tree_conflicts(&conflicts, tree_conflict_data, "",
-                                      pool));
-
-  hi = apr_hash_first(pool, conflicts);
-  conflict = svn__apr_hash_index_val(hi);
+  skel = svn_skel__parse(tree_conflict_data, strlen(tree_conflict_data), pool);
+  SVN_ERR(svn_wc__deserialize_conflict(&conflict, skel, "", pool, pool));
 
   if ((conflict->node_kind != exp_conflict->node_kind) ||
       (conflict->action    != exp_conflict->action) ||
@@ -87,120 +83,13 @@ test_read_tree_conflict(apr_pool_t *pool
 }
 
 static svn_error_t *
-test_read_2_tree_conflicts(apr_pool_t *pool)
-{
-  const char *tree_conflict_data;
-  svn_wc_conflict_description2_t *conflict1, *conflict2;
-  apr_hash_t *conflicts;
-  svn_wc_conflict_description2_t *exp_conflict1, *exp_conflict2;
-  apr_hash_index_t *hi;
-  const char *local_abspath;
-
-  tree_conflict_data =
-    "((conflict Foo.c file update deleted edited "
-      "(version 0  2 -1 0  0 ) (version 0  2 -1 0  0 )) "
-     "(conflict Bar.h file update edited deleted "
-      "(version 0  2 -1 0  0 ) (version 0  2 -1 0  0 )))";
-
-  SVN_ERR(svn_dirent_get_absolute(&local_abspath, "Foo.c", pool));
-  exp_conflict1 = svn_wc_conflict_description_create_tree2(
-                        local_abspath, svn_node_file, svn_wc_operation_update,
-                        NULL, NULL, pool);
-  exp_conflict1->action = svn_wc_conflict_action_delete;
-  exp_conflict1->reason = svn_wc_conflict_reason_edited;
-
-  SVN_ERR(svn_dirent_get_absolute(&local_abspath, "Bar.h", pool));
-  exp_conflict2 = svn_wc_conflict_description_create_tree2(
-                        local_abspath, svn_node_file, svn_wc_operation_update,
-                         NULL, NULL, pool);
-  exp_conflict2->action = svn_wc_conflict_action_edit;
-  exp_conflict2->reason = svn_wc_conflict_reason_deleted;
-
-  SVN_ERR(svn_wc__read_tree_conflicts(&conflicts, tree_conflict_data, "",
-                                      pool));
-
-  hi = apr_hash_first(pool, conflicts);
-  conflict1 = svn__apr_hash_index_val(hi);
-  if ((conflict1->node_kind != exp_conflict1->node_kind) ||
-      (conflict1->action    != exp_conflict1->action) ||
-      (conflict1->reason    != exp_conflict1->reason) ||
-      (conflict1->operation != exp_conflict1->operation) ||
-      (strcmp(conflict1->local_abspath, exp_conflict1->local_abspath) != 0))
-    return fail(pool, "Tree conflict struct #1 has bad data");
-
-  hi = apr_hash_next(hi);
-  conflict2 = svn__apr_hash_index_val(hi);
-  if ((conflict2->node_kind != exp_conflict2->node_kind) ||
-      (conflict2->action    != exp_conflict2->action) ||
-      (conflict2->reason    != exp_conflict2->reason) ||
-      (conflict2->operation != exp_conflict2->operation) ||
-      (strcmp(conflict2->local_abspath, exp_conflict2->local_abspath) != 0))
-    return fail(pool, "Tree conflict struct #2 has bad data");
-
-  return SVN_NO_ERROR;
-}
-
-/* This needs to be adjusted in case the constants for the
- * delimiters change... */
-static const char* broken_tree_conflict_test_data[] = {
-  /* Missing descriptions */
-  "|Bar.h:file:update:edited:deleted::::::::",
-  "Foo.c:file:update:deleted:edited::::::::|",
-  "|||||||",
-  "",
-  /* Missing fields */
-  "Foo.c:fileupdate:deleted:edited::::::::",
-  "Foo.c",
-  "::::",
-  ":::",
-  "Foo.c:::::::::::::;",
-  /* Bad separators */
-  "Foo.c:file:update:deleted:edited::::::::$Bar.h:file:update:edited:deleted::::::::",
-  "Foo.c|file|update|deleted|edited:::::::::Bar.h|file|update|edited|deleted::::::::",
-  /* Missing separators */
-  "Foo.c:file:update:deleted:edited::::::::Bar.h:file:update:edited:deleted::::::::",
-  "Foo.c:fileupdate:deleted:edited::::::::",
-  /* Unescaped separators */
-  "F|oo.c:file:update:deleted:edited::::::::",
-  "F:oo.c:file:update:deleted:edited::::::::",
-  /* Unescaped escape */
-  "Foo.c\\:file:update:deleted:edited::::::::",
-  "Foo.c\\",
-  /* Illegally escaped char */
-  "\\Foo.c:file:update:deleted:edited::::::::",
-  NULL
-};
-
-static svn_error_t *
-test_read_invalid_tree_conflicts(apr_pool_t *pool)
-{
-  int i;
-  const char *tree_conflict_data;
-  apr_hash_t *conflicts;
-  svn_error_t *err;
-
-  for (i = 0; broken_tree_conflict_test_data[i] != NULL; i++)
-    {
-      tree_conflict_data = broken_tree_conflict_test_data[i];
-      err = svn_wc__read_tree_conflicts(&conflicts, tree_conflict_data, "",
-                                        pool);
-      if (err == SVN_NO_ERROR)
-        return fail(pool,
-                    "Error in broken tree conflict data was not detected:\n"
-                    "  %s", tree_conflict_data);
-      svn_error_clear(err);
-    }
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
 test_write_tree_conflict(apr_pool_t *pool)
 {
   svn_wc_conflict_description2_t *conflict;
   const char *tree_conflict_data;
-  apr_hash_t *conflicts;
   const char *expected;
   const char *local_abspath;
+  svn_skel_t *skel;
 
   SVN_ERR(svn_dirent_get_absolute(&local_abspath, "Foo.c", pool));
 
@@ -210,14 +99,11 @@ test_write_tree_conflict(apr_pool_t *poo
   conflict->action = svn_wc_conflict_action_delete;
   conflict->reason = svn_wc_conflict_reason_edited;
 
-  conflicts = apr_hash_make(pool);
-  apr_hash_set(conflicts, conflict->local_abspath, APR_HASH_KEY_STRING,
-               conflict);
-
-  expected = "((conflict Foo.c file update deleted edited "
-               "(version 0  2 -1 0  0 ) (version 0  2 -1 0  0 )))";
+  SVN_ERR(svn_wc__serialize_conflict(&skel, conflict, pool, pool));
+  tree_conflict_data = svn_skel__unparse(skel, pool)->data;
 
-  SVN_ERR(svn_wc__write_tree_conflicts(&tree_conflict_data, conflicts, pool));
+  expected = "(conflict Foo.c file update deleted edited "
+             "(version 0  2 -1 0  0 ) (version 0  2 -1 0  0 ))";
 
   if (strcmp(expected, tree_conflict_data) != 0)
     return fail(pool, "Unexpected text from tree conflict\n"
@@ -227,60 +113,6 @@ test_write_tree_conflict(apr_pool_t *poo
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *
-test_write_2_tree_conflicts(apr_pool_t *pool)
-{
-  svn_wc_conflict_description2_t *conflict1, *conflict2;
-  apr_hash_t *conflicts;
-  const char *tree_conflict_data;
-  const char *expected1;
-  const char *expected2;
-  const char *local_abspath;
-
-  SVN_ERR(svn_dirent_get_absolute(&local_abspath, "Foo.c", pool));
-  conflict1 = svn_wc_conflict_description_create_tree2(
-                    local_abspath, svn_node_file, svn_wc_operation_update,
-                    NULL, NULL, pool);
-  conflict1->action = svn_wc_conflict_action_delete;
-  conflict1->reason = svn_wc_conflict_reason_edited;
-
-  SVN_ERR(svn_dirent_get_absolute(&local_abspath, "Bar.h", pool));
-  conflict2 = svn_wc_conflict_description_create_tree2(
-                    local_abspath, svn_node_file, svn_wc_operation_update,
-                    NULL, NULL, pool);
-  conflict2->action = svn_wc_conflict_action_edit;
-  conflict2->reason = svn_wc_conflict_reason_deleted;
-
-  conflicts = apr_hash_make(pool);
-  apr_hash_set(conflicts, conflict1->local_abspath, APR_HASH_KEY_STRING,
-               conflict1);
-  apr_hash_set(conflicts, conflict2->local_abspath, APR_HASH_KEY_STRING,
-               conflict2);
-
-  /* We don't know the order the hash will spit out the data, so just test
-     for both possibilities. */
-  expected1 = "((conflict Foo.c file update deleted edited "
-                 "(version 0  2 -1 0  0 ) (version 0  2 -1 0  0 )) "
-               "(conflict Bar.h file update edited deleted "
-                 "(version 0  2 -1 0  0 ) (version 0  2 -1 0  0 )))";
-  expected2 = "((conflict Bar.h file update edited deleted "
-                 "(version 0  2 -1 0  0 ) (version 0  2 -1 0  0 )) "
-               "(conflict Foo.c file update deleted edited "
-                 "(version 0  2 -1 0  0 ) (version 0  2 -1 0  0 )))";
-
-  SVN_ERR(svn_wc__write_tree_conflicts(&tree_conflict_data, conflicts, pool));
-
-  if (strcmp(expected1, tree_conflict_data) != 0
-        && strcmp(expected2, tree_conflict_data) != 0)
-    return fail(pool, "Unexpected text from tree conflict\n"
-                      "  Expected: %s\n"
-                      "         OR %s\n"
-                      "  Actual:   %s\n", expected1, expected2,
-                                          tree_conflict_data);
-
-  return SVN_NO_ERROR;
-}
-
 #ifdef THIS_TEST_RAISES_MALFUNCTION
 static svn_error_t *
 test_write_invalid_tree_conflicts(apr_pool_t *pool)
@@ -380,14 +212,8 @@ struct svn_test_descriptor_t test_funcs[
     SVN_TEST_NULL,
     SVN_TEST_PASS2(test_read_tree_conflict,
                    "read 1 tree conflict"),
-    SVN_TEST_PASS2(test_read_2_tree_conflicts,
-                   "read 2 tree conflicts"),
-    SVN_TEST_XFAIL2(test_read_invalid_tree_conflicts,
-                    "detect broken tree conflict data"),
     SVN_TEST_PASS2(test_write_tree_conflict,
                    "write 1 tree conflict"),
-    SVN_TEST_PASS2(test_write_2_tree_conflicts,
-                   "write 2 tree conflicts"),
 #ifdef THIS_TEST_RAISES_MALFUNCTION
     SVN_TEST_PASS2(test_write_invalid_tree_conflicts,
                    "detect broken tree conflict data while writing"),