3 # svnlook_tests.py: testing the 'svnlook' tool.
5 # Subversion is a tool for revision control.
6 # See http://subversion.tigris.org for more information.
8 # ====================================================================
9 # Copyright (c) 2000-2004, 2007 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 ######################################################################
27 Skip
= svntest
.testcase
.Skip
28 XFail
= svntest
.testcase
.XFail
29 Item
= svntest
.wc
.StateItem
32 #----------------------------------------------------------------------
34 # Convenience functions to make writing more tests easier
36 def run_svnlook(*varargs
):
37 """Run svnlook with VARARGS, returns stdout as list of lines.
38 Raises Failure if any stderr messages."""
39 output
, dummy_errput
= svntest
.main
.run_command(svntest
.main
.svnlook_binary
,
44 def expect(tag
, expected
, got
):
46 print "When testing: %s" % tag
47 print "Expected: %s" % expected
48 print " Got: %s" % got
55 "test miscellaneous svnlook features"
59 repo_dir
= sbox
.repo_dir
61 # Make a couple of local mods to files
62 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
63 rho_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G', 'rho')
64 svntest
.main
.file_append(mu_path
, 'appended mu text')
65 svntest
.main
.file_append(rho_path
, 'new appended text for rho')
67 # Created expected output tree for 'svn ci'
68 expected_output
= svntest
.wc
.State(wc_dir
, {
69 'A/mu' : Item(verb
='Sending'),
70 'A/D/G/rho' : Item(verb
='Sending'),
73 # Create expected status tree; all local revisions should be at 1,
74 # but mu and rho should be at revision 2.
75 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
76 expected_status
.tweak('A/mu', 'A/D/G/rho', wc_rev
=2)
78 svntest
.actions
.run_and_verify_commit(wc_dir
,
84 # give the repo a new UUID
85 uuid
= "01234567-89ab-cdef-89ab-cdef01234567"
86 svntest
.main
.run_command_stdin(svntest
.main
.svnadmin_binary
, None, 1,
87 ["SVN-fs-dump-format-version: 2\n",
91 'load', '--force-uuid', repo_dir
)
93 expect('youngest', [ '2\n' ], run_svnlook('youngest', repo_dir
))
95 expect('uuid', [ uuid
+ '\n' ], run_svnlook('uuid', repo_dir
))
97 # it would be nice to test the author too, but the current test framework
98 # does not pull a username when testing over ra_neon or ra_svn,
99 # so the commits have an empty author.
101 expect('log', [ 'log msg\n' ], run_svnlook('log', repo_dir
))
103 # check if the 'svnlook tree' output can be expanded to
104 # the 'svnlook tree --full-paths' output if demanding the whole repository
105 treelist
= run_svnlook('tree', repo_dir
)
106 treelistfull
= run_svnlook('tree', '--full-paths', repo_dir
)
109 for entry
in treelist
:
111 len2
= len(entry
.lstrip())
112 path
= path
[0:2*(len1
-len2
)-1] + entry
.strip()
113 test
= treelistfull
[n
].rstrip()
117 print "Unexpected result from tree with --full-paths:"
118 print " entry : %s" % entry
.rstrip()
119 print " with --full-paths: %s" % treelistfull
[n
].rstrip()
120 raise svntest
.Failure
123 # check if the 'svnlook tree' output is the ending of
124 # the 'svnlook tree --full-paths' output if demanding
125 # any part of the repository
127 treelist
= run_svnlook('tree', repo_dir
, '/A/B')
128 treelistfull
= run_svnlook('tree', '--full-paths', repo_dir
, '/A/B')
129 for entry
in treelist
:
130 if not treelistfull
[n
].endswith(entry
.lstrip()):
131 print "Unexpected result from tree with --full-paths:"
132 print " entry : %s" % entry
.rstrip()
133 print " with --full-paths: %s" % treelistfull
[n
].rstrip()
134 raise svntest
.Failure
137 treelist
= run_svnlook('tree', repo_dir
, '/')
138 if treelist
[0] != '/\n':
139 raise svntest
.Failure
141 expect('propget svn:log', [ 'log msg' ],
142 run_svnlook('propget', '--revprop', repo_dir
, 'svn:log'))
145 proplist
= run_svnlook('proplist', '--revprop', repo_dir
)
146 proplist
= [prop
.strip() for prop
in proplist
]
149 # We cannot rely on svn:author's presence. ra_svn doesn't set it.
150 if not (proplist
== [ 'svn:author', 'svn:date', 'svn:log' ]
151 or proplist
== [ 'svn:date', 'svn:log' ]):
152 print "Unexpected result from proplist: %s" % proplist
153 raise svntest
.Failure
155 prop_name
= 'foo:bar-baz-quux'
156 output
, errput
= svntest
.main
.run_svnlook('propget', '--revprop', repo_dir
,
159 expected_err
= "Property '%s' not found on revision " % prop_name
161 if line
.find(expected_err
) != -1:
164 raise svntest
.main
.SVNUnmatchedError
166 output
, errput
= svntest
.main
.run_svnlook('propget', '-r1', repo_dir
,
169 expected_err
= "Property '%s' not found on path '/' in revision " % prop_name
171 if line
.find(expected_err
) != -1:
174 raise svntest
.main
.SVNUnmatchedError
176 #----------------------------------------------------------------------
178 def delete_file_in_moved_dir(sbox
):
179 "delete file in moved dir"
183 repo_dir
= sbox
.repo_dir
185 # move E to E2 and delete E2/alpha
186 E_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E')
187 E2_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E2')
188 svntest
.actions
.run_and_verify_svn(None, None, [], 'mv', E_path
, E2_path
)
189 alpha_path
= os
.path
.join(E2_path
, 'alpha')
190 svntest
.actions
.run_and_verify_svn(None, None, [], 'rm', alpha_path
)
193 expected_output
= svntest
.wc
.State(wc_dir
, {
194 'A/B/E' : Item(verb
='Deleting'),
195 'A/B/E2' : Item(verb
='Adding'),
196 'A/B/E2/alpha' : Item(verb
='Deleting'),
198 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
199 expected_status
.remove('A/B/E', 'A/B/E/alpha', 'A/B/E/beta')
200 expected_status
.add({
201 'A/B/E2' : Item(status
=' ', wc_rev
=2),
202 'A/B/E2/beta' : Item(status
=' ', wc_rev
=2),
204 svntest
.actions
.run_and_verify_commit(wc_dir
,
210 output
, errput
= svntest
.main
.run_svnlook("dirs-changed", repo_dir
)
212 raise svntest
.Failure
214 # Okay. No failure, but did we get the right output?
216 raise svntest
.Failure
217 if not ((output
[0].strip() == 'A/B/')
218 and (output
[1].strip() == 'A/B/E2/')):
219 raise svntest
.Failure
222 #----------------------------------------------------------------------
224 def test_print_property_diffs(sbox
):
225 "test the printing of property diffs"
229 repo_dir
= sbox
.repo_dir
231 # Add a bogus property to iota
232 iota_path
= os
.path
.join(wc_dir
, 'iota')
233 svntest
.actions
.run_and_verify_svn(None, None, [], 'propset',
234 'bogus_prop', 'bogus_val', iota_path
)
237 svntest
.actions
.run_and_verify_svn(None, None, [],
238 'ci', '-m', 'log msg', iota_path
)
241 expected_output
, err
= svntest
.actions
.run_and_verify_svn(None, None, [],
246 output
, errput
= svntest
.main
.run_svnlook("diff", repo_dir
)
248 raise svntest
.Failure
250 # Okay. No failure, but did we get the right output?
251 if len(output
) != len(expected_output
):
252 raise svntest
.Failure
254 # replace wcdir/iota with iota in expected_output
255 for i
in xrange(len(expected_output
)):
256 expected_output
[i
] = expected_output
[i
].replace(iota_path
, 'iota')
258 svntest
.verify
.compare_and_display_lines('', '', expected_output
, output
)
260 #----------------------------------------------------------------------
261 # Check that svnlook info repairs allows inconsistent line endings in logs.
263 def info_bad_newlines(sbox
):
264 "svnlook info must allow inconsistent newlines"
266 dump_str
= """SVN-fs-dump-format-version: 2
268 UUID: dc40867b-38f6-0310-9f5f-f81aa277e06e
271 Prop-content-length: 56
277 2005-05-03T19:09:41.129900Z
281 Prop-content-length: 99
295 2005-05-03T19:10:19.975578Z
301 Prop-content-length: 10
302 Text-content-length: 5
303 Text-content-md5: e1cbb0c3879af8347246f12c559a86b5
312 # load dumpfile with inconsistent newlines into repos.
313 svntest
.actions
.load_repo(sbox
, dump_str
=dump_str
)
315 output
, errput
= svntest
.main
.run_svnlook("info", sbox
.repo_dir
, "-r1")
317 raise svntest
.Failure
319 def changed_copy_info(sbox
):
320 "test --copy-info flag on the changed command"
323 repo_dir
= sbox
.repo_dir
325 # Copy alpha to /A/alpha2.
326 E_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E')
327 alpha_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E', 'alpha')
328 alpha2_path
= os
.path
.join(wc_dir
, 'A', 'alpha2')
329 svntest
.actions
.run_and_verify_svn(None, None, [], 'cp', alpha_path
,
333 expected_output
= svntest
.wc
.State(wc_dir
, {
334 'A/alpha2' : Item(verb
='Adding'),
336 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
337 expected_status
.add({
338 'A/alpha2' : Item(status
=' ', wc_rev
=2),
340 svntest
.actions
.run_and_verify_commit(wc_dir
,
346 output
, errput
= svntest
.main
.run_svnlook("changed", repo_dir
)
348 raise svntest
.Failure
350 expect("changed without --copy-info", ["A A/alpha2\n"], output
)
352 output
, errput
= svntest
.main
.run_svnlook("changed", repo_dir
, "--copy-info")
354 raise svntest
.Failure
356 expect("changed with --copy-info",
358 " (from A/B/E/alpha:r1)\n"],
361 #----------------------------------------------------------------------
363 def tree_non_recursive(sbox
):
364 "test 'svnlook tree --non-recursive'"
367 repo_dir
= sbox
.repo_dir
369 expected_results_root
= ('/', ' iota', ' A/')
370 expected_results_deep
= ('B/', ' lambda', ' E/', ' F/')
372 # check the output of svnlook --non-recursive on the
373 # root of the repository
374 treelist
= run_svnlook('tree', '--non-recursive', repo_dir
)
375 for entry
in treelist
:
376 if not entry
.rstrip() in expected_results_root
:
377 print "Unexpected result from tree with --non-recursive:"
378 print " entry : %s" % entry
.rstrip()
379 raise svntest
.Failure
380 if len(treelist
) != len(expected_results_root
):
381 print "Expected %i output entries, found %i" \
382 % (len(expected_results_root
), len(treelist
))
383 raise svntest
.Failure
385 # check the output of svnlook --non-recursive on a
386 # subdirectory of the repository
387 treelist
= run_svnlook('tree', '--non-recursive', repo_dir
, '/A/B')
388 for entry
in treelist
:
389 if not entry
.rstrip() in expected_results_deep
:
390 print "Unexpected result from tree with --non-recursive:"
391 print " entry : %s" % entry
.rstrip()
392 raise svntest
.Failure
393 if len(treelist
) != len(expected_results_deep
):
394 print "Expected %i output entries, found %i" \
395 % (len(expected_results_deep
), len(treelist
))
396 raise svntest
.Failure
398 #----------------------------------------------------------------------
399 def limit_history(sbox
):
401 sbox
.build(create_wc
=False)
402 repo_url
= sbox
.repo_url
403 svntest
.actions
.run_and_verify_svn(None, None, [],
404 'mv', '-m', 'log msg',
405 repo_url
+ "/iota", repo_url
+ "/iota2")
406 svntest
.actions
.run_and_verify_svn(None, None, [],
407 'mv', '-m', 'log msg',
408 repo_url
+ "/A/mu", repo_url
+ "/iota")
409 history
= run_svnlook("history", "--limit=1", sbox
.repo_dir
)
410 # Ignore the two lines of header, and verify expected number of items.
411 if len(history
[2:]) != 1:
412 raise svntest
.Failure("Output not limited to expected number of items")
414 #----------------------------------------------------------------------
415 def diff_ignore_whitespace(sbox
):
416 "test 'svnlook diff -x -b' and 'svnlook diff -x -w'"
419 repo_dir
= sbox
.repo_dir
422 # Make whitespace-only changes to mu
423 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
424 svntest
.main
.file_write(mu_path
, "This is the file 'mu'.\n", "wb")
426 # Created expected output tree for 'svn ci'
427 expected_output
= svntest
.wc
.State(wc_dir
, {
428 'A/mu' : Item(verb
='Sending'),
431 # Create expected status tree; all local revisions should be at 1,
432 # but mu should be at revision 2.
433 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
434 expected_status
.tweak('A/mu', wc_rev
=2)
436 svntest
.actions
.run_and_verify_commit(wc_dir
,
442 # Check the output of 'svnlook diff -x --ignore-space-change' on mu.
443 # It should not print anything.
444 output
= run_svnlook('diff', '-r2', '-x', '--ignore-space-change',
447 raise svntest
.Failure
449 # Check the output of 'svnlook diff -x --ignore-all-space' on mu.
450 # It should not print anything.
451 output
= run_svnlook('diff', '-r2', '-x', '--ignore-all-space',
454 raise svntest
.Failure
456 #----------------------------------------------------------------------
457 def diff_ignore_eolstyle(sbox
):
458 "test 'svnlook diff -x --ignore-eol-style'"
461 repo_dir
= sbox
.repo_dir
469 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
472 # do the --ignore-eol-style test for each eol-style
473 for eol
, eolchar
in zip(['CRLF', 'CR', 'native', 'LF'],
474 [crlf
, '\015', '\n', '\012']):
475 # rewrite file mu and set the eol-style property.
476 svntest
.main
.file_write(mu_path
, "This is the file 'mu'." + eolchar
, 'wb')
477 svntest
.main
.run_svn(None, 'propset', 'svn:eol-style', eol
, mu_path
)
479 # Created expected output tree for 'svn ci'
480 expected_output
= svntest
.wc
.State(wc_dir
, {
481 'A/mu' : Item(verb
='Sending'),
484 # Create expected status tree; all local revisions should be at
485 # revision 1, but mu should be at revision rev + 1.
486 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
487 expected_status
.tweak('A/mu', wc_rev
=rev
+ 1)
489 svntest
.actions
.run_and_verify_commit(wc_dir
,
496 expected_output
, err
= \
497 svntest
.actions
.run_and_verify_svn(None, None, [], 'diff',
499 '--ignore-eol-style', mu_path
)
501 output
= run_svnlook('diff', '-r', str(rev
+ 1), '-x',
502 '--ignore-eol-style', repo_dir
, '/A/mu')
505 # replace wcdir/A/mu with A/mu in expected_output
506 for i
in xrange(len(expected_output
)):
507 expected_output
[i
] = expected_output
[i
].replace(mu_path
, 'A/mu')
509 svntest
.verify
.compare_and_display_lines('', '', expected_output
, output
)
512 ########################################################################
516 # list all tests here, starting with None:
519 delete_file_in_moved_dir
,
520 test_print_property_diffs
,
525 diff_ignore_whitespace
,
526 diff_ignore_eolstyle
,
529 if __name__
== '__main__':
530 svntest
.main
.run_tests(test_list
)