diff options
Diffstat (limited to 'subversion/tests/libsvn_wc')
-rw-r--r-- | subversion/tests/libsvn_wc/conflict-data-test.c | 178 | ||||
-rw-r--r-- | subversion/tests/libsvn_wc/db-test.c | 634 | ||||
-rw-r--r-- | subversion/tests/libsvn_wc/entries-compat.c | 388 | ||||
-rw-r--r-- | subversion/tests/libsvn_wc/op-depth-test.c | 3547 | ||||
-rw-r--r-- | subversion/tests/libsvn_wc/pristine-store-test.c | 138 | ||||
-rw-r--r-- | subversion/tests/libsvn_wc/utils.c | 265 | ||||
-rw-r--r-- | subversion/tests/libsvn_wc/utils.h | 55 | ||||
-rw-r--r-- | subversion/tests/libsvn_wc/wc-lock-tester.c | 33 | ||||
-rw-r--r-- | subversion/tests/libsvn_wc/wc-queries-test.c | 223 | ||||
-rw-r--r-- | subversion/tests/libsvn_wc/wc-test-queries.h | 112 | ||||
-rw-r--r-- | subversion/tests/libsvn_wc/wc-test-queries.sql | 78 | ||||
-rw-r--r-- | subversion/tests/libsvn_wc/wc-test.c | 143 |
12 files changed, 4790 insertions, 1004 deletions
diff --git a/subversion/tests/libsvn_wc/conflict-data-test.c b/subversion/tests/libsvn_wc/conflict-data-test.c index 97d22ea..7d89825 100644 --- a/subversion/tests/libsvn_wc/conflict-data-test.c +++ b/subversion/tests/libsvn_wc/conflict-data-test.c @@ -134,7 +134,7 @@ compare_file_content(const char *file_abspath, * conflict, or are both NULL. Return an error if not. * * Compare the property values found in files named by - * ACTUAL->base_abspath, ACTUAL->my_abspath, ACTUAL->merged_abspath + * ACTUAL->base_abspath, ACTUAL->my_abspath, ACTUAL->merged_file * with EXPECTED_BASE_VAL, EXPECTED_MY_VAL, EXPECTED_THEIR_VAL * respectively, ignoring the corresponding fields in EXPECTED. */ static svn_error_t * @@ -236,8 +236,8 @@ test_deserialize_tree_conflict(apr_pool_t *pool) SVN_ERR(svn_wc__deserialize_conflict(&conflict, skel, "", pool, pool)); if ((conflict->node_kind != exp_conflict->node_kind) || - (conflict->action != exp_conflict->action) || - (conflict->reason != exp_conflict->reason) || + (conflict->action != exp_conflict->action) || + (conflict->reason != exp_conflict->reason) || (conflict->operation != exp_conflict->operation) || (strcmp(conflict->local_abspath, exp_conflict->local_abspath) != 0)) return fail(pool, "Unexpected tree conflict"); @@ -289,10 +289,12 @@ test_read_write_tree_conflicts(const svn_test_opts_t *opts, SVN_ERR(svn_test__sandbox_create(&sbox, "read_write_tree_conflicts", opts, pool)); parent_abspath = svn_dirent_join(sbox.wc_abspath, "A", pool); - SVN_ERR(svn_wc__db_op_add_directory(sbox.wc_ctx->db, parent_abspath, - NULL /*props*/, NULL, pool)); child1_abspath = svn_dirent_join(parent_abspath, "foo", pool); child2_abspath = svn_dirent_join(parent_abspath, "bar", pool); + SVN_ERR(sbox_wc_mkdir(&sbox, "A")); + SVN_ERR(sbox_wc_mkdir(&sbox, "A/bar")); + SVN_ERR(sbox_file_write(&sbox, "A/foo", "")); + SVN_ERR(sbox_wc_add(&sbox, "A/foo")); conflict1 = tree_conflict_create(child1_abspath, svn_node_file, svn_wc_operation_merge, @@ -606,22 +608,22 @@ test_serialize_tree_conflict(const svn_test_opts_t *opts, SVN_TEST_ASSERT(complete); /* Everything available */ { - svn_wc_conflict_reason_t local_change; - svn_wc_conflict_action_t incoming_change; + svn_wc_conflict_reason_t reason; + svn_wc_conflict_action_t action; const char *moved_away_op_root_abspath; - SVN_ERR(svn_wc__conflict_read_tree_conflict(&local_change, - &incoming_change, + SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, + &action, &moved_away_op_root_abspath, sbox.wc_ctx->db, sbox.wc_abspath, conflict_skel, pool, pool)); - SVN_TEST_ASSERT(local_change == svn_wc_conflict_reason_moved_away); - SVN_TEST_ASSERT(incoming_change == svn_wc_conflict_action_delete); - SVN_TEST_ASSERT(!strcmp(moved_away_op_root_abspath, - sbox_wc_path(&sbox, "A/B"))); + SVN_TEST_ASSERT(reason == svn_wc_conflict_reason_moved_away); + SVN_TEST_ASSERT(action == svn_wc_conflict_action_delete); + SVN_TEST_STRING_ASSERT(moved_away_op_root_abspath, + sbox_wc_path(&sbox, "A/B")); } return SVN_NO_ERROR; @@ -807,9 +809,152 @@ test_prop_conflicts(const svn_test_opts_t *opts, return SVN_NO_ERROR; } +static svn_error_t * +test_prop_conflict_resolving(const svn_test_opts_t *opts, + apr_pool_t *pool) +{ + svn_test__sandbox_t b; + svn_skel_t *conflict; + const char *A_abspath; + const char *marker_abspath; + apr_hash_t *conflicted_props; + apr_hash_t *props; + const char *value; + + SVN_ERR(svn_test__sandbox_create(&b, "test_prop_resolving", opts, pool)); + SVN_ERR(sbox_wc_mkdir(&b, "A")); + + SVN_ERR(sbox_wc_propset(&b, "prop-1", "r1", "A")); + SVN_ERR(sbox_wc_propset(&b, "prop-2", "r1", "A")); + SVN_ERR(sbox_wc_propset(&b, "prop-3", "r1", "A")); + SVN_ERR(sbox_wc_propset(&b, "prop-4", "r1", "A")); + SVN_ERR(sbox_wc_propset(&b, "prop-5", "r1", "A")); + SVN_ERR(sbox_wc_propset(&b, "prop-6", "r1", "A")); + + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_propset(&b, "prop-1", "r2", "A")); + SVN_ERR(sbox_wc_propset(&b, "prop-2", "r2", "A")); + SVN_ERR(sbox_wc_propset(&b, "prop-3", "r2", "A")); + SVN_ERR(sbox_wc_propset(&b, "prop-4", NULL, "A")); + SVN_ERR(sbox_wc_propset(&b, "prop-5", NULL, "A")); + SVN_ERR(sbox_wc_propset(&b, "prop-7", "r2", "A")); + SVN_ERR(sbox_wc_propset(&b, "prop-8", "r2", "A")); + SVN_ERR(sbox_wc_commit(&b, "")); + + SVN_ERR(sbox_wc_propset(&b, "prop-1", "mod", "A")); + SVN_ERR(sbox_wc_propset(&b, "prop-2", "mod", "A")); + SVN_ERR(sbox_wc_propset(&b, "prop-3", "mod", "A")); + SVN_ERR(sbox_wc_propset(&b, "prop-4", "mod", "A")); + SVN_ERR(sbox_wc_propset(&b, "prop-5", "mod", "A")); + SVN_ERR(sbox_wc_propset(&b, "prop-6", "mod", "A")); + SVN_ERR(sbox_wc_propset(&b, "prop-7", "mod", "A")); + SVN_ERR(sbox_wc_propset(&b, "prop-8", "mod", "A")); + + SVN_ERR(sbox_wc_update(&b, "", 1)); + + A_abspath = sbox_wc_path(&b, "A"); + SVN_ERR(svn_wc__db_read_conflict(&conflict, NULL, NULL, + b.wc_ctx->db, A_abspath, + pool, pool)); + + /* We have tree conflicts... */ + SVN_TEST_ASSERT(conflict != NULL); + + SVN_ERR(svn_wc__conflict_read_prop_conflict(&marker_abspath, + NULL, NULL, NULL, + &conflicted_props, + b.wc_ctx->db, A_abspath, + conflict, + pool, pool)); + + SVN_TEST_ASSERT(conflicted_props != NULL); + /* All properties but r6 are conflicted */ + SVN_TEST_ASSERT(apr_hash_count(conflicted_props) == 7); + SVN_TEST_ASSERT(! svn_hash_gets(conflicted_props, "prop-6")); + + /* Let's resolve a few conflicts */ + SVN_ERR(sbox_wc_resolve_prop(&b, "A", "prop-1", + svn_wc_conflict_choose_mine_conflict)); + SVN_ERR(sbox_wc_resolve_prop(&b, "A", "prop-2", + svn_wc_conflict_choose_theirs_conflict)); + SVN_ERR(sbox_wc_resolve_prop(&b, "A", "prop-3", + svn_wc_conflict_choose_merged)); + + SVN_ERR(svn_wc__db_read_conflict(&conflict, NULL, NULL, + b.wc_ctx->db, A_abspath, + pool, pool)); + + /* We have tree conflicts... */ + SVN_TEST_ASSERT(conflict != NULL); + + SVN_ERR(svn_wc__conflict_read_prop_conflict(&marker_abspath, + NULL, NULL, NULL, + &conflicted_props, + b.wc_ctx->db, A_abspath, + conflict, + pool, pool)); + + SVN_TEST_ASSERT(conflicted_props != NULL); + SVN_TEST_ASSERT(apr_hash_count(conflicted_props) == 4); + + SVN_ERR(svn_wc__db_read_props(&props, b.wc_ctx->db, A_abspath, + pool, pool)); + + value = svn_prop_get_value(props, "prop-1"); + SVN_TEST_STRING_ASSERT(value, "mod"); + value = svn_prop_get_value(props, "prop-2"); + SVN_TEST_STRING_ASSERT(value, "r1"); + value = svn_prop_get_value(props, "prop-3"); + SVN_TEST_STRING_ASSERT(value, "mod"); + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_binary_file_conflict(const svn_test_opts_t *opts, + apr_pool_t *pool) +{ + svn_test__sandbox_t sbox; + const apr_array_header_t *conflicts; + svn_wc_conflict_description2_t *desc; + + SVN_ERR(svn_test__sandbox_create(&sbox, "test_binary_file_conflict", opts, pool)); + + /* Create and add a binary file. */ + SVN_ERR(sbox_file_write(&sbox, "binary-file", "\xff\xff")); + SVN_ERR(sbox_wc_add(&sbox, "binary-file")); + SVN_ERR(sbox_wc_propset(&sbox, SVN_PROP_MIME_TYPE, + "application/octet-stream", "binary-file")); + SVN_ERR(sbox_wc_commit(&sbox, "binary-file")); /* r1 */ + + /* Make a change to the binary file. */ + SVN_ERR(sbox_file_write(&sbox, "binary-file", "\xfc\xfc\xfc\xfc\xfc\xfc")); + SVN_ERR(sbox_wc_commit(&sbox, "binary-file")); /* r2 */ + + /* Update back to r1, make a conflicting change to binary file. */ + SVN_ERR(sbox_wc_update(&sbox, "binary-file", 1)); + SVN_ERR(sbox_file_write(&sbox, "binary-file", "\xfd\xfd\xfd\xfd")); + + /* Update to HEAD and ensure the conflict is marked as binary. */ + SVN_ERR(sbox_wc_update(&sbox, "binary-file", 2)); + SVN_ERR(svn_wc__read_conflicts(&conflicts, NULL, sbox.wc_ctx->db, + sbox_wc_path(&sbox, "binary-file"), + FALSE /* create_tempfiles */, + FALSE /* only_tree_conflict */, + pool, pool)); + SVN_TEST_ASSERT(conflicts->nelts == 1); + desc = APR_ARRAY_IDX(conflicts, 0, svn_wc_conflict_description2_t *); + SVN_TEST_ASSERT(desc->is_binary); + + return SVN_NO_ERROR; +} + + /* The test table. */ -struct svn_test_descriptor_t test_funcs[] = +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS2(test_deserialize_tree_conflict, @@ -826,6 +971,11 @@ struct svn_test_descriptor_t test_funcs[] = "read and write a tree conflict"), SVN_TEST_OPTS_PASS(test_prop_conflicts, "test prop conflicts"), + SVN_TEST_OPTS_PASS(test_prop_conflict_resolving, + "test property conflict resolving"), + SVN_TEST_OPTS_PASS(test_binary_file_conflict, + "test binary file conflict"), SVN_TEST_NULL }; +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_wc/db-test.c b/subversion/tests/libsvn_wc/db-test.c index 45e9c4d..76ec893 100644 --- a/subversion/tests/libsvn_wc/db-test.c +++ b/subversion/tests/libsvn_wc/db-test.c @@ -88,248 +88,205 @@ static const char * const TESTING_DATA = ( "insert into wcroot values (1, null); " "insert into pristine values ('$sha1$" SHA1_1 "', NULL, 15, 1, '$md5 $" MD5_1 "'); " +); - /* ### The file_externals column in NODES is temporary, and will be - ### removed. However, to keep the tests passing, we need to add it - ### to the following insert statements. *Be sure to remove it*. */ +#define NOT_MOVED FALSE, NULL +#define NO_COPY_FROM 0, NULL, SVN_INVALID_REVNUM +static const svn_test__nodes_data_t nodes_init_data[] = { /* load the base nodes into the nodes table */ - "insert into nodes values (" - " 1, '', 0, null, 1, '', 1, 'normal'," - " null, null, 'dir', '()', 'infinity', null, null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'A', 0, '', 1, 'A', 1, 'normal'," - " null, null, 'file', '()', null, '$sha1$" SHA1_1 "', null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " 10, null, null, null, null);" - "insert into nodes values (" - " 1, 'B', 0, '', 1, 'B', null, 'excluded'," - " null, null, 'symlink', null, null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'C', 0, '', 1, 'C', null, 'server-excluded'," - " null, null, 'unknown', null, null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'D', 0, '', 1, 'D', null, 'not-present'," - " null, null, 'unknown', null, null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'E', 0, '', 1, 'E', null, 'incomplete'," - " null, null, 'unknown', null, null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'F', 0, '', 1, 'F', 1, 'normal'," - " null, null, 'file', '()', null, '$sha1$" SHA1_1 "', null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " 15, null, null, null, null);" - "insert into nodes values (" - " 1, 'G', 0, '', 2, 'G-alt', 1, 'normal'," - " null, null, 'file', '()', null, '$sha1$" SHA1_1 "', null, 2, " TIME_2s ", '" AUTHOR_2 "'," - " 15, null, null, null, null);" - "insert into nodes values (" - " 1, 'H', 0, '', 1, 'H', 1, 'normal'," - " null, null, 'symlink', '()', null, null, 'H-target', 1, " TIME_1s ", '" AUTHOR_1 "'," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'I', 0, '', 1, 'I', 1, 'normal'," - " null, null, 'dir', '()', null, null, null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J', 0, '', 1, 'J', 1, 'normal'," - " null, null, 'dir', '()', null, null, null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-e', 0, 'J', 1, 'J/J-e', 1, 'normal'," - " null, 'other/place', 'dir', '()', null, null, null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-e/J-e-a', 0, 'J/J-e', 1, 'J/J-e/J-e-a', 1, 'normal'," - " null, null, 'file', '()', null, '$sha1$" SHA1_1 "', null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " 15, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-e/J-e-b', 0, 'J/J-e', 1, 'J/J-e/J-e-b', 1, 'normal'," - " null, null, 'dir', '()', null, null, null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-e/J-e-b/Jeba', 0, 'J/J-e/J-e-b', 1, 'J/J-e/J-e-b/Jeba', 1, 'normal'," - " null, null, 'file', '()', null, '$sha1$" SHA1_1 "', null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " 15, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-f', 0, 'J', 1, 'J/J-f', 1, 'normal'," - " null, null, 'dir', '()', null, null, null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-f/J-f-a', 0, 'J/J-f', 1, 'J/J-f/J-f-a', 1, 'normal'," - " null, null, 'dir', '()', null, null, null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'K', 0, '', 1, 'K', 1, 'normal'," - " null, null, 'dir', '()', null, null, null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'K/K-a', 0, 'K', 1, 'K/K-a', 1, 'normal'," - " null, null, 'file', '()', null, '$sha1$" SHA1_1 "', null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " 15, null, null, null, null);" - "insert into nodes values (" - " 1, 'K/K-b', 0, 'K', 1, 'K/K-b', 1, 'normal'," - " null, 'moved/away', 'file', '()', null, '$sha1$" SHA1_1 "', null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " 15, null, null, null, null);" - "" - /* Load data into NODES table; - ### op_depths have not been calculated by me yet; - the value 1 is just 'good enough' to make the nodes WORKING nodes. */ - "insert into nodes values (" - " 1, 'I', 1, '', 2, 'some/dir', 2, 'normal'," - " null, null, 'dir', '()', 'immediates', null, null, 2, " TIME_2s ", '" AUTHOR_2 "'," - " null, null, null, null, null);" - - /* I'm not sure what the working J is supposed to represent. It - replaces the base J, but is it a copy or not? It has no - copyfrom, but nodes like J/J-e appear to be deleted which - implies they are children of a copied J. */ - "insert into nodes values (" - " 1, 'J', 1, '', null, null, null, 'normal'," - " null, null, 'dir', '()', 'immediates', null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-a', 1, 'J', null, null, null, 'normal'," - " null, null, 'file', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-b', 2, 'J', 2, 'some/dir', 2, 'normal'," - " null, null, 'dir', '()', 'infinity', null, null, 2, " TIME_2s ", '" AUTHOR_2 "'," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-b/J-b-a', 3, 'J/J-b', 2, 'another/dir', 2, 'normal'," - " null, null, 'dir', '()', 'infinity', null, null, 2, " TIME_2s ", '" AUTHOR_2 "'," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-b/J-b-b', 2, 'J/J-b', null, null, 2, 'normal'," - " null, null, 'file', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-c', 1, 'J', null, null, null, 'normal'," - " null, null, 'dir', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-c/J-c-a', 1, 'J/J-c', null, null, null, 'normal'," - " null, null, 'dir', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-c', 2, 'J', null, null, null, 'base-deleted'," - " null, null, 'dir', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-c/J-c-a', 2, 'J/J-c', null, null, null, 'base-deleted'," - " null, null, 'dir', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-d', 2, 'J', 2, 'moved/file', 2, 'normal'," - " 1, null, 'file', '()', null, '$sha1$" SHA1_1 "', null, 2, " TIME_2s ", '" AUTHOR_2 "'," - " 10, null, null, null, null);" - "insert into nodes values (" - " 1, 'moved/file', 0, 'moved', 2, 'moved/file', 2, 'normal'," - " null, null, 'file', '()', null, '$sha1$" SHA1_1 "', null, 2, " TIME_2s ", '" AUTHOR_2 "'," - " 10, null, null, null, null);" - "insert into nodes values (" - " 1, 'moved/file', 2, 'moved', 2, 'moved/file', 2, 'base-deleted'," - " null, 'J/J-d', 'file', '()', null, null, null, null, null, null," - " 10, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-e', 1, 'J', null, null, null, 'normal'," - " null, null, 'dir', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-e/J-e-a', 1, 'J/J-e', null, null, null, 'normal'," - " null, null, 'file', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-e/J-e-b', 1, 'J/J-e', null, null, null, 'normal'," - " null, null, 'dir', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-e', 2, 'J', null, null, null, 'base-deleted'," - " null, null, 'dir', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-e/J-e-a', 2, 'J/J-e', null, null, null, 'base-deleted'," - " null, null, 'file', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-e/J-e-b', 2, 'J/J-e', null, null, null, 'base-deleted'," - " null, null, 'dir', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-e/J-e-b/Jeba', 1, 'J/J-e/J-e-b', null, null, null, 'base-deleted'," - " null, null, 'file', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-f', 1, 'J', null, null, null, 'normal'," - " null, null, 'dir', '()', 'immediates', null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-f/J-f-a', 1, 'J/J-f', null, null, null, 'base-deleted'," - " null, null, 'dir', '()', 'immediates', null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'K', 1, '', null, null, null, 'base-deleted'," - " null, null, 'dir', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'K/K-a', 1, 'K', null, null, null, 'base-deleted'," - " null, null, 'file', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'K/K-b', 1, 'K', null, null, null, 'base-deleted'," - " null, null, 'file', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'L', 1, '', null, null, null, 'normal'," - " null, null, 'dir', '()', 'immediates', null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'L/L-a', 1, 'L', null, null, null, 'normal'," - " null, null, 'dir', '()', 'immediates', null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'L/L-a/L-a-a', 1, 'L/L-a', null, null, null, 'normal'," - " null, null, 'dir', '()', 'immediates', null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'L/L-a', 2, 'L', null, null, null, 'base-deleted'," - " null, null, 'dir', '()', 'immediates', null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'L/L-a/L-a-a', 2, 'L/L-a', null, null, null, 'base-deleted'," - " null, null, 'dir', '()', 'immediates', null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'other/place', 2, 'other', null, null, null, 'normal'," - " 1, null, 'dir', '()', 'immediates', null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'other/place/J-e-a', 2, 'other/place', null, null, null, 'normal'," - " null, null, 'dir', '()', 'immediates', null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'other/place/J-e-b', 2, 'other/place', null, null, null, 'normal'," - " null, null, 'dir', '()', null, null, null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'other/place/J-e-b/Jeba', 0, 'other/place/J-e-b', null, null, null, 'normal'," - " null, null, 'file', '()', null, '$sha1$" SHA1_1 "', null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " 15, null, null, null, null);" - "insert into actual_node values (" - " 1, 'I', '', null, null, null, null, null, 'changelist', null, " - " null, null, null, null, null);" - "insert into actual_node values (" - " 1, 'F', '', null, null, null, null, null, null, null, " - " '" F_TC_DATA "', null, null, null, null);" - "insert into actual_node values (" - " 1, 'G', '', null, null, null, null, null, null, null, " - " '" G_TC_DATA "', null, null, null, null);" - ); + { 0, "", "normal", 1, "", 1, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 }, + { 0, "A", "normal", 1, "A", 1, NOT_MOVED, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 1, TIME_1a, AUTHOR_1, + FALSE, NULL, 10, 10 }, + + { 0, "B", "excluded", 1, "B", SVN_INVALID_REVNUM, NOT_MOVED, + svn_node_symlink}, + + { 0, "C", "server-excluded", 1, "C", 0, NOT_MOVED, + svn_node_unknown}, + + { 0, "D", "not-present", 1, "D", 0, NOT_MOVED, + svn_node_unknown}, + + { 0, "E", "incomplete", 1, "E", 1, NOT_MOVED, + svn_node_unknown}, + + { 0, "F", "normal", 1, "F", 1, NOT_MOVED, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2}, + + { 0, "G", "normal", 2, "G-alt", 1, NOT_MOVED, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2 }, + + { 0, "H", "normal", 1, "H", 1, NOT_MOVED, + svn_node_symlink, "()", NULL, NULL, "H-target", 1, TIME_1a, AUTHOR_1 }, + + { 0, "I", "normal", 1, "I", 1, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 }, + + { 0, "J", "normal", 1, "J", 1, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 }, + + { 0, "J/J-e", "normal", 1, "J/J-e", 1, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 }, + + { 0, "J/J-e/J-e-a", "normal", 1, "J/J-e/J-e-a", 1, NOT_MOVED, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 1, TIME_1a, AUTHOR_1 }, + + { 0, "J/J-e/J-e-b", "normal", 1, "J/J-e/J-e-b", 1, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 }, + + { 0, "J/J-e/J-e-b/Jeba", "normal", 1, "J/J-e/J-e-b/Jeba", 1, NOT_MOVED, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 1, TIME_1a, AUTHOR_1 }, + + { 0, "J/J-f", "normal", 1, "J/J-f", 1, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 }, + + { 0, "J/J-f/J-f-a", "normal", 1, "J/J-f/J-f-a", 1, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 }, + + { 0, "J", "normal", 1, "J", 1, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 }, + + { 0, "K", "normal", 1, "K", 1, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 }, + + { 0, "K/K-a", "normal", 2, "K/K-a", 1, NOT_MOVED, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2, + FALSE, NULL, 15, 14}, + + { 0, "K/K-b", "normal", 2, "K/K-b", 1, NOT_MOVED, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2, + FALSE, NULL, 15, 14}, + + /* Load data into the working layers of NODES */ + + { 1, "I", "normal", 2, "some/dir", 2, NOT_MOVED, + svn_node_dir, "()", "immediates", NULL, NULL, 2, TIME_2a, AUTHOR_2 }, + + /* J was originally a local addition, but its descendants are replaced, + so let's turn J in a copy */ + { 1, "J", "normal", 2, "q", 2, NOT_MOVED, + svn_node_dir, "()", "immediates", NULL, NULL, 2, TIME_2a, AUTHOR_2 }, + + { 1, "J/J-a", "normal", 2, "q/J-a", 2, NOT_MOVED, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2 }, + + { 1, "J/J-b", "normal", 2, "q/J-b", 2, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2 }, + + { 3, "J/J-b/J-b-a", "normal", 2, "another/dir", 2, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2 }, + + { 1, "J/J-b/J-b-b", "normal", 2, "q/J-b/J-b-b", 2, NOT_MOVED, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2 }, + + { 1, "J/J-c", "normal", 2, "q/J-c", 2, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2 }, + + { 1, "J/J-c/J-c-a", "normal", 2, "q/J-c/J-c-a", 2, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2 }, + + { 2, "J/J-c", "base-deleted", NO_COPY_FROM, NOT_MOVED, + svn_node_dir}, + + { 2, "J/J-c/J-c-a", "base-deleted", NO_COPY_FROM, NOT_MOVED, + svn_node_dir}, + + { 2, "J/J-d", "normal", 2, "moved/file", 2, TRUE, NULL, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2 }, + + { 0, "moved", "normal", 2, "moved", 2, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 }, + + { 0, "moved/file", "normal", 2, "moved/file", 2, NOT_MOVED, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2 }, + + { 2, "moved/file", "base-deleted", NO_COPY_FROM, FALSE, "J/J-d", + svn_node_file}, + + { 1, "J/J-e", "normal", 2, "q/J-e", 2, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2 }, + + { 1, "J/J-e/J-e-a", "normal", 2, "q/J-e/J-e-a", 2, NOT_MOVED, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2 }, + + { 1, "J/J-e/J-e-b", "normal", 2, "q/J-e/J-e-b", 2, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2 }, + + { 2, "J/J-e", "base-deleted", NO_COPY_FROM, FALSE, "other/place", + svn_node_dir}, + + { 2, "J/J-e/J-e-a", "base-deleted", NO_COPY_FROM, NOT_MOVED, + svn_node_file}, + + { 2, "J/J-e/J-e-b", "base-deleted", NO_COPY_FROM, NOT_MOVED, + svn_node_dir}, + + { 1, "J/J-e/J-e-b/Jeba", "base-deleted", NO_COPY_FROM, NOT_MOVED, + svn_node_file}, + + { 1, "J/J-f", "normal", 2, "q/J-f", 2, NOT_MOVED, + svn_node_dir, "()", "immediates", NULL, NULL, 2, TIME_2a, AUTHOR_2 }, + + { 1, "J/J-f/J-f-a", "base-deleted", NO_COPY_FROM, NOT_MOVED, + svn_node_dir}, + + { 1, "K", "base-deleted", NO_COPY_FROM, NOT_MOVED, + svn_node_dir}, + + { 1, "K/K-a", "base-deleted", NO_COPY_FROM, NOT_MOVED, + svn_node_file}, + + { 1, "K/K-b", "base-deleted", NO_COPY_FROM, FALSE, "moved/away", + svn_node_file}, + + { 1, "L", "normal", 2, "from", 2, NOT_MOVED, + svn_node_dir, "()", "immediates", NULL, NULL, 2, TIME_2a, AUTHOR_2 }, + + { 1, "L/L-a", "normal", 2, "from/L-a", 2, NOT_MOVED, + svn_node_dir, "()", "immediates", NULL, NULL, 2, TIME_2a, AUTHOR_2 }, + + { 1, "L/L-a/L-a-a", "normal", 2, "from/L-a/L-a-a", 2, NOT_MOVED, + svn_node_dir, "()", "immediates", NULL, NULL, 2, TIME_2a, AUTHOR_2 }, + + { 2, "L/L-a", "base-deleted", NO_COPY_FROM, NOT_MOVED, + svn_node_dir}, + + { 2, "L/L-a/L-a-a", "base-deleted", NO_COPY_FROM, NOT_MOVED, + svn_node_dir}, + + { 0, "other", "normal", 2, "other", 2, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2 }, + + { 2, "other/place", "normal", 2, "q/J-e", 2, TRUE, NULL, + svn_node_dir, "()", "immediates", NULL, NULL, 2, TIME_2a, AUTHOR_2 }, + + { 2, "other/place/J-e-a", "normal", 2, "q/J-e/J-e-a", 2, TRUE, NULL, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2 }, + + { 2, "other/place/J-e-b", "normal", 2, "q/J-e/J-e-b", 2, TRUE, NULL, + svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2 }, + + { 2, "other/place/J-e-b/Jeba", "normal", 2, "q/J-e/J-e-b/Jeba", 2, TRUE, NULL, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 1, TIME_1a, AUTHOR_1 }, + + /*** NEW ****/ + { 2, "moved/away", "normal", 2, "K/K-b", 1, TRUE, NULL, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2, + FALSE, NULL, 15, 14}, + { 0 } +}; + +static const svn_test__actual_data_t actual_init_data[] = { + { "A", NULL, "changelist", NULL }, + { "F", NULL, NULL, F_TC_DATA }, + { "G", NULL, NULL, F_TC_DATA }, + + { 0 } +}; static svn_error_t * create_open(svn_wc__db_t **db, @@ -338,10 +295,16 @@ create_open(svn_wc__db_t **db, apr_pool_t *pool) { SVN_ERR(svn_dirent_get_absolute(local_abspath, - svn_dirent_join("fake-wc", subdir, pool), + svn_dirent_join( + svn_test_data_path("db-test", pool), + subdir, pool), pool)); + + SVN_ERR(svn_io_remove_dir2(*local_abspath, TRUE, NULL, NULL, pool)); + SVN_ERR(svn_wc__db_open(db, NULL, FALSE, TRUE, pool, pool)); - SVN_ERR(svn_test__create_fake_wc(*local_abspath, TESTING_DATA, pool, pool)); + SVN_ERR(svn_test__create_fake_wc(*local_abspath, TESTING_DATA, + nodes_init_data, actual_init_data, pool)); svn_test_add_dir_cleanup(*local_abspath); @@ -361,18 +324,17 @@ set_prop(apr_hash_t *props, const char *name, const char *value, } -static svn_boolean_t +static svn_error_t * validate_abspath(const char *wcroot_abspath, const char *expected_relpath, const char *actual_abspath, apr_pool_t *scratch_pool) { - if (actual_abspath == NULL) - return FALSE; - return strcmp(svn_dirent_join(wcroot_abspath, + SVN_TEST_STRING_ASSERT(actual_abspath, + svn_dirent_join(wcroot_abspath, expected_relpath, - scratch_pool), - actual_abspath) == 0; + scratch_pool)); + return SVN_NO_ERROR; } @@ -660,7 +622,7 @@ test_inserting_nodes(apr_pool_t *pool) props, 1, TIME_1a, AUTHOR_1, children, svn_depth_infinity, - NULL, NULL, FALSE, NULL, NULL, NULL, + NULL, FALSE, NULL, NULL, NULL, NULL, pool)); /* Replace an incomplete node with a file node. */ @@ -771,11 +733,17 @@ test_children(apr_pool_t *pool) SVN_ERR(svn_wc__db_base_get_children(&children, db, local_abspath, pool, pool)); - SVN_TEST_ASSERT(children->nelts == 11); + SVN_TEST_ASSERT(children->nelts == 13); for (i = children->nelts; i--; ) { const char *name = APR_ARRAY_IDX(children, i, const char *); + if (strcmp(name, "moved") == 0 + || strcmp(name, "other") == 0) + { + continue; + } + SVN_TEST_ASSERT(strlen(name) == 1); /* ### check the actual values */ } @@ -783,11 +751,17 @@ test_children(apr_pool_t *pool) SVN_ERR(svn_wc__db_read_children(&children, db, local_abspath, pool, pool)); - SVN_TEST_ASSERT(children->nelts == 12); + SVN_TEST_ASSERT(children->nelts == 14); for (i = children->nelts; i--; ) { const char *name = APR_ARRAY_IDX(children, i, const char *); + if (strcmp(name, "moved") == 0 + || strcmp(name, "other") == 0) + { + continue; + } + SVN_TEST_ASSERT(strlen(name) == 1); /* ### check the actual values */ } @@ -858,7 +832,7 @@ test_working_info(apr_pool_t *pool) SVN_TEST_ASSERT(checksum == NULL); SVN_TEST_ASSERT(recorded_size == SVN_INVALID_FILESIZE); SVN_TEST_ASSERT(target == NULL); - SVN_TEST_STRING_ASSERT(changelist, "changelist"); + SVN_TEST_STRING_ASSERT(changelist, NULL); SVN_TEST_STRING_ASSERT(original_repos_relpath, "some/dir"); SVN_TEST_STRING_ASSERT(original_root_url, ROOT_TWO); SVN_TEST_STRING_ASSERT(original_uuid, UUID_TWO); @@ -876,8 +850,31 @@ test_working_info(apr_pool_t *pool) /* ### we need a hojillion more tests in here. I just want to get this ### round checked in, so I'm skipping more tests at this point. */ - - + SVN_ERR(svn_wc__db_read_info( + &status, &kind, &revision, + &repos_relpath, &repos_root_url, &repos_uuid, + &changed_rev, &changed_date, &changed_author, + &depth, &checksum, &target, &original_repos_relpath, + &original_root_url, &original_uuid, &original_revnum, + &lock, &recorded_size, &recorded_time, &changelist, + &conflicted, &op_root, &had_props, &props_mod, + &have_base, &have_more_work, &have_work, + db, svn_dirent_join(local_abspath, "A", pool), + pool, pool)); + SVN_TEST_ASSERT(status == svn_wc__db_status_normal); + SVN_TEST_ASSERT(kind == svn_node_file); + SVN_TEST_STRING_ASSERT(changelist, "changelist"); + SVN_TEST_ASSERT(revision == 1); + SVN_TEST_STRING_ASSERT(repos_relpath, "A"); + SVN_TEST_STRING_ASSERT(repos_root_url, "http://example.com/one"); + SVN_TEST_STRING_ASSERT(repos_uuid, "uuid1"); + SVN_TEST_ASSERT(changed_rev == 1); + SVN_TEST_ASSERT(changed_date == TIME_1a); + SVN_TEST_STRING_ASSERT(changed_author, AUTHOR_1); + SVN_TEST_ASSERT(depth == svn_depth_unknown); + SVN_TEST_ASSERT(checksum != NULL); + SVN_TEST_ASSERT(recorded_size == 10); + SVN_TEST_ASSERT(target == NULL); return SVN_NO_ERROR; } @@ -901,9 +898,16 @@ test_pdh(apr_pool_t *pool) NULL, NULL, pool)); + SVN_ERR(svn_wc__db_base_add_directory( + db, svn_dirent_join(local_abspath, "sub2", pool), + local_abspath, "sub2", ROOT_ONE, UUID_ONE, 1, + apr_hash_make(pool), 1, 1, "me", NULL, + svn_depth_infinity, NULL, FALSE, NULL, NULL, + NULL, NULL, pool)); + SVN_ERR(svn_wc__db_base_add_excluded_node( - db, svn_dirent_join(local_abspath, "sub/A", pool), - "sub/A", ROOT_ONE, UUID_ONE, 1, + db, svn_dirent_join(local_abspath, "sub2/A", pool), + "sub2/A", ROOT_ONE, UUID_ONE, 1, svn_node_file, svn_wc__db_status_server_excluded, NULL, NULL, pool)); @@ -941,17 +945,17 @@ test_scan_addition(apr_pool_t *pool) &original_revision, db, svn_dirent_join(local_abspath, "J", pool), pool, pool)); - SVN_TEST_ASSERT(status == svn_wc__db_status_added); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "J", op_root_abspath, pool)); + SVN_TEST_ASSERT(status == svn_wc__db_status_copied); + SVN_ERR(validate_abspath(local_abspath, "J", op_root_abspath, pool)); SVN_TEST_STRING_ASSERT(repos_relpath, "J"); SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE); SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE); - SVN_TEST_ASSERT(original_repos_relpath == NULL); - SVN_TEST_ASSERT(original_root_url == NULL); - SVN_TEST_ASSERT(original_uuid == NULL); - SVN_TEST_ASSERT(original_revision == SVN_INVALID_REVNUM); + SVN_TEST_STRING_ASSERT(original_repos_relpath, "q"); + SVN_TEST_STRING_ASSERT(original_root_url, ROOT_TWO); + SVN_TEST_STRING_ASSERT(original_uuid, UUID_TWO); + SVN_TEST_ASSERT(original_revision == 2); - /* Simple addition of a file (affects how scan-up is started). */ + /* Simple copy (affects how scan-up is started). */ SVN_ERR(svn_wc__db_scan_addition( &status, &op_root_abspath, &repos_relpath, &repos_root_url, &repos_uuid, @@ -959,15 +963,15 @@ test_scan_addition(apr_pool_t *pool) &original_revision, db, svn_dirent_join(local_abspath, "J/J-a", pool), pool, pool)); - SVN_TEST_ASSERT(status == svn_wc__db_status_added); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "J", op_root_abspath, pool)); + SVN_TEST_ASSERT(status == svn_wc__db_status_copied); + SVN_ERR(validate_abspath(local_abspath, "J", op_root_abspath, pool)); SVN_TEST_STRING_ASSERT(repos_relpath, "J/J-a"); SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE); SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE); - SVN_TEST_ASSERT(original_repos_relpath == NULL); - SVN_TEST_ASSERT(original_root_url == NULL); - SVN_TEST_ASSERT(original_uuid == NULL); - SVN_TEST_ASSERT(original_revision == SVN_INVALID_REVNUM); + SVN_TEST_STRING_ASSERT(original_repos_relpath, "q"); + SVN_TEST_STRING_ASSERT(original_root_url, ROOT_TWO); + SVN_TEST_STRING_ASSERT(original_uuid, UUID_TWO); + SVN_TEST_ASSERT(original_revision == 2); /* Node was moved here. */ SVN_ERR(svn_wc__db_scan_addition( @@ -985,15 +989,15 @@ test_scan_addition(apr_pool_t *pool) db, svn_dirent_join(local_abspath, "J/J-d", pool), pool, pool)); SVN_TEST_ASSERT(status == svn_wc__db_status_moved_here); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "J/J-d", + SVN_ERR(validate_abspath(local_abspath, "J/J-d", op_root_abspath, pool)); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "moved/file", + SVN_ERR(validate_abspath(local_abspath, "moved/file", moved_from_abspath, pool)); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "J/J-d", + SVN_ERR(validate_abspath(local_abspath, "J/J-d", move_op_root_abspath, pool)); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "moved/file", + SVN_ERR(validate_abspath(local_abspath, "moved/file", move_op_root_src, pool)); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "moved/file", + SVN_ERR(validate_abspath(local_abspath, "moved/file", delete_op_root_abspath, pool)); SVN_TEST_STRING_ASSERT(repos_relpath, "J/J-d"); SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE); @@ -1012,12 +1016,12 @@ test_scan_addition(apr_pool_t *pool) db, svn_dirent_join(local_abspath, "J/J-b", pool), pool, pool)); SVN_TEST_ASSERT(status == svn_wc__db_status_copied); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "J/J-b", + SVN_ERR(validate_abspath(local_abspath, "J", op_root_abspath, pool)); SVN_TEST_STRING_ASSERT(repos_relpath, "J/J-b"); SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE); SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE); - SVN_TEST_STRING_ASSERT(original_repos_relpath, "some/dir"); + SVN_TEST_STRING_ASSERT(original_repos_relpath, "q"); SVN_TEST_STRING_ASSERT(original_root_url, ROOT_TWO); SVN_TEST_STRING_ASSERT(original_uuid, UUID_TWO); SVN_TEST_ASSERT(original_revision == 2); @@ -1031,7 +1035,7 @@ test_scan_addition(apr_pool_t *pool) db, svn_dirent_join(local_abspath, "J/J-b/J-b-a", pool), pool, pool)); SVN_TEST_ASSERT(status == svn_wc__db_status_copied); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "J/J-b/J-b-a", + SVN_ERR(validate_abspath(local_abspath, "J/J-b/J-b-a", op_root_abspath, pool)); SVN_TEST_STRING_ASSERT(repos_relpath, "J/J-b/J-b-a"); SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE); @@ -1050,12 +1054,12 @@ test_scan_addition(apr_pool_t *pool) db, svn_dirent_join(local_abspath, "J/J-b/J-b-b", pool), pool, pool)); SVN_TEST_ASSERT(status == svn_wc__db_status_copied); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "J/J-b", + SVN_ERR(validate_abspath(local_abspath, "J", op_root_abspath, pool)); SVN_TEST_STRING_ASSERT(repos_relpath, "J/J-b/J-b-b"); SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE); SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE); - SVN_TEST_STRING_ASSERT(original_repos_relpath, "some/dir"); + SVN_TEST_STRING_ASSERT(original_repos_relpath, "q"); SVN_TEST_STRING_ASSERT(original_root_url, ROOT_TWO); SVN_TEST_STRING_ASSERT(original_uuid, UUID_TWO); SVN_TEST_ASSERT(original_revision == 2); @@ -1084,13 +1088,13 @@ test_scan_deletion(apr_pool_t *pool) ©_op_root_abspath, db, svn_dirent_join(local_abspath, "J/J-e", pool), pool, pool)); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "J", + SVN_ERR(validate_abspath(local_abspath, "J", base_del_abspath, pool)); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "other/place", + SVN_ERR(validate_abspath(local_abspath, "other/place", moved_to_abspath, pool)); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "J/J-e", + SVN_ERR(validate_abspath(local_abspath, "J/J-e", work_del_abspath, pool)); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "other/place", + SVN_ERR(validate_abspath(local_abspath, "other/place", copy_op_root_abspath, pool)); /* Node was moved elsewhere (child of operation root). */ @@ -1101,13 +1105,13 @@ test_scan_deletion(apr_pool_t *pool) ©_op_root_abspath, db, svn_dirent_join(local_abspath, "J/J-e/J-e-a", pool), pool, pool)); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "J", + SVN_ERR(validate_abspath(local_abspath, "J", base_del_abspath, pool)); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "other/place/J-e-a", + SVN_ERR(validate_abspath(local_abspath, "other/place/J-e-a", moved_to_abspath, pool)); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "J/J-e", + SVN_ERR(validate_abspath(local_abspath, "J/J-e", work_del_abspath, pool)); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "other/place", + SVN_ERR(validate_abspath(local_abspath, "other/place", copy_op_root_abspath, pool)); /* Root of delete. Parent is a WORKING node. */ @@ -1119,10 +1123,10 @@ test_scan_deletion(apr_pool_t *pool) db, svn_dirent_join(local_abspath, "J/J-c", pool), pool, pool)); /* Implicit delete of "J" (via replacement). */ - SVN_TEST_ASSERT(validate_abspath(local_abspath, "J", + SVN_ERR(validate_abspath(local_abspath, "J", base_del_abspath, pool)); SVN_TEST_ASSERT(moved_to_abspath == NULL); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "J/J-c", + SVN_ERR(validate_abspath(local_abspath, "J/J-c", work_del_abspath, pool)); /* Child of a deleted root. */ @@ -1134,10 +1138,10 @@ test_scan_deletion(apr_pool_t *pool) db, svn_dirent_join(local_abspath, "J/J-c/J-c-a", pool), pool, pool)); /* Implicit delete of "J" (via replacement). */ - SVN_TEST_ASSERT(validate_abspath(local_abspath, "J", + SVN_ERR(validate_abspath(local_abspath, "J", base_del_abspath, pool)); SVN_TEST_ASSERT(moved_to_abspath == NULL); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "J/J-c", + SVN_ERR(validate_abspath(local_abspath, "J/J-c", work_del_abspath, pool)); /* Base-deleted tree extending past deleted WORKING subtree. */ @@ -1151,11 +1155,11 @@ test_scan_deletion(apr_pool_t *pool) /* ### I don't understand this. "J/J-e/J-e-b/Jeba" is a deleted base node that is not overlayed by the replacement rooted at "J". Why does base_del_abspath refer to "J-e"? */ - SVN_TEST_ASSERT(validate_abspath(local_abspath, "J", + SVN_ERR(validate_abspath(local_abspath, "J", base_del_abspath, pool)); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "other/place/J-e-b/Jeba", + SVN_ERR(validate_abspath(local_abspath, "other/place/J-e-b/Jeba", moved_to_abspath, pool)); - SVN_TEST_ASSERT(work_del_abspath == NULL); + SVN_TEST_STRING_ASSERT(work_del_abspath, NULL); /* Base-deleted tree extending past added WORKING tree. */ SVN_ERR(svn_wc__db_scan_deletion( @@ -1166,10 +1170,10 @@ test_scan_deletion(apr_pool_t *pool) db, svn_dirent_join(local_abspath, "J/J-f/J-f-a", pool), pool, pool)); /* Implicit delete of "J" (via replacement). */ - SVN_TEST_ASSERT(validate_abspath(local_abspath, "J", + SVN_ERR(validate_abspath(local_abspath, "J", base_del_abspath, pool)); - SVN_TEST_ASSERT(moved_to_abspath == NULL); - SVN_TEST_ASSERT(work_del_abspath == NULL); + SVN_TEST_STRING_ASSERT(moved_to_abspath, NULL); + SVN_TEST_STRING_ASSERT(work_del_abspath, NULL); /* Root of delete. Parent is a BASE node. */ SVN_ERR(svn_wc__db_scan_deletion( @@ -1179,10 +1183,10 @@ test_scan_deletion(apr_pool_t *pool) NULL, db, svn_dirent_join(local_abspath, "K", pool), pool, pool)); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "K", + SVN_ERR(validate_abspath(local_abspath, "K", base_del_abspath, pool)); - SVN_TEST_ASSERT(moved_to_abspath == NULL); - SVN_TEST_ASSERT(work_del_abspath == NULL); + SVN_TEST_STRING_ASSERT(moved_to_abspath, NULL); + SVN_TEST_STRING_ASSERT(work_del_abspath, NULL); /* Base-deleted tree. Start below root. */ SVN_ERR(svn_wc__db_scan_deletion( @@ -1192,10 +1196,10 @@ test_scan_deletion(apr_pool_t *pool) NULL, db, svn_dirent_join(local_abspath, "K/K-a", pool), pool, pool)); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "K", + SVN_ERR(validate_abspath(local_abspath, "K", base_del_abspath, pool)); - SVN_TEST_ASSERT(moved_to_abspath == NULL); - SVN_TEST_ASSERT(work_del_abspath == NULL); + SVN_TEST_STRING_ASSERT(moved_to_abspath, NULL); + SVN_TEST_STRING_ASSERT(work_del_abspath, NULL); /* Base-deleted tree via move. */ SVN_ERR(svn_wc__db_scan_deletion( @@ -1205,13 +1209,13 @@ test_scan_deletion(apr_pool_t *pool) ©_op_root_abspath, db, svn_dirent_join(local_abspath, "K/K-b", pool), pool, pool)); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "K", + SVN_ERR(validate_abspath(local_abspath, "K", base_del_abspath, pool)); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "moved/away", + SVN_ERR(validate_abspath(local_abspath, "moved/away", moved_to_abspath, pool)); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "moved/away", + SVN_ERR(validate_abspath(local_abspath, "moved/away", copy_op_root_abspath, pool)); - SVN_TEST_ASSERT(work_del_abspath == NULL); + SVN_TEST_STRING_ASSERT(work_del_abspath, NULL); /* Subtree deletion of added tree. Start at child. */ SVN_ERR(svn_wc__db_scan_deletion( @@ -1221,9 +1225,9 @@ test_scan_deletion(apr_pool_t *pool) NULL, db, svn_dirent_join(local_abspath, "L/L-a/L-a-a", pool), pool, pool)); - SVN_TEST_ASSERT(base_del_abspath == NULL); - SVN_TEST_ASSERT(moved_to_abspath == NULL); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "L/L-a", + SVN_TEST_STRING_ASSERT(base_del_abspath, NULL); + SVN_TEST_STRING_ASSERT(moved_to_abspath, NULL); + SVN_ERR(validate_abspath(local_abspath, "L/L-a", work_del_abspath, pool)); /* Subtree deletion of added tree. Start at root. */ @@ -1234,9 +1238,9 @@ test_scan_deletion(apr_pool_t *pool) NULL, db, svn_dirent_join(local_abspath, "L/L-a", pool), pool, pool)); - SVN_TEST_ASSERT(base_del_abspath == NULL); - SVN_TEST_ASSERT(moved_to_abspath == NULL); - SVN_TEST_ASSERT(validate_abspath(local_abspath, "L/L-a", + SVN_TEST_STRING_ASSERT(base_del_abspath, NULL); + SVN_TEST_STRING_ASSERT(moved_to_abspath, NULL); + SVN_ERR(validate_abspath(local_abspath, "L/L-a", work_del_abspath, pool)); return SVN_NO_ERROR; @@ -1269,7 +1273,7 @@ test_global_relocate(apr_pool_t *pool) SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE); SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE); - /* Test relocating to a repos not existant in the db */ + /* Test relocating to a repos not existent in the db */ SVN_ERR(svn_wc__db_global_relocate(db, local_abspath, ROOT_THREE, pool)); SVN_ERR(svn_wc__db_read_info(NULL, NULL, NULL, &repos_relpath, &repos_root_url, &repos_uuid, @@ -1521,7 +1525,9 @@ test_externals_store(apr_pool_t *pool) return SVN_NO_ERROR; } -struct svn_test_descriptor_t test_funcs[] = +static int max_threads = 2; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS2(test_getting_info, @@ -1546,3 +1552,5 @@ struct svn_test_descriptor_t test_funcs[] = "externals store"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_wc/entries-compat.c b/subversion/tests/libsvn_wc/entries-compat.c index 34ad425..3470c06 100644 --- a/subversion/tests/libsvn_wc/entries-compat.c +++ b/subversion/tests/libsvn_wc/entries-compat.c @@ -87,199 +87,186 @@ static const char * const TESTING_DATA = ( "insert into wcroot values (1, null); " "insert into pristine values ('$sha1$" SHA1_1 "', NULL, 15, 1, '$md5 $" MD5_1 "'); " + ); - /* ### The file_externals column in NODES is temporary, and will be - ### removed. However, to keep the tests passing, we need to add it - ### to the following insert statements. *Be sure to remove it*. */ +#define NOT_MOVED FALSE, NULL +#define NO_COPY_FROM 0, NULL, SVN_INVALID_REVNUM +static const svn_test__nodes_data_t nodes[] = +{ /* load the base nodes into the nodes table */ - "insert into nodes values (" - " 1, '', 0, null, 1, '', 1, 'normal'," - " null, null, 'dir', '()', 'infinity', null, null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'A', 0, '', 1, 'A', 1, 'normal'," - " null, null, 'file', '()', null, '$sha1$" SHA1_1 "', null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " 10, null, null, null, null);" - "insert into nodes values (" - " 1, 'B', 0, '', 1, 'B', null, 'excluded'," - " null, null, 'symlink', null, null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'C', 0, '', 1, 'C', null, 'server-excluded'," - " null, null, 'unknown', null, null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'D', 0, '', 1, 'D', null, 'not-present'," - " null, null, 'unknown', null, null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'E', 0, '', 1, 'E', null, 'incomplete'," - " null, null, 'unknown', null, null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'F', 0, '', 1, 'F', 1, 'normal'," - " null, null, 'file', '()', null, '$sha1$" SHA1_1 "', null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " 15, null, null, null, null);" - "insert into nodes values (" - " 1, 'G', 0, '', 2, 'G-alt', 1, 'normal'," - " null, null, 'file', '()', null, '$sha1$" SHA1_1 "', null, 2, " TIME_2s ", '" AUTHOR_2 "'," - " 15, null, null, null, null);" - "insert into nodes values (" - " 1, 'H', 0, '', 1, 'H', 1, 'normal'," - " null, null, 'symlink', '()', null, null, 'H-target', 1, " TIME_1s ", '" AUTHOR_1 "'," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'I', 0, '', 1, 'I', 1, 'normal'," - " null, null, 'dir', '()', null, null, null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J', 0, '', 1, 'J', 1, 'normal'," - " null, null, 'dir', '()', null, null, null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-e', 0, 'J', 1, 'J/J-e', 1, 'normal'," - " null, null, 'dir', '()', null, null, null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-e/J-e-a', 0, 'J/J-e', 1, 'J/J-e/J-e-a', 1, 'normal'," - " null, null, 'file', '()', null, '$sha1$" SHA1_1 "', null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " 15, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-e/J-e-b', 0, 'J/J-e', 1, 'J/J-e/J-e-b', 1, 'normal'," - " null, null, 'dir', '()', null, null, null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-e/J-e-b/Jeba', 0, 'J/J-e/J-e-b', 1, 'J/J-e/J-e-b/Jeba', 1, 'normal'," - " null, null, 'file', '()', null, '$sha1$" SHA1_1 "', null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " 15, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-f', 0, 'J', 1, 'J/J-f', 1, 'normal'," - " null, null, 'dir', '()', null, null, null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-f/J-f-a', 0, 'J/J-f', 1, 'J/J-f/J-f-a', 1, 'normal'," - " null, null, 'dir', '()', null, null, null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'K', 0, '', 1, 'K', 1, 'normal'," - " null, null, 'dir', '()', null, null, null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'K/K-a', 0, 'K', 1, 'K/K-a', 1, 'normal'," - " null, null, 'file', '()', null, '$sha1$" SHA1_1 "', null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " 15, null, null, null, null);" - "insert into nodes values (" - " 1, 'K/K-b', 0, 'K', 1, 'K/K-b', 1, 'normal'," - " null, null, 'file', '()', null, '$sha1$" SHA1_1 "', null, 1, " TIME_1s ", '" AUTHOR_1 "'," - " 15, null, null, null, null);" - "" + { 0, "", "normal", 1, "", 1, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1}, + + { 0, "A", "normal", 1, "A", 1, NOT_MOVED, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 1, TIME_1a, AUTHOR_1}, + + { 0, "B", "excluded", 1, "B", 1, NOT_MOVED, + svn_node_symlink}, + + { 0, "C", "server-excluded",1, "C", 0, NOT_MOVED, + svn_node_unknown}, + + { 0, "D", "not-present", 1, "D", 0, NOT_MOVED, + svn_node_unknown}, + + { 0, "E", "incomplete", 1, "E", SVN_INVALID_REVNUM, NOT_MOVED, + svn_node_unknown}, + + { 0, "F", "normal", 1, "G-alt", 1, NOT_MOVED, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 1, TIME_1a, AUTHOR_1}, + + { 0, "G", "normal", 1, "G-alt", 1, NOT_MOVED, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 1, TIME_1a, AUTHOR_1}, + + { 0, "H", "normal", 1, "I", 1, NOT_MOVED, + svn_node_symlink, NULL, NULL, NULL, "H-target", 1, TIME_1a, AUTHOR_1}, + + { 0, "I", "normal", 1, "I", 1, NOT_MOVED, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 1, TIME_1a, AUTHOR_1}, + + { 0, "J", "normal", 1, "J", 1, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1}, + + { 0, "J/J-c", "normal", 1, "J/J-c", 1, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1}, + + { 0, "J/J-c/J-c-a", "not-present", 1, "J/J-c/J-c-a", 1, NOT_MOVED, + svn_node_dir}, + + { 0, "J/J-e", "normal", 1, "J/J-e", 1, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1}, + + { 0, "J/J-e/J-e-a", "normal", 1, "J/J-e/J-e-a", 1, NOT_MOVED, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 1, TIME_1a, AUTHOR_1}, + + { 0, "J/J-e/J-e-b", "normal", 1, "J/J-e/J-e-b", 1, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1}, + + { 0, "J/J-e/J-e-b/Jeba", "normal", 1, "J/J-e/J-e-b/Jeba", 1, NOT_MOVED, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 1, TIME_1a, AUTHOR_1}, + + { 0, "J/J-f", "normal", 1, "J/J-f", 1, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1}, + + { 0, "J/J-f/J-f-a", "normal", 1, "J/J-f/J-f-a", 1, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1}, + + { 0, "K", "normal", 1, "K", 1, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1}, + + { 0, "K/K-a", "normal", 1, "K/K-a", 1, NOT_MOVED, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 1, TIME_1a, AUTHOR_1}, + + { 0, "K/K-b", "normal", 1, "K/K-b", 1, NOT_MOVED, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 1, TIME_1a, AUTHOR_1}, + + { 0, "L", "normal", 1, "switched", 1, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1}, + + { 0, "L/L-a", "normal", 1, "switched/L-a", 1, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1}, + + { 0, "L/L-a/L-a-a", "normal", 1, "switched/L-a/L-a-a", 1, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1}, + /* Load data into NODES table; ### op_depths have not been calculated by me yet; the value 1 is just 'good enough' to make the nodes WORKING nodes. */ - "insert into nodes values (" - " 1, 'I', 1, '', 2, 'some/dir', 2, 'normal'," - " null, null, 'dir', '()', 'immediates', null, null, 2, " TIME_2s ", '" AUTHOR_2 "'," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J', 1, '', null, null, null, 'normal'," - " null, null, 'dir', '()', 'immediates', null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-a', 1, 'J', null, null, null, 'normal'," - " null, null, 'file', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-b', 1, 'J', 2, 'some/dir', 2, 'normal'," - " null, null, 'dir', '()', 'infinity', null, null, 2, " TIME_2s ", '" AUTHOR_2 "'," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-b/J-b-a', 1, 'J/J-b', 2, 'another/dir', 2, 'normal'," - " null, null, 'dir', '()', 'infinity', null, null, 2, " TIME_2s ", '" AUTHOR_2 "'," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-b/J-b-b', 1, 'J/J-b', null, null, null, 'normal'," - " null, null, 'file', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-c', 1, 'J', null, null, null, 'not-present'," - " null, null, 'dir', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-c/J-c-a', 1, 'J/J-c', null, null, null, 'not-present'," - " null, null, 'dir', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-d', 1, 'J', 2, 'moved/file', 2, 'normal'," - " 1, null, 'file', '()', null, '$sha1$" SHA1_1 "', null, 2, " TIME_2s ", '" AUTHOR_2 "'," - " 10, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-e', 1, 'J', null, null, null, 'not-present'," - " null, 'other/place', 'dir', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-e/J-e-a', 1, 'J/J-e', null, null, null, 'not-present'," - " null, null, 'file', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-e/J-e-b', 1, 'J/J-e', null, null, null, 'not-present'," - " null, null, 'dir', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-e/J-e-b/Jeba', 1, 'J/J-e/J-e-b', null, null, null, 'base-deleted'," - " null, null, 'file', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-f', 1, 'J', null, null, null, 'normal'," - " null, null, 'dir', '()', 'immediates', null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'J/J-f/J-f-a', 1, 'J/J-f', null, null, null, 'base-deleted'," - " null, null, 'dir', '()', 'immediates', null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'K', 1, '', null, null, null, 'base-deleted'," - " null, null, 'dir', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'K/K-a', 1, 'K', null, null, null, 'base-deleted'," - " null, null, 'file', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'K/K-b', 1, 'K', null, null, null, 'base-deleted'," - " null, 'moved/away', 'file', '()', null, null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'L', 1, '', null, null, null, 'normal'," - " null, null, 'dir', '()', 'immediates', null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'L/L-a', 1, 'L', null, null, null, 'not-present'," - " null, null, 'dir', '()', 'immediates', null, null, null, null, null," - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'L/L-a/L-a-a', 1, 'L/L-a', null, null, null, 'not-present'," - " null, null, 'dir', '()', 'immediates', null, null, null, null, null," - " null, null, null, null, null);" - "insert into actual_node values (" - " 1, 'I', '', null, null, null, null, null, 'changelist', null, " - " null, null, null, null, null);" - "insert into actual_node values (" - " 1, 'F', '', null, null, null, null, null, null, null, " - " '" F_TC_DATA "', null, null, null, null);" - "insert into actual_node values (" - " 1, 'G', '', null, null, null, null, null, null, null, " - " '" G_TC_DATA "', null, null, null, null);" - " " - "insert into nodes values (" - " 1, 'M', 0, '', 1, 'M', 1, 'normal', " - " null, null, 'dir', '()', null, null, null, 1, " TIME_1s ", '" AUTHOR_1 "', " - " null, null, null, null, null);" - "insert into nodes values (" - " 1, 'M/M-a', 0, 'M', 1, 'M/M-a', 1, 'not-present', " - " null, null, 'file', '()', null, null, null, 1, null, null, " - " null, null, null, null, null);" - ); + + { 1, "I", "normal", 2, "some/file", 2, NOT_MOVED, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2}, + + { 1, "J", "normal", NO_COPY_FROM, NOT_MOVED, + svn_node_dir, NULL, "immediates"}, + + { 2, "J/J-a", "normal", NO_COPY_FROM, NOT_MOVED, + svn_node_file}, + + { 2, "J/J-b", "normal", 2, "some/dir", 2, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2}, + + { 3, "J/J-b/J-b-a", "normal", 2, "another/dir", 2, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2}, + + { 3, "J/J-b/J-b-b", "normal", NO_COPY_FROM, NOT_MOVED, + svn_node_file}, + + /* This triggers a validation warning: bad delete */ + { 1, "J/J-c", "base-deleted", NO_COPY_FROM, NOT_MOVED, + svn_node_dir}, + + { 1, "J/J-d", "normal", 2, "moved/file", 2, NOT_MOVED, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2}, + + { 1, "J/J-e", "base-deleted", NO_COPY_FROM, FALSE, "other/place", + svn_node_dir}, + + { 1, "J/J-e/J-e-a", "base-deleted", NO_COPY_FROM, NOT_MOVED, + svn_node_file}, + + { 1, "J/J-e/J-e-b", "base-deleted", NO_COPY_FROM, NOT_MOVED, + svn_node_dir}, + + { 1, "J/J-e/J-e-b/Jeba", "base-deleted", NO_COPY_FROM, NOT_MOVED, + svn_node_file}, + + { 1, "J/J-f", "base-deleted", NO_COPY_FROM, NOT_MOVED, + svn_node_dir}, + + { 2, "J/J-f", "normal", NO_COPY_FROM, NOT_MOVED, + svn_node_dir, NULL, "immediates"}, + + { 1, "J/J-f/J-f-a", "base-deleted", NO_COPY_FROM, NOT_MOVED, + svn_node_dir}, + + { 1, "K", "base-deleted", NO_COPY_FROM, NOT_MOVED, + svn_node_dir}, + + { 1, "K/K-a", "base-deleted", NO_COPY_FROM, NOT_MOVED, + svn_node_file}, + + { 1, "K/K-b", "base-deleted", NO_COPY_FROM, FALSE, "moved/away", + svn_node_file}, + + { 1, "L", "normal", NO_COPY_FROM, NOT_MOVED, + svn_node_dir, NULL, "immediates"}, + + { 1, "L/L-a", "base-deleted", NO_COPY_FROM, NOT_MOVED, + svn_node_dir}, + + { 1, "L/L-a/L-a-a", "base-deleted", NO_COPY_FROM, NOT_MOVED, + svn_node_dir}, + + { 1, "M", "normal", 1, "M", 1, NOT_MOVED, + svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1}, + + { 1, "M/M-a", "not-present", 1, "M/M-a", 1, NOT_MOVED, + svn_node_file}, + + /**** Move target of K/K-b ****/ + { 1, "moved", "normal", NO_COPY_FROM, NOT_MOVED, + svn_node_dir, NULL, "infinity" }, + { 2, "moved/away", "normal", 1, "??", 1, TRUE, NULL, + svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 1, TIME_1a, AUTHOR_1}, + + /**** Move target of J/J-e ****/ + { 1, "other", "normal", NO_COPY_FROM, NOT_MOVED, + svn_node_dir, NULL, "empty"}, + + { 2, "other/place", "normal", 1, "??", 1, TRUE, NULL, + svn_node_dir, "()", "infinity"}, + + { 0 }, +}; + +static const svn_test__actual_data_t actuals[] = +{ + { "I", NULL, "changelist", NULL }, + { "F", NULL, NULL, NULL /* TC-DATA */ }, + { "G", NULL, NULL, NULL /* TC-DATA */ }, + { 0 }, +}; static const char * const M_TESTING_DATA = ( @@ -310,10 +297,8 @@ create_fake_wc(const char *subdir, apr_pool_t *pool) SVN_ERR(svn_io_remove_dir2(root, TRUE, NULL, NULL, pool)); SVN_ERR(svn_dirent_get_absolute(&wc_abspath, root, pool)); - SVN_ERR(svn_test__create_fake_wc(wc_abspath, TESTING_DATA, pool, pool)); - - wc_abspath = svn_dirent_join(wc_abspath, "M", pool); - SVN_ERR(svn_test__create_fake_wc(wc_abspath, M_TESTING_DATA, pool, pool)); + SVN_ERR(svn_test__create_fake_wc(wc_abspath, TESTING_DATA, nodes, actuals, + pool)); return SVN_NO_ERROR; } @@ -368,8 +353,8 @@ test_entries_alloc(apr_pool_t *pool) SVN_ERR(svn_wc_entries_read(&entries, adm_access, TRUE /* show_hidden */, pool)); - /* The wcroot has 12 BASE children + 1 WORKING child + "this dir". */ - SVN_TEST_ASSERT(apr_hash_count(entries) == 14); + /* The wcroot has 12 BASE children + 3 WORKING child + "this dir". */ + SVN_TEST_ASSERT(apr_hash_count(entries) == 16); /* The "D" entry in the entries hash should be what we get from the svn_wc_entry() entrypoint. */ @@ -377,7 +362,7 @@ test_entries_alloc(apr_pool_t *pool) "fake-wc", WC_NAME, "D", - NULL); + SVN_VA_NULL); SVN_ERR(svn_wc_entry(&entry, local_relpath, adm_access, TRUE, pool)); SVN_TEST_ASSERT(entry == apr_hash_get(entries, "D", APR_HASH_KEY_STRING)); @@ -400,6 +385,7 @@ test_stubs(apr_pool_t *pool) const svn_wc_entry_t *stub_entry; const svn_wc_entry_t *entry; const svn_wc_entry_t *test_entry; + const char *M_dir; apr_hash_t *entries; #undef WC_NAME @@ -407,13 +393,16 @@ test_stubs(apr_pool_t *pool) SVN_ERR(create_open(&db, &local_abspath, WC_NAME, pool)); + M_dir = svn_dirent_join(local_abspath, "M", pool); + SVN_ERR(svn_test__create_fake_wc(M_dir, M_TESTING_DATA, NULL, NULL, pool)); + /* The "M" entry is a subdir. Let's ensure we can reach its stub, and the actual contents. */ local_relpath = svn_dirent_join_many(pool, "fake-wc", WC_NAME, "M", - NULL); + SVN_VA_NULL); SVN_ERR(svn_wc_adm_open3(&adm_access, NULL /* associated */, @@ -428,6 +417,8 @@ test_stubs(apr_pool_t *pool) subdir baton with ADM_ACCESS. */ SVN_ERR(svn_wc_entry(&stub_entry, local_relpath, adm_access, TRUE, pool)); SVN_TEST_STRING_ASSERT(stub_entry->name, "M"); + /* Schedule add in parent-wc. Schedule normal in obstructing working copy */ + SVN_TEST_ASSERT(stub_entry->schedule == svn_wc_schedule_add); SVN_ERR(svn_wc_adm_open3(&subdir_access, adm_access, @@ -441,6 +432,7 @@ test_stubs(apr_pool_t *pool) /* Ensure we get the real entry. */ SVN_ERR(svn_wc_entry(&entry, local_relpath, subdir_access, TRUE, pool)); SVN_TEST_STRING_ASSERT(entry->name, ""); + SVN_TEST_ASSERT(entry->schedule == svn_wc_schedule_normal); /* Ensure that we get the SAME entry, even using the parent baton. */ SVN_ERR(svn_wc_entry(&test_entry, local_relpath, adm_access, TRUE, pool)); @@ -638,7 +630,9 @@ test_access_baton_like_locking(apr_pool_t *pool) } -struct svn_test_descriptor_t test_funcs[] = +static int max_threads = -1; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS2(test_entries_alloc, @@ -649,3 +643,5 @@ struct svn_test_descriptor_t test_funcs[] = "access baton like locks must work with wc-ng"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_wc/op-depth-test.c b/subversion/tests/libsvn_wc/op-depth-test.c index 39afcf4..c0ec24b 100644 --- a/subversion/tests/libsvn_wc/op-depth-test.c +++ b/subversion/tests/libsvn_wc/op-depth-test.c @@ -28,6 +28,7 @@ #include <apr_general.h> #include "svn_types.h" +#include "svn_hash.h" #include "svn_io.h" #include "svn_dirent_uri.h" #include "svn_pools.h" @@ -39,9 +40,10 @@ #include "utils.h" -#include "private/svn_wc_private.h" -#include "private/svn_sqlite.h" #include "private/svn_dep_compat.h" +#include "private/svn_sorts_private.h" +#include "private/svn_sqlite.h" +#include "private/svn_wc_private.h" #include "../../libsvn_wc/wc.h" #include "../../libsvn_wc/wc_db.h" #include "../../libsvn_wc/workqueue.h" @@ -51,17 +53,9 @@ #include "../svn_test.h" -#ifdef _MSC_VER -#pragma warning(disable: 4221) /* nonstandard extension used */ -#endif +#include "wc-test-queries.h" -/* This macro is not available in 1.8.x, but let's just use it here */ -#ifndef SVN_VA_NULL -struct svn_null_pointer_constant_stdarg_sentinel_t; - -/** Null pointer constant used as a sentinel in variable argument lists. */ -#define SVN_VA_NULL ((struct svn_null_pointer_constant_stdarg_sentinel_t*)0) -#endif +WC_TEST_QUERIES_SQL_DECLARE_STATEMENTS(op_depth_statements); /* Compare strings, like strcmp but either or both may be NULL which * compares equal to NULL and not equal to any non-NULL string. */ @@ -83,13 +77,13 @@ strcmp_null(const char *s1, const char *s2) static svn_error_t * open_wc_db(svn_sqlite__db_t **sdb, const char *wc_root_abspath, - const char *const *my_statements, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { SVN_ERR(svn_wc__db_util_open_db(sdb, wc_root_abspath, "wc.db", svn_sqlite__mode_readwrite, - FALSE /* exclusive */, my_statements, + FALSE /* exclusive */, 0 /* timeout */, + op_depth_statements, result_pool, scratch_pool)); return SVN_NO_ERROR; } @@ -111,11 +105,30 @@ typedef struct nodes_row_t { const char *props; /* comma-separated list of prop names */ } nodes_row_t; +/* Tree conflict details */ +typedef struct tree_conflict_info +{ + svn_wc_conflict_action_t action; + svn_wc_conflict_reason_t reason; + const char *delete_path; + svn_boolean_t conflicted_fb; /* fallback for reason, action and path 0 */ +} tree_conflict_info; + +/* What conflicts are on a path. */ +typedef struct conflict_info_t { + const char *local_relpath; + svn_boolean_t text_conflicted; + svn_boolean_t prop_conflicted; + + tree_conflict_info tc; +} conflict_info_t; + /* Macro for filling in the REPO_* fields of a non-base NODES_ROW_T * that has no copy-from info. */ #define NO_COPY_FROM SVN_INVALID_REVNUM, NULL, FALSE #define MOVED_HERE FALSE, NULL, TRUE #define NOT_MOVED FALSE, NULL, FALSE +#define FILE_EXTERNAL TRUE /* Return a comma-separated list of the prop names in PROPS, in lexically * ascending order, or NULL if PROPS is empty or NULL. (Here, we don't @@ -145,28 +158,36 @@ props_hash_to_text(apr_hash_t *props, apr_pool_t *pool) return str->len ? str->data : NULL; } -/* Return a human-readable string representing ROW. */ +/* Return a human-readable string representing ROW. With a tiny bit of editting + this can be used to create expected results */ static const char * print_row(const nodes_row_t *row, apr_pool_t *result_pool) { + const char *relpath_str, *presence_str; const char *file_external_str, *moved_here_str, *moved_to_str, *props; if (row == NULL) return "(null)"; + relpath_str = apr_psprintf(result_pool, "\"%s\",", row->local_relpath); + presence_str = apr_psprintf(result_pool, "\"%s\",", row->presence); if (row->moved_to) - moved_to_str = apr_psprintf(result_pool, ", moved-to %s", row->moved_to); + moved_to_str = apr_psprintf(result_pool, ", \"%s\"", row->moved_to); else moved_to_str = ""; - if (row->moved_here) - moved_here_str = ", moved-here"; + if (row->moved_here && !row->file_external && !row->moved_to) + moved_here_str = ", MOVED_HERE"; + else if (row->moved_to) + moved_here_str = ", TRUE"; else moved_here_str = ""; if (row->file_external) - file_external_str = ", file-external"; + file_external_str = ", FILE_EXTERNAL"; + else if (row->moved_to || row->props) + file_external_str = ", FALSE"; else file_external_str = ""; @@ -176,19 +197,17 @@ print_row(const nodes_row_t *row, props = ""; if (row->repo_revnum == SVN_INVALID_REVNUM) - return apr_psprintf(result_pool, "%d, \"%s\", \"%s\"%s%s%s%s", - row->op_depth, row->local_relpath, row->presence, - moved_here_str, moved_to_str, - file_external_str, props); + return apr_psprintf(result_pool, "%d, %-20s%-15s NO_COPY_FROM%s%s%s%s", + row->op_depth, relpath_str, presence_str, + file_external_str, moved_here_str, moved_to_str, + props); else - return apr_psprintf(result_pool, "%d, \"%s\", \"%s\", %s ^/%s@%d%s%s%s%s", - row->op_depth, row->local_relpath, row->presence, - row->op_depth == 0 ? "base" : "copyfrom", - row->repo_relpath, (int)row->repo_revnum, - moved_here_str, moved_to_str, - file_external_str, props); + return apr_psprintf(result_pool, "%d, %-20s%-15s %d, \"%s\"%s%s%s%s", + row->op_depth, relpath_str, presence_str, + (int)row->repo_revnum, row->repo_relpath, + file_external_str, moved_here_str, moved_to_str, + props); } - /* A baton to pass through svn_hash_diff() to compare_nodes_rows(). */ typedef struct comparison_baton_t { apr_hash_t *expected_hash; /* Maps "OP_DEPTH PATH" to nodes_row_t. */ @@ -259,20 +278,9 @@ check_db_rows(svn_test__sandbox_t *b, const char *root_path, const nodes_row_t *expected_rows) { - const char *base_relpath = root_path; svn_sqlite__db_t *sdb; int i; svn_sqlite__stmt_t *stmt; - static const char *const statements[] = { - "SELECT op_depth, nodes.presence, nodes.local_relpath, revision," - " repos_path, file_external, def_local_relpath, moved_to, moved_here," - " properties" - " FROM nodes " - " LEFT OUTER JOIN externals" - " ON nodes.local_relpath = externals.local_relpath" - " WHERE nodes.local_relpath = ?1 OR nodes.local_relpath LIKE ?2", - NULL }; -#define STMT_SELECT_NODES_INFO 0 svn_boolean_t have_row; apr_hash_t *found_hash = apr_hash_make(b->pool); @@ -285,12 +293,10 @@ check_db_rows(svn_test__sandbox_t *b, comparison_baton.errors = NULL; /* Fill ACTUAL_HASH with data from the WC DB. */ - SVN_ERR(open_wc_db(&sdb, b->wc_abspath, statements, b->pool, b->pool)); + 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, - (base_relpath[0] - ? apr_psprintf(b->pool, "%s/%%", base_relpath) - : "_%"))); + SVN_ERR(svn_sqlite__bindf(stmt, "is", (apr_int64_t)1 /* wc_id */, + root_path)); SVN_ERR(svn_sqlite__step(&have_row, stmt)); while (have_row) { @@ -304,16 +310,17 @@ check_db_rows(svn_test__sandbox_t *b, row->repo_revnum = svn_sqlite__column_revnum(stmt, 3); row->repo_relpath = svn_sqlite__column_text(stmt, 4, b->pool); row->file_external = !svn_sqlite__column_is_null(stmt, 5); - if (row->file_external && svn_sqlite__column_is_null(stmt, 6)) - comparison_baton.errors - = svn_error_createf(SVN_ERR_TEST_FAILED, comparison_baton.errors, - "incomplete {%s}", print_row(row, b->pool)); row->moved_to = svn_sqlite__column_text(stmt, 7, b->pool); row->moved_here = svn_sqlite__column_boolean(stmt, 8); SVN_ERR(svn_sqlite__column_properties(&props_hash, stmt, 9, b->pool, b->pool)); row->props = props_hash_to_text(props_hash, b->pool); + if (row->file_external && svn_sqlite__column_is_null(stmt, 6)) + comparison_baton.errors + = svn_error_createf(SVN_ERR_TEST_FAILED, comparison_baton.errors, + "incomplete {%s}", print_row(row, b->pool)); + key = apr_psprintf(b->pool, "%d %s", row->op_depth, row->local_relpath); apr_hash_set(found_hash, key, APR_HASH_KEY_STRING, row); @@ -338,6 +345,257 @@ check_db_rows(svn_test__sandbox_t *b, return comparison_baton.errors; } +#define EDIT_EDIT_TC {svn_wc_conflict_reason_edited, \ + svn_wc_conflict_action_edit, \ + NULL, TRUE} +#define NO_TC { 0 } +static const char * +print_conflict(const conflict_info_t *row, + apr_pool_t *result_pool) +{ + const char *tc_text; + + if (!row->tc.reason && !row->tc.action && !row->tc.delete_path) + { + if (row->tc.conflicted_fb) + tc_text = "EDIT_EDIT_TC"; + else + tc_text = "NO_TC"; + } + else + { + const char *action; + const char *reason; + const char *path; + +#define CASE_ENUM_STRVAL(x, y) case y: x = #y; break + switch(row->tc.action) + { + CASE_ENUM_STRVAL(action, svn_wc_conflict_action_edit); + CASE_ENUM_STRVAL(action, svn_wc_conflict_action_add); + CASE_ENUM_STRVAL(action, svn_wc_conflict_action_delete); + CASE_ENUM_STRVAL(action, svn_wc_conflict_action_replace); + default: + SVN_ERR_MALFUNCTION_NO_RETURN(); + } + switch(row->tc.reason) + { + CASE_ENUM_STRVAL(reason, svn_wc_conflict_reason_edited); + CASE_ENUM_STRVAL(reason, svn_wc_conflict_reason_obstructed); + CASE_ENUM_STRVAL(reason, svn_wc_conflict_reason_deleted); + CASE_ENUM_STRVAL(reason, svn_wc_conflict_reason_missing); + CASE_ENUM_STRVAL(reason, svn_wc_conflict_reason_unversioned); + CASE_ENUM_STRVAL(reason, svn_wc_conflict_reason_added); + CASE_ENUM_STRVAL(reason, svn_wc_conflict_reason_replaced); + CASE_ENUM_STRVAL(reason, svn_wc_conflict_reason_moved_away); + CASE_ENUM_STRVAL(reason, svn_wc_conflict_reason_moved_here); + default: + SVN_ERR_MALFUNCTION_NO_RETURN(); + } + + if (row->tc.delete_path) + path = apr_psprintf(result_pool, ", \"%s\"", row->tc.delete_path); + else + path = ""; + + tc_text = apr_psprintf(result_pool, "{%s, %s%s}", action, + reason, path); + } + + return apr_psprintf(result_pool, "\"%s\", %s, %s, %s", + row->local_relpath, + row->text_conflicted ? "TRUE" : "FALSE", + row->prop_conflicted ? "TRUE" : "FALSE", + tc_text); +} + +static svn_boolean_t +tree_conflicts_match(const tree_conflict_info *expected, + const tree_conflict_info *actual) +{ + if (expected->action != actual->action) + return FALSE; + else if (expected->reason != actual->reason) + return FALSE; + else if (strcmp_null(expected->delete_path, actual->delete_path) != 0) + return FALSE; + else if (expected->conflicted_fb != actual->conflicted_fb) + return FALSE; + + return TRUE; +} + +static svn_error_t * +compare_conflict_info(const void *key, apr_ssize_t klen, + enum svn_hash_diff_key_status status, + void *baton) +{ + comparison_baton_t *b = baton; + conflict_info_t *expected = apr_hash_get(b->expected_hash, key, klen); + conflict_info_t *found = apr_hash_get(b->found_hash, key, klen); + + if (! expected) + { + b->errors = svn_error_createf( + SVN_ERR_TEST_FAILED, b->errors, + "found {%s}", + print_conflict(found, b->scratch_pool)); + } + else if (! found) + { + b->errors = svn_error_createf( + SVN_ERR_TEST_FAILED, b->errors, + "expected {%s}", + print_conflict(expected, b->scratch_pool)); + } + else if (expected->text_conflicted != found->text_conflicted + || expected->prop_conflicted != found->prop_conflicted + || !tree_conflicts_match(&expected->tc, &found->tc)) + { + b->errors = svn_error_createf( + SVN_ERR_TEST_FAILED, b->errors, + "expected {%s}; found {%s}", + print_conflict(expected, b->scratch_pool), + print_conflict(found, b->scratch_pool)); + } + + /* Don't terminate the comparison: accumulate all differences. */ + return SVN_NO_ERROR; +} + +static svn_error_t * +check_db_conflicts(svn_test__sandbox_t *b, + const char *root_path, + const conflict_info_t *expected_conflicts) +{ + svn_sqlite__db_t *sdb; + int i; + svn_sqlite__stmt_t *stmt; + + svn_boolean_t have_row; + apr_hash_t *found_hash = apr_hash_make(b->pool); + apr_hash_t *expected_hash = apr_hash_make(b->pool); + apr_pool_t *iterpool = svn_pool_create(b->pool); + apr_hash_index_t *hi; + comparison_baton_t comparison_baton; + + comparison_baton.expected_hash = expected_hash; + comparison_baton.found_hash = found_hash; + comparison_baton.scratch_pool = b->pool; + comparison_baton.errors = NULL; + + /* Fill ACTUAL_HASH with data from the WC DB. */ + SVN_ERR(open_wc_db(&sdb, b->wc_abspath, b->pool, b->pool)); + SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_ACTUAL_INFO)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", (apr_int64_t)1 /* wc_id */, + root_path)); + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + while (have_row) + { + conflict_info_t *row = apr_pcalloc(b->pool, sizeof(*row)); + + row->local_relpath = svn_sqlite__column_text(stmt, 0, b->pool); + + svn_hash_sets(found_hash, row->local_relpath, row); + + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + } + SVN_ERR(svn_sqlite__reset(stmt)); + SVN_ERR(svn_sqlite__close(sdb)); + + for (hi = apr_hash_first(b->pool, found_hash); hi; hi = apr_hash_next(hi)) + { + svn_skel_t *conflict; + conflict_info_t *info = apr_hash_this_val(hi); + const char *local_abspath; + svn_boolean_t tree_conflicted; + + svn_pool_clear(iterpool); + + local_abspath = svn_dirent_join(b->wc_abspath, info->local_relpath, + iterpool); + + SVN_ERR(svn_wc__db_read_conflict(&conflict, NULL, NULL, + b->wc_ctx->db, local_abspath, + iterpool, iterpool)); + + SVN_TEST_ASSERT(conflict != NULL); + + SVN_ERR(svn_wc__conflict_read_info(NULL, NULL, + &info->text_conflicted, + &info->prop_conflicted, + &tree_conflicted, + b->wc_ctx->db, local_abspath, + conflict, + iterpool, iterpool)); + + if (tree_conflicted) + { + const char *move_src_abspath; + SVN_ERR(svn_wc__conflict_read_tree_conflict(&info->tc.reason, + &info->tc.action, + &move_src_abspath, + b->wc_ctx->db, + local_abspath, + conflict, + b->pool, iterpool)); + + if (move_src_abspath) + info->tc.delete_path = + svn_dirent_skip_ancestor(b->wc_abspath, move_src_abspath); + + if (!info->tc.reason + && !info->tc.action + && !info->tc.delete_path) + { + info->tc.conflicted_fb = TRUE; + } + } + } + + /* Fill EXPECTED_HASH with data from EXPECTED_ROWS. */ + if (expected_conflicts) + for (i = 0; expected_conflicts[i].local_relpath != NULL; i++) + { + const conflict_info_t *row = &expected_conflicts[i]; + + svn_hash_sets(expected_hash, row->local_relpath, row); + } + + /* Compare EXPECTED_HASH with ACTUAL_HASH and return any errors. */ + SVN_ERR(svn_hash_diff(expected_hash, found_hash, + compare_conflict_info, &comparison_baton, b->pool)); + return comparison_baton.errors; +} + +static svn_error_t * +verify_db_callback(void *baton, + const char *wc_abspath, + const char *local_relpath, + int op_depth, + int id, + const char *msg, + apr_pool_t *scratch_pool) +{ + if (op_depth >= 0) + return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL, + "Verify: %s: %s (%d): SV%04d %s", + wc_abspath, local_relpath, op_depth, id, msg); + else + return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL, + "DB-VRFY: %s: %s: SV%04d %s", + wc_abspath, local_relpath, id, msg); +} + +static svn_error_t * +verify_db(svn_test__sandbox_t *b) +{ + SVN_ERR(svn_wc__db_verify_db_full(b->wc_ctx->db, b->wc_abspath, + verify_db_callback, NULL, b->pool)); + + return SVN_NO_ERROR; +} + /* ---------------------------------------------------------------------- */ /* The test functions */ @@ -374,7 +632,7 @@ wc_wc_copies(svn_test__sandbox_t *b) /* Create the various kinds of source node which will be copied */ - sbox_file_write(b, source_added_file, "New file"); + SVN_ERR(sbox_file_write(b, source_added_file, "New file")); SVN_ERR(sbox_wc_add(b, source_added_file)); SVN_ERR(sbox_wc_mkdir(b, source_added_dir)); SVN_ERR(sbox_wc_mkdir(b, source_added_dir2)); @@ -578,7 +836,7 @@ repo_wc_copies(svn_test__sandbox_t *b) } /* Perform each copy. */ - SVN_ERR(svn_client_create_context(&ctx, b->pool)); + SVN_ERR(svn_test__create_client_ctx(&ctx, b, b->pool)); for (subtest = subtests; subtest->from_path; subtest++) { svn_opt_revision_t rev = { svn_opt_revision_number, { 1 } }; @@ -647,7 +905,7 @@ test_deletes(const svn_test_opts_t *opts, apr_pool_t *pool) SVN_ERR(svn_test__sandbox_create(&b, "deletes", opts, pool)); SVN_ERR(sbox_add_and_commit_greek_tree(&b)); - sbox_file_write(&b, "A/B/E/new-file", "New file"); + SVN_ERR(sbox_file_write(&b, "A/B/E/new-file", "New file")); SVN_ERR(sbox_wc_add(&b, "A/B/E/new-file")); { nodes_row_t rows[] = { @@ -709,7 +967,7 @@ test_adds(const svn_test_opts_t *opts, apr_pool_t *pool) SVN_ERR(sbox_add_and_commit_greek_tree(&b)); /* add file */ - sbox_file_write(&b, "new-file", "New file"); + SVN_ERR(sbox_file_write(&b, "new-file", "New file")); SVN_ERR(sbox_wc_add(&b, "new-file")); { nodes_row_t rows[] = { @@ -731,7 +989,7 @@ test_adds(const svn_test_opts_t *opts, apr_pool_t *pool) /* replace file */ SVN_ERR(sbox_wc_delete(&b, "iota")); - sbox_file_write(&b, "iota", "New iota file"); + SVN_ERR(sbox_file_write(&b, "iota", "New iota file")); SVN_ERR(sbox_wc_add(&b, "iota")); { nodes_row_t rows[] = { @@ -766,12 +1024,12 @@ test_adds_change_kind(const svn_test_opts_t *opts, apr_pool_t *pool) { svn_test__sandbox_t b; - SVN_ERR(svn_test__sandbox_create(&b, "adds", opts, pool)); + SVN_ERR(svn_test__sandbox_create(&b, "test_adds_change_kind", opts, pool)); SVN_ERR(sbox_add_and_commit_greek_tree(&b)); /* replace dir with file */ SVN_ERR(sbox_wc_delete(&b, "A/B/E")); - sbox_file_write(&b, "A/B/E", "New E file"); + SVN_ERR(sbox_file_write(&b, "A/B/E", "New E file")); SVN_ERR(sbox_wc_add(&b, "A/B/E")); { nodes_row_t rows[] = { @@ -1024,47 +1282,53 @@ insert_dirs(svn_test__sandbox_t *b, { svn_sqlite__db_t *sdb; svn_sqlite__stmt_t *stmt; - static 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(open_wc_db(&sdb, b->wc_abspath, statements, b->pool, b->pool)); + SVN_ERR(open_wc_db(&sdb, b->wc_abspath, b->pool, b->pool)); - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, 0)); + SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_DELETE_NODES)); SVN_ERR(svn_sqlite__step_done(stmt)); while(nodes->local_relpath) { - if (nodes->local_relpath[0]) + SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_INSERT_NODE)); + SVN_ERR(svn_sqlite__bindf(stmt, "sdssrs", + nodes->local_relpath, + nodes->op_depth, + nodes->presence, + nodes->repo_relpath, + nodes->repo_revnum, + nodes->local_relpath[0] + ? svn_relpath_dirname(nodes->local_relpath, + b->pool) + : NULL)); + + if (nodes->moved_to) + SVN_ERR(svn_sqlite__bind_text(stmt, 7, nodes->moved_to)); + if (nodes->moved_here) + SVN_ERR(svn_sqlite__bind_int(stmt, 8, 1)); + if (nodes->props) { - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, 2)); - SVN_ERR(svn_sqlite__bindf(stmt, "sdssrs", - nodes->local_relpath, - nodes->op_depth, - nodes->presence, - nodes->repo_relpath, - nodes->repo_revnum, - svn_relpath_dirname(nodes->local_relpath, - b->pool))); + int i; + apr_hash_t *props = apr_hash_make(b->pool); + apr_array_header_t *names = svn_cstring_split(nodes->props, ",", + TRUE, b->pool); + + for (i = 0; i < names->nelts; i++) + { + const char *name = APR_ARRAY_IDX(names, i, const char *); + svn_hash_sets(props, name, svn_string_create(name, b->pool)); + } + + SVN_ERR(svn_sqlite__bind_properties(stmt, 9, props, b->pool)); } - else + else if (nodes->repo_relpath + && strcmp(nodes->presence, "normal") == 0) { - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, 1)); - SVN_ERR(svn_sqlite__bindf(stmt, "sdssr", - nodes->local_relpath, - nodes->op_depth, - nodes->presence, - nodes->repo_relpath, - nodes->repo_revnum)); + SVN_ERR(svn_sqlite__bind_text(stmt, 9, "()")); } + /* File externals? */ + SVN_ERR(svn_sqlite__step_done(stmt)); ++nodes; } @@ -1102,7 +1366,7 @@ base_dir_insert_remove(svn_test__sandbox_t *b, "not-even-a-uuid", revision, apr_hash_make(b->pool), revision, 0, NULL, NULL, svn_depth_infinity, - NULL, NULL, FALSE, NULL, NULL, NULL, + NULL, FALSE, NULL, NULL, NULL, NULL, b->pool)); after = apr_palloc(b->pool, sizeof(*after) * (apr_size_t)(num_before + num_added + 1)); @@ -1115,9 +1379,7 @@ base_dir_insert_remove(svn_test__sandbox_t *b, SVN_ERR(check_db_rows(b, "", after)); SVN_ERR(svn_wc__db_base_remove(b->wc_ctx->db, dir_abspath, - FALSE /* keep_as_Working */, - FALSE /* queue_deletes */, - FALSE /* remove_locks */, + FALSE, FALSE, FALSE, SVN_INVALID_REVNUM, NULL, NULL, b->pool)); SVN_ERR(svn_wc__wq_run(b->wc_ctx->db, dir_abspath, @@ -1427,29 +1689,11 @@ test_base_dir_insert_remove(const svn_test_opts_t *opts, apr_pool_t *pool) } static svn_error_t * -temp_op_make_copy(svn_test__sandbox_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_op_make_copy(b->wc_ctx->db, dir_abspath, NULL, NULL, 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) +test_db_make_copy(const svn_test_opts_t *opts, apr_pool_t *pool) { svn_test__sandbox_t b; - SVN_ERR(svn_test__sandbox_create(&b, "temp_op_make_copy", opts, pool)); + SVN_ERR(svn_test__sandbox_create(&b, "make_copy", opts, pool)); { /* / norm - @@ -1480,7 +1724,7 @@ test_temp_op_make_copy(const svn_test_opts_t *opts, apr_pool_t *pool) { 2, "A/F", "normal", 1, "S2" }, { 2, "A/F/G", "normal", 1, "S2/G" }, { 2, "A/F/H", "not-present", 1, "S2/H" }, - { 2, "A/F/E", "base-deleted", 2, "A/F/E" }, + { 2, "A/F/E", "base-deleted", NO_COPY_FROM }, { 0 } }; /* / norm - @@ -1518,14 +1762,18 @@ test_temp_op_make_copy(const svn_test_opts_t *opts, apr_pool_t *pool) { 2, "A/B", "normal", NO_COPY_FROM }, { 2, "A/B/C", "base-deleted", NO_COPY_FROM }, { 2, "A/F", "normal", 1, "S2" }, - { 2, "A/F/E", "base-deleted", 2, "A/F/E" }, + { 2, "A/F/E", "base-deleted", NO_COPY_FROM }, { 2, "A/F/G", "normal", 1, "S2/G" }, { 2, "A/F/H", "not-present", 1, "S2/H" }, { 3, "A/B/C", "normal", NO_COPY_FROM }, { 0 } }; - SVN_ERR(temp_op_make_copy(&b, "A", before, after)); + SVN_ERR(insert_dirs(&b, before)); + SVN_ERR(svn_wc__db_op_make_copy(b.wc_ctx->db, sbox_wc_path(&b, "A"), + NULL, NULL, pool)); + + SVN_ERR(check_db_rows(&b, "", after)); } return SVN_NO_ERROR; @@ -1821,46 +2069,32 @@ insert_actual(svn_test__sandbox_t *b, { svn_sqlite__db_t *sdb; svn_sqlite__stmt_t *stmt; - static const char * const statements[] = { - "DELETE FROM actual_node;", - "INSERT INTO actual_node (local_relpath, changelist, wc_id)" - " VALUES (?1, ?2, 1)", - "INSERT INTO actual_node (local_relpath, parent_relpath, changelist, wc_id)" - " VALUES (?1, ?2, ?3, 1)", - "UPDATE nodes SET kind = 'file' WHERE wc_id = 1 and local_relpath = ?1", - NULL, - }; if (!actual) return SVN_NO_ERROR; - SVN_ERR(open_wc_db(&sdb, b->wc_abspath, statements, b->pool, b->pool)); + SVN_ERR(open_wc_db(&sdb, b->wc_abspath, b->pool, b->pool)); - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, 0)); + SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_DELETE_ACTUAL)); SVN_ERR(svn_sqlite__step_done(stmt)); while(actual->local_relpath) { - if (actual->local_relpath[0]) - { - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, 2)); - SVN_ERR(svn_sqlite__bindf(stmt, "sss", - actual->local_relpath, - svn_relpath_dirname(actual->local_relpath, - b->pool), - actual->changelist)); - } - else - { - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, 1)); - SVN_ERR(svn_sqlite__bindf(stmt, "ss", - actual->local_relpath, - actual->changelist)); - } + SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_INSERT_ACTUAL)); + SVN_ERR(svn_sqlite__bindf(stmt, "sss", + actual->local_relpath, + actual->local_relpath[0] + ? svn_relpath_dirname(actual->local_relpath, + b->pool) + : NULL, + actual->changelist)); SVN_ERR(svn_sqlite__step_done(stmt)); if (actual->changelist) { - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, 3)); + SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, + STMT_ENSURE_EMPTY_PRISTINE)); + SVN_ERR(svn_sqlite__step_done(stmt)); + SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_NODES_SET_FILE)); SVN_ERR(svn_sqlite__bindf(stmt, "s", actual->local_relpath)); SVN_ERR(svn_sqlite__step_done(stmt)); } @@ -1876,10 +2110,6 @@ check_db_actual(svn_test__sandbox_t* b, actual_row_t *rows) { svn_sqlite__db_t *sdb; svn_sqlite__stmt_t *stmt; - static const char * const statements[] = { - "SELECT local_relpath FROM actual_node WHERE wc_id = 1;", - NULL, - }; svn_boolean_t have_row; apr_hash_t *path_hash = apr_hash_make(b->pool); @@ -1893,15 +2123,15 @@ check_db_actual(svn_test__sandbox_t* b, actual_row_t *rows) ++rows; } - SVN_ERR(open_wc_db(&sdb, b->wc_abspath, statements, b->pool, b->pool)); + SVN_ERR(open_wc_db(&sdb, b->wc_abspath, b->pool, b->pool)); - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, 0)); + SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_ALL_ACTUAL)); SVN_ERR(svn_sqlite__step(&have_row, stmt)); while (have_row) { const char *local_relpath = svn_sqlite__column_text(stmt, 0, b->pool); if (!apr_hash_get(path_hash, local_relpath, APR_HASH_KEY_STRING)) - return svn_error_createf(SVN_ERR_TEST_FAILED, svn_sqlite__close(sdb), + return svn_error_createf(SVN_ERR_TEST_FAILED, svn_sqlite__reset(stmt), "actual '%s' unexpected", local_relpath); apr_hash_set(path_hash, local_relpath, APR_HASH_KEY_STRING, NULL); SVN_ERR(svn_sqlite__step(&have_row, stmt)); @@ -1910,8 +2140,8 @@ check_db_actual(svn_test__sandbox_t* b, actual_row_t *rows) if (apr_hash_count(path_hash)) { const char *local_relpath - = svn__apr_hash_index_key(apr_hash_first(b->pool, path_hash)); - return svn_error_createf(SVN_ERR_TEST_FAILED, svn_sqlite__close(sdb), + = apr_hash_this_key(apr_hash_first(b->pool, path_hash)); + return svn_error_createf(SVN_ERR_TEST_FAILED, svn_sqlite__reset(stmt), "actual '%s' expected", local_relpath); } @@ -1943,7 +2173,7 @@ revert(svn_test__sandbox_t *b, SVN_ERR(insert_actual(b, before_actual)); SVN_ERR(check_db_rows(b, "", before_nodes)); SVN_ERR(check_db_actual(b, before_actual)); - err = svn_wc__db_op_revert(b->wc_ctx->db, local_abspath, depth, + err = svn_wc__db_op_revert(b->wc_ctx->db, local_abspath, depth, FALSE, b->pool, b->pool); if (err) { @@ -2511,7 +2741,7 @@ check_hash_keys(apr_hash_t *hash, for (hi = apr_hash_first(scratch_pool, hash); hi; hi = apr_hash_next(hi)) { - const char *name = svn__apr_hash_index_key(hi); + const char *name = apr_hash_this_key(hi); err = svn_error_compose_create( err, svn_error_createf(SVN_ERR_TEST_FAILED, NULL, _("Found, not expected: '%s'"), name)); @@ -2613,8 +2843,8 @@ test_children_of_replaced_dir(const svn_test_opts_t *opts, apr_pool_t *pool) &children_array, b.wc_ctx->db, A_abspath, pool, pool)); SVN_ERR(CHECK_ARRAY(children_array, working_children_inc_hidden, pool)); - SVN_ERR(svn_wc__node_get_children(&children_array, b.wc_ctx, A_abspath, - TRUE /* show_hidden */, pool, pool)); + SVN_ERR(svn_wc__db_read_children(&children_array, b.wc_ctx->db, A_abspath, + pool, pool)); SVN_ERR(CHECK_ARRAY(children_array, all_children_inc_hidden, pool)); /* I am not testing svn_wc__node_get_children(show_hidden=FALSE) because @@ -2623,17 +2853,14 @@ test_children_of_replaced_dir(const svn_test_opts_t *opts, apr_pool_t *pool) * a 'hidden' child of the working dir (so should be excluded). */ SVN_ERR(svn_wc__node_get_children_of_working_node( - &children_array, b.wc_ctx, A_abspath, TRUE /* show_hidden */, - pool, pool)); - SVN_ERR(CHECK_ARRAY(children_array, working_children_inc_hidden, pool)); - - SVN_ERR(svn_wc__node_get_children_of_working_node( - &children_array, b.wc_ctx, A_abspath, FALSE /* show_hidden */, + &children_array, b.wc_ctx, A_abspath, pool, pool)); SVN_ERR(CHECK_ARRAY(children_array, working_children_exc_hidden, pool)); SVN_ERR(svn_wc__db_read_children_info(&children_hash, &conflicts_hash, - b.wc_ctx->db, A_abspath, pool, pool)); + b.wc_ctx->db, A_abspath, + FALSE /* base_tree_only */, + pool, pool)); SVN_ERR(CHECK_HASH(children_hash, all_children_inc_hidden, pool)); /* We don't yet have a svn_wc__db_read_children_info2() to test. */ @@ -2970,7 +3197,7 @@ test_shadowed_update(const svn_test_opts_t *opts, apr_pool_t *pool) SVN_ERR(svn_test__sandbox_create(&b, "shadowed_update", opts, pool)); /* Set up the base state as revision 1. */ - sbox_file_write(&b, "iota", "This is iota"); + SVN_ERR(sbox_file_write(&b, "iota", "This is iota")); SVN_ERR(sbox_wc_add(&b, "iota")); SVN_ERR(sbox_wc_commit(&b, "")); @@ -2985,7 +3212,7 @@ test_shadowed_update(const svn_test_opts_t *opts, apr_pool_t *pool) SVN_ERR(sbox_wc_commit(&b, "")); /* And change something in r3 */ - sbox_file_write(&b, "iota", "This is a new iota"); + SVN_ERR(sbox_file_write(&b, "iota", "This is a new iota")); SVN_ERR(sbox_wc_commit(&b, "")); /* And delete C & M */ @@ -3306,12 +3533,12 @@ commit_file_external(const svn_test_opts_t *opts, apr_pool_t *pool) svn_test__sandbox_t b; SVN_ERR(svn_test__sandbox_create(&b, "commit_file_external", opts, pool)); - sbox_file_write(&b, "f", "this is f\n"); + SVN_ERR(sbox_file_write(&b, "f", "this is f\n")); SVN_ERR(sbox_wc_add(&b, "f")); SVN_ERR(sbox_wc_propset(&b, "svn:externals", "^/f g", "")); SVN_ERR(sbox_wc_commit(&b, "")); SVN_ERR(sbox_wc_update(&b, "", 1)); - sbox_file_write(&b, "g", "this is f\nmodified via g\n"); + SVN_ERR(sbox_file_write(&b, "g", "this is f\nmodified via g\n")); SVN_ERR(sbox_wc_commit(&b, "")); SVN_ERR(sbox_wc_update(&b, "", 2)); @@ -3334,7 +3561,7 @@ revert_file_externals(const svn_test_opts_t *opts, apr_pool_t *pool) svn_test__sandbox_t b; SVN_ERR(svn_test__sandbox_create(&b, "revert_file_externals", opts, pool)); - sbox_file_write(&b, "f", "this is f\n"); + SVN_ERR(sbox_file_write(&b, "f", "this is f\n")); SVN_ERR(sbox_wc_add(&b, "f")); SVN_ERR(sbox_wc_propset(&b, "svn:externals", "^/f g", "")); SVN_ERR(sbox_wc_commit(&b, "")); @@ -3356,11 +3583,13 @@ revert_file_externals(const svn_test_opts_t *opts, apr_pool_t *pool) SVN_ERR(sbox_wc_update(&b, "", 1)); { nodes_row_t rows[] = { - { 0, "", "normal", 1, "" }, - { 0, "f", "normal", 1, "f" }, - { 1, "A", "normal", NO_COPY_FROM }, - { 0, "h", "normal", 1, "f", TRUE }, - { 0, "A/g", "normal", 1, "f", TRUE }, + { 0, "", "normal", 1, "" }, + { 0, "f", "normal", 1, "f" }, + { 1, "A", "normal", NO_COPY_FROM }, + { 0, "h", "normal", 1, "f", TRUE }, + { 0, "A/g", "normal", 1, "f", TRUE }, + + { 0, "g", "not-present", 0, "g"}, { 0 } }; SVN_ERR(check_db_rows(&b, "", rows)); @@ -3369,10 +3598,12 @@ revert_file_externals(const svn_test_opts_t *opts, apr_pool_t *pool) SVN_ERR(sbox_wc_revert(&b, "", svn_depth_infinity)); { nodes_row_t rows[] = { - { 0, "", "normal", 1, "" }, - { 0, "f", "normal", 1, "f" }, - { 0, "h", "normal", 1, "f", TRUE }, - { 0, "A/g", "normal", 1, "f", TRUE }, + { 0, "", "normal", 1, "" }, + { 0, "f", "normal", 1, "f" }, + { 0, "h", "normal", 1, "f", TRUE }, + { 0, "A/g", "normal", 1, "f", TRUE }, + + { 0, "g", "not-present", 0, "g"}, { 0 } }; SVN_ERR(check_db_rows(&b, "", rows)); @@ -3381,9 +3612,11 @@ revert_file_externals(const svn_test_opts_t *opts, apr_pool_t *pool) SVN_ERR(sbox_wc_update(&b, "", 1)); { nodes_row_t rows[] = { - { 0, "", "normal", 1, "" }, - { 0, "f", "normal", 1, "f" }, - { 0, "g", "normal", 1, "f", TRUE }, + { 0, "", "normal", 1, "" }, + { 0, "f", "normal", 1, "f" }, + { 0, "g", "normal", 1, "f", TRUE }, + + { 0, "h", "not-present", 0, "h"}, { 0 } }; SVN_ERR(check_db_rows(&b, "", rows)); @@ -3398,7 +3631,7 @@ copy_file_externals(const svn_test_opts_t *opts, apr_pool_t *pool) svn_test__sandbox_t b; SVN_ERR(svn_test__sandbox_create(&b, "copy_file_externals", opts, pool)); - sbox_file_write(&b, "f", "this is f\n"); + SVN_ERR(sbox_file_write(&b, "f", "this is f\n")); SVN_ERR(sbox_wc_add(&b, "f")); SVN_ERR(sbox_wc_mkdir(&b, "A")); SVN_ERR(sbox_wc_propset(&b, "svn:externals", "^/f g", "A")); @@ -3560,6 +3793,8 @@ incomplete_switch(const svn_test_opts_t *opts, apr_pool_t *pool) }; SVN_ERR(insert_dirs(&b, before)); + SVN_ERR(svn_io_remove_dir2(sbox_wc_path(&b, "A/B/C/D"), FALSE, + NULL, NULL, pool)); SVN_ERR(check_db_rows(&b, "", before)); SVN_ERR(sbox_wc_update(&b, "", 4)); SVN_ERR(check_db_rows(&b, "", after_update)); @@ -4430,27 +4665,27 @@ move_update(const svn_test_opts_t *opts, apr_pool_t *pool) /* r1: Create files 'f', 'h' */ SVN_ERR(sbox_wc_mkdir(&b, "A")); SVN_ERR(sbox_wc_mkdir(&b, "A/B")); - sbox_file_write(&b, "A/B/f", "r1 content\n"); - sbox_file_write(&b, "A/B/h", "r1 content\n"); + SVN_ERR(sbox_file_write(&b, "A/B/f", "r1 content\n")); + SVN_ERR(sbox_file_write(&b, "A/B/h", "r1 content\n")); SVN_ERR(sbox_wc_add(&b, "A/B/f")); SVN_ERR(sbox_wc_add(&b, "A/B/h")); SVN_ERR(sbox_wc_commit(&b, "")); /* r2: Modify 'f' */ - sbox_file_write(&b, "A/B/f", "r1 content\nr2 content\n"); + SVN_ERR(sbox_file_write(&b, "A/B/f", "r1 content\nr2 content\n")); SVN_ERR(sbox_wc_commit(&b, "")); /* r3: Delete 'h', add 'g' */ - sbox_file_write(&b, "A/B/g", "r3 content\n"); + SVN_ERR(sbox_file_write(&b, "A/B/g", "r3 content\n")); SVN_ERR(sbox_wc_add(&b, "A/B/g")); SVN_ERR(sbox_wc_delete(&b, "A/B/h")); SVN_ERR(sbox_wc_commit(&b, "")); /* r4: Add a new subtree 'X' */ SVN_ERR(sbox_wc_mkdir(&b, "X")); - sbox_file_write(&b, "X/f", "r4 content\n"); - sbox_file_write(&b, "X/g", "r4 content\n"); - sbox_file_write(&b, "X/h", "r4 content\n"); + SVN_ERR(sbox_file_write(&b, "X/f", "r4 content\n")); + SVN_ERR(sbox_file_write(&b, "X/g", "r4 content\n")); + SVN_ERR(sbox_file_write(&b, "X/h", "r4 content\n")); SVN_ERR(sbox_wc_add(&b, "X/f")); SVN_ERR(sbox_wc_add(&b, "X/g")); SVN_ERR(sbox_wc_add(&b, "X/h")); @@ -5031,8 +5266,10 @@ mixed_rev_move(const svn_test_opts_t *opts, apr_pool_t *pool) SVN_ERR(sbox_wc_mkdir(&b, "A")); SVN_ERR(sbox_wc_commit(&b, "")); SVN_ERR(sbox_wc_mkdir(&b, "A/B")); + SVN_ERR(sbox_wc_mkdir(&b, "A/D")); SVN_ERR(sbox_wc_commit(&b, "")); SVN_ERR(sbox_wc_mkdir(&b, "A/B/C")); + SVN_ERR(sbox_wc_mkdir(&b, "A/D/E")); SVN_ERR(sbox_wc_commit(&b, "")); { @@ -5041,6 +5278,8 @@ mixed_rev_move(const svn_test_opts_t *opts, apr_pool_t *pool) {0, "A", "normal", 1, "A"}, {0, "A/B", "normal", 2, "A/B"}, {0, "A/B/C", "normal", 3, "A/B/C"}, + {0, "A/D", "normal", 2, "A/D"}, + {0, "A/D/E", "normal", 3, "A/D/E"}, {0} }; SVN_ERR(check_db_rows(&b, "", nodes)); @@ -5060,20 +5299,30 @@ mixed_rev_move(const svn_test_opts_t *opts, apr_pool_t *pool) {0, "A", "normal", 1, "A"}, {0, "A/B", "normal", 2, "A/B"}, {0, "A/B/C", "normal", 3, "A/B/C"}, + {0, "A/D", "normal", 2, "A/D"}, + {0, "A/D/E", "normal", 3, "A/D/E"}, {1, "A", "base-deleted", NO_COPY_FROM, "X"}, {1, "A/B", "base-deleted", NO_COPY_FROM}, {1, "A/B/C", "base-deleted", NO_COPY_FROM}, + {1, "A/D", "base-deleted", NO_COPY_FROM}, + {1, "A/D/E", "base-deleted", NO_COPY_FROM}, {1, "X", "normal", 1, "A", MOVED_HERE}, {1, "X/B", "not-present", 2, "A/B"}, + {1, "X/D", "not-present", 2, "A/D"}, {2, "X/B", "normal", 2, "A/B"}, {2, "X/B/C", "not-present", 3, "A/B/C"}, + {2, "X/D", "normal", 2, "A/D"}, + {2, "X/D/E", "not-present", 3, "A/D/E"}, {3, "X/B/C", "normal", 3, "A/B/C"}, + {3, "X/D/E", "normal", 3, "A/D/E"}, + {0} }; SVN_ERR(check_db_rows(&b, "", nodes)); } /* ### These values PASS but I'm not sure they are correct. */ + /* A/B/C doesn't exist as X/B/C at op depth 1, but is reported */ SVN_ERR(svn_wc__db_follow_moved_to(&moved_tos, b.wc_ctx->db, sbox_wc_path(&b, "A/B/C"), pool, pool)); SVN_ERR(check_moved_to(moved_tos, 0, 1, "X/B/C")); @@ -5099,32 +5348,109 @@ mixed_rev_move(const svn_test_opts_t *opts, apr_pool_t *pool) {0, "A", "normal", 1, "A"}, {0, "A/B", "normal", 2, "A/B"}, {0, "A/B/C", "normal", 3, "A/B/C"}, + {0, "A/D", "normal", 2, "A/D"}, + {0, "A/D/E", "normal", 3, "A/D/E"}, {1, "A", "base-deleted", NO_COPY_FROM, "X"}, {1, "A/B", "base-deleted", NO_COPY_FROM}, {1, "A/B/C", "base-deleted", NO_COPY_FROM}, + {1, "A/D", "base-deleted", NO_COPY_FROM}, + {1, "A/D/E", "base-deleted", NO_COPY_FROM}, {1, "X", "normal", 1, "A", MOVED_HERE}, {1, "X/B", "not-present", 2, "A/B"}, + {1, "X/D", "not-present", 2, "A/D"}, + {2, "X/D", "normal", 2, "A/D"}, + {2, "X/D/E", "not-present", 3, "A/D/E"}, {2, "X/Y", "normal", 2, "A/B"}, {2, "X/Y/C", "not-present", NO_COPY_FROM}, {3, "X/Y/C", "normal", 3, "A/B/C"}, + {3, "X/D/E", "normal", 3, "A/D/E"}, + {0} }; SVN_ERR(check_db_rows(&b, "", nodes)); } + /* A/B/C still doesn't exist as X/B/C at op depth 1 */ SVN_ERR(svn_wc__db_follow_moved_to(&moved_tos, b.wc_ctx->db, sbox_wc_path(&b, "A/B/C"), pool, pool)); - SVN_TEST_ASSERT(moved_tos->nelts == 0); + SVN_ERR(check_moved_to(moved_tos, 0, 1, "X/B/C")); + SVN_TEST_ASSERT(moved_tos->nelts == 1); + /* A/B doesn't exist exist as X/B and the move to Y can't be tracked in + the current scheme */ SVN_ERR(svn_wc__db_follow_moved_to(&moved_tos, b.wc_ctx->db, sbox_wc_path(&b, "A/B"), pool, pool)); - SVN_TEST_ASSERT(moved_tos->nelts == 0); + SVN_ERR(check_moved_to(moved_tos, 0, 1, "X/B")); + SVN_TEST_ASSERT(moved_tos->nelts == 1); + + SVN_ERR(svn_wc__db_follow_moved_to(&moved_tos, b.wc_ctx->db, + sbox_wc_path(&b, "A"), pool, pool)); + SVN_ERR(check_moved_to(moved_tos, 0, 1, "X")); + SVN_TEST_ASSERT(moved_tos->nelts == 1); + + + SVN_ERR(sbox_wc_mkdir(&b, "Z")); + SVN_ERR(sbox_wc_commit(&b, "Z")); /* r4 */ + + SVN_ERR(sbox_wc_update(&b, "", 4)); + + { + nodes_row_t nodes[] = { + {0, "", "normal", 4, ""}, + {0, "A", "normal", 4, "A"}, + {0, "A/B", "normal", 4, "A/B"}, + {0, "A/B/C", "normal", 4, "A/B/C"}, + {0, "A/D", "normal", 4, "A/D"}, + {0, "A/D/E", "normal", 4, "A/D/E"}, + {1, "A", "base-deleted", NO_COPY_FROM, "X"}, + {1, "A/B", "base-deleted", NO_COPY_FROM}, + {1, "A/B/C", "base-deleted", NO_COPY_FROM}, + {1, "A/D", "base-deleted", NO_COPY_FROM}, + {1, "A/D/E", "base-deleted", NO_COPY_FROM}, + /* X is expanded on update. The not-present nodes are now here */ + {1, "X", "normal", 4, "A", MOVED_HERE}, + {1, "X/B", "normal", 4, "A/B", MOVED_HERE}, + {1, "X/B/C", "normal", 4, "A/B/C", MOVED_HERE}, + {1, "X/D", "normal", 4, "A/D", MOVED_HERE}, + {1, "X/D/E", "normal", 4, "A/D/E", MOVED_HERE}, + {2, "X/D", "normal", 2, "A/D"}, + {2, "X/D/E", "not-present", 3, "A/D/E"}, + {2, "X/Y", "normal", 2, "A/B"}, + {2, "X/Y/C", "not-present", NO_COPY_FROM}, + {3, "X/D/E", "normal", 3, "A/D/E"}, + {3, "X/Y/C", "normal", 3, "A/B/C"}, + + {0, "Z", "normal", 4, "Z"}, + {0} + }; + + SVN_ERR(check_db_rows(&b, "", nodes)); + } + + SVN_ERR(svn_wc__db_follow_moved_to(&moved_tos, b.wc_ctx->db, + sbox_wc_path(&b, "A/B/C"), pool, pool)); + SVN_ERR(check_moved_to(moved_tos, 0, 1, "X/B/C")); + SVN_TEST_ASSERT(moved_tos->nelts == 1); + + SVN_ERR(svn_wc__db_follow_moved_to(&moved_tos, b.wc_ctx->db, + sbox_wc_path(&b, "A/B"), pool, pool)); + SVN_ERR(check_moved_to(moved_tos, 0, 1, "X/B")); + SVN_TEST_ASSERT(moved_tos->nelts == 1); SVN_ERR(svn_wc__db_follow_moved_to(&moved_tos, b.wc_ctx->db, sbox_wc_path(&b, "A"), pool, pool)); SVN_ERR(check_moved_to(moved_tos, 0, 1, "X")); SVN_TEST_ASSERT(moved_tos->nelts == 1); + { + conflict_info_t conflicts[] = { + { "X/D", FALSE, FALSE, {0 /* ### Needs fixing */} }, + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } + return SVN_NO_ERROR; } @@ -5140,8 +5466,8 @@ update_prop_mod_into_moved(const svn_test_opts_t *opts, apr_pool_t *pool) /* r1: Create files 'f', 'h' */ SVN_ERR(sbox_wc_mkdir(&b, "A")); SVN_ERR(sbox_wc_mkdir(&b, "A/B")); - sbox_file_write(&b, "A/B/f", "r1 content\n"); - sbox_file_write(&b, "A/B/h", "r1 content\n"); + SVN_ERR(sbox_file_write(&b, "A/B/f", "r1 content\n")); + SVN_ERR(sbox_file_write(&b, "A/B/h", "r1 content\n")); SVN_ERR(sbox_wc_add(&b, "A/B/f")); SVN_ERR(sbox_wc_add(&b, "A/B/h")); SVN_ERR(sbox_wc_propset(&b, "pd", "f1", "A/B/f")); @@ -5152,14 +5478,14 @@ update_prop_mod_into_moved(const svn_test_opts_t *opts, apr_pool_t *pool) /* r2: Modify 'f'. Delete prop 'pd', modify prop 'pm', add prop 'pa', * leave prop 'pn' unchanged. */ - sbox_file_write(&b, "A/B/f", "r1 content\nr2 content\n"); + SVN_ERR(sbox_file_write(&b, "A/B/f", "r1 content\nr2 content\n")); SVN_ERR(sbox_wc_propset(&b, "pd", NULL, "A/B/f")); SVN_ERR(sbox_wc_propset(&b, "pm", "f2", "A/B/f")); SVN_ERR(sbox_wc_propset(&b, "pa", "f2", "A/B/f")); SVN_ERR(sbox_wc_commit(&b, "")); /* r3: Delete 'h', add 'g' */ - sbox_file_write(&b, "A/B/g", "r3 content\n"); + SVN_ERR(sbox_file_write(&b, "A/B/g", "r3 content\n")); SVN_ERR(sbox_wc_add(&b, "A/B/g")); SVN_ERR(sbox_wc_propset(&b, "p", "g3", "A/B/g")); SVN_ERR(sbox_wc_delete(&b, "A/B/h")); @@ -5222,9 +5548,22 @@ update_prop_mod_into_moved(const svn_test_opts_t *opts, apr_pool_t *pool) SVN_ERR(check_db_rows(&b, "", nodes)); } + { + conflict_info_t conflicts[] = { + { "A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "A"}}, + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } + /* Resolve should update the move. */ SVN_ERR(sbox_wc_resolve(&b, "A", svn_depth_empty, svn_wc_conflict_choose_mine_conflict)); + + SVN_ERR(check_db_conflicts(&b, "", NULL)); + { nodes_row_t nodes[] = { {0, "", "normal", 2, ""}, @@ -5259,12 +5598,12 @@ nested_move_update(const svn_test_opts_t *opts, apr_pool_t *pool) SVN_ERR(sbox_wc_mkdir(&b, "A")); SVN_ERR(sbox_wc_mkdir(&b, "A/B")); SVN_ERR(sbox_wc_mkdir(&b, "A/B/C")); - sbox_file_write(&b, "A/B/C/f", "r1 content\n"); + SVN_ERR(sbox_file_write(&b, "A/B/C/f", "r1 content\n")); SVN_ERR(sbox_wc_add(&b, "A/B/C/f")); SVN_ERR(sbox_wc_commit(&b, "")); /* r2: Modify 'f' */ - sbox_file_write(&b, "A/B/C/f", "r1 content\nr2 content\n"); + SVN_ERR(sbox_file_write(&b, "A/B/C/f", "r1 content\nr2 content\n")); SVN_ERR(sbox_wc_commit(&b, "")); /* r3: Create 'X' */ @@ -5301,12 +5640,37 @@ nested_move_update(const svn_test_opts_t *opts, apr_pool_t *pool) SVN_ERR(sbox_wc_update(&b, "", 2)); + { + nodes_row_t nodes[] = { + {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/B/C/f", "normal", 2, "A/B/C/f"}, + {1, "A", "base-deleted", NO_COPY_FROM, "A2"}, + {1, "A/B", "base-deleted", NO_COPY_FROM}, + {1, "A/B/C", "base-deleted", NO_COPY_FROM}, + {1, "A/B/C/f", "base-deleted", NO_COPY_FROM}, + {1, "A2", "normal", 1, "A", MOVED_HERE}, + {1, "A2/B", "normal", 1, "A/B", MOVED_HERE}, + {1, "A2/B/C", "normal", 1, "A/B/C", MOVED_HERE}, + {1, "A2/B/C/f", "normal", 1, "A/B/C/f", MOVED_HERE}, + {3, "A2/B/C", "base-deleted", NO_COPY_FROM, "A2/B/C2"}, + {3, "A2/B/C/f", "base-deleted", NO_COPY_FROM}, + {3, "A2/B/C2", "normal", 1, "A/B/C", MOVED_HERE}, + {3, "A2/B/C2/f", "normal", 1, "A/B/C/f", MOVED_HERE}, + {0} + }; + SVN_ERR(check_db_rows(&b, "", nodes)); + } + /* Following the A->A2 move should raise a tree-conflict on A2/B/C, resolving that may require an explicit resolve. */ SVN_ERR(sbox_wc_resolve(&b, "A", svn_depth_empty, svn_wc_conflict_choose_mine_conflict)); SVN_ERR(sbox_wc_resolve(&b, "A2/B/C", svn_depth_empty, svn_wc_conflict_choose_mine_conflict)); + SVN_ERR(check_db_conflicts(&b, "", NULL /* no conflicts */)); { nodes_row_t nodes[] = { {0, "", "normal", 2, ""}, @@ -5333,6 +5697,8 @@ nested_move_update(const svn_test_opts_t *opts, apr_pool_t *pool) /* Update A to r3 brings no changes but updates the revisions. */ SVN_ERR(sbox_wc_update(&b, "A", 3)); + SVN_ERR(check_db_conflicts(&b, "", NULL /* no conflicts */)); + { nodes_row_t nodes[] = { {0, "", "normal", 2, ""}, @@ -5371,7 +5737,7 @@ nested_move_commit(const svn_test_opts_t *opts, apr_pool_t *pool) SVN_ERR(sbox_wc_mkdir(&b, "A")); SVN_ERR(sbox_wc_mkdir(&b, "A/B")); SVN_ERR(sbox_wc_mkdir(&b, "A/B/C")); - sbox_file_write(&b, "A/B/C/f", "r1 content\n"); + SVN_ERR(sbox_file_write(&b, "A/B/C/f", "r1 content\n")); SVN_ERR(sbox_wc_add(&b, "A/B/C/f")); SVN_ERR(sbox_wc_commit(&b, "")); SVN_ERR(sbox_wc_update(&b, "", 1)); @@ -5615,10 +5981,12 @@ check_tree_conflict_repos_path(svn_test__sandbox_t *b, const apr_array_header_t *locations; svn_boolean_t text_conflicted, prop_conflicted, tree_conflicted; - SVN_ERR(svn_wc__db_read_conflict(&conflict, b->wc_ctx->db, - sbox_wc_path(b, wc_path), + SVN_ERR(svn_wc__db_read_conflict(&conflict, NULL, NULL, + b->wc_ctx->db, sbox_wc_path(b, wc_path), b->pool, b->pool)); + SVN_TEST_ASSERT(conflict != NULL); + SVN_ERR(svn_wc__conflict_read_info(&operation, &locations, &text_conflicted, &prop_conflicted, &tree_conflicted, @@ -5632,7 +6000,9 @@ check_tree_conflict_repos_path(svn_test__sandbox_t *b, svn_wc_conflict_version_t *version = APR_ARRAY_IDX(locations, 0, svn_wc_conflict_version_t *); - SVN_ERR_ASSERT(!strcmp(version->path_in_repos, repos_path1)); + SVN_TEST_ASSERT(version != NULL); + + SVN_TEST_STRING_ASSERT(version->path_in_repos, repos_path1); } if (repos_path2) @@ -5640,7 +6010,9 @@ check_tree_conflict_repos_path(svn_test__sandbox_t *b, svn_wc_conflict_version_t *version = APR_ARRAY_IDX(locations, 1, svn_wc_conflict_version_t *); - SVN_ERR_ASSERT(!strcmp(version->path_in_repos, repos_path2)); + SVN_TEST_ASSERT(version != NULL); + + SVN_TEST_STRING_ASSERT(version->path_in_repos, repos_path2); } return SVN_NO_ERROR; @@ -5666,7 +6038,7 @@ move_update_conflicts(const svn_test_opts_t *opts, apr_pool_t *pool) SVN_ERR(sbox_wc_update(&b, "", 1)); SVN_ERR(sbox_wc_move(&b, "A", "A2")); SVN_ERR(sbox_wc_move(&b, "A2/B/C", "A2/B/C2")); - sbox_file_write(&b, "A2/B/F", "obstruction\n"); + SVN_ERR(sbox_file_write(&b, "A2/B/F", "obstruction\n")); { nodes_row_t nodes[] = { @@ -5744,7 +6116,7 @@ move_update_delete_mods(const svn_test_opts_t *opts, apr_pool_t *pool) SVN_ERR(sbox_wc_mkdir(&b, "A/B")); SVN_ERR(sbox_wc_mkdir(&b, "A/B/C")); SVN_ERR(sbox_wc_mkdir(&b, "A/B/D")); - sbox_file_write(&b, "A/B/C/f", "r1 content\n"); + SVN_ERR(sbox_file_write(&b, "A/B/C/f", "r1 content\n")); SVN_ERR(sbox_wc_add(&b, "A/B/C/f")); SVN_ERR(sbox_wc_commit(&b, "")); SVN_ERR(sbox_wc_delete(&b, "A/B/C")); @@ -5753,7 +6125,7 @@ move_update_delete_mods(const svn_test_opts_t *opts, apr_pool_t *pool) SVN_ERR(sbox_wc_update(&b, "", 1)); SVN_ERR(sbox_wc_move(&b, "A/B", "B2")); - sbox_file_write(&b, "B2/C/f", "modified content\n"); + SVN_ERR(sbox_file_write(&b, "B2/C/f", "modified content\n")); SVN_ERR(sbox_wc_delete(&b, "B2/D")); { nodes_row_t nodes[] = { @@ -5791,7 +6163,16 @@ move_update_delete_mods(const svn_test_opts_t *opts, apr_pool_t *pool) {2, "B2/C/f", "normal", 1, "A/B/C/f"}, {0} }; + conflict_info_t conflicts[] = { + {"B2/C", FALSE, FALSE, {svn_wc_conflict_action_delete, + svn_wc_conflict_reason_edited}}, + {"B2/D", FALSE, FALSE, {svn_wc_conflict_action_delete, + svn_wc_conflict_reason_deleted}}, + { 0 } + }; + SVN_ERR(check_db_rows(&b, "", nodes)); + SVN_ERR(check_db_conflicts(&b, "", conflicts)); } SVN_ERR(check_tree_conflict_repos_path(&b, "B2/C", "A/B/C", "A/B/C")); @@ -5949,6 +6330,34 @@ move_in_delete(const svn_test_opts_t *opts, apr_pool_t *pool) } SVN_ERR(sbox_wc_update(&b, "", 3)); + { + nodes_row_t nodes[] = { + {0, "", "normal", 3, ""}, + {0, "A", "normal", 3, "A"}, + {0, "A/B", "normal", 3, "A/B"}, + {0, "A/B/C", "normal", 3, "A/B/C"}, + {0, "A/B/C/D", "normal", 3, "A/B/C/D"}, + {0, "A/B/C/D/E", "normal", 3, "A/B/C/D/E"}, + + {1, "C2", "normal", 2, "A/B/C", MOVED_HERE}, + {1, "C2/D", "normal", 2, "A/B/C/D", MOVED_HERE}, + + {2, "A/B", "base-deleted", NO_COPY_FROM}, + {2, "A/B/C", "base-deleted", NO_COPY_FROM, "C2"}, + {2, "A/B/C/D", "base-deleted", NO_COPY_FROM}, + {2, "A/B/C/D/E", "base-deleted", NO_COPY_FROM}, + + {0} + }; + conflict_info_t conflicts[] = { + {"A/B", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_deleted}}, + {0} + }; + + SVN_ERR(check_db_rows(&b, "", nodes)); + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } SVN_ERR(sbox_wc_revert(&b, "A/B", svn_depth_empty)); { nodes_row_t nodes[] = { @@ -5965,7 +6374,14 @@ move_in_delete(const svn_test_opts_t *opts, apr_pool_t *pool) {1, "C2/D", "normal", 2, "A/B/C/D", MOVED_HERE}, {0} }; + conflict_info_t conflicts[] = { + {"A/B/C", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "A/B/C"}}, + {0} + }; SVN_ERR(check_db_rows(&b, "", nodes)); + /* Where did this conflict come from? */ + SVN_ERR(check_db_conflicts(&b, "", conflicts)); } /* Revert should have left a tree-conflict (or broken the move). */ @@ -5988,6 +6404,7 @@ move_in_delete(const svn_test_opts_t *opts, apr_pool_t *pool) {0} }; SVN_ERR(check_db_rows(&b, "", nodes)); + SVN_ERR(check_db_conflicts(&b, "", NULL)); } return SVN_NO_ERROR; @@ -6563,6 +6980,31 @@ commit_moved_descendant(const svn_test_opts_t *opts, apr_pool_t *pool) shadowed, like in this case. The commit processing doesn't support this yet though*/ + { + nodes_row_t nodes[] = { + {0, "", "normal", 0, ""}, + {0, "A", "normal", 1, "A"}, + {0, "A/A", "normal", 2, "A/A"}, + {0, "A/A/A", "normal", 2, "A/A/A"}, + {0, "A/A/A/A", "normal", 2, "A/A/A/A"}, + {0, "A/A/A/A/A", "normal", 2, "A/A/A/A/A"}, + {0, "A/A/A/A/A/A", "normal", 2, "A/A/A/A/A/A"}, + {0, "A_copied", "normal", 2, "A_copied"}, + {0, "A_copied/A", "normal", 2, "A_copied/A"}, + {0, "A_copied/A/A", "normal", 2, "A_copied/A/A"}, + {0, "A_copied/A/A/A", "normal", 2, "A_copied/A/A/A"}, + {0, "A_copied/A/A/A/A", "normal", 2, "A_copied/A/A/A/A"}, + {0, "A_copied/A/A/A/A/A","normal", 2, "A_copied/A/A/A/A/A"}, + {0, "AAA_moved", "normal", 2, "AAA_moved"}, + {0, "AAA_moved/A", "normal", 2, "AAA_moved/A"}, + {0, "AAA_moved/A/A", "normal", 2, "AAA_moved/A/A"}, + {0, "AAA_moved/A/A/A", "normal", 2, "AAA_moved/A/A/A"}, + + {0} + }; + SVN_ERR(check_db_rows(&b, "", nodes)); + } + return SVN_NO_ERROR; } @@ -6585,10 +7027,63 @@ commit_moved_away_descendant(const svn_test_opts_t *opts, apr_pool_t *pool) SVN_ERR(sbox_wc_delete(&b, "A/A")); SVN_ERR(sbox_wc_copy(&b, "A_copied/A", "A/A")); + { + nodes_row_t nodes[] = { + {0, "", "normal", 0, ""}, + {0, "A", "normal", 1, "A"}, + {0, "A/A", "normal", 1, "A/A"}, + {0, "A/A/A", "normal", 1, "A/A/A"}, + {0, "A/A/A/A", "normal", 1, "A/A/A/A"}, + {0, "A/A/A/A/A", "normal", 1, "A/A/A/A/A"}, + {0, "A/A/A/A/A/A", "normal", 1, "A/A/A/A/A/A"}, + {1, "A_copied", "normal", 1, "A"}, + {1, "A_copied/A", "normal", 1, "A/A"}, + {1, "A_copied/A/A", "normal", 1, "A/A/A"}, + {1, "A_copied/A/A/A", "normal", 1, "A/A/A/A"}, + {1, "A_copied/A/A/A/A", "normal", 1, "A/A/A/A/A"}, + {1, "A_copied/A/A/A/A/A", "normal", 1, "A/A/A/A/A/A"}, + {1, "AAA_moved", "normal", 1, "A/A/A", MOVED_HERE}, + {1, "AAA_moved/A", "normal", 1, "A/A/A/A", MOVED_HERE}, + {1, "AAA_moved/A/A", "normal", 1, "A/A/A/A/A", MOVED_HERE}, + {1, "AAA_moved/A/A/A", "normal", 1, "A/A/A/A/A/A", MOVED_HERE}, + {2, "A/A", "normal", 1, "A/A"}, + {2, "A/A/A", "normal", 1, "A/A/A", FALSE, "AAA_moved"}, + {2, "A/A/A/A", "normal", 1, "A/A/A/A"}, + {2, "A/A/A/A/A", "normal", 1, "A/A/A/A/A"}, + {2, "A/A/A/A/A/A", "normal", 1, "A/A/A/A/A/A"}, + {0} + }; + SVN_ERR(check_db_rows(&b, "", nodes)); + } + /* And now I want to make sure that I can't commit A, without also committing AAA_moved, as that would break the move*/ SVN_ERR(sbox_wc_commit(&b, "A")); + { + nodes_row_t nodes[] = { + {0, "", "normal", 0, ""}, + {0, "A", "normal", 1, "A"}, + {0, "A/A", "normal", 2, "A/A"}, + {0, "A/A/A", "normal", 2, "A/A/A"}, + {0, "A/A/A/A", "normal", 2, "A/A/A/A"}, + {0, "A/A/A/A/A", "normal", 2, "A/A/A/A/A"}, + {0, "A/A/A/A/A/A", "normal", 2, "A/A/A/A/A/A"}, + {1, "A_copied", "normal", 1, "A"}, + {1, "A_copied/A", "normal", 1, "A/A"}, + {1, "A_copied/A/A", "normal", 1, "A/A/A"}, + {1, "A_copied/A/A/A", "normal", 1, "A/A/A/A"}, + {1, "A_copied/A/A/A/A", "normal", 1, "A/A/A/A/A"}, + {1, "A_copied/A/A/A/A/A", "normal", 1, "A/A/A/A/A/A"}, + {1, "AAA_moved", "normal", 1, "A/A/A"}, + {1, "AAA_moved/A", "normal", 1, "A/A/A/A"}, + {1, "AAA_moved/A/A", "normal", 1, "A/A/A/A/A"}, + {1, "AAA_moved/A/A/A", "normal", 1, "A/A/A/A/A/A"}, + {0} + }; + SVN_ERR(check_db_rows(&b, "", nodes)); + } + return svn_error_create(SVN_ERR_TEST_FAILED, NULL, "The commit should have failed"); @@ -6608,7 +7103,7 @@ finite_move_update_bump(const svn_test_opts_t *opts, apr_pool_t *pool) SVN_ERR(sbox_wc_mkdir(&b, "A/B/C")); SVN_ERR(sbox_wc_mkdir(&b, "P")); SVN_ERR(sbox_wc_mkdir(&b, "P/Q")); - sbox_file_write(&b, "P/Q/f", "r1 content\n"); + SVN_ERR(sbox_file_write(&b, "P/Q/f", "r1 content\n")); SVN_ERR(sbox_wc_add(&b, "P/Q/f")); SVN_ERR(sbox_wc_commit(&b, "")); SVN_ERR(sbox_wc_mkdir(&b, "X")); @@ -6645,10 +7140,27 @@ finite_move_update_bump(const svn_test_opts_t *opts, apr_pool_t *pool) SVN_ERR(sbox_wc_move(&b, "P/Q", "Q2")); SVN_ERR(sbox_wc_update_depth(&b, "A/B", 2, svn_depth_files, FALSE)); SVN_ERR(sbox_wc_update_depth(&b, "P/Q", 2, svn_depth_files, FALSE)); - SVN_ERR(check_tree_conflict_repos_path(&b, "A/B", NULL, NULL)); + { + conflict_info_t conflicts[] = { + {"A/B", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "A/B"}}, + {"P/Q", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "P/Q"}}, + {0} + }; + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } + + SVN_ERR(check_tree_conflict_repos_path(&b, "A/B", "A/B", "A/B")); + SVN_ERR(check_tree_conflict_repos_path(&b, "P/Q", "P/Q", "P/Q")); err = sbox_wc_resolve(&b, "A/B", svn_depth_empty, svn_wc_conflict_choose_mine_conflict); SVN_TEST_ASSERT_ERROR(err, SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE); + + /* sbox_wc_resolve() obtains a lock on the target path, so now it + will apply the change on the target */ + SVN_ERR(sbox_wc_resolve(&b, "P/Q", svn_depth_empty, + svn_wc_conflict_choose_mine_conflict)); { nodes_row_t nodes[] = { {0, "", "normal", 1, ""}, @@ -6677,10 +7189,23 @@ finite_move_update_bump(const svn_test_opts_t *opts, apr_pool_t *pool) SVN_ERR(sbox_wc_move(&b, "P", "P2")); SVN_ERR(sbox_wc_update_depth(&b, "A/B", 2, svn_depth_immediates, FALSE)); SVN_ERR(sbox_wc_update_depth(&b, "P", 2, svn_depth_immediates, FALSE)); - SVN_ERR(check_tree_conflict_repos_path(&b, "P", NULL, NULL)); + { + conflict_info_t conflicts[] = { + {"A/B", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "A/B"}}, + {"P", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "P"}}, + {0} + }; + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } + SVN_ERR(check_tree_conflict_repos_path(&b, "P", "P", "P")); + SVN_ERR(check_tree_conflict_repos_path(&b, "A/B", "A/B", "A/B")); err = sbox_wc_resolve(&b, "P", svn_depth_empty, svn_wc_conflict_choose_mine_conflict); SVN_TEST_ASSERT_ERROR(err, SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE); + SVN_ERR(sbox_wc_resolve(&b, "A/B", svn_depth_empty, + svn_wc_conflict_choose_mine_conflict)); { nodes_row_t nodes[] = { {0, "", "normal", 1, ""}, @@ -6711,10 +7236,24 @@ finite_move_update_bump(const svn_test_opts_t *opts, apr_pool_t *pool) SVN_ERR(sbox_wc_move(&b, "P/Q", "Q2")); SVN_ERR(sbox_wc_update_depth(&b, "A/B/C", 2, svn_depth_empty, FALSE)); SVN_ERR(sbox_wc_update_depth(&b, "P/Q", 2, svn_depth_empty, FALSE)); - SVN_ERR(check_tree_conflict_repos_path(&b, "P/Q", NULL, NULL)); + { + conflict_info_t conflicts[] = { + {"A/B/C", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "A/B/C"}}, + {"P/Q", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "P/Q"}}, + + {0} + }; + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } + SVN_ERR(check_tree_conflict_repos_path(&b, "A/B/C", "A/B/C", "A/B/C")); + SVN_ERR(check_tree_conflict_repos_path(&b, "P/Q", "P/Q", "P/Q")); err = sbox_wc_resolve(&b, "P/Q", svn_depth_empty, svn_wc_conflict_choose_mine_conflict); SVN_TEST_ASSERT_ERROR(err, SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE); + SVN_ERR(sbox_wc_resolve(&b, "A/B/C", svn_depth_empty, + svn_wc_conflict_choose_mine_conflict)); { nodes_row_t nodes[] = { {0, "", "normal", 1, ""}, @@ -6767,11 +7306,23 @@ move_away_delete_update(const svn_test_opts_t *opts, apr_pool_t *pool) {0, "", "normal", 2, ""}, {0, "A", "normal", 2, "A"}, {0, "P", "normal", 2, "P"}, - {1, "C2", "normal", 1, "A/B/C"}, + {1, "C2", "normal", 1, "A/B/C", MOVED_HERE}, {1, "Q2", "normal", 1, "P/Q"}, + + {2, "A/B", "normal", 1, "A/B"}, + {2, "A/B/C", "normal", 1, "A/B/C"}, + {3, "A/B/C", "base-deleted", NO_COPY_FROM, "C2"}, + {0} + }; + conflict_info_t conflicts[] = { + {"A/B", FALSE, FALSE, {svn_wc_conflict_action_delete, + svn_wc_conflict_reason_edited}}, + {"P/Q", FALSE, FALSE, {svn_wc_conflict_action_delete, + svn_wc_conflict_reason_moved_away, "P/Q"}}, {0} }; SVN_ERR(check_db_rows(&b, "", nodes)); + SVN_ERR(check_db_conflicts(&b, "", conflicts)); } return SVN_NO_ERROR; @@ -7092,7 +7643,7 @@ movedto_opdepth(const svn_test_opts_t *opts, apr_pool_t *pool) { svn_test__sandbox_t b; - SVN_ERR(svn_test__sandbox_create(&b, "moved_to_op_depth", + SVN_ERR(svn_test__sandbox_create(&b, "movedto_opdepth", opts, pool)); SVN_ERR(sbox_wc_mkdir(&b, "A")); @@ -7731,6 +8282,42 @@ move_depth_expand(const svn_test_opts_t *opts, apr_pool_t *pool) SVN_ERR(sbox_wc_update_depth(&b, "", 1, svn_depth_infinity, TRUE)); + /* And now verify that there are no not-present nodes left and a + consistent working copy */ + { + nodes_row_t nodes[] = { + {0, "", "normal", 1, "" }, + + {0, "A", "normal", 1, "A" }, + {0, "A/A", "normal", 1, "A/A" }, + {0, "A/A/A", "normal", 1, "A/A/A" }, + {0, "A/A/A/A", "normal", 1, "A/A/A/A" }, + {0, "A/B", "normal", 1, "A/B" }, + {0, "A/B/A", "normal", 1, "A/B/A" }, + {0, "A/B/A/A", "normal", 1, "A/B/A/A" }, + + {1, "A", "base-deleted", NO_COPY_FROM, "C" }, + {1, "A/A", "base-deleted", NO_COPY_FROM }, + {1, "A/A/A", "base-deleted", NO_COPY_FROM }, + {1, "A/B", "base-deleted", NO_COPY_FROM }, + {1, "A/B/A", "base-deleted", NO_COPY_FROM }, + {1, "A/B/A/A", "base-deleted", NO_COPY_FROM }, + {1, "A/A/A/A", "base-deleted", NO_COPY_FROM }, + + {1, "C", "normal", 1, "A", MOVED_HERE }, + {1, "C/A", "normal", 1, "A/A", MOVED_HERE }, + {1, "C/B", "not-present", 0, "A/B", MOVED_HERE}, + + {2, "C/B", "normal", 1, "A/A" }, + + {3, "C/A/A", "normal", NO_COPY_FROM }, + {3, "C/B/A", "normal", NO_COPY_FROM }, + + {0} + }; + SVN_ERR(check_db_rows(&b, "", nodes)); + } + /* This used to cause a segfault. Then it asserted in a different place */ SVN_ERR(sbox_wc_resolve(&b, "A", svn_depth_empty, svn_wc_conflict_choose_mine_conflict)); @@ -7762,10 +8349,6 @@ move_depth_expand(const svn_test_opts_t *opts, apr_pool_t *pool) {1, "C/A", "normal", 1, "A/A", MOVED_HERE }, {1, "C/A/A", "normal", 1, "A/A/A", MOVED_HERE }, {1, "C/A/A/A", "normal", 1, "A/A/A/A", MOVED_HERE }, - - {3, "C/A/A", "normal", NO_COPY_FROM }, - {3, "C/A/A/A", "base-deleted", NO_COPY_FROM }, - {1, "C/B", "normal", 1, "A/B", MOVED_HERE }, {1, "C/B/A", "normal", 1, "A/B/A", MOVED_HERE }, {1, "C/B/A/A", "normal", 1, "A/B/A/A", MOVED_HERE }, @@ -7774,6 +8357,8 @@ move_depth_expand(const svn_test_opts_t *opts, apr_pool_t *pool) {2, "C/B/A", "base-deleted", NO_COPY_FROM }, {2, "C/B/A/A", "base-deleted", NO_COPY_FROM }, + {3, "C/A/A", "normal", NO_COPY_FROM }, + {3, "C/A/A/A", "base-deleted", NO_COPY_FROM }, {3, "C/B/A", "normal", NO_COPY_FROM }, {0} @@ -7878,7 +8463,15 @@ move_retract(const svn_test_opts_t *opts, apr_pool_t *pool) {0} }; + conflict_info_t conflicts[] = { + {"A/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "A/A"}}, + {"A/B", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_replaced}}, + { 0 }, + }; SVN_ERR(check_db_rows(&b, "", nodes)); + SVN_ERR(check_db_conflicts(&b, "", conflicts)); } @@ -7909,9 +8502,21 @@ move_retract(const svn_test_opts_t *opts, apr_pool_t *pool) /* Still conflicted */ {1, "D", "normal", 1, "A/B/A/D", MOVED_HERE }, + {4, "A/B/A/C", "normal", 1, "A/A/A/C"}, + + + {0} + }; + conflict_info_t conflicts[] = { + {"A/B", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_replaced}}, + {"A/B/A/C", FALSE, FALSE, {svn_wc_conflict_action_delete, + svn_wc_conflict_reason_edited}}, {0} }; + SVN_ERR(check_db_rows(&b, "", nodes)); + SVN_ERR(check_db_conflicts(&b, "", conflicts)); } /* ### TODO: Resolve via which specific target? */ @@ -7921,7 +8526,7 @@ move_retract(const svn_test_opts_t *opts, apr_pool_t *pool) { nodes_row_t nodes[] = { - {1, "D", "normal", 2, "A/B/A/D", MOVED_HERE }, + {1, "D", "normal", 1, "A/B/A/D", MOVED_HERE }, {0} }; @@ -7941,7 +8546,7 @@ move_delete_file_externals(const svn_test_opts_t *opts, apr_pool_t *pool) SVN_ERR(sbox_wc_mkdir(&b, "A")); SVN_ERR(sbox_wc_mkdir(&b, "A/B")); - sbox_file_write(&b, "f", "New file"); + SVN_ERR(sbox_file_write(&b, "f", "New file")); SVN_ERR(sbox_wc_add(&b, "f")); SVN_ERR(sbox_wc_propset(&b, "svn:externals", "^/f B/P/g", "A")); SVN_ERR(sbox_wc_propset(&b, "svn:externals", "^/f Q/g\n^/f g", "A/B")); @@ -8158,6 +8763,128 @@ update_with_tree_conflict(const svn_test_opts_t *opts, apr_pool_t *pool) } static svn_error_t * +move_update_parent_replace(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + + SVN_ERR(svn_test__sandbox_create(&b, "move_update_parent_replace", opts, + pool)); + + SVN_ERR(sbox_wc_mkdir(&b, "A")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/C")); + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_delete(&b, "A/B")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B")); + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_update(&b, "", 1)); + SVN_ERR(sbox_wc_move(&b, "A/B/C", "A/C")); + + /* Update breaks the move and leaves a conflict. */ + SVN_ERR(sbox_wc_update(&b, "", 2)); + { + nodes_row_t nodes[] = { + {0, "", "normal", 2, ""}, + {0, "A", "normal", 2, "A"}, + {0, "A/B", "normal", 2, "A/B"}, + + {2, "A/C", "normal", 1, "A/B/C", MOVED_HERE}, + + {2, "A/B", "normal", 1, "A/B"}, + {2, "A/B/C", "normal", 1, "A/B/C", FALSE}, + + {3, "A/B/C", "base-deleted", NO_COPY_FROM, "A/C"}, + + {0} + }; + conflict_info_t conflicts[] = { + {"A/B", FALSE, FALSE, {svn_wc_conflict_action_replace, + svn_wc_conflict_reason_edited}}, + {0} + }; + SVN_ERR(check_db_rows(&b, "", nodes)); + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } + + SVN_ERR(sbox_wc_resolve(&b, "A/B", svn_depth_infinity, + svn_wc_conflict_choose_merged)); + + { + nodes_row_t nodes[] = { + {0, "", "normal", 2, ""}, + {0, "A", "normal", 2, "A"}, + {0, "A/B", "normal", 2, "A/B"}, + {2, "A/C", "normal", 1, "A/B/C", MOVED_HERE}, + {2, "A/B", "normal", 1, "A/B"}, + {2, "A/B/C", "normal", 1, "A/B/C", FALSE}, + {3, "A/B/C", "base-deleted", NO_COPY_FROM, "A/C"}, + + {0} + }; + + SVN_ERR(check_db_rows(&b, "", nodes)); + SVN_ERR(check_db_conflicts(&b, "", NULL)); + } + + return SVN_NO_ERROR; +} + +static svn_error_t * +copy_mixed_rev_mods(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + + SVN_ERR(svn_test__sandbox_create(&b, "copy_mixed_rev_mods", opts, + pool)); + + SVN_ERR(sbox_wc_mkdir(&b, "A")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B")); + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/C")); + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_update(&b, "", 1)); + SVN_ERR(sbox_wc_update(&b, "A/B", 2)); + SVN_ERR(sbox_wc_delete(&b, "A/B")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B")); + + { + nodes_row_t nodes[] = { + {0, "", "normal", 1, ""}, + {0, "A", "normal", 1, "A"}, + {0, "A/B", "normal", 2, "A/B"}, + {0, "A/B/C", "normal", 2, "A/B/C"}, + {2, "A/B", "normal", NO_COPY_FROM}, + {2, "A/B/C", "base-deleted", NO_COPY_FROM}, + {0} + }; + SVN_ERR(check_db_rows(&b, "", nodes)); + } + + SVN_ERR(sbox_wc_copy(&b, "A", "X")); + { + nodes_row_t nodes[] = { + {1, "X", "normal", 1, "A"}, + {1, "X/B", "not-present", 2, "A/B"}, + {2, "X/B", "normal", NO_COPY_FROM}, + {0} + }; + SVN_ERR(check_db_rows(&b, "X", nodes)); + } + + SVN_ERR(sbox_wc_commit(&b, "X")); + { + nodes_row_t nodes[] = { + {0, "X", "normal", 3, "X"}, + {0, "X/B", "normal", 3, "X/B"}, + {0} + }; + SVN_ERR(check_db_rows(&b, "X", nodes)); + } + + return SVN_NO_ERROR; +} + +static svn_error_t * move_child_to_parent_revert(const svn_test_opts_t *opts, apr_pool_t *pool) { svn_test__sandbox_t b; @@ -8493,61 +9220,6 @@ move_revert_intermediate(const svn_test_opts_t *opts, apr_pool_t *pool) } static svn_error_t * -copy_mixed_rev_mods(const svn_test_opts_t *opts, apr_pool_t *pool) -{ - svn_test__sandbox_t b; - - SVN_ERR(svn_test__sandbox_create(&b, "copy_mixed_rev_mods", opts, - pool)); - - SVN_ERR(sbox_wc_mkdir(&b, "A")); - SVN_ERR(sbox_wc_mkdir(&b, "A/B")); - SVN_ERR(sbox_wc_commit(&b, "")); - SVN_ERR(sbox_wc_mkdir(&b, "A/B/C")); - SVN_ERR(sbox_wc_commit(&b, "")); - SVN_ERR(sbox_wc_update(&b, "", 1)); - SVN_ERR(sbox_wc_update(&b, "A/B", 2)); - SVN_ERR(sbox_wc_delete(&b, "A/B")); - SVN_ERR(sbox_wc_mkdir(&b, "A/B")); - - { - nodes_row_t nodes[] = { - {0, "", "normal", 1, ""}, - {0, "A", "normal", 1, "A"}, - {0, "A/B", "normal", 2, "A/B"}, - {0, "A/B/C", "normal", 2, "A/B/C"}, - {2, "A/B", "normal", NO_COPY_FROM}, - {2, "A/B/C", "base-deleted", NO_COPY_FROM}, - {0} - }; - SVN_ERR(check_db_rows(&b, "", nodes)); - } - - SVN_ERR(sbox_wc_copy(&b, "A", "X")); - { - nodes_row_t nodes[] = { - {1, "X", "normal", 1, "A"}, - {1, "X/B", "not-present", 2, "A/B"}, - {2, "X/B", "normal", NO_COPY_FROM}, - {0} - }; - SVN_ERR(check_db_rows(&b, "X", nodes)); - } - - SVN_ERR(sbox_wc_commit(&b, "X")); - { - nodes_row_t nodes[] = { - {0, "X", "normal", 3, "X"}, - {0, "X/B", "normal", 3, "X/B"}, - {0} - }; - SVN_ERR(check_db_rows(&b, "X", nodes)); - } - - return SVN_NO_ERROR; -} - -static svn_error_t * move_replace_ancestor_with_child(const svn_test_opts_t *opts, apr_pool_t *pool) { svn_test__sandbox_t b; @@ -8650,15 +9322,15 @@ move_twice_within_delete(const svn_test_opts_t *opts, apr_pool_t *pool) nodes_row_t nodes[] = { { 0, "", "normal", 1, "" }, - + { 0, "A", "normal", 1, "A" }, { 0, "A/A", "normal", 1, "A/A" }, { 0, "A/A/A", "normal", 1, "A/A/A" }, - + { 1, "A", "base-deleted", NO_COPY_FROM, "B/A" }, { 1, "A/A", "base-deleted", NO_COPY_FROM }, { 1, "A/A/A", "base-deleted", NO_COPY_FROM }, - + { 1, "AA", "normal", 1, "A/A/A", MOVED_HERE }, { 1, "B", "normal", NO_COPY_FROM }, @@ -8703,73 +9375,1160 @@ move_twice_within_delete(const svn_test_opts_t *opts, apr_pool_t *pool) return SVN_NO_ERROR; } +/* Helper function for 4 move4 tests */ static svn_error_t * -repo_wc_copy(const svn_test_opts_t *opts, apr_pool_t *pool) +init_move4(svn_test__sandbox_t *sandbox, + const char *test_name, + const svn_test_opts_t *opts, + svn_boolean_t move_away, + apr_pool_t *pool) +{ + SVN_ERR(svn_test__sandbox_create(sandbox, test_name, opts, pool)); + + SVN_ERR(sbox_wc_mkdir(sandbox, "A")); + SVN_ERR(sbox_wc_mkdir(sandbox, "A/A")); + SVN_ERR(sbox_wc_mkdir(sandbox, "A/A/A")); + SVN_ERR(sbox_wc_mkdir(sandbox, "A/A/A/A")); + + SVN_ERR(sbox_wc_mkdir(sandbox, "B")); + SVN_ERR(sbox_wc_mkdir(sandbox, "B/A")); + SVN_ERR(sbox_wc_mkdir(sandbox, "B/A/A")); + SVN_ERR(sbox_wc_mkdir(sandbox, "B/A/A/A")); + + SVN_ERR(sbox_wc_mkdir(sandbox, "C")); + SVN_ERR(sbox_wc_mkdir(sandbox, "C/A")); + SVN_ERR(sbox_wc_mkdir(sandbox, "C/A/A")); + SVN_ERR(sbox_wc_mkdir(sandbox, "C/A/A/A")); + + SVN_ERR(sbox_wc_mkdir(sandbox, "D")); + SVN_ERR(sbox_wc_mkdir(sandbox, "D/A")); + SVN_ERR(sbox_wc_mkdir(sandbox, "D/A/A")); + SVN_ERR(sbox_wc_mkdir(sandbox, "D/A/A/A")); + + SVN_ERR(sbox_wc_commit(sandbox, "")); /* r1 */ + + if (strstr(test_name, "_edit_")) + { + SVN_ERR(sbox_wc_propset(sandbox, "key", "value", "A/A/A")); + SVN_ERR(sbox_wc_propset(sandbox, "key", "value", "B/A/A")); + SVN_ERR(sbox_wc_propset(sandbox, "key", "value", "C/A/A")); + SVN_ERR(sbox_wc_propset(sandbox, "key", "value", "D/A/A")); + SVN_ERR(sbox_wc_propset(sandbox, "key", "value", "A/A/A/A")); + SVN_ERR(sbox_wc_propset(sandbox, "key", "value", "B/A/A/A")); + SVN_ERR(sbox_wc_propset(sandbox, "key", "value", "C/A/A/A")); + SVN_ERR(sbox_wc_propset(sandbox, "key", "value", "D/A/A/A")); + } + else if (strstr(test_name, "_delete_")) + { + SVN_ERR(sbox_wc_delete(sandbox, "A/A/A/A")); + SVN_ERR(sbox_wc_delete(sandbox, "B/A/A/A")); + SVN_ERR(sbox_wc_delete(sandbox, "C/A/A/A")); + SVN_ERR(sbox_wc_delete(sandbox, "D/A/A/A")); + } + else if (strstr(test_name, "_add_")) + { + SVN_ERR(sbox_wc_mkdir(sandbox, "A/A/A/NEW")); + SVN_ERR(sbox_wc_mkdir(sandbox, "B/A/A/NEW")); + SVN_ERR(sbox_wc_mkdir(sandbox, "C/A/A/NEW")); + SVN_ERR(sbox_wc_mkdir(sandbox, "D/A/A/NEW")); + } + else if (strstr(test_name, "_replace_")) + { + SVN_ERR(sbox_wc_delete(sandbox, "A/A/A/A")); + SVN_ERR(sbox_wc_delete(sandbox, "B/A/A/A")); + SVN_ERR(sbox_wc_delete(sandbox, "C/A/A/A")); + SVN_ERR(sbox_wc_delete(sandbox, "D/A/A/A")); + SVN_ERR(sbox_file_write(sandbox, "A/A/A/A", "A")); + SVN_ERR(sbox_file_write(sandbox, "B/A/A/A", "A")); + SVN_ERR(sbox_file_write(sandbox, "C/A/A/A", "A")); + SVN_ERR(sbox_file_write(sandbox, "D/A/A/A", "A")); + SVN_ERR(sbox_wc_add(sandbox, "A/A/A/A")); + SVN_ERR(sbox_wc_add(sandbox, "B/A/A/A")); + SVN_ERR(sbox_wc_add(sandbox, "C/A/A/A")); + SVN_ERR(sbox_wc_add(sandbox, "D/A/A/A")); + } + else if (strstr(test_name, "_delself_")) + { + SVN_ERR(sbox_wc_delete(sandbox, "A/A/A")); + SVN_ERR(sbox_wc_delete(sandbox, "B/A/A")); + SVN_ERR(sbox_wc_delete(sandbox, "C/A/A")); + SVN_ERR(sbox_wc_delete(sandbox, "D/A/A")); + } + else if (strstr(test_name, "_replaceself_")) + { + SVN_ERR(sbox_wc_delete(sandbox, "A/A/A")); + SVN_ERR(sbox_wc_delete(sandbox, "B/A/A")); + SVN_ERR(sbox_wc_delete(sandbox, "C/A/A")); + SVN_ERR(sbox_wc_delete(sandbox, "D/A/A")); + SVN_ERR(sbox_file_write(sandbox, "A/A/A", "A")); + SVN_ERR(sbox_file_write(sandbox, "B/A/A", "A")); + SVN_ERR(sbox_file_write(sandbox, "C/A/A", "A")); + SVN_ERR(sbox_file_write(sandbox, "D/A/A", "A")); + SVN_ERR(sbox_wc_add(sandbox, "A/A/A")); + SVN_ERR(sbox_wc_add(sandbox, "B/A/A")); + SVN_ERR(sbox_wc_add(sandbox, "C/A/A")); + SVN_ERR(sbox_wc_add(sandbox, "D/A/A")); + } + + SVN_ERR(sbox_wc_commit(sandbox, "")); + SVN_ERR(sbox_wc_update(sandbox, "", 1)); + + SVN_ERR(sbox_wc_move(sandbox, "A/A/A", "AAA_1")); + + if (move_away) + SVN_ERR(sbox_wc_move(sandbox, "A", "A_moved")); + else + SVN_ERR(sbox_wc_delete(sandbox, "A")); + + SVN_ERR(sbox_wc_move(sandbox, "B", "A")); + + SVN_ERR(sbox_wc_move(sandbox, "A/A/A", "AAA_2")); + + if (move_away) + SVN_ERR(sbox_wc_move(sandbox, "A/A", "BA_moved")); + else + SVN_ERR(sbox_wc_delete(sandbox, "A/A")); + + SVN_ERR(sbox_wc_move(sandbox, "C/A", "A/A")); + + SVN_ERR(sbox_wc_move(sandbox, "A/A/A", "AAA_3")); + + SVN_ERR(sbox_wc_move(sandbox, "D/A/A", "A/A/A")); + + return SVN_NO_ERROR; +} + +static svn_error_t * +del4_update_edit_AAA(const svn_test_opts_t *opts, apr_pool_t *pool) { svn_test__sandbox_t b; - const char *repos_dir; - const char *new_repos_dir; - const char *new_repos_url; - SVN_ERR(svn_test__sandbox_create(&b, "repo_wc_copy", - opts, pool)); - SVN_ERR(sbox_add_and_commit_greek_tree(&b)); + SVN_ERR(init_move4(&b, "del4_update_edit_AAA", opts, FALSE, pool)); - SVN_ERR(sbox_wc_copy_url(&b, - svn_path_url_add_component2(b.repos_url, "A/B", - pool), - -1, "AA")); + { + nodes_row_t nodes[] = { + + { 0, "A/A/A", "normal", 1, "A/A/A" }, + { 1, "A/A/A", "normal", 1, "B/A/A", FALSE, "AAA_1", TRUE }, + { 2, "A/A/A", "normal", 1, "C/A/A", FALSE, "AAA_2", TRUE }, + { 3, "A/A/A", "normal", 1, "D/A/A", FALSE, "AAA_3", TRUE }, + + { 0, "A/A/A/A", "normal", 1, "A/A/A/A" }, + { 1, "A/A/A/A", "normal", 1, "B/A/A/A", FALSE, NULL, TRUE }, + { 2, "A/A/A/A", "normal", 1, "C/A/A/A", FALSE, NULL, TRUE }, + { 3, "A/A/A/A", "normal", 1, "D/A/A/A", FALSE, NULL, TRUE }, + + { 0 }, + }; + + SVN_ERR(check_db_rows(&b, "A/A/A", nodes)); + } + + /* Update and resolve via mine strategy */ + SVN_ERR(sbox_wc_update(&b, "", 2)); + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); + + { + nodes_row_t nodes[] = { + {0, "", "normal", 2, ""}, + {0, "A", "normal", 2, "A"}, + {0, "A/A", "normal", 2, "A/A"}, + {0, "A/A/A", "normal", 2, "A/A/A", NOT_MOVED, "key"}, + {0, "A/A/A/A", "normal", 2, "A/A/A/A", NOT_MOVED, "key"}, + {0, "B", "normal", 2, "B"}, + {0, "B/A", "normal", 2, "B/A"}, + {0, "B/A/A", "normal", 2, "B/A/A", NOT_MOVED, "key"}, + {0, "B/A/A/A", "normal", 2, "B/A/A/A", NOT_MOVED, "key"}, + {0, "C", "normal", 2, "C"}, + {0, "C/A", "normal", 2, "C/A"}, + {0, "C/A/A", "normal", 2, "C/A/A", NOT_MOVED, "key"}, + {0, "C/A/A/A", "normal", 2, "C/A/A/A", NOT_MOVED, "key"}, + {0, "D", "normal", 2, "D"}, + {0, "D/A", "normal", 2, "D/A"}, + {0, "D/A/A", "normal", 2, "D/A/A", NOT_MOVED, "key"}, + {0, "D/A/A/A", "normal", 2, "D/A/A/A", NOT_MOVED, "key"}, + + {1, "A", "normal", 2, "B", MOVED_HERE}, + {1, "A/A", "normal", 2, "B/A", MOVED_HERE}, + {1, "A/A/A", "normal", 2, "B/A/A", FALSE, "AAA_1", TRUE, "key"}, + {1, "A/A/A/A", "normal", 2, "B/A/A/A", FALSE, NULL, TRUE, "key"}, + {1, "AAA_1", "normal", 2, "A/A/A", MOVED_HERE, "key"}, + {1, "AAA_1/A", "normal", 2, "A/A/A/A", MOVED_HERE, "key"}, + {1, "AAA_2", "normal", 2, "B/A/A", MOVED_HERE, "key"}, + {1, "AAA_2/A", "normal", 2, "B/A/A/A", MOVED_HERE, "key"}, + {1, "AAA_3", "normal", 2, "C/A/A", MOVED_HERE, "key"}, + {1, "AAA_3/A", "normal", 2, "C/A/A/A", MOVED_HERE, "key"}, + {1, "B", "base-deleted", NO_COPY_FROM, "A"}, + {1, "B/A", "base-deleted", NO_COPY_FROM}, + {1, "B/A/A", "base-deleted", NO_COPY_FROM}, + {1, "B/A/A/A", "base-deleted", NO_COPY_FROM}, + + {2, "A/A", "normal", 2, "C/A", MOVED_HERE}, + {2, "A/A/A", "normal", 2, "C/A/A", FALSE, "AAA_2", TRUE, "key"}, + {2, "A/A/A/A", "normal", 2, "C/A/A/A", FALSE, NULL, TRUE, "key"}, + {2, "C/A", "base-deleted", NO_COPY_FROM, "A/A"}, + {2, "C/A/A", "base-deleted", NO_COPY_FROM}, + {2, "C/A/A/A", "base-deleted", NO_COPY_FROM}, + + {3, "A/A/A", "normal", 2, "D/A/A", FALSE, "AAA_3", TRUE, "key"}, + {3, "A/A/A/A", "normal", 2, "D/A/A/A", FALSE, NULL, TRUE, "key"}, + {3, "D/A/A", "base-deleted", NO_COPY_FROM, "A/A/A"}, + {3, "D/A/A/A", "base-deleted", NO_COPY_FROM}, + + { 0 }, + }; + + SVN_ERR(check_db_rows(&b, "", nodes)); + SVN_ERR(check_db_conflicts(&b, "", NULL)); + } + + /* Go back to start position */ + SVN_ERR(sbox_wc_update(&b, "", 1)); + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); + + { + nodes_row_t nodes[] = { + {0, "", "normal", 1, ""}, + {0, "A", "normal", 1, "A"}, + {0, "A/A", "normal", 1, "A/A"}, + {0, "A/A/A", "normal", 1, "A/A/A", NOT_MOVED}, + {0, "A/A/A/A", "normal", 1, "A/A/A/A", NOT_MOVED}, + {0, "B", "normal", 1, "B"}, + {0, "B/A", "normal", 1, "B/A"}, + {0, "B/A/A", "normal", 1, "B/A/A", NOT_MOVED}, + {0, "B/A/A/A", "normal", 1, "B/A/A/A", NOT_MOVED}, + {0, "C", "normal", 1, "C"}, + {0, "C/A", "normal", 1, "C/A"}, + {0, "C/A/A", "normal", 1, "C/A/A", NOT_MOVED}, + {0, "C/A/A/A", "normal", 1, "C/A/A/A", NOT_MOVED}, + {0, "D", "normal", 1, "D"}, + {0, "D/A", "normal", 1, "D/A"}, + {0, "D/A/A", "normal", 1, "D/A/A", NOT_MOVED}, + {0, "D/A/A/A", "normal", 1, "D/A/A/A", NOT_MOVED}, + + {1, "A", "normal", 1, "B", MOVED_HERE}, + {1, "A/A", "normal", 1, "B/A", MOVED_HERE}, + {1, "A/A/A", "normal", 1, "B/A/A", FALSE, "AAA_1", TRUE}, + {1, "A/A/A/A", "normal", 1, "B/A/A/A", FALSE, NULL, TRUE}, + {1, "AAA_1", "normal", 1, "A/A/A", MOVED_HERE}, + {1, "AAA_1/A", "normal", 1, "A/A/A/A", MOVED_HERE}, + {1, "AAA_2", "normal", 1, "B/A/A", MOVED_HERE}, + {1, "AAA_2/A", "normal", 1, "B/A/A/A", MOVED_HERE}, + {1, "AAA_3", "normal", 1, "C/A/A", MOVED_HERE}, + {1, "AAA_3/A", "normal", 1, "C/A/A/A", MOVED_HERE}, + {1, "B", "base-deleted", NO_COPY_FROM, "A"}, + {1, "B/A", "base-deleted", NO_COPY_FROM}, + {1, "B/A/A", "base-deleted", NO_COPY_FROM}, + {1, "B/A/A/A", "base-deleted", NO_COPY_FROM}, + + {2, "A/A", "normal", 1, "C/A", MOVED_HERE}, + {2, "A/A/A", "normal", 1, "C/A/A", FALSE, "AAA_2", TRUE}, + {2, "A/A/A/A", "normal", 1, "C/A/A/A", FALSE, NULL, TRUE}, + {2, "C/A", "base-deleted", NO_COPY_FROM, "A/A"}, + {2, "C/A/A", "base-deleted", NO_COPY_FROM}, + {2, "C/A/A/A", "base-deleted", NO_COPY_FROM}, + + {3, "A/A/A", "normal", 1, "D/A/A", FALSE, "AAA_3", TRUE}, + {3, "A/A/A/A", "normal", 1, "D/A/A/A", FALSE, NULL, TRUE}, + {3, "D/A/A", "base-deleted", NO_COPY_FROM, "A/A/A"}, + {3, "D/A/A/A", "base-deleted", NO_COPY_FROM}, + + { 0 }, + }; + + SVN_ERR(check_db_rows(&b, "", nodes)); + SVN_ERR(check_db_conflicts(&b, "", NULL)); + } + + /* Update and resolve via their strategy */ + SVN_ERR(sbox_wc_update(&b, "", 2)); + { + conflict_info_t conflicts[] = { + {"A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_replaced}}, + {"B", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "B"}}, + {"C/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "C/A"}}, + {"D/A/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "D/A/A"}}, + {0}, + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } + /* This breaks the move A/A/A -> AAA_1 */ + SVN_ERR(sbox_wc_resolve(&b, "A", svn_depth_empty, svn_wc_conflict_choose_merged)); + /* This breaks the move B -> A */ + SVN_ERR(sbox_wc_resolve(&b, "B", svn_depth_empty, svn_wc_conflict_choose_merged)); + /* This breaks the move C/A/A -> A/A */ + SVN_ERR(sbox_wc_resolve(&b, "C/A", svn_depth_empty, svn_wc_conflict_choose_merged)); + /* This breaks the move from D/A/A -> A/A/A */ + SVN_ERR(sbox_wc_resolve(&b, "D/A/A", svn_depth_empty, svn_wc_conflict_choose_merged)); { nodes_row_t nodes[] = { + {0, "", "normal", 2, ""}, + {0, "A", "normal", 2, "A"}, + {0, "A/A", "normal", 2, "A/A"}, + {0, "A/A/A", "normal", 2, "A/A/A", NOT_MOVED, "key"}, + {0, "A/A/A/A", "normal", 2, "A/A/A/A", NOT_MOVED, "key"}, + {0, "B", "normal", 2, "B"}, + {0, "B/A", "normal", 2, "B/A"}, + {0, "B/A/A", "normal", 2, "B/A/A", NOT_MOVED, "key"}, + {0, "B/A/A/A", "normal", 2, "B/A/A/A", NOT_MOVED, "key"}, + {0, "C", "normal", 2, "C"}, + {0, "C/A", "normal", 2, "C/A"}, + {0, "C/A/A", "normal", 2, "C/A/A", NOT_MOVED, "key"}, + {0, "C/A/A/A", "normal", 2, "C/A/A/A", NOT_MOVED, "key"}, + {0, "D", "normal", 2, "D"}, + {0, "D/A", "normal", 2, "D/A"}, + {0, "D/A/A", "normal", 2, "D/A/A", NOT_MOVED, "key"}, + {0, "D/A/A/A", "normal", 2, "D/A/A/A", NOT_MOVED, "key"}, + {1, "A", "normal", 1, "B"}, + {1, "A/A", "normal", 1, "B/A"}, + {1, "A/A/A", "normal", 1, "B/A/A", FALSE}, + {1, "A/A/A/A", "normal", 1, "B/A/A/A"}, + {1, "AAA_1", "normal", 1, "A/A/A"}, + {1, "AAA_1/A", "normal", 1, "A/A/A/A"}, + {1, "AAA_2", "normal", 1, "B/A/A", MOVED_HERE}, + {1, "AAA_2/A", "normal", 1, "B/A/A/A", MOVED_HERE}, + {1, "AAA_3", "normal", 1, "C/A/A", MOVED_HERE}, + {1, "AAA_3/A", "normal", 1, "C/A/A/A", MOVED_HERE}, + {1, "B", "base-deleted", NO_COPY_FROM}, + {1, "B/A", "base-deleted", NO_COPY_FROM}, + {1, "B/A/A", "base-deleted", NO_COPY_FROM}, + {1, "B/A/A/A", "base-deleted", NO_COPY_FROM}, + {2, "A/A", "normal", 1, "C/A"}, + {2, "A/A/A", "normal", 1, "C/A/A", FALSE, "AAA_2"}, + {2, "A/A/A/A", "normal", 1, "C/A/A/A"}, + {2, "C/A", "base-deleted", NO_COPY_FROM}, + {2, "C/A/A", "base-deleted", NO_COPY_FROM}, + {2, "C/A/A/A", "base-deleted", NO_COPY_FROM}, + {3, "A/A/A", "normal", 1, "D/A/A", FALSE, "AAA_3"}, + {3, "A/A/A/A", "normal", 1, "D/A/A/A"}, + {3, "D/A/A", "base-deleted", NO_COPY_FROM}, + {3, "D/A/A/A", "base-deleted", NO_COPY_FROM}, - {1, "AA/lambda", "normal", 1, "A/B/lambda"}, - {1, "AA", "normal", 1, "A/B"}, - {1, "AA/E/beta", "normal", 1, "A/B/E/beta"}, - {1, "AA/E/alpha", "normal", 1, "A/B/E/alpha"}, - {1, "AA/F", "normal", 1, "A/B/F"}, - {1, "AA/E", "normal", 1, "A/B/E"}, + { 0 }, + }; + + SVN_ERR(check_db_rows(&b, "", nodes)); + } + + + return SVN_NO_ERROR; +} + +static svn_error_t * +del4_update_delete_AAA(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + + SVN_ERR(init_move4(&b, "del4_update_delete_AAA", opts, FALSE, pool)); + + /* Update and resolve via mine strategy */ + SVN_ERR(sbox_wc_update(&b, "", 2)); + { + conflict_info_t conflicts[] = { + {"A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_replaced}}, + {"B", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "B"}}, + {"C/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "C/A"}}, + {"D/A/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "D/A/A"}}, + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); + /* Go back to start position */ + SVN_ERR(sbox_wc_update(&b, "", 1)); + { + conflict_info_t conflicts[] = { + {"A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_replaced}}, + {"B", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "B"}}, + {"C/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "C/A"}}, + {"D/A/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "D/A/A"}}, + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); + /* Update and resolve via their strategy */ + SVN_ERR(sbox_wc_update(&b, "", 2)); + { + conflict_info_t conflicts[] = { + {"A", FALSE, FALSE, {svn_wc_conflict_action_edit, svn_wc_conflict_reason_replaced}}, + {"B", FALSE, FALSE, {svn_wc_conflict_action_edit, svn_wc_conflict_reason_moved_away, "B"}}, + {"C/A", FALSE, FALSE, {svn_wc_conflict_action_edit, svn_wc_conflict_reason_moved_away, "C/A"}}, + {"D/A/A", FALSE, FALSE, {svn_wc_conflict_action_edit, svn_wc_conflict_reason_moved_away, "D/A/A"}}, + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_merged)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +del4_update_add_AAA(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + + SVN_ERR(init_move4(&b, "del4_update_add_AAA", opts, FALSE, pool)); + + /* Update and resolve via mine strategy */ + SVN_ERR(sbox_wc_update(&b, "", 2)); + { + conflict_info_t conflicts[] = { + {"A", FALSE, FALSE, {svn_wc_conflict_action_edit, svn_wc_conflict_reason_replaced}}, + {"B", FALSE, FALSE, {svn_wc_conflict_action_edit, svn_wc_conflict_reason_moved_away, "B"}}, + {"C/A", FALSE, FALSE, {svn_wc_conflict_action_edit, svn_wc_conflict_reason_moved_away, "C/A"}}, + {"D/A/A", FALSE, FALSE, {svn_wc_conflict_action_edit, svn_wc_conflict_reason_moved_away, "D/A/A"}}, + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); + /* Go back to start position */ + SVN_ERR(sbox_wc_update(&b, "", 1)); + { + conflict_info_t conflicts[] = { + {"A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_replaced}}, + {"B", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "B"}}, + {"C/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "C/A"}}, + {"D/A/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "D/A/A"}}, + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); + /* Update and resolve via their strategy */ + SVN_ERR(sbox_wc_update(&b, "", 2)); + { + conflict_info_t conflicts[] = { + {"A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_replaced}}, + {"B", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "B"}}, + {"C/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "C/A"}}, + {"D/A/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "D/A/A"}}, + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_merged)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +del4_update_replace_AAA(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + + SVN_ERR(init_move4(&b, "del4_update_replace_AAA", opts, FALSE, pool)); + + /* Update and resolve via mine strategy */ + SVN_ERR(sbox_wc_update(&b, "", 2)); + { + conflict_info_t conflicts[] = { + {"A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_replaced}}, + {"B", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "B"}}, + {"C/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "C/A"}}, + {"D/A/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "D/A/A"}}, + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); + /* Go back to start position */ + SVN_ERR(sbox_wc_update(&b, "", 1)); + { + conflict_info_t conflicts[] = { + {"A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_replaced}}, + {"B", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "B"}}, + {"C/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "C/A"}}, + {"D/A/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "D/A/A"}}, + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); + /* Update and resolve via their strategy */ + SVN_ERR(sbox_wc_update(&b, "", 2)); + { + conflict_info_t conflicts[] = { + {"A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_replaced}}, + {"B", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "B"}}, + {"C/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "C/A"}}, + {"D/A/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "D/A/A"}}, + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_merged)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +del4_update_delself_AAA(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + + SVN_ERR(init_move4(&b, "del4_update_delself_AAA", opts, FALSE, pool)); + + /* Update and resolve via mine strategy */ + SVN_ERR(sbox_wc_update(&b, "", 2)); + + { + conflict_info_t conflicts[] = { + {"A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_replaced}}, + {"B", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "B"}}, + {"C/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "C/A"}}, + {"D/A/A", FALSE, FALSE, {svn_wc_conflict_action_delete, + svn_wc_conflict_reason_moved_away, "D/A/A"}}, + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } + + + /* Resolve a few conflicts manually */ + SVN_ERR(sbox_wc_resolve(&b, "A", svn_depth_empty, + svn_wc_conflict_choose_mine_conflict)); + SVN_ERR(sbox_wc_resolve(&b, "B", svn_depth_empty, + svn_wc_conflict_choose_mine_conflict)); + SVN_ERR(sbox_wc_resolve(&b, "C/A", svn_depth_empty, + svn_wc_conflict_choose_mine_conflict)); + + { + nodes_row_t nodes[] = { + {0, "", "normal", 2, ""}, + {0, "A", "normal", 2, "A"}, + {0, "A/A", "normal", 2, "A/A"}, + {0, "B", "normal", 2, "B"}, + {0, "B/A", "normal", 2, "B/A"}, + {0, "C", "normal", 2, "C"}, + {0, "C/A", "normal", 2, "C/A"}, + {0, "D", "normal", 2, "D"}, + {0, "D/A", "normal", 2, "D/A"}, + {1, "A", "normal", 2, "B", MOVED_HERE}, + {1, "A/A", "normal", 2, "B/A", MOVED_HERE}, + {1, "AAA_1", "normal", 1, "A/A/A"}, + {1, "AAA_1/A", "normal", 1, "A/A/A/A"}, + {1, "AAA_2", "normal", 1, "B/A/A"}, + {1, "AAA_2/A", "normal", 1, "B/A/A/A"}, + {1, "AAA_3", "normal", 1, "C/A/A"}, + {1, "AAA_3/A", "normal", 1, "C/A/A/A"}, + {1, "B", "base-deleted", NO_COPY_FROM, "A"}, + {1, "B/A", "base-deleted", NO_COPY_FROM}, + {2, "A/A", "normal", 2, "C/A", MOVED_HERE}, + {2, "C/A", "base-deleted", NO_COPY_FROM, "A/A"}, + {3, "A/A/A", "normal", 1, "D/A/A"}, + {3, "A/A/A/A", "normal", 1, "D/A/A/A"}, { 0 }, }; - SVN_ERR(check_db_rows(&b, "AA", nodes)); + + SVN_ERR(check_db_rows(&b, "", nodes)); } + { + conflict_info_t conflicts[] = { + /* Not resolved yet */ + {"D/A/A", FALSE, FALSE, {svn_wc_conflict_action_delete, + svn_wc_conflict_reason_moved_away, "D/A/A"}}, - SVN_ERR(svn_uri_get_dirent_from_file_url(&repos_dir, b.repos_url, - pool)); - new_repos_dir = apr_pstrcat(pool, repos_dir, "-2", SVN_VA_NULL); - new_repos_url = apr_pstrcat(pool, b.repos_url, "-2", SVN_VA_NULL); + /* New */ + {"A/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_deleted}}, + {"A/A/A", FALSE, FALSE, {svn_wc_conflict_action_delete, + svn_wc_conflict_reason_moved_away, "A/A/A"}}, - svn_test_add_dir_cleanup(new_repos_dir); + {0} + }; - SVN_ERR(svn_io_remove_dir2(new_repos_dir, TRUE, NULL, NULL, pool)); - SVN_ERR(svn_io_copy_dir_recursively(repos_dir, - svn_dirent_dirname(new_repos_dir, pool), - svn_dirent_basename(new_repos_dir, pool), - FALSE, NULL, NULL, pool)); + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } - SVN_ERR(sbox_wc_relocate(&b, new_repos_url)); + /* These can only be resolved to merged, as the merge is already broken + (because the move source is gone): incoming delete on moved_away */ + SVN_ERR(sbox_wc_resolve(&b, "D/A/A", svn_depth_empty, + svn_wc_conflict_choose_merged)); + SVN_ERR(sbox_wc_resolve(&b, "A/A/A", svn_depth_empty, + svn_wc_conflict_choose_merged)); - /* This produced an invalid copy in Subversion <= 1.8.8. - Status would show all descendants as incomplete */ - SVN_ERR(sbox_wc_copy_url(&b, - svn_path_url_add_component2(b.repos_url, "A/B", - pool), - -1, "BB")); + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); + /* Go back to start position */ + SVN_ERR(sbox_wc_update(&b, "", 1)); + { + conflict_info_t conflicts[] = { + {"A", FALSE, FALSE, { svn_wc_conflict_action_edit, + svn_wc_conflict_reason_replaced}}, + {"B", FALSE, FALSE, { svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "B"}}, + {"C/A", FALSE, FALSE, { svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "C/A"}}, + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } + SVN_ERR(sbox_wc_resolve(&b, "A", svn_depth_empty, + svn_wc_conflict_choose_mine_conflict)); + SVN_ERR(sbox_wc_resolve(&b, "B", svn_depth_empty, + svn_wc_conflict_choose_mine_conflict)); + SVN_ERR(sbox_wc_resolve(&b, "C/A", svn_depth_empty, + svn_wc_conflict_choose_mine_conflict)); + { + conflict_info_t conflicts[] = { + {"A/A", FALSE, FALSE, { svn_wc_conflict_action_edit, + svn_wc_conflict_reason_deleted}}, + {"A/A/A", FALSE, FALSE, { svn_wc_conflict_action_add, + svn_wc_conflict_reason_added}}, + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } + SVN_ERR(sbox_wc_resolve(&b, "A/A/A", svn_depth_empty, + svn_wc_conflict_choose_merged)); + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, + svn_wc_conflict_choose_mine_conflict)); + /* Update and resolve via their strategy */ + SVN_ERR(sbox_wc_update(&b, "", 2)); + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_merged)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +del4_update_replaceself_AAA(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + + SVN_ERR(init_move4(&b, "del4_update_replaceself_AAA", opts, FALSE, pool)); + + /* Update and resolve via mine strategy */ + SVN_ERR(sbox_wc_update(&b, "", 2)); + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); + /* Go back to start position */ + SVN_ERR(sbox_wc_update(&b, "", 1)); + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); + /* Update and resolve via their strategy */ + SVN_ERR(sbox_wc_update(&b, "", 2)); + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_merged)); + + return SVN_NO_ERROR; +} + + +static svn_error_t * +move4_update_edit_AAA(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + + SVN_ERR(init_move4(&b, "move4_update_edit_AAA", opts, TRUE, pool)); + + { + nodes_row_t nodes[] = { + + { 0, "A/A/A", "normal", 1, "A/A/A" }, + { 1, "A/A/A", "normal", 1, "B/A/A", FALSE, NULL /*"AAA_1"*/, TRUE }, + { 2, "A/A/A", "normal", 1, "C/A/A", FALSE, NULL /*"AAA_2"*/, TRUE }, + { 3, "A/A/A", "normal", 1, "D/A/A", FALSE, "AAA_3", TRUE }, + + { 0, "A/A/A/A", "normal", 1, "A/A/A/A" }, + { 1, "A/A/A/A", "normal", 1, "B/A/A/A", FALSE, NULL, TRUE }, + { 2, "A/A/A/A", "normal", 1, "C/A/A/A", FALSE, NULL, TRUE }, + { 3, "A/A/A/A", "normal", 1, "D/A/A/A", FALSE, NULL, TRUE }, + + + { 0 }, + }; + + SVN_ERR(check_db_rows(&b, "A/A/A", nodes)); + } + + /* Update and resolve via mine strategy */ + SVN_ERR(sbox_wc_update(&b, "", 2)); + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); + + { + nodes_row_t nodes[] = { + + { 0, "A/A/A", "normal", 2, "A/A/A", NOT_MOVED, "key" }, + { 1, "A/A/A", "normal", 2, "B/A/A", FALSE, NULL /*"AAA_1"*/, TRUE, "key" }, + { 2, "A/A/A", "normal", 2, "C/A/A", FALSE, NULL /*"AAA_2"*/, TRUE, "key" }, + { 3, "A/A/A", "normal", 2, "D/A/A", FALSE, "AAA_3", TRUE, "key" }, + + { 0, "A/A/A/A", "normal", 2, "A/A/A/A", NOT_MOVED, "key" }, + { 1, "A/A/A/A", "normal", 2, "B/A/A/A", FALSE, NULL, TRUE, "key" }, + { 2, "A/A/A/A", "normal", 2, "C/A/A/A", FALSE, NULL, TRUE, "key" }, + { 3, "A/A/A/A", "normal", 2, "D/A/A/A", FALSE, NULL, TRUE, "key" }, + + { 0 }, + }; + SVN_ERR(check_db_rows(&b, "A/A/A", nodes)); + } + + /* Go back to start position */ + SVN_ERR(sbox_wc_update(&b, "", 1)); + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); + /* Update and resolve via their strategy */ + SVN_ERR(sbox_wc_update(&b, "", 2)); + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_merged)); + + { + nodes_row_t nodes[] = { + + { 0, "A/A/A", "normal", 2, "A/A/A", NOT_MOVED, "key" }, + { 1, "A/A/A", "normal", 1, "B/A/A" }, + { 2, "A/A/A", "normal", 1, "C/A/A" }, + { 3, "A/A/A", "normal", 1, "D/A/A", FALSE, "AAA_3"}, + + { 0, "A/A/A/A", "normal", 2, "A/A/A/A", NOT_MOVED, "key" }, + { 1, "A/A/A/A", "normal", 1, "B/A/A/A" }, + { 2, "A/A/A/A", "normal", 1, "C/A/A/A" }, + { 3, "A/A/A/A", "normal", 1, "D/A/A/A" }, + + { 0 }, + }; + + SVN_ERR(check_db_rows(&b, "A/A/A", nodes)); + } + + return SVN_NO_ERROR; +} + +static svn_error_t * +move4_update_delete_AAA(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + + SVN_ERR(init_move4(&b, "move4_update_delete_AAA", opts, TRUE, pool)); + + /* Update and resolve via mine strategy */ + SVN_ERR(sbox_wc_update(&b, "", 2)); + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); + /* Go back to start position */ + SVN_ERR(sbox_wc_update(&b, "", 1)); + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); + /* Update and resolve via their strategy */ + SVN_ERR(sbox_wc_update(&b, "", 2)); + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_merged)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +move4_update_add_AAA(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + + SVN_ERR(init_move4(&b, "move4_update_add_AAA", opts, TRUE, pool)); + + /* Update and resolve via mine strategy */ + SVN_ERR(sbox_wc_update(&b, "", 2)); + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); + /* Go back to start position */ + SVN_ERR(sbox_wc_update(&b, "", 1)); + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); + /* Update and resolve via their strategy */ + SVN_ERR(sbox_wc_update(&b, "", 2)); + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_merged)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +move4_update_replace_AAA(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + + SVN_ERR(init_move4(&b, "move4_update_replace_AAA", opts, TRUE, pool)); + + /* Update and resolve via mine strategy */ + SVN_ERR(sbox_wc_update(&b, "", 2)); + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); + /* Go back to start position */ + SVN_ERR(sbox_wc_update(&b, "", 1)); + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); + /* Update and resolve via their strategy */ + SVN_ERR(sbox_wc_update(&b, "", 2)); + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_merged)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +move4_update_delself_AAA(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + + SVN_ERR(init_move4(&b, "move4_update_delself_AAA", opts, TRUE, pool)); + + /* Update and resolve via mine strategy */ + SVN_ERR(sbox_wc_update(&b, "", 2)); + + { + nodes_row_t nodes[] = { + + {1, "A_moved", "normal", 1, "A", MOVED_HERE}, + {1, "A_moved/A", "normal", 1, "A/A", MOVED_HERE}, + {1, "A_moved/A/A", "normal", 1, "A/A/A", MOVED_HERE}, + {3, "A_moved/A/A", "base-deleted", NO_COPY_FROM, "AAA_1"}, + {1, "A_moved/A/A/A", "normal", 1, "A/A/A/A", MOVED_HERE}, + {3, "A_moved/A/A/A", "base-deleted", NO_COPY_FROM}, + + { 0 }, + }; + SVN_ERR(check_db_rows(&b, "A_moved", nodes)); + } + + /* Resolve a few conflicts manually */ + SVN_ERR(sbox_wc_resolve(&b, "A", svn_depth_empty, + svn_wc_conflict_choose_mine_conflict)); + + { + nodes_row_t nodes[] = { + {0, "", "normal", 2, ""}, + {0, "A", "normal", 2, "A"}, + {0, "A/A", "normal", 2, "A/A"}, + {0, "B", "normal", 2, "B"}, + {0, "B/A", "normal", 2, "B/A"}, + {0, "C", "normal", 2, "C"}, + {0, "C/A", "normal", 2, "C/A"}, + {0, "D", "normal", 2, "D"}, + {0, "D/A", "normal", 2, "D/A"}, + {1, "A", "normal", 1, "B", FALSE, "A_moved", TRUE}, + {1, "A/A", "normal", 1, "B/A", MOVED_HERE}, + {1, "A/A/A", "normal", 1, "B/A/A", MOVED_HERE}, + {1, "A/A/A/A", "normal", 1, "B/A/A/A", MOVED_HERE}, + {1, "AAA_1", "normal", 1, "A/A/A"}, + {1, "AAA_1/A", "normal", 1, "A/A/A/A"}, + {1, "AAA_2", "normal", 1, "B/A/A", MOVED_HERE}, + {1, "AAA_2/A", "normal", 1, "B/A/A/A", MOVED_HERE}, + {1, "AAA_3", "normal", 1, "C/A/A", MOVED_HERE}, + {1, "AAA_3/A", "normal", 1, "C/A/A/A", MOVED_HERE}, + {1, "A_moved", "normal", 2, "A", MOVED_HERE}, + {1, "A_moved/A", "normal", 2, "A/A", MOVED_HERE}, + {1, "B", "base-deleted", NO_COPY_FROM, "A"}, + {1, "B/A", "base-deleted", NO_COPY_FROM}, + {1, "BA_moved", "normal", 1, "B/A", MOVED_HERE}, + {1, "BA_moved/A", "normal", 1, "B/A/A", MOVED_HERE}, + {1, "BA_moved/A/A", "normal", 1, "B/A/A/A", MOVED_HERE}, + {2, "A/A", "normal", 1, "C/A", FALSE, "BA_moved", TRUE}, + {2, "A/A/A", "normal", 1, "C/A/A", MOVED_HERE}, + {2, "A/A/A/A", "normal", 1, "C/A/A/A", MOVED_HERE}, + {2, "BA_moved/A", "base-deleted", NO_COPY_FROM, "AAA_2"}, + {2, "BA_moved/A/A", "base-deleted", NO_COPY_FROM}, + {2, "C/A", "base-deleted", NO_COPY_FROM, "A/A"}, + {3, "A/A/A", "normal", 1, "D/A/A", FALSE, "AAA_3"}, + {3, "A/A/A/A", "normal", 1, "D/A/A/A"}, + + { 0 }, + }; + conflict_info_t conflicts[] = { + {"A_moved/A/A", FALSE, FALSE, {svn_wc_conflict_action_delete, + svn_wc_conflict_reason_moved_away, "A_moved/A/A"}}, + {"B", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "B"}}, + {"C/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "C/A"}}, + {"D/A/A", FALSE, FALSE, {svn_wc_conflict_action_delete, + svn_wc_conflict_reason_moved_away, "D/A/A"}}, + + { 0 }, + }; + + SVN_ERR(check_db_rows(&b, "", nodes)); + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } + + SVN_ERR(sbox_wc_resolve(&b, "B", svn_depth_empty, + svn_wc_conflict_choose_mine_conflict)); + SVN_ERR(sbox_wc_resolve(&b, "C/A", svn_depth_empty, + svn_wc_conflict_choose_mine_conflict)); + + + /* ### These can currently only be resolved to merged ???? */ + SVN_ERR(sbox_wc_resolve(&b, "D/A/A", svn_depth_empty, + svn_wc_conflict_choose_merged)); + SVN_ERR(sbox_wc_resolve(&b, "A/A/A", svn_depth_empty, + svn_wc_conflict_choose_merged)); + SVN_ERR(sbox_wc_resolve(&b, "A_moved/A/A", svn_depth_empty, + svn_wc_conflict_choose_merged)); + SVN_ERR(sbox_wc_resolve(&b, "A/A", svn_depth_empty, + svn_wc_conflict_choose_mine_conflict)); + SVN_ERR(sbox_wc_resolve(&b, "BA_moved/A", svn_depth_empty, + svn_wc_conflict_choose_merged)); + SVN_ERR(check_db_conflicts(&b, "", NULL)); + /* Go back to start position */ + SVN_ERR(sbox_wc_update(&b, "", 1)); + { + nodes_row_t nodes[] = { + {0, "", "normal", 1, ""}, + {0, "A", "normal", 1, "A"}, + {0, "A/A", "normal", 1, "A/A"}, + {0, "A/A/A", "normal", 1, "A/A/A"}, + {0, "A/A/A/A", "normal", 1, "A/A/A/A"}, + {0, "B", "normal", 1, "B"}, + {0, "B/A", "normal", 1, "B/A"}, + {0, "B/A/A", "normal", 1, "B/A/A"}, + {0, "B/A/A/A", "normal", 1, "B/A/A/A"}, + {0, "C", "normal", 1, "C"}, + {0, "C/A", "normal", 1, "C/A"}, + {0, "C/A/A", "normal", 1, "C/A/A"}, + {0, "C/A/A/A", "normal", 1, "C/A/A/A"}, + {0, "D", "normal", 1, "D"}, + {0, "D/A", "normal", 1, "D/A"}, + {0, "D/A/A", "normal", 1, "D/A/A"}, + {0, "D/A/A/A", "normal", 1, "D/A/A/A"}, + {1, "A", "normal", 2, "B", FALSE, "A_moved", TRUE}, + {1, "A/A", "normal", 2, "B/A", MOVED_HERE}, + {1, "A/A/A", "base-deleted", NO_COPY_FROM}, + {1, "A/A/A/A", "base-deleted", NO_COPY_FROM}, + {1, "A_moved", "normal", 2, "A", MOVED_HERE}, + {1, "A_moved/A", "normal", 2, "A/A", MOVED_HERE}, + {1, "AAA_1", "normal", 1, "A/A/A"}, + {1, "AAA_1/A", "normal", 1, "A/A/A/A"}, + {1, "AAA_2", "normal", 1, "B/A/A"}, + {1, "AAA_2/A", "normal", 1, "B/A/A/A"}, + {1, "AAA_3", "normal", 1, "C/A/A"}, + {1, "AAA_3/A", "normal", 1, "C/A/A/A"}, + {1, "B", "base-deleted", NO_COPY_FROM, "A"}, + {1, "B/A", "base-deleted", NO_COPY_FROM}, + {1, "B/A/A", "base-deleted", NO_COPY_FROM}, + {1, "B/A/A/A", "base-deleted", NO_COPY_FROM}, + {1, "BA_moved", "normal", 2, "B/A", MOVED_HERE}, + {2, "A/A", "normal", 2, "C/A", FALSE, "BA_moved", TRUE}, + {2, "C/A", "base-deleted", NO_COPY_FROM, "A/A"}, + {2, "C/A/A", "base-deleted", NO_COPY_FROM}, + {2, "C/A/A/A", "base-deleted", NO_COPY_FROM}, + {3, "A/A/A", "normal", 1, "D/A/A"}, + {3, "A/A/A/A", "normal", 1, "D/A/A/A"}, + + { 0 }, + }; + + conflict_info_t conflicts[] = { + {"A", FALSE, FALSE, { svn_wc_conflict_action_edit, + svn_wc_conflict_reason_replaced}}, + {"B", FALSE, FALSE, { svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "B"}}, + {"C/A", FALSE, FALSE, { svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "C/A"}}, + {0} + }; + + SVN_ERR(check_db_rows(&b, "", nodes)); + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } + + SVN_ERR(sbox_wc_resolve(&b, "A", svn_depth_empty, + svn_wc_conflict_choose_mine_conflict)); + SVN_ERR(sbox_wc_resolve(&b, "B", svn_depth_empty, + svn_wc_conflict_choose_mine_conflict)); + SVN_ERR(sbox_wc_resolve(&b, "C/A", svn_depth_empty, + svn_wc_conflict_choose_mine_conflict)); + { + conflict_info_t conflicts[] = { + {"A/A", FALSE, FALSE, { svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "A/A"}}, + {"A/A/A", FALSE, FALSE, { svn_wc_conflict_action_add, + svn_wc_conflict_reason_added}}, + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } + SVN_ERR(sbox_wc_resolve(&b, "A/A/A", svn_depth_empty, + svn_wc_conflict_choose_merged)); + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); + /* Update and resolve via their strategy */ + SVN_ERR(sbox_wc_update(&b, "", 2)); + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_merged)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +move4_update_replaceself_AAA(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + + SVN_ERR(init_move4(&b, "move4_update_replaceself_AAA", opts, TRUE, pool)); + + /* Update and resolve via mine strategy */ + SVN_ERR(sbox_wc_update(&b, "", 2)); + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); + /* Go back to start position */ + SVN_ERR(sbox_wc_update(&b, "", 1)); + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); + /* Update and resolve via their strategy */ + SVN_ERR(sbox_wc_update(&b, "", 2)); + SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_merged)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +simple_move_bump(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + + SVN_ERR(svn_test__sandbox_create(&b, "simple_move_bump", opts, pool)); + + SVN_ERR(sbox_wc_mkdir(&b, "A")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B")); + + SVN_ERR(sbox_wc_propset(&b, "old_A", "val", "A")); + SVN_ERR(sbox_wc_propset(&b, "old_B", "val", "A/B")); + + SVN_ERR(sbox_wc_commit(&b, "")); + + SVN_ERR(sbox_wc_propset(&b, "new_A", "val", "A")); + SVN_ERR(sbox_wc_propset(&b, "new_B", "val", "A/B")); + + SVN_ERR(sbox_wc_commit(&b, "")); + + SVN_ERR(sbox_wc_update(&b, "", 1)); + + SVN_ERR(sbox_wc_move(&b, "A/B", "A/B_mv")); + SVN_ERR(sbox_wc_move(&b, "A", "A_mv")); { nodes_row_t nodes[] = { - {1, "BB/lambda", "normal", 1, "A/B/lambda"}, - {1, "BB", "normal", 1, "A/B"}, - {1, "BB/E/beta", "normal", 1, "A/B/E/beta"}, - {1, "BB/E/alpha", "normal", 1, "A/B/E/alpha"}, - {1, "BB/F", "normal", 1, "A/B/F"}, - {1, "BB/E", "normal", 1, "A/B/E"}, + { 0, "", "normal", 1, ""}, + { 0, "A", "normal", 1, "A", NOT_MOVED, "old_A"}, + { 0, "A/B", "normal", 1, "A/B", NOT_MOVED, "old_B"}, + + { 1, "A", "base-deleted", NO_COPY_FROM, "A_mv"}, + { 1, "A/B", "base-deleted", NO_COPY_FROM}, + + { 1, "A_mv", "normal", 1, "A", MOVED_HERE, "old_A" }, + { 1, "A_mv/B", "normal", 1, "A/B", MOVED_HERE, "old_B" }, + + { 2, "A_mv/B", "base-deleted", NO_COPY_FROM, "A_mv/B_mv" }, + { 2, "A_mv/B_mv", "normal", 1, "A/B", FALSE, NULL, TRUE, "old_B" }, { 0 }, }; - SVN_ERR(check_db_rows(&b, "BB", nodes)); + SVN_ERR(check_db_rows(&b, "", nodes)); + } + + SVN_ERR(sbox_wc_update(&b, "", 2)); + + /* Expect the A tree to be updated */ + { + nodes_row_t nodes[] = { + + { 0, "", "normal", 2, ""}, + { 0, "A", "normal", 2, "A", NOT_MOVED, "new_A,old_A"}, + { 0, "A/B", "normal", 2, "A/B", NOT_MOVED, "new_B,old_B"}, + + { 1, "A", "base-deleted", NO_COPY_FROM, "A_mv"}, + { 1, "A/B", "base-deleted", NO_COPY_FROM}, + + { 1, "A_mv", "normal", 1, "A", MOVED_HERE, "old_A" }, + { 1, "A_mv/B", "normal", 1, "A/B", MOVED_HERE, "old_B" }, + + { 2, "A_mv/B", "base-deleted", NO_COPY_FROM, "A_mv/B_mv" }, + { 2, "A_mv/B_mv", "normal", 1, "A/B", FALSE, NULL, TRUE, "old_B" }, + + { 0 }, + }; + SVN_ERR(check_db_rows(&b, "", nodes)); + } + + SVN_ERR(sbox_wc_resolve(&b, "A", svn_depth_empty, + svn_wc_conflict_choose_mine_conflict)); + + { + nodes_row_t nodes[] = { + + { 0, "", "normal", 2, ""}, + { 0, "A", "normal", 2, "A", NOT_MOVED, "new_A,old_A"}, + { 0, "A/B", "normal", 2, "A/B", NOT_MOVED, "new_B,old_B"}, + + { 1, "A", "base-deleted", NO_COPY_FROM, "A_mv"}, + { 1, "A/B", "base-deleted", NO_COPY_FROM}, + + { 1, "A_mv", "normal", 2, "A", MOVED_HERE, "new_A,old_A" }, + { 1, "A_mv/B", "normal", 2, "A/B", MOVED_HERE, "new_B,old_B" }, + + { 2, "A_mv/B", "base-deleted", NO_COPY_FROM, "A_mv/B_mv" }, + { 2, "A_mv/B_mv", "normal", 1, "A/B", FALSE, NULL, TRUE, "old_B" }, + + { 0 }, + }; + SVN_ERR(check_db_rows(&b, "", nodes)); + } + + SVN_ERR(sbox_wc_resolve(&b, "A_mv/B", svn_depth_empty, + svn_wc_conflict_choose_mine_conflict)); + + { + nodes_row_t nodes[] = { + + { 0, "", "normal", 2, ""}, + { 0, "A", "normal", 2, "A", NOT_MOVED, "new_A,old_A"}, + { 0, "A/B", "normal", 2, "A/B", NOT_MOVED, "new_B,old_B"}, + + { 1, "A", "base-deleted", NO_COPY_FROM, "A_mv"}, + { 1, "A/B", "base-deleted", NO_COPY_FROM}, + + { 1, "A_mv", "normal", 2, "A", MOVED_HERE, "new_A,old_A" }, + { 1, "A_mv/B", "normal", 2, "A/B", MOVED_HERE, "new_B,old_B" }, + + { 2, "A_mv/B", "base-deleted", NO_COPY_FROM, "A_mv/B_mv" }, + { 2, "A_mv/B_mv", "normal", 2, "A/B", FALSE, NULL, TRUE, "new_B,old_B" }, + + { 0 }, + }; + SVN_ERR(check_db_rows(&b, "", nodes)); } return SVN_NO_ERROR; @@ -8826,8 +10585,35 @@ movedhere_extract_retract(const svn_test_opts_t *opts, apr_pool_t *pool) SVN_ERR(sbox_wc_mkdir(&b, "Z/E2")); SVN_ERR(sbox_wc_update(&b, "", 2)); + { + conflict_info_t conflicts[] = { + {"A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "A"}}, + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } SVN_ERR(sbox_wc_resolve(&b, "A", svn_depth_empty, svn_wc_conflict_choose_mine_conflict)); + { + conflict_info_t conflicts[] = { + {"Z/B1", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_deleted}}, + {"Z/B2", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "Z/B2"}}, + {"Z/C1", FALSE, FALSE, {svn_wc_conflict_action_delete, + svn_wc_conflict_reason_deleted}}, + {"Z/C2", FALSE, FALSE, {svn_wc_conflict_action_delete, + svn_wc_conflict_reason_moved_away, "Z/C2"}}, + {"Z/E2", FALSE, FALSE, {svn_wc_conflict_action_add, + svn_wc_conflict_reason_added}}, + + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } SVN_ERR(sbox_wc_resolve(&b, "Z/B1", svn_depth_empty, svn_wc_conflict_choose_mine_conflict)); SVN_ERR(sbox_wc_resolve(&b, "Z/B2", svn_depth_empty, @@ -8838,8 +10624,10 @@ movedhere_extract_retract(const svn_test_opts_t *opts, apr_pool_t *pool) SVN_ERR(sbox_wc_resolve(&b, "Z/C2", svn_depth_empty, svn_wc_conflict_choose_merged)); - SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, - svn_wc_conflict_choose_mine_conflict)); + SVN_ERR(sbox_wc_resolve(&b, "Z/E2", svn_depth_empty, + svn_wc_conflict_choose_merged)); + + SVN_ERR(check_db_conflicts(&b, "", NULL)); { nodes_row_t nodes[] = { @@ -8894,6 +10682,168 @@ movedhere_extract_retract(const svn_test_opts_t *opts, apr_pool_t *pool) { 0 }, }; SVN_ERR(check_db_rows(&b, "", nodes)); + + SVN_ERR(check_db_conflicts(&b, "", NULL)); + } + + return SVN_NO_ERROR; +} + +static svn_error_t * +repo_wc_copy(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + const char *new_repos_dir; + const char *new_repos_url; + + SVN_ERR(svn_test__sandbox_create(&b, "repo_wc_copy", + opts, pool)); + SVN_ERR(sbox_add_and_commit_greek_tree(&b)); + + SVN_ERR(sbox_wc_copy_url(&b, + svn_path_url_add_component2(b.repos_url, "A/B", + pool), + -1, "AA")); + + { + nodes_row_t nodes[] = { + + {1, "AA/lambda", "normal", 1, "A/B/lambda"}, + {1, "AA", "normal", 1, "A/B"}, + {1, "AA/E/beta", "normal", 1, "A/B/E/beta"}, + {1, "AA/E/alpha", "normal", 1, "A/B/E/alpha"}, + {1, "AA/F", "normal", 1, "A/B/F"}, + {1, "AA/E", "normal", 1, "A/B/E"}, + + { 0 }, + }; + SVN_ERR(check_db_rows(&b, "AA", nodes)); + } + + new_repos_dir = apr_pstrcat(pool, b.repos_dir, "-2", SVN_VA_NULL); + new_repos_url = apr_pstrcat(pool, b.repos_url, "-2", SVN_VA_NULL); + + svn_test_add_dir_cleanup(new_repos_dir); + + SVN_ERR(svn_io_remove_dir2(new_repos_dir, TRUE, NULL, NULL, pool)); + SVN_ERR(svn_io_copy_dir_recursively(b.repos_dir, + svn_dirent_dirname(new_repos_dir, pool), + svn_dirent_basename(new_repos_dir, pool), + FALSE, NULL, NULL, pool)); + + SVN_ERR(sbox_wc_relocate(&b, new_repos_url)); + + /* This produced an invalid copy in Subversion <= 1.8.8. + Status would show all descendants as incomplete */ + SVN_ERR(sbox_wc_copy_url(&b, + svn_path_url_add_component2(b.repos_url, "A/B", + pool), + -1, "BB")); + + { + nodes_row_t nodes[] = { + + {1, "BB/lambda", "normal", 1, "A/B/lambda"}, + {1, "BB", "normal", 1, "A/B"}, + {1, "BB/E/beta", "normal", 1, "A/B/E/beta"}, + {1, "BB/E/alpha", "normal", 1, "A/B/E/alpha"}, + {1, "BB/F", "normal", 1, "A/B/F"}, + {1, "BB/E", "normal", 1, "A/B/E"}, + + { 0 }, + }; + SVN_ERR(check_db_rows(&b, "BB", nodes)); + } + + return SVN_NO_ERROR; +} + +static svn_error_t * +break_move_in_delete(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + + SVN_ERR(svn_test__sandbox_create(&b, "break_move_in_delete", opts, pool)); + + SVN_ERR(sbox_wc_mkdir(&b, "A")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B")); + SVN_ERR(sbox_wc_mkdir(&b, "X")); + SVN_ERR(sbox_wc_mkdir(&b, "X/Y")); + SVN_ERR(sbox_wc_mkdir(&b, "X/Y/Z")); + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_propset(&b, "key", "value", "X/Y/Z")); + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_update(&b, "", 1)); + + SVN_ERR(sbox_wc_move(&b, "X/Y/Z", "A/Z")); + SVN_ERR(sbox_wc_delete(&b, "X")); + { + nodes_row_t nodes[] = { + {0, "", "normal", 1, ""}, + {0, "A", "normal", 1, "A"}, + {0, "A/B", "normal", 1, "A/B"}, + {0, "X", "normal", 1, "X"}, + {0, "X/Y", "normal", 1, "X/Y"}, + {0, "X/Y/Z", "normal", 1, "X/Y/Z"}, + {1, "X", "base-deleted", NO_COPY_FROM}, + {1, "X/Y", "base-deleted", NO_COPY_FROM}, + {1, "X/Y/Z", "base-deleted", NO_COPY_FROM, "A/Z"}, + {2, "A/Z", "normal", 1, "X/Y/Z", MOVED_HERE}, + {0} + }; + SVN_ERR(check_db_rows(&b, "", nodes)); + } + + SVN_ERR(sbox_wc_update(&b, "", 2)); + { + nodes_row_t nodes[] = { + {0, "", "normal", 2, ""}, + {0, "A", "normal", 2, "A"}, + {0, "A/B", "normal", 2, "A/B"}, + {0, "X", "normal", 2, "X"}, + {0, "X/Y", "normal", 2, "X/Y"}, + {0, "X/Y/Z", "normal", 2, "X/Y/Z"}, + {1, "X", "base-deleted", NO_COPY_FROM}, + {1, "X/Y", "base-deleted", NO_COPY_FROM}, + {1, "X/Y/Z", "base-deleted", NO_COPY_FROM, "A/Z"}, + {2, "A/Z", "normal", 1, "X/Y/Z", MOVED_HERE}, + {0} + }; + conflict_info_t conflicts1[] = { + {"X", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_deleted}}, + {0} + }; + conflict_info_t conflicts2[] = { + {"X/Y/Z", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "X"}}, + {0} + }; + SVN_ERR(check_db_rows(&b, "", nodes)); + SVN_ERR(check_db_conflicts(&b, "", conflicts1)); + SVN_ERR(sbox_wc_resolve(&b, "X", svn_depth_empty, + svn_wc_conflict_choose_mine_conflict)); + SVN_ERR(check_db_rows(&b, "", nodes)); + SVN_ERR(check_db_conflicts(&b, "", conflicts2)); + } + + SVN_ERR(sbox_wc_resolved(&b, "X/Y/Z")); + { + nodes_row_t nodes[] = { + {0, "", "normal", 2, ""}, + {0, "A", "normal", 2, "A"}, + {0, "A/B", "normal", 2, "A/B"}, + {0, "X", "normal", 2, "X"}, + {0, "X/Y", "normal", 2, "X/Y"}, + {0, "X/Y/Z", "normal", 2, "X/Y/Z"}, + {1, "X", "base-deleted", NO_COPY_FROM}, + {1, "X/Y", "base-deleted", NO_COPY_FROM}, + {1, "X/Y/Z", "base-deleted", NO_COPY_FROM}, + {2, "A/Z", "normal", 1, "X/Y/Z"}, + {0} + }; + SVN_ERR(check_db_rows(&b, "", nodes)); + SVN_ERR(check_db_conflicts(&b, "", NULL)); } return SVN_NO_ERROR; @@ -9021,10 +10971,911 @@ nested_move_delete(const svn_test_opts_t *opts, apr_pool_t *pool) return SVN_NO_ERROR; } +static svn_error_t * +move_within_mixed_move(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + + SVN_ERR(svn_test__sandbox_create(&b, "move_within_mixed_move", opts, pool)); + + SVN_ERR(sbox_add_and_commit_greek_tree(&b)); + + SVN_ERR(sbox_wc_delete(&b, "iota")); + SVN_ERR(sbox_wc_commit(&b, "")); + + /* Make A mixed revision */ + SVN_ERR(sbox_wc_update(&b, "A/B/E", 2)); + + /* Single rev moves.. ok */ + SVN_ERR(sbox_wc_move(&b, "A/D", "A/D_mv")); + SVN_ERR(sbox_wc_move(&b, "A/C", "C_mv")); + + { + nodes_row_t nodes[] = { + {0, "", "normal", 0, ""}, + {0, "A", "normal", 1, "A"}, + {0, "A/B", "normal", 1, "A/B"}, + {0, "A/B/E", "normal", 2, "A/B/E"}, + {0, "A/B/E/alpha", "normal", 2, "A/B/E/alpha"}, + {0, "A/B/E/beta", "normal", 2, "A/B/E/beta"}, + {0, "A/B/F", "normal", 1, "A/B/F"}, + {0, "A/B/lambda", "normal", 1, "A/B/lambda"}, + {0, "A/C", "normal", 1, "A/C"}, + {0, "A/D", "normal", 1, "A/D"}, + {0, "A/D/G", "normal", 1, "A/D/G"}, + {0, "A/D/G/pi", "normal", 1, "A/D/G/pi"}, + {0, "A/D/G/rho", "normal", 1, "A/D/G/rho"}, + {0, "A/D/G/tau", "normal", 1, "A/D/G/tau"}, + {0, "A/D/gamma", "normal", 1, "A/D/gamma"}, + {0, "A/D/H", "normal", 1, "A/D/H"}, + {0, "A/D/H/chi", "normal", 1, "A/D/H/chi"}, + {0, "A/D/H/omega", "normal", 1, "A/D/H/omega"}, + {0, "A/D/H/psi", "normal", 1, "A/D/H/psi"}, + {0, "A/mu", "normal", 1, "A/mu"}, + {0, "iota", "not-present", 2, "iota"}, + {1, "C_mv", "normal", 1, "A/C", MOVED_HERE}, + {2, "A/C", "base-deleted", NO_COPY_FROM, "C_mv"}, + {2, "A/D", "base-deleted", NO_COPY_FROM, "A/D_mv"}, + {2, "A/D/G", "base-deleted", NO_COPY_FROM}, + {2, "A/D/G/pi", "base-deleted", NO_COPY_FROM}, + {2, "A/D/G/rho", "base-deleted", NO_COPY_FROM}, + {2, "A/D/G/tau", "base-deleted", NO_COPY_FROM}, + {2, "A/D/gamma", "base-deleted", NO_COPY_FROM}, + {2, "A/D/H", "base-deleted", NO_COPY_FROM}, + {2, "A/D/H/chi", "base-deleted", NO_COPY_FROM}, + {2, "A/D/H/omega", "base-deleted", NO_COPY_FROM}, + {2, "A/D/H/psi", "base-deleted", NO_COPY_FROM}, + {2, "A/D_mv", "normal", 1, "A/D", MOVED_HERE}, + {2, "A/D_mv/G", "normal", 1, "A/D/G", MOVED_HERE}, + {2, "A/D_mv/G/pi", "normal", 1, "A/D/G/pi", MOVED_HERE}, + {2, "A/D_mv/G/rho", "normal", 1, "A/D/G/rho", MOVED_HERE}, + {2, "A/D_mv/G/tau", "normal", 1, "A/D/G/tau", MOVED_HERE}, + {2, "A/D_mv/gamma", "normal", 1, "A/D/gamma", MOVED_HERE}, + {2, "A/D_mv/H", "normal", 1, "A/D/H", MOVED_HERE}, + {2, "A/D_mv/H/chi", "normal", 1, "A/D/H/chi", MOVED_HERE}, + {2, "A/D_mv/H/omega", "normal", 1, "A/D/H/omega", MOVED_HERE}, + {2, "A/D_mv/H/psi", "normal", 1, "A/D/H/psi", MOVED_HERE}, + {0} + }; + + SVN_ERR(check_db_rows(&b, "", nodes)); + } + + /* Mixed rev move... breaks recordings "A/D" -> "A/D_mv" */ + SVN_ERR(sbox_wc_move(&b, "A", "A_mv")); + + { + nodes_row_t nodes[] = { + {0, "", "normal", 0, ""}, + {0, "A", "normal", 1, "A"}, + {0, "A/B", "normal", 1, "A/B"}, + {0, "A/B/E", "normal", 2, "A/B/E"}, + {0, "A/B/E/alpha", "normal", 2, "A/B/E/alpha"}, + {0, "A/B/E/beta", "normal", 2, "A/B/E/beta"}, + {0, "A/B/F", "normal", 1, "A/B/F"}, + {0, "A/B/lambda", "normal", 1, "A/B/lambda"}, + {0, "A/C", "normal", 1, "A/C"}, + {0, "A/D", "normal", 1, "A/D"}, + {0, "A/D/G", "normal", 1, "A/D/G"}, + {0, "A/D/G/pi", "normal", 1, "A/D/G/pi"}, + {0, "A/D/G/rho", "normal", 1, "A/D/G/rho"}, + {0, "A/D/G/tau", "normal", 1, "A/D/G/tau"}, + {0, "A/D/gamma", "normal", 1, "A/D/gamma"}, + {0, "A/D/H", "normal", 1, "A/D/H"}, + {0, "A/D/H/chi", "normal", 1, "A/D/H/chi"}, + {0, "A/D/H/omega", "normal", 1, "A/D/H/omega"}, + {0, "A/D/H/psi", "normal", 1, "A/D/H/psi"}, + {0, "A/mu", "normal", 1, "A/mu"}, + {0, "iota", "not-present", 2, "iota"}, + {1, "A", "base-deleted", NO_COPY_FROM }, + {1, "A/B", "base-deleted", NO_COPY_FROM }, + {1, "A/B/E", "base-deleted", NO_COPY_FROM }, + {1, "A/B/E/alpha", "base-deleted", NO_COPY_FROM }, + {1, "A/B/E/beta", "base-deleted", NO_COPY_FROM }, + {1, "A/B/F", "base-deleted", NO_COPY_FROM }, + {1, "A/B/lambda", "base-deleted", NO_COPY_FROM }, + {1, "A/C", "base-deleted", NO_COPY_FROM, "C_mv"}, + {1, "A/D", "base-deleted", NO_COPY_FROM, "A/D_mv" }, + {1, "A/D/G", "base-deleted", NO_COPY_FROM }, + {1, "A/D/G/pi", "base-deleted", NO_COPY_FROM }, + {1, "A/D/G/rho", "base-deleted", NO_COPY_FROM }, + {1, "A/D/G/tau", "base-deleted", NO_COPY_FROM }, + {1, "A/D/gamma", "base-deleted", NO_COPY_FROM }, + {1, "A/D/H", "base-deleted", NO_COPY_FROM }, + {1, "A/D/H/chi", "base-deleted", NO_COPY_FROM }, + {1, "A/D/H/omega", "base-deleted", NO_COPY_FROM }, + {1, "A/D/H/psi", "base-deleted", NO_COPY_FROM }, + {1, "A/mu", "base-deleted", NO_COPY_FROM }, + {1, "A_mv", "normal", 1, "A"}, + {1, "A_mv/B", "normal", 1, "A/B"}, + {1, "A_mv/B/E", "not-present", 2, "A/B/E"}, + {1, "A_mv/B/F", "normal", 1, "A/B/F"}, + {1, "A_mv/B/lambda", "normal", 1, "A/B/lambda"}, + {1, "A_mv/C", "normal", 1, "A/C"}, + {1, "A_mv/D", "normal", 1, "A/D"}, + {1, "A_mv/D/G", "normal", 1, "A/D/G"}, + {1, "A_mv/D/G/pi", "normal", 1, "A/D/G/pi"}, + {1, "A_mv/D/G/rho", "normal", 1, "A/D/G/rho"}, + {1, "A_mv/D/G/tau", "normal", 1, "A/D/G/tau"}, + {1, "A_mv/D/gamma", "normal", 1, "A/D/gamma"}, + {1, "A_mv/D/H", "normal", 1, "A/D/H"}, + {1, "A_mv/D/H/chi", "normal", 1, "A/D/H/chi"}, + {1, "A_mv/D/H/omega", "normal", 1, "A/D/H/omega"}, + {1, "A_mv/D/H/psi", "normal", 1, "A/D/H/psi"}, + {1, "A_mv/mu", "normal", 1, "A/mu"}, + {1, "C_mv", "normal", 1, "A/C", MOVED_HERE}, + {2, "A_mv/C", "base-deleted", NO_COPY_FROM }, + {2, "A_mv/D", "base-deleted", NO_COPY_FROM }, + {2, "A_mv/D/G", "base-deleted", NO_COPY_FROM }, + {2, "A_mv/D/G/pi", "base-deleted", NO_COPY_FROM }, + {2, "A_mv/D/G/rho", "base-deleted", NO_COPY_FROM }, + {2, "A_mv/D/G/tau", "base-deleted", NO_COPY_FROM }, + {2, "A_mv/D/gamma", "base-deleted", NO_COPY_FROM }, + {2, "A_mv/D/H", "base-deleted", NO_COPY_FROM }, + {2, "A_mv/D/H/chi", "base-deleted", NO_COPY_FROM }, + {2, "A_mv/D/H/omega", "base-deleted", NO_COPY_FROM }, + {2, "A_mv/D/H/psi", "base-deleted", NO_COPY_FROM }, + {2, "A_mv/D_mv", "normal", 1, "A/D", MOVED_HERE}, + {2, "A_mv/D_mv/G", "normal", 1, "A/D/G", MOVED_HERE}, + {2, "A_mv/D_mv/G/pi", "normal", 1, "A/D/G/pi", MOVED_HERE}, + {2, "A_mv/D_mv/G/rho", "normal", 1, "A/D/G/rho", MOVED_HERE}, + {2, "A_mv/D_mv/G/tau", "normal", 1, "A/D/G/tau", MOVED_HERE}, + {2, "A_mv/D_mv/gamma", "normal", 1, "A/D/gamma", MOVED_HERE}, + {2, "A_mv/D_mv/H", "normal", 1, "A/D/H", MOVED_HERE}, + {2, "A_mv/D_mv/H/chi", "normal", 1, "A/D/H/chi", MOVED_HERE}, + {2, "A_mv/D_mv/H/omega","normal", 1, "A/D/H/omega", MOVED_HERE}, + {2, "A_mv/D_mv/H/psi", "normal", 1, "A/D/H/psi", MOVED_HERE}, + {3, "A_mv/B/E", "normal", 2, "A/B/E"}, + {3, "A_mv/B/E/alpha", "normal", 2, "A/B/E/alpha"}, + {3, "A_mv/B/E/beta", "normal", 2, "A/B/E/beta"}, + + {0} + }; + + SVN_ERR(check_db_rows(&b, "", nodes)); + } + + return SVN_NO_ERROR; +} + +static svn_error_t * +move_edit_obstruction(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + + SVN_ERR(svn_test__sandbox_create(&b, "move_edit_obstruction", opts, pool)); + + SVN_ERR(sbox_add_and_commit_greek_tree(&b)); + + SVN_ERR(sbox_file_write(&b, "A/B/E/alpha", "Update alpha")); + SVN_ERR(sbox_wc_propset(&b, "a", "b", "A/B/F")); + SVN_ERR(sbox_wc_commit(&b, "")); /* r2 */ + + SVN_ERR(sbox_wc_update(&b, "", 1)); + + /* Simple move */ + SVN_ERR(sbox_wc_move(&b, "A", "A_mv")); + SVN_ERR(sbox_wc_update(&b, "", 2)); + SVN_ERR(sbox_wc_resolve(&b, "A", svn_depth_empty, + svn_wc_conflict_choose_mine_conflict)); + + { + nodes_row_t nodes[] = { + {1, "A_mv", "normal", 2, "A", MOVED_HERE}, + {1, "A_mv/B", "normal", 2, "A/B", MOVED_HERE}, + {1, "A_mv/B/E", "normal", 2, "A/B/E", MOVED_HERE}, + {1, "A_mv/B/E/alpha", "normal", 2, "A/B/E/alpha", MOVED_HERE}, + {1, "A_mv/B/E/beta", "normal", 2, "A/B/E/beta", MOVED_HERE}, + {1, "A_mv/B/F", "normal", 2, "A/B/F", MOVED_HERE, "a"}, + {1, "A_mv/B/lambda", "normal", 2, "A/B/lambda", MOVED_HERE}, + {1, "A_mv/C", "normal", 2, "A/C", MOVED_HERE}, + {1, "A_mv/D", "normal", 2, "A/D", MOVED_HERE}, + {1, "A_mv/D/G", "normal", 2, "A/D/G", MOVED_HERE}, + {1, "A_mv/D/G/pi", "normal", 2, "A/D/G/pi", MOVED_HERE}, + {1, "A_mv/D/G/rho", "normal", 2, "A/D/G/rho", MOVED_HERE}, + {1, "A_mv/D/G/tau", "normal", 2, "A/D/G/tau", MOVED_HERE}, + {1, "A_mv/D/gamma", "normal", 2, "A/D/gamma", MOVED_HERE}, + {1, "A_mv/D/H", "normal", 2, "A/D/H", MOVED_HERE}, + {1, "A_mv/D/H/chi", "normal", 2, "A/D/H/chi", MOVED_HERE}, + {1, "A_mv/D/H/omega", "normal", 2, "A/D/H/omega", MOVED_HERE}, + {1, "A_mv/D/H/psi", "normal", 2, "A/D/H/psi", MOVED_HERE}, + {1, "A_mv/mu", "normal", 2, "A/mu", MOVED_HERE}, + {0} + }; + + SVN_ERR(check_db_rows(&b, "A_mv", nodes)); + SVN_ERR(check_db_conflicts(&b, "", NULL)); + } + + /* Now do the same thing with local obstructions on the edited nodes */ + SVN_ERR(sbox_wc_update(&b, "", 1)); + SVN_ERR(sbox_wc_revert(&b, "", svn_depth_infinity)); + SVN_ERR(sbox_wc_move(&b, "A", "A_mv")); + + SVN_ERR(svn_io_remove_file2(sbox_wc_path(&b, "A_mv/B/E/alpha"), FALSE, pool)); + SVN_ERR(svn_io_dir_make(sbox_wc_path(&b, "A_mv/B/E/alpha"), APR_OS_DEFAULT, + pool)); + SVN_ERR(svn_io_dir_remove_nonrecursive(sbox_wc_path(&b, "A_mv/B/F"), pool)); + SVN_ERR(sbox_file_write(&b, "A_mv/B/F", "F file")); + + SVN_ERR(sbox_wc_update(&b, "", 2)); + SVN_ERR(sbox_wc_resolve(&b, "A", svn_depth_empty, + svn_wc_conflict_choose_mine_conflict)); + + { + nodes_row_t nodes[] = { + {1, "A_mv", "normal", 2, "A", MOVED_HERE}, + {1, "A_mv/B", "normal", 2, "A/B", MOVED_HERE}, + {1, "A_mv/B/E", "normal", 2, "A/B/E", MOVED_HERE}, + {1, "A_mv/B/E/alpha", "normal", 2, "A/B/E/alpha", MOVED_HERE}, + {1, "A_mv/B/E/beta", "normal", 2, "A/B/E/beta", MOVED_HERE}, + {1, "A_mv/B/F", "normal", 2, "A/B/F", MOVED_HERE, "a"}, + {1, "A_mv/B/lambda", "normal", 2, "A/B/lambda", MOVED_HERE}, + {1, "A_mv/C", "normal", 2, "A/C", MOVED_HERE}, + {1, "A_mv/D", "normal", 2, "A/D", MOVED_HERE}, + {1, "A_mv/D/G", "normal", 2, "A/D/G", MOVED_HERE}, + {1, "A_mv/D/G/pi", "normal", 2, "A/D/G/pi", MOVED_HERE}, + {1, "A_mv/D/G/rho", "normal", 2, "A/D/G/rho", MOVED_HERE}, + {1, "A_mv/D/G/tau", "normal", 2, "A/D/G/tau", MOVED_HERE}, + {1, "A_mv/D/gamma", "normal", 2, "A/D/gamma", MOVED_HERE}, + {1, "A_mv/D/H", "normal", 2, "A/D/H", MOVED_HERE}, + {1, "A_mv/D/H/chi", "normal", 2, "A/D/H/chi", MOVED_HERE}, + {1, "A_mv/D/H/omega", "normal", 2, "A/D/H/omega", MOVED_HERE}, + {1, "A_mv/D/H/psi", "normal", 2, "A/D/H/psi", MOVED_HERE}, + {1, "A_mv/mu", "normal", 2, "A/mu", MOVED_HERE}, + {0} + }; + conflict_info_t conflicts[] = { + {"A_mv/B/E/alpha", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_obstructed}}, + {"A_mv/B/F", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_obstructed}}, + {0} + }; + + SVN_ERR(check_db_rows(&b, "A_mv", nodes)); + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } + + return SVN_NO_ERROR; +} + +static svn_error_t * +move_deep_bump(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + + SVN_ERR(svn_test__sandbox_create(&b, "move_deep_bump", opts, pool)); + + SVN_ERR(sbox_wc_mkdir(&b, "B")); + SVN_ERR(sbox_wc_mkdir(&b, "B/B")); + SVN_ERR(sbox_wc_mkdir(&b, "B/B/A")); + SVN_ERR(sbox_wc_mkdir(&b, "B/B/A/A")); + SVN_ERR(sbox_wc_mkdir(&b, "B/B/A/A/A")); + SVN_ERR(sbox_wc_mkdir(&b, "C")); + SVN_ERR(sbox_wc_mkdir(&b, "C/C")); + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_mkdir(&b, "Z")); + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_mkdir(&b, "B/B/A/A/A/A")); + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_update(&b, "", 1)); + + SVN_ERR(sbox_wc_move(&b, "B/B/A", "B/B/B")); + SVN_ERR(sbox_wc_move(&b, "B/B/B/A", "C/C/A")); + + /* This can't bump C/C/A as that is outside the lock range + so we expect a tree conflict. + + This used to cause a node not found during bumping + because B/B/B/A doesn't have a BASE node */ + SVN_ERR(sbox_wc_update(&b, "B/B", 2)); + + { + nodes_row_t nodes[] = { + {0, "", "normal", 1, ""}, + {0, "B", "normal", 1, "B"}, + {0, "B/B", "normal", 2, "B/B"}, + {0, "B/B/A", "normal", 2, "B/B/A"}, + {0, "B/B/A/A", "normal", 2, "B/B/A/A"}, + {0, "B/B/A/A/A", "normal", 2, "B/B/A/A/A"}, + {0, "C", "normal", 1, "C"}, + {0, "C/C", "normal", 1, "C/C"}, + {3, "B/B/A", "base-deleted", NO_COPY_FROM, "B/B/B"}, + {3, "B/B/A/A", "base-deleted", NO_COPY_FROM}, + {3, "B/B/A/A/A", "base-deleted", NO_COPY_FROM}, + {3, "B/B/B", "normal", 2, "B/B/A", MOVED_HERE}, + {3, "B/B/B/A", "normal", 2, "B/B/A/A", MOVED_HERE}, + {3, "B/B/B/A/A", "normal", 2, "B/B/A/A/A", MOVED_HERE}, + {3, "C/C/A", "normal", 1, "B/B/A/A", MOVED_HERE}, + {3, "C/C/A/A", "normal", 1, "B/B/A/A/A", MOVED_HERE}, + {4, "B/B/B/A", "base-deleted", NO_COPY_FROM, "C/C/A"}, + {4, "B/B/B/A/A", "base-deleted", NO_COPY_FROM}, + {0} + }; + conflict_info_t conflicts[] = { + {"B/B/B/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "B/B/B/A"}}, + {0} + }; + + SVN_ERR(check_db_rows(&b, "", nodes)); + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } + + SVN_ERR(sbox_wc_resolve(&b, "B/B/B/A", svn_depth_empty, + svn_wc_conflict_choose_mine_conflict)); + SVN_ERR(check_db_conflicts(&b, "", NULL)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +make_copy_mixed(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + + SVN_ERR(svn_test__sandbox_create(&b, "make_copy_mixed", opts, pool)); + + SVN_ERR(sbox_wc_mkdir(&b, "A")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/C")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/C/D")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/C/E")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/C/F")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/G")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/H")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/I")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/J")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/K")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/K/L")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/K/M")); + SVN_ERR(sbox_wc_mkdir(&b, "A/N")); + SVN_ERR(sbox_wc_mkdir(&b, "A/N/O")); + SVN_ERR(sbox_wc_mkdir(&b, "A/N/P")); + SVN_ERR(sbox_wc_mkdir(&b, "A/N/Q")); + SVN_ERR(sbox_wc_mkdir(&b, "A/R")); + SVN_ERR(sbox_wc_mkdir(&b, "A/R/S")); + SVN_ERR(sbox_wc_mkdir(&b, "A/R/S/T")); + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_update(&b, "", 1)); + SVN_ERR(sbox_wc_propset(&b, "k", "r2", "")); + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_propset(&b, "k", "r3", "")); + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_propset(&b, "k", "r4", "")); + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_propset(&b, "k", "r5", "")); + SVN_ERR(sbox_wc_commit(&b, "")); + + SVN_ERR(sbox_wc_update(&b, "", 5)); + SVN_ERR(sbox_wc_update(&b, "A", 4)); + SVN_ERR(sbox_wc_update(&b, "A/B", 3)); + SVN_ERR(sbox_wc_update(&b, "A/B/C", 2)); + SVN_ERR(sbox_wc_update(&b, "A/B/K", 1)); + SVN_ERR(sbox_wc_update(&b, "A/N/O", 3)); + + SVN_ERR(sbox_wc_delete(&b, "A/B/C/F")); + SVN_ERR(sbox_wc_delete(&b, "A/B/G/J")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/J")); + + SVN_ERR(sbox_wc_update(&b, "A/N/P", 1)); + SVN_ERR(sbox_wc_update(&b, "A/N/Q", 1)); + SVN_ERR(sbox_wc_delete(&b, "A/N/P")); + SVN_ERR(sbox_wc_mkdir(&b, "A/N/P")); + SVN_ERR(sbox_wc_move(&b, "A/N/Q", "Q")); + SVN_ERR(sbox_wc_move(&b, "A/B/G/H", "H")); + + /* And something that can't be represented */ + SVN_ERR(sbox_wc_update(&b, "A/B/C/E", 1)); + SVN_ERR(sbox_wc_move(&b, "A/B/C/E", "E")); + + { + nodes_row_t nodes[] = { + {0, "", "normal", 5, "", NOT_MOVED, "k"}, + {0, "A", "normal", 4, "A"}, + {0, "A/B", "normal", 3, "A/B"}, + {0, "A/B/C", "normal", 2, "A/B/C"}, + {0, "A/B/C/D", "normal", 2, "A/B/C/D"}, + {0, "A/B/C/E", "normal", 1, "A/B/C/E"}, + {0, "A/B/C/F", "normal", 2, "A/B/C/F"}, + {0, "A/B/G", "normal", 3, "A/B/G"}, + {0, "A/B/G/H", "normal", 3, "A/B/G/H"}, + {0, "A/B/G/I", "normal", 3, "A/B/G/I"}, + {0, "A/B/G/J", "normal", 3, "A/B/G/J"}, + {0, "A/B/K", "normal", 1, "A/B/K"}, + {0, "A/B/K/L", "normal", 1, "A/B/K/L"}, + {0, "A/B/K/M", "normal", 1, "A/B/K/M"}, + {0, "A/N", "normal", 4, "A/N"}, + {0, "A/N/O", "normal", 3, "A/N/O"}, + {0, "A/N/P", "normal", 1, "A/N/P"}, + {0, "A/N/Q", "normal", 1, "A/N/Q"}, + {0, "A/R", "normal", 4, "A/R"}, + {0, "A/R/S", "normal", 4, "A/R/S"}, + {0, "A/R/S/T", "normal", 4, "A/R/S/T"}, + {1, "E", "normal", 1, "A/B/C/E", MOVED_HERE}, + {1, "H", "normal", 3, "A/B/G/H", MOVED_HERE}, + {1, "Q", "normal", 1, "A/N/Q", MOVED_HERE}, + {3, "A/N/P", "normal", NO_COPY_FROM}, + {3, "A/N/Q", "base-deleted", NO_COPY_FROM, "Q"}, + {4, "A/B/C/E", "base-deleted", NO_COPY_FROM, "E"}, + {4, "A/B/C/F", "base-deleted", NO_COPY_FROM}, + {4, "A/B/G/H", "base-deleted", NO_COPY_FROM, "H"}, + {4, "A/B/G/J", "normal", NO_COPY_FROM}, + + {0} + }; + + SVN_ERR(check_db_rows(&b, "", nodes)); + } + + SVN_ERR(svn_wc__db_op_make_copy(b.wc_ctx->db, sbox_wc_path(&b, "A"), + NULL, NULL, pool)); + + { + nodes_row_t nodes[] = { + {0, "", "normal", 5, "", NOT_MOVED, "k"}, + {0, "A", "normal", 4, "A"}, + {0, "A/B", "normal", 3, "A/B"}, + {0, "A/B/C", "normal", 2, "A/B/C"}, + {0, "A/B/C/D", "normal", 2, "A/B/C/D"}, + {0, "A/B/C/E", "normal", 1, "A/B/C/E"}, + {0, "A/B/C/F", "normal", 2, "A/B/C/F"}, + {0, "A/B/G", "normal", 3, "A/B/G"}, + {0, "A/B/G/H", "normal", 3, "A/B/G/H"}, + {0, "A/B/G/I", "normal", 3, "A/B/G/I"}, + {0, "A/B/G/J", "normal", 3, "A/B/G/J"}, + {0, "A/B/K", "normal", 1, "A/B/K"}, + {0, "A/B/K/L", "normal", 1, "A/B/K/L"}, + {0, "A/B/K/M", "normal", 1, "A/B/K/M"}, + {0, "A/N", "normal", 4, "A/N"}, + {0, "A/N/O", "normal", 3, "A/N/O"}, + {0, "A/N/P", "normal", 1, "A/N/P"}, + {0, "A/N/Q", "normal", 1, "A/N/Q"}, + {0, "A/R", "normal", 4, "A/R"}, + {0, "A/R/S", "normal", 4, "A/R/S"}, + {0, "A/R/S/T", "normal", 4, "A/R/S/T"}, + {1, "A", "normal", 4, "A"}, + {1, "A/B", "not-present", 3, "A/B"}, + {1, "A/B/C", "base-deleted", NO_COPY_FROM}, + {1, "A/B/C/D", "base-deleted", NO_COPY_FROM}, + {1, "A/B/C/E", "base-deleted", NO_COPY_FROM, "E"}, + {1, "A/B/C/F", "base-deleted", NO_COPY_FROM}, + {1, "A/B/G", "base-deleted", NO_COPY_FROM}, + {1, "A/B/G/H", "base-deleted", NO_COPY_FROM, "H"}, + {1, "A/B/G/I", "base-deleted", NO_COPY_FROM}, + {1, "A/B/G/J", "base-deleted", NO_COPY_FROM}, + {1, "A/B/K", "base-deleted", NO_COPY_FROM}, + {1, "A/B/K/L", "base-deleted", NO_COPY_FROM}, + {1, "A/B/K/M", "base-deleted", NO_COPY_FROM}, + {1, "A/N", "normal", 4, "A/N"}, + {1, "A/N/O", "not-present", 3, "A/N/O"}, + {1, "A/N/P", "not-present", 1, "A/N/P"}, + {1, "A/N/Q", "not-present", 1, "A/N/Q", FALSE, "Q"}, + {1, "A/R", "normal", 4, "A/R"}, + {1, "A/R/S", "normal", 4, "A/R/S"}, + {1, "A/R/S/T", "normal", 4, "A/R/S/T"}, + {1, "E", "normal", 1, "A/B/C/E", MOVED_HERE}, + {1, "H", "normal", 3, "A/B/G/H", MOVED_HERE}, + {1, "Q", "normal", 1, "A/N/Q", MOVED_HERE}, + {2, "A/B", "normal", 3, "A/B"}, + {2, "A/B/C", "not-present", 2, "A/B/C"}, + {2, "A/B/G", "normal", 3, "A/B/G"}, + {2, "A/B/G/H", "normal", 3, "A/B/G/H"}, + {2, "A/B/G/I", "normal", 3, "A/B/G/I"}, + {2, "A/B/G/J", "normal", 3, "A/B/G/J"}, + {2, "A/B/K", "not-present", 1, "A/B/K"}, + {3, "A/B/C", "normal", 2, "A/B/C"}, + {3, "A/B/C/D", "normal", 2, "A/B/C/D"}, + {3, "A/B/C/E", "not-present", 1, "A/B/C/E"}, + {3, "A/B/C/F", "normal", 2, "A/B/C/F"}, + {3, "A/B/K", "normal", 1, "A/B/K"}, + {3, "A/B/K/L", "normal", 1, "A/B/K/L"}, + {3, "A/B/K/M", "normal", 1, "A/B/K/M"}, + {3, "A/N/O", "normal", 3, "A/N/O"}, + {3, "A/N/P", "normal", NO_COPY_FROM}, + {4, "A/B/C/F", "base-deleted", NO_COPY_FROM}, + {4, "A/B/G/H", "base-deleted", NO_COPY_FROM}, + {4, "A/B/G/J", "normal", NO_COPY_FROM}, + + {0} + }; + + SVN_ERR(check_db_rows(&b, "", nodes)); + } + + SVN_ERR(verify_db(&b)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +make_copy_and_delete_mixed(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + + SVN_ERR(svn_test__sandbox_create(&b, "make_copy_and_del_mixed", opts, pool)); + + SVN_ERR(sbox_wc_mkdir(&b, "A")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/C")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/C/D")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/C/E")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/C/F")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/G")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/H")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/I")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/J")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/K")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/K/L")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/K/M")); + SVN_ERR(sbox_wc_mkdir(&b, "A/N")); + SVN_ERR(sbox_wc_mkdir(&b, "A/N/O")); + SVN_ERR(sbox_wc_mkdir(&b, "A/N/P")); + SVN_ERR(sbox_wc_mkdir(&b, "A/N/Q")); + SVN_ERR(sbox_wc_mkdir(&b, "A/R")); + SVN_ERR(sbox_wc_mkdir(&b, "A/R/S")); + SVN_ERR(sbox_wc_mkdir(&b, "A/R/S/T")); + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_update(&b, "", 1)); + SVN_ERR(sbox_wc_propset(&b, "k", "r2", "")); + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_propset(&b, "k", "r3", "")); + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_propset(&b, "k", "r4", "")); + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_propset(&b, "k", "r5", "")); + SVN_ERR(sbox_wc_commit(&b, "")); + + SVN_ERR(sbox_wc_update(&b, "", 5)); + SVN_ERR(sbox_wc_update(&b, "A", 4)); + SVN_ERR(sbox_wc_update(&b, "A/B", 3)); + SVN_ERR(sbox_wc_update(&b, "A/B/C", 2)); + SVN_ERR(sbox_wc_update(&b, "A/B/K", 1)); + SVN_ERR(sbox_wc_update(&b, "A/N/O", 3)); + + SVN_ERR(sbox_wc_delete(&b, "A/B/C/F")); + SVN_ERR(sbox_wc_delete(&b, "A/B/G/J")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/J")); + + SVN_ERR(sbox_wc_update(&b, "A/N/P", 1)); + SVN_ERR(sbox_wc_update(&b, "A/N/Q", 1)); + SVN_ERR(sbox_wc_delete(&b, "A/N/P")); + SVN_ERR(sbox_wc_mkdir(&b, "A/N/P")); + SVN_ERR(sbox_wc_move(&b, "A/N/Q", "Q")); + SVN_ERR(sbox_wc_move(&b, "A/B/G/H", "H")); + + /* And something that can't be represented */ + SVN_ERR(sbox_wc_update(&b, "A/B/C/E", 1)); + SVN_ERR(sbox_wc_move(&b, "A/B/C/E", "E")); + + { + nodes_row_t nodes[] = { + {0, "", "normal", 5, "", NOT_MOVED, "k"}, + {0, "A", "normal", 4, "A"}, + {0, "A/B", "normal", 3, "A/B"}, + {0, "A/B/C", "normal", 2, "A/B/C"}, + {0, "A/B/C/D", "normal", 2, "A/B/C/D"}, + {0, "A/B/C/E", "normal", 1, "A/B/C/E"}, + {0, "A/B/C/F", "normal", 2, "A/B/C/F"}, + {0, "A/B/G", "normal", 3, "A/B/G"}, + {0, "A/B/G/H", "normal", 3, "A/B/G/H"}, + {0, "A/B/G/I", "normal", 3, "A/B/G/I"}, + {0, "A/B/G/J", "normal", 3, "A/B/G/J"}, + {0, "A/B/K", "normal", 1, "A/B/K"}, + {0, "A/B/K/L", "normal", 1, "A/B/K/L"}, + {0, "A/B/K/M", "normal", 1, "A/B/K/M"}, + {0, "A/N", "normal", 4, "A/N"}, + {0, "A/N/O", "normal", 3, "A/N/O"}, + {0, "A/N/P", "normal", 1, "A/N/P"}, + {0, "A/N/Q", "normal", 1, "A/N/Q"}, + {0, "A/R", "normal", 4, "A/R"}, + {0, "A/R/S", "normal", 4, "A/R/S"}, + {0, "A/R/S/T", "normal", 4, "A/R/S/T"}, + {1, "E", "normal", 1, "A/B/C/E", MOVED_HERE}, + {1, "H", "normal", 3, "A/B/G/H", MOVED_HERE}, + {1, "Q", "normal", 1, "A/N/Q", MOVED_HERE}, + {3, "A/N/P", "normal", NO_COPY_FROM}, + {3, "A/N/Q", "base-deleted", NO_COPY_FROM, "Q"}, + {4, "A/B/C/E", "base-deleted", NO_COPY_FROM, "E"}, + {4, "A/B/C/F", "base-deleted", NO_COPY_FROM}, + {4, "A/B/G/H", "base-deleted", NO_COPY_FROM, "H"}, + {4, "A/B/G/J", "normal", NO_COPY_FROM}, + + {0} + }; + + SVN_ERR(check_db_rows(&b, "", nodes)); + } + + SVN_ERR(svn_wc__db_base_remove(b.wc_ctx->db, sbox_wc_path(&b, "A"), + TRUE, TRUE, FALSE, 99, + NULL, NULL, pool)); + + { + nodes_row_t nodes[] = { + {0, "", "normal", 5, "", NOT_MOVED, "k"}, + {0, "A", "not-present", 99, "A"}, + {1, "A", "normal", 4, "A"}, + {1, "A/B", "not-present", 3, "A/B"}, + {1, "A/N", "normal", 4, "A/N"}, + {1, "A/N/O", "not-present", 3, "A/N/O"}, + {1, "A/N/P", "not-present", 1, "A/N/P"}, + {1, "A/N/Q", "not-present", 1, "A/N/Q", FALSE}, + {1, "A/R", "normal", 4, "A/R"}, + {1, "A/R/S", "normal", 4, "A/R/S"}, + {1, "A/R/S/T", "normal", 4, "A/R/S/T"}, + {1, "E", "normal", 1, "A/B/C/E"}, + {1, "H", "normal", 3, "A/B/G/H", MOVED_HERE}, + {1, "Q", "normal", 1, "A/N/Q"}, + {2, "A/B", "normal", 3, "A/B"}, + {2, "A/B/C", "not-present", 2, "A/B/C"}, + {2, "A/B/G", "normal", 3, "A/B/G"}, + {2, "A/B/G/H", "normal", 3, "A/B/G/H"}, + {2, "A/B/G/I", "normal", 3, "A/B/G/I"}, + {2, "A/B/G/J", "normal", 3, "A/B/G/J"}, + {3, "A/B/C", "normal", 2, "A/B/C"}, + {3, "A/B/C/D", "normal", 2, "A/B/C/D"}, + {3, "A/B/C/E", "not-present", 1, "A/B/C/E"}, + {3, "A/B/C/F", "normal", 2, "A/B/C/F"}, + {2, "A/B/K", "not-present", 1, "A/B/K"}, + {3, "A/B/K", "normal", 1, "A/B/K"}, + {3, "A/B/K/L", "normal", 1, "A/B/K/L"}, + {3, "A/B/K/M", "normal", 1, "A/B/K/M"}, + {3, "A/N/O", "normal", 3, "A/N/O"}, + {3, "A/N/P", "normal", NO_COPY_FROM}, + {4, "A/B/C/F", "base-deleted", NO_COPY_FROM}, + {4, "A/B/G/H", "base-deleted", NO_COPY_FROM, "H"}, + {4, "A/B/G/J", "normal", NO_COPY_FROM}, + + {0} + }; + + /* This currently fails because Q and E are still marked as moved, + while there is nothing to be moved. */ + SVN_ERR(check_db_rows(&b, "", nodes)); + } + + SVN_ERR(verify_db(&b)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_global_commit(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + + SVN_ERR(svn_test__sandbox_create(&b, "global_commit", opts, pool)); + + { + 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/B/D", "normal", 2, "A/B/D" }, + { 0, "A/B/D/E", "normal", 2, "A/B/D/E" }, + { 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, "C", "normal", 2, "A/B/C", MOVED_HERE}, + { 1, "E", "normal", 2, "A/B/D/E", MOVED_HERE}, + { 2, "A/B", "normal", 3, "some", MOVED_HERE }, + { 2, "A/B/C", "base-deleted", NO_COPY_FROM, "C" }, + { 2, "A/B/D", "normal", 3, "some/D", MOVED_HERE}, + { 2, "A/B/D/E", "not-present", 3, "some/D/E", FALSE, "E", TRUE}, + { 3, "A/B/C", "normal", NO_COPY_FROM}, + { 2, "A/F", "normal", 1, "S2" }, + { 2, "A/F/G", "normal", 1, "S2/G" }, + { 2, "A/F/H", "not-present", 1, "S2/H" }, + { 2, "A/F/E", "base-deleted", NO_COPY_FROM }, + { 1, "some", "normal", 3, "some", FALSE, "A/B"}, + { 0 } + }; + SVN_ERR(insert_dirs(&b, before)); + SVN_ERR(check_db_rows(&b, "", before)); /* Check move insertion logic */ + SVN_ERR(verify_db(&b)); + } + + /* This should break the moves */ + SVN_ERR(svn_wc__db_global_commit(b.wc_ctx->db, + sbox_wc_path(&b, "A/B"), + 5, 5, 700, "me", NULL, NULL, + FALSE, FALSE, NULL, pool)); + { + nodes_row_t after[] = { + { 0, "", "normal", 2, "" }, + { 0, "A", "normal", 2, "A" }, + { 0, "A/B", "normal", 5, "A/B" }, + { 0, "A/B/D", "normal", 5, "A/B/D"}, + { 0, "A/B/D/E", "not-present", 5, "A/B/D/E"}, + { 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, "C", "normal", 2, "A/B/C"}, + { 1, "E", "normal", 2, "A/B/D/E"}, + { 1, "some", "normal", 3, "some"}, + { 3, "A/B/C", "normal", NO_COPY_FROM}, + { 2, "A/F", "normal", 1, "S2" }, + { 2, "A/F/G", "normal", 1, "S2/G" }, + { 2, "A/F/H", "not-present", 1, "S2/H" }, + { 2, "A/F/E", "base-deleted", NO_COPY_FROM }, + { 0 } + }; + + SVN_ERR(check_db_rows(&b, "", after)); + SVN_ERR(verify_db(&b)); + } + + SVN_ERR(svn_wc__db_global_commit(b.wc_ctx->db, + sbox_wc_path(&b, "A/F"), + 6, 6, 800, "me", NULL, NULL, + FALSE, FALSE, NULL, pool)); + + { + nodes_row_t after[] = { + { 0, "", "normal", 2, "" }, + { 0, "A", "normal", 2, "A" }, + { 0, "A/B", "normal", 5, "A/B" }, + { 0, "A/B/D", "normal", 5, "A/B/D"}, + { 0, "A/B/D/E", "not-present", 5, "A/B/D/E"}, + { 0, "A/F", "normal", 6, "A/F" }, + { 0, "A/F/G", "normal", 6, "A/F/G" }, + { 0, "A/F/H", "not-present", 6, "A/F/H" }, + { 0, "A/X", "normal", 2, "A/X" }, + { 0, "A/X/Y", "incomplete", 2, "A/X/Y" }, + { 1, "C", "normal", 2, "A/B/C"}, + { 1, "E", "normal", 2, "A/B/D/E"}, + { 1, "some", "normal", 3, "some"}, + { 3, "A/B/C", "normal", NO_COPY_FROM }, + { 0 } + }; + + SVN_ERR(check_db_rows(&b, "", after)); + SVN_ERR(verify_db(&b)); + } + + SVN_ERR(svn_wc__db_global_commit(b.wc_ctx->db, + sbox_wc_path(&b, "A/B/C"), + 7, 7, 900, "me", NULL, NULL, + FALSE, FALSE, NULL, pool)); + + { + nodes_row_t after[] = { + { 0, "", "normal", 2, "" }, + { 0, "A", "normal", 2, "A" }, + { 0, "A/B", "normal", 5, "A/B" }, + { 0, "A/B/C", "normal", 7, "A/B/C"}, + { 0, "A/B/D", "normal", 5, "A/B/D"}, + { 0, "A/B/D/E", "not-present", 5, "A/B/D/E"}, + { 0, "A/F", "normal", 6, "A/F" }, + { 0, "A/F/G", "normal", 6, "A/F/G" }, + { 0, "A/F/H", "not-present", 6, "A/F/H" }, + { 0, "A/X", "normal", 2, "A/X" }, + { 0, "A/X/Y", "incomplete", 2, "A/X/Y" }, + { 1, "some", "normal", 3, "some"}, + { 1, "E", "normal", 2, "A/B/D/E"}, + { 1, "C", "normal", 2, "A/B/C"}, + { 0 } + }; + + SVN_ERR(check_db_rows(&b, "", after)); + SVN_ERR(verify_db(&b)); + } + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_global_commit_switched(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + + SVN_ERR(svn_test__sandbox_create(&b, "global_commit_switched", opts, pool)); + { + nodes_row_t before[] = { + { 0, "", "normal", 2, "" }, + { 0, "A", "normal", 2, "A" }, + /* A/B is switched... The libsvn_client layer tries to prevent this, + because it has such an unexpected behavior. */ + { 0, "A/B", "normal", 2, "N/B" }, + { 0, "A/B/C", "normal", 2, "N/B/C" }, + { 0, "A/B/C/D", "normal", 2, "N/B/C/D" }, + { 0, "A/B/C/E", "normal", 2, "N/B/C/E" }, + { 2, "A/B", "normal", 3, "Z/B" }, + { 2, "A/B/C", "normal", 3, "Z/B/C" }, + { 2, "A/B/C/D", "normal", 3, "Z/B/C/D" }, + { 2, "A/B/C/E", "base-deleted", NO_COPY_FROM }, + /* not-present nodes have an 'uninteresting path', + which doesn't have to be as implied by ancestor at same depth */ + { 2, "A/B/C/F", "not-present", 3, "ZZ-Z-Z_ZZ_Z_Z" }, + { 2, "A/B/C/G", "normal", 3, "Z/B/C/G" }, + { 2, "A/B/C/G/H", "normal", 3, "Z/B/C/G/H" }, + + { 3, "A/B/C", "normal", 4, "Q/C" }, + { 3, "A/B/C/D", "base-deleted", NO_COPY_FROM }, + { 3, "A/B/C/G", "normal", 4, "Q/C/G" }, + { 3, "A/B/C/G/H", "base-deleted", NO_COPY_FROM }, + + { 4, "A/B/C/F", "normal", NO_COPY_FROM }, + { 5, "A/B/C/G/H", "normal", NO_COPY_FROM }, + { 0 } + }; + SVN_ERR(insert_dirs(&b, before)); + SVN_ERR(verify_db(&b)); + } + + SVN_ERR(svn_wc__db_global_commit(b.wc_ctx->db, + sbox_wc_path(&b, "A/B"), + 7, 7, 12, "me", NULL, NULL, + FALSE, FALSE, NULL, pool)); + + { + nodes_row_t after[] = { + { 0, "", "normal", 2, "" }, + { 0, "A", "normal", 2, "A" }, + /* The commit is applied as A/B, because the path is calculated from A, + and not the shadowed node at A/B. (Fixed in r1663991) */ + { 0, "A/B", "normal", 7, "A/B" }, + { 0, "A/B/C", "normal", 7, "A/B/C" }, + { 0, "A/B/C/D", "normal", 7, "A/B/C/D" }, + /* Even calculated path of not-present is fixed */ + { 0, "A/B/C/F", "not-present", 7, "A/B/C/F" }, + { 0, "A/B/C/G", "normal", 7, "A/B/C/G" }, + { 0, "A/B/C/G/H", "normal", 7, "A/B/C/G/H" }, + + /* The higher layers are unaffected */ + { 3, "A/B/C", "normal", 4, "Q/C" }, + { 3, "A/B/C/D", "base-deleted", NO_COPY_FROM }, + { 3, "A/B/C/G", "normal", 4, "Q/C/G" }, + { 3, "A/B/C/G/H", "base-deleted", NO_COPY_FROM }, + + { 4, "A/B/C/F", "normal", NO_COPY_FROM }, + { 5, "A/B/C/G/H", "normal", NO_COPY_FROM }, + { 0 } + }; + SVN_ERR(verify_db(&b)); + SVN_ERR(check_db_rows(&b, "", after)); + } + + SVN_ERR(svn_wc__db_global_commit(b.wc_ctx->db, + sbox_wc_path(&b, "A/B/C"), + 8, 8, 12, "me", NULL, NULL, + FALSE, FALSE, NULL, pool)); + + { + nodes_row_t after[] = { + { 0, "", "normal", 2, "" }, + { 0, "A", "normal", 2, "A" }, + { 0, "A/B", "normal", 7, "A/B" }, + /* Base deleted and not-present are now gone */ + { 0, "A/B/C", "normal", 8, "A/B/C" }, + { 0, "A/B/C/G", "normal", 8, "A/B/C/G" }, + + { 4, "A/B/C/F", "normal", NO_COPY_FROM }, + { 5, "A/B/C/G/H", "normal", NO_COPY_FROM }, + { 0 } + }; + SVN_ERR(verify_db(&b)); + SVN_ERR(check_db_rows(&b, "", after)); + } + + return SVN_NO_ERROR; +} + /* ---------------------------------------------------------------------- */ /* The list of test functions */ -struct svn_test_descriptor_t test_funcs[] = +static int max_threads = 4; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_OPTS_PASS(test_wc_wc_copies, @@ -9047,8 +11898,8 @@ struct svn_test_descriptor_t test_funcs[] = "test_adds_change_kind"), SVN_TEST_OPTS_PASS(test_base_dir_insert_remove, "test_base_dir_insert_remove"), - SVN_TEST_OPTS_PASS(test_temp_op_make_copy, - "test_temp_op_make_copy"), + SVN_TEST_OPTS_PASS(test_db_make_copy, + "test_db_make_copy"), SVN_TEST_OPTS_PASS(test_wc_move, "test_wc_move"), SVN_TEST_OPTS_PASS(test_mixed_rev_copy, @@ -9168,12 +12019,16 @@ struct svn_test_descriptor_t test_funcs[] = "move_parent_into_child (issue 4333)"), SVN_TEST_OPTS_PASS(move_depth_expand, "move depth expansion"), - SVN_TEST_OPTS_PASS(move_retract, + SVN_TEST_OPTS_XFAIL(move_retract, "move retract (issue 4336)"), SVN_TEST_OPTS_PASS(move_delete_file_externals, "move/delete file externals (issue 4293)"), SVN_TEST_OPTS_PASS(update_with_tree_conflict, "update with tree conflict (issue 4347)"), + SVN_TEST_OPTS_PASS(move_update_parent_replace, + "move update with replaced parent (issue 4388)"), + SVN_TEST_OPTS_PASS(copy_mixed_rev_mods, + "copy mixed-rev with mods"), SVN_TEST_OPTS_PASS(move_child_to_parent_revert, "move child to parent and revert (issue 4436)"), SVN_TEST_OPTS_PASS(move_delete_intermediate, @@ -9184,13 +12039,55 @@ struct svn_test_descriptor_t test_funcs[] = "move replace ancestor with child"), SVN_TEST_OPTS_PASS(move_twice_within_delete, "move twice and then delete"), - SVN_TEST_OPTS_PASS(repo_wc_copy, - "repo_wc_copy"), - SVN_TEST_OPTS_PASS(copy_mixed_rev_mods, - "copy mixed-rev with mods"), + SVN_TEST_OPTS_PASS(del4_update_edit_AAA, + "del4: edit AAA"), + SVN_TEST_OPTS_XFAIL(del4_update_delete_AAA, + "del4: delete AAA"), + SVN_TEST_OPTS_XFAIL(del4_update_add_AAA, + "del4: add AAA"), + SVN_TEST_OPTS_XFAIL(del4_update_replace_AAA, + "del4: replace AAA"), + SVN_TEST_OPTS_PASS(del4_update_delself_AAA, + "del4: delete self AAA"), + SVN_TEST_OPTS_XFAIL(del4_update_replaceself_AAA, + "del4: replace self AAA"), + SVN_TEST_OPTS_PASS(move4_update_edit_AAA, + "move4: edit AAA"), + SVN_TEST_OPTS_XFAIL(move4_update_delete_AAA, + "move4: delete AAA"), + SVN_TEST_OPTS_XFAIL(move4_update_add_AAA, + "move4: add AAA"), + SVN_TEST_OPTS_XFAIL(move4_update_replace_AAA, + "move4: replace AAA"), + SVN_TEST_OPTS_PASS(move4_update_delself_AAA, + "move4: delete self AAA"), + SVN_TEST_OPTS_XFAIL(move4_update_replaceself_AAA, + "move4: replace self AAA"), + SVN_TEST_OPTS_PASS(simple_move_bump, + "simple move bump"), SVN_TEST_OPTS_PASS(movedhere_extract_retract, "movedhere extract retract"), + SVN_TEST_OPTS_PASS(repo_wc_copy, + "repo_wc_copy"), + SVN_TEST_OPTS_PASS(break_move_in_delete, + "break move in delete (issue 4491)"), SVN_TEST_OPTS_PASS(nested_move_delete, "nested move delete"), + SVN_TEST_OPTS_XFAIL(move_within_mixed_move, + "move within mixed move"), + SVN_TEST_OPTS_PASS(move_edit_obstruction, + "move edit obstruction"), + SVN_TEST_OPTS_PASS(move_deep_bump, + "move deep bump"), + SVN_TEST_OPTS_PASS(make_copy_mixed, + "make a copy of a mixed revision tree"), + SVN_TEST_OPTS_PASS(make_copy_and_delete_mixed, + "make a copy of a mixed revision tree and del"), + SVN_TEST_OPTS_PASS(test_global_commit, + "test global commit"), + SVN_TEST_OPTS_PASS(test_global_commit_switched, + "test global commit switched"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_wc/pristine-store-test.c b/subversion/tests/libsvn_wc/pristine-store-test.c index 6df96fc..d9ed077 100644 --- a/subversion/tests/libsvn_wc/pristine-store-test.c +++ b/subversion/tests/libsvn_wc/pristine-store-test.c @@ -70,40 +70,6 @@ create_repos_and_wc(const char **wc_abspath, return SVN_NO_ERROR; } - -/* Write the string DATA into a new unique-named file in the directory - * DIR_ABSPATH. Set *FILE_ABSPATH to its absolute path and *CHECKSUM_SHA1 - * and *CHECKSUM_MD5 to its SHA-1 and MD-5 checksums. - * - * CHECKSUM_SHA1 and/or CHECKSUM_MD5 may be null if not required. */ -static svn_error_t * -write_and_checksum_temp_file(const char **file_abspath, - svn_checksum_t **sha1_checksum, - svn_checksum_t **md5_checksum, - const char *data, - const char *dir_abspath, - apr_pool_t *pool) -{ - apr_file_t *file; - - SVN_ERR(svn_io_open_unique_file3(&file, file_abspath, - dir_abspath, svn_io_file_del_none, - pool, pool)); - - SVN_ERR(svn_io_file_write_full(file, data, strlen(data), NULL, pool)); - SVN_ERR(svn_io_file_close(file, pool)); - - if (sha1_checksum) - SVN_ERR(svn_io_file_checksum2(sha1_checksum, *file_abspath, - svn_checksum_sha1, pool)); - if (md5_checksum) - SVN_ERR(svn_io_file_checksum2(md5_checksum, *file_abspath, - svn_checksum_md5, pool)); - - return SVN_NO_ERROR; -} - - /* Exercise the pristine text API with a simple write and read. */ static svn_error_t * pristine_write_read(const svn_test_opts_t *opts, @@ -112,7 +78,9 @@ pristine_write_read(const svn_test_opts_t *opts, svn_wc__db_t *db; const char *wc_abspath; - const char *pristine_tmp_abspath; + svn_wc__db_install_data_t *install_data; + svn_stream_t *pristine_stream; + apr_size_t sz; const char data[] = "Blah"; svn_string_t *data_string = svn_string_create(data, pool); @@ -123,15 +91,15 @@ pristine_write_read(const svn_test_opts_t *opts, /* Write DATA into a new temporary pristine file, set PRISTINE_TMP_ABSPATH * to its path and set DATA_SHA1 and DATA_MD5 to its checksums. */ - { - const char *pristine_tmp_dir; + SVN_ERR(svn_wc__db_pristine_prepare_install(&pristine_stream, + &install_data, + &data_sha1, &data_md5, + db, wc_abspath, + pool, pool)); - SVN_ERR(svn_wc__db_pristine_get_tempdir(&pristine_tmp_dir, db, - wc_abspath, pool, pool)); - SVN_ERR(write_and_checksum_temp_file(&pristine_tmp_abspath, - &data_sha1, &data_md5, - data, pristine_tmp_dir, pool)); - } + sz = strlen(data); + SVN_ERR(svn_stream_write(pristine_stream, data, &sz)); + SVN_ERR(svn_stream_close(pristine_stream)); /* Ensure it's not already in the store. */ { @@ -143,7 +111,7 @@ pristine_write_read(const svn_test_opts_t *opts, } /* Install the new pristine file, referenced by its checksum. */ - SVN_ERR(svn_wc__db_pristine_install(db, pristine_tmp_abspath, + SVN_ERR(svn_wc__db_pristine_install(install_data, data_sha1, data_md5, pool)); /* Ensure it is now found in the store. */ @@ -209,8 +177,10 @@ pristine_delete_while_open(const svn_test_opts_t *opts, { svn_wc__db_t *db; const char *wc_abspath; - const char *pristine_tmp_dir; + svn_wc__db_install_data_t *install_data; + svn_stream_t *pristine_stream; svn_stream_t *contents; + apr_size_t sz; const char data[] = "Blah"; svn_checksum_t *data_sha1, *data_md5; @@ -218,17 +188,17 @@ pristine_delete_while_open(const svn_test_opts_t *opts, SVN_ERR(create_repos_and_wc(&wc_abspath, &db, "pristine_delete_while_open", opts, pool)); - SVN_ERR(svn_wc__db_pristine_get_tempdir(&pristine_tmp_dir, db, - wc_abspath, pool, pool)); + SVN_ERR(svn_wc__db_pristine_prepare_install(&pristine_stream, + &install_data, + &data_sha1, &data_md5, + db, wc_abspath, + pool, pool)); - /* Install a pristine text. */ - { - const char *path; - - SVN_ERR(write_and_checksum_temp_file(&path, &data_sha1, &data_md5, - data, pristine_tmp_dir, pool)); - SVN_ERR(svn_wc__db_pristine_install(db, path, data_sha1, data_md5, pool)); - } + sz = strlen(data); + SVN_ERR(svn_stream_write(pristine_stream, data, &sz)); + SVN_ERR(svn_stream_close(pristine_stream)); + SVN_ERR(svn_wc__db_pristine_install(install_data, + data_sha1, data_md5, pool)); /* Open it for reading */ SVN_ERR(svn_wc__db_pristine_read(&contents, NULL, db, wc_abspath, data_sha1, @@ -242,7 +212,7 @@ pristine_delete_while_open(const svn_test_opts_t *opts, char buffer[4]; apr_size_t len = 4; - SVN_ERR(svn_stream_read(contents, buffer, &len)); + SVN_ERR(svn_stream_read_full(contents, buffer, &len)); SVN_TEST_ASSERT(len == 4); SVN_TEST_ASSERT(memcmp(buffer, data, len) == 0); } @@ -276,7 +246,6 @@ reject_mismatching_text(const svn_test_opts_t *opts, #ifdef SVN_DEBUG /* The pristine store only checks this in debug mode. */ svn_wc__db_t *db; const char *wc_abspath; - const char *pristine_tmp_dir; const char data[] = "Blah"; svn_checksum_t *data_sha1, *data_md5; @@ -286,28 +255,47 @@ reject_mismatching_text(const svn_test_opts_t *opts, SVN_ERR(create_repos_and_wc(&wc_abspath, &db, "reject_mismatching_text", opts, pool)); - SVN_ERR(svn_wc__db_pristine_get_tempdir(&pristine_tmp_dir, db, - wc_abspath, pool, pool)); - /* Install a pristine text. */ { - const char *path; - - SVN_ERR(write_and_checksum_temp_file(&path, &data_sha1, &data_md5, - data, pristine_tmp_dir, pool)); - SVN_ERR(svn_wc__db_pristine_install(db, path, data_sha1, data_md5, pool)); + svn_wc__db_install_data_t *install_data; + svn_stream_t *pristine_stream; + apr_size_t sz; + + SVN_ERR(svn_wc__db_pristine_prepare_install(&pristine_stream, + &install_data, + &data_sha1, &data_md5, + db, wc_abspath, + pool, pool)); + + sz = strlen(data); + SVN_ERR(svn_stream_write(pristine_stream, data, &sz)); + SVN_ERR(svn_stream_close(pristine_stream)); + + SVN_ERR(svn_wc__db_pristine_install(install_data, + data_sha1, data_md5, + pool)); } /* Try to install the wrong pristine text against the same checksum. * Should fail. */ { - svn_error_t *err; - const char *path; - - SVN_ERR(write_and_checksum_temp_file(&path, NULL, NULL, - data2, pristine_tmp_dir, pool)); - err = svn_wc__db_pristine_install(db, path, data_sha1, data_md5, pool); - SVN_TEST_ASSERT_ERROR(err, SVN_ERR_WC_CORRUPT_TEXT_BASE); + svn_wc__db_install_data_t *install_data; + svn_stream_t *pristine_stream; + apr_size_t sz; + + SVN_ERR(svn_wc__db_pristine_prepare_install(&pristine_stream, + &install_data, + &data_sha1, &data_md5, + db, wc_abspath, + pool, pool)); + + sz = strlen(data2); + SVN_ERR(svn_stream_write(pristine_stream, data2, &sz)); + SVN_ERR(svn_stream_close(pristine_stream)); + + SVN_ERR(svn_wc__db_pristine_install(install_data, + data_sha1, data_md5, + pool)); } return SVN_NO_ERROR; @@ -319,7 +307,9 @@ reject_mismatching_text(const svn_test_opts_t *opts, } -struct svn_test_descriptor_t test_funcs[] = +static int max_threads = -1; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_OPTS_PASS(pristine_write_read, @@ -330,3 +320,5 @@ struct svn_test_descriptor_t test_funcs[] = "reject_mismatching_text"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_wc/utils.c b/subversion/tests/libsvn_wc/utils.c index 1682b98..bebfc8a 100644 --- a/subversion/tests/libsvn_wc/utils.c +++ b/subversion/tests/libsvn_wc/utils.c @@ -22,8 +22,8 @@ #include "svn_error.h" #include "svn_client.h" +#include "svn_cmdline.h" #include "svn_pools.h" -#include "private/svn_dep_compat.h" #include "utils.h" @@ -33,10 +33,26 @@ #include "../../libsvn_wc/wc-queries.h" #define SVN_WC__I_AM_WC_DB #include "../../libsvn_wc/wc_db_private.h" +#include "../../libsvn_wc/token-map.h" +svn_error_t * +svn_test__create_client_ctx(svn_client_ctx_t **ctx, + svn_test__sandbox_t *sbox, + apr_pool_t *result_pool) +{ + SVN_ERR(svn_client_create_context2(ctx, NULL, result_pool)); + + SVN_ERR(svn_test__init_auth_baton(&(*ctx)->auth_baton, + result_pool)); + + if (sbox) + (*ctx)->wc_ctx = sbox->wc_ctx; + return SVN_NO_ERROR; +} /* Create an empty repository and WC for the test TEST_NAME. Set *REPOS_URL - * to the URL of the new repository and *WC_ABSPATH to the root path of the + * to the URL of the new repository, *REPOS_DIR to its local path and + * *WC_ABSPATH to the root path of the * new WC. * * Create the repository and WC in subdirectories called @@ -46,6 +62,7 @@ * Register the repo and WC to be cleaned up when the test suite exits. */ static svn_error_t * create_repos_and_wc(const char **repos_url, + const char **repos_dir, const char **wc_abspath, const char *test_name, const svn_test_opts_t *opts, @@ -66,8 +83,6 @@ create_repos_and_wc(const char **repos_url, /* Create a repos. Register it for clean-up. Set *REPOS_URL to its path. */ { - svn_repos_t *repos; - /* Use a subpool to create the repository and then destroy the subpool so the repository's underlying filesystem is closed. If opts->fs_type is BDB this prevents any attempt to open a second environment handle @@ -75,8 +90,8 @@ create_repos_and_wc(const char **repos_url, only a single environment handle to be open per process. */ apr_pool_t *subpool = svn_pool_create(pool); - SVN_ERR(svn_test__create_repos(&repos, repos_path, opts, subpool)); - SVN_ERR(svn_uri_get_file_url_from_dirent(repos_url, repos_path, pool)); + SVN_ERR(svn_test__create_repos2(NULL, repos_url, repos_dir, repos_path, + opts, pool, subpool)); svn_pool_destroy(subpool); } @@ -86,7 +101,7 @@ create_repos_and_wc(const char **repos_url, svn_client_ctx_t *ctx; svn_opt_revision_t head_rev = { svn_opt_revision_head, {0} }; - SVN_ERR(svn_client_create_context2(&ctx, NULL, subpool)); + SVN_ERR(svn_test__create_client_ctx(&ctx, NULL, subpool)); SVN_ERR(svn_dirent_get_absolute(wc_abspath, wc_path, pool)); SVN_ERR(svn_client_checkout3(NULL, *repos_url, *wc_abspath, &head_rev, &head_rev, svn_depth_infinity, @@ -102,44 +117,151 @@ create_repos_and_wc(const char **repos_url, return SVN_NO_ERROR; } - WC_QUERIES_SQL_DECLARE_STATEMENTS(statements); svn_error_t * svn_test__create_fake_wc(const char *wc_abspath, const char *extra_statements, - apr_pool_t *result_pool, + const svn_test__nodes_data_t nodes[], + const svn_test__actual_data_t actuals[], + apr_pool_t *scratch_pool) { const char *dotsvn_abspath = svn_dirent_join(wc_abspath, ".svn", scratch_pool); - const char *db_abspath = svn_dirent_join(dotsvn_abspath, "wc.db", - scratch_pool); svn_sqlite__db_t *sdb; const char **my_statements; int i; + svn_sqlite__stmt_t *stmt; + const apr_int64_t wc_id = 1; /* Allocate MY_STATEMENTS in RESULT_POOL because the SDB will continue to * refer to it over its lifetime. */ - my_statements = apr_palloc(result_pool, 6 * sizeof(const char *)); + my_statements = apr_palloc(scratch_pool, 7 * sizeof(const char *)); my_statements[0] = statements[STMT_CREATE_SCHEMA]; my_statements[1] = statements[STMT_CREATE_NODES]; my_statements[2] = statements[STMT_CREATE_NODES_TRIGGERS]; my_statements[3] = statements[STMT_CREATE_EXTERNALS]; - my_statements[4] = extra_statements; - my_statements[5] = NULL; + my_statements[4] = statements[STMT_INSTALL_SCHEMA_STATISTICS]; + my_statements[5] = extra_statements; + my_statements[6] = NULL; /* Create fake-wc/SUBDIR/.svn/ for placing the metadata. */ SVN_ERR(svn_io_make_dir_recursively(dotsvn_abspath, scratch_pool)); - - svn_error_clear(svn_io_remove_file2(db_abspath, FALSE, scratch_pool)); SVN_ERR(svn_wc__db_util_open_db(&sdb, wc_abspath, "wc.db", svn_sqlite__mode_rwcreate, - FALSE /* exclusive */, my_statements, - result_pool, scratch_pool)); + FALSE /* exclusive */, 0 /* timeout */, + my_statements, + scratch_pool, scratch_pool)); for (i = 0; my_statements[i] != NULL; i++) SVN_ERR(svn_sqlite__exec_statements(sdb, /* my_statements[] */ i)); + SVN_ERR(svn_sqlite__close(sdb)); + + if (!nodes && !actuals) + return SVN_NO_ERROR; + + /* Re-open with normal set of statements */ + SVN_ERR(svn_wc__db_util_open_db(&sdb, wc_abspath, "wc.db", + svn_sqlite__mode_readwrite, + FALSE /* exclusive */, 0 /* timeout */, + statements, + scratch_pool, scratch_pool)); + + if (nodes) + { + SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, + STMT_INSERT_NODE)); + + for (i = 0; nodes[i].local_relpath; i++) + { + SVN_ERR(svn_sqlite__bindf(stmt, "isdsnnns", + wc_id, + nodes[i].local_relpath, + nodes[i].op_depth, + nodes[i].local_relpath[0] + ? svn_relpath_dirname(nodes[i].local_relpath, + scratch_pool) + : NULL, + nodes[i].presence)); + + if (nodes[i].repos_relpath) + { + SVN_ERR(svn_sqlite__bind_int64(stmt, 5, nodes[i].repos_id)); + SVN_ERR(svn_sqlite__bind_text(stmt, 6, nodes[i].repos_relpath)); + SVN_ERR(svn_sqlite__bind_revnum(stmt, 7, nodes[i].revision)); + } + + if (nodes[i].depth) + SVN_ERR(svn_sqlite__bind_text(stmt, 9, nodes[i].depth)); + + if (nodes[i].kind != 0) + SVN_ERR(svn_sqlite__bind_token(stmt, 10, kind_map, nodes[i].kind)); + + if (nodes[i].last_author || nodes[i].last_date) + { + SVN_ERR(svn_sqlite__bind_revnum(stmt, 11, nodes[i].last_revision)); + SVN_ERR(svn_sqlite__bind_int64(stmt, 12, nodes[i].last_date)); + SVN_ERR(svn_sqlite__bind_text(stmt, 13, nodes[i].last_author)); + } + + if (nodes[i].checksum) + SVN_ERR(svn_sqlite__bind_text(stmt, 14, nodes[i].checksum)); + + if (nodes[i].properties) + SVN_ERR(svn_sqlite__bind_text(stmt, 15, nodes[i].properties)); + + if (nodes[i].recorded_size || nodes[i].recorded_time) + { + SVN_ERR(svn_sqlite__bind_int64(stmt, 16, nodes[i].recorded_size)); + SVN_ERR(svn_sqlite__bind_int64(stmt, 17, nodes[i].recorded_time)); + } + + /* 18 is DAV cache */ + + if (nodes[i].symlink_target) + SVN_ERR(svn_sqlite__bind_text(stmt, 19, nodes[i].symlink_target)); + + if (nodes[i].file_external) + SVN_ERR(svn_sqlite__bind_int(stmt, 20, 1)); + + if (nodes[i].moved_to) + SVN_ERR(svn_sqlite__bind_text(stmt, 21, nodes[i].moved_to)); + + if (nodes[i].moved_here) + SVN_ERR(svn_sqlite__bind_int(stmt, 22, 1)); + + if (nodes[i].inherited_props) + SVN_ERR(svn_sqlite__bind_text(stmt, 23, nodes[i].inherited_props)); + + SVN_ERR(svn_sqlite__step_done(stmt)); + } + } + + if (actuals) + { + SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, + STMT_INSERT_ACTUAL_NODE)); + + for (i = 0; actuals[i].local_relpath; i++) + { + SVN_ERR(svn_sqlite__bindf(stmt, "isssss", + wc_id, + actuals[i].local_relpath, + actuals[i].local_relpath[0] + ? svn_relpath_dirname(actuals[i].local_relpath, + scratch_pool) + : NULL, + actuals[i].properties, + actuals[i].changelist, + actuals[i].conflict_data)); + + SVN_ERR(svn_sqlite__step_done(stmt)); + } + } + + SVN_ERR(svn_sqlite__close(sdb)); + return SVN_NO_ERROR; } @@ -151,19 +273,28 @@ svn_test__sandbox_create(svn_test__sandbox_t *sandbox, apr_pool_t *pool) { sandbox->pool = pool; - SVN_ERR(create_repos_and_wc(&sandbox->repos_url, &sandbox->wc_abspath, + SVN_ERR(create_repos_and_wc(&sandbox->repos_url, &sandbox->repos_dir, + &sandbox->wc_abspath, test_name, opts, pool)); SVN_ERR(svn_wc_context_create(&sandbox->wc_ctx, NULL, pool, pool)); return SVN_NO_ERROR; } -void +svn_error_t * sbox_file_write(svn_test__sandbox_t *b, const char *path, const char *text) { - FILE *f = fopen(sbox_wc_path(b, path), "w"); + apr_file_t *f; - fputs(text, f); - fclose(f); + SVN_ERR(svn_io_file_open(&f, sbox_wc_path(b, path), + (APR_WRITE | APR_CREATE | APR_TRUNCATE), + APR_OS_DEFAULT, + b->pool)); + + SVN_ERR(svn_io_file_write_full(f, text, strlen(text), NULL, b->pool)); + + SVN_ERR(svn_io_file_close(f, b->pool)); + + return SVN_NO_ERROR; } svn_error_t * @@ -175,7 +306,8 @@ sbox_wc_add(svn_test__sandbox_t *b, const char *path) parent_abspath = svn_dirent_dirname(path, b->pool); SVN_ERR(svn_wc__acquire_write_lock(NULL, b->wc_ctx, parent_abspath, FALSE, b->pool, b->pool)); - SVN_ERR(svn_wc_add_from_disk2(b->wc_ctx, path, NULL /*props*/, + SVN_ERR(svn_wc_add_from_disk3(b->wc_ctx, path, NULL /*props*/, + FALSE /* skip checks */, NULL, NULL, b->pool)); SVN_ERR(svn_wc__release_write_lock(b->wc_ctx, parent_abspath, b->pool)); return SVN_NO_ERROR; @@ -241,8 +373,7 @@ sbox_wc_copy_url(svn_test__sandbox_t *b, const char *from_url, scratch_pool, 1, sizeof(svn_client_copy_source_t *)); - SVN_ERR(svn_client_create_context2(&ctx, NULL, scratch_pool)); - ctx->wc_ctx = b->wc_ctx; + SVN_ERR(svn_test__create_client_ctx(&ctx, b, scratch_pool)); if (SVN_IS_VALID_REVNUM(revision)) { @@ -258,8 +389,14 @@ sbox_wc_copy_url(svn_test__sandbox_t *b, const char *from_url, APR_ARRAY_PUSH(sources, svn_client_copy_source_t *) = src; - SVN_ERR(svn_client_copy6(sources, sbox_wc_path(b, to_path), - FALSE, FALSE, FALSE, NULL, NULL, NULL, + SVN_ERR(svn_client_copy7(sources, sbox_wc_path(b, to_path), + FALSE /* copy_as_child */, + FALSE /* make_parents */, + FALSE /* ignore_externals */, + FALSE /* metadata_only */, + FALSE, NULL /* pin_external */, + NULL /* revprops */, + NULL, NULL, /* commit_callback */ ctx, scratch_pool)); ctx->wc_ctx = NULL; @@ -283,7 +420,11 @@ sbox_wc_revert(svn_test__sandbox_t *b, const char *path, svn_depth_t depth) SVN_ERR(svn_wc__acquire_write_lock(&lock_root_abspath, b->wc_ctx, dir_abspath, FALSE /* lock_anchor */, b->pool, b->pool)); - SVN_ERR(svn_wc_revert4(b->wc_ctx, abspath, depth, FALSE, NULL, + SVN_ERR(svn_wc_revert5(b->wc_ctx, abspath, depth, + FALSE /* use_commit_times */, + NULL /* changelist_filter */, + FALSE /* clear_changelists */, + FALSE /* metadata_only */, NULL, NULL, /* cancel baton + func */ NULL, NULL, /* notify baton + func */ b->pool)); @@ -335,8 +476,7 @@ sbox_wc_commit_ex(svn_test__sandbox_t *b, apr_pool_t *scratch_pool = svn_pool_create(b->pool); svn_error_t *err; - SVN_ERR(svn_client_create_context2(&ctx, NULL, scratch_pool)); - ctx->wc_ctx = b->wc_ctx; + SVN_ERR(svn_test__create_client_ctx(&ctx, b, scratch_pool)); /* A successfull commit doesn't close the ra session, but leaves that to the caller. This leaves the BDB handle open, which might cause @@ -377,12 +517,19 @@ sbox_wc_update_depth(svn_test__sandbox_t *b, sizeof(const char *)); svn_opt_revision_t revision; - revision.kind = svn_opt_revision_number; - revision.value.number = revnum; + if (SVN_IS_VALID_REVNUM(revnum)) + { + revision.kind = svn_opt_revision_number; + revision.value.number = revnum; + } + else + { + revision.kind = svn_opt_revision_head; + } APR_ARRAY_PUSH(paths, const char *) = sbox_wc_path(b, path); - SVN_ERR(svn_client_create_context2(&ctx, NULL, b->pool)); - ctx->wc_ctx = b->wc_ctx; + SVN_ERR(svn_test__create_client_ctx(&ctx, b, b->pool)); + return svn_client_update4(&result_revs, paths, &revision, depth, sticky, FALSE, FALSE, FALSE, FALSE, ctx, b->pool); @@ -405,9 +552,9 @@ sbox_wc_switch(svn_test__sandbox_t *b, svn_revnum_t result_rev; svn_opt_revision_t head_rev = { svn_opt_revision_head, {0} }; - url = apr_pstrcat(b->pool, b->repos_url, url, (char*)NULL); - SVN_ERR(svn_client_create_context2(&ctx, NULL, b->pool)); - ctx->wc_ctx = b->wc_ctx; + url = apr_pstrcat(b->pool, b->repos_url, url, SVN_VA_NULL); + SVN_ERR(svn_test__create_client_ctx(&ctx, b, b->pool)); + return svn_client_switch3(&result_rev, sbox_wc_path(b, path), url, &head_rev, &head_rev, depth, FALSE /* depth_is_sticky */, @@ -452,14 +599,43 @@ sbox_wc_resolve(svn_test__sandbox_t *b, const char *path, svn_depth_t depth, } svn_error_t * +sbox_wc_resolve_prop(svn_test__sandbox_t *b, const char *path, + const char *propname, + svn_wc_conflict_choice_t conflict_choice) +{ + const char *lock_abspath; + svn_error_t *err; + + SVN_ERR(svn_wc__acquire_write_lock_for_resolve(&lock_abspath, b->wc_ctx, + sbox_wc_path(b, path), + b->pool, b->pool)); + err = svn_wc__resolve_conflicts(b->wc_ctx, sbox_wc_path(b, path), + svn_depth_empty, + FALSE, + propname, + FALSE, + conflict_choice, + NULL, NULL, /* conflict func */ + NULL, NULL, /* cancellation */ + NULL, NULL, /* notification */ + b->pool); + + err = svn_error_compose_create(err, svn_wc__release_write_lock(b->wc_ctx, + lock_abspath, + b->pool)); + return err; +} + + +svn_error_t * sbox_wc_move(svn_test__sandbox_t *b, const char *src, const char *dst) { svn_client_ctx_t *ctx; apr_array_header_t *paths = apr_array_make(b->pool, 1, sizeof(const char *)); - SVN_ERR(svn_client_create_context2(&ctx, NULL, b->pool)); - ctx->wc_ctx = b->wc_ctx; + SVN_ERR(svn_test__create_client_ctx(&ctx, b, b->pool)); + APR_ARRAY_PUSH(paths, const char *) = sbox_wc_path(b, src); return svn_client_move7(paths, sbox_wc_path(b, dst), FALSE /* move_as_child */, @@ -482,8 +658,8 @@ sbox_wc_propset(svn_test__sandbox_t *b, sizeof(const char *)); svn_string_t *pval = value ? svn_string_create(value, b->pool) : NULL; - SVN_ERR(svn_client_create_context2(&ctx, NULL, b->pool)); - ctx->wc_ctx = b->wc_ctx; + SVN_ERR(svn_test__create_client_ctx(&ctx, b, b->pool)); + APR_ARRAY_PUSH(paths, const char *) = sbox_wc_path(b, path); return svn_client_propset_local(name, pval, paths, svn_depth_empty, TRUE /* skip_checks */, @@ -497,8 +673,7 @@ sbox_wc_relocate(svn_test__sandbox_t *b, apr_pool_t *scratch_pool = b->pool; svn_client_ctx_t *ctx; - SVN_ERR(svn_client_create_context2(&ctx, NULL, scratch_pool)); - ctx->wc_ctx = b->wc_ctx; + SVN_ERR(svn_test__create_client_ctx(&ctx, b, scratch_pool)); SVN_ERR(svn_client_relocate2(b->wc_abspath, b->repos_url, new_repos_url, FALSE, ctx,scratch_pool)); @@ -517,7 +692,7 @@ sbox_add_and_commit_greek_tree(svn_test__sandbox_t *b) { if (node->contents) { - sbox_file_write(b, node->path, node->contents); + SVN_ERR(sbox_file_write(b, node->path, node->contents)); SVN_ERR(sbox_wc_add(b, node->path)); } else diff --git a/subversion/tests/libsvn_wc/utils.h b/subversion/tests/libsvn_wc/utils.h index 3004634..260139d 100644 --- a/subversion/tests/libsvn_wc/utils.h +++ b/subversion/tests/libsvn_wc/utils.h @@ -25,6 +25,8 @@ #include <apr_pools.h> #include "svn_error.h" +#include "svn_client.h" + #include "../svn_test.h" #ifdef __cplusplus @@ -53,6 +55,8 @@ typedef struct svn_test__sandbox_t svn_wc_context_t *wc_ctx; /* The repository URL. */ const char *repos_url; + /* Local path to the repository */ + const char *repos_dir; /* The absolute local path of the WC root. */ const char *wc_abspath; /* A pool that can be used for all allocations. */ @@ -83,7 +87,7 @@ svn_test__sandbox_create(svn_test__sandbox_t *sandbox, (svn_dirent_join((b)->wc_abspath, (path), (b)->pool)) /* Create a file on disk at PATH, with TEXT as its content. */ -void +svn_error_t * sbox_file_write(svn_test__sandbox_t *b, const char *path, const char *text); /* Schedule for addition the single node that exists on disk at PATH, @@ -162,6 +166,12 @@ sbox_wc_resolve(svn_test__sandbox_t *b, const char *path, svn_depth_t depth, /* */ svn_error_t * +sbox_wc_resolve_prop(svn_test__sandbox_t *b, const char *path, + const char *propname, + svn_wc_conflict_choice_t conflict_choice); + +/* */ +svn_error_t * sbox_wc_move(svn_test__sandbox_t *b, const char *src, const char *dst); /* Set property NAME to VALUE on PATH. If VALUE=NULL, delete the property. */ @@ -175,6 +185,39 @@ sbox_wc_propset(svn_test__sandbox_t *b, svn_error_t * sbox_add_and_commit_greek_tree(svn_test__sandbox_t *b); +/* Initial data to store in NODES */ +typedef struct svn_test__nodes_data_t +{ + int op_depth; + const char *local_relpath; + const char *presence; + int repos_id; + const char *repos_relpath; + svn_revnum_t revision; + svn_boolean_t moved_here; + const char *moved_to; + svn_node_kind_t kind; + const char *properties; + const char *depth; + const char *checksum; + const char *symlink_target; + svn_revnum_t last_revision; + apr_time_t last_date; + const char *last_author; + svn_boolean_t file_external; + const char *inherited_props; + svn_filesize_t recorded_size; + apr_time_t recorded_time; +} svn_test__nodes_data_t; + +/* Initial data to store in ACTUAL */ +typedef struct svn_test__actual_data_t +{ + const char *local_relpath; + const char *properties; + const char *changelist; + const char *conflict_data; +} svn_test__actual_data_t; /* Create a WC directory at WC_ABSPATH containing a fake WC DB, generated by * executing the SQL statements EXTRA_STATEMENTS in addition to the standard @@ -182,10 +225,18 @@ sbox_add_and_commit_greek_tree(svn_test__sandbox_t *b); svn_error_t * svn_test__create_fake_wc(const char *wc_abspath, const char *extra_statements, - apr_pool_t *result_pool, + const svn_test__nodes_data_t nodes[], + const svn_test__actual_data_t actuals[], apr_pool_t *scratch_pool); +/* Create a client context for the specified sandbox */ +svn_error_t * +svn_test__create_client_ctx(svn_client_ctx_t **ctx, + svn_test__sandbox_t *sbox, + apr_pool_t *result_pool); + + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/subversion/tests/libsvn_wc/wc-lock-tester.c b/subversion/tests/libsvn_wc/wc-lock-tester.c index d72c536..1daee66 100644 --- a/subversion/tests/libsvn_wc/wc-lock-tester.c +++ b/subversion/tests/libsvn_wc/wc-lock-tester.c @@ -35,16 +35,19 @@ #include "private/svn_wc_private.h" #include "../../libsvn_wc/wc.h" #include "../../libsvn_wc/wc_db.h" +#include "../../libsvn_wc/workqueue.h" #include "svn_private_config.h" #define USAGE_MSG \ - "Usage: %s [-r|-1] DIRNAME\n" \ + "Usage: %s [-1|-r|-w] DIRNAME\n" \ "\n" \ - "Locks one directory (-1), or a tree recursively (-r)\n" + "Locks one directory (-1), or a tree recursively (-r), or locks\n" \ + "recursively and creates an outstanding work queue item (-w)\n" static svn_error_t * obtain_lock(const char *path, svn_boolean_t recursive, + svn_boolean_t populate_work_queue, apr_pool_t *scratch_pool) { const char *local_abspath; @@ -52,9 +55,7 @@ obtain_lock(const char *path, svn_boolean_t recursive, SVN_ERR(svn_path_cstring_to_utf8(&path, path, scratch_pool)); SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool)); - - SVN_ERR(svn_wc_context_create(&wc_ctx, NULL, scratch_pool, - scratch_pool)); + SVN_ERR(svn_wc_context_create(&wc_ctx, NULL, scratch_pool, scratch_pool)); if (recursive) { @@ -68,6 +69,19 @@ obtain_lock(const char *path, svn_boolean_t recursive, scratch_pool)); } + if (populate_work_queue) + { + svn_skel_t *work_item; + + /* Add an arbitrary work item to the work queue for DB, but don't + * run the work queue. */ + SVN_ERR(svn_wc__wq_build_sync_file_flags(&work_item, wc_ctx->db, + local_abspath, scratch_pool, + scratch_pool)); + SVN_ERR(svn_wc__db_wq_add(wc_ctx->db, local_abspath, work_item, + scratch_pool)); + } + SVN_ERR(svn_cmdline_printf(scratch_pool, "Lock on '%s' obtained, and we " "are not going to release it.\n", svn_dirent_local_style(local_abspath, @@ -83,9 +97,11 @@ main(int argc, const char *argv[]) int exit_code = EXIT_SUCCESS; svn_error_t *err; svn_boolean_t recursive; + svn_boolean_t populate_work_queue; if (argc != 3 - || (strcmp(argv[1], "-1") && apr_strnatcmp(argv[1], "-r"))) + || (strcmp(argv[1], "-1") && apr_strnatcmp(argv[1], "-r") && + apr_strnatcmp(argv[1], "-w"))) { fprintf(stderr, USAGE_MSG, argv[0]); exit(EXIT_FAILURE); @@ -100,9 +116,10 @@ main(int argc, const char *argv[]) /* set up the global pool */ pool = svn_pool_create(NULL); - recursive = (strcmp(argv[1], "-1") != 0); + populate_work_queue = (strcmp(argv[1], "-w") == 0); + recursive = ((strcmp(argv[1], "-1") != 0) || populate_work_queue); - err = obtain_lock(argv[2], recursive, pool); + err = obtain_lock(argv[2], recursive, populate_work_queue, pool); if (err) { diff --git a/subversion/tests/libsvn_wc/wc-queries-test.c b/subversion/tests/libsvn_wc/wc-queries-test.c index 0621720..d63aa57 100644 --- a/subversion/tests/libsvn_wc/wc-queries-test.c +++ b/subversion/tests/libsvn_wc/wc-queries-test.c @@ -22,6 +22,7 @@ */ #include "svn_pools.h" +#include "svn_hash.h" #include "svn_ctype.h" #include "private/svn_dep_compat.h" @@ -30,22 +31,17 @@ #include "../svn_test.h" #ifdef SVN_SQLITE_INLINE -/* Include sqlite3 inline, making all symbols private. */ - #define SQLITE_API static - #ifdef __APPLE__ - #include <Availability.h> - #if __MAC_OS_X_VERSION_MIN_REQUIRED < 1060 - /* <libkern/OSAtomic.h> is included on OS X by sqlite3.c, and - on old systems (Leopard or older), it cannot be compiled - with -std=c89 because it uses inline. This is a work-around. */ - #define inline __inline__ - #include <libkern/OSAtomic.h> - #undef inline - #endif - #endif - #include <sqlite3.c> +/* Import the sqlite3 API vtable from sqlite3wrapper.c */ +# define SQLITE_OMIT_DEPRECATED +# include <sqlite3ext.h> +extern const sqlite3_api_routines *const svn_sqlite3__api_funcs; +extern int (*const svn_sqlite3__api_initialize)(void); +extern int (*const svn_sqlite3__api_config)(int, ...); +# define sqlite3_api svn_sqlite3__api_funcs +# define sqlite3_initialize svn_sqlite3__api_initialize +# define sqlite3_config svn_sqlite3__api_config #else - #include <sqlite3.h> +# include <sqlite3.h> #endif #include "../../libsvn_wc/wc-queries.h" @@ -56,7 +52,7 @@ WC_QUERIES_SQL_DECLARE_STATEMENT_INFO(wc_query_info); /* The first query after the normal wc queries */ #define STMT_SCHEMA_FIRST STMT_CREATE_SCHEMA -#define SQLITE_ERR(x) \ +#define SQLITE_ERR(x) do \ { \ int sqlite_err__temp = (x); \ if (sqlite_err__temp != SQLITE_OK) \ @@ -101,6 +97,7 @@ static const int slow_statements[] = /* Full temporary table read */ STMT_INSERT_ACTUAL_EMPTIES, + STMT_INSERT_ACTUAL_EMPTIES_FILES, STMT_SELECT_REVERT_LIST_RECURSIVE, STMT_SELECT_DELETE_LIST, STMT_SELECT_UPDATE_MOVE_LIST, @@ -177,15 +174,15 @@ create_memory_db(sqlite3 **db, static svn_error_t * test_sqlite_version(apr_pool_t *scratch_pool) { - printf("DBG: Using Sqlite %s\n", sqlite3_version); + printf("DBG: Using Sqlite %s\n", sqlite3_libversion()); if (sqlite3_libversion_number() != SQLITE_VERSION_NUMBER) - printf("DBG: Compiled against Sqlite %s", SQLITE_VERSION); + printf("DBG: Compiled against Sqlite %s\n", SQLITE_VERSION); if (sqlite3_libversion_number() < SQLITE_VERSION_NUMBER) return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, "Compiled against Sqlite %s (at runtime we have Sqlite %s)", - SQLITE_VERSION, sqlite3_version); + SQLITE_VERSION, sqlite3_libversion()); #if !SQLITE_VERSION_AT_LEAST(3, 7, 9) return svn_error_create(SVN_ERR_TEST_FAILED, NULL, @@ -307,14 +304,21 @@ parse_explanation_item(struct explanation_item **parsed_item, item->search = TRUE; /* Search or scan */ token = apr_strtok(NULL, " ", &last); - if (!MATCH_TOKEN(token, "TABLE")) + if (MATCH_TOKEN(token, "TABLE")) + { + item->table = apr_strtok(NULL, " ", &last); + } + else if (MATCH_TOKEN(token, "SUBQUERY")) + { + item->table = apr_psprintf(result_pool, "SUBQUERY-%s", + apr_strtok(NULL, " ", &last)); + } + else { printf("DBG: Expected 'TABLE', got '%s' in '%s'\n", token, text); return SVN_NO_ERROR; /* Nothing to parse */ } - item->table = apr_strtok(NULL, " ", &last); - token = apr_strtok(NULL, " ", &last); /* Skip alias */ @@ -418,7 +422,7 @@ parse_explanation_item(struct explanation_item **parsed_item, return SVN_NO_ERROR; } - /* Parsing successfull */ + /* Parsing successful */ } else if (MATCH_TOKEN(item->operation, "EXECUTE")) { @@ -606,7 +610,7 @@ test_query_expectations(apr_pool_t *scratch_pool) apr_pstrcat(iterpool, "EXPLAIN QUERY PLAN ", wc_queries[i], - NULL), + SVN_VA_NULL), -1, &stmt, &tail); if (r != SQLITE_OK) @@ -744,6 +748,105 @@ test_query_expectations(apr_pool_t *scratch_pool) return warnings; } +static svn_error_t * +test_query_duplicates(apr_pool_t *scratch_pool) +{ + sqlite3 *sdb; + int i; + apr_pool_t *iterpool = svn_pool_create(scratch_pool); + svn_error_t *warnings = NULL; + svn_boolean_t supports_query_info; + apr_hash_t *sha_to_query = apr_hash_make(scratch_pool); + + SVN_ERR(create_memory_db(&sdb, scratch_pool)); + + SVN_ERR(supported_explain_query_plan(&supports_query_info, sdb, + scratch_pool)); + if (!supports_query_info) + { + SQLITE_ERR(sqlite3_close(sdb)); + return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL, + "Sqlite doesn't support EXPLAIN QUERY PLAN"); + } + + for (i = 0; i < STMT_SCHEMA_FIRST; i++) + { + sqlite3_stmt *stmt; + const char *tail; + int r; + svn_stringbuf_t *result; + svn_checksum_t *checksum; + + if (is_schema_statement(i)) + continue; + + /* Prepare statement to find if it is a single statement. */ + r = sqlite3_prepare_v2(sdb, wc_queries[i], -1, &stmt, &tail); + + if (r != SQLITE_OK) + continue; /* Parse failure is already reported by 'test_parable' */ + + SQLITE_ERR(sqlite3_finalize(stmt)); + if (tail[0] != '\0') + continue; /* Multi-queries are currently not testable */ + + svn_pool_clear(iterpool); + + r = sqlite3_prepare_v2(sdb, + apr_pstrcat(iterpool, + "EXPLAIN ", + wc_queries[i], + SVN_VA_NULL), + -1, &stmt, &tail); + + if (r != SQLITE_OK) + continue; /* EXPLAIN not enabled or doesn't support this query */ + + result = svn_stringbuf_create_empty(iterpool); + + while (SQLITE_ROW == (r = sqlite3_step(stmt))) + { + int col; + + for (col = 0; col < sqlite3_column_count(stmt); col++) + { + const char *txt = (const char*)sqlite3_column_text(stmt, col); + if (txt) + svn_stringbuf_appendcstr(result, txt); + + svn_stringbuf_appendcstr(result, "|"); + } + + svn_stringbuf_appendcstr(result, "\n"); + } + + SQLITE_ERR(sqlite3_reset(stmt)); + SQLITE_ERR(sqlite3_finalize(stmt)); + + SVN_ERR(svn_checksum(&checksum, svn_checksum_sha1, + result->data, result->len, + iterpool)); + + { + const char *hex = svn_checksum_to_cstring(checksum, scratch_pool); + const char *other; + + other = svn_hash_gets(sha_to_query, hex); + if (other) + { + warnings = svn_error_createf(SVN_ERR_TEST_FAILED, warnings, + "Query %s has an identical execution plan as %s", + wc_query_info[i][0], other); + } + else + svn_hash_sets(sha_to_query, hex, wc_query_info[i][0]); + } + } + SQLITE_ERR(sqlite3_close(sdb)); /* Close the DB if ok; otherwise leaked */ + + return warnings; +} + /* Helper to verify a bit of data in the sqlite3 statistics */ static int parse_stat_data(const char *stat) @@ -824,6 +927,15 @@ test_schema_statistics(apr_pool_t *scratch_pool) "VALUES (1, '', '')", NULL, NULL, NULL)); + SQLITE_ERR( + sqlite3_exec(sdb, + "INSERT INTO EXTERNALS (wc_id, local_relpath," + " parent_relpath, repos_id," + " presence, kind, def_local_relpath," + " def_repos_relpath) " + "VALUES (1, 'subdir', '', 1, 'normal', 'dir', '', '')", + NULL, NULL, NULL)); + /* These are currently not necessary for query optimization, but it's better to tell Sqlite how we intend to use this table anyway */ SQLITE_ERR( @@ -882,7 +994,62 @@ test_schema_statistics(apr_pool_t *scratch_pool) return SVN_NO_ERROR; } -struct svn_test_descriptor_t test_funcs[] = +/* An SQLite application defined function that allows SQL queries to + use "relpath_depth(local_relpath)". */ +static void relpath_depth_sqlite(sqlite3_context* context, + int argc, + sqlite3_value* values[]) +{ + SVN_ERR_MALFUNCTION_NO_RETURN(); /* STUB! */ +} + +/* Parse all verify/check queries */ +static svn_error_t * +test_verify_parsable(apr_pool_t *scratch_pool) +{ + sqlite3 *sdb; + int i; + + SVN_ERR(create_memory_db(&sdb, scratch_pool)); + + SQLITE_ERR(sqlite3_create_function(sdb, "relpath_depth", 1, SQLITE_ANY, NULL, + relpath_depth_sqlite, NULL, NULL)); + + for (i=STMT_VERIFICATION_TRIGGERS; wc_queries[i]; i++) + { + sqlite3_stmt *stmt; + const char *text = wc_queries[i]; + + /* Some of our statement texts contain multiple queries. We prepare + them all. */ + while (*text != '\0') + { + const char *tail; + int r = sqlite3_prepare_v2(sdb, text, -1, &stmt, &tail); + + if (r != SQLITE_OK) + return svn_error_createf(SVN_ERR_SQLITE_ERROR, NULL, + "Preparing %s failed: %s\n%s", + wc_query_info[i][0], + sqlite3_errmsg(sdb), + text); + + SQLITE_ERR(sqlite3_finalize(stmt)); + + /* Continue after the current statement */ + text = tail; + } + } + + SQLITE_ERR(sqlite3_close(sdb)); /* Close the DB if ok; otherwise leaked */ + + return SVN_NO_ERROR; +} + + +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS2(test_sqlite_version, @@ -891,7 +1058,13 @@ struct svn_test_descriptor_t test_funcs[] = "queries are parsable"), SVN_TEST_PASS2(test_query_expectations, "test query expectations"), + SVN_TEST_PASS2(test_query_duplicates, + "test query duplicates"), SVN_TEST_PASS2(test_schema_statistics, "test schema statistics"), + SVN_TEST_PASS2(test_verify_parsable, + "verify queries are parsable"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_wc/wc-test-queries.h b/subversion/tests/libsvn_wc/wc-test-queries.h new file mode 100644 index 0000000..4b5060c --- /dev/null +++ b/subversion/tests/libsvn_wc/wc-test-queries.h @@ -0,0 +1,112 @@ +/* This file is automatically generated from wc-test-queries.sql and .dist_sandbox/subversion-1.9.7/subversion/tests/libsvn_wc/token-map.h. + * Do not edit this file -- edit the source and rerun gen-make.py */ + +#define STMT_SELECT_NODES_INFO 0 +#define STMT_0_INFO {"STMT_SELECT_NODES_INFO", NULL} +#define STMT_0 \ + "SELECT op_depth, n.presence, n.local_relpath, revision, " \ + " repos_path, file_external, def_local_relpath, moved_to, moved_here, " \ + " properties " \ + "FROM nodes n " \ + "LEFT OUTER JOIN externals e " \ + " ON n.wc_id = e.wc_id " \ + " AND n.local_relpath = e.local_relpath " \ + "WHERE n.wc_id = ?1 " \ + " AND (n.local_relpath = ?2 OR (((n.local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((n.local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END))) " \ + "" + +#define STMT_SELECT_ACTUAL_INFO 1 +#define STMT_1_INFO {"STMT_SELECT_ACTUAL_INFO", NULL} +#define STMT_1 \ + "SELECT local_relpath " \ + "FROM actual_node " \ + "WHERE wc_id = ?1 " \ + " AND conflict_data is NOT NULL " \ + " AND (local_relpath = ?2 OR (((local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END))) " \ + "" + +#define STMT_DELETE_NODES 2 +#define STMT_2_INFO {"STMT_DELETE_NODES", NULL} +#define STMT_2 \ + "DELETE FROM nodes; " \ + "" + +#define STMT_INSERT_NODE 3 +#define STMT_3_INFO {"STMT_INSERT_NODE", NULL} +#define STMT_3 \ + "INSERT INTO nodes (local_relpath, op_depth, presence, repos_path, " \ + " revision, parent_relpath, moved_to, moved_here, " \ + " properties, wc_id, repos_id, kind, " \ + " depth) " \ + " VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, 1, " \ + " CASE WHEN ?3 != 'base-deleted' THEN 1 END, " \ + " 'dir', " \ + " CASE WHEN ?3 in ('normal', 'incomplete') " \ + " THEN 'infinity' END) " \ + "" + +#define STMT_DELETE_ACTUAL 4 +#define STMT_4_INFO {"STMT_DELETE_ACTUAL", NULL} +#define STMT_4 \ + "DELETE FROM actual_node; " \ + "" + +#define STMT_INSERT_ACTUAL 5 +#define STMT_5_INFO {"STMT_INSERT_ACTUAL", NULL} +#define STMT_5 \ + "INSERT INTO actual_node (local_relpath, parent_relpath, changelist, wc_id) " \ + " VALUES (?1, ?2, ?3, 1) " \ + "" + +#define STMT_ENSURE_EMPTY_PRISTINE 6 +#define STMT_6_INFO {"STMT_ENSURE_EMPTY_PRISTINE", NULL} +#define STMT_6 \ + "INSERT OR IGNORE INTO pristine (checksum, md5_checksum, size, refcount) " \ + " VALUES ('$sha1$da39a3ee5e6b4b0d3255bfef95601890afd80709', " \ + " '$md5 $d41d8cd98f00b204e9800998ecf8427e', " \ + " 0, 0) " \ + "" + +#define STMT_NODES_SET_FILE 7 +#define STMT_7_INFO {"STMT_NODES_SET_FILE", NULL} +#define STMT_7 \ + "UPDATE nodes " \ + " SET kind = 'file', " \ + " checksum = '$sha1$da39a3ee5e6b4b0d3255bfef95601890afd80709', " \ + " depth = NULL " \ + "WHERE wc_id = 1 and local_relpath = ?1 " \ + "" + +#define STMT_SELECT_ALL_ACTUAL 8 +#define STMT_8_INFO {"STMT_SELECT_ALL_ACTUAL", NULL} +#define STMT_8 \ + "SELECT local_relpath FROM actual_node WHERE wc_id = 1 " \ + "" + +#define WC_TEST_QUERIES_SQL_DECLARE_STATEMENTS(varname) \ + static const char * const varname[] = { \ + STMT_0, \ + STMT_1, \ + STMT_2, \ + STMT_3, \ + STMT_4, \ + STMT_5, \ + STMT_6, \ + STMT_7, \ + STMT_8, \ + NULL \ + } + +#define WC_TEST_QUERIES_SQL_DECLARE_STATEMENT_INFO(varname) \ + static const char * const varname[][2] = { \ + STMT_0_INFO, \ + STMT_1_INFO, \ + STMT_2_INFO, \ + STMT_3_INFO, \ + STMT_4_INFO, \ + STMT_5_INFO, \ + STMT_6_INFO, \ + STMT_7_INFO, \ + STMT_8_INFO, \ + {NULL, NULL} \ + } diff --git a/subversion/tests/libsvn_wc/wc-test-queries.sql b/subversion/tests/libsvn_wc/wc-test-queries.sql new file mode 100644 index 0000000..613819a --- /dev/null +++ b/subversion/tests/libsvn_wc/wc-test-queries.sql @@ -0,0 +1,78 @@ +/* wc-test-queries.sql -- queries used to verify wc metadata from + * the C tests. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ + +-- STMT_SELECT_NODES_INFO +SELECT op_depth, n.presence, n.local_relpath, revision, + repos_path, file_external, def_local_relpath, moved_to, moved_here, + properties +FROM nodes n +LEFT OUTER JOIN externals e + ON n.wc_id = e.wc_id + AND n.local_relpath = e.local_relpath +WHERE n.wc_id = ?1 + AND (n.local_relpath = ?2 OR IS_STRICT_DESCENDANT_OF(n.local_relpath, ?2)) + +-- STMT_SELECT_ACTUAL_INFO +SELECT local_relpath +FROM actual_node +WHERE wc_id = ?1 + AND conflict_data is NOT NULL + AND (local_relpath = ?2 OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2)) + +-- STMT_DELETE_NODES +DELETE FROM nodes; + +-- STMT_INSERT_NODE +INSERT INTO nodes (local_relpath, op_depth, presence, repos_path, + revision, parent_relpath, moved_to, moved_here, + properties, wc_id, repos_id, kind, + depth) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, 1, + CASE WHEN ?3 != 'base-deleted' THEN 1 END, + 'dir', + CASE WHEN ?3 in ('normal', 'incomplete') + THEN 'infinity' END) + +-- STMT_DELETE_ACTUAL +DELETE FROM actual_node; + +-- STMT_INSERT_ACTUAL +INSERT INTO actual_node (local_relpath, parent_relpath, changelist, wc_id) + VALUES (?1, ?2, ?3, 1) + +-- STMT_ENSURE_EMPTY_PRISTINE +INSERT OR IGNORE INTO pristine (checksum, md5_checksum, size, refcount) + VALUES ('$sha1$da39a3ee5e6b4b0d3255bfef95601890afd80709', + '$md5 $d41d8cd98f00b204e9800998ecf8427e', + 0, 0) + +-- STMT_NODES_SET_FILE +UPDATE nodes + SET kind = 'file', + checksum = '$sha1$da39a3ee5e6b4b0d3255bfef95601890afd80709', + depth = NULL +WHERE wc_id = 1 and local_relpath = ?1 + +-- STMT_SELECT_ALL_ACTUAL +SELECT local_relpath FROM actual_node WHERE wc_id = 1 + diff --git a/subversion/tests/libsvn_wc/wc-test.c b/subversion/tests/libsvn_wc/wc-test.c index 30eb18a..8910cb0 100644 --- a/subversion/tests/libsvn_wc/wc-test.c +++ b/subversion/tests/libsvn_wc/wc-test.c @@ -23,6 +23,9 @@ #include <apr_pools.h> #include <apr_general.h> +#include <apr_md5.h> + +#define SVN_DEPRECATED #include "svn_types.h" #include "svn_io.h" @@ -71,7 +74,7 @@ struct base_origin_t }; /* Data for testing node_get_base and node_get_origin. */ -struct base_origin_t base_origin_subtests[] = +static struct base_origin_t base_origin_subtests[] = { /* file copied onto nothing */ { "A/C/copy1", -1, "iota", {"iota", 1} }, @@ -138,7 +141,6 @@ test_node_get_base(const svn_test_opts_t *opts, apr_pool_t *pool) NULL, b->wc_ctx, local_abspath, TRUE /* ignore_enoent */, - FALSE /* show_hidden */, b->pool, b->pool)); SVN_TEST_ASSERT(revision == subtest->base_rev); if (SVN_IS_VALID_REVNUM(subtest->base_rev)) @@ -181,6 +183,7 @@ test_node_get_origin(const svn_test_opts_t *opts, apr_pool_t *pool) SVN_ERR(svn_wc__node_get_origin(NULL, &revision, &repos_relpath, &repos_root_url, &repos_uuid, NULL, + NULL, b->wc_ctx, local_abspath, FALSE, b->pool, b->pool)); SVN_TEST_ASSERT(revision == subtest->origin.rev); @@ -304,11 +307,139 @@ test_externals_parse_erratic(apr_pool_t *pool) return SVN_NO_ERROR; } +static svn_error_t * +test_legacy_commit1(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + svn_wc_adm_access_t *adm_access; + const char *lambda; + + SVN_ERR(svn_test__sandbox_create(&b, "legacy_commit1", opts, pool)); + SVN_ERR(sbox_add_and_commit_greek_tree(&b)); + + SVN_ERR(sbox_wc_copy(&b, "A", "A_copied")); + + lambda = sbox_wc_path(&b, "A_copied/B/lambda"); + + + SVN_ERR(svn_io_remove_file2(lambda, FALSE, pool)); + SVN_ERR(svn_io_copy_file(sbox_wc_path(&b, "iota"), lambda, FALSE, pool)); + SVN_ERR(svn_wc_adm_open3(&adm_access, NULL, b.wc_abspath, TRUE, -1, + NULL, NULL, pool)); + + { + svn_wc_status2_t *status; + + SVN_ERR(svn_wc_status2(&status, lambda, adm_access, pool)); + + SVN_TEST_ASSERT(status != NULL); + SVN_TEST_ASSERT(status->text_status == svn_wc_status_modified); + SVN_TEST_ASSERT(status->copied == TRUE); + } + + /* Simulate a very old style svn ci . -m "QQQ" on the WC root */ + SVN_ERR(svn_wc_process_committed4(sbox_wc_path(&b, "A_copied"), adm_access, + TRUE, 12, "2014-10-01T19:00:50.966679Z", + "me", NULL, TRUE, TRUE, + NULL, pool)); + + { + unsigned char digest[APR_MD5_DIGESTSIZE]; + + /* Use the fact that iota has the same checksum to ease committing */ + + SVN_ERR(svn_io_file_checksum (digest, lambda, pool)); + + SVN_ERR(svn_wc_process_committed4(lambda, adm_access, + TRUE, 12, "2014-10-01T19:00:50.966679Z", + "me", NULL, TRUE, TRUE, + digest, pool)); + } + + { + svn_wc_status2_t *status; + + SVN_ERR(svn_wc_status2(&status, lambda, adm_access, pool)); + + /* Node is still modified, as we didn't change the text base! */ + SVN_TEST_ASSERT(status != NULL); + SVN_TEST_ASSERT(status->text_status == svn_wc_status_normal); + SVN_TEST_ASSERT(status->copied == FALSE); + } + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_legacy_commit2(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + svn_wc_adm_access_t *adm_access; + const char *lambda; + svn_wc_committed_queue_t *queue; + + SVN_ERR(svn_test__sandbox_create(&b, "legacy_commit2", opts, pool)); + SVN_ERR(sbox_add_and_commit_greek_tree(&b)); + + SVN_ERR(sbox_wc_copy(&b, "A", "A_copied")); + + lambda = sbox_wc_path(&b, "A_copied/B/lambda"); + + SVN_ERR(svn_io_remove_file2(lambda, FALSE, pool)); + SVN_ERR(svn_io_copy_file(sbox_wc_path(&b, "iota"), lambda, FALSE, pool)); + + SVN_ERR(svn_wc_adm_open3(&adm_access, NULL, b.wc_abspath, TRUE, -1, + NULL, NULL, pool)); + + { + svn_wc_status2_t *status; + + SVN_ERR(svn_wc_status2(&status, lambda, adm_access, pool)); + + SVN_TEST_ASSERT(status != NULL); + SVN_TEST_ASSERT(status->text_status == svn_wc_status_modified); + SVN_TEST_ASSERT(status->copied == TRUE); + } + + /* Simulate an old style svn ci . -m "QQQ" on the WC root */ + queue = svn_wc_committed_queue_create(pool); + SVN_ERR(svn_wc_queue_committed(&queue, sbox_wc_path(&b, "A_copied"), adm_access, + TRUE, NULL, FALSE, FALSE, NULL, pool)); + { + unsigned char digest[APR_MD5_DIGESTSIZE]; + + /* Use the fact that iota has the same checksum to ease committing */ + + SVN_ERR(svn_io_file_checksum(digest, lambda, pool)); + + SVN_ERR(svn_wc_queue_committed(&queue, lambda, adm_access, FALSE, NULL, + FALSE, FALSE, digest, pool)); + } + + SVN_ERR(svn_wc_process_committed_queue(queue, adm_access, + 12, "2014-10-01T19:00:50.966679Z", + "me", pool)); + + { + svn_wc_status2_t *status; + + SVN_ERR(svn_wc_status2(&status, lambda, adm_access, pool)); + + /* Node is still modified, as we didn't change the text base! */ + SVN_TEST_ASSERT(status != NULL); + SVN_TEST_ASSERT(status->text_status == svn_wc_status_normal); + SVN_TEST_ASSERT(status->copied == FALSE); + } + + return SVN_NO_ERROR; +} /* ---------------------------------------------------------------------- */ /* The list of test functions */ -struct svn_test_descriptor_t test_funcs[] = +static int max_threads = 2; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_OPTS_PASS(test_node_get_base, @@ -319,5 +450,11 @@ struct svn_test_descriptor_t test_funcs[] = "test svn_wc_parse_externals_description3"), SVN_TEST_PASS2(test_externals_parse_erratic, "parse erratic externals definition"), + SVN_TEST_OPTS_PASS(test_legacy_commit1, + "test legacy commit1"), + SVN_TEST_OPTS_PASS(test_legacy_commit2, + "test legacy commit2"), SVN_TEST_NULL }; + +SVN_TEST_MAIN |