3 # log_tests.py: testing "svn log"
5 # Subversion is a tool for revision control.
6 # See http://subversion.tigris.org for more information.
8 # ====================================================================
9 # Copyright (c) 2000-2008 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 ######################################################################
24 from svntest
import wc
26 from svntest
.main
import server_has_mergeinfo
27 from svntest
.main
import SVN_PROP_MERGEINFO
29 ######################################################################
33 # Get a repository, commit about 6 or 7 revisions to it, each
34 # involving different kinds of operations. Make sure to have some
35 # add, del, mv, cp, as well as file modifications, and make sure that
36 # some files are modified more than once.
38 # Give each commit a recognizable log message. Test all combinations
39 # of -r options, including none. Then test with -v, which will
40 # (presumably) show changed paths as well.
42 ######################################################################
46 ######################################################################
50 # These variables are set by guarantee_repos_and_wc().
51 max_revision
= 0 # Highest revision in the repos
53 # What separates log msgs from one another in raw log output.
54 msg_separator
= '------------------------------------' \
55 + '------------------------------------\n'
59 Skip
= svntest
.testcase
.Skip
60 SkipUnless
= svntest
.testcase
.SkipUnless
61 XFail
= svntest
.testcase
.XFail
62 Item
= svntest
.wc
.StateItem
65 ######################################################################
69 def guarantee_repos_and_wc(sbox
):
70 "Make a repos and wc, commit max_revision revs."
75 msg_file
=os
.path
.join(sbox
.repo_dir
, 'log-msg')
76 msg_file
=os
.path
.abspath(msg_file
)
78 # Now we have a repos and wc at revision 1.
83 # Set up the paths we'll be using most often.
84 iota_path
= os
.path
.join('iota')
85 mu_path
= os
.path
.join('A', 'mu')
86 B_path
= os
.path
.join('A', 'B')
87 omega_path
= os
.path
.join('A', 'D', 'H', 'omega')
88 pi_path
= os
.path
.join('A', 'D', 'G', 'pi')
89 rho_path
= os
.path
.join('A', 'D', 'G', 'rho')
90 alpha_path
= os
.path
.join('A', 'B', 'E', 'alpha')
91 beta_path
= os
.path
.join('A', 'B', 'E', 'beta')
92 psi_path
= os
.path
.join('A', 'D', 'H', 'psi')
93 epsilon_path
= os
.path
.join('A', 'C', 'epsilon')
95 # Do a varied bunch of commits. No copies yet, we'll wait till Ben
98 # Revision 2: edit iota
99 msg
=""" Log message for revision 2
100 but with multiple lines
102 svntest
.main
.file_write(msg_file
, msg
)
103 svntest
.main
.file_append(iota_path
, "2")
104 svntest
.main
.run_svn(None,
105 'ci', '-F', msg_file
)
106 svntest
.main
.run_svn(None,
109 # Revision 3: edit A/D/H/omega, A/D/G/pi, A/D/G/rho, and A/B/E/alpha
110 svntest
.main
.file_append(omega_path
, "3")
111 svntest
.main
.file_append(pi_path
, "3")
112 svntest
.main
.file_append(rho_path
, "3")
113 svntest
.main
.file_append(alpha_path
, "3")
114 svntest
.main
.run_svn(None,
115 'ci', '-m', "Log message for revision 3")
116 svntest
.main
.run_svn(None,
119 # Revision 4: edit iota again, add A/C/epsilon
120 msg
=""" Log message for revision 4
121 but with multiple lines
123 svntest
.main
.file_write(msg_file
, msg
)
124 svntest
.main
.file_append(iota_path
, "4")
125 svntest
.main
.file_append(epsilon_path
, "4")
126 svntest
.main
.run_svn(None, 'add', epsilon_path
)
127 svntest
.main
.run_svn(None,
128 'ci', '-F', msg_file
)
129 svntest
.main
.run_svn(None,
132 # Revision 5: edit A/C/epsilon, delete A/D/G/rho
133 svntest
.main
.file_append(epsilon_path
, "5")
134 svntest
.main
.run_svn(None, 'rm', rho_path
)
135 svntest
.main
.run_svn(None,
136 'ci', '-m', "Log message for revision 5")
137 svntest
.main
.run_svn(None,
140 # Revision 6: prop change on A/B, edit A/D/H/psi
141 msg
=""" Log message for revision 6
142 but with multiple lines
144 svntest
.main
.file_write(msg_file
, msg
)
145 svntest
.main
.run_svn(None, 'ps', 'blue', 'azul', B_path
)
146 svntest
.main
.file_append(psi_path
, "6")
147 svntest
.main
.run_svn(None,
148 'ci', '-F', msg_file
)
149 svntest
.main
.run_svn(None,
152 # Revision 7: edit A/mu, prop change on A/mu
153 svntest
.main
.file_append(mu_path
, "7")
154 svntest
.main
.run_svn(None, 'ps', 'red', 'burgundy', mu_path
)
155 svntest
.main
.run_svn(None,
156 'ci', '-m', "Log message for revision 7")
157 svntest
.main
.run_svn(None,
160 # Revision 8: edit iota yet again, re-add A/D/G/rho
161 msg
=""" Log message for revision 8
162 but with multiple lines
164 svntest
.main
.file_write(msg_file
, msg
)
165 svntest
.main
.file_append(iota_path
, "8")
166 svntest
.main
.file_append(rho_path
, "8")
167 svntest
.main
.run_svn(None, 'add', rho_path
)
168 svntest
.main
.run_svn(None,
169 'ci', '-F', msg_file
)
170 svntest
.main
.run_svn(None,
173 # Revision 9: edit A/B/E/beta, delete A/B/E/alpha
174 svntest
.main
.file_append(beta_path
, "9")
175 svntest
.main
.run_svn(None, 'rm', alpha_path
)
176 svntest
.main
.run_svn(None,
177 'ci', '-m', "Log message for revision 9")
178 svntest
.main
.run_svn(None,
186 # Let's run 'svn status' and make sure the working copy looks
187 # exactly the way we think it should. Start with a generic
188 # greek-tree-list, where every local and repos revision is at 9.
189 expected_status
= svntest
.actions
.get_virginal_state(wc_path
, 9)
190 expected_status
.remove('A/B/E/alpha')
191 expected_status
.add({
192 'A/C/epsilon' : Item(status
=' ', wc_rev
=9),
195 # props exist on A/B and A/mu
196 expected_status
.tweak('A/B', 'A/mu', status
=' ')
198 # Run 'svn st -uv' and compare the actual results with our tree.
199 svntest
.actions
.run_and_verify_status(wc_path
, expected_status
)
202 def merge_history_repos(sbox
):
203 """Make a repos with varied and interesting merge history, similar
204 to the repos found at:
205 http://merge-tracking.open.collab.net/servlets/ProjectProcess?documentContainer=c2__Sample%20repository"""
207 upsilon_path
= os
.path
.join('A', 'upsilon')
208 omicron_path
= os
.path
.join('blocked', 'omicron')
209 branch_a
= os
.path
.join('branches', 'a')
210 branch_b
= os
.path
.join('branches', 'b')
211 branch_c
= os
.path
.join('branches', 'c')
213 # Create an empty repository - r0
214 svntest
.main
.safe_rmtree(sbox
.repo_dir
, 1)
215 svntest
.main
.safe_rmtree(sbox
.wc_dir
, 1)
216 svntest
.main
.create_repos(sbox
.repo_dir
)
218 svntest
.actions
.run_and_verify_svn(None, None, [], "co", sbox
.repo_url
,
220 was_cwd
= os
.getcwd()
221 os
.chdir(sbox
.wc_dir
)
223 # Create trunk/tags/branches - r1
224 svntest
.main
.run_svn(None, 'mkdir', 'trunk')
225 svntest
.main
.run_svn(None, 'mkdir', 'tags')
226 svntest
.main
.run_svn(None, 'mkdir', 'branches')
227 svntest
.main
.run_svn(None, 'ci', '-m',
228 'Add trunk/tags/branches structure.')
230 # Import greek tree to trunk - r2
231 svntest
.main
.greek_state
.write_to_disk('trunk')
232 svntest
.main
.run_svn(None, 'add', os
.path
.join('trunk', 'A'),
233 os
.path
.join('trunk', 'iota'))
234 svntest
.main
.run_svn(None, 'ci', '-m',
235 'Import greek tree into trunk.')
237 # Update from the repository to avoid a mix-rev working copy
238 svntest
.main
.run_svn(None, 'up')
240 # Create a branch - r3
241 svntest
.main
.run_svn(None, 'cp', 'trunk', branch_a
)
242 svntest
.main
.run_svn(None, 'ci', '-m',
243 'Create branches/a from trunk.',
244 '--username', svntest
.main
.wc_author2
)
246 # Some changes on the branch - r4
247 svntest
.main
.file_append_binary(os
.path
.join(branch_a
, 'iota'),
248 "'A' has changed a bit.\n")
249 svntest
.main
.file_append_binary(os
.path
.join(branch_a
, 'A', 'mu'),
250 "Don't forget to look at 'upsilon', too.")
251 svntest
.main
.file_write(os
.path
.join(branch_a
, upsilon_path
),
252 "This is the file 'upsilon'.\n", "wb")
253 svntest
.main
.run_svn(None, 'add',
254 os
.path
.join(branch_a
, upsilon_path
))
255 svntest
.main
.run_svn(None, 'ci', '-m',
256 "Add the file 'upsilon', and change some other files.")
258 # Create another branch - r5
259 svntest
.main
.run_svn(None, 'cp', 'trunk', branch_c
)
260 svntest
.main
.run_svn(None, 'ci', '-m',
261 'Create branches/c from trunk.',
262 '--username', svntest
.main
.wc_author2
)
264 # Do some mergeing - r6
266 svntest
.main
.run_svn(None, 'merge', os
.path
.join('..', branch_a
) + '@HEAD')
267 svntest
.main
.run_svn(None, 'ci', '-m',
268 'Merged branches/a to trunk.',
269 '--username', svntest
.main
.wc_author2
)
272 # Add omicron to branches/a - r7
273 svntest
.main
.run_svn(None, 'mkdir', os
.path
.join(branch_a
, 'blocked'))
274 svntest
.main
.file_write(os
.path
.join(branch_a
, omicron_path
),
275 "This is the file 'omicron'.\n")
276 svntest
.main
.run_svn(None, 'add',
277 os
.path
.join(branch_a
, omicron_path
))
278 svntest
.main
.run_svn(None, 'ci', '-m',
279 "Add omicron to branches/a. " +
280 "It will be blocked from merging in r8.")
282 # Block r7 from being merged to trunk - r8
284 svntest
.main
.run_svn(None, 'merge', '--record-only', '-r6:7',
285 os
.path
.join('..', branch_a
))
286 svntest
.main
.run_svn(None, 'ci', '-m',
287 "Block r7 from merging to trunk.",
288 '--username', svntest
.main
.wc_author2
)
291 # Wording change in mu - r9
292 svntest
.main
.file_write(os
.path
.join('trunk', 'A', 'mu'),
293 "This is the file 'mu'.\n" +
294 "Don't forget to look at 'upsilon', as well.", "wb")
295 svntest
.main
.run_svn(None, 'ci', '-m',
296 "Wording change in mu.")
298 # Update from the repository to avoid a mix-rev working copy
299 svntest
.main
.run_svn(None, 'up')
301 # Create another branch - r10
302 svntest
.main
.run_svn(None, 'cp', 'trunk', branch_b
)
303 svntest
.main
.run_svn(None, 'ci', '-m',
304 "Create branches/b from trunk",
305 '--username', svntest
.main
.wc_author2
)
307 # Add another file, make some changes on branches/a - r11
308 svntest
.main
.file_append_binary(os
.path
.join(branch_a
, upsilon_path
),
309 "There is also the file 'xi'.")
310 svntest
.main
.file_write(os
.path
.join(branch_a
, 'A', 'xi'),
311 "This is the file 'xi'.\n", "wb")
312 svntest
.main
.run_svn(None, 'add',
313 os
.path
.join(branch_a
, 'A', 'xi'))
314 svntest
.main
.file_write(os
.path
.join(branch_a
, 'iota'),
315 "This is the file 'iota'.\n" +
316 "'A' has changed a bit, with 'upsilon', and 'xi'.",
318 svntest
.main
.run_svn(None, 'ci', '-m',
319 "Added 'xi' to branches/a, made a few other changes.")
321 # Merge branches/a to branches/b - r12
323 svntest
.main
.run_svn(None, 'merge', os
.path
.join('..', 'a') + '@HEAD')
324 svntest
.main
.run_svn(None, 'ci', '-m',
325 "Merged branches/a to branches/b.",
326 '--username', svntest
.main
.wc_author2
)
327 os
.chdir(os
.path
.join('..', '..'))
329 # More wording changes - r13
330 svntest
.main
.file_append_binary(os
.path
.join(branch_b
, 'A', 'D', 'gamma'),
331 "Watch out for the rays!")
332 svntest
.main
.run_svn(None, 'ci', '-m',
333 "Modify 'gamma' on branches/b.")
337 svntest
.main
.run_svn(None, 'merge', os
.path
.join('..', branch_b
) + '@HEAD')
338 svntest
.main
.run_svn(None, 'ci', '-m',
339 "Merged branches/b to trunk.",
340 '--username', svntest
.main
.wc_author2
)
343 # Even more merging - r15
345 svntest
.main
.run_svn(None, 'merge',
346 os
.path
.join('..', '..', 'trunk') + '@HEAD')
347 svntest
.main
.run_svn(None, 'ci', '-m',
348 "Bring branches/c up to date with trunk.",
349 '--username', svntest
.main
.wc_author2
)
350 os
.chdir(os
.path
.join('..', '..'))
352 # Modify a file on branches/c - r16
353 svntest
.main
.file_append_binary(os
.path
.join(branch_c
, 'A', 'mu'),
354 "\nThis is yet more content in 'mu'.")
355 svntest
.main
.run_svn(None, 'ci', '-m',
356 "Modify 'mu' on branches/c.")
358 # Merge branches/c to trunk, which produces a conflict - r17
360 svntest
.main
.run_svn(None, 'merge', os
.path
.join('..', branch_c
) + '@HEAD')
361 svntest
.main
.file_write(os
.path
.join('A', 'mu'),
362 "This is the file 'mu'.\n" +
363 "Don't forget to look at 'upsilon', as well.\n" +
364 "This is yet more content in 'mu'.",
366 svntest
.main
.run_svn(None, 'resolved', os
.path
.join('A', 'mu'))
367 svntest
.main
.run_svn(None, 'ci', '-m',
368 "Merge branches/c to trunk, " +
369 "resolving a conflict in 'mu'.",
370 '--username', svntest
.main
.wc_author2
)
373 # Restore working directory
377 # For errors seen while parsing log data.
378 class SVNLogParseError(Exception):
379 def __init__(self
, args
=None):
383 def parse_log_output(log_lines
):
384 """Return a log chain derived from LOG_LINES.
385 A log chain is a list of hashes; each hash represents one log
386 message, in the order it appears in LOG_LINES (the first log
387 message in the data is also the first element of the list, and so
390 Each hash contains the following keys/values:
392 'revision' ===> number
395 'msg' ===> string (the log message itself)
396 'lines' ===> number (so that it may be checked against rev)
397 If LOG_LINES contains changed-path information, then the hash
400 'paths' ===> list of tuples of the form (X, PATH), where X is the
401 first column of verbose output, and PATH is the affected path.
403 If LOG_LINES contains merge result information, then the hash also contains
405 'merges' ===> list of merging revisions that resulted in this log
406 being part of the list of messages.
409 # Here's some log output to look at while writing this function:
411 # ------------------------------------------------------------------------
412 # r5 | kfogel | Tue 6 Nov 2001 17:18:19 | 1 line
414 # Log message for revision 5.
415 # ------------------------------------------------------------------------
416 # r4 | kfogel | Tue 6 Nov 2001 17:18:18 | 3 lines
418 # Log message for revision 4
419 # but with multiple lines
421 # ------------------------------------------------------------------------
422 # r3 | kfogel | Tue 6 Nov 2001 17:18:17 | 1 line
424 # Log message for revision 3.
425 # ------------------------------------------------------------------------
426 # r2 | kfogel | Tue 6 Nov 2001 17:18:16 | 3 lines
428 # Log message for revision 2
429 # but with multiple lines
431 # ------------------------------------------------------------------------
432 # r1 | foo | Tue 6 Nov 2001 15:27:57 | 1 line
434 # Log message for revision 1.
435 # ------------------------------------------------------------------------
437 # Regular expression to match the header line of a log message, with
438 # these groups: (revision number), (author), (date), (num lines).
439 header_re
= re
.compile('^r([0-9]+) \| ' \
440 + '([^|]*) \| ([^|]*) \| ([0-9]+) lines?')
442 # The log chain to return.
448 this_line
= log_lines
.pop(0)
452 match
= header_re
.search(this_line
)
453 if match
and match
.groups():
456 this_item
['revision'] = int(match
.group(1))
457 this_item
['author'] = match
.group(2)
458 this_item
['date'] = match
.group(3)
459 lines
= int(match
.group(4))
460 this_item
['lines'] = lines
462 # Parse verbose output, starting with "Changed paths"
463 next_line
= log_lines
.pop(0)
464 if next_line
.strip() == 'Changed paths:':
466 path_line
= log_lines
.pop(0).strip()
468 # Stop on either a blank line or a "Merged via: ..." line
469 while path_line
!= '' and path_line
[0:6] != 'Merged':
470 paths
.append( (path_line
[0], path_line
[2:]) )
471 path_line
= log_lines
.pop(0).strip()
473 this_item
['paths'] = paths
475 if path_line
[0:6] == 'Merged':
477 result_line
= path_line
479 elif next_line
[0:6] == 'Merged':
481 result_line
= next_line
.strip()
483 # Parse output of "Merged via: ..." line
486 prefix_len
= len('Merged via: ')
487 for rev_str
in result_line
[prefix_len
:].split(','):
488 merges
.append(int(rev_str
.strip()[1:]))
489 this_item
['merges'] = merges
494 # Accumulate the log message
496 for line
in log_lines
[0:lines
]:
498 del log_lines
[0:lines
]
499 elif this_line
== msg_separator
:
501 this_item
['msg'] = msg
502 chain
.append(this_item
)
503 else: # if didn't see separator now, then something's wrong
505 raise SVNLogParseError
, "trailing garbage after log message"
510 class SVNUnexpectedLogs(svntest
.Failure
):
511 "Exception raised if a set of log messages doesn't meet expectations."
513 def __init__(self
, msg
, chain
, field_selector
= 'revision'):
514 """Stores the log chain for later use. FIELD_SELECTOR indicates
515 which individual field to display when turning the exception into
517 svntest
.Failure
.__init
__(self
, msg
)
519 self
.field_selector
= field_selector
522 msg
= svntest
.Failure
.__str
__(self
)
524 chain_data
= list(self
.chain
)
525 for i
in range(0, len(self
.chain
)):
526 chain_data
[i
] = self
.chain
[i
][self
.field_selector
]
527 msg
= msg
+ ': Actual %s list was %s' % (self
.field_selector
, chain_data
)
531 def check_log_chain(chain
, revlist
, path_counts
=[]):
532 """Verify that log chain CHAIN contains the right log messages for
533 revisions START to END (see documentation for parse_log_output() for
534 more about log chains).
536 Do nothing if the log chain's messages run from revision START to END
537 and each log message contains a line of the form
539 'Log message for revision N'
541 where N is the revision number of that commit. Verify that
542 author and date are present and look sane, but don't check them too
544 Also verify that even numbered commit messages have three lines.
546 If the length of PATH_COUNTS is greater than zero, make sure that each
547 log has that number of paths.
549 Raise an error if anything looks wrong.
552 nbr_expected
= len(revlist
)
553 if len(chain
) != nbr_expected
:
554 raise SVNUnexpectedLogs('Number of elements in log chain and revision ' +
555 'list %s not equal' % revlist
, chain
)
556 if path_counts
and len(path_counts
) != nbr_expected
:
557 raise SVNUnexpectedLogs('Number of elements in log chain and path ' +
558 'counts %s not equal' % path_counts
, chain
)
560 for i
in range(0, nbr_expected
):
561 expect_rev
= revlist
[i
]
563 saw_rev
= log_item
['revision']
564 date
= log_item
['date']
565 author
= log_item
['author']
566 msg
= log_item
['msg']
567 # The most important check is that the revision is right:
568 if expect_rev
!= saw_rev
:
569 missing_revs
.append(expect_rev
)
571 # Check that date looks at least vaguely right:
572 date_re
= re
.compile('[0-9]+')
573 if not date_re
.search(date
):
574 raise SVNUnexpectedLogs('Malformed date', chain
, 'date')
575 # Authors are a little harder, since they might not exist over ra-dav.
576 # Well, it's not much of a check, but we'll do what we can.
577 author_re
= re
.compile('[a-zA-Z]+')
578 if (not (author_re
.search(author
)
580 or author
== '(no author)')):
581 raise SVNUnexpectedLogs('Malformed author', chain
, 'author')
583 # Verify the expectation that even-numbered revisions in the Greek
584 # tree tweaked by the log tests have 3-line log messages.
585 if (saw_rev
% 2 == 0 and log_item
['lines'] != 3):
586 raise SVNUnexpectedLogs('Malformed log line counts', chain
, 'lines')
588 # Check that the log message looks right:
589 pattern
= 'Log message for revision ' + `saw_rev`
590 msg_re
= re
.compile(pattern
)
591 if not msg_re
.search(msg
):
592 raise SVNUnexpectedLogs("Malformed log message, expected '%s'" % msg
,
595 # If path_counts, check the number of changed paths
597 if (not 'paths' in log_item
) or (not log_item
['paths']):
598 raise SVNUnexpectedLogs("No changed path information", chain
)
599 if path_counts
[i
] != len(log_item
['paths']):
600 raise SVNUnexpectedLogs("Changed paths counts not equal for " +
601 "revision %d" % (i
+ 1), chain
)
603 nbr_missing_revs
= len(missing_revs
)
604 if nbr_missing_revs
> 0:
605 raise SVNUnexpectedLogs('Unable to find expected revision(s) %s' %
610 ######################################################################
614 #----------------------------------------------------------------------
616 "'svn log', no args, top of wc"
618 guarantee_repos_and_wc(sbox
)
620 os
.chdir(sbox
.wc_dir
)
622 exit_code
, output
, err
= svntest
.actions
.run_and_verify_svn(None, None, [],
625 log_chain
= parse_log_output(output
)
626 check_log_chain(log_chain
, range(max_revision
, 1 - 1, -1))
629 #----------------------------------------------------------------------
630 def log_with_empty_repos(sbox
):
631 "'svn log' on an empty repository"
633 # Create virgin repos
634 svntest
.main
.safe_rmtree(sbox
.repo_dir
, 1)
635 svntest
.main
.create_repos(sbox
.repo_dir
)
637 svntest
.actions
.run_and_verify_svn(None, None, [],
641 #----------------------------------------------------------------------
642 def log_where_nothing_changed(sbox
):
643 "'svn log -rN some_dir_unchanged_in_N'"
646 # Fix bug whereby running 'svn log -rN SOMEPATH' would result in an
647 # xml protocol error if there were no changes in revision N
648 # underneath SOMEPATH. This problem was introduced in revision
649 # 3811, which didn't cover the case where svn_repos_get_logs might
650 # invoke log_receiver zero times. Since the receiver never ran, the
651 # lrb->needs_header flag never got cleared. Control would proceed
652 # without error to the end of dav_svn__log_report(), which would
653 # send a closing tag even though no opening tag had ever been sent.
655 rho_path
= os
.path
.join(sbox
.wc_dir
, 'A', 'D', 'G', 'rho')
656 svntest
.main
.file_append(rho_path
, "some new material in rho")
657 svntest
.actions
.run_and_verify_svn(None, None, [],
661 # Now run 'svn log -r2' on a directory unaffected by revision 2.
662 H_path
= os
.path
.join(sbox
.wc_dir
, 'A', 'D', 'H')
663 svntest
.actions
.run_and_verify_svn(None, None, [],
664 'log', '-r', '2', H_path
)
667 #----------------------------------------------------------------------
668 def log_to_revision_zero(sbox
):
669 "'svn log -v -r 1:0 wc_root'"
670 sbox
.build(read_only
= True)
672 # This used to segfault the server.
674 svntest
.actions
.run_and_verify_svn(None, None, [],
676 '-r', '1:0', sbox
.wc_dir
)
678 #----------------------------------------------------------------------
679 def log_with_path_args(sbox
):
680 "'svn log', with args, top of wc"
682 guarantee_repos_and_wc(sbox
)
684 os
.chdir(sbox
.wc_dir
)
686 exit_code
, output
, err
= svntest
.actions
.run_and_verify_svn(
688 'log', sbox
.repo_url
, 'A/D/G', 'A/D/H')
690 log_chain
= parse_log_output(output
)
691 check_log_chain(log_chain
, [8, 6, 5, 3, 1])
693 #----------------------------------------------------------------------
694 def dynamic_revision(sbox
):
695 "'svn log -r COMMITTED' of dynamic/local WC rev"
697 guarantee_repos_and_wc(sbox
)
698 os
.chdir(sbox
.wc_dir
)
700 revprops
= [{'svn:author': 'jrandom',
701 'svn:date': '', 'svn:log': 'Log message for revision 9'}]
702 for rev
in ('HEAD', 'BASE', 'COMMITTED'):
703 svntest
.actions
.run_and_verify_log_xml(expected_revprops
=revprops
,
705 revprops
[0]['svn:log'] = ('Log message for revision 8\n'
706 ' but with multiple lines\n'
708 svntest
.actions
.run_and_verify_log_xml(expected_revprops
=revprops
,
711 #----------------------------------------------------------------------
712 def log_wc_with_peg_revision(sbox
):
713 "'svn log wc_target@N'"
714 guarantee_repos_and_wc(sbox
)
715 my_path
= os
.path
.join(sbox
.wc_dir
, "A", "B", "E", "beta") + "@8"
716 exit_code
, output
, err
= svntest
.actions
.run_and_verify_svn(None, None, [],
718 check_log_chain(parse_log_output(output
), [1])
720 #----------------------------------------------------------------------
721 def url_missing_in_head(sbox
):
722 "'svn log target@N' when target removed from HEAD"
724 guarantee_repos_and_wc(sbox
)
726 my_url
= sbox
.repo_url
+ "/A/B/E/alpha" + "@8"
728 exit_code
, output
, err
= svntest
.actions
.run_and_verify_svn(None, None, [],
730 check_log_chain(parse_log_output(output
), [3, 1])
732 #----------------------------------------------------------------------
733 def log_through_copyfrom_history(sbox
):
734 "'svn log TGT' with copyfrom history"
737 msg_file
=os
.path
.join(sbox
.repo_dir
, 'log-msg')
738 msg_file
=os
.path
.abspath(msg_file
)
740 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
741 mu2_path
= os
.path
.join(wc_dir
, 'A', 'mu2')
742 mu_URL
= sbox
.repo_url
+ '/A/mu'
743 mu2_URL
= sbox
.repo_url
+ '/A/mu2'
745 msg2
=""" Log message for revision 2
746 but with multiple lines
749 msg4
=""" Log message for revision 4
750 but with multiple lines
753 msg6
=""" Log message for revision 6
754 but with multiple lines
757 svntest
.main
.file_write(msg_file
, msg2
)
758 svntest
.main
.file_append(mu_path
, "2")
759 svntest
.actions
.run_and_verify_svn(None, None, [],
762 svntest
.main
.file_append(mu2_path
, "this is mu2")
763 svntest
.actions
.run_and_verify_svn(None, None, [], 'add', mu2_path
)
764 svntest
.actions
.run_and_verify_svn(None, None, [],
766 '-m', "Log message for revision 3")
767 svntest
.actions
.run_and_verify_svn(None, None, [], 'rm', mu2_path
)
768 svntest
.main
.file_write(msg_file
, msg4
)
769 svntest
.actions
.run_and_verify_svn(None, None, [],
772 svntest
.main
.file_append(mu_path
, "5")
773 svntest
.actions
.run_and_verify_svn(None, None, [],
775 '-m', "Log message for revision 5")
777 svntest
.main
.file_write(msg_file
, msg6
)
778 svntest
.actions
.run_and_verify_svn(None, None, [],
779 'cp', '-r', '5', mu_URL
, mu2_URL
,
781 svntest
.actions
.run_and_verify_svn(None, None, [],
784 # The full log for mu2 is relatively unsurprising
785 exit_code
, output
, err
= svntest
.actions
.run_and_verify_svn(None, None, [],
787 log_chain
= parse_log_output(output
)
788 check_log_chain(log_chain
, [6, 5, 2, 1])
790 exit_code
, output
, err
= svntest
.actions
.run_and_verify_svn(None, None, [],
792 log_chain
= parse_log_output(output
)
793 check_log_chain(log_chain
, [6, 5, 2, 1])
795 # First "oddity", the full log for mu2 doesn't include r3, but the -r3
797 peg_mu2_path
= mu2_path
+ "@3"
798 exit_code
, output
, err
= svntest
.actions
.run_and_verify_svn(None, None, [],
801 log_chain
= parse_log_output(output
)
802 check_log_chain(log_chain
, [3])
804 peg_mu2_URL
= mu2_URL
+ "@3"
805 exit_code
, output
, err
= svntest
.actions
.run_and_verify_svn(None, None, [],
808 log_chain
= parse_log_output(output
)
809 check_log_chain(log_chain
, [3])
810 exit_code
, output
, err
= svntest
.actions
.run_and_verify_svn(None, None, [],
813 log_chain
= parse_log_output(output
)
814 check_log_chain(log_chain
, [2])
816 exit_code
, output
, err
= svntest
.actions
.run_and_verify_svn(None, None, [],
819 log_chain
= parse_log_output(output
)
820 check_log_chain(log_chain
, [2])
822 #----------------------------------------------------------------------
823 def escape_control_chars(sbox
):
824 "mod_dav_svn must escape invalid XML control chars"
826 dump_str
= """SVN-fs-dump-format-version: 2
828 UUID: ffcae364-69ee-0310-a980-ca5f10462af2
831 Prop-content-length: 56
837 2005-01-24T10:09:21.759592Z
841 Prop-content-length: 128
847 This msg contains a Ctrl-T (\x14) and a Ctrl-I (\t).
848 The former might be escaped, but the latter never.
857 2005-01-24T10:09:22.012524Z
861 # load dumpfile with control character into repos to get
862 # a log with control char content
863 svntest
.actions
.load_repo(sbox
, dump_str
=dump_str
)
868 exit_code
, output
, errput
= svntest
.actions
.run_and_verify_svn(
869 None, None, [], 'log', URL
)
871 # Verify the output contains either the expected fuzzy escape
872 # sequence, or the literal control char.
873 match_unescaped_ctrl_re
= "This msg contains a Ctrl-T \(.\) " \
874 "and a Ctrl-I \(\t\)\."
875 match_escaped_ctrl_re
= "^This msg contains a Ctrl-T \(\?\\\\020\) " \
876 "and a Ctrl-I \(\t\)\."
879 if re
.match(match_unescaped_ctrl_re
, line
) \
880 or re
.match(match_escaped_ctrl_re
, line
):
884 raise svntest
.Failure("log message not transmitted properly:" +
885 str(output
) + "\n" + "error: " + str(errput
))
887 #----------------------------------------------------------------------
888 def log_xml_empty_date(sbox
):
889 "svn log --xml must not print empty date elements"
892 # Create the revprop-change hook for this test
893 svntest
.actions
.enable_revprop_changes(sbox
.repo_dir
)
895 date_re
= re
.compile('<date');
897 # Ensure that we get a date before we delete the property.
898 exit_code
, output
, errput
= svntest
.actions
.run_and_verify_svn(
899 None, None, [], 'log', '--xml', '-r1', sbox
.wc_dir
)
903 if date_re
.search(line
):
906 raise svntest
.Failure("log contains no date element")
908 # Set the svn:date revprop to the empty string on revision 1.
909 svntest
.actions
.run_and_verify_svn(None, None, [],
910 'pdel', '--revprop', '-r1', 'svn:date',
913 exit_code
, output
, errput
= svntest
.actions
.run_and_verify_svn(
914 None, None, [], 'log', '--xml', '-r1', sbox
.wc_dir
)
917 if date_re
.search(line
):
918 raise svntest
.Failure("log contains date element when svn:date is empty")
920 #----------------------------------------------------------------------
923 guarantee_repos_and_wc(sbox
)
925 exit_code
, out
, err
= svntest
.actions
.run_and_verify_svn(None, None, [],
929 log_chain
= parse_log_output(out
)
930 check_log_chain(log_chain
, [9, 8])
932 exit_code
, out
, err
= svntest
.actions
.run_and_verify_svn(None, None, [],
937 log_chain
= parse_log_output(out
)
938 check_log_chain(log_chain
, [9, 6])
940 exit_code
, out
, err
= svntest
.actions
.run_and_verify_svn(
942 'log', '--limit', '2', '--revision', '2:HEAD', sbox
.repo_url
, 'A/B')
944 log_chain
= parse_log_output(out
)
945 check_log_chain(log_chain
, [3, 6])
947 # Use -l instead of --limit to test both option forms.
948 exit_code
, out
, err
= svntest
.actions
.run_and_verify_svn(
950 'log', '-l', '2', '--revision', '1', sbox
.repo_url
, 'A/B')
952 log_chain
= parse_log_output(out
)
953 check_log_chain(log_chain
, [1])
955 must_be_positive
= ".*Argument to --limit must be positive.*"
957 # error expected when limit <= 0
958 svntest
.actions
.run_and_verify_svn(None, None, must_be_positive
,
959 'log', '--limit', '0', '--revision', '1',
960 sbox
.repo_url
, 'A/B')
962 svntest
.actions
.run_and_verify_svn(None, None, must_be_positive
,
963 'log', '--limit', '-1', '--revision', '1',
964 sbox
.repo_url
, 'A/B')
966 def log_base_peg(sbox
):
967 "run log on an @BASE target"
968 guarantee_repos_and_wc(sbox
)
970 target
= os
.path
.join(sbox
.wc_dir
, 'A', 'B', 'E', 'beta') + '@BASE'
972 exit_code
, out
, err
= svntest
.actions
.run_and_verify_svn(None, None, [],
975 log_chain
= parse_log_output(out
)
976 check_log_chain(log_chain
, [9, 1])
978 svntest
.actions
.run_and_verify_svn(None, None, [], 'update', '-r', '1',
981 exit_code
, out
, err
= svntest
.actions
.run_and_verify_svn(None, None, [],
984 log_chain
= parse_log_output(out
)
985 check_log_chain(log_chain
, [1])
988 def log_verbose(sbox
):
989 "run log with verbose output"
990 guarantee_repos_and_wc(sbox
)
992 exit_code
, output
, err
= svntest
.actions
.run_and_verify_svn(None, None, [],
996 log_chain
= parse_log_output(output
)
997 path_counts
= [2, 2, 1, 2, 2, 2, 4, 1, 20]
998 check_log_chain(log_chain
, range(max_revision
, 1 - 1, -1), path_counts
)
1001 def log_parser(sbox
):
1002 "meta-test for the log parser"
1004 logs
= ['''------------------------------------------------------------------------
1005 r24 | chuck | 2007-04-30 10:18:01 -0500 (Mon, 16 Apr 2007) | 1 line
1007 M /trunk/death-ray.c
1008 M /trunk/frobnicator/frapnalyzer.c
1010 Merge r12 and r14 from branch to trunk.
1011 ------------------------------------------------------------------------
1012 r14 | bob | 2007-04-16 18:50:29 -0500 (Mon, 16 Apr 2007) | 1 line
1014 M /trunk/death-ray.c
1017 Remove inadvertent changes to Death-Ray-o-Matic introduced in r12.
1018 ------------------------------------------------------------------------
1019 r12 | alice | 2007-04-16 19:02:48 -0500 (Mon, 16 Apr 2007) | 1 line
1021 M /trunk/frobnicator/frapnalyzer.c
1022 M /trunk/death-ray.c
1025 Fix frapnalyzer bug in frobnicator.
1026 ------------------------------------------------------------------------''',
1027 '''------------------------------------------------------------------------
1028 r24 | chuck | 2007-04-30 10:18:01 -0500 (Mon, 16 Apr 2007) | 1 line
1030 Merge r12 and r14 from branch to trunk.
1031 ------------------------------------------------------------------------
1032 r14 | bob | 2007-04-16 18:50:29 -0500 (Mon, 16 Apr 2007) | 1 line
1035 Remove inadvertent changes to Death-Ray-o-Matic introduced in r12.
1036 ------------------------------------------------------------------------
1037 r12 | alice | 2007-04-16 19:02:48 -0500 (Mon, 16 Apr 2007) | 1 line
1040 Fix frapnalyzer bug in frobnicator.
1041 ------------------------------------------------------------------------
1042 r10 | alice | 2007-04-16 19:02:28 -0500 (Mon, 16 Apr 2007) | 1 line
1043 Merged via: r12, r24
1045 Fix frapnalyzer documentation.
1046 ------------------------------------------------------------------------
1047 r9 | bob | 2007-04-16 19:01:48 -0500 (Mon, 16 Apr 2007) | 1 line
1048 Merged via: r12, r24
1050 Whitespace fixes. No functional change.
1051 ------------------------------------------------------------------------''',
1052 '''------------------------------------------------------------------------
1053 r5 | kfogel | Tue 6 Nov 2001 17:18:19 | 1 line
1055 Log message for revision 5.
1056 ------------------------------------------------------------------------
1057 r4 | kfogel | Tue 6 Nov 2001 17:18:18 | 3 lines
1059 Log message for revision 4
1060 but with multiple lines
1062 ------------------------------------------------------------------------
1063 r3 | kfogel | Tue 6 Nov 2001 17:18:17 | 1 line
1065 Log message for revision 3.
1066 ------------------------------------------------------------------------''',
1070 log_chain
= parse_log_output([line
+"\n" for line
in log
.split("\n")])
1073 def check_merge_results(log_chain
, expected_merges
):
1074 '''Check LOG_CHAIN to see if the log information contains 'Merged via'
1075 information indicated by EXPECTED_MERGES. EXPECTED_MERGES is a dictionary
1076 whose key is the merged revision, and whose value is the merging revision.'''
1078 # Check to see if the number and values of the revisions is correct
1079 for log
in log_chain
:
1080 if log
['revision'] not in expected_merges
:
1081 raise SVNUnexpectedLogs("Found unexpected revision %d" %
1082 log
['revision'], log_chain
)
1084 # Check to see that each rev in expected_merges contains the correct data
1085 for rev
in expected_merges
:
1087 log
= [x
for x
in log_chain
if x
['revision'] == rev
][0]
1088 if 'merges' in log
.keys():
1089 actual
= log
['merges']
1092 expected
= expected_merges
[rev
]
1094 if actual
!= expected
:
1095 raise SVNUnexpectedLogs(("Merging revisions in rev %d not correct; " +
1096 "expecting %s, found %s") %
1097 (rev
, str(expected
), str(actual
)), log_chain
)
1099 raise SVNUnexpectedLogs("Merged revision '%d' missing" % rev
, log_chain
)
1102 def merge_sensitive_log_single_revision(sbox
):
1103 "test sensitive log on a single revision"
1105 merge_history_repos(sbox
)
1107 # Paths we care about
1108 wc_dir
= sbox
.wc_dir
1109 TRUNK_path
= os
.path
.join(wc_dir
, "trunk")
1110 BRANCH_B_path
= os
.path
.join(wc_dir
, "branches", "b")
1112 # Run the merge sensitive log, and compare results
1113 saved_cwd
= os
.getcwd()
1115 os
.chdir(TRUNK_path
)
1116 exit_code
, output
, err
= svntest
.actions
.run_and_verify_svn(None, None, [],
1121 log_chain
= parse_log_output(output
)
1123 14: [], 13 : [14], 12 : [14], 11 : [14, 12],
1125 check_merge_results(log_chain
, expected_merges
)
1129 exit_code
, output
, err
= svntest
.actions
.run_and_verify_svn(None, None, [],
1133 log_chain
= parse_log_output(output
)
1137 check_merge_results(log_chain
, expected_merges
)
1140 def merge_sensitive_log_branching_revision(sbox
):
1141 "test 'svn log -g' on a branching revision"
1143 merge_history_repos(sbox
)
1145 # Paths we care about
1146 wc_dir
= sbox
.wc_dir
1147 BRANCH_B_path
= os
.path
.join(wc_dir
, "branches", "b")
1149 # Run log on a copying revision
1150 exit_code
, output
, err
= svntest
.actions
.run_and_verify_svn(None, None, [],
1155 # Parse and check output. There should be no extra revisions.
1156 log_chain
= parse_log_output(output
)
1160 check_merge_results(log_chain
, expected_merges
)
1163 def merge_sensitive_log_non_branching_revision(sbox
):
1164 "test 'svn log -g' on a non-branching revision"
1166 merge_history_repos(sbox
)
1168 TRUNK_path
= os
.path
.join(sbox
.wc_dir
, "trunk")
1170 # Run log on a non-copying revision that adds mergeinfo
1171 exit_code
, output
, err
= svntest
.actions
.run_and_verify_svn(None, None, [],
1176 # Parse and check output. There should be one extra revision.
1177 log_chain
= parse_log_output(output
)
1179 6: [], 4 : [6], 3: [6],
1181 check_merge_results(log_chain
, expected_merges
)
1184 def merge_sensitive_log_added_path(sbox
):
1185 "test 'svn log -g' a path added before merge"
1187 merge_history_repos(sbox
)
1189 XI_path
= os
.path
.join(sbox
.wc_dir
, "trunk", "A", "xi")
1191 # Run log on a non-copying revision that adds mergeinfo
1192 exit_code
, output
, err
= svntest
.actions
.run_and_verify_svn(None, None, [],
1196 # Parse and check output. There should be one extra revision.
1197 log_chain
= parse_log_output(output
)
1199 14: [], 12 : [], 11 : [],
1201 check_merge_results(log_chain
, expected_merges
)
1203 revprops
= [{'svn:author': 'jconstant', 'svn:date': '',
1204 'svn:log': 'Merged branches/b to trunk.'},
1205 {'svn:author': 'jconstant', 'svn:date': '',
1206 'svn:log': 'Merged branches/a to branches/b.'},
1207 {'svn:author': 'jrandom', 'svn:date': '',
1208 'svn:log': "Added 'xi' to branches/a,"
1209 ' made a few other changes.'}]
1210 svntest
.actions
.run_and_verify_log_xml(expected_revprops
=revprops
,
1211 args
=['-g', XI_path
])
1214 def log_single_change(sbox
):
1215 "test log -c for a single change"
1217 guarantee_repos_and_wc(sbox
)
1218 repo_url
= sbox
.repo_url
1220 exit_code
, output
, err
= svntest
.actions
.run_and_verify_svn(None, None, [],
1223 log_chain
= parse_log_output(output
)
1224 check_log_chain(log_chain
, [4])
1226 def log_changes_range(sbox
):
1227 "test log -c on range of changes"
1229 guarantee_repos_and_wc(sbox
)
1230 repo_url
= sbox
.repo_url
1232 exit_code
, output
, err
= svntest
.actions
.run_and_verify_svn(None, None, [],
1236 log_chain
= parse_log_output(output
)
1237 check_log_chain(log_chain
, [2, 3, 4, 5])
1239 def log_changes_list(sbox
):
1240 "test log -c on comma-separated list of changes"
1242 guarantee_repos_and_wc(sbox
)
1243 repo_url
= sbox
.repo_url
1245 exit_code
, output
, err
= svntest
.actions
.run_and_verify_svn(None, None, [],
1250 log_chain
= parse_log_output(output
)
1251 check_log_chain(log_chain
, [2, 5, 7])
1253 #----------------------------------------------------------------------
1254 def only_one_wc_path(sbox
):
1255 "svn log of two wc paths is disallowed"
1257 sbox
.build(read_only
= True)
1258 os
.chdir(sbox
.wc_dir
)
1260 svntest
.actions
.run_and_verify_log_xml(
1261 expected_stderr
=('.*When specifying working copy paths,'
1262 ' only one target may be given'),
1263 args
=['A/mu', 'iota'])
1265 #----------------------------------------------------------------------
1266 def retrieve_revprops(sbox
):
1267 "test revprop retrieval"
1270 svntest
.actions
.enable_revprop_changes(sbox
.repo_dir
)
1274 msg1
= 'Log message for revision 1.'
1275 msg2
= 'Log message for revision 2.'
1276 custom_name
= 'retrieve_revprops'
1277 custom_value
= 'foo bar'
1280 wc_dir
= sbox
.wc_dir
1283 svntest
.main
.file_append(os
.path
.join('A', 'D', 'H', 'omega'), "new otext")
1285 omega_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H', 'omega')
1286 expected_output
= svntest
.wc
.State(wc_dir
, {
1287 'A/D/H/omega' : Item(verb
='Sending'),
1289 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1290 expected_status
.tweak('A/D/H/omega', wc_rev
=2, status
=' ')
1291 svntest
.actions
.run_and_verify_commit(wc_dir
,
1300 # Set custom property on r1 and r2.
1301 svntest
.actions
.run_and_verify_svn(
1302 None, None, [], # message, expected_stdout, expected_stderr
1303 'ps', '--revprop', '-r1', custom_name
, custom_value
, sbox
.repo_url
)
1304 svntest
.actions
.run_and_verify_svn(
1305 None, None, [], # message, expected_stdout, expected_stderr
1306 'ps', '--revprop', '-r2', custom_name
, custom_value
, sbox
.repo_url
)
1308 # Can't set revprops with log.
1309 svntest
.actions
.run_and_verify_log_xml(
1310 expected_stderr
=(".*cannot assign with 'with-revprop' option"
1311 " \(drop the '='\)"),
1312 args
=['--with-revprop=foo=bar'])
1314 # basic test without revprop options
1315 svntest
.actions
.run_and_verify_log_xml(
1316 expected_revprops
=[{'svn:author': author
, 'svn:date': '', 'svn:log': msg1
}],
1319 # basic test without revprop options, with multiple revisions
1320 svntest
.actions
.run_and_verify_log_xml(
1321 expected_revprops
=[{'svn:author': author
, 'svn:date': '', 'svn:log': msg1
},
1322 {'svn:author': author
, 'svn:date': '', 'svn:log': msg2
}])
1324 # -q with no revprop options must suppress svn:log only.
1325 svntest
.actions
.run_and_verify_log_xml(
1326 expected_revprops
=[{'svn:author': author
, 'svn:date': ''}],
1329 # Request svn:date, svn:log, and a non-existent property.
1330 svntest
.actions
.run_and_verify_log_xml(
1331 expected_revprops
=[{'svn:date': '', 'svn:log': msg1
}],
1332 args
=['-r1', '--with-revprop=svn:date', '--with-revprop', 'svn:log',
1333 '--with-revprop', 'nosuchprop'])
1336 svntest
.actions
.run_and_verify_log_xml(
1337 expected_revprops
=[{'svn:author': author
, 'svn:date': '',
1338 'svn:log': msg1
, custom_name
: custom_value
}],
1339 args
=['-r1', '--with-all-revprops'])
1341 # Get all revprops, with multiple revisions.
1342 svntest
.actions
.run_and_verify_log_xml(
1343 expected_revprops
=[{'svn:author': author
, 'svn:date': '',
1344 'svn:log': msg1
, custom_name
: custom_value
},
1345 {'svn:author': author
, 'svn:date': '',
1346 'svn:log': msg2
, custom_name
: custom_value
}],
1347 args
=['--with-all-revprops'])
1349 # Get only the custom property.
1350 svntest
.actions
.run_and_verify_log_xml(
1351 expected_revprops
=[{custom_name
: custom_value
}],
1352 args
=['-r1', '--with-revprop', custom_name
])
1355 def log_xml_with_bad_data(sbox
):
1356 "log --xml escapes non-utf8 data (issue #2866)"
1357 svntest
.actions
.load_repo(sbox
, os
.path
.join(os
.path
.dirname(sys
.argv
[0]),
1359 'xml-invalid-chars.dump'))
1362 'svn:log' : 'After the colon are a space, 3 bad chars, '
1363 + '2 good chars, and a period: '
1364 + '?\\021?\\022?\\017\t\n.' }
1365 svntest
.actions
.run_and_verify_log_xml(
1366 expected_revprops
=(r0_props
,), args
=[sbox
.repo_url
])
1368 def merge_sensitive_log_target_with_bogus_mergeinfo(sbox
):
1369 "'svn log -g target_with_bogus_mergeinfo'"
1370 #Refer issue 3172 for details.
1372 #svn ps 'svn:mergeinfo' '/A/B:0' A/D
1373 #svn ci -m 'setting bogus mergeinfo'
1376 wc_path
= sbox
.wc_dir
1377 D_path
= os
.path
.join(wc_path
, 'A', 'D')
1378 svntest
.main
.run_svn(None, 'ps', SVN_PROP_MERGEINFO
, '/A/B:0', D_path
)
1380 svntest
.main
.run_svn(None, 'ci', '-m', 'setting bogus mergeinfo', D_path
)
1381 exit_code
, output
, err
= svntest
.actions
.run_and_verify_svn(None, None,
1385 raise svntest
.Failure("svn log -g target_with_bogus_mergeinfo fails")
1387 ########################################################################
1391 # list all tests here, starting with None:
1394 log_with_empty_repos
,
1395 log_where_nothing_changed
,
1396 log_to_revision_zero
,
1399 log_wc_with_peg_revision
,
1400 url_missing_in_head
,
1401 log_through_copyfrom_history
,
1402 escape_control_chars
,
1408 SkipUnless(merge_sensitive_log_single_revision
,
1409 server_has_mergeinfo
),
1410 SkipUnless(merge_sensitive_log_branching_revision
,
1411 server_has_mergeinfo
),
1412 SkipUnless(merge_sensitive_log_non_branching_revision
,
1413 server_has_mergeinfo
),
1414 SkipUnless(merge_sensitive_log_added_path
,
1415 server_has_mergeinfo
),
1417 XFail(log_changes_range
),
1418 XFail(log_changes_list
),
1421 log_xml_with_bad_data
,
1422 SkipUnless(merge_sensitive_log_target_with_bogus_mergeinfo
,
1423 server_has_mergeinfo
),
1426 if __name__
== '__main__':
1427 svntest
.main
.run_tests(test_list
)