Author: kotkov Date: Tue Oct 18 14:57:54 2016 New Revision: 1765452 URL: http://svn.apache.org/viewvc?rev=1765452&view=rev Log: Add a couple of failing tests for "remote move vs local edit" tree conflict resolution upon merge.
These tests exploit a few problems in how we merge the file properties and files with keywords. For now, I noted them in the implementation of the corresponding resolution option. * subversion/libsvn_client/conflicts.c (resolve_incoming_move_file_text_merge): Add a comment about what needs to be fixed. * subversion/tests/libsvn_client/conflicts-test.c (): Include "svn_props.h". (test_merge_incoming_move_file_prop_merge_conflict, test_merge_incoming_move_file_text_merge_keywords): New failing tests. (test_funcs): Reference new tests. Modified: subversion/trunk/subversion/libsvn_client/conflicts.c subversion/trunk/subversion/tests/libsvn_client/conflicts-test.c Modified: subversion/trunk/subversion/libsvn_client/conflicts.c URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/conflicts.c?rev=1765452&r1=1765451&r2=1765452&view=diff ============================================================================== --- subversion/trunk/subversion/libsvn_client/conflicts.c (original) +++ subversion/trunk/subversion/libsvn_client/conflicts.c Tue Oct 18 14:57:54 2016 @@ -6835,7 +6835,16 @@ resolve_incoming_move_file_text_merge(sv if (err) goto unlock_wc; - /* Perform the file merge. */ + /* Perform the file merge. + * + * ### Need to fix what we pass as "right_abspath" here, as svn_wc_merge5() + * ### expects to see the fulltext in repository-normal form (linefeeds, + * ### with keywords contracted). + * + * ### And I think we also need to patch up what we pass as original_props, + * ### so that conflicting properties would actually produce a conflict. + * ### See what resolve_local_move_file_merge() does. + */ err = svn_wc_merge5(&merge_content_outcome, &merge_props_outcome, ctx->wc_ctx, ancestor_abspath, local_abspath, moved_to_abspath, Modified: subversion/trunk/subversion/tests/libsvn_client/conflicts-test.c URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_client/conflicts-test.c?rev=1765452&r1=1765451&r2=1765452&view=diff ============================================================================== --- subversion/trunk/subversion/tests/libsvn_client/conflicts-test.c (original) +++ subversion/trunk/subversion/tests/libsvn_client/conflicts-test.c Tue Oct 18 14:57:54 2016 @@ -28,6 +28,7 @@ #include "svn_client.h" #include "svn_dirent_uri.h" #include "svn_hash.h" +#include "svn_props.h" #include "../svn_test.h" #include "../svn_test_fs.h" @@ -3463,6 +3464,249 @@ test_update_incoming_added_file_text_mer return SVN_NO_ERROR; } +static svn_error_t * +test_merge_incoming_move_file_prop_merge_conflict(const svn_test_opts_t *opts, + apr_pool_t *pool) +{ + svn_test__sandbox_t *b = apr_palloc(pool, sizeof(*b)); + svn_client_ctx_t *ctx; + svn_opt_revision_t opt_rev; + svn_client_conflict_t *conflict; + svn_boolean_t text_conflicted; + apr_array_header_t *props_conflicted; + svn_boolean_t tree_conflicted; + const svn_string_t *base_propval; + const svn_string_t *working_propval; + const svn_string_t *incoming_old_propval; + const svn_string_t *incoming_new_propval; + + SVN_ERR(svn_test__sandbox_create( + b, "merge_incoming_move_file_prop_merge_conflict", opts, pool)); + + SVN_ERR(sbox_add_and_commit_greek_tree(b)); + /* Add a file property. */ + SVN_ERR(sbox_wc_propset(b, "prop", "val-initial", "A/mu"));; + SVN_ERR(sbox_wc_commit(b, "")); + /* Create a copy of node "A". */ + SVN_ERR(sbox_wc_update(b, "", SVN_INVALID_REVNUM)); + SVN_ERR(sbox_wc_copy(b, "A", "A1")); + SVN_ERR(sbox_wc_commit(b, "")); + /* On "trunk", move the file and edit the property. */ + SVN_ERR(sbox_wc_move(b, "A/mu", "A/mu-moved")); + SVN_ERR(sbox_wc_propset(b, "prop", "val-trunk", "A/mu-moved"));; + SVN_ERR(sbox_wc_commit(b, "")); + /* On "branch", edit the same property. */ + SVN_ERR(sbox_wc_propset(b, "prop", "val-branch", "A1/mu"));; + SVN_ERR(sbox_wc_commit(b, "")); + + SVN_ERR(sbox_wc_update(b, "", SVN_INVALID_REVNUM)); + opt_rev.kind = svn_opt_revision_head; + opt_rev.value.number = SVN_INVALID_REVNUM; + SVN_ERR(svn_test__create_client_ctx(&ctx, b, pool)); + + /* Merge "A" to "A1". */ + SVN_ERR(svn_client_merge_peg5(svn_path_url_add_component2(b->repos_url, "A", + pool), + NULL, &opt_rev, sbox_wc_path(b, "A1"), + svn_depth_infinity, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + NULL, ctx, pool)); + + /* We should have a tree conflict in the file "mu". */ + SVN_ERR(svn_client_conflict_get(&conflict, sbox_wc_path(b, "A1/mu"), ctx, + pool, pool)); + SVN_ERR(svn_client_conflict_get_conflicted(&text_conflicted, + &props_conflicted, + &tree_conflicted, + conflict, pool, pool)); + SVN_TEST_ASSERT(!text_conflicted); + SVN_TEST_INT_ASSERT(props_conflicted->nelts, 0); + SVN_TEST_ASSERT(tree_conflicted); + + /* Check available tree conflict resolution options. */ + { + svn_client_conflict_option_id_t expected_opts[] = { + svn_client_conflict_option_postpone, + svn_client_conflict_option_accept_current_wc_state, + svn_client_conflict_option_incoming_delete_ignore, + svn_client_conflict_option_incoming_delete_accept, + -1 /* end of list */ + }; + SVN_ERR(assert_tree_conflict_options(conflict, ctx, expected_opts, pool)); + } + + SVN_ERR(svn_client_conflict_tree_get_details(conflict, ctx, pool)); + + { + svn_client_conflict_option_id_t expected_opts[] = { + svn_client_conflict_option_postpone, + svn_client_conflict_option_accept_current_wc_state, + svn_client_conflict_option_incoming_move_file_text_merge, + -1 /* end of list */ + }; + SVN_ERR(assert_tree_conflict_options(conflict, ctx, expected_opts, pool)); + } + + /* Resolve the tree conflict by moving "mu" to "mu-moved". */ + SVN_ERR(svn_client_conflict_tree_resolve_by_id( + conflict, svn_client_conflict_option_incoming_move_file_text_merge, + ctx, pool)); + + /* We should now have a property conflict in the file "mu-moved". + * + * XFAIL: Currently, there is no property conflict. + */ + SVN_ERR(svn_client_conflict_get(&conflict, sbox_wc_path(b, "A1/mu-moved"), + ctx, pool, pool)); + SVN_ERR(svn_client_conflict_get_conflicted(&text_conflicted, + &props_conflicted, + &tree_conflicted, + conflict, pool, pool)); + SVN_TEST_ASSERT(!text_conflicted); + SVN_TEST_INT_ASSERT(props_conflicted->nelts, 1); + SVN_TEST_STRING_ASSERT(APR_ARRAY_IDX(props_conflicted, 0, const char *), + "prop"); + SVN_TEST_ASSERT(!tree_conflicted); + + /* Check available property conflict resolution options. */ + { + svn_client_conflict_option_id_t expected_opts[] = { + svn_client_conflict_option_postpone, + svn_client_conflict_option_base_text, + svn_client_conflict_option_incoming_text, + svn_client_conflict_option_working_text, + svn_client_conflict_option_incoming_text_where_conflicted, + svn_client_conflict_option_working_text_where_conflicted, + svn_client_conflict_option_merged_text, + -1 /* end of list */ + }; + SVN_ERR(assert_prop_conflict_options(conflict, ctx, expected_opts, pool)); + } + + /* Check conflicted property values. */ + SVN_ERR(svn_client_conflict_prop_get_propvals(&base_propval, + &working_propval, + &incoming_old_propval, + &incoming_new_propval, + conflict, "prop", pool)); + /* ### Is this the proper expectation for base_propval? */ + SVN_TEST_STRING_ASSERT(base_propval->data, "val-branch"); + SVN_TEST_STRING_ASSERT(working_propval->data, "val-branch"); + SVN_TEST_STRING_ASSERT(incoming_old_propval->data, "val-initial"); + SVN_TEST_STRING_ASSERT(incoming_new_propval->data, "val-trunk"); + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_merge_incoming_move_file_text_merge_keywords(const svn_test_opts_t *opts, + apr_pool_t *pool) +{ + svn_test__sandbox_t *b = apr_palloc(pool, sizeof(*b)); + svn_client_ctx_t *ctx; + svn_opt_revision_t opt_rev; + svn_client_conflict_t *conflict; + svn_boolean_t text_conflicted; + apr_array_header_t *props_conflicted; + svn_boolean_t tree_conflicted; + svn_stringbuf_t *buf; + + SVN_ERR(svn_test__sandbox_create( + b, "merge_incoming_move_file_text_merge_keywords", opts, pool)); + + SVN_ERR(sbox_add_and_commit_greek_tree(b)); + /* Set svn:keywords on a file. */ + SVN_ERR(sbox_wc_propset(b, SVN_PROP_KEYWORDS, "Revision", "A/mu"));; + SVN_ERR(sbox_wc_commit(b, "")); + /* Create a copy of node "A". */ + SVN_ERR(sbox_wc_update(b, "", SVN_INVALID_REVNUM)); + SVN_ERR(sbox_wc_copy(b, "A", "A1")); + SVN_ERR(sbox_wc_commit(b, "")); + /* On "trunk", begin using keywords in the file and move it. */ + SVN_ERR(sbox_file_write(b, "A/mu", "$Revision$\n")); + SVN_ERR(sbox_wc_move(b, "A/mu", "A/mu-moved")); + SVN_ERR(sbox_wc_commit(b, "")); + /* On "branch", edit the file and make it equal to what's in trunk. */ + SVN_ERR(sbox_file_write(b, "A1/mu", "$Revision$\n")); + SVN_ERR(sbox_wc_commit(b, "")); + + SVN_ERR(sbox_wc_update(b, "", SVN_INVALID_REVNUM)); + opt_rev.kind = svn_opt_revision_head; + opt_rev.value.number = SVN_INVALID_REVNUM; + SVN_ERR(svn_test__create_client_ctx(&ctx, b, pool)); + + /* Merge "A" to "A1". */ + SVN_ERR(svn_client_merge_peg5(svn_path_url_add_component2(b->repos_url, "A", + pool), + NULL, &opt_rev, sbox_wc_path(b, "A1"), + svn_depth_infinity, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + NULL, ctx, pool)); + + /* We should have a tree conflict in the file "mu". */ + SVN_ERR(svn_client_conflict_get(&conflict, sbox_wc_path(b, "A1/mu"), ctx, + pool, pool)); + SVN_ERR(svn_client_conflict_get_conflicted(&text_conflicted, + &props_conflicted, + &tree_conflicted, + conflict, pool, pool)); + SVN_TEST_ASSERT(!text_conflicted); + SVN_TEST_INT_ASSERT(props_conflicted->nelts, 0); + SVN_TEST_ASSERT(tree_conflicted); + + /* Check available tree conflict resolution options. */ + { + svn_client_conflict_option_id_t expected_opts[] = { + svn_client_conflict_option_postpone, + svn_client_conflict_option_accept_current_wc_state, + svn_client_conflict_option_incoming_delete_ignore, + svn_client_conflict_option_incoming_delete_accept, + -1 /* end of list */ + }; + SVN_ERR(assert_tree_conflict_options(conflict, ctx, expected_opts, pool)); + } + + SVN_ERR(svn_client_conflict_tree_get_details(conflict, ctx, pool)); + + { + svn_client_conflict_option_id_t expected_opts[] = { + svn_client_conflict_option_postpone, + svn_client_conflict_option_accept_current_wc_state, + svn_client_conflict_option_incoming_move_file_text_merge, + -1 /* end of list */ + }; + SVN_ERR(assert_tree_conflict_options(conflict, ctx, expected_opts, pool)); + } + + /* Resolve the tree conflict by moving "mu" to "mu-moved". */ + SVN_ERR(svn_client_conflict_tree_resolve_by_id( + conflict, svn_client_conflict_option_incoming_move_file_text_merge, + ctx, pool)); + + /* The file should no longer be in conflict, and should not have a + * text conflict, because the contents are identical in "trunk" and + * in the "branch". + * + * XFAIL: Currently, there is an unexpected text conflict. + */ + SVN_ERR(svn_client_conflict_get(&conflict, sbox_wc_path(b, "A1/mu-moved"), + ctx, pool, pool)); + SVN_ERR(svn_client_conflict_get_conflicted(&text_conflicted, + &props_conflicted, + &tree_conflicted, + conflict, pool, pool)); + SVN_TEST_ASSERT(!text_conflicted); + SVN_TEST_INT_ASSERT(props_conflicted->nelts, 0); + SVN_TEST_ASSERT(!tree_conflicted); + + /* And it should have expected contents (with expanded keywords). */ + SVN_ERR(svn_stringbuf_from_file2(&buf, sbox_wc_path(b, "A1/mu-moved"), + pool)); + SVN_TEST_STRING_ASSERT(buf->data, "$Revision: 4 $\n"); + + return SVN_NO_ERROR; +} + /* ========================================================================== */ @@ -3523,6 +3767,10 @@ static struct svn_test_descriptor_t test "update incoming dir move with nested file move"), SVN_TEST_OPTS_XFAIL(test_update_incoming_added_file_text_merge, "update incoming add file text merge"), + SVN_TEST_OPTS_XFAIL(test_merge_incoming_move_file_prop_merge_conflict, + "merge incoming move file merge with prop conflict"), + SVN_TEST_OPTS_XFAIL(test_merge_incoming_move_file_text_merge_keywords, + "merge incoming move file merge with keywords"), SVN_TEST_NULL };