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,
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_stdout
, actual_stderr
= svntest
.main
.run_svn(None,
765 expected_stdout
= [orig_mime_type
+ '\n']
766 if actual_stdout
!= expected_stdout
:
767 print "svn pg svn:mime-type output does not match expected."
768 print "Expected standard output: ", expected_stdout
, "\n"
769 print "Actual standard output: ", actual_stdout
, "\n"
770 raise svntest
.verify
.SVNUnexpectedOutput
772 # Check the svn:executable value.
773 # The value of the svn:executable property is now always forced to '*'
774 if os
.name
== 'posix':
775 actual_stdout
, actual_stderr
= svntest
.main
.run_svn(None,
779 expected_stdout
= ['*\n']
780 if actual_stdout
!= expected_stdout
:
781 print "svn pg svn:executable output does not match expected."
782 print "Expected standard output: ", expected_stdout
, "\n"
783 print "Actual standard output: ", actual_stdout
, "\n"
784 raise svntest
.verify
.SVNUnexpectedOutput
786 #----------------------------------------------------------------------
788 def revprop_change(sbox
):
789 "set, get, and delete a revprop change"
793 # First test the error when no revprop-change hook exists.
794 svntest
.actions
.run_and_verify_svn(None, None, '.*pre-revprop-change',
795 'propset', '--revprop', '-r', '0',
796 'cash-sound', 'cha-ching!', sbox
.wc_dir
)
798 # Now test error output from revprop-change hook.
799 svntest
.actions
.disable_revprop_changes(sbox
.repo_dir
)
800 svntest
.actions
.run_and_verify_svn(None, None, '.*pre-revprop-change.* 0 jrandom cash-sound A',
801 'propset', '--revprop', '-r', '0',
802 'cash-sound', 'cha-ching!', sbox
.wc_dir
)
804 # Create the revprop-change hook for this test
805 svntest
.actions
.enable_revprop_changes(sbox
.repo_dir
)
807 svntest
.actions
.run_and_verify_svn(None, None, [],
808 'propset', '--revprop', '-r', '0',
809 'cash-sound', 'cha-ching!', sbox
.wc_dir
)
811 svntest
.actions
.run_and_verify_svn(None, None, [],
812 'propget', '--revprop', '-r', '0',
813 'cash-sound', sbox
.wc_dir
)
815 # Now test that blocking the revprop delete.
816 svntest
.actions
.disable_revprop_changes(sbox
.repo_dir
)
817 svntest
.actions
.run_and_verify_svn(None, None, '.*pre-revprop-change.* 0 jrandom cash-sound D',
818 'propdel', '--revprop', '-r', '0',
819 'cash-sound', sbox
.wc_dir
)
821 # Now test actually deleting the revprop.
822 svntest
.actions
.enable_revprop_changes(sbox
.repo_dir
)
823 svntest
.actions
.run_and_verify_svn(None, None, [],
824 'propdel', '--revprop', '-r', '0',
825 'cash-sound', sbox
.wc_dir
)
827 actual_stdout
, actual_stderr
= svntest
.main
.run_svn(None,
833 # The property should have been deleted.
835 for line
in actual_stdout
:
836 if re
.match(regex
, line
):
837 raise svntest
.Failure
840 #----------------------------------------------------------------------
842 def prop_value_conversions(sbox
):
843 "some svn: properties should be converted"
849 A_path
= os
.path
.join(wc_dir
, 'A')
850 B_path
= os
.path
.join(wc_dir
, 'A', 'B')
851 iota_path
= os
.path
.join(wc_dir
, 'iota')
852 lambda_path
= os
.path
.join(wc_dir
, 'A', 'B', 'lambda')
853 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
855 # We'll use a file to set the prop values, so that weird characters
856 # in the props don't confuse the shell.
857 propval_path
= os
.path
.join(wc_dir
, 'propval.tmp')
858 propval_file
= open(propval_path
, 'wb')
860 def set_prop(name
, value
, path
, valf
=propval_file
, valp
=propval_path
,
861 expected_error
=None):
866 svntest
.main
.run_svn(expected_error
, 'propset', '-F', valp
, name
, path
)
868 # Leading and trailing whitespace should be stripped
869 set_prop('svn:mime-type', ' text/html\n\n', iota_path
)
870 set_prop('svn:mime-type', 'text/html', mu_path
)
872 # Leading and trailing whitespace should be stripped
873 set_prop('svn:eol-style', '\nnative\n', iota_path
)
874 set_prop('svn:eol-style', 'native', mu_path
)
876 # A trailing newline should be added
877 set_prop('svn:ignore', '*.o\nfoo.c', A_path
)
878 set_prop('svn:ignore', '*.o\nfoo.c\n', B_path
)
880 # A trailing newline should be added
881 set_prop('svn:externals', 'foo http://foo.com/repos', A_path
)
882 set_prop('svn:externals', 'foo http://foo.com/repos\n', B_path
)
884 # Leading and trailing whitespace should be stripped, but not internal
886 set_prop('svn:keywords', ' Rev Date \n', iota_path
)
887 set_prop('svn:keywords', 'Rev Date', mu_path
)
889 # svn:executable value should be forced to a '*'
890 set_prop('svn:executable', 'foo', iota_path
)
891 set_prop('svn:executable', '*', lambda_path
)
892 for pval
in (' ', '', 'no', 'off', 'false'):
893 set_prop('svn:executable', pval
, mu_path
, propval_file
, propval_path
,
894 ["svn: warning: To turn off the svn:executable property, "
895 "use 'svn propdel';\n",
896 "setting the property to '" + pval
+
897 "' will not turn it off.\n"])
899 # Anything else should be untouched
900 set_prop('svn:some-prop', 'bar', lambda_path
)
901 set_prop('svn:some-prop', ' bar baz', mu_path
)
902 set_prop('svn:some-prop', 'bar\n', iota_path
)
903 set_prop('some-prop', 'bar', lambda_path
)
904 set_prop('some-prop', ' bar baz', mu_path
)
905 set_prop('some-prop', 'bar\n', iota_path
)
907 # Close and remove the prop value file
909 os
.unlink(propval_path
)
911 # NOTE: When writing out multi-line prop values in svn:* props, the
912 # client converts to local encoding and local eoln style.
913 # Therefore, the expected output must contain the right kind of eoln
914 # strings. That's why we use os.linesep in the tests below, not just
915 # plain '\n'. The _last_ \n is also from the client, but it's not
916 # part of the prop value and it doesn't get converted in the pipe.
918 # Check svn:mime-type
919 svntest
.actions
.check_prop('svn:mime-type', iota_path
, ['text/html'])
920 svntest
.actions
.check_prop('svn:mime-type', mu_path
, ['text/html'])
922 # Check svn:eol-style
923 svntest
.actions
.check_prop('svn:eol-style', iota_path
, ['native'])
924 svntest
.actions
.check_prop('svn:eol-style', mu_path
, ['native'])
927 svntest
.actions
.check_prop('svn:ignore', A_path
,
928 ['*.o'+os
.linesep
, 'foo.c'+os
.linesep
])
929 svntest
.actions
.check_prop('svn:ignore', B_path
,
930 ['*.o'+os
.linesep
, 'foo.c'+os
.linesep
])
932 # Check svn:externals
933 svntest
.actions
.check_prop('svn:externals', A_path
,
934 ['foo http://foo.com/repos'+os
.linesep
])
935 svntest
.actions
.check_prop('svn:externals', B_path
,
936 ['foo http://foo.com/repos'+os
.linesep
])
939 svntest
.actions
.check_prop('svn:keywords', iota_path
, ['Rev Date'])
940 svntest
.actions
.check_prop('svn:keywords', mu_path
, ['Rev Date'])
942 # Check svn:executable
943 svntest
.actions
.check_prop('svn:executable', iota_path
, ['*'])
944 svntest
.actions
.check_prop('svn:executable', lambda_path
, ['*'])
945 svntest
.actions
.check_prop('svn:executable', mu_path
, ['*'])
948 svntest
.actions
.check_prop('svn:some-prop', lambda_path
, ['bar'])
949 svntest
.actions
.check_prop('svn:some-prop', mu_path
, [' bar baz'])
950 svntest
.actions
.check_prop('svn:some-prop', iota_path
, ['bar'+os
.linesep
])
951 svntest
.actions
.check_prop('some-prop', lambda_path
, ['bar'])
952 svntest
.actions
.check_prop('some-prop', mu_path
,[' bar baz'])
953 svntest
.actions
.check_prop('some-prop', iota_path
, ['bar\n'])
956 #----------------------------------------------------------------------
958 def binary_props(sbox
):
959 "test binary property support"
965 # Make a backup copy of the working copy
966 wc_backup
= sbox
.add_wc_path('backup')
967 svntest
.actions
.duplicate_dir(wc_dir
, wc_backup
)
969 # Some path convenience vars.
970 A_path
= os
.path
.join(wc_dir
, 'A')
971 B_path
= os
.path
.join(wc_dir
, 'A', 'B')
972 iota_path
= os
.path
.join(wc_dir
, 'iota')
973 lambda_path
= os
.path
.join(wc_dir
, 'A', 'B', 'lambda')
974 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
975 A_path_bak
= os
.path
.join(wc_backup
, 'A')
976 B_path_bak
= os
.path
.join(wc_backup
, 'A', 'B')
977 iota_path_bak
= os
.path
.join(wc_backup
, 'iota')
978 lambda_path_bak
= os
.path
.join(wc_backup
, 'A', 'B', 'lambda')
979 mu_path_bak
= os
.path
.join(wc_backup
, 'A', 'mu')
981 # Property value convenience vars.
982 prop_zb
= "This property has a zer\000 byte."
983 prop_ff
= "This property has a form\014feed."
984 prop_xml
= "This property has an <xml> tag."
985 prop_binx
= "This property has an <xml> tag and a zer\000 byte."
987 # Set some binary properties.
988 propval_path
= os
.path
.join(wc_dir
, 'propval.tmp')
989 propval_file
= open(propval_path
, 'wb')
991 def set_prop(name
, value
, path
, valf
=propval_file
, valp
=propval_path
):
996 svntest
.main
.run_svn(None, 'propset', '-F', valp
, name
, path
)
998 set_prop('prop_zb', prop_zb
, B_path
)
999 set_prop('prop_ff', prop_ff
, iota_path
)
1000 set_prop('prop_xml', prop_xml
, lambda_path
)
1001 set_prop('prop_binx', prop_binx
, mu_path
)
1002 set_prop('prop_binx', prop_binx
, A_path
)
1004 # Create expected output and status trees.
1005 expected_output
= svntest
.wc
.State(wc_dir
, {
1006 'A' : Item(verb
='Sending'),
1007 'A/B' : Item(verb
='Sending'),
1008 'iota' : Item(verb
='Sending'),
1009 'A/B/lambda' : Item(verb
='Sending'),
1010 'A/mu' : Item(verb
='Sending'),
1012 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1013 expected_status
.tweak('A', 'A/B', 'iota', 'A/B/lambda', 'A/mu',
1014 wc_rev
=2, status
=' ')
1016 # Commit the propsets.
1017 svntest
.actions
.run_and_verify_commit(wc_dir
,
1023 # Create expected output, disk, and status trees for an update of
1025 expected_output
= svntest
.wc
.State(wc_backup
, {
1026 'A' : Item(status
=' U'),
1027 'A/B' : Item(status
=' U'),
1028 'iota' : Item(status
=' U'),
1029 'A/B/lambda' : Item(status
=' U'),
1030 'A/mu' : Item(status
=' U'),
1032 expected_disk
= svntest
.main
.greek_state
.copy()
1033 expected_status
= svntest
.actions
.get_virginal_state(wc_backup
, 2)
1035 # Do the update and check the results.
1036 svntest
.actions
.run_and_verify_update(wc_backup
,
1040 None, None, None, None, None, 0)
1042 # Now, check those properties.
1043 svntest
.actions
.check_prop('prop_zb', B_path_bak
, [prop_zb
])
1044 svntest
.actions
.check_prop('prop_ff', iota_path_bak
, [prop_ff
])
1045 svntest
.actions
.check_prop('prop_xml', lambda_path_bak
, [prop_xml
])
1046 svntest
.actions
.check_prop('prop_binx', mu_path_bak
, [prop_binx
])
1047 svntest
.actions
.check_prop('prop_binx', A_path_bak
, [prop_binx
])
1049 #----------------------------------------------------------------------
1051 # Ensure that each line of output contains the corresponding string of
1052 # expected_out, and that errput is empty.
1053 def verify_output(expected_out
, output
, errput
):
1055 print 'Error: stderr:'
1057 raise svntest
.Failure
1061 if ((line
.find(expected_out
[ln
]) == -1) or
1062 (line
!= '' and expected_out
[ln
] == '')):
1063 print 'Error: expected keywords: ', expected_out
1064 print ' actual full output:', output
1065 raise svntest
.Failure
1068 def recursive_base_wc_ops(sbox
):
1069 "recursive property operations in BASE and WC"
1073 wc_dir
= sbox
.wc_dir
1075 # Files with which to test, in alphabetical order
1076 f_add
= os
.path
.join('A', 'added')
1077 f_del
= os
.path
.join('A', 'mu')
1078 f_keep
= os
.path
.join('iota')
1079 fp_add
= os
.path
.join(wc_dir
, f_add
)
1080 fp_del
= os
.path
.join(wc_dir
, f_del
)
1081 fp_keep
= os
.path
.join(wc_dir
, f_keep
)
1084 svntest
.main
.run_svn(None, 'propset', 'p', 'old-del', fp_del
)
1085 svntest
.main
.run_svn(None, 'propset', 'p', 'old-keep',fp_keep
)
1086 svntest
.main
.run_svn(None,
1087 'commit', '-m', '', wc_dir
)
1088 svntest
.main
.file_append(fp_add
, 'blah')
1089 svntest
.main
.run_svn(None, 'add', fp_add
)
1090 svntest
.main
.run_svn(None, 'propset', 'p', 'new-add', fp_add
)
1091 svntest
.main
.run_svn(None, 'propset', 'p', 'new-del', fp_del
)
1092 svntest
.main
.run_svn(None, 'propset', 'p', 'new-keep',fp_keep
)
1093 svntest
.main
.run_svn(None, 'del', '--force', fp_del
)
1095 # Test recursive proplist
1096 output
, errput
= svntest
.main
.run_svn(None, 'proplist', '-R', '-v', wc_dir
,
1098 verify_output([ 'old-del', 'old-keep', 'Properties on ', 'Properties on ' ],
1101 output
, errput
= svntest
.main
.run_svn(None, 'proplist', '-R', '-v', wc_dir
)
1102 verify_output([ 'new-add', 'new-keep', 'Properties on ', 'Properties on ' ],
1105 # Test recursive propget
1106 output
, errput
= svntest
.main
.run_svn(None, 'propget', '-R', 'p', wc_dir
,
1108 verify_output([ 'old-del', 'old-keep' ], output
, errput
)
1110 output
, errput
= svntest
.main
.run_svn(None, 'propget', '-R', 'p', wc_dir
)
1111 verify_output([ 'new-add', 'new-keep' ], output
, errput
)
1113 # Test recursive propset (issue 1794)
1114 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1115 expected_status
.tweak('A/mu', status
='D ', wc_rev
=2)
1116 expected_status
.tweak('iota', status
=' M', wc_rev
=2)
1117 expected_status
.add({
1118 'A/added' : Item(status
='A ', wc_rev
=0),
1120 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
1122 svntest
.actions
.run_and_verify_svn(None, None, [],
1123 'propset', '-R', 'svn:keywords', 'Date',
1124 os
.path
.join(wc_dir
, 'A', 'B'))
1125 expected_status
.tweak('A/B/lambda', 'A/B/E/alpha', 'A/B/E/beta', status
=' M')
1126 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
1128 #----------------------------------------------------------------------
1130 def url_props_ops(sbox
):
1131 "property operations on an URL"
1135 wc_dir
= sbox
.wc_dir
1138 propval1
= 'propval1 is foo'
1140 propval2
= 'propval2'
1142 iota_path
= os
.path
.join(sbox
.wc_dir
, 'iota')
1143 iota_url
= sbox
.repo_url
+ '/iota'
1144 A_path
= os
.path
.join(sbox
.wc_dir
, 'A')
1145 A_url
= sbox
.repo_url
+ '/A'
1147 # Add a couple of properties
1148 svntest
.main
.run_svn(None, 'propset', prop1
, propval1
, iota_path
)
1149 svntest
.main
.run_svn(None, 'propset', prop1
, propval1
, A_path
)
1152 svntest
.main
.run_svn(None,
1153 'ci', '-m', 'logmsg', sbox
.wc_dir
)
1155 # Add a few more properties
1156 svntest
.main
.run_svn(None, 'propset', prop2
, propval2
, iota_path
)
1157 svntest
.main
.run_svn(None, 'propset', prop2
, propval2
, A_path
)
1160 svntest
.main
.run_svn(None,
1161 'ci', '-m', 'logmsg', sbox
.wc_dir
)
1164 svntest
.actions
.run_and_verify_svn(None, [ propval1
+ '\n' ], [],
1165 'propget', prop1
, iota_url
)
1166 svntest
.actions
.run_and_verify_svn(None, [ propval1
+ '\n' ], [],
1167 'propget', prop1
, A_url
)
1169 # Test normal proplist
1170 output
, errput
= svntest
.main
.run_svn(None,
1171 'proplist', iota_url
)
1172 verify_output([ prop1
, prop2
, 'Properties on ' ],
1175 output
, errput
= svntest
.main
.run_svn(None,
1177 verify_output([ prop1
, prop2
, 'Properties on ' ],
1180 # Test verbose proplist
1181 output
, errput
= svntest
.main
.run_svn(None,
1182 'proplist', '-v', iota_url
)
1183 verify_output([ prop1
+ ' : ' + propval1
, prop2
+ ' : ' + propval2
,
1184 'Properties on ' ], output
, errput
)
1186 output
, errput
= svntest
.main
.run_svn(None,
1187 'proplist', '-v', A_url
)
1188 verify_output([ prop1
+ ' : ' + propval1
, prop2
+ ' : ' + propval2
,
1189 'Properties on ' ], output
, errput
)
1192 svntest
.main
.use_editor('foo_to_bar')
1193 propval1
= propval1
.replace('foo', 'bar')
1194 svntest
.main
.run_svn(None,
1195 'propedit', prop1
, '-m', 'editlog', iota_url
)
1196 svntest
.main
.run_svn(None,
1197 'propedit', prop1
, '-m', 'editlog', A_url
)
1198 svntest
.actions
.run_and_verify_svn(None, [ propval1
+ '\n' ], [],
1199 'propget', prop1
, iota_url
)
1200 svntest
.actions
.run_and_verify_svn(None, [ propval1
+ '\n' ], [],
1201 'propget', prop1
, A_url
)
1203 # Edit without actually changing the property
1204 svntest
.main
.use_editor('identity')
1205 svntest
.actions
.run_and_verify_svn(None,
1206 "No changes to property '%s' on '.*'"
1209 'propedit', prop1
, '-m', 'nocommit',
1214 #----------------------------------------------------------------------
1215 def removal_schedule_added_props(sbox
):
1216 "removal of schedule added file with properties"
1220 wc_dir
= sbox
.wc_dir
1221 newfile_path
= os
.path
.join(wc_dir
, 'newfile')
1222 file_add_output
= ["A " + newfile_path
+ "\n"]
1223 propset_output
= ["property 'newprop' set on '" + newfile_path
+ "'\n"]
1224 file_rm_output
= ["D " + newfile_path
+ "\n"]
1226 "Properties on '" + newfile_path
+ "':\n",
1227 " newprop : newvalue\n",
1230 # create new fs file
1231 open(newfile_path
, 'w').close()
1232 # Add it and set a property
1233 svntest
.actions
.run_and_verify_svn(None, file_add_output
, [], 'add', newfile_path
)
1234 svntest
.actions
.run_and_verify_svn(None, propset_output
, [], 'propset',
1235 'newprop', 'newvalue', newfile_path
)
1236 svntest
.actions
.run_and_verify_svn(None, propls_output
, [],
1237 'proplist', '-v', newfile_path
)
1239 svntest
.actions
.run_and_verify_svn(None, file_rm_output
, [],
1240 'rm', '--force', newfile_path
)
1241 # recreate the file and add it again
1242 open(newfile_path
, 'w').close()
1243 svntest
.actions
.run_and_verify_svn(None, file_add_output
, [], 'add', newfile_path
)
1245 # Now there should be NO properties leftover...
1246 svntest
.actions
.run_and_verify_svn(None, [], [],
1247 'proplist', '-v', newfile_path
)
1249 #----------------------------------------------------------------------
1251 def update_props_on_wc_root(sbox
):
1252 "receive properties on the wc root via update"
1256 wc_dir
= sbox
.wc_dir
1258 # Make a backup copy of the working copy
1259 wc_backup
= sbox
.add_wc_path('backup')
1260 svntest
.actions
.duplicate_dir(wc_dir
, wc_backup
)
1262 # Add a property to the root folder
1263 svntest
.main
.run_svn(None, 'propset', 'red', 'rojo', wc_dir
)
1265 # Create expected output tree.
1266 expected_output
= svntest
.wc
.State(wc_dir
, {
1267 '' : Item(verb
='Sending')
1270 # Created expected status tree.
1271 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1272 expected_status
.tweak('', wc_rev
=2, status
=' ')
1274 # Commit the working copy
1275 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
1279 # Create expected output tree for an update of the wc_backup.
1280 expected_output
= svntest
.wc
.State(wc_backup
, {
1281 '' : Item(status
=' U'),
1283 # Create expected disk tree for the update.
1284 expected_disk
= svntest
.main
.greek_state
.copy()
1286 '' : Item(props
= {'red' : 'rojo'}),
1288 # Create expected status tree for the update.
1289 expected_status
= svntest
.actions
.get_virginal_state(wc_backup
, 2)
1290 expected_status
.tweak('', status
=' ')
1292 # Do the update and check the results in three ways... INCLUDING PROPS
1293 svntest
.actions
.run_and_verify_update(wc_backup
,
1297 None, None, None, None, None, 1)
1299 # test for issue 2743
1300 def props_on_replaced_file(sbox
):
1301 """test properties on replaced files"""
1304 wc_dir
= sbox
.wc_dir
1306 # Add some properties to iota
1307 iota_path
= os
.path
.join(wc_dir
, "iota")
1308 svntest
.main
.run_svn(None, 'propset', 'red', 'rojo', iota_path
)
1309 svntest
.main
.run_svn(None, 'propset', 'blue', 'lagoon', iota_path
)
1310 svntest
.main
.run_svn(None,
1311 'ci', '-m', 'log message', wc_dir
)
1314 svntest
.main
.run_svn(None, 'rm', iota_path
)
1315 svntest
.main
.file_append(iota_path
, "some mod")
1316 svntest
.main
.run_svn(None, 'add', iota_path
)
1318 # check that the replaced file has no properties
1319 expected_disk
= svntest
.main
.greek_state
.copy()
1320 expected_disk
.tweak('iota', contents
="some mod")
1321 actual_disk_tree
= svntest
.tree
.build_tree_from_wc(wc_dir
, 1)
1322 svntest
.tree
.compare_trees("disk", actual_disk_tree
,
1323 expected_disk
.old_tree())
1325 # now add a new property to iota
1326 svntest
.main
.run_svn(None, 'propset', 'red', 'mojo', iota_path
)
1327 svntest
.main
.run_svn(None, 'propset', 'groovy', 'baby', iota_path
)
1329 # What we expect the disk tree to look like:
1330 expected_disk
.tweak('iota', props
={'red' : 'mojo', 'groovy' : 'baby'})
1331 actual_disk_tree
= svntest
.tree
.build_tree_from_wc(wc_dir
, 1)
1332 svntest
.tree
.compare_trees("disk", actual_disk_tree
,
1333 expected_disk
.old_tree())
1335 #----------------------------------------------------------------------
1337 def depthy_wc_proplist(sbox
):
1338 """test proplist at various depths on a wc"""
1341 wc_dir
= sbox
.wc_dir
1343 A_path
= os
.path
.join(wc_dir
, 'A')
1344 iota_path
= os
.path
.join(wc_dir
, 'iota')
1345 mu_path
= os
.path
.join(A_path
, 'mu')
1347 # Set up properties.
1348 svntest
.main
.run_svn(None, 'propset', 'p', 'prop1', wc_dir
)
1349 svntest
.main
.run_svn(None, 'propset', 'p', 'prop2', iota_path
)
1350 svntest
.main
.run_svn(None, 'propset', 'p', 'prop3', A_path
)
1351 svntest
.main
.run_svn(None, 'propset', 'p', 'prop4', mu_path
)
1354 svntest
.main
.run_svn(None,
1355 'ci', '-m', 'log message', wc_dir
)
1357 # Test depth-empty proplist.
1358 output
, errput
= svntest
.main
.run_svn(None, 'proplist', '--depth', 'empty',
1360 verify_output([ 'prop1', 'Properties on ' ],
1363 # Test depth-files proplist.
1364 output
, errput
= svntest
.main
.run_svn(None, 'proplist', '--depth', 'files',
1366 verify_output([ 'prop1', 'prop2', 'Properties on ', 'Properties on ' ],
1369 # Test depth-immediates proplist.
1370 output
, errput
= svntest
.main
.run_svn(None, 'proplist', '--depth',
1371 'immediates', '-v', wc_dir
)
1372 verify_output([ 'prop1', 'prop2', 'prop3' ] + ['Properties on '] * 3,
1375 # Test depth-infinity proplist.
1376 output
, errput
= svntest
.main
.run_svn(None, 'proplist', '--depth',
1377 'infinity', '-v', wc_dir
)
1378 verify_output([ 'prop1', 'prop2', 'prop3', 'prop4' ] + ['Properties on '] * 4,
1381 #----------------------------------------------------------------------
1383 def depthy_url_proplist(sbox
):
1384 """test proplist at various depths on a url"""
1387 repo_url
= sbox
.repo_url
1388 wc_dir
= sbox
.wc_dir
1390 A_path
= os
.path
.join(wc_dir
, 'A')
1391 iota_path
= os
.path
.join(wc_dir
, 'iota')
1392 mu_path
= os
.path
.join(A_path
, 'mu')
1394 # Set up properties.
1395 svntest
.main
.run_svn(None, 'propset', 'p', 'prop1', wc_dir
)
1396 svntest
.main
.run_svn(None, 'propset', 'p', 'prop2', iota_path
)
1397 svntest
.main
.run_svn(None, 'propset', 'p', 'prop3', A_path
)
1398 svntest
.main
.run_svn(None, 'propset', 'p', 'prop4', mu_path
)
1400 # Test depth-empty proplist.
1401 output
, errput
= svntest
.main
.run_svn(None,
1402 'proplist', '--depth', 'empty',
1404 verify_output([ 'prop1', 'Properties on ' ],
1407 # Test depth-files proplist.
1408 output
, errput
= svntest
.main
.run_svn(None,
1409 'proplist', '--depth', 'files',
1411 verify_output([ 'prop1', 'prop2', 'Properties on ', 'Properties on ' ],
1414 # Test depth-immediates proplist.
1415 output
, errput
= svntest
.main
.run_svn(None,
1416 'proplist', '--depth',
1417 'immediates', '-v', repo_url
)
1418 verify_output([ 'prop1', 'prop2', 'prop3' ] + ['Properties on '] * 3,
1421 # Test depth-infinity proplist.
1422 output
, errput
= svntest
.main
.run_svn(None,
1423 'proplist', '--depth',
1424 'infinity', '-v', repo_url
)
1425 verify_output([ 'prop1', 'prop2', 'prop3', 'prop4' ] + ['Properties on '] * 4,
1428 #----------------------------------------------------------------------
1430 def invalid_propnames(sbox
):
1431 """test prop* handle invalid property names"""
1434 repo_url
= sbox
.repo_url
1435 wc_dir
= sbox
.wc_dir
1442 expected_stdout
= ["property '%s' deleted from '.'.\n" % (propname
,)]
1443 svntest
.actions
.run_and_verify_svn(None, expected_stdout
, [],
1444 'propdel', propname
)
1445 expected_stderr
= (".*'%s' is not a valid Subversion"
1446 ' property name' % (propname
,))
1447 svntest
.actions
.run_and_verify_svn(None, None, expected_stderr
,
1448 'propedit', propname
)
1449 svntest
.actions
.run_and_verify_svn(None, None, expected_stderr
,
1450 'propget', propname
)
1451 svntest
.actions
.run_and_verify_svn(None, None, expected_stderr
,
1452 'propset', propname
, propval
)
1454 svntest
.actions
.run_and_verify_svn(None, None, expected_stderr
,
1455 'commit', '--with-revprop',
1456 '='.join([propname
, propval
]))
1457 # Now swap them: --with-revprop should accept propname as a property
1458 # value; no concept of validity there.
1459 svntest
.actions
.run_and_verify_svn(None, [], [],
1460 'commit', '--with-revprop',
1461 '='.join([propval
, propname
]))
1465 def perms_on_symlink(sbox
):
1466 "issue #2581: propset shouldn't touch symlink perms"
1468 # We can't just run commands on absolute paths in the usual way
1469 # (e.g., os.path.join(sbox.wc_dir, 'newdir')), because for some
1470 # reason, if the symlink points to newdir as an absolute path, the
1471 # bug doesn't reproduce. I have no idea why. Since it does have to
1472 # point to newdir, the only other choice is to have it point to it
1473 # in the same directory, so we have to run the test from inside the
1475 saved_cwd
= os
.getcwd()
1476 os
.chdir(sbox
.wc_dir
)
1478 svntest
.actions
.run_and_verify_svn(None, None, [], 'mkdir', 'newdir')
1479 os
.symlink('newdir', 'symlink')
1480 svntest
.actions
.run_and_verify_svn(None, None, [], 'add', 'symlink')
1481 old_mode
= os
.stat('newdir')[stat
.ST_MODE
]
1482 svntest
.actions
.run_and_verify_svn(None, None, [], 'propdel',
1483 'svn:executable', 'symlink')
1484 new_mode
= os
.stat('newdir')[stat
.ST_MODE
]
1485 if not old_mode
== new_mode
:
1486 # Chmod newdir back, so the test suite can remove this working
1487 # copy when cleaning up later.
1488 os
.chmod('newdir', stat
.S_IRWXU | stat
.S_IRWXG | stat
.S_IRWXO
)
1489 raise svntest
.Failure
1493 # Use a property with a custom namespace, ie 'ns:prop' or 'mycompany:prop'.
1494 def remove_custom_ns_props(sbox
):
1495 "remove a property with a custom namespace"
1499 wc_dir
= sbox
.wc_dir
1501 # Add a property to a file
1502 iota_path
= os
.path
.join(wc_dir
, 'iota')
1503 svntest
.main
.run_svn(None, 'propset', 'ns:cash-sound', 'cha-ching!', iota_path
)
1506 svntest
.main
.run_svn(None,
1507 'ci', '-m', 'logmsg', iota_path
)
1509 # Now, make a backup copy of the working copy
1510 wc_backup
= sbox
.add_wc_path('backup')
1511 svntest
.actions
.duplicate_dir(wc_dir
, wc_backup
)
1513 # Remove the property
1514 svntest
.main
.run_svn(None, 'propdel', 'ns:cash-sound', iota_path
)
1516 # Create expected trees.
1517 expected_output
= svntest
.wc
.State(wc_dir
, {
1518 'iota' : Item(verb
='Sending'),
1520 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1521 expected_status
.tweak('iota', wc_rev
=3, status
=' ')
1523 # Commit the one file.
1524 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
1528 # Create expected trees for the update.
1529 expected_output
= svntest
.wc
.State(wc_backup
, {
1530 'iota' : Item(status
=' U'),
1532 expected_disk
= svntest
.main
.greek_state
.copy()
1533 expected_status
= svntest
.actions
.get_virginal_state(wc_backup
, 3)
1534 expected_status
.tweak('iota', wc_rev
=3, status
=' ')
1536 # Do the update and check the results in three ways... INCLUDING PROPS
1537 svntest
.actions
.run_and_verify_update(wc_backup
,
1541 None, None, None, None, None, 1)
1543 def props_over_time(sbox
):
1544 "property retrieval with peg and operative revs"
1548 wc_dir
= sbox
.wc_dir
1550 # Convenience variables
1551 iota_path
= os
.path
.join(wc_dir
, 'iota')
1552 iota_url
= sbox
.repo_url
+ '/iota'
1554 # Add/tweak a property 'revision' with value revision-committed to a
1555 # file, commit, and then repeat this a few times.
1556 for rev
in range(2, 4):
1557 svntest
.main
.run_svn(None, 'propset', 'revision', str(rev
), iota_path
)
1558 svntest
.main
.run_svn(None, 'ci', '-m', 'logmsg', iota_path
)
1560 # Backdate to r2 so the defaults for URL- vs. WC-style queries are
1562 svntest
.main
.run_svn(None, 'up', '-r2', wc_dir
)
1564 # Now, test propget of the property across many combinations of
1565 # pegrevs, operative revs, and wc-path vs. url style input specs.
1566 # NOTE: We're using 0 in these loops to mean "unspecified".
1567 for path
in iota_path
, iota_url
:
1568 for peg_rev
in range(0, 4):
1569 for op_rev
in range(0, 4):
1570 # Calculate the expected property value. If there is an
1571 # operative rev, we expect the output to match revisions
1572 # there. Else, we'll be looking at the peg-rev value. And if
1573 # neither are supplied, it depends on the path vs. URL
1576 expected
= str(op_rev
)
1581 expected
= str(peg_rev
)
1585 if path
== iota_url
:
1586 expected
= "3" # HEAD
1588 expected
= "2" # BASE
1590 peg_path
= path
+ (peg_rev
!= 0 and '@' + str(peg_rev
) or "")
1592 ### Test 'svn propget'
1593 pget_expected
= expected
1595 pget_expected
= [ pget_expected
+ "\n" ]
1597 svntest
.actions
.run_and_verify_svn(None, pget_expected
, [],
1598 'propget', 'revision', peg_path
,
1601 svntest
.actions
.run_and_verify_svn(None, pget_expected
, [],
1602 'propget', 'revision', peg_path
)
1604 ### Test 'svn proplist -v'
1605 if op_rev
!= 0 or peg_rev
!= 0: # a revision-ful query output URLs
1607 plist_expected
= expected
1609 plist_expected
= [ "Properties on '" + path
+ "':\n",
1610 " revision : " + expected
+ "\n" ]
1613 svntest
.actions
.run_and_verify_svn(None, plist_expected
, [],
1614 'proplist', '-v', peg_path
,
1617 svntest
.actions
.run_and_verify_svn(None, plist_expected
, [],
1618 'proplist', '-v', peg_path
)
1620 ########################################################################
1623 # list all tests here, starting with None:
1630 update_conflict_props
,
1631 commit_conflict_dirprops
,
1632 commit_replacement_props
,
1633 revert_replacement_props
,
1634 inappropriate_props
,
1635 copy_inherits_special_props
,
1636 # If we learn how to write a pre-revprop-change hook for
1637 # non-Posix platforms, we won't have to skip here:
1638 # TODO(epg): Removed Skip as long as we have this XFail
1639 # because I couldn't get Skip and XFail to interact
1640 # properly (it kept showing the failure and then
1641 # printing PASS instead of XFAIL).
1642 #Skip(revprop_change, is_non_posix_and_non_windows_os),
1643 XFail(revprop_change
, svntest
.main
.is_ra_type_dav
),
1644 prop_value_conversions
,
1646 recursive_base_wc_ops
,
1648 removal_schedule_added_props
,
1649 update_props_on_wc_root
,
1650 props_on_replaced_file
,
1652 depthy_url_proplist
,
1654 SkipUnless(perms_on_symlink
, svntest
.main
.is_posix_os
),
1655 remove_custom_ns_props
,
1659 if __name__
== '__main__':
1660 svntest
.main
.run_tests(test_list
)