1#!/usr/bin/env python 2# 3# svnversion_tests.py: testing the 'svnversion' tool. 4# 5# Subversion is a tool for revision control. 6# See http://subversion.apache.org for more information. 7# 8# ==================================================================== 9# Licensed to the Apache Software Foundation (ASF) under one 10# or more contributor license agreements. See the NOTICE file 11# distributed with this work for additional information 12# regarding copyright ownership. The ASF licenses this file 13# to you under the Apache License, Version 2.0 (the 14# "License"); you may not use this file except in compliance 15# with the License. You may obtain a copy of the License at 16# 17# http://www.apache.org/licenses/LICENSE-2.0 18# 19# Unless required by applicable law or agreed to in writing, 20# software distributed under the License is distributed on an 21# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 22# KIND, either express or implied. See the License for the 23# specific language governing permissions and limitations 24# under the License. 25###################################################################### 26 27# General modules 28import os.path 29import tempfile 30 31# Our testing module 32import svntest 33from svntest import wc 34 35# (abbreviation) 36Skip = svntest.testcase.Skip_deco 37SkipUnless = svntest.testcase.SkipUnless_deco 38XFail = svntest.testcase.XFail_deco 39Issues = svntest.testcase.Issues_deco 40Issue = svntest.testcase.Issue_deco 41Wimp = svntest.testcase.Wimp_deco 42Item = svntest.wc.StateItem 43 44#---------------------------------------------------------------------- 45 46def svnversion_test(sbox): 47 "test 'svnversion' on files and directories" 48 sbox.build() 49 wc_dir = sbox.wc_dir 50 repo_url = sbox.repo_url 51 52 # Unmodified 53 svntest.actions.run_and_verify_svnversion(wc_dir, repo_url, 54 [ "1\n" ], []) 55 56 # Unmodified, whole wc switched 57 svntest.actions.run_and_verify_svnversion(wc_dir, "some/other/url", 58 [ "1S\n" ], []) 59 60 mu_path = os.path.join(wc_dir, 'A', 'mu') 61 svntest.main.file_append(mu_path, 'appended mu text') 62 63 # Modified file 64 svntest.actions.run_and_verify_svnversion(mu_path, repo_url + '/A/mu', 65 [ "1M\n" ], []) 66 67 # Text modified 68 svntest.actions.run_and_verify_svnversion(wc_dir, repo_url, 69 [ "1M\n" ], []) 70 71 expected_output = wc.State(wc_dir, {'A/mu' : Item(verb='Sending')}) 72 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 73 expected_status.tweak('A/mu', wc_rev=2) 74 svntest.actions.run_and_verify_commit(wc_dir, 75 expected_output, expected_status) 76 77 # Unmodified, mixed 78 svntest.actions.run_and_verify_svnversion(wc_dir, repo_url, 79 [ "1:2\n" ], []) 80 81 svntest.actions.run_and_verify_svn(None, [], 82 'propset', 'blue', 'azul', 83 os.path.join(wc_dir, 'A', 'mu')) 84 85 # Prop modified, mixed 86 svntest.actions.run_and_verify_svnversion(wc_dir, repo_url, 87 [ "1:2M\n" ], []) 88 89 iota_path = os.path.join(wc_dir, 'iota') 90 gamma_url = sbox.repo_url + '/A/D/gamma' 91 expected_output = wc.State(wc_dir, {'iota' : Item(status='U ')}) 92 expected_status.tweak('A/mu', status=' M') 93 expected_status.tweak('iota', switched='S', wc_rev=2) 94 expected_disk = svntest.main.greek_state.copy() 95 expected_disk.tweak('A/mu', 96 contents=expected_disk.desc['A/mu'].contents 97 + 'appended mu text') 98 expected_disk.tweak('iota', 99 contents=expected_disk.desc['A/D/gamma'].contents) 100 svntest.actions.run_and_verify_switch(wc_dir, iota_path, gamma_url, 101 expected_output, 102 expected_disk, 103 expected_status, 104 [], 105 False, '--ignore-ancestry') 106 107 # Prop modified, mixed, part wc switched 108 svntest.actions.run_and_verify_svnversion(wc_dir, repo_url, 109 [ "1:2MS\n" ], []) 110 111 # Plain (exported) directory that is a direct subdir of a versioned dir 112 Q_path = os.path.join(wc_dir, 'Q') 113 os.mkdir(Q_path) 114 svntest.actions.run_and_verify_svnversion(Q_path, repo_url, 115 [ "Unversioned directory\n" ], []) 116 117 # Plain (exported) directory that is not a direct subdir of a versioned dir 118 R_path = os.path.join(Q_path, 'Q') 119 os.mkdir(R_path) 120 svntest.actions.run_and_verify_svnversion(R_path, repo_url, 121 [ "Unversioned directory\n" ], []) 122 123 # Switched file 124 svntest.actions.run_and_verify_svnversion(iota_path, repo_url + '/iota', 125 [ "2S\n" ], []) 126 127 # Unversioned file 128 kappa_path = os.path.join(wc_dir, 'kappa') 129 svntest.main.file_write(kappa_path, "This is the file 'kappa'.") 130 svntest.actions.run_and_verify_svnversion(kappa_path, repo_url, 131 [ "Unversioned file\n" ], []) 132 133 # Nonexistent file or directory 134 X_path = os.path.join(wc_dir, 'Q', 'X') 135 svntest.actions.run_and_verify_svnversion(X_path, repo_url, 136 None, [ "'%s' doesn't exist\n" 137 % os.path.abspath(X_path) ]) 138 139 # Perform a sparse checkout of under the existing WC, and confirm that 140 # svnversion detects it as a "partial" WC. 141 A_path = os.path.join(wc_dir, "A") 142 A_A_path = os.path.join(A_path, "SPARSE_A") 143 expected_output = wc.State(A_path, { 144 "SPARSE_A" : Item(), 145 "SPARSE_A/mu" : Item(status='A '), 146 }) 147 expected_disk = wc.State("", { 148 "mu" : Item(expected_disk.desc['A/mu'].contents), 149 }) 150 svntest.actions.run_and_verify_checkout(repo_url + "/A", A_A_path, 151 expected_output, expected_disk, 152 [], "--depth=files") 153 154 # Partial (sparse) checkout 155 svntest.actions.run_and_verify_svnversion(A_A_path, 156 repo_url, [ "2SP\n" ], []) 157 158 159#---------------------------------------------------------------------- 160 161@Issue(3816) 162def ignore_externals(sbox): 163 "test 'svnversion' with svn:externals" 164 sbox.build() 165 wc_dir = sbox.wc_dir 166 repo_url = sbox.repo_url 167 168 # Set up an external item 169 C_path = os.path.join(wc_dir, "A", "C") 170 externals_desc = """\ 171ext-dir -r 1 %s/A/D/G 172ext-file -r 1 %s/A/D/H/omega 173""" % (repo_url, repo_url) 174 (fd, tmp_f) = tempfile.mkstemp(dir=wc_dir) 175 svntest.main.file_append(tmp_f, externals_desc) 176 svntest.actions.run_and_verify_svn(None, [], 177 'pset', 178 '-F', tmp_f, 'svn:externals', C_path) 179 os.close(fd) 180 os.remove(tmp_f) 181 expected_output = svntest.wc.State(wc_dir, { 182 'A/C' : Item(verb='Sending'), 183 }) 184 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 185 expected_status.tweak('A/C', wc_rev=2) 186 svntest.actions.run_and_verify_commit(wc_dir, 187 expected_output, 188 expected_status) 189 190 # Update to get it on disk 191 svntest.actions.run_and_verify_svn(None, [], 'up', wc_dir) 192 ext_dir_path = os.path.join(C_path, 'ext-dir') 193 ext_file_path = os.path.join(C_path, 'ext-file') 194 expected_infos = [ 195 { 'Revision' : '^1$' }, 196 { 'Revision' : '^1$' }, 197 ] 198 svntest.actions.run_and_verify_info(expected_infos, ext_dir_path, ext_file_path) 199 200 svntest.actions.run_and_verify_svnversion(wc_dir, repo_url, 201 [ "2\n" ], []) 202 203#---------------------------------------------------------------------- 204 205# Test for issue #3461 'excluded subtrees are not detected by svnversion' 206@Issue(3461) 207def svnversion_with_excluded_subtrees(sbox): 208 "test 'svnversion' with excluded subtrees" 209 sbox.build() 210 wc_dir = sbox.wc_dir 211 repo_url = sbox.repo_url 212 213 B_path = os.path.join(wc_dir, "A", "B") 214 D_path = os.path.join(wc_dir, "A", "D") 215 psi_path = os.path.join(wc_dir, "A", "D", "H", "psi") 216 217 svntest.actions.run_and_verify_svnversion(wc_dir, repo_url, 218 [ "1\n" ], []) 219 220 # Exclude a directory and check that svnversion detects it. 221 svntest.actions.run_and_verify_svn(None, [], 222 'up', '--set-depth', 'exclude', B_path) 223 svntest.actions.run_and_verify_svnversion(wc_dir, repo_url, 224 [ "1P\n" ], []) 225 226 # Exclude a file and check that svnversion detects it. Target the 227 # svnversion command on a subtree that does not contain the excluded 228 # directory to assure we a detecting the switched file. 229 svntest.actions.run_and_verify_svn(None, [], 230 'up', '--set-depth', 'exclude', psi_path) 231 svntest.actions.run_and_verify_svnversion(D_path, repo_url + '/A/D', 232 [ "1P\n" ], []) 233 234def svnversion_with_structural_changes(sbox): 235 "test 'svnversion' with structural changes" 236 sbox.build() 237 wc_dir = sbox.wc_dir 238 repo_url = sbox.repo_url 239 240 # Test a copy 241 iota_path = os.path.join(wc_dir, 'iota') 242 iota_copy_path = os.path.join(wc_dir, 'iota_copy') 243 244 svntest.actions.run_and_verify_svn(None, [], 245 'cp', iota_path, iota_copy_path) 246 247 svntest.actions.run_and_verify_svnversion(iota_copy_path, repo_url + 248 '/iota_copy', 249 [ "Uncommitted local addition, " 250 "copy or move\n" ], 251 []) 252 C_path = os.path.join(wc_dir, 'A', 'C') 253 C_copy_path = os.path.join(wc_dir, 'C_copy') 254 svntest.actions.run_and_verify_svn(None, [], 255 'cp', C_path, C_copy_path) 256 257 svntest.actions.run_and_verify_svnversion(C_copy_path, repo_url + 258 '/C_copy', 259 [ "Uncommitted local addition, " 260 "copy or move\n" ], 261 []) 262 sbox.simple_commit() 263 264 # Test deletion 265 sbox.simple_rm('iota') 266 svntest.actions.run_and_verify_svnversion(sbox.ospath('iota'), 267 repo_url + '/iota', 268 ["1M\n"], 269 [], 270 ) 271 svntest.actions.run_and_verify_svnversion(wc_dir, repo_url, 272 [ "1:2M\n" ], []) 273 274def committed_revisions(sbox): 275 "test 'svnversion --committed'" 276 sbox.build() 277 wc_dir = sbox.wc_dir 278 repo_url = sbox.repo_url 279 280 sbox.simple_copy('iota', 'iota2') 281 sbox.simple_commit() 282 sbox.simple_update() 283 svntest.actions.run_and_verify_svnversion(wc_dir, repo_url, 284 [ "1:2\n" ], [], 285 "--committed") 286 287def non_reposroot_wc(sbox): 288 "test 'svnversion' on a non-repos-root working copy" 289 sbox.build(create_wc=False) 290 wc_dir = sbox.add_wc_path('wc2') 291 repo_url = sbox.repo_url + "/A/B" 292 svntest.main.run_svn(None, 'checkout', repo_url, wc_dir) 293 svntest.actions.run_and_verify_svnversion(wc_dir, repo_url, 294 [ "1\n" ], []) 295 296@Issue(3858) 297def child_switched(sbox): 298 "test svnversion output for switched children" 299 sbox.build()#sbox.build(read_only = True) 300 wc_dir = sbox.wc_dir 301 repo_url = sbox.repo_url 302 303 # Copy A to A2 304 sbox.simple_copy('A', 'branch') 305 sbox.simple_commit() 306 sbox.simple_update() 307 308 ### Target is repos root and WC root. 309 310 # No switches. 311 svntest.actions.run_and_verify_svnversion(wc_dir, None, 312 [ "2\n" ], []) 313 314 # Switch A/B to a sibling. 315 sbox.simple_switch(repo_url + '/A/D', 'A/B') 316 317 # This should detect the switch at A/B. 318 svntest.actions.run_and_verify_svnversion(wc_dir, None, 319 [ "2S\n" ], []) 320 321 ### Target is neither repos root nor WC root. 322 323 # But A/B/G and its children are not switched by itself. 324 svntest.actions.run_and_verify_svnversion(os.path.join(wc_dir, 'A/B/G'), 325 None, [ "2\n" ], []) 326 327 # And A/B isn't switched when you look at it directly. 328 svntest.actions.run_and_verify_svnversion(os.path.join(wc_dir, 'A/B'), 329 None, [ "2\n" ], []) 330 331 # Switch branch/D to ^/A, then switch branch/D/G back to ^/branch/D/G so 332 # the latter is switched relative to its parent but not the WC root. 333 sbox.simple_switch(repo_url + '/A/D', 'branch/D') 334 sbox.simple_switch(repo_url + '/branch/D/G', 'branch/D/G') 335 336 # This should detect the switch at branch/D and branch/D/G. 337 svntest.actions.run_and_verify_svnversion(os.path.join(wc_dir, 'branch'), 338 None, [ "2S\n" ], []) 339 340 # Directly targeting the switched branch/D should still detect the switch 341 # at branch/D/G even though the latter isn't switched against the root of 342 # the working copy. 343 svntest.actions.run_and_verify_svnversion(os.path.join(wc_dir, 'branch', 344 'D'), 345 None, [ "2S\n" ], []) 346 347 # Switch A/B to ^/. 348 sbox.simple_switch(repo_url, 'A/B') 349 svntest.actions.run_and_verify_svnversion(os.path.join(wc_dir), 350 None, [ "2S\n" ], []) 351 svntest.actions.run_and_verify_svnversion(os.path.join(wc_dir, 'A'), 352 None, [ "2S\n" ], []) 353 354 ### Target is repos root but not WC root. 355 356 svntest.actions.run_and_verify_svnversion(os.path.join(wc_dir, 'A', 'B'), 357 None, [ "2\n" ], []) 358 359 # Switch A/B/A/D/G to ^/A/D/H. 360 sbox.simple_switch(repo_url + '/A/D/H', 'A/B/A/D/G') 361 svntest.actions.run_and_verify_svnversion(os.path.join(wc_dir, 'A', 'B'), 362 None, [ "2S\n" ], []) 363 364 ### Target is not repos root but is WC root. 365 366 # Switch the root of the working copy to ^/branch, then switch D/G to 367 # ^A/D/G. 368 sbox.simple_switch(repo_url + '/branch', '.') 369 sbox.simple_switch(repo_url + '/A/D/G', 'D/G') 370 svntest.actions.run_and_verify_svnversion(os.path.join(wc_dir,), 371 None, [ "2S\n" ], []) 372 373 ### Target is neither repos root nor WC root. 374 375 svntest.actions.run_and_verify_svnversion(os.path.join(wc_dir, 'D'), 376 None, [ "2S\n" ], []) 377 svntest.actions.run_and_verify_svnversion(os.path.join(wc_dir, 'D', 'H'), 378 None, [ "2\n" ], []) 379 380######################################################################## 381# Run the tests 382 383 384# list all tests here, starting with None: 385test_list = [ None, 386 svnversion_test, 387 ignore_externals, 388 svnversion_with_excluded_subtrees, 389 svnversion_with_structural_changes, 390 committed_revisions, 391 non_reposroot_wc, 392 child_switched, 393 ] 394 395if __name__ == '__main__': 396 svntest.main.run_tests(test_list) 397 # NOTREACHED 398 399 400### End of file. 401