3 # prop_tests.py: testing versioned properties
5 # Subversion is a tool for revision control.
6 # See http://subversion.tigris.org for more information.
8 # ====================================================================
9 # Copyright (c) 2000-2004 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 ######################################################################
20 import sys
, re
, os
, stat
25 from svntest
.main
import SVN_PROP_MERGEINFO
28 Skip
= svntest
.testcase
.Skip
29 SkipUnless
= svntest
.testcase
.SkipUnless
30 XFail
= svntest
.testcase
.XFail
31 Item
= svntest
.wc
.StateItem
33 def is_non_posix_and_non_windows_os():
34 """lambda function to skip revprop_change test"""
35 return (not svntest
.main
.is_posix_os()) and sys
.platform
!= 'win32'
37 ######################################################################
40 #----------------------------------------------------------------------
42 def make_local_props(sbox
):
43 "write/read props in wc only (ps, pl, pdel, pe)"
49 # Add properties to one file and one directory
50 svntest
.main
.run_svn(None, 'propset', 'blue', 'azul',
51 os
.path
.join(wc_dir
, 'A', 'mu'))
52 svntest
.main
.run_svn(None, 'propset', 'green', 'verde',
53 os
.path
.join(wc_dir
, 'A', 'mu'))
54 svntest
.main
.run_svn(None, 'propset', 'editme', 'the foo fighters',
55 os
.path
.join(wc_dir
, 'A', 'mu'))
56 svntest
.main
.run_svn(None, 'propset', 'red', 'rojo',
57 os
.path
.join(wc_dir
, 'A', 'D', 'G'))
58 svntest
.main
.run_svn(None, 'propset', 'yellow', 'amarillo',
59 os
.path
.join(wc_dir
, 'A', 'D', 'G'))
61 # Make sure they show up as local mods in status
62 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
63 expected_status
.tweak('A/mu', status
=' M')
64 expected_status
.tweak('A/D/G', status
=' M')
66 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
69 svntest
.main
.run_svn(None, 'propdel', 'yellow',
70 os
.path
.join(wc_dir
, 'A', 'D', 'G'))
72 svntest
.main
.use_editor('foo_to_bar')
74 svntest
.main
.run_svn(None, 'propedit', 'editme',
75 os
.path
.join(wc_dir
, 'A', 'mu'))
77 # What we expect the disk tree to look like:
78 expected_disk
= svntest
.main
.greek_state
.copy()
79 expected_disk
.tweak('A/mu', props
={'blue' : 'azul', 'green' : 'verde',
80 'editme' : 'the bar fighters'})
81 expected_disk
.tweak('A/D/G', props
={'red' : 'rojo'})
83 # Read the real disk tree. Notice we are passing the (normally
84 # disabled) "load props" flag to this routine. This will run 'svn
85 # proplist' on every item in the working copy!
86 actual_disk_tree
= svntest
.tree
.build_tree_from_wc(wc_dir
, 1)
88 # Compare actual vs. expected disk trees.
89 svntest
.tree
.compare_trees("disk", actual_disk_tree
,
90 expected_disk
.old_tree())
92 # Edit without actually changing the property
93 svntest
.main
.use_editor('identity')
94 svntest
.actions
.run_and_verify_svn(None,
95 "No changes to property 'editme' on '.*'",
98 os
.path
.join(wc_dir
, 'A', 'mu'))
102 #----------------------------------------------------------------------
104 def commit_props(sbox
):
111 # Add a property to a file and a directory
112 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
113 H_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H')
114 svntest
.main
.run_svn(None, 'propset', 'blue', 'azul', mu_path
)
115 svntest
.main
.run_svn(None, 'propset', 'red', 'rojo', H_path
)
117 # Create expected output tree.
118 expected_output
= svntest
.wc
.State(wc_dir
, {
119 'A/mu' : Item(verb
='Sending'),
120 'A/D/H' : Item(verb
='Sending'),
123 # Created expected status tree.
124 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
125 expected_status
.tweak('A/mu', 'A/D/H', wc_rev
=2, status
=' ')
127 # Commit the one file.
128 svntest
.actions
.run_and_verify_commit(wc_dir
,
136 #----------------------------------------------------------------------
138 def update_props(sbox
):
139 "receive properties via update"
145 # Make a backup copy of the working copy
146 wc_backup
= sbox
.add_wc_path('backup')
147 svntest
.actions
.duplicate_dir(wc_dir
, wc_backup
)
149 # Add a property to a file and a directory
150 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
151 H_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H')
152 svntest
.main
.run_svn(None, 'propset', 'blue', 'azul', mu_path
)
153 svntest
.main
.run_svn(None, 'propset', 'red', 'rojo', H_path
)
155 # Create expected output tree.
156 expected_output
= svntest
.wc
.State(wc_dir
, {
157 'A/mu' : Item(verb
='Sending'),
158 'A/D/H' : Item(verb
='Sending'),
161 # Created expected status tree.
162 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
163 expected_status
.tweak('A/mu', 'A/D/H', wc_rev
=2, status
=' ')
165 # Commit the one file.
166 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
170 # Overwrite mu_path and H_path to refer to the backup copies from
172 mu_path
= os
.path
.join(wc_backup
, 'A', 'mu')
173 H_path
= os
.path
.join(wc_backup
, 'A', 'D', 'H')
175 # Create expected output tree for an update of the wc_backup.
176 expected_output
= svntest
.wc
.State(wc_backup
, {
177 'A/mu' : Item(status
=' U'),
178 'A/D/H' : Item(status
=' U'),
181 # Create expected disk tree for the update.
182 expected_disk
= svntest
.main
.greek_state
.copy()
183 expected_disk
.tweak('A/mu', props
={'blue' : 'azul'})
184 expected_disk
.tweak('A/D/H', props
={'red' : 'rojo'})
186 # Create expected status tree for the update.
187 expected_status
= svntest
.actions
.get_virginal_state(wc_backup
, 2)
188 expected_status
.tweak('A/mu', 'A/D/H', status
=' ')
190 # Do the update and check the results in three ways... INCLUDING PROPS
191 svntest
.actions
.run_and_verify_update(wc_backup
,
195 None, None, None, None, None, 1)
197 #----------------------------------------------------------------------
199 def downdate_props(sbox
):
200 "receive property changes as part of a downdate"
206 iota_path
= os
.path
.join(wc_dir
, 'iota')
207 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
209 # Add a property to a file
210 svntest
.main
.run_svn(None, 'propset', 'cash-sound', 'cha-ching!', iota_path
)
212 # Create expected output tree.
213 expected_output
= svntest
.wc
.State(wc_dir
, {
214 'iota' : Item(verb
='Sending'),
217 # Created expected status tree.
218 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
219 expected_status
.tweak('iota', wc_rev
=2, status
=' ')
221 # Commit the one file.
222 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
226 # Make some mod (something to commit)
227 svntest
.main
.file_append(mu_path
, "some mod")
229 # Create expected output tree.
230 expected_output
= svntest
.wc
.State(wc_dir
, {
231 'A/mu' : Item(verb
='Sending'),
234 # Created expected status tree.
235 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
236 expected_status
.tweak('iota', wc_rev
=2, status
=' ')
237 expected_status
.tweak('A/mu', wc_rev
=3, status
=' ')
239 # Commit the one file.
240 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
244 # Create expected output tree for an update.
245 expected_output
= svntest
.wc
.State(wc_dir
, {
246 'iota' : Item(status
=' U'),
247 'A/mu' : Item(status
='U '),
250 # Create expected disk tree for the update.
251 expected_disk
= svntest
.main
.greek_state
253 # Create expected status tree for the update.
254 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
256 # Do the update and check the results in three ways... INCLUDING PROPS
257 svntest
.actions
.run_and_verify_update(wc_dir
,
261 None, None, None, None, None, 1,
264 #----------------------------------------------------------------------
266 def remove_props(sbox
):
267 "commit the removal of props"
273 # Add a property to a file
274 iota_path
= os
.path
.join(wc_dir
, 'iota')
275 svntest
.main
.run_svn(None, 'propset', 'cash-sound', 'cha-ching!', iota_path
)
278 svntest
.main
.run_svn(None,
279 'ci', '-m', 'logmsg', iota_path
)
281 # Now, remove the property
282 svntest
.main
.run_svn(None, 'propdel', 'cash-sound', iota_path
)
284 # Create expected output tree.
285 expected_output
= svntest
.wc
.State(wc_dir
, {
286 'iota' : Item(verb
='Sending'),
289 # Created expected status tree.
290 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
291 expected_status
.tweak('iota', wc_rev
=3, status
=' ')
293 # Commit the one file.
294 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
298 #----------------------------------------------------------------------
300 def update_conflict_props(sbox
):
301 "update with conflicting props"
307 # Add a property to a file and a directory
308 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
309 svntest
.main
.run_svn(None, 'propset', 'cash-sound', 'cha-ching!', mu_path
)
310 A_path
= os
.path
.join(wc_dir
, 'A')
311 svntest
.main
.run_svn(None, 'propset', 'foo', 'bar', A_path
)
313 # Commit the file and directory
314 svntest
.main
.run_svn(None,
315 'ci', '-m', 'logmsg', wc_dir
)
318 svntest
.main
.run_svn(None, 'up', '-r', '1', wc_dir
)
320 # Add conflicting properties
321 svntest
.main
.run_svn(None, 'propset', 'cash-sound', 'beep!', mu_path
)
322 svntest
.main
.run_svn(None, 'propset', 'foo', 'baz', A_path
)
324 # Create expected output tree for an update of the wc_backup.
325 expected_output
= svntest
.wc
.State(wc_dir
, {
326 'A/mu' : Item(status
=' C'),
327 'A' : Item(status
=' C'),
330 # Create expected disk tree for the update.
331 expected_disk
= svntest
.main
.greek_state
.copy()
332 expected_disk
.tweak('A/mu', props
={'cash-sound' : 'beep!'})
333 expected_disk
.tweak('A', props
={'foo' : 'baz'})
335 # Create expected status tree for the update.
336 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 2)
337 expected_status
.tweak('A/mu', 'A', status
=' C')
339 extra_files
= ['mu.*\.prej', 'dir_conflicts.*\.prej']
340 # Do the update and check the results in three ways... INCLUDING PROPS
341 svntest
.actions
.run_and_verify_update(wc_dir
,
346 svntest
.tree
.detect_conflict_files
,
350 if len(extra_files
) != 0:
351 print "didn't get expected conflict files"
352 raise svntest
.verify
.SVNUnexpectedOutput
354 # Resolve the conflicts
355 svntest
.main
.run_svn(None, 'resolved', mu_path
)
356 svntest
.main
.run_svn(None, 'resolved', A_path
)
358 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 2)
359 expected_status
.tweak('A/mu', 'A', status
=' M')
361 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
363 #----------------------------------------------------------------------
364 def commit_conflict_dirprops(sbox
):
365 "commit with conflicting dirprops"
367 # Issue #2608: failure to see conflicting dirprops on root of
374 svntest
.main
.run_svn(None, 'propset', 'foo', 'bar', wc_dir
)
376 # Commit the file and directory
377 svntest
.main
.run_svn(None,
378 'ci', '-m', 'r2', wc_dir
)
381 svntest
.main
.run_svn(None,
382 'up', '-r', '1', wc_dir
)
384 # Add conflicting properties
385 svntest
.main
.run_svn(None, 'propset', 'foo', 'eek', wc_dir
)
387 svntest
.actions
.run_and_verify_commit(wc_dir
, None, None,
388 "[oO]ut[- ]of[- ]date",
391 #----------------------------------------------------------------------
393 # Issue #742: we used to screw up when committing a file replacement
394 # that also had properties. It was fixed by teaching
395 # svn_wc_props_modified_p and svn_wc_transmit_prop_deltas to *ignore*
396 # leftover base-props when a file is scheduled for replacement. (When
397 # we svn_wc_add a file, it starts life with no working props.)
399 def commit_replacement_props(sbox
):
400 "props work when committing a replacement"
406 # Add a property to two files
407 iota_path
= os
.path
.join(wc_dir
, 'iota')
408 lambda_path
= os
.path
.join(wc_dir
, 'A', 'B', 'lambda')
409 svntest
.main
.run_svn(None, 'propset', 'cash-sound', 'cha-ching!', iota_path
)
410 svntest
.main
.run_svn(None, 'propset', 'boson', 'W', lambda_path
)
412 # Commit (### someday use run_and_verify_commit for better coverage)
413 svntest
.actions
.run_and_verify_svn("Error in property commit",
415 'ci', '-m', 'logmsg', wc_dir
)
417 # Schedule both files for deletion
418 svntest
.main
.run_svn(None, 'rm', iota_path
, lambda_path
)
420 # Now recreate the files, and schedule them for addition.
421 # Poof, the 'new' files don't have any properties at birth.
422 svntest
.main
.file_append(iota_path
, 'iota TNG')
423 svntest
.main
.file_append(lambda_path
, 'lambda TNG')
424 svntest
.main
.run_svn(None, 'add', iota_path
, lambda_path
)
426 # Sanity check: the two files should be scheduled for (R)eplacement.
427 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
428 expected_status
.tweak('iota', wc_rev
=2, status
='R ')
429 expected_status
.tweak('A/B/lambda', wc_rev
=2, status
='R ')
431 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
433 # Now add a property to lambda. Iota still doesn't have any.
434 svntest
.main
.run_svn(None, 'propset', 'capacitor', 'flux', lambda_path
)
436 # Commit, with careful output checking. We're actually going to
437 # scan the working copy for props after the commit.
439 expected_output
= svntest
.wc
.State(wc_dir
, {
440 'iota' : Item(verb
='Replacing'),
441 'A/B/lambda' : Item(verb
='Replacing'),
444 # Expected status tree: lambda has one prop, iota doesn't.
445 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
446 expected_status
.tweak('iota', wc_rev
=3)
447 expected_status
.tweak('A/B/lambda', wc_rev
=3, status
=' ')
449 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
453 #----------------------------------------------------------------------
455 def revert_replacement_props(sbox
):
456 "props work when reverting a replacement"
462 # Add a property to two files
463 iota_path
= os
.path
.join(wc_dir
, 'iota')
464 lambda_path
= os
.path
.join(wc_dir
, 'A', 'B', 'lambda')
465 svntest
.main
.run_svn(None, 'propset', 'cash-sound', 'cha-ching!', iota_path
)
466 svntest
.main
.run_svn(None, 'propset', 'boson', 'W', lambda_path
)
468 # Commit rev 2. (### someday use run_and_verify_commit for better coverage)
469 svntest
.actions
.run_and_verify_svn("Error in property commit", None, [],
470 'ci', '-m', 'logmsg', wc_dir
)
472 # Schedule both files for deletion
473 svntest
.main
.run_svn(None, 'rm', iota_path
, lambda_path
)
475 # Now recreate the files, and schedule them for addition.
476 # Poof, the 'new' files don't have any properties at birth.
477 svntest
.main
.file_append(iota_path
, 'iota TNG')
478 svntest
.main
.file_append(lambda_path
, 'lambda TNG')
479 svntest
.main
.run_svn(None, 'add', iota_path
, lambda_path
)
481 # Sanity check: the two files should be scheduled for (R)eplacement.
482 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
483 expected_status
.tweak('iota', wc_rev
=2, status
='R ')
484 expected_status
.tweak('A/B/lambda', wc_rev
=2, status
='R ')
486 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
488 # Now add a property to lambda. Iota still doesn't have any.
489 svntest
.main
.run_svn(None, 'propset', 'capacitor', 'flux', lambda_path
)
491 # Now revert both files.
492 svntest
.main
.run_svn(None, 'revert', iota_path
, lambda_path
)
494 # Do an update; even though the update is really a no-op,
495 # run_and_verify_update has the nice feature of scanning disk as
496 # well as running status. We want to verify that we truly have a
497 # *pristine* revision 2 tree, with the original rev 2 props, and no
500 expected_output
= svntest
.wc
.State(wc_dir
, {
503 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 2)
504 expected_status
.tweak('iota', status
=' ')
505 expected_status
.tweak('A/B/lambda', status
=' ')
507 expected_disk
= svntest
.main
.greek_state
.copy()
508 expected_disk
.tweak('iota', props
={'cash-sound' : 'cha-ching!'})
509 expected_disk
.tweak('A/B/lambda', props
={'boson' : 'W'})
511 # scan disk for props too.
512 svntest
.actions
.run_and_verify_update(wc_dir
,
516 None, None, None, None, None,
519 #----------------------------------------------------------------------
521 def inappropriate_props(sbox
):
522 "try to set inappropriate props"
528 A_path
= os
.path
.join(wc_dir
, 'A')
529 E_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E')
530 iota_path
= os
.path
.join(wc_dir
, 'iota')
532 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
533 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
535 # These should produce an error
536 svntest
.actions
.run_and_verify_svn('Illegal target',
537 None, svntest
.verify
.AnyOutput
,
538 'propset', 'svn:executable', 'on', A_path
)
540 svntest
.actions
.run_and_verify_svn('Illegal target', None,
541 svntest
.verify
.AnyOutput
, 'propset',
542 'svn:keywords', 'LastChangedDate',
545 svntest
.actions
.run_and_verify_svn('Illegal target', None,
546 svntest
.verify
.AnyOutput
, 'propset',
547 'svn:eol-style', 'native', A_path
)
549 svntest
.actions
.run_and_verify_svn('Invalid svn:eol-style', None,
550 svntest
.verify
.AnyOutput
, 'propset',
551 'svn:eol-style', 'invalid value',
552 os
.path
.join(A_path
, 'mu'))
554 svntest
.actions
.run_and_verify_svn('Illegal target', None,
555 svntest
.verify
.AnyOutput
, 'propset',
556 'svn:mime-type', 'image/png', A_path
)
558 svntest
.actions
.run_and_verify_svn('Illegal target', None,
559 svntest
.verify
.AnyOutput
, 'propset',
560 'svn:ignore', '*.o', iota_path
)
562 svntest
.actions
.run_and_verify_svn('Illegal target', None,
563 svntest
.verify
.AnyOutput
, 'propset',
565 'foo http://host.com/repos', iota_path
)
567 svntest
.actions
.run_and_verify_svn('Illegal target', None,
568 svntest
.verify
.AnyOutput
, 'propset',
569 'svn:author', 'socrates', iota_path
)
571 svntest
.actions
.run_and_verify_svn('Illegal target', None,
572 svntest
.verify
.AnyOutput
, 'propset',
573 'svn:log', 'log message', iota_path
)
575 svntest
.actions
.run_and_verify_svn('Illegal target', None,
576 svntest
.verify
.AnyOutput
, 'propset',
577 'svn:date', 'Tue Jan 19 04:14:07 2038',
580 svntest
.actions
.run_and_verify_svn('Illegal target', None,
581 svntest
.verify
.AnyOutput
, 'propset',
583 'Thu Jan 1 01:00:00 1970', iota_path
)
586 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
588 # Recursive setting of inappropriate dir prop should work on files
589 svntest
.actions
.run_and_verify_svn(None, None, [], 'propset', '-R',
590 'svn:executable', 'on', E_path
)
592 expected_status
.tweak('A/B/E/alpha', 'A/B/E/beta', status
=' M')
593 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
595 # Issue #920. Don't allow setting of svn:eol-style on binary files or files
596 # with inconsistent eol types.
598 path
= os
.path
.join(wc_dir
, 'binary')
599 svntest
.main
.file_append(path
, "binary")
600 svntest
.main
.run_svn(None, 'add', path
)
602 svntest
.main
.run_svn(None, 'propset', 'svn:mime-type',
603 'application/octet-stream', path
)
605 svntest
.actions
.run_and_verify_svn('Illegal target', None,
606 svntest
.verify
.AnyOutput
,
607 'propset', 'svn:eol-style',
610 path
= os
.path
.join(wc_dir
, 'multi-eol')
611 svntest
.main
.file_append(path
, "line1\rline2\n")
612 svntest
.main
.run_svn(None, 'add', path
)
614 svntest
.actions
.run_and_verify_svn('Illegal target', None,
615 svntest
.verify
.AnyOutput
,
616 'propset', 'svn:eol-style',
619 path
= os
.path
.join(wc_dir
, 'backwards-eol')
620 svntest
.main
.file_append(path
, "line1\n\r")
621 svntest
.main
.run_svn(None, 'add', path
)
623 svntest
.actions
.run_and_verify_svn('Illegal target', None,
624 svntest
.verify
.AnyOutput
,
625 'propset', 'svn:eol-style',
628 path
= os
.path
.join(wc_dir
, 'incomplete-eol')
629 svntest
.main
.file_append(path
, "line1\r\n\r")
630 svntest
.main
.run_svn(None, 'add', path
)
632 svntest
.actions
.run_and_verify_svn('Illegal target', None,
633 svntest
.verify
.AnyOutput
,
634 'propset', 'svn:eol-style',
637 # Issue #2065. Do allow setting of svn:eol-style on binary files or files
638 # with inconsistent eol types if --force is passed.
640 path
= os
.path
.join(wc_dir
, 'binary')
641 svntest
.main
.file_append(path
, "binary")
642 svntest
.actions
.run_and_verify_svn(None, None, [],
643 'propset', '--force',
644 'svn:eol-style', 'CRLF',
647 path
= os
.path
.join(wc_dir
, 'multi-eol')
648 svntest
.actions
.run_and_verify_svn(None, None, [],
649 'propset', '--force',
650 'svn:eol-style', 'LF',
653 path
= os
.path
.join(wc_dir
, 'backwards-eol')
654 svntest
.actions
.run_and_verify_svn(None, None, [],
655 'propset', '--force',
656 'svn:eol-style', 'native',
659 path
= os
.path
.join(wc_dir
, 'incomplete-eol')
660 svntest
.actions
.run_and_verify_svn(None, None, [],
661 'propset', '--force',
662 'svn:eol-style', 'CR',
665 # Prevent setting of svn:mergeinfo prop values that are...
666 path
= os
.path
.join(wc_dir
, 'A', 'D')
668 # ...grammatically incorrect
669 svntest
.actions
.run_and_verify_svn('illegal grammar', None,
670 "svn: Pathname not terminated by ':'\n",
671 'propset', SVN_PROP_MERGEINFO
, '/trunk',
673 svntest
.actions
.run_and_verify_svn('illegal grammar', None,
674 "svn: Invalid revision number found "
676 'propset', SVN_PROP_MERGEINFO
,
679 # ...contain overlapping revision ranges
680 svntest
.actions
.run_and_verify_svn('overlapping ranges', None,
681 "svn: Parsing of overlapping revision "
682 "ranges '9-20' and '18-22' is not "
684 'propset', SVN_PROP_MERGEINFO
,
685 '/branch:5-7,9-20,18-22', path
)
687 svntest
.actions
.run_and_verify_svn('overlapping ranges', None,
688 "svn: Parsing of overlapping revision "
689 "ranges '3' and '3' is not supported\n",
690 'propset', SVN_PROP_MERGEINFO
,
693 # ...contain unordered revision ranges
694 svntest
.actions
.run_and_verify_svn('unordered ranges', None,
695 "svn: Unable to parse unordered "
696 "revision ranges '5' and '2-3'\n",
697 'propset', SVN_PROP_MERGEINFO
,
698 '/featureX:5,2-3,9', path
)
700 # ...contain revision ranges with start revisions greater than or
701 # equal to end revisions.
702 svntest
.actions
.run_and_verify_svn('range start >= range end', None,
703 "svn: Unable to parse reversed "
704 "revision range '20-5'\n",
705 'propset', SVN_PROP_MERGEINFO
,
706 '/featureX:4,20-5', path
)
708 # ...contain paths mapped to empty revision ranges
709 svntest
.actions
.run_and_verify_svn('empty ranges', None,
710 "svn: Mergeinfo for '/trunk' maps to "
711 "an empty revision range\n",
712 'propset', SVN_PROP_MERGEINFO
,
715 #----------------------------------------------------------------------
717 # Issue #976. When copying a file, do not determine svn:executable
718 # and svn:mime-type values as though the file is brand new, instead
719 # use the copied file's property values.
721 def copy_inherits_special_props(sbox
):
722 "file copies inherit (not re-derive) special props"
728 orig_mime_type
= 'image/fake_image'
731 new_path1
= os
.path
.join(wc_dir
, 'new_file1.bin')
732 new_path2
= os
.path
.join(wc_dir
, 'new_file2.bin')
734 # Create the first path as a binary file. To have svn treat the
735 # file as binary, have a 0x00 in the file.
736 svntest
.main
.file_append(new_path1
, "binary file\000")
737 svntest
.main
.run_svn(None, 'add', new_path1
)
739 # Add initial svn:mime-type to the file
740 svntest
.main
.run_svn(None, 'propset', 'svn:mime-type', orig_mime_type
,
743 # Set the svn:executable property on the file if this is a system
744 # that can handle chmod, in which case svn will turn on the
745 # executable bits on the file. Then remove the executable bits
746 # manually on the file and see the value of svn:executable in the
748 if os
.name
== 'posix':
749 svntest
.main
.run_svn(None, 'propset', 'svn:executable', 'on', new_path1
)
750 os
.chmod(new_path1
, 0644)
753 svntest
.main
.run_svn(None,
754 'ci', '-m', 'create file and set svn:mime-type',
758 svntest
.main
.run_svn(None, 'cp', new_path1
, new_path2
)
760 # Check the svn:mime-type
761 actual_exit
, actual_stdout
, actual_stderr
= svntest
.main
.run_svn(
762 None, 'pg', 'svn:mime-type', new_path2
)
764 expected_stdout
= [orig_mime_type
+ '\n']
765 if actual_stdout
!= expected_stdout
:
766 print "svn pg svn:mime-type output does not match expected."
767 print "Expected standard output: ", expected_stdout
, "\n"
768 print "Actual standard output: ", actual_stdout
, "\n"
769 raise svntest
.verify
.SVNUnexpectedOutput
771 # Check the svn:executable value.
772 # The value of the svn:executable property is now always forced to '*'
773 if os
.name
== 'posix':
774 actual_exit
, actual_stdout
, actual_stderr
= svntest
.main
.run_svn(
775 None, 'pg', 'svn:executable', new_path2
)
777 expected_stdout
= ['*\n']
778 if actual_stdout
!= expected_stdout
:
779 print "svn pg svn:executable output does not match expected."
780 print "Expected standard output: ", expected_stdout
, "\n"
781 print "Actual standard output: ", actual_stdout
, "\n"
782 raise svntest
.verify
.SVNUnexpectedOutput
784 #----------------------------------------------------------------------
786 def revprop_change(sbox
):
787 "set, get, and delete a revprop change"
791 # First test the error when no revprop-change hook exists.
792 svntest
.actions
.run_and_verify_svn(None, None, '.*pre-revprop-change',
793 'propset', '--revprop', '-r', '0',
794 'cash-sound', 'cha-ching!', sbox
.wc_dir
)
796 # Now test error output from revprop-change hook.
797 svntest
.actions
.disable_revprop_changes(sbox
.repo_dir
)
798 svntest
.actions
.run_and_verify_svn(None, None, '.*pre-revprop-change.* 0 jrandom cash-sound A',
799 'propset', '--revprop', '-r', '0',
800 'cash-sound', 'cha-ching!', sbox
.wc_dir
)
802 # Create the revprop-change hook for this test
803 svntest
.actions
.enable_revprop_changes(sbox
.repo_dir
)
805 svntest
.actions
.run_and_verify_svn(None, None, [],
806 'propset', '--revprop', '-r', '0',
807 'cash-sound', 'cha-ching!', sbox
.wc_dir
)
809 svntest
.actions
.run_and_verify_svn(None, None, [],
810 'propget', '--revprop', '-r', '0',
811 'cash-sound', sbox
.wc_dir
)
813 # Now test that blocking the revprop delete.
814 svntest
.actions
.disable_revprop_changes(sbox
.repo_dir
)
815 svntest
.actions
.run_and_verify_svn(None, None, '.*pre-revprop-change.* 0 jrandom cash-sound D',
816 'propdel', '--revprop', '-r', '0',
817 'cash-sound', sbox
.wc_dir
)
819 # Now test actually deleting the revprop.
820 svntest
.actions
.enable_revprop_changes(sbox
.repo_dir
)
821 svntest
.actions
.run_and_verify_svn(None, None, [],
822 'propdel', '--revprop', '-r', '0',
823 'cash-sound', sbox
.wc_dir
)
825 actual_exit
, actual_stdout
, actual_stderr
= svntest
.main
.run_svn(
826 None, 'pg', '--revprop', '-r', '0', 'cash-sound', sbox
.wc_dir
)
828 # The property should have been deleted.
830 for line
in actual_stdout
:
831 if re
.match(regex
, line
):
832 raise svntest
.Failure
835 #----------------------------------------------------------------------
837 def prop_value_conversions(sbox
):
838 "some svn: properties should be converted"
844 A_path
= os
.path
.join(wc_dir
, 'A')
845 B_path
= os
.path
.join(wc_dir
, 'A', 'B')
846 iota_path
= os
.path
.join(wc_dir
, 'iota')
847 lambda_path
= os
.path
.join(wc_dir
, 'A', 'B', 'lambda')
848 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
850 # We'll use a file to set the prop values, so that weird characters
851 # in the props don't confuse the shell.
852 propval_path
= os
.path
.join(wc_dir
, 'propval.tmp')
853 propval_file
= open(propval_path
, 'wb')
855 def set_prop(name
, value
, path
, valf
=propval_file
, valp
=propval_path
,
856 expected_error
=None):
861 svntest
.main
.run_svn(expected_error
, 'propset', '-F', valp
, name
, path
)
863 # Leading and trailing whitespace should be stripped
864 set_prop('svn:mime-type', ' text/html\n\n', iota_path
)
865 set_prop('svn:mime-type', 'text/html', mu_path
)
867 # Leading and trailing whitespace should be stripped
868 set_prop('svn:eol-style', '\nnative\n', iota_path
)
869 set_prop('svn:eol-style', 'native', mu_path
)
871 # A trailing newline should be added
872 set_prop('svn:ignore', '*.o\nfoo.c', A_path
)
873 set_prop('svn:ignore', '*.o\nfoo.c\n', B_path
)
875 # A trailing newline should be added
876 set_prop('svn:externals', 'foo http://foo.com/repos', A_path
)
877 set_prop('svn:externals', 'foo http://foo.com/repos\n', B_path
)
879 # Leading and trailing whitespace should be stripped, but not internal
881 set_prop('svn:keywords', ' Rev Date \n', iota_path
)
882 set_prop('svn:keywords', 'Rev Date', mu_path
)
884 # svn:executable value should be forced to a '*'
885 set_prop('svn:executable', 'foo', iota_path
)
886 set_prop('svn:executable', '*', lambda_path
)
887 for pval
in (' ', '', 'no', 'off', 'false'):
888 set_prop('svn:executable', pval
, mu_path
, propval_file
, propval_path
,
889 ["svn: warning: To turn off the svn:executable property, "
890 "use 'svn propdel';\n",
891 "setting the property to '" + pval
+
892 "' will not turn it off.\n"])
894 # Anything else should be untouched
895 set_prop('svn:some-prop', 'bar', lambda_path
)
896 set_prop('svn:some-prop', ' bar baz', mu_path
)
897 set_prop('svn:some-prop', 'bar\n', iota_path
)
898 set_prop('some-prop', 'bar', lambda_path
)
899 set_prop('some-prop', ' bar baz', mu_path
)
900 set_prop('some-prop', 'bar\n', iota_path
)
902 # Close and remove the prop value file
904 os
.unlink(propval_path
)
906 # NOTE: When writing out multi-line prop values in svn:* props, the
907 # client converts to local encoding and local eoln style.
908 # Therefore, the expected output must contain the right kind of eoln
909 # strings. That's why we use os.linesep in the tests below, not just
910 # plain '\n'. The _last_ \n is also from the client, but it's not
911 # part of the prop value and it doesn't get converted in the pipe.
913 # Check svn:mime-type
914 svntest
.actions
.check_prop('svn:mime-type', iota_path
, ['text/html'])
915 svntest
.actions
.check_prop('svn:mime-type', mu_path
, ['text/html'])
917 # Check svn:eol-style
918 svntest
.actions
.check_prop('svn:eol-style', iota_path
, ['native'])
919 svntest
.actions
.check_prop('svn:eol-style', mu_path
, ['native'])
922 svntest
.actions
.check_prop('svn:ignore', A_path
,
923 ['*.o'+os
.linesep
, 'foo.c'+os
.linesep
])
924 svntest
.actions
.check_prop('svn:ignore', B_path
,
925 ['*.o'+os
.linesep
, 'foo.c'+os
.linesep
])
927 # Check svn:externals
928 svntest
.actions
.check_prop('svn:externals', A_path
,
929 ['foo http://foo.com/repos'+os
.linesep
])
930 svntest
.actions
.check_prop('svn:externals', B_path
,
931 ['foo http://foo.com/repos'+os
.linesep
])
934 svntest
.actions
.check_prop('svn:keywords', iota_path
, ['Rev Date'])
935 svntest
.actions
.check_prop('svn:keywords', mu_path
, ['Rev Date'])
937 # Check svn:executable
938 svntest
.actions
.check_prop('svn:executable', iota_path
, ['*'])
939 svntest
.actions
.check_prop('svn:executable', lambda_path
, ['*'])
940 svntest
.actions
.check_prop('svn:executable', mu_path
, ['*'])
943 svntest
.actions
.check_prop('svn:some-prop', lambda_path
, ['bar'])
944 svntest
.actions
.check_prop('svn:some-prop', mu_path
, [' bar baz'])
945 svntest
.actions
.check_prop('svn:some-prop', iota_path
, ['bar'+os
.linesep
])
946 svntest
.actions
.check_prop('some-prop', lambda_path
, ['bar'])
947 svntest
.actions
.check_prop('some-prop', mu_path
,[' bar baz'])
948 svntest
.actions
.check_prop('some-prop', iota_path
, ['bar\n'])
951 #----------------------------------------------------------------------
953 def binary_props(sbox
):
954 "test binary property support"
960 # Make a backup copy of the working copy
961 wc_backup
= sbox
.add_wc_path('backup')
962 svntest
.actions
.duplicate_dir(wc_dir
, wc_backup
)
964 # Some path convenience vars.
965 A_path
= os
.path
.join(wc_dir
, 'A')
966 B_path
= os
.path
.join(wc_dir
, 'A', 'B')
967 iota_path
= os
.path
.join(wc_dir
, 'iota')
968 lambda_path
= os
.path
.join(wc_dir
, 'A', 'B', 'lambda')
969 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
970 A_path_bak
= os
.path
.join(wc_backup
, 'A')
971 B_path_bak
= os
.path
.join(wc_backup
, 'A', 'B')
972 iota_path_bak
= os
.path
.join(wc_backup
, 'iota')
973 lambda_path_bak
= os
.path
.join(wc_backup
, 'A', 'B', 'lambda')
974 mu_path_bak
= os
.path
.join(wc_backup
, 'A', 'mu')
976 # Property value convenience vars.
977 prop_zb
= "This property has a zer\000 byte."
978 prop_ff
= "This property has a form\014feed."
979 prop_xml
= "This property has an <xml> tag."
980 prop_binx
= "This property has an <xml> tag and a zer\000 byte."
982 # Set some binary properties.
983 propval_path
= os
.path
.join(wc_dir
, 'propval.tmp')
984 propval_file
= open(propval_path
, 'wb')
986 def set_prop(name
, value
, path
, valf
=propval_file
, valp
=propval_path
):
991 svntest
.main
.run_svn(None, 'propset', '-F', valp
, name
, path
)
993 set_prop('prop_zb', prop_zb
, B_path
)
994 set_prop('prop_ff', prop_ff
, iota_path
)
995 set_prop('prop_xml', prop_xml
, lambda_path
)
996 set_prop('prop_binx', prop_binx
, mu_path
)
997 set_prop('prop_binx', prop_binx
, A_path
)
999 # Create expected output and status trees.
1000 expected_output
= svntest
.wc
.State(wc_dir
, {
1001 'A' : Item(verb
='Sending'),
1002 'A/B' : Item(verb
='Sending'),
1003 'iota' : Item(verb
='Sending'),
1004 'A/B/lambda' : Item(verb
='Sending'),
1005 'A/mu' : Item(verb
='Sending'),
1007 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1008 expected_status
.tweak('A', 'A/B', 'iota', 'A/B/lambda', 'A/mu',
1009 wc_rev
=2, status
=' ')
1011 # Commit the propsets.
1012 svntest
.actions
.run_and_verify_commit(wc_dir
,
1018 # Create expected output, disk, and status trees for an update of
1020 expected_output
= svntest
.wc
.State(wc_backup
, {
1021 'A' : Item(status
=' U'),
1022 'A/B' : Item(status
=' U'),
1023 'iota' : Item(status
=' U'),
1024 'A/B/lambda' : Item(status
=' U'),
1025 'A/mu' : Item(status
=' U'),
1027 expected_disk
= svntest
.main
.greek_state
.copy()
1028 expected_status
= svntest
.actions
.get_virginal_state(wc_backup
, 2)
1030 # Do the update and check the results.
1031 svntest
.actions
.run_and_verify_update(wc_backup
,
1035 None, None, None, None, None, 0)
1037 # Now, check those properties.
1038 svntest
.actions
.check_prop('prop_zb', B_path_bak
, [prop_zb
])
1039 svntest
.actions
.check_prop('prop_ff', iota_path_bak
, [prop_ff
])
1040 svntest
.actions
.check_prop('prop_xml', lambda_path_bak
, [prop_xml
])
1041 svntest
.actions
.check_prop('prop_binx', mu_path_bak
, [prop_binx
])
1042 svntest
.actions
.check_prop('prop_binx', A_path_bak
, [prop_binx
])
1044 #----------------------------------------------------------------------
1046 # Ensure that each line of output contains the corresponding string of
1047 # expected_out, and that errput is empty.
1048 def verify_output(expected_out
, output
, errput
):
1050 print 'Error: stderr:'
1052 raise svntest
.Failure
1056 if ((line
.find(expected_out
[ln
]) == -1) or
1057 (line
!= '' and expected_out
[ln
] == '')):
1058 print 'Error: expected keywords: ', expected_out
1059 print ' actual full output:', output
1060 raise svntest
.Failure
1063 def recursive_base_wc_ops(sbox
):
1064 "recursive property operations in BASE and WC"
1068 wc_dir
= sbox
.wc_dir
1070 # Files with which to test, in alphabetical order
1071 f_add
= os
.path
.join('A', 'added')
1072 f_del
= os
.path
.join('A', 'mu')
1073 f_keep
= os
.path
.join('iota')
1074 fp_add
= os
.path
.join(wc_dir
, f_add
)
1075 fp_del
= os
.path
.join(wc_dir
, f_del
)
1076 fp_keep
= os
.path
.join(wc_dir
, f_keep
)
1079 svntest
.main
.run_svn(None, 'propset', 'p', 'old-del', fp_del
)
1080 svntest
.main
.run_svn(None, 'propset', 'p', 'old-keep',fp_keep
)
1081 svntest
.main
.run_svn(None,
1082 'commit', '-m', '', wc_dir
)
1083 svntest
.main
.file_append(fp_add
, 'blah')
1084 svntest
.main
.run_svn(None, 'add', fp_add
)
1085 svntest
.main
.run_svn(None, 'propset', 'p', 'new-add', fp_add
)
1086 svntest
.main
.run_svn(None, 'propset', 'p', 'new-del', fp_del
)
1087 svntest
.main
.run_svn(None, 'propset', 'p', 'new-keep',fp_keep
)
1088 svntest
.main
.run_svn(None, 'del', '--force', fp_del
)
1090 # Test recursive proplist
1091 exit_code
, output
, errput
= svntest
.main
.run_svn(None, 'proplist', '-R',
1092 '-v', wc_dir
, '-rBASE')
1093 verify_output([ 'old-del', 'old-keep', 'Properties on ', 'Properties on ' ],
1095 svntest
.verify
.verify_exit_code(None, exit_code
, 0)
1097 exit_code
, output
, errput
= svntest
.main
.run_svn(None, 'proplist', '-R',
1099 verify_output([ 'new-add', 'new-keep', 'Properties on ', 'Properties on ' ],
1101 svntest
.verify
.verify_exit_code(None, exit_code
, 0)
1103 # Test recursive propget
1104 exit_code
, output
, errput
= svntest
.main
.run_svn(None, 'propget', '-R',
1105 'p', wc_dir
, '-rBASE')
1106 verify_output([ 'old-del', 'old-keep' ], output
, errput
)
1107 svntest
.verify
.verify_exit_code(None, exit_code
, 0)
1109 exit_code
, output
, errput
= svntest
.main
.run_svn(None, 'propget', '-R',
1111 verify_output([ 'new-add', 'new-keep' ], output
, errput
)
1112 svntest
.verify
.verify_exit_code(None, exit_code
, 0)
1114 # Test recursive propset (issue 1794)
1115 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1116 expected_status
.tweak('A/mu', status
='D ', wc_rev
=2)
1117 expected_status
.tweak('iota', status
=' M', wc_rev
=2)
1118 expected_status
.add({
1119 'A/added' : Item(status
='A ', wc_rev
=0),
1121 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
1123 svntest
.actions
.run_and_verify_svn(None, None, [],
1124 'propset', '-R', 'svn:keywords', 'Date',
1125 os
.path
.join(wc_dir
, 'A', 'B'))
1126 expected_status
.tweak('A/B/lambda', 'A/B/E/alpha', 'A/B/E/beta', status
=' M')
1127 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
1129 #----------------------------------------------------------------------
1131 def url_props_ops(sbox
):
1132 "property operations on an URL"
1136 wc_dir
= sbox
.wc_dir
1139 propval1
= 'propval1 is foo'
1141 propval2
= 'propval2'
1143 iota_path
= os
.path
.join(sbox
.wc_dir
, 'iota')
1144 iota_url
= sbox
.repo_url
+ '/iota'
1145 A_path
= os
.path
.join(sbox
.wc_dir
, 'A')
1146 A_url
= sbox
.repo_url
+ '/A'
1148 # Add a couple of properties
1149 svntest
.main
.run_svn(None, 'propset', prop1
, propval1
, iota_path
)
1150 svntest
.main
.run_svn(None, 'propset', prop1
, propval1
, A_path
)
1153 svntest
.main
.run_svn(None,
1154 'ci', '-m', 'logmsg', sbox
.wc_dir
)
1156 # Add a few more properties
1157 svntest
.main
.run_svn(None, 'propset', prop2
, propval2
, iota_path
)
1158 svntest
.main
.run_svn(None, 'propset', prop2
, propval2
, A_path
)
1161 svntest
.main
.run_svn(None,
1162 'ci', '-m', 'logmsg', sbox
.wc_dir
)
1165 svntest
.actions
.run_and_verify_svn(None, [ propval1
+ '\n' ], [],
1166 'propget', prop1
, iota_url
)
1167 svntest
.actions
.run_and_verify_svn(None, [ propval1
+ '\n' ], [],
1168 'propget', prop1
, A_url
)
1170 # Test normal proplist
1171 exit_code
, output
, errput
= svntest
.main
.run_svn(None,
1172 'proplist', iota_url
)
1173 verify_output([ prop1
, prop2
, 'Properties on ' ],
1175 svntest
.verify
.verify_exit_code(None, exit_code
, 0)
1177 exit_code
, output
, errput
= svntest
.main
.run_svn(None,
1179 verify_output([ prop1
, prop2
, 'Properties on ' ],
1181 svntest
.verify
.verify_exit_code(None, exit_code
, 0)
1183 # Test verbose proplist
1184 exit_code
, output
, errput
= svntest
.main
.run_svn(None,
1185 'proplist', '-v', iota_url
)
1186 verify_output([ prop1
+ ' : ' + propval1
, prop2
+ ' : ' + propval2
,
1187 'Properties on ' ], output
, errput
)
1188 svntest
.verify
.verify_exit_code(None, exit_code
, 0)
1190 exit_code
, output
, errput
= svntest
.main
.run_svn(None,
1191 'proplist', '-v', A_url
)
1192 verify_output([ prop1
+ ' : ' + propval1
, prop2
+ ' : ' + propval2
,
1193 'Properties on ' ], output
, errput
)
1194 svntest
.verify
.verify_exit_code(None, exit_code
, 0)
1197 svntest
.main
.use_editor('foo_to_bar')
1198 propval1
= propval1
.replace('foo', 'bar')
1199 svntest
.main
.run_svn(None,
1200 'propedit', prop1
, '-m', 'editlog', iota_url
)
1201 svntest
.main
.run_svn(None,
1202 'propedit', prop1
, '-m', 'editlog', A_url
)
1203 svntest
.actions
.run_and_verify_svn(None, [ propval1
+ '\n' ], [],
1204 'propget', prop1
, iota_url
)
1205 svntest
.actions
.run_and_verify_svn(None, [ propval1
+ '\n' ], [],
1206 'propget', prop1
, A_url
)
1208 # Edit without actually changing the property
1209 svntest
.main
.use_editor('identity')
1210 svntest
.actions
.run_and_verify_svn(None,
1211 "No changes to property '%s' on '.*'"
1214 'propedit', prop1
, '-m', 'nocommit',
1219 #----------------------------------------------------------------------
1220 def removal_schedule_added_props(sbox
):
1221 "removal of schedule added file with properties"
1225 wc_dir
= sbox
.wc_dir
1226 newfile_path
= os
.path
.join(wc_dir
, 'newfile')
1227 file_add_output
= ["A " + newfile_path
+ "\n"]
1228 propset_output
= ["property 'newprop' set on '" + newfile_path
+ "'\n"]
1229 file_rm_output
= ["D " + newfile_path
+ "\n"]
1231 "Properties on '" + newfile_path
+ "':\n",
1232 " newprop : newvalue\n",
1235 # create new fs file
1236 open(newfile_path
, 'w').close()
1237 # Add it and set a property
1238 svntest
.actions
.run_and_verify_svn(None, file_add_output
, [], 'add', newfile_path
)
1239 svntest
.actions
.run_and_verify_svn(None, propset_output
, [], 'propset',
1240 'newprop', 'newvalue', newfile_path
)
1241 svntest
.actions
.run_and_verify_svn(None, propls_output
, [],
1242 'proplist', '-v', newfile_path
)
1244 svntest
.actions
.run_and_verify_svn(None, file_rm_output
, [],
1245 'rm', '--force', newfile_path
)
1246 # recreate the file and add it again
1247 open(newfile_path
, 'w').close()
1248 svntest
.actions
.run_and_verify_svn(None, file_add_output
, [], 'add', newfile_path
)
1250 # Now there should be NO properties leftover...
1251 svntest
.actions
.run_and_verify_svn(None, [], [],
1252 'proplist', '-v', newfile_path
)
1254 #----------------------------------------------------------------------
1256 def update_props_on_wc_root(sbox
):
1257 "receive properties on the wc root via update"
1261 wc_dir
= sbox
.wc_dir
1263 # Make a backup copy of the working copy
1264 wc_backup
= sbox
.add_wc_path('backup')
1265 svntest
.actions
.duplicate_dir(wc_dir
, wc_backup
)
1267 # Add a property to the root folder
1268 svntest
.main
.run_svn(None, 'propset', 'red', 'rojo', wc_dir
)
1270 # Create expected output tree.
1271 expected_output
= svntest
.wc
.State(wc_dir
, {
1272 '' : Item(verb
='Sending')
1275 # Created expected status tree.
1276 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1277 expected_status
.tweak('', wc_rev
=2, status
=' ')
1279 # Commit the working copy
1280 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
1284 # Create expected output tree for an update of the wc_backup.
1285 expected_output
= svntest
.wc
.State(wc_backup
, {
1286 '' : Item(status
=' U'),
1288 # Create expected disk tree for the update.
1289 expected_disk
= svntest
.main
.greek_state
.copy()
1291 '' : Item(props
= {'red' : 'rojo'}),
1293 # Create expected status tree for the update.
1294 expected_status
= svntest
.actions
.get_virginal_state(wc_backup
, 2)
1295 expected_status
.tweak('', status
=' ')
1297 # Do the update and check the results in three ways... INCLUDING PROPS
1298 svntest
.actions
.run_and_verify_update(wc_backup
,
1302 None, None, None, None, None, 1)
1304 # test for issue 2743
1305 def props_on_replaced_file(sbox
):
1306 """test properties on replaced files"""
1309 wc_dir
= sbox
.wc_dir
1311 # Add some properties to iota
1312 iota_path
= os
.path
.join(wc_dir
, "iota")
1313 svntest
.main
.run_svn(None, 'propset', 'red', 'rojo', iota_path
)
1314 svntest
.main
.run_svn(None, 'propset', 'blue', 'lagoon', iota_path
)
1315 svntest
.main
.run_svn(None,
1316 'ci', '-m', 'log message', wc_dir
)
1319 svntest
.main
.run_svn(None, 'rm', iota_path
)
1320 svntest
.main
.file_append(iota_path
, "some mod")
1321 svntest
.main
.run_svn(None, 'add', iota_path
)
1323 # check that the replaced file has no properties
1324 expected_disk
= svntest
.main
.greek_state
.copy()
1325 expected_disk
.tweak('iota', contents
="some mod")
1326 actual_disk_tree
= svntest
.tree
.build_tree_from_wc(wc_dir
, 1)
1327 svntest
.tree
.compare_trees("disk", actual_disk_tree
,
1328 expected_disk
.old_tree())
1330 # now add a new property to iota
1331 svntest
.main
.run_svn(None, 'propset', 'red', 'mojo', iota_path
)
1332 svntest
.main
.run_svn(None, 'propset', 'groovy', 'baby', iota_path
)
1334 # What we expect the disk tree to look like:
1335 expected_disk
.tweak('iota', props
={'red' : 'mojo', 'groovy' : 'baby'})
1336 actual_disk_tree
= svntest
.tree
.build_tree_from_wc(wc_dir
, 1)
1337 svntest
.tree
.compare_trees("disk", actual_disk_tree
,
1338 expected_disk
.old_tree())
1340 #----------------------------------------------------------------------
1342 def depthy_wc_proplist(sbox
):
1343 """test proplist at various depths on a wc"""
1346 wc_dir
= sbox
.wc_dir
1348 A_path
= os
.path
.join(wc_dir
, 'A')
1349 iota_path
= os
.path
.join(wc_dir
, 'iota')
1350 mu_path
= os
.path
.join(A_path
, 'mu')
1352 # Set up properties.
1353 svntest
.main
.run_svn(None, 'propset', 'p', 'prop1', wc_dir
)
1354 svntest
.main
.run_svn(None, 'propset', 'p', 'prop2', iota_path
)
1355 svntest
.main
.run_svn(None, 'propset', 'p', 'prop3', A_path
)
1356 svntest
.main
.run_svn(None, 'propset', 'p', 'prop4', mu_path
)
1359 svntest
.main
.run_svn(None,
1360 'ci', '-m', 'log message', wc_dir
)
1362 # Test depth-empty proplist.
1363 exit_code
, output
, errput
= svntest
.main
.run_svn(None, 'proplist',
1366 verify_output([ 'prop1', 'Properties on ' ],
1368 svntest
.verify
.verify_exit_code(None, exit_code
, 0)
1370 # Test depth-files proplist.
1371 exit_code
, output
, errput
= svntest
.main
.run_svn(None, 'proplist',
1374 verify_output([ 'prop1', 'prop2', 'Properties on ', 'Properties on ' ],
1376 svntest
.verify
.verify_exit_code(None, exit_code
, 0)
1378 # Test depth-immediates proplist.
1379 exit_code
, output
, errput
= svntest
.main
.run_svn(None, 'proplist', '--depth',
1380 'immediates', '-v', wc_dir
)
1381 verify_output([ 'prop1', 'prop2', 'prop3' ] + ['Properties on '] * 3,
1383 svntest
.verify
.verify_exit_code(None, exit_code
, 0)
1385 # Test depth-infinity proplist.
1386 exit_code
, output
, errput
= svntest
.main
.run_svn(None, 'proplist', '--depth',
1387 'infinity', '-v', wc_dir
)
1388 verify_output([ 'prop1', 'prop2', 'prop3', 'prop4' ] + ['Properties on '] * 4,
1390 svntest
.verify
.verify_exit_code(None, exit_code
, 0)
1392 #----------------------------------------------------------------------
1394 def depthy_url_proplist(sbox
):
1395 """test proplist at various depths on a url"""
1398 repo_url
= sbox
.repo_url
1399 wc_dir
= sbox
.wc_dir
1401 A_path
= os
.path
.join(wc_dir
, 'A')
1402 iota_path
= os
.path
.join(wc_dir
, 'iota')
1403 mu_path
= os
.path
.join(A_path
, 'mu')
1405 # Set up properties.
1406 svntest
.main
.run_svn(None, 'propset', 'p', 'prop1', wc_dir
)
1407 svntest
.main
.run_svn(None, 'propset', 'p', 'prop2', iota_path
)
1408 svntest
.main
.run_svn(None, 'propset', 'p', 'prop3', A_path
)
1409 svntest
.main
.run_svn(None, 'propset', 'p', 'prop4', mu_path
)
1411 # Test depth-empty proplist.
1412 exit_code
, output
, errput
= svntest
.main
.run_svn(None, 'proplist',
1415 verify_output([ 'prop1', 'Properties on ' ],
1417 svntest
.verify
.verify_exit_code(None, exit_code
, 0)
1419 # Test depth-files proplist.
1420 exit_code
, output
, errput
= svntest
.main
.run_svn(None, 'proplist',
1423 verify_output([ 'prop1', 'prop2', 'Properties on ', 'Properties on ' ],
1425 svntest
.verify
.verify_exit_code(None, exit_code
, 0)
1427 # Test depth-immediates proplist.
1428 exit_code
, output
, errput
= svntest
.main
.run_svn(None, 'proplist',
1429 '--depth', 'immediates',
1432 verify_output([ 'prop1', 'prop2', 'prop3' ] + ['Properties on '] * 3,
1434 svntest
.verify
.verify_exit_code(None, exit_code
, 0)
1436 # Test depth-infinity proplist.
1437 exit_code
, output
, errput
= svntest
.main
.run_svn(None,
1438 'proplist', '--depth',
1439 'infinity', '-v', repo_url
)
1440 verify_output([ 'prop1', 'prop2', 'prop3', 'prop4' ] + ['Properties on '] * 4,
1442 svntest
.verify
.verify_exit_code(None, exit_code
, 0)
1444 #----------------------------------------------------------------------
1446 def invalid_propnames(sbox
):
1447 """test prop* handle invalid property names"""
1450 repo_url
= sbox
.repo_url
1451 wc_dir
= sbox
.wc_dir
1458 expected_stdout
= ["property '%s' deleted from '.'.\n" % (propname
,)]
1459 svntest
.actions
.run_and_verify_svn(None, expected_stdout
, [],
1460 'propdel', propname
)
1461 expected_stderr
= (".*'%s' is not a valid Subversion"
1462 ' property name' % (propname
,))
1463 svntest
.actions
.run_and_verify_svn(None, None, expected_stderr
,
1464 'propedit', propname
)
1465 svntest
.actions
.run_and_verify_svn(None, None, expected_stderr
,
1466 'propget', propname
)
1467 svntest
.actions
.run_and_verify_svn(None, None, expected_stderr
,
1468 'propset', propname
, propval
)
1470 svntest
.actions
.run_and_verify_svn(None, None, expected_stderr
,
1471 'commit', '--with-revprop',
1472 '='.join([propname
, propval
]))
1473 # Now swap them: --with-revprop should accept propname as a property
1474 # value; no concept of validity there.
1475 svntest
.actions
.run_and_verify_svn(None, [], [],
1476 'commit', '--with-revprop',
1477 '='.join([propval
, propname
]))
1481 def perms_on_symlink(sbox
):
1482 "issue #2581: propset shouldn't touch symlink perms"
1484 # We can't just run commands on absolute paths in the usual way
1485 # (e.g., os.path.join(sbox.wc_dir, 'newdir')), because for some
1486 # reason, if the symlink points to newdir as an absolute path, the
1487 # bug doesn't reproduce. I have no idea why. Since it does have to
1488 # point to newdir, the only other choice is to have it point to it
1489 # in the same directory, so we have to run the test from inside the
1491 saved_cwd
= os
.getcwd()
1492 os
.chdir(sbox
.wc_dir
)
1494 svntest
.actions
.run_and_verify_svn(None, None, [], 'mkdir', 'newdir')
1495 os
.symlink('newdir', 'symlink')
1496 svntest
.actions
.run_and_verify_svn(None, None, [], 'add', 'symlink')
1497 old_mode
= os
.stat('newdir')[stat
.ST_MODE
]
1498 svntest
.actions
.run_and_verify_svn(None, None, [], 'propdel',
1499 'svn:executable', 'symlink')
1500 new_mode
= os
.stat('newdir')[stat
.ST_MODE
]
1501 if not old_mode
== new_mode
:
1502 # Chmod newdir back, so the test suite can remove this working
1503 # copy when cleaning up later.
1504 os
.chmod('newdir', stat
.S_IRWXU | stat
.S_IRWXG | stat
.S_IRWXO
)
1505 raise svntest
.Failure
1509 # Use a property with a custom namespace, ie 'ns:prop' or 'mycompany:prop'.
1510 def remove_custom_ns_props(sbox
):
1511 "remove a property with a custom namespace"
1515 wc_dir
= sbox
.wc_dir
1517 # Add a property to a file
1518 iota_path
= os
.path
.join(wc_dir
, 'iota')
1519 svntest
.main
.run_svn(None, 'propset', 'ns:cash-sound', 'cha-ching!', iota_path
)
1522 svntest
.main
.run_svn(None,
1523 'ci', '-m', 'logmsg', iota_path
)
1525 # Now, make a backup copy of the working copy
1526 wc_backup
= sbox
.add_wc_path('backup')
1527 svntest
.actions
.duplicate_dir(wc_dir
, wc_backup
)
1529 # Remove the property
1530 svntest
.main
.run_svn(None, 'propdel', 'ns:cash-sound', iota_path
)
1532 # Create expected trees.
1533 expected_output
= svntest
.wc
.State(wc_dir
, {
1534 'iota' : Item(verb
='Sending'),
1536 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1537 expected_status
.tweak('iota', wc_rev
=3, status
=' ')
1539 # Commit the one file.
1540 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
1544 # Create expected trees for the update.
1545 expected_output
= svntest
.wc
.State(wc_backup
, {
1546 'iota' : Item(status
=' U'),
1548 expected_disk
= svntest
.main
.greek_state
.copy()
1549 expected_status
= svntest
.actions
.get_virginal_state(wc_backup
, 3)
1550 expected_status
.tweak('iota', wc_rev
=3, status
=' ')
1552 # Do the update and check the results in three ways... INCLUDING PROPS
1553 svntest
.actions
.run_and_verify_update(wc_backup
,
1557 None, None, None, None, None, 1)
1559 def props_over_time(sbox
):
1560 "property retrieval with peg and operative revs"
1564 wc_dir
= sbox
.wc_dir
1566 # Convenience variables
1567 iota_path
= os
.path
.join(wc_dir
, 'iota')
1568 iota_url
= sbox
.repo_url
+ '/iota'
1570 # Add/tweak a property 'revision' with value revision-committed to a
1571 # file, commit, and then repeat this a few times.
1572 for rev
in range(2, 4):
1573 svntest
.main
.run_svn(None, 'propset', 'revision', str(rev
), iota_path
)
1574 svntest
.main
.run_svn(None, 'ci', '-m', 'logmsg', iota_path
)
1576 # Backdate to r2 so the defaults for URL- vs. WC-style queries are
1578 svntest
.main
.run_svn(None, 'up', '-r2', wc_dir
)
1580 # Now, test propget of the property across many combinations of
1581 # pegrevs, operative revs, and wc-path vs. url style input specs.
1582 # NOTE: We're using 0 in these loops to mean "unspecified".
1583 for path
in iota_path
, iota_url
:
1584 for peg_rev
in range(0, 4):
1585 for op_rev
in range(0, 4):
1586 # Calculate the expected property value. If there is an
1587 # operative rev, we expect the output to match revisions
1588 # there. Else, we'll be looking at the peg-rev value. And if
1589 # neither are supplied, it depends on the path vs. URL
1592 expected
= str(op_rev
)
1597 expected
= str(peg_rev
)
1601 if path
== iota_url
:
1602 expected
= "3" # HEAD
1604 expected
= "2" # BASE
1606 peg_path
= path
+ (peg_rev
!= 0 and '@' + str(peg_rev
) or "")
1608 ### Test 'svn propget'
1609 pget_expected
= expected
1611 pget_expected
= [ pget_expected
+ "\n" ]
1613 svntest
.actions
.run_and_verify_svn(None, pget_expected
, [],
1614 'propget', 'revision', peg_path
,
1617 svntest
.actions
.run_and_verify_svn(None, pget_expected
, [],
1618 'propget', 'revision', peg_path
)
1620 ### Test 'svn proplist -v'
1621 if op_rev
!= 0 or peg_rev
!= 0: # a revision-ful query output URLs
1623 plist_expected
= expected
1625 plist_expected
= [ "Properties on '" + path
+ "':\n",
1626 " revision : " + expected
+ "\n" ]
1629 svntest
.actions
.run_and_verify_svn(None, plist_expected
, [],
1630 'proplist', '-v', peg_path
,
1633 svntest
.actions
.run_and_verify_svn(None, plist_expected
, [],
1634 'proplist', '-v', peg_path
)
1636 ########################################################################
1639 # list all tests here, starting with None:
1646 update_conflict_props
,
1647 commit_conflict_dirprops
,
1648 commit_replacement_props
,
1649 revert_replacement_props
,
1650 inappropriate_props
,
1651 copy_inherits_special_props
,
1652 # If we learn how to write a pre-revprop-change hook for
1653 # non-Posix platforms, we won't have to skip here:
1654 # TODO(epg): Removed Skip as long as we have this XFail
1655 # because I couldn't get Skip and XFail to interact
1656 # properly (it kept showing the failure and then
1657 # printing PASS instead of XFAIL).
1658 #Skip(revprop_change, is_non_posix_and_non_windows_os),
1659 XFail(revprop_change
, svntest
.main
.is_ra_type_dav
),
1660 prop_value_conversions
,
1662 recursive_base_wc_ops
,
1664 removal_schedule_added_props
,
1665 update_props_on_wc_root
,
1666 props_on_replaced_file
,
1668 depthy_url_proplist
,
1670 SkipUnless(perms_on_symlink
, svntest
.main
.is_posix_os
),
1671 remove_custom_ns_props
,
1675 if __name__
== '__main__':
1676 svntest
.main
.run_tests(test_list
)