Fix compiler warning due to missing function prototype.
[svn.git] / subversion / tests / libsvn_fs_base / changes-test.c
blob5d34ddfa3482e05d0b1e939c53547c5a9fc82061
1 /* changes-test.c --- test `changes' interfaces
3 * ====================================================================
4 * Copyright (c) 2000-2004 CollabNet. All rights reserved.
6 * This software is licensed as described in the file COPYING, which
7 * you should have received as part of this distribution. The terms
8 * are also available at http://subversion.tigris.org/license-1.html.
9 * If newer versions of this license are posted there, you may use a
10 * newer version instead, at your option.
12 * This software consists of voluntary contributions made by many
13 * individuals. For exact contribution history, see the revision
14 * history and logs, available at http://subversion.tigris.org/.
15 * ====================================================================
18 #include <stdlib.h>
19 #include <stdarg.h>
20 #include <string.h>
21 #include <stdio.h>
23 #include <apr.h>
25 #include "svn_pools.h"
26 #include "svn_error.h"
28 #include "../svn_test.h"
29 #include "../svn_test_fs.h"
30 #include "../../libsvn_fs_base/util/skel.h"
31 #include "../../libsvn_fs_base/util/fs_skels.h"
32 #include "../../libsvn_fs_base/bdb/changes-table.h"
36 /* Helper functions/variables. */
37 static const char *standard_txns[]
38 = { "0", "1", "2", "3", "4", "5", "6" };
39 static const char *standard_changes[19][6]
40 /* KEY PATH NODEREVID KIND TEXT PROP */
41 = { { "0", "/foo", "1.0.0", "add", 0, 0 },
42 { "0", "/foo", "1.0.0", "modify", 0, "1" },
43 { "0", "/bar", "2.0.0", "add", 0, 0 },
44 { "0", "/bar", "2.0.0", "modify", "1", 0 },
45 { "0", "/bar", "2.0.0", "modify", 0, "1" },
46 { "0", "/baz", "3.0.0", "add", 0, 0 },
47 { "0", "/baz", "3.0.0", "modify", "1", 0 },
48 { "1", "/foo", "1.0.1", "modify", "1", 0 },
49 { "2", "/foo", "1.0.2", "modify", 0, "1" },
50 { "2", "/bar", "2.0.2", "modify", "1", 0 },
51 { "3", "/baz", "3.0.3", "modify", "1", 0 },
52 { "4", "/fob", "4.0.4", "add", 0, 0 },
53 { "4", "/fob", "4.0.4", "modify", "1", 0 },
54 { "5", "/baz", "3.0.3", "delete", 0, 0 },
55 { "5", "/baz", "5.0.5", "add", 0, "1" },
56 { "5", "/baz", "5.0.5", "modify", "1", 0 },
57 { "6", "/fob", "4.0.6", "modify", "1", 0 },
58 { "6", "/fob", "4.0.6", "reset", 0, 0 },
59 { "6", "/fob", "4.0.6", "modify", 0, "1" } };
62 static svn_fs_path_change_kind_t string_to_kind(const char *str)
64 if (strcmp(str, "add") == 0)
65 return svn_fs_path_change_add;
66 if (strcmp(str, "delete") == 0)
67 return svn_fs_path_change_delete;
68 if (strcmp(str, "replace") == 0)
69 return svn_fs_path_change_replace;
70 if (strcmp(str, "modify") == 0)
71 return svn_fs_path_change_modify;
72 if (strcmp(str, "reset") == 0)
73 return svn_fs_path_change_reset;
74 return 0;
78 /* Common args structure for several different txn_body_* functions. */
79 struct changes_args
81 svn_fs_t *fs;
82 const char *key;
83 change_t *change;
84 apr_array_header_t *raw_changes;
85 apr_hash_t *changes;
89 static svn_error_t *
90 txn_body_changes_add(void *baton, trail_t *trail)
92 struct changes_args *b = baton;
93 return svn_fs_bdb__changes_add(b->fs, b->key, b->change,
94 trail, trail->pool);
98 static svn_error_t *
99 add_standard_changes(svn_fs_t *fs,
100 apr_pool_t *pool)
102 int i;
103 struct changes_args args;
104 int num_changes = sizeof(standard_changes) / sizeof(const char *) / 6;
106 for (i = 0; i < num_changes; i++)
108 change_t change;
110 /* Set up the current change item. */
111 change.path = standard_changes[i][1];
112 change.noderev_id = svn_fs_parse_id(standard_changes[i][2],
113 strlen(standard_changes[i][2]),
114 pool);
115 change.kind = string_to_kind(standard_changes[i][3]);
116 change.text_mod = standard_changes[i][4] ? 1 : 0;
117 change.prop_mod = standard_changes[i][5] ? 1 : 0;
119 /* Set up transaction baton. */
120 args.fs = fs;
121 args.key = standard_changes[i][0];
122 args.change = &change;
124 /* Write new changes to the changes table. */
125 SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_changes_add, &args,
126 pool));
129 return SVN_NO_ERROR;
133 static svn_error_t *
134 txn_body_changes_fetch_raw(void *baton, trail_t *trail)
136 struct changes_args *b = baton;
137 return svn_fs_bdb__changes_fetch_raw(&(b->raw_changes), b->fs, b->key,
138 trail, trail->pool);
142 static svn_error_t *
143 txn_body_changes_fetch(void *baton, trail_t *trail)
145 struct changes_args *b = baton;
146 return svn_fs_bdb__changes_fetch(&(b->changes), b->fs, b->key,
147 trail, trail->pool);
151 static svn_error_t *
152 txn_body_changes_delete(void *baton, trail_t *trail)
154 struct changes_args *b = baton;
155 return svn_fs_bdb__changes_delete(b->fs, b->key, trail, trail->pool);
160 /* The tests. */
162 static svn_error_t *
163 changes_add(const char **msg,
164 svn_boolean_t msg_only,
165 svn_test_opts_t *opts,
166 apr_pool_t *pool)
168 svn_fs_t *fs;
170 *msg = "add changes to the changes table";
172 if (msg_only)
173 return SVN_NO_ERROR;
175 /* Create a new fs and repos */
176 SVN_ERR(svn_test__create_fs(&fs, "test-repo-changes-add",
177 "bdb", pool));
179 /* Add the standard slew of changes. */
180 SVN_ERR(add_standard_changes(fs, pool));
182 return SVN_NO_ERROR;
186 static svn_error_t *
187 changes_fetch_raw(const char **msg,
188 svn_boolean_t msg_only,
189 svn_test_opts_t *opts,
190 apr_pool_t *pool)
192 svn_fs_t *fs;
193 int i;
194 int num_txns = sizeof(standard_txns) / sizeof(const char *);
195 int cur_change_index = 0;
196 struct changes_args args;
198 *msg = "fetch raw changes from the changes table";
200 if (msg_only)
201 return SVN_NO_ERROR;
203 /* Create a new fs and repos */
204 SVN_ERR(svn_test__create_fs(&fs, "test-repo-changes-fetch",
205 "bdb", pool));
207 /* First, verify that we can request changes for an arbitrary key
208 without error. */
209 args.fs = fs;
210 args.key = "blahbliggityblah";
211 SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_changes_fetch_raw,
212 &args, pool));
213 if ((! args.raw_changes) || (args.raw_changes->nelts))
214 return svn_error_create(SVN_ERR_TEST_FAILED, NULL,
215 "expected empty changes array");
217 /* Add the standard slew of changes. */
218 SVN_ERR(add_standard_changes(fs, pool));
220 /* For each transaction, fetch that transaction's changes, and
221 compare those changes against the standard changes list. Order
222 matters throughout all the changes code, so we shouldn't have to
223 worry about ordering of the arrays. */
224 for (i = 0; i < num_txns; i++)
226 const char *txn_id = standard_txns[i];
227 int j;
229 /* Setup the trail baton. */
230 args.fs = fs;
231 args.key = txn_id;
233 /* And get those changes. */
234 SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_changes_fetch_raw,
235 &args, pool));
236 if (! args.raw_changes)
237 return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
238 "got no changes for key '%s'", txn_id);
240 for (j = 0; j < args.raw_changes->nelts; j++)
242 svn_string_t *noderev_id;
243 svn_fs_path_change_kind_t kind;
244 change_t *change = APR_ARRAY_IDX(args.raw_changes, j, change_t *);
245 int mod_bit = 0;
247 /* Verify that the TXN_ID matches. */
248 if (strcmp(standard_changes[cur_change_index][0], txn_id))
249 return svn_error_createf
250 (SVN_ERR_TEST_FAILED, NULL,
251 "missing some changes for key '%s'", txn_id);
253 /* Verify that the PATH matches. */
254 if (strcmp(standard_changes[cur_change_index][1], change->path))
255 return svn_error_createf
256 (SVN_ERR_TEST_FAILED, NULL,
257 "paths differ in change for key '%s'", txn_id);
259 /* Verify that the NODE-REV-ID matches. */
260 noderev_id = svn_fs_unparse_id(change->noderev_id, pool);
261 if (strcmp(standard_changes[cur_change_index][2], noderev_id->data))
262 return svn_error_createf
263 (SVN_ERR_TEST_FAILED, NULL,
264 "node revision ids differ in change for key '%s'", txn_id);
266 /* Verify that the change KIND matches. */
267 kind = string_to_kind(standard_changes[cur_change_index][3]);
268 if (kind != change->kind)
269 return svn_error_createf
270 (SVN_ERR_TEST_FAILED, NULL,
271 "change kinds differ in change for key '%s'", txn_id);
273 /* Verify that the change TEXT-MOD bit matches. */
274 mod_bit = standard_changes[cur_change_index][4] ? 1 : 0;
275 if (mod_bit != change->text_mod)
276 return svn_error_createf
277 (SVN_ERR_TEST_FAILED, NULL,
278 "change text-mod bits differ in change for key '%s'", txn_id);
280 /* Verify that the change PROP-MOD bit matches. */
281 mod_bit = standard_changes[cur_change_index][5] ? 1 : 0;
282 if (mod_bit != change->prop_mod)
283 return svn_error_createf
284 (SVN_ERR_TEST_FAILED, NULL,
285 "change prop-mod bits differ in change for key '%s'", txn_id);
287 cur_change_index++;
291 return SVN_NO_ERROR;
295 static svn_error_t *
296 changes_delete(const char **msg,
297 svn_boolean_t msg_only,
298 svn_test_opts_t *opts,
299 apr_pool_t *pool)
301 svn_fs_t *fs;
302 int i;
303 int num_txns = sizeof(standard_txns) / sizeof(const char *);
304 struct changes_args args;
306 *msg = "delete changes from the changes table";
308 if (msg_only)
309 return SVN_NO_ERROR;
311 /* Create a new fs and repos */
312 SVN_ERR(svn_test__create_fs(&fs, "test-repo-changes-delete",
313 "bdb", pool));
315 /* Add the standard slew of changes. */
316 SVN_ERR(add_standard_changes(fs, pool));
318 /* Now, delete all the changes we know about, verifying their removal. */
319 for (i = 0; i < num_txns; i++)
321 args.fs = fs;
322 args.key = standard_txns[i];
323 SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_changes_delete,
324 &args, pool));
325 args.changes = 0;
326 SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_changes_fetch_raw,
327 &args, pool));
328 if ((! args.raw_changes) || (args.raw_changes->nelts))
329 return svn_error_createf
330 (SVN_ERR_TEST_FAILED, NULL,
331 "expected empty changes array for txn '%s'", args.key);
334 return SVN_NO_ERROR;
338 static apr_hash_t *
339 get_ideal_changes(const char *txn_id,
340 apr_pool_t *pool)
342 apr_hash_t *ideal = apr_hash_make(pool);
343 svn_fs_path_change_t *change;
344 if (strcmp(txn_id, "0") == 0)
346 change = apr_palloc(pool, sizeof(*change));
347 change->node_rev_id = svn_fs_parse_id("1.0.0", 5, pool);
348 change->change_kind = svn_fs_path_change_add;
349 change->text_mod = 0;
350 change->prop_mod = 1;
351 apr_hash_set(ideal, "/foo", APR_HASH_KEY_STRING, change);
353 change = apr_palloc(pool, sizeof(*change));
354 change->node_rev_id = svn_fs_parse_id("2.0.0", 5, pool);
355 change->change_kind = svn_fs_path_change_add;
356 change->text_mod = 1;
357 change->prop_mod = 1;
358 apr_hash_set(ideal, "/bar", APR_HASH_KEY_STRING, change);
360 change = apr_palloc(pool, sizeof(*change));
361 change->node_rev_id = svn_fs_parse_id("3.0.0", 5, pool);
362 change->change_kind = svn_fs_path_change_add;
363 change->text_mod = 1;
364 change->prop_mod = 0;
365 apr_hash_set(ideal, "/baz", APR_HASH_KEY_STRING, change);
367 if (strcmp(txn_id, "1") == 0)
369 change = apr_palloc(pool, sizeof(*change));
370 change->node_rev_id = svn_fs_parse_id("1.0.1", 5, pool);
371 change->change_kind = svn_fs_path_change_modify;
372 change->text_mod = 1;
373 change->prop_mod = 0;
374 apr_hash_set(ideal, "/foo", APR_HASH_KEY_STRING, change);
376 if (strcmp(txn_id, "2") == 0)
378 change = apr_palloc(pool, sizeof(*change));
379 change->node_rev_id = svn_fs_parse_id("1.0.2", 5, pool);
380 change->change_kind = svn_fs_path_change_modify;
381 change->text_mod = 0;
382 change->prop_mod = 1;
383 apr_hash_set(ideal, "/foo", APR_HASH_KEY_STRING, change);
385 change = apr_palloc(pool, sizeof(*change));
386 change->node_rev_id = svn_fs_parse_id("2.0.2", 5, pool);
387 change->change_kind = svn_fs_path_change_modify;
388 change->text_mod = 1;
389 change->prop_mod = 0;
390 apr_hash_set(ideal, "/bar", APR_HASH_KEY_STRING, change);
392 if (strcmp(txn_id, "3") == 0)
394 change = apr_palloc(pool, sizeof(*change));
395 change->node_rev_id = svn_fs_parse_id("3.0.3", 5, pool);
396 change->change_kind = svn_fs_path_change_modify;
397 change->text_mod = 1;
398 change->prop_mod = 0;
399 apr_hash_set(ideal, "/baz", APR_HASH_KEY_STRING, change);
401 if (strcmp(txn_id, "4") == 0)
403 change = apr_palloc(pool, sizeof(*change));
404 change->node_rev_id = svn_fs_parse_id("4.0.4", 5, pool);
405 change->change_kind = svn_fs_path_change_add;
406 change->text_mod = 1;
407 change->prop_mod = 0;
408 apr_hash_set(ideal, "/fob", APR_HASH_KEY_STRING, change);
410 if (strcmp(txn_id, "5") == 0)
412 change = apr_palloc(pool, sizeof(*change));
413 change->node_rev_id = svn_fs_parse_id("5.0.5", 5, pool);
414 change->change_kind = svn_fs_path_change_replace;
415 change->text_mod = 1;
416 change->prop_mod = 1;
417 apr_hash_set(ideal, "/baz", APR_HASH_KEY_STRING, change);
419 if (strcmp(txn_id, "6") == 0)
421 change = apr_palloc(pool, sizeof(*change));
422 change->node_rev_id = svn_fs_parse_id("4.0.6", 5, pool);
423 change->change_kind = svn_fs_path_change_modify;
424 change->text_mod = 0;
425 change->prop_mod = 1;
426 apr_hash_set(ideal, "/fob", APR_HASH_KEY_STRING, change);
428 return ideal;
432 static svn_error_t *
433 compare_changes(apr_hash_t *ideals,
434 apr_hash_t *changes,
435 svn_test_opts_t *opts,
436 const char *txn_id,
437 apr_pool_t *pool)
439 apr_hash_index_t *hi;
441 for (hi = apr_hash_first(pool, ideals); hi; hi = apr_hash_next(hi))
443 const void *key;
444 void *val;
445 svn_fs_path_change_t *ideal_change, *change;
446 const char *path;
448 /* KEY will be the path, VAL the change. */
449 apr_hash_this(hi, &key, NULL, &val);
450 path = (const char *) key;
451 ideal_change = val;
453 /* Now get the change that refers to PATH in the actual
454 changes hash. */
455 change = apr_hash_get(changes, path, APR_HASH_KEY_STRING);
456 if (! change)
457 return svn_error_createf
458 (SVN_ERR_TEST_FAILED, NULL,
459 "missing expected change for path '%s' in txn_id '%s'",
460 path, txn_id);
462 /* Verify that the NODE-REV-ID matches. */
463 if (svn_fs_compare_ids(change->node_rev_id,
464 ideal_change->node_rev_id))
465 return svn_error_createf
466 (SVN_ERR_TEST_FAILED, NULL,
467 "node revision ids differ in change for key '%s'", txn_id);
469 /* Verify that the change KIND matches. */
470 if (change->change_kind != ideal_change->change_kind)
471 return svn_error_createf
472 (SVN_ERR_TEST_FAILED, NULL,
473 "change kinds differ in change for key '%s'", txn_id);
475 /* Verify that the change TEXT-MOD bit matches. */
476 if (change->text_mod != ideal_change->text_mod)
477 return svn_error_createf
478 (SVN_ERR_TEST_FAILED, NULL,
479 "change text-mod bits differ in change for key '%s'", txn_id);
481 /* Verify that the change PROP-MOD bit matches. */
482 if (change->prop_mod != ideal_change->prop_mod)
483 return svn_error_createf
484 (SVN_ERR_TEST_FAILED, NULL,
485 "change prop-mod bits differ in change for key '%s'", txn_id);
488 return SVN_NO_ERROR;
492 static svn_error_t *
493 changes_fetch(const char **msg,
494 svn_boolean_t msg_only,
495 svn_test_opts_t *opts,
496 apr_pool_t *pool)
498 svn_fs_t *fs;
499 int i;
500 int num_txns = sizeof(standard_txns) / sizeof(const char *);
501 struct changes_args args;
502 *msg = "fetch compressed changes from the changes table";
504 if (msg_only)
505 return SVN_NO_ERROR;
507 /* Create a new fs and repos */
508 SVN_ERR(svn_test__create_fs(&fs, "test-repo-changes-fetch",
509 "bdb", pool));
511 /* First, verify that we can request changes for an arbitrary key
512 without error. */
513 args.fs = fs;
514 args.key = "blahbliggityblah";
515 SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_changes_fetch, &args, pool));
516 if ((! args.changes) || (apr_hash_count(args.changes)))
517 return svn_error_create(SVN_ERR_TEST_FAILED, NULL,
518 "expected empty changes hash");
520 /* Add the standard slew of changes. */
521 SVN_ERR(add_standard_changes(fs, pool));
523 /* For each transaction, fetch that transaction's changes, and
524 compare those changes against our ideal compressed changes
525 hash. */
526 for (i = 0; i < num_txns; i++)
528 const char *txn_id = standard_txns[i];
529 apr_hash_t *ideals;
531 /* Get the ideal changes hash. */
532 ideals = get_ideal_changes(txn_id, pool);
534 /* Setup the trail baton. */
535 args.fs = fs;
536 args.key = txn_id;
538 /* And get those changes via in the internal interface, and
539 verify that they are accurate. */
540 SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_changes_fetch, &args,
541 pool));
542 if (! args.changes)
543 return svn_error_createf
544 (SVN_ERR_TEST_FAILED, NULL,
545 "got no changes for key '%s'", txn_id);
546 if (apr_hash_count(ideals) != apr_hash_count(args.changes))
547 return svn_error_createf
548 (SVN_ERR_TEST_FAILED, NULL,
549 "unexpected number of changes for key '%s'", txn_id);
550 SVN_ERR(compare_changes(ideals, args.changes, opts, txn_id, pool));
553 return SVN_NO_ERROR;
557 static svn_error_t *
558 changes_fetch_ordering(const char **msg,
559 svn_boolean_t msg_only,
560 svn_test_opts_t *opts,
561 apr_pool_t *pool)
563 svn_fs_t *fs;
564 svn_revnum_t youngest_rev = 0;
565 const char *txn_name;
566 svn_fs_txn_t *txn;
567 svn_fs_root_t *txn_root, *rev_root;
568 struct changes_args args;
569 apr_pool_t *subpool = svn_pool_create(pool);
570 apr_hash_index_t *hi;
572 *msg = "verify ordered-ness of fetched compressed changes";
574 if (msg_only)
575 return SVN_NO_ERROR;
577 /* Create a new fs and repos */
578 SVN_ERR(svn_test__create_fs
579 (&fs, "test-repo-changes-fetch-ordering",
580 "bdb", pool));
582 /*** REVISION 1: Make some files and dirs. ***/
583 SVN_ERR(svn_fs_begin_txn(&txn, fs, youngest_rev, subpool));
584 SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
586 static svn_test__txn_script_command_t script_entries[] = {
587 { 'a', "dir1", 0 },
588 { 'a', "file1", "This is the file 'file1'.\n" },
589 { 'a', "dir1/file2", "This is the file 'file2'.\n" },
590 { 'a', "dir1/file3", "This is the file 'file3'.\n" },
591 { 'a', "dir1/file4", "This is the file 'file4'.\n" },
593 SVN_ERR(svn_test__txn_script_exec(txn_root, script_entries, 5, subpool));
595 SVN_ERR(svn_fs_commit_txn(NULL, &youngest_rev, txn, subpool));
596 svn_pool_clear(subpool);
598 /*** REVISION 2: Delete and add some stuff, non-depth-first. ***/
599 SVN_ERR(svn_fs_begin_txn(&txn, fs, youngest_rev, subpool));
600 /* Don't use subpool, txn_name is used after subpool is cleared */
601 SVN_ERR(svn_fs_txn_name(&txn_name, txn, pool));
602 SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
604 static svn_test__txn_script_command_t script_entries[] = {
605 { 'd', "file1", "This is the file 'file1'.\n" },
606 { 'd', "dir1/file2", "This is the file 'file2'.\n" },
607 { 'd', "dir1/file3", "This is the file 'file3'.\n" },
608 { 'a', "dir1/file5", "This is the file 'file4'.\n" },
609 { 'a', "dir1/dir2", 0 },
610 { 'd', "dir1", 0 },
611 { 'a', "dir3", 0 },
613 SVN_ERR(svn_test__txn_script_exec(txn_root, script_entries, 7, subpool));
615 SVN_ERR(svn_fs_commit_txn(NULL, &youngest_rev, txn, subpool));
616 svn_pool_clear(subpool);
618 /*** TEST: We should have only three changes, the deletion of 'file1'
619 the deletion of 'dir1', and the addition of 'dir3'. ***/
620 args.fs = fs;
621 args.key = txn_name;
622 SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_changes_fetch, &args,
623 subpool));
624 if ((! args.changes) || (apr_hash_count(args.changes) != 3))
625 return svn_error_create(SVN_ERR_TEST_FAILED, NULL,
626 "expected changes");
627 for (hi = apr_hash_first(subpool, args.changes);
628 hi; hi = apr_hash_next(hi))
630 const void *key;
631 void *val;
632 svn_fs_path_change_t *change;
634 /* KEY will be the path, VAL the change. */
635 apr_hash_this(hi, &key, NULL, &val);
636 change = val;
638 if ((change->change_kind == svn_fs_path_change_add)
639 && (strcmp(key, "/dir3") == 0))
641 else if ((change->change_kind == svn_fs_path_change_delete)
642 && ((strcmp(key, "/dir1") == 0)
643 || (strcmp(key, "/file1") == 0)))
645 else
646 return svn_error_create(SVN_ERR_TEST_FAILED, NULL,
647 "got wrong changes");
650 /*** REVISION 3: Do the same stuff as in revision 1. ***/
651 SVN_ERR(svn_fs_begin_txn(&txn, fs, youngest_rev, subpool));
652 SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
654 static svn_test__txn_script_command_t script_entries[] = {
655 { 'a', "dir1", 0 },
656 { 'a', "file1", "This is the file 'file1'.\n" },
657 { 'a', "dir1/file2", "This is the file 'file2'.\n" },
658 { 'a', "dir1/file3", "This is the file 'file3'.\n" },
659 { 'a', "dir1/file4", "This is the file 'file4'.\n" },
661 SVN_ERR(svn_test__txn_script_exec(txn_root, script_entries, 5, subpool));
663 SVN_ERR(svn_fs_commit_txn(NULL, &youngest_rev, txn, subpool));
664 svn_pool_clear(subpool);
666 /*** REVISION 4: Do the same stuff as in revision 2, but use a copy
667 overwrite of the top directory (instead of a delete) to test
668 that the 'replace' change type works, too. (And add 'dir4'
669 instead of 'dir3', since 'dir3' still exists). ***/
670 SVN_ERR(svn_fs_begin_txn(&txn, fs, youngest_rev, subpool));
671 /* Don't use subpool, txn_name is used after subpool is cleared */
672 SVN_ERR(svn_fs_txn_name(&txn_name, txn, pool));
673 SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
674 SVN_ERR(svn_fs_revision_root(&rev_root, fs, 1, subpool));
676 static svn_test__txn_script_command_t script_entries[] = {
677 { 'd', "file1", "This is the file 'file1'.\n" },
678 { 'd', "dir1/file2", "This is the file 'file2'.\n" },
679 { 'd', "dir1/file3", "This is the file 'file3'.\n" },
680 { 'a', "dir1/file5", "This is the file 'file4'.\n" },
681 { 'a', "dir1/dir2", 0 },
683 SVN_ERR(svn_test__txn_script_exec(txn_root, script_entries, 5, subpool));
684 SVN_ERR(svn_fs_copy(rev_root, "dir1", txn_root, "dir1", subpool));
685 SVN_ERR(svn_fs_make_dir(txn_root, "dir4", subpool));
687 SVN_ERR(svn_fs_commit_txn(NULL, &youngest_rev, txn, subpool));
688 svn_pool_clear(subpool);
690 /*** TEST: We should have only three changes, the deletion of 'file1'
691 the replacement of 'dir1', and the addition of 'dir4'. ***/
692 args.fs = fs;
693 args.key = txn_name;
694 SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_changes_fetch, &args,
695 subpool));
696 if ((! args.changes) || (apr_hash_count(args.changes) != 3))
697 return svn_error_create(SVN_ERR_TEST_FAILED, NULL,
698 "expected changes");
699 for (hi = apr_hash_first(subpool, args.changes);
700 hi; hi = apr_hash_next(hi))
702 const void *key;
703 void *val;
704 svn_fs_path_change_t *change;
706 /* KEY will be the path, VAL the change. */
707 apr_hash_this(hi, &key, NULL, &val);
708 change = val;
710 if ((change->change_kind == svn_fs_path_change_add)
711 && (strcmp(key, "/dir4") == 0))
713 else if ((change->change_kind == svn_fs_path_change_replace)
714 && (strcmp(key, "/dir1") == 0))
716 else if ((change->change_kind == svn_fs_path_change_delete)
717 && (strcmp(key, "/file1") == 0))
719 else
720 return svn_error_create(SVN_ERR_TEST_FAILED, NULL,
721 "got wrong changes");
724 return SVN_NO_ERROR;
729 /* The test table. */
731 struct svn_test_descriptor_t test_funcs[] =
733 SVN_TEST_NULL,
734 SVN_TEST_PASS(changes_add),
735 SVN_TEST_PASS(changes_fetch_raw),
736 SVN_TEST_PASS(changes_delete),
737 SVN_TEST_PASS(changes_fetch),
738 SVN_TEST_PASS(changes_fetch_ordering),
739 SVN_TEST_NULL