Add a little more to the svn_rangelist_intersect test to test the
[svn.git] / subversion / tests / cmdline / svnlook_tests.py
blobf9fd065c987075874187c0ebd535e0083aa68c75
1 #!/usr/bin/env python
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 ######################################################################
19 # General modules
20 import re, os
22 # Our testing module
23 import svntest
26 # (abbreviation)
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,
40 0, 0, *varargs)
41 return output
44 def expect(tag, expected, got):
45 if expected != got:
46 print "When testing: %s" % tag
47 print "Expected: %s" % expected
48 print " Got: %s" % got
49 raise svntest.Failure
52 # Tests
54 def test_misc(sbox):
55 "test miscellaneous svnlook features"
57 sbox.build()
58 wc_dir = sbox.wc_dir
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,
79 expected_output,
80 expected_status,
81 None,
82 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",
88 "\n",
89 "UUID: ", uuid, "\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)
107 path = ''
108 n = 0
109 for entry in treelist:
110 len1 = len(entry)
111 len2 = len(entry.lstrip())
112 path = path[0:2*(len1-len2)-1] + entry.strip()
113 test = treelistfull[n].rstrip()
114 if n != 0:
115 test = "/" + test
116 if not path == test:
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
121 n = n + 1
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
126 n = 0
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
135 n = n + 1
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]
147 proplist.sort()
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,
157 prop_name)
159 expected_err = "Property '%s' not found on revision " % prop_name
160 for line in errput:
161 if line.find(expected_err) != -1:
162 break
163 else:
164 raise svntest.main.SVNUnmatchedError
166 output, errput = svntest.main.run_svnlook('propget', '-r1', repo_dir,
167 prop_name, '/')
169 expected_err = "Property '%s' not found on path '/' in revision " % prop_name
170 for line in errput:
171 if line.find(expected_err) != -1:
172 break
173 else:
174 raise svntest.main.SVNUnmatchedError
176 #----------------------------------------------------------------------
177 # Issue 1089
178 def delete_file_in_moved_dir(sbox):
179 "delete file in moved dir"
181 sbox.build()
182 wc_dir = sbox.wc_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)
192 # commit
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,
205 expected_output,
206 expected_status,
207 None,
208 wc_dir)
210 output, errput = svntest.main.run_svnlook("dirs-changed", repo_dir)
211 if errput:
212 raise svntest.Failure
214 # Okay. No failure, but did we get the right output?
215 if len(output) != 2:
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 #----------------------------------------------------------------------
223 # Issue 1241
224 def test_print_property_diffs(sbox):
225 "test the printing of property diffs"
227 sbox.build()
228 wc_dir = sbox.wc_dir
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)
236 # commit the change
237 svntest.actions.run_and_verify_svn(None, None, [],
238 'ci', '-m', 'log msg', iota_path)
240 # Grab the diff
241 expected_output, err = svntest.actions.run_and_verify_svn(None, None, [],
242 'diff',
243 '-r', 'PREV',
244 iota_path)
246 output, errput = svntest.main.run_svnlook("diff", repo_dir)
247 if errput:
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
270 Revision-number: 0
271 Prop-content-length: 56
272 Content-length: 56
275 svn:date
276 V 27
277 2005-05-03T19:09:41.129900Z
278 PROPS-END
280 Revision-number: 1
281 Prop-content-length: 99
282 Content-length: 99
285 svn:log
287 \n\r\n
288 K 10
289 svn:author
293 svn:date
294 V 27
295 2005-05-03T19:10:19.975578Z
296 PROPS-END
298 Node-path: file
299 Node-kind: file
300 Node-action: add
301 Prop-content-length: 10
302 Text-content-length: 5
303 Text-content-md5: e1cbb0c3879af8347246f12c559a86b5
304 Content-length: 15
306 PROPS-END
307 text
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")
316 if errput:
317 raise svntest.Failure
319 def changed_copy_info(sbox):
320 "test --copy-info flag on the changed command"
321 sbox.build()
322 wc_dir = sbox.wc_dir
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,
330 alpha2_path)
332 # commit
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,
341 expected_output,
342 expected_status,
343 None,
344 wc_dir)
346 output, errput = svntest.main.run_svnlook("changed", repo_dir)
347 if errput:
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")
353 if errput:
354 raise svntest.Failure
356 expect("changed with --copy-info",
357 ["A + A/alpha2\n",
358 " (from A/B/E/alpha:r1)\n"],
359 output)
361 #----------------------------------------------------------------------
362 # Issue 2663
363 def tree_non_recursive(sbox):
364 "test 'svnlook tree --non-recursive'"
366 sbox.build()
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):
400 "history --limit"
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'"
418 sbox.build()
419 repo_dir = sbox.repo_dir
420 wc_dir = sbox.wc_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,
437 expected_output,
438 expected_status,
439 None,
440 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',
445 repo_dir, '/A/mu')
446 if output != []:
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',
452 repo_dir, '/A/mu')
453 if output != []:
454 raise svntest.Failure
456 #----------------------------------------------------------------------
457 def diff_ignore_eolstyle(sbox):
458 "test 'svnlook diff -x --ignore-eol-style'"
460 sbox.build()
461 repo_dir = sbox.repo_dir
462 wc_dir = sbox.wc_dir
464 if os.name == 'nt':
465 crlf = '\n'
466 else:
467 crlf = '\r\n'
469 mu_path = os.path.join(wc_dir, 'A', 'mu')
471 rev = 1
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,
490 expected_output,
491 expected_status,
492 None,
493 wc_dir)
495 # Grab the diff
496 expected_output, err = \
497 svntest.actions.run_and_verify_svn(None, None, [], 'diff',
498 '-r', 'PREV', '-x',
499 '--ignore-eol-style', mu_path)
501 output = run_svnlook('diff', '-r', str(rev + 1), '-x',
502 '--ignore-eol-style', repo_dir, '/A/mu')
503 rev += 1
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 ########################################################################
513 # Run the tests
516 # list all tests here, starting with None:
517 test_list = [ None,
518 test_misc,
519 delete_file_in_moved_dir,
520 test_print_property_diffs,
521 info_bad_newlines,
522 changed_copy_info,
523 tree_non_recursive,
524 limit_history,
525 diff_ignore_whitespace,
526 diff_ignore_eolstyle,
529 if __name__ == '__main__':
530 svntest.main.run_tests(test_list)
531 # NOTREACHED
534 ### End of file.