Revert r7770 ("Speed up the regression tests") because, to quote Branko,
[svnrdump.git] / svntest / actions.py
blob0b421eedf180d3d1e78bbdafb582e6957be87907
1 #!/usr/bin/env python
3 # actions.py: routines that actually run the svn client.
5 # Subversion is a tool for revision control.
6 # See http://subversion.tigris.org for more information.
7 #
8 # ====================================================================
9 # Copyright (c) 2000-2003 CollabNet. All rights reserved.
11 # This software is licensed as described in the file COPYING, which
12 # you should have received as part of this distribution. The terms
13 # are also available at http://subversion.tigris.org/license-1.html.
14 # If newer versions of this license are posted there, you may use a
15 # newer version instead, at your option.
17 ######################################################################
19 import os.path, shutil, string, re, sys
21 import main, tree, wc # general svntest routines in this module.
22 from svntest import Failure, SVNAnyOutput
24 class SVNUnexpectedOutput(Failure):
25 """Exception raised if an invocation of svn results in unexpected
26 output of any kind."""
27 pass
29 class SVNUnexpectedStdout(SVNUnexpectedOutput):
30 """Exception raised if an invocation of svn results in unexpected
31 output on STDOUT."""
32 pass
34 class SVNUnexpectedStderr(SVNUnexpectedOutput):
35 """Exception raised if an invocation of svn results in unexpected
36 output on STDERR."""
37 pass
39 class SVNExpectedStdout(SVNUnexpectedOutput):
40 """Exception raised if an invocation of svn results in no output on
41 STDOUT when output was expected."""
42 pass
44 class SVNExpectedStderr(SVNUnexpectedOutput):
45 """Exception raised if an invocation of svn results in no output on
46 STDERR when output was expected."""
47 pass
49 class SVNIncorrectDatatype(SVNUnexpectedOutput):
50 """Exception raised if invalid input is passed to the
51 run_and_verify_* API"""
52 pass
55 ######################################################################
56 # Used by every test, so that they can run independently of
57 # one another. The first time it's run, it executes 'svnadmin' to
58 # create a repository and then 'svn imports' the greek tree.
59 # Thereafter, every time this routine is called, it recursively copies
60 # the `pristine repos' to a new location.
62 def guarantee_greek_repository(path):
63 """Guarantee that a local svn repository exists at PATH, containing
64 nothing but the greek-tree at revision 1."""
66 if path == main.pristine_dir:
67 print "ERROR: attempt to overwrite the pristine repos! Aborting."
68 sys.exit(1)
70 # If there's no pristine repos, create one.
71 if not os.path.exists(main.pristine_dir):
72 main.create_repos(main.pristine_dir)
74 # dump the greek tree to disk.
75 main.greek_state.write_to_disk(main.greek_dump_dir)
77 # build a URL for doing an import.
78 url = main.test_area_url + '/' + main.pristine_dir
79 if main.windows == 1:
80 url = string.replace(url, '\\', '/')
82 # import the greek tree, using l:foo/p:bar
83 ### todo: svn should not be prompting for auth info when using
84 ### repositories with no auth/auth requirements
85 output, errput = main.run_svn(None, 'import',
86 '--username', main.wc_author,
87 '--password', main.wc_passwd,
88 '-m', 'Log message for revision 1.',
89 main.greek_dump_dir, url)
91 # check for any errors from the import
92 if len(errput):
93 display_lines("Errors during initial 'svn import':",
94 'STDERR', None, errput)
95 sys.exit(1)
97 # verify the printed output of 'svn import'.
98 lastline = string.strip(output.pop())
99 cm = re.compile ("(Committed|Imported) revision [0-9]+.")
100 match = cm.search (lastline)
101 if not match:
102 print "ERROR: import did not succeed, while creating greek repos."
103 print "The final line from 'svn import' was:"
104 print lastline
105 sys.exit(1)
106 output_tree = tree.build_tree_from_commit(output)
108 ### due to path normalization in the .old_tree() method, we cannot
109 ### prepend the necessary '.' directory. thus, let's construct an old
110 ### tree manually from the greek_state.
111 output_list = []
112 for greek_path in main.greek_state.desc.keys():
113 output_list.append([ os.path.join(main.greek_dump_dir, greek_path),
114 None, {}, {'verb' : 'Adding'}])
115 expected_output_tree = tree.build_generic_tree(output_list)
117 try:
118 tree.compare_trees(output_tree, expected_output_tree)
119 except tree.SVNTreeUnequal:
120 display_trees("ERROR: output of import command is unexpected.",
121 'OUTPUT TREE', expected_output_tree, output_tree)
122 sys.exit(1)
124 # Now that the pristine repos exists, copy it to PATH.
125 if os.path.exists(path):
126 shutil.rmtree(path)
127 if main.copy_repos(main.pristine_dir, path, 1):
128 print "ERROR: copying repository failed."
129 sys.exit(1)
131 # make the repos world-writeable, for mod_dav_svn's sake.
132 main.chmod_tree(path, 0666, 0666)
135 def run_and_verify_svn(message, expected_stdout, expected_stderr, *varargs):
136 """Invokes main.run_svn with *VARARGS. If EXPECTED_STDOUT or
137 EXPECTED_STDERR is not 'None', invokes compare_and_display_lines
138 with MESSAGE and the expected output. If the comparison fails,
139 compare_and_display_lines will raise."""
140 ### TODO catch and throw particular exceptions from above
141 want_err = None
142 if expected_stderr is not None and expected_stderr is not []:
143 want_err = 1
145 out, err = main.run_svn(want_err, *varargs)
147 if type(expected_stdout) is type([]):
148 compare_and_display_lines(message, 'STDOUT', expected_stdout, out)
149 elif expected_stdout == SVNAnyOutput:
150 if len(out) == 0:
151 if message is not None: print message
152 raise SVNExpectedStdout
153 elif expected_stdout is not None:
154 raise SVNIncorrectDatatype("Unexpected specification for stdout data")
156 if type(expected_stderr) is type([]):
157 compare_and_display_lines(message, 'STDERR', expected_stderr, err)
158 elif expected_stderr == SVNAnyOutput:
159 if len(err) == 0:
160 if message is not None: print message
161 raise SVNExpectedStderr
162 elif expected_stderr is not None:
163 raise SVNIncorrectDatatype("Unexpected specification for stderr data")
164 return out, err
167 ######################################################################
168 # Subversion Actions
170 # These are all routines that invoke 'svn' in particular ways, and
171 # then verify the results by comparing expected trees with actual
172 # trees.
174 # For all the functions below, the OUTPUT_TREE and DISK_TREE args need
175 # to be created by feeding carefully constructed lists to
176 # tree.build_generic_tree(). A STATUS_TREE can be built by
177 # hand, or by editing the tree returned by get_virginal_state().
180 def run_and_verify_checkout(URL, wc_dir_name, output_tree, disk_tree,
181 singleton_handler_a = None,
182 a_baton = None,
183 singleton_handler_b = None,
184 b_baton = None):
185 """Checkout the URL into a new directory WC_DIR_NAME.
187 The subcommand output will be verified against OUTPUT_TREE,
188 and the working copy itself will be verified against DISK_TREE.
189 SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will be passed to
190 tree.compare_trees - see that function's doc string for more details.
191 Returns if successful and raise on failure."""
193 if isinstance(output_tree, wc.State):
194 output_tree = output_tree.old_tree()
195 if isinstance(disk_tree, wc.State):
196 disk_tree = disk_tree.old_tree()
198 # Remove dir if it's already there.
199 main.safe_rmtree(wc_dir_name)
201 # Checkout and make a tree of the output, using l:foo/p:bar
202 ### todo: svn should not be prompting for auth info when using
203 ### repositories with no auth/auth requirements
204 output, errput = main.run_svn (None, 'co',
205 '--username', main.wc_author,
206 '--password', main.wc_passwd,
207 URL, wc_dir_name)
208 mytree = tree.build_tree_from_checkout (output)
210 # Verify actual output against expected output.
211 tree.compare_trees (mytree, output_tree)
213 # Create a tree by scanning the working copy
214 mytree = tree.build_tree_from_wc (wc_dir_name)
216 # Verify expected disk against actual disk.
217 tree.compare_trees (mytree, disk_tree,
218 singleton_handler_a, a_baton,
219 singleton_handler_b, b_baton)
222 def run_and_verify_export(URL, export_dir_name, output_tree, disk_tree,
223 singleton_handler_a = None,
224 a_baton = None,
225 singleton_handler_b = None,
226 b_baton = None):
227 """Export the URL into a new directory WC_DIR_NAME.
229 The subcommand output will be verified against OUTPUT_TREE,
230 and the exported copy itself will be verified against DISK_TREE.
231 SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will be passed to
232 tree.compare_trees - see that function's doc string for more details.
233 Returns if successful and raise on failure."""
235 if isinstance(output_tree, wc.State):
236 output_tree = output_tree.old_tree()
237 if isinstance(disk_tree, wc.State):
238 disk_tree = disk_tree.old_tree()
240 # Export and make a tree of the output, using l:foo/p:bar
241 ### todo: svn should not be prompting for auth info when using
242 ### repositories with no auth/auth requirements
243 output, errput = main.run_svn (None, 'export',
244 '--username', main.wc_author,
245 '--password', main.wc_passwd,
246 URL, export_dir_name)
247 mytree = tree.build_tree_from_checkout (output)
249 # Verify actual output against expected output.
250 tree.compare_trees (mytree, output_tree)
252 # Create a tree by scanning the working copy. Don't ignore
253 # the .svn directories so that we generate an error if they
254 # happen to show up.
255 mytree = tree.build_tree_from_wc (export_dir_name, ignore_svn=0)
257 # Verify expected disk against actual disk.
258 tree.compare_trees (mytree, disk_tree,
259 singleton_handler_a, a_baton,
260 singleton_handler_b, b_baton)
263 def verify_update(actual_output, wc_dir_name,
264 output_tree, disk_tree, status_tree,
265 singleton_handler_a, a_baton,
266 singleton_handler_b, b_baton,
267 check_props):
268 """Verify update of WC_DIR_NAME.
270 The subcommand output (found in ACTUAL_OUTPUT) will be verified
271 against OUTPUT_TREE, and the working copy itself will be verified
272 against DISK_TREE. If optional STATUS_OUTPUT_TREE is given, then
273 'svn status' output will be compared. (This is a good way to check
274 that revision numbers were bumped.) SINGLETON_HANDLER_A and
275 SINGLETON_HANDLER_B will be passed to tree.compare_trees - see that
276 function's doc string for more details. If CHECK_PROPS is set, then
277 disk comparison will examine props. Returns if successful, raises
278 on failure."""
280 # Verify actual output against expected output.
281 tree.compare_trees (actual_output, output_tree)
283 # Create a tree by scanning the working copy
284 mytree = tree.build_tree_from_wc (wc_dir_name, check_props)
286 # Verify expected disk against actual disk.
287 tree.compare_trees (mytree, disk_tree,
288 singleton_handler_a, a_baton,
289 singleton_handler_b, b_baton)
291 # Verify via 'status' command too, if possible.
292 if status_tree:
293 run_and_verify_status(wc_dir_name, status_tree)
296 def run_and_verify_update(wc_dir_name,
297 output_tree, disk_tree, status_tree,
298 error_re_string = None,
299 singleton_handler_a = None,
300 a_baton = None,
301 singleton_handler_b = None,
302 b_baton = None,
303 check_props = 0,
304 *args):
306 """Update WC_DIR_NAME. *ARGS are any extra optional args to the
307 update subcommand. NOTE: If *ARGS is specified at all, explicit
308 target paths must be passed in *ARGS as well (or a default `.' will
309 be chosen by the 'svn' binary). This allows the caller to update
310 many items in a single working copy dir, but still verify the entire
311 working copy dir.
313 If ERROR_RE_STRING, the update must exit with error, and the error
314 message must match regular expression ERROR_RE_STRING.
316 Else if ERROR_RE_STRING is None, then:
318 The subcommand output will be verified against OUTPUT_TREE, and the
319 working copy itself will be verified against DISK_TREE. If optional
320 STATUS_TREE is given, then 'svn status' output will be compared.
321 (This is a good way to check that revision numbers were bumped.)
322 SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will be passed to
323 tree.compare_trees - see that function's doc string for more
324 details.
326 If CHECK_PROPS is set, then disk comparison will examine props.
327 Returns if successful, raises on failure."""
329 if isinstance(output_tree, wc.State):
330 output_tree = output_tree.old_tree()
331 if isinstance(disk_tree, wc.State):
332 disk_tree = disk_tree.old_tree()
333 if isinstance(status_tree, wc.State):
334 status_tree = status_tree.old_tree()
336 # Update and make a tree of the output.
337 if len(args):
338 output, errput = main.run_svn (error_re_string, 'up', *args)
339 else:
340 output, errput = main.run_svn (error_re_string, 'up', wc_dir_name, *args)
342 if (error_re_string):
343 rm = re.compile(error_re_string)
344 for line in errput:
345 match = rm.search(line)
346 if match:
347 return
348 raise main.SVNUnmatchedError
350 mytree = tree.build_tree_from_checkout (output)
351 verify_update (mytree, wc_dir_name,
352 output_tree, disk_tree, status_tree,
353 singleton_handler_a, a_baton,
354 singleton_handler_b, b_baton,
355 check_props)
358 def run_and_verify_merge(dir, rev1, rev2, url,
359 output_tree, disk_tree, status_tree, skip_tree,
360 error_re_string = None,
361 singleton_handler_a = None,
362 a_baton = None,
363 singleton_handler_b = None,
364 b_baton = None,
365 check_props = 0,
366 dry_run = 1,
367 *args):
369 """Run 'svn merge -rREV1:REV2 URL DIR'
371 If ERROR_RE_STRING, the merge must exit with error, and the error
372 message must match regular expression ERROR_RE_STRING.
374 Else if ERROR_RE_STRING is None, then:
376 The subcommand output will be verified against OUTPUT_TREE, and the
377 working copy itself will be verified against DISK_TREE. If optional
378 STATUS_TREE is given, then 'svn status' output will be compared.
379 The 'skipped' merge output will be compared to SKIP_TREE.
380 SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will be passed to
381 tree.compare_trees - see that function's doc string for more
382 details.
384 If CHECK_PROPS is set, then disk comparison will examine props.
386 If DRY_RUN is set then a --dry-run merge will be carried out first and
387 the output compared with that of the full merge.
389 Returns if successful, raises on failure."""
391 if isinstance(output_tree, wc.State):
392 output_tree = output_tree.old_tree()
393 if isinstance(disk_tree, wc.State):
394 disk_tree = disk_tree.old_tree()
395 if isinstance(status_tree, wc.State):
396 status_tree = status_tree.old_tree()
397 if isinstance(skip_tree, wc.State):
398 skip_tree = skip_tree.old_tree()
400 merge_command = ('merge', '-r', rev1 + ':' + rev2, url, dir)
402 if dry_run:
403 pre_disk = tree.build_tree_from_wc(dir)
404 dry_run_command = merge_command + ('--dry-run',)
405 dry_run_command = dry_run_command + args
406 out_dry, err_dry = main.run_svn(error_re_string, *dry_run_command)
407 post_disk = tree.build_tree_from_wc(dir)
408 try:
409 tree.compare_trees(post_disk, pre_disk)
410 except tree.SVNTreeError:
411 print "============================================================="
412 print "Dry-run merge altered working copy"
413 print "============================================================="
414 raise
417 # Update and make a tree of the output.
418 merge_command = merge_command + args
419 out, err = main.run_svn (error_re_string, *merge_command)
421 if (error_re_string):
422 rm = re.compile(error_re_string)
423 for line in err:
424 match = rm.search(line)
425 if match:
426 return
427 raise main.SVNUnmatchedError
428 elif err:
429 ### we should raise a less generic error here. which?
430 raise Failure(err)
432 if dry_run and out != out_dry:
433 print "============================================================="
434 print "Merge outputs differ"
435 print "The dry-run merge output:"
436 map(sys.stdout.write, out_dry)
437 print "The full merge output:"
438 map(sys.stdout.write, out)
439 print "============================================================="
440 raise main.SVNUnmatchedError
442 def missing_skip(a, b):
443 print "============================================================="
444 print "Merge failed to skip: " + a.path
445 print "============================================================="
446 raise Failure
447 def extra_skip(a, b):
448 print "============================================================="
449 print "Merge unexpectedly skipped: " + a.path
450 print "============================================================="
451 raise Failure
453 myskiptree = tree.build_tree_from_skipped(out)
454 tree.compare_trees(myskiptree, skip_tree,
455 extra_skip, None, missing_skip, None)
457 mytree = tree.build_tree_from_checkout(out)
458 verify_update (mytree, dir,
459 output_tree, disk_tree, status_tree,
460 singleton_handler_a, a_baton,
461 singleton_handler_b, b_baton,
462 check_props)
465 def run_and_verify_switch(wc_dir_name,
466 wc_target,
467 switch_url,
468 output_tree, disk_tree, status_tree,
469 singleton_handler_a = None,
470 a_baton = None,
471 singleton_handler_b = None,
472 b_baton = None,
473 check_props = 0):
475 """Switch WC_TARGET (in working copy dir WC_DIR_NAME) to SWITCH_URL.
477 The subcommand output will be verified against OUTPUT_TREE, and the
478 working copy itself will be verified against DISK_TREE. If optional
479 STATUS_OUTPUT_TREE is given, then 'svn status' output will be
480 compared. (This is a good way to check that revision numbers were
481 bumped.) SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will be passed to
482 tree.compare_trees - see that function's doc string for more details.
483 If CHECK_PROPS is set, then disk comparison will examine props.
484 Returns if successful, raises on failure."""
486 if isinstance(output_tree, wc.State):
487 output_tree = output_tree.old_tree()
488 if isinstance(disk_tree, wc.State):
489 disk_tree = disk_tree.old_tree()
490 if isinstance(status_tree, wc.State):
491 status_tree = status_tree.old_tree()
493 # Update and make a tree of the output.
494 output, errput = main.run_svn (None, 'switch',
495 '--username', main.wc_author,
496 '--password', main.wc_passwd,
497 switch_url, wc_target)
498 mytree = tree.build_tree_from_checkout (output)
500 verify_update (mytree, wc_dir_name,
501 output_tree, disk_tree, status_tree,
502 singleton_handler_a, a_baton,
503 singleton_handler_b, b_baton,
504 check_props)
507 def run_and_verify_commit(wc_dir_name, output_tree, status_output_tree,
508 error_re_string = None,
509 singleton_handler_a = None,
510 a_baton = None,
511 singleton_handler_b = None,
512 b_baton = None,
513 *args):
514 """Commit and verify results within working copy WC_DIR_NAME,
515 sending ARGS to the commit subcommand.
517 The subcommand output will be verified against OUTPUT_TREE. If
518 optional STATUS_OUTPUT_TREE is given, then 'svn status' output will
519 be compared. (This is a good way to check that revision numbers
520 were bumped.)
522 If ERROR_RE_STRING is None, the commit must not exit with error. If
523 ERROR_RE_STRING is a string, the commit must exit with error, and
524 the error message must match regular expression ERROR_RE_STRING.
526 SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will be passed to
527 tree.compare_trees - see that function's doc string for more
528 details. Returns if successful, raises on failure."""
530 if isinstance(output_tree, wc.State):
531 output_tree = output_tree.old_tree()
532 if isinstance(status_output_tree, wc.State):
533 status_output_tree = status_output_tree.old_tree()
535 # Commit.
536 output, errput = main.run_svn(error_re_string, 'ci', '-m', 'log msg', *args)
538 if (error_re_string):
539 rm = re.compile(error_re_string)
540 for line in errput:
541 match = rm.search(line)
542 if match:
543 return
544 raise main.SVNUnmatchedError
546 # Else not expecting error:
548 # Remove the final output line, and verify that the commit succeeded.
549 lastline = ""
550 if len(output):
551 lastline = string.strip(output.pop())
553 cm = re.compile("(Committed|Imported) revision [0-9]+.")
554 match = cm.search(lastline)
555 if not match:
556 print "ERROR: commit did not succeed."
557 print "The final line from 'svn ci' was:"
558 print lastline
559 raise main.SVNCommitFailure
561 # The new 'final' line in the output is either a regular line that
562 # mentions {Adding, Deleting, Sending, ...}, or it could be a line
563 # that says "Transmitting file data ...". If the latter case, we
564 # want to remove the line from the output; it should be ignored when
565 # building a tree.
566 if len(output):
567 lastline = output.pop()
569 tm = re.compile("Transmitting file data.+")
570 match = tm.search(lastline)
571 if not match:
572 # whoops, it was important output, put it back.
573 output.append(lastline)
575 # Convert the output into a tree.
576 mytree = tree.build_tree_from_commit (output)
578 # Verify actual output against expected output.
579 try:
580 tree.compare_trees (mytree, output_tree)
581 except tree.SVNTreeError:
582 display_trees("Output of commit is unexpected.",
583 "OUTPUT TREE", output_tree, mytree)
584 raise
586 # Verify via 'status' command too, if possible.
587 if status_output_tree:
588 run_and_verify_status(wc_dir_name, status_output_tree)
591 # This function always passes '-q' to the status command, which
592 # suppresses the printing of any unversioned or nonexistent items.
593 def run_and_verify_status(wc_dir_name, output_tree,
594 singleton_handler_a = None,
595 a_baton = None,
596 singleton_handler_b = None,
597 b_baton = None):
598 """Run 'status' on WC_DIR_NAME and compare it with the
599 expected OUTPUT_TREE. SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will
600 be passed to tree.compare_trees - see that function's doc string for
601 more details.
602 Returns on success, raises on failure."""
604 if isinstance(output_tree, wc.State):
605 output_tree = output_tree.old_tree()
607 output, errput = main.run_svn (None, 'status', '-v', '-u', '-q', wc_dir_name)
609 mytree = tree.build_tree_from_status (output)
611 # Verify actual output against expected output.
612 if (singleton_handler_a or singleton_handler_b):
613 try:
614 tree.compare_trees (mytree, output_tree,
615 singleton_handler_a, a_baton,
616 singleton_handler_b, b_baton)
617 except tree.SVNTreeError:
618 display_trees(None, 'OUTPUT TREE', output_tree, mytree)
619 raise
620 else:
621 try:
622 tree.compare_trees (mytree, output_tree)
623 except tree.SVNTreeError:
624 display_trees(None, 'OUTPUT TREE', output_tree, mytree)
625 raise
628 # A variant of previous func, but doesn't pass '-q'. This allows us
629 # to verify unversioned or nonexistent items in the list.
630 def run_and_verify_unquiet_status(wc_dir_name, output_tree,
631 singleton_handler_a = None,
632 a_baton = None,
633 singleton_handler_b = None,
634 b_baton = None):
635 """Run 'status' on WC_DIR_NAME and compare it with the
636 expected OUTPUT_TREE. SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will
637 be passed to tree.compare_trees - see that function's doc string for
638 more details.
639 Returns on success, raises on failure."""
641 if isinstance(output_tree, wc.State):
642 output_tree = output_tree.old_tree()
644 output, errput = main.run_svn (None, 'status', '-v', '-u', wc_dir_name)
646 mytree = tree.build_tree_from_status (output)
648 # Verify actual output against expected output.
649 if (singleton_handler_a or singleton_handler_b):
650 tree.compare_trees (mytree, output_tree,
651 singleton_handler_a, a_baton,
652 singleton_handler_b, b_baton)
653 else:
654 tree.compare_trees (mytree, output_tree)
657 ######################################################################
658 # Displaying expected and actual output
660 def display_trees(message, label, expected, actual):
661 'Print two trees, expected and actual.'
662 if message is not None:
663 print message
664 if expected is not None:
665 print 'EXPECTED', label + ':'
666 tree.dump_tree(expected)
667 if actual is not None:
668 print 'ACTUAL', label + ':'
669 tree.dump_tree(actual)
672 def display_lines(message, label, expected, actual):
673 'Print two sets of output lines, expected and actual.'
674 if message is not None:
675 print message
676 if expected is not None:
677 print 'EXPECTED', label + ':'
678 map(sys.stdout.write, expected)
679 if actual is not None:
680 print 'ACTUAL', label + ':'
681 map(sys.stdout.write, actual)
683 def compare_and_display_lines(message, label, expected, actual):
684 'Compare two sets of output lines, and print them if they differ.'
685 # This catches the None vs. [] cases
686 if expected is None: exp = []
687 else: exp = expected
688 if actual is None: act = []
689 else: act = actual
691 if exp != act:
692 display_lines(message, label, expected, actual)
693 raise main.SVNLineUnequal
696 ######################################################################
697 # Other general utilities
700 # This allows a test to *quickly* bootstrap itself.
701 def make_repo_and_wc(sbox):
702 """Create a fresh repository and checkout a wc from it.
704 The repo and wc directories will both be named TEST_NAME, and
705 repsectively live within the global dirs 'general_repo_dir' and
706 'general_wc_dir' (variables defined at the top of this test
707 suite.) Returns on success, raises on failure."""
709 # Store the path of the current repository.
710 main.set_repos_paths(sbox.repo_dir)
712 # Create (or copy afresh) a new repos with a greek tree in it.
713 guarantee_greek_repository(sbox.repo_dir)
715 # Generate the expected output tree.
716 expected_output = main.greek_state.copy()
717 expected_output.wc_dir = sbox.wc_dir
718 expected_output.tweak(status='A ', contents=None)
720 # Generate an expected wc tree.
721 expected_wc = main.greek_state
723 # Do a checkout, and verify the resulting output and disk contents.
724 run_and_verify_checkout(main.current_repo_url,
725 sbox.wc_dir,
726 expected_output,
727 expected_wc)
730 # Duplicate a working copy or other dir.
731 def duplicate_dir(wc_name, wc_copy_name):
732 """Copy the working copy WC_NAME to WC_COPY_NAME. Overwrite any
733 existing tree at that location."""
735 if os.path.exists(wc_copy_name):
736 main.safe_rmtree(wc_copy_name)
737 shutil.copytree(wc_name, wc_copy_name)
741 def get_virginal_state(wc_dir, rev):
742 "Return a virginal greek tree state for a WC and repos at revision REV."
744 rev = str(rev) ### maybe switch rev to an integer?
746 # copy the greek tree, shift it to the new wc_dir, insert a root elem,
747 # then tweak all values
748 state = main.greek_state.copy()
749 state.wc_dir = wc_dir
750 state.desc[''] = wc.StateItem()
751 state.tweak(contents=None, status=' ', wc_rev=rev, repos_rev=rev)
753 return state
756 # Cheap administrative directory locking
757 def lock_admin_dir(wc_dir):
758 "Lock a SVN administrative directory"
760 path = os.path.join(wc_dir, main.get_admin_name(), 'lock')
761 main.file_append(path, "stop looking!")
764 ### End of file.