Index: subversion/tests/svn_test_fs.h =================================================================== --- subversion/tests/svn_test_fs.h (revision 902368) +++ subversion/tests/svn_test_fs.h (working copy) @@ -73,6 +73,13 @@ svn_test__create_repos(svn_repos_t **repos_p, const svn_test_opts_t *opts, apr_pool_t *pool); +/* Set URL to a "file://" url for the current directory, suffixed by the + forward-slash-style relative path SUFFIX, performing all allocation + in POOL. */ +svn_error_t * +svn_test__current_directory_url(const char **url, + const char *suffix, + apr_pool_t *pool); /* Read all data from a generic read STREAM, and return it in STRING. Allocate the svn_stringbuf_t in APRPOOL. (All data in STRING will be @@ -169,7 +176,20 @@ svn_error_t * svn_test__create_greek_tree(svn_fs_root_t *txn_root, apr_pool_t *pool); +/* Create the Greek Tree under TXN_ROOT at dir ROOT_DIR. */ +svn_error_t * +svn_test__create_greek_tree_at(svn_fs_root_t *txn_root, + const char *root_dir, + apr_pool_t *pool); +/* Create a new repository with a greek tree, trunk, branch and some + merges between them. */ +svn_error_t * +svn_test__create_blame_repository(svn_repos_t **out_repos, + const char *test_name, + const svn_test_opts_t *opts, + apr_pool_t *pool); + #ifdef __cplusplus } #endif /* __cplusplus */ Index: subversion/tests/libsvn_ra_local/ra-local-test.c =================================================================== --- subversion/tests/libsvn_ra_local/ra-local-test.c (revision 902368) +++ subversion/tests/libsvn_ra_local/ra-local-test.c (working copy) @@ -26,15 +26,6 @@ #include #include -#ifdef _MSC_VER -#include -#define getcwd _getcwd -#else -#include /* for getcwd() */ -#endif - -#include "svn_string.h" -#include "svn_utf.h" #include "svn_error.h" #include "svn_delta.h" #include "svn_ra.h" @@ -49,37 +40,7 @@ /** Helper routines. **/ -/* Helper function. Set URL to a "file://" url for the current directory, - suffixed by the forward-slash-style relative path SUFFIX, performing all - allocation in POOL. */ static svn_error_t * -current_directory_url(const char **url, - const char *suffix, - apr_pool_t *pool) -{ - /* 8KB is a lot, but it almost guarantees that any path will fit. */ - char curdir[8192]; - const char *utf8_ls_curdir, *utf8_is_curdir, *unencoded_url; - - if (! getcwd(curdir, sizeof(curdir))) - return svn_error_create(SVN_ERR_BASE, NULL, "getcwd() failed"); - - SVN_ERR(svn_utf_cstring_to_utf8(&utf8_ls_curdir, curdir, pool)); - utf8_is_curdir = svn_path_internal_style(utf8_ls_curdir, pool); - - unencoded_url = apr_psprintf(pool, "file://%s%s%s%s", - (utf8_is_curdir[0] != '/') ? "/" : "", - utf8_is_curdir, - (suffix[0] && suffix[0] != '/') ? "/" : "", - suffix); - - *url = svn_path_uri_encode(unencoded_url, pool); - - return SVN_NO_ERROR; -} - - -static svn_error_t * make_and_open_local_repos(svn_ra_session_t **session, const char *repos_name, const svn_test_opts_t *opts, @@ -94,7 +55,7 @@ make_and_open_local_repos(svn_ra_session_t **sessi SVN_ERR(svn_test__create_repos(&repos, repos_name, opts, pool)); SVN_ERR(svn_ra_initialize(pool)); - SVN_ERR(current_directory_url(&url, repos_name, pool)); + SVN_ERR(svn_test__current_directory_url(&url, repos_name, pool)); SVN_ERR(svn_ra_open3(session, url, @@ -262,7 +223,7 @@ check_split_url(const char *repos_path, /* Create a filesystem and repository */ SVN_ERR(svn_test__create_repos(&repos, repos_path, opts, pool)); - SVN_ERR(current_directory_url(&root_url, repos_path, pool)); + SVN_ERR(svn_test__current_directory_url(&root_url, repos_path, pool)); if (in_repos_path) url = apr_pstrcat(pool, root_url, in_repos_path, NULL); else Index: subversion/tests/libsvn_client/client-test.c =================================================================== --- subversion/tests/libsvn_client/client-test.c (revision 902368) +++ subversion/tests/libsvn_client/client-test.c (working copy) @@ -26,8 +26,10 @@ #include "../../libsvn_client/mergeinfo.h" #include "svn_pools.h" #include "svn_client.h" +#include "svn_ra.h" #include "../svn_test.h" +#include "../svn_test_fs.h" typedef struct { const char *path; @@ -99,8 +101,7 @@ test_elide_mergeinfo_catalog(apr_pool_t *pool) static svn_error_t * test_args_to_target_array(apr_pool_t *pool) -{ - apr_size_t i; +{ apr_size_t i; apr_pool_t *iterpool; svn_client_ctx_t *ctx; static struct { @@ -199,6 +200,92 @@ test_args_to_target_array(apr_pool_t *pool) return SVN_NO_ERROR; } + +/* Tests for svn_client_blameN() */ + +typedef struct { + svn_revnum_t rev; + const char *path; + svn_boolean_t result_of_merge; + const char *author; +} file_revs_t; + +static svn_error_t * +blame_receiver(void *baton, + apr_int64_t line_no, + svn_revnum_t revision, + apr_hash_t *rev_props, + svn_revnum_t merged_revision, + apr_hash_t *merged_rev_props, + const char *merged_path, + const char *line, + svn_boolean_t local_change, + apr_pool_t *pool) +{ + printf("%s %s\n", merged_path, line); + return SVN_NO_ERROR; +} + +static svn_error_t * +test_svn_client_blame(const svn_test_opts_t *opts, + apr_pool_t *pool) +{ + svn_repos_t *repos = NULL; + svn_fs_t *fs; + svn_revnum_t youngest_rev = 0; + apr_pool_t *subpool = svn_pool_create(pool); + svn_client_ctx_t *ctx; + svn_opt_revision_t start_rev, end_rev, peg_rev; + const char *repos_name = "test-client-blame"; + const char *url; + svn_ra_callbacks2_t *cbtable; + svn_ra_session_t *session; + svn_diff_file_options_t *diff_options = svn_diff_file_options_create(subpool); + + /* Create the repository and verify blame results. */ + SVN_ERR(svn_test__create_blame_repository(&repos, repos_name, + opts, subpool)); + fs = svn_repos_fs(repos); + + SVN_ERR(svn_fs_youngest_rev(&youngest_rev, fs, subpool)); + + SVN_ERR(svn_client_create_context(&ctx, subpool)); + + /* Open ra_local session */ + SVN_ERR(svn_ra_create_callbacks(&cbtable, pool)); + SVN_ERR(svn_ra_initialize(subpool)); + + SVN_ERR(svn_test__current_directory_url(&url, repos_name, subpool)); + + printf("url: %s\n", url); + SVN_ERR(svn_ra_open3(&session, + url, + NULL, + cbtable, + NULL, + NULL, + subpool)); + + peg_rev.kind = svn_opt_revision_head; + start_rev.kind = svn_opt_revision_number; + start_rev.value.number = youngest_rev; + end_rev.kind = svn_opt_revision_head; + SVN_ERR(svn_client_blame5(svn_uri_join(url, "branches/1.0.x/A/mu", subpool), + &peg_rev, + &start_rev, + &end_rev, + diff_options, + FALSE, + TRUE, + blame_receiver, + NULL, + ctx, + subpool)); + + return SVN_NO_ERROR; +} + + /* ========================================================================== */ struct svn_test_descriptor_t test_funcs[] = @@ -208,5 +295,7 @@ struct svn_test_descriptor_t test_funcs[] = "test svn_client__elide_mergeinfo_catalog"), SVN_TEST_PASS2(test_args_to_target_array, "test svn_client_args_to_target_array"), + SVN_TEST_OPTS_PASS(test_svn_client_blame, + "test svn_client_blame"), SVN_TEST_NULL }; Index: subversion/tests/libsvn_repos/repos-test.c =================================================================== --- subversion/tests/libsvn_repos/repos-test.c (revision 902368) +++ subversion/tests/libsvn_repos/repos-test.c (working copy) @@ -2340,7 +2340,126 @@ get_logs(const svn_test_opts_t *opts, return SVN_NO_ERROR; } + +/* Tests for svn_repos_get_file_revsN() */ +typedef struct { + svn_revnum_t rev; + const char *path; + svn_boolean_t result_of_merge; + const char *author; +} file_revs_t; + +/* Finds the revision REV in the hash table passed in in BATON, and checks + if the PATH and RESULT_OF_MERGE match are as expected. */ +static svn_error_t * +file_rev_handler(void *baton, const char *path, svn_revnum_t rev, + apr_hash_t *rev_props, svn_boolean_t result_of_merge, + svn_txdelta_window_handler_t *delta_handler, + void **delta_baton, apr_array_header_t *prop_diffs, + apr_pool_t *pool) +{ + apr_hash_t *ht = baton; + const char *author; + file_revs_t *file_rev = apr_hash_get(ht, &rev, sizeof(svn_revnum_t)); + + if (!file_rev) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "Revision rev info not expected for rev %ld " + "from path %s", + rev, path); + + author = svn_prop_get_value(rev_props, + SVN_PROP_REVISION_AUTHOR); + + SVN_TEST_STRING_ASSERT(author, file_rev->author); + SVN_TEST_STRING_ASSERT(path, file_rev->path); + SVN_TEST_ASSERT(rev == file_rev->rev); + SVN_TEST_ASSERT(result_of_merge == file_rev->result_of_merge); + + /* Remove this revision from this list so we'll be able to verify that we + have seen all expected revisions. */ + apr_hash_set(ht, &rev, sizeof(svn_revnum_t), NULL); + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_get_file_revs(const svn_test_opts_t *opts, + apr_pool_t *pool) +{ + svn_repos_t *repos = NULL; + svn_fs_t *fs; + svn_revnum_t youngest_rev = 0; + apr_pool_t *subpool = svn_pool_create(pool); + int i; + + file_revs_t trunk_results[] = { + { 2, "/trunk/A/mu", FALSE, "initial" }, + { 3, "/trunk/A/mu", FALSE, "user-trunk" }, + { 4, "/branches/1.0.x/A/mu", TRUE, "copy" }, + { 5, "/trunk/A/mu", FALSE, "user-trunk" }, + { 6, "/branches/1.0.x/A/mu", TRUE, "user-branch" }, + { 7, "/branches/1.0.x/A/mu", TRUE, "user-merge1" }, + { 8, "/trunk/A/mu", FALSE, "user-merge2" }, + }; + file_revs_t branch_results[] = { + { 2, "/trunk/A/mu", FALSE, "initial" }, + { 3, "/trunk/A/mu", FALSE, "user-trunk" }, + { 4, "/branches/1.0.x/A/mu", FALSE, "copy" }, + { 5, "/trunk/A/mu", TRUE, "user-trunk" }, + { 6, "/branches/1.0.x/A/mu", FALSE, "user-branch" }, + { 7, "/branches/1.0.x/A/mu", FALSE, "user-merge1" }, + }; + apr_hash_t *ht_trunk_results = apr_hash_make(subpool); + apr_hash_t *ht_branch_results = apr_hash_make(subpool); + + for (i = 0; i < sizeof(trunk_results) / sizeof(trunk_results[0]); i++) + apr_hash_set(ht_trunk_results, &trunk_results[i].rev, + sizeof(svn_revnum_t), &trunk_results[i]); + + for (i = 0; i < sizeof(branch_results) / sizeof(branch_results[0]); i++) + apr_hash_set(ht_branch_results, &branch_results[i].rev, + sizeof(svn_revnum_t), &branch_results[i]); + + /* Create the repository and verify blame results. */ + SVN_ERR(svn_test__create_blame_repository(&repos, "test-repo-get-filerevs", + opts, subpool)); + fs = svn_repos_fs(repos); + + SVN_ERR(svn_fs_youngest_rev(&youngest_rev, fs, subpool)); + + /* Verify blame of /trunk/A/mu */ + SVN_ERR(svn_repos_get_file_revs2(repos, "/trunk/A/mu", 0, youngest_rev, + 1, NULL, NULL, + file_rev_handler, + ht_trunk_results, + subpool)); + SVN_TEST_ASSERT(apr_hash_count(ht_trunk_results) == 0); + + /* Verify blame of /branches/1.0.x/A/mu */ + SVN_ERR(svn_repos_get_file_revs2(repos, "/branches/1.0.x/A/mu", 0, + youngest_rev, + 1, NULL, NULL, + file_rev_handler, + ht_branch_results, + subpool)); + SVN_TEST_ASSERT(apr_hash_count(ht_branch_results) == 0); + + /* Verify blame of /branches/1.0.x/A/mu in range 6-7 */ +#if 0 + /* This should only return revision 6, 7 and maximum one revision < 6. */ + printf("=== branch range\n"); + SVN_ERR(svn_repos_get_file_revs2(repos, "/branches/1.0.x/A/mu", 6, 7, + 1, NULL, NULL, + file_rev_handler, NULL, subpool)); +#endif + + svn_pool_destroy(subpool); + + return SVN_NO_ERROR; +} + /* The test table. */ @@ -2373,5 +2492,7 @@ struct svn_test_descriptor_t test_funcs[] = "test if revprops are validated by repos"), SVN_TEST_OPTS_PASS(get_logs, "test svn_repos_get_logs ranges and limits"), + SVN_TEST_OPTS_PASS(test_get_file_revs, + "test svn_repos_get_file_revsN"), SVN_TEST_NULL }; Index: subversion/tests/svn_test_fs.c =================================================================== --- subversion/tests/svn_test_fs.c (revision 902368) +++ subversion/tests/svn_test_fs.c (working copy) @@ -24,8 +24,17 @@ #include #include +#ifdef _MSC_VER +#include +#define getcwd _getcwd +#else +#include /* for getcwd() */ +#endif + #include "svn_test.h" +#include "svn_string.h" +#include "svn_utf.h" #include "svn_pools.h" #include "svn_error.h" #include "svn_fs.h" @@ -227,7 +236,37 @@ svn_test__create_repos(svn_repos_t **repos_p, } +/* Helper function. Set URL to a "file://" url for the current directory, + suffixed by the forward-slash-style relative path SUFFIX, performing all + allocation in POOL. */ svn_error_t * +svn_test__current_directory_url(const char **url, + const char *suffix, + apr_pool_t *pool) +{ + /* 8KB is a lot, but it almost guarantees that any path will fit. */ + char curdir[8192]; + const char *utf8_ls_curdir, *utf8_is_curdir, *unencoded_url; + + if (! getcwd(curdir, sizeof(curdir))) + return svn_error_create(SVN_ERR_BASE, NULL, "getcwd() failed"); + + SVN_ERR(svn_utf_cstring_to_utf8(&utf8_ls_curdir, curdir, pool)); + utf8_is_curdir = svn_path_internal_style(utf8_ls_curdir, pool); + + unencoded_url = apr_psprintf(pool, "file://%s%s%s%s", + (utf8_is_curdir[0] != '/') ? "/" : "", + utf8_is_curdir, + (suffix[0] && suffix[0] != '/') ? "/" : "", + suffix); + + *url = svn_path_uri_encode(unencoded_url, pool); + + return SVN_NO_ERROR; +} + + +svn_error_t * svn_test__stream_to_string(svn_stringbuf_t **string, svn_stream_t *stream, apr_pool_t *pool) @@ -606,55 +645,186 @@ svn_test__check_greek_tree(svn_fs_root_t *root, return SVN_NO_ERROR; } - - +/** + * Loads the greek tree in a directory at ROOT_DIR under transaction TXN_ROOT. + * ROOT_DIR should be created by the caller. + * + * Note: this function will not commit the transaction. + */ svn_error_t * -svn_test__create_greek_tree(svn_fs_root_t *txn_root, - apr_pool_t *pool) +svn_test__create_greek_tree_at(svn_fs_root_t *txn_root, + const char *root_dir, + apr_pool_t *pool) { - SVN_ERR(svn_fs_make_file(txn_root, "iota", pool)); + char *iota = svn_relpath_join(root_dir, "iota", pool); + char *A = svn_relpath_join(root_dir, "A", pool); + char *Amu = svn_relpath_join(root_dir, "A/mu", pool); + char *AB = svn_relpath_join(root_dir, "A/B", pool); + char *ABlambda = svn_relpath_join(root_dir, "A/B/lambda", pool); + char *ABE = svn_relpath_join(root_dir, "A/B/E", pool); + char *ABEalpha = svn_relpath_join(root_dir, "A/B/E/alpha", pool); + char *ABEbeta = svn_relpath_join(root_dir, "A/B/E/beta", pool); + char *ABF = svn_relpath_join(root_dir, "A/B/F", pool); + char *AC = svn_relpath_join(root_dir, "A/C", pool); + char *AD = svn_relpath_join(root_dir, "A/D", pool); + char *ADgamma = svn_relpath_join(root_dir, "A/D/gamma", pool); + char *ADG = svn_relpath_join(root_dir, "A/D/G", pool); + char *ADGpi = svn_relpath_join(root_dir, "A/D/G/pi", pool); + char *ADGrho = svn_relpath_join(root_dir, "A/D/G/rho", pool); + char *ADGtau = svn_relpath_join(root_dir, "A/D/G/tau", pool); + char *ADH = svn_relpath_join(root_dir, "A/D/H", pool); + char *ADHchi = svn_relpath_join(root_dir, "A/D/H/chi", pool); + char *ADHpsi = svn_relpath_join(root_dir, "A/D/H/psi", pool); + char *ADHomega = svn_relpath_join(root_dir, "A/D/H/omega", pool); + + SVN_ERR(svn_fs_make_file(txn_root, iota, pool)); SVN_ERR(svn_test__set_file_contents - (txn_root, "iota", "This is the file 'iota'.\n", pool)); - SVN_ERR(svn_fs_make_dir (txn_root, "A", pool)); - SVN_ERR(svn_fs_make_file(txn_root, "A/mu", pool)); + (txn_root, iota, "This is the file 'iota'.\n", pool)); + SVN_ERR(svn_fs_make_dir (txn_root, A, pool)); + SVN_ERR(svn_fs_make_file(txn_root, Amu, pool)); SVN_ERR(svn_test__set_file_contents - (txn_root, "A/mu", "This is the file 'mu'.\n", pool)); - SVN_ERR(svn_fs_make_dir (txn_root, "A/B", pool)); - SVN_ERR(svn_fs_make_file(txn_root, "A/B/lambda", pool)); + (txn_root, Amu, "This is the file 'mu'.\n", pool)); + SVN_ERR(svn_fs_make_dir (txn_root, AB, pool)); + SVN_ERR(svn_fs_make_file(txn_root, ABlambda, pool)); SVN_ERR(svn_test__set_file_contents - (txn_root, "A/B/lambda", "This is the file 'lambda'.\n", pool)); - SVN_ERR(svn_fs_make_dir (txn_root, "A/B/E", pool)); - SVN_ERR(svn_fs_make_file(txn_root, "A/B/E/alpha", pool)); + (txn_root, ABlambda, "This is the file 'lambda'.\n", pool)); + SVN_ERR(svn_fs_make_dir (txn_root, ABE, pool)); + SVN_ERR(svn_fs_make_file(txn_root, ABEalpha, pool)); SVN_ERR(svn_test__set_file_contents - (txn_root, "A/B/E/alpha", "This is the file 'alpha'.\n", pool)); - SVN_ERR(svn_fs_make_file(txn_root, "A/B/E/beta", pool)); + (txn_root, ABEalpha, "This is the file 'alpha'.\n", pool)); + SVN_ERR(svn_fs_make_file(txn_root, ABEbeta, pool)); SVN_ERR(svn_test__set_file_contents - (txn_root, "A/B/E/beta", "This is the file 'beta'.\n", pool)); - SVN_ERR(svn_fs_make_dir (txn_root, "A/B/F", pool)); - SVN_ERR(svn_fs_make_dir (txn_root, "A/C", pool)); - SVN_ERR(svn_fs_make_dir (txn_root, "A/D", pool)); - SVN_ERR(svn_fs_make_file(txn_root, "A/D/gamma", pool)); + (txn_root, ABEbeta, "This is the file 'beta'.\n", pool)); + SVN_ERR(svn_fs_make_dir (txn_root, ABF, pool)); + SVN_ERR(svn_fs_make_dir (txn_root, AC, pool)); + SVN_ERR(svn_fs_make_dir (txn_root, AD, pool)); + SVN_ERR(svn_fs_make_file(txn_root, ADgamma, pool)); SVN_ERR(svn_test__set_file_contents - (txn_root, "A/D/gamma", "This is the file 'gamma'.\n", pool)); - SVN_ERR(svn_fs_make_dir (txn_root, "A/D/G", pool)); - SVN_ERR(svn_fs_make_file(txn_root, "A/D/G/pi", pool)); + (txn_root, ADgamma, "This is the file 'gamma'.\n", pool)); + SVN_ERR(svn_fs_make_dir (txn_root, ADG, pool)); + SVN_ERR(svn_fs_make_file(txn_root, ADGpi, pool)); SVN_ERR(svn_test__set_file_contents - (txn_root, "A/D/G/pi", "This is the file 'pi'.\n", pool)); - SVN_ERR(svn_fs_make_file(txn_root, "A/D/G/rho", pool)); + (txn_root, ADGpi, "This is the file 'pi'.\n", pool)); + SVN_ERR(svn_fs_make_file(txn_root, ADGrho, pool)); SVN_ERR(svn_test__set_file_contents - (txn_root, "A/D/G/rho", "This is the file 'rho'.\n", pool)); - SVN_ERR(svn_fs_make_file(txn_root, "A/D/G/tau", pool)); + (txn_root, ADGrho, "This is the file 'rho'.\n", pool)); + SVN_ERR(svn_fs_make_file(txn_root, ADGtau, pool)); SVN_ERR(svn_test__set_file_contents - (txn_root, "A/D/G/tau", "This is the file 'tau'.\n", pool)); - SVN_ERR(svn_fs_make_dir (txn_root, "A/D/H", pool)); - SVN_ERR(svn_fs_make_file(txn_root, "A/D/H/chi", pool)); + (txn_root, ADGtau, "This is the file 'tau'.\n", pool)); + SVN_ERR(svn_fs_make_dir (txn_root, ADH, pool)); + SVN_ERR(svn_fs_make_file(txn_root, ADHchi, pool)); SVN_ERR(svn_test__set_file_contents - (txn_root, "A/D/H/chi", "This is the file 'chi'.\n", pool)); - SVN_ERR(svn_fs_make_file(txn_root, "A/D/H/psi", pool)); + (txn_root, ADHchi, "This is the file 'chi'.\n", pool)); + SVN_ERR(svn_fs_make_file(txn_root, ADHpsi, pool)); SVN_ERR(svn_test__set_file_contents - (txn_root, "A/D/H/psi", "This is the file 'psi'.\n", pool)); - SVN_ERR(svn_fs_make_file(txn_root, "A/D/H/omega", pool)); + (txn_root, ADHpsi, "This is the file 'psi'.\n", pool)); + SVN_ERR(svn_fs_make_file(txn_root, ADHomega, pool)); SVN_ERR(svn_test__set_file_contents - (txn_root, "A/D/H/omega", "This is the file 'omega'.\n", pool)); + (txn_root, ADHomega, "This is the file 'omega'.\n", pool)); return SVN_NO_ERROR; } + +svn_error_t * +svn_test__create_greek_tree(svn_fs_root_t *txn_root, + apr_pool_t *pool) +{ + return svn_test__create_greek_tree_at(txn_root, "", pool); +} + +svn_error_t * +svn_test__create_blame_repository(svn_repos_t **out_repos, + const char *test_name, + const svn_test_opts_t *opts, + apr_pool_t *pool) +{ + svn_repos_t *repos; + svn_fs_t *fs; + svn_fs_txn_t *txn; + svn_fs_root_t *txn_root, *revision_root; + svn_revnum_t youngest_rev = 0; + + /* Create a filesystem and repository. */ + SVN_ERR(svn_test__create_repos(&repos, test_name, + opts, pool)); + *out_repos = repos; + + fs = svn_repos_fs(repos); + + /* Revision 1: Add trunk, tags, branches. */ + SVN_ERR(svn_repos_fs_begin_txn_for_commit(&txn, repos, youngest_rev, + "initial", "log msg", pool)); + SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool)); + SVN_ERR(svn_fs_make_dir(txn_root, "trunk", pool)); + SVN_ERR(svn_fs_make_dir(txn_root, "tags", pool)); + SVN_ERR(svn_fs_make_dir(txn_root, "branches", pool)); + SVN_ERR(svn_repos_fs_commit_txn(NULL, repos, &youngest_rev, txn, pool)); + + /* Revision 2: Add the Greek tree on the trunk. */ + SVN_ERR(svn_repos_fs_begin_txn_for_commit(&txn, repos, youngest_rev, + "initial", "log msg", pool)); + SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool)); + SVN_ERR(svn_test__create_greek_tree_at(txn_root, "trunk", pool)); + SVN_ERR(svn_repos_fs_commit_txn(NULL, repos, &youngest_rev, txn, pool)); + + /* Revision 3: Tweak trunk/A/mu. */ + SVN_ERR(svn_repos_fs_begin_txn_for_commit(&txn, repos, youngest_rev, + "user-trunk", "log msg", pool)); + SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool)); + SVN_ERR(svn_test__set_file_contents(txn_root, "trunk/A/mu", + "A\nB\nC\nD\nE\nF\nG\nH\nI", pool)); + SVN_ERR(svn_repos_fs_commit_txn(NULL, repos, &youngest_rev, txn, pool)); + + /* Revision 4: Copy trunk to branches/1.0.x. */ + SVN_ERR(svn_repos_fs_begin_txn_for_commit(&txn, repos, youngest_rev, + "copy", "log msg", pool)); + SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool)); + SVN_ERR(svn_fs_revision_root(&revision_root, fs, youngest_rev, pool)); + SVN_ERR(svn_fs_copy(revision_root, "trunk", + txn_root, "branches/1.0.x", + pool)); + SVN_ERR(svn_repos_fs_commit_txn(NULL, repos, &youngest_rev, txn, pool)); + + /* Revision 5: Tweak trunk/A/mu. */ + SVN_ERR(svn_repos_fs_begin_txn_for_commit(&txn, repos, youngest_rev, + "user-trunk", "log msg", pool)); + SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool)); + SVN_ERR(svn_test__set_file_contents(txn_root, "trunk/A/mu", + "A\nB\nC -- trunk edit\nD\nE\nF\nG\nH\nI", + pool)); + SVN_ERR(svn_repos_fs_commit_txn(NULL, repos, &youngest_rev, txn, pool)); + + /* Revision 6: Tweak branches/1.0.x/A/mu. */ + SVN_ERR(svn_repos_fs_begin_txn_for_commit(&txn, repos, youngest_rev, + "user-branch", "log msg", pool)); + SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool)); + SVN_ERR(svn_test__set_file_contents(txn_root, "branches/1.0.x/A/mu", + "A\nB\nC\nD -- branch edit\nE\nF\nG\nH\nI", + pool)); + SVN_ERR(svn_repos_fs_commit_txn(NULL, repos, &youngest_rev, txn, pool)); + + /* Revision 7: Merge trunk to branch. */ + SVN_ERR(svn_repos_fs_begin_txn_for_commit(&txn, repos, youngest_rev, + "user-merge1", "log msg", pool)); + SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool)); + SVN_ERR(svn_test__set_file_contents(txn_root, "branches/1.0.x/A/mu", + "A\nB\nC -- trunk edit\nD -- branch edit" + "\nE\nF\nG\nH\nI", pool)); + SVN_ERR(svn_fs_change_node_prop(txn_root, "/branches/1.0.x", "svn:mergeinfo", + svn_string_create("/trunk:4-6", pool), + pool)); + SVN_ERR(svn_repos_fs_commit_txn(NULL, repos, &youngest_rev, txn, pool)); + + /* Revision 8: Merge branch to trunk. */ + SVN_ERR(svn_repos_fs_begin_txn_for_commit(&txn, repos, youngest_rev, + "user-merge2", "log msg", pool)); + SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool)); + SVN_ERR(svn_test__set_file_contents(txn_root, "trunk/A/mu", + "A\nB\nC -- trunk edit\nD -- branch edit\n" + "E\nF\nG\nH\nI", pool)); + SVN_ERR(svn_fs_change_node_prop(txn_root, "/trunk", "svn:mergeinfo", + svn_string_create("/branches/1.0.x:4-7", pool), + pool)); + SVN_ERR(svn_repos_fs_commit_txn(NULL, repos, &youngest_rev, txn, pool)); + + return SVN_NO_ERROR; +}