1 /** 2 * @copyright 3 * ==================================================================== 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance 10 * with the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, 15 * software distributed under the License is distributed on an 16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 * KIND, either express or implied. See the License for the 18 * specific language governing permissions and limitations 19 * under the License. 20 * ==================================================================== 21 * @endcopyright 22 */ 23 package org.tigris.subversion.javahl; 24 25 import java.io.File; 26 import java.io.FileOutputStream; 27 import java.io.FileNotFoundException; 28 import java.io.FileReader; 29 import java.io.IOException; 30 import java.io.PrintWriter; 31 import java.io.ByteArrayOutputStream; 32 import java.text.ParseException; 33 import java.util.Arrays; 34 import java.util.ArrayList; 35 import java.util.HashMap; 36 import java.util.Iterator; 37 import java.util.List; 38 import java.util.Set; 39 import java.util.Map; 40 41 42 /** 43 * Tests the basic functionality of javahl binding (inspired by the 44 * tests in subversion/tests/cmdline/basic_tests.py). 45 */ 46 public class BasicTests extends SVNTests 47 { 48 /** 49 * Base name of all our tests. 50 */ 51 public final static String testName = "basic_test"; 52 BasicTests()53 public BasicTests() 54 { 55 init(); 56 } 57 BasicTests(String name)58 public BasicTests(String name) 59 { 60 super(name); 61 init(); 62 } 63 64 /** 65 * Initialize the testBaseName and the testCounter, if this is the 66 * first test of this class. 67 */ init()68 private void init() 69 { 70 if (!testName.equals(testBaseName)) 71 { 72 testCounter = 0; 73 testBaseName = testName; 74 } 75 } 76 77 /** 78 * Test LogDate(). 79 * @throws Throwable 80 */ testLogDate()81 public void testLogDate() throws Throwable 82 { 83 String goodDate = "2007-10-04T03:00:52.134992Z"; 84 String badDate = "2008-01-14"; 85 LogDate logDate; 86 87 try 88 { 89 logDate = new LogDate(goodDate); 90 assertEquals(1191466852134992L, logDate.getTimeMicros()); 91 } catch (ParseException e) { 92 fail("Failed to parse date " + goodDate); 93 } 94 95 try 96 { 97 logDate = new LogDate(badDate); 98 fail("Failed to throw exception on bad date " + badDate); 99 } catch (ParseException e) { 100 } 101 } 102 103 /** 104 * Test SVNClient.getVersion(). 105 * @throws Throwable 106 */ testVersion()107 public void testVersion() throws Throwable 108 { 109 try 110 { 111 Version version = client.getVersion(); 112 String versionString = version.toString(); 113 if (versionString == null || versionString.trim().length() == 0) 114 { 115 throw new Exception("Version string empty"); 116 } 117 } 118 catch (Exception e) 119 { 120 fail("Version should always be available unless the " + 121 "native libraries failed to initialize: " + e); 122 } 123 } 124 125 /** 126 * Tests Subversion path validation. 127 */ testPathValidation()128 public void testPathValidation() throws Throwable 129 { 130 // Rather than segfaulting, JavaHL considers null an invalid path. 131 assertFalse("Path validation produced false-positive for null path", 132 Path.isValid(null)); 133 134 String path = "valid-path"; 135 assertTrue("Validation check of valid path '" + path + 136 "' should succeed", Path.isValid(path)); 137 138 // File names cannot contain control characters. 139 path = "invalid-\u0001-path"; 140 assertFalse("Validation check of invalid path '" + path + 141 "' (which contains control characters) should fail", 142 Path.isValid(path)); 143 } 144 145 /** 146 * Tests Subversion path as URL predicate. 147 */ testPathIsURL()148 public void testPathIsURL() throws Throwable 149 { 150 try 151 { 152 Path.isURL(null); 153 fail("A null path should raise an exception"); 154 } 155 catch (IllegalArgumentException expected) 156 { 157 } 158 159 // Subversion "paths" which aren't URLs. 160 String[] paths = { "/path", "c:\\path" }; 161 for (int i = 0; i < paths.length; i++) 162 { 163 assertFalse("'" + paths[i] + "' should not be considered a URL", 164 Path.isURL(paths[i])); 165 } 166 167 // Subversion "paths" which are URLs. 168 paths = new String[] { "http://example.com", "svn://example.com", 169 "svn+ssh://example.com", "file:///src/svn/" }; 170 for (int i = 0; i < paths.length; i++) 171 { 172 assertTrue("'" + paths[i] + "' should be considered a URL", 173 Path.isURL(paths[i])); 174 } 175 } 176 177 /** 178 * Tests Mergeinfo and RevisionRange classes. 179 * @since 1.5 180 */ testMergeinfoParser()181 public void testMergeinfoParser() throws Throwable 182 { 183 String mergeInfoPropertyValue = 184 "/trunk:1-300,305,307,400-405\n/branches/branch:308-400"; 185 Mergeinfo info = new Mergeinfo(mergeInfoPropertyValue); 186 String[] paths = info.getPaths(); 187 assertEquals(2, paths.length); 188 RevisionRange[] trunkRange = info.getRevisionRange("/trunk"); 189 assertEquals(4, trunkRange.length); 190 assertEquals("1-300", trunkRange[0].toString()); 191 assertEquals("305", trunkRange[1].toString()); 192 assertEquals("307", trunkRange[2].toString()); 193 assertEquals("400-405", trunkRange[3].toString()); 194 RevisionRange[] branchRange = 195 info.getRevisionRange("/branches/branch"); 196 assertEquals(1, branchRange.length); 197 } 198 199 /** 200 * Test the basic SVNClient.status functionality. 201 * @throws Throwable 202 */ testBasicStatus()203 public void testBasicStatus() throws Throwable 204 { 205 // build the test setup 206 OneTest thisTest = new OneTest(); 207 208 // check the status of the working copy 209 thisTest.checkStatus(); 210 211 // Test status of non-existent file 212 File fileC = new File(thisTest.getWorkingCopy() + "/A", "foo.c"); 213 214 Status s = client.singleStatus(fileToSVNPath(fileC, false), false); 215 if (s != null) 216 { 217 if (s.hasTreeConflict() 218 || s.getTextStatus() != Status.Kind.none 219 || s.getPropStatus() != Status.Kind.none 220 || s.getRepositoryTextStatus() != Status.Kind.none 221 || s.getRepositoryPropStatus() != Status.Kind.none) 222 { 223 fail("File foo.c should not return a status."); 224 } 225 } 226 227 } 228 229 /** 230 * Test the "out of date" info from {@link 231 * org.tigris.subversion.javahl.SVNClient#status()}. 232 * 233 * @throws SubversionException 234 * @throws IOException 235 */ testOODStatus()236 public void testOODStatus() throws SubversionException, IOException 237 { 238 // build the test setup 239 OneTest thisTest = new OneTest(); 240 241 // Make a whole slew of changes to a WC: 242 // 243 // (root) r7 - prop change 244 // iota 245 // A 246 // |__mu 247 // | 248 // |__B 249 // | |__lambda 250 // | | 251 // | |__E r12 - deleted 252 // | | |__alpha 253 // | | |__beta 254 // | | 255 // | |__F r9 - prop change 256 // | |__I r6 - added dir 257 // | 258 // |__C r5 - deleted 259 // | 260 // |__D 261 // |__gamma 262 // | 263 // |__G 264 // | |__pi r3 - deleted 265 // | |__rho r2 - modify text 266 // | |__tau r4 - modify text 267 // | 268 // |__H 269 // |__chi r10-11 replaced with file 270 // |__psi r13-14 replaced with dir 271 // |__omega 272 // |__nu r8 - added file 273 File file, dir; 274 PrintWriter pw; 275 Status status; 276 long rev; // Resulting rev from co or update 277 long expectedRev = 2; // Keeps track of the latest rev committed 278 279 // ----- r2: modify file A/D/G/rho -------------------------- 280 file = new File(thisTest.getWorkingCopy(), "A/D/G/rho"); 281 pw = new PrintWriter(new FileOutputStream(file, true)); 282 pw.print("modification to rho"); 283 pw.close(); 284 addExpectedCommitItem(thisTest.getWCPath(), 285 thisTest.getUrl(), "A/D/G/rho", NodeKind.file, 286 CommitItemStateFlags.TextMods); 287 assertEquals("wrong revision number from commit", 288 rev = client.commit(new String[]{thisTest.getWCPath()}, 289 "log msg", true), expectedRev++); 290 thisTest.getWc().setItemWorkingCopyRevision("A/D/G/rho", rev); 291 thisTest.getWc().setItemContent("A/D/G/rho", 292 thisTest.getWc().getItemContent("A/D/G/rho") 293 + "modification to rho"); 294 295 status = client.singleStatus(thisTest.getWCPath() + "/A/D/G/rho", 296 false); 297 long rhoCommitDate = status.getLastChangedDate().getTime(); 298 long rhoCommitRev = rev; 299 String rhoAuthor = status.getLastCommitAuthor(); 300 301 // ----- r3: delete file A/D/G/pi --------------------------- 302 client.remove(new String[] {thisTest.getWCPath() + "/A/D/G/pi"}, null, 303 false); 304 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 305 "A/D/G/pi", NodeKind.file, 306 CommitItemStateFlags.Delete); 307 assertEquals("wrong revision number from commit", 308 rev = client.commit(new String[] {thisTest.getWCPath()}, 309 "log msg", true), 310 expectedRev++); 311 thisTest.getWc().removeItem("A/D/G/pi"); 312 313 thisTest.getWc().setItemWorkingCopyRevision("A/D/G", rev); 314 assertEquals("wrong revision from update", 315 client.update(thisTest.getWCPath() + "/A/D/G", 316 null, true), 317 rev); 318 long GCommitRev = rev; 319 320 // ----- r4: modify file A/D/G/tau -------------------------- 321 file = new File(thisTest.getWorkingCopy(), "A/D/G/tau"); 322 pw = new PrintWriter(new FileOutputStream(file, true)); 323 pw.print("modification to tau"); 324 pw.close(); 325 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 326 "A/D/G/tau",NodeKind.file, 327 CommitItemStateFlags.TextMods); 328 assertEquals("wrong revision number from commit", 329 rev = client.commit(new String[] {thisTest.getWCPath()}, 330 "log msg", true), 331 expectedRev++); 332 thisTest.getWc().setItemWorkingCopyRevision("A/D/G/tau", rev); 333 thisTest.getWc().setItemContent("A/D/G/tau", 334 thisTest.getWc().getItemContent("A/D/G/tau") 335 + "modification to tau"); 336 status = client.singleStatus(thisTest.getWCPath() + "/A/D/G/tau", 337 false); 338 long tauCommitDate = status.getLastChangedDate().getTime(); 339 long tauCommitRev = rev; 340 String tauAuthor = status.getLastCommitAuthor(); 341 342 // ----- r5: delete dir with no children A/C --------------- 343 client.remove(new String[] {thisTest.getWCPath() + "/A/C"}, null, 344 false); 345 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 346 "A/C", NodeKind.dir, 347 CommitItemStateFlags.Delete); 348 assertEquals("wrong revision number from commit", 349 rev = client.commit(new String[] {thisTest.getWCPath()}, 350 "log msg", true), 351 expectedRev++); 352 thisTest.getWc().removeItem("A/C"); 353 long CCommitRev = rev; 354 355 // ----- r6: Add dir A/B/I ---------------------------------- 356 dir = new File(thisTest.getWorkingCopy(), "A/B/I"); 357 dir.mkdir(); 358 359 client.add(dir.getAbsolutePath(), true); 360 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 361 "A/B/I", NodeKind.dir, CommitItemStateFlags.Add); 362 assertEquals("wrong revision number from commit", 363 rev = client.commit(new String[] {thisTest.getWCPath()}, 364 "log msg", true), 365 expectedRev++); 366 thisTest.getWc().addItem("A/B/I", null); 367 status = client.singleStatus(thisTest.getWCPath() + "/A/B/I", false); 368 long ICommitDate = status.getLastChangedDate().getTime(); 369 long ICommitRev = rev; 370 String IAuthor = status.getLastCommitAuthor(); 371 372 // ----- r7: Update then commit prop change on root dir ----- 373 thisTest.getWc().setRevision(rev); 374 assertEquals("wrong revision from update", 375 client.update(thisTest.getWCPath(), null, true), rev); 376 thisTest.checkStatus(); 377 client.propertySet(thisTest.getWCPath(), "propname", "propval", false); 378 thisTest.getWc().setItemPropStatus("", Status.Kind.modified); 379 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), null, 380 NodeKind.dir, CommitItemStateFlags.PropMods); 381 assertEquals("wrong revision number from commit", 382 rev = client.commit(new String[] {thisTest.getWCPath()}, 383 "log msg", true), 384 expectedRev++); 385 thisTest.getWc().setItemWorkingCopyRevision("", rev); 386 thisTest.getWc().setItemPropStatus("", Status.Kind.normal); 387 388 // ----- r8: Add a file A/D/H/nu ---------------------------- 389 file = new File(thisTest.getWorkingCopy(), "A/D/H/nu"); 390 pw = new PrintWriter(new FileOutputStream(file)); 391 pw.print("This is the file 'nu'."); 392 pw.close(); 393 client.add(file.getAbsolutePath(), false); 394 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 395 "A/D/H/nu", NodeKind.file, 396 CommitItemStateFlags.TextMods + 397 CommitItemStateFlags.Add); 398 assertEquals("wrong revision number from commit", 399 rev = client.commit(new String[] {thisTest.getWCPath()}, 400 "log msg", true), 401 expectedRev++); 402 thisTest.getWc().addItem("A/D/H/nu", "This is the file 'nu'."); 403 status = client.singleStatus(thisTest.getWCPath() + "/A/D/H/nu", 404 false); 405 long nuCommitDate = status.getLastChangedDate().getTime(); 406 long nuCommitRev = rev; 407 String nuAuthor = status.getLastCommitAuthor(); 408 409 // ----- r9: Prop change on A/B/F --------------------------- 410 client.propertySet(thisTest.getWCPath() + "/A/B/F", "propname", 411 "propval", false); 412 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 413 "A/B/F", NodeKind.dir, 414 CommitItemStateFlags.PropMods); 415 assertEquals("wrong revision number from commit", 416 rev = client.commit(new String[] {thisTest.getWCPath()}, 417 "log msg", true), 418 expectedRev++); 419 thisTest.getWc().setItemPropStatus("A/B/F", Status.Kind.normal); 420 thisTest.getWc().setItemWorkingCopyRevision("A/B/F", rev); 421 status = client.singleStatus(thisTest.getWCPath() + "/A/B/F", false); 422 long FCommitDate = status.getLastChangedDate().getTime(); 423 long FCommitRev = rev; 424 String FAuthor = status.getLastCommitAuthor(); 425 426 // ----- r10-11: Replace file A/D/H/chi with file ----------- 427 client.remove(new String[] {thisTest.getWCPath() + "/A/D/H/chi"}, 428 null, false); 429 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 430 "A/D/H/chi", NodeKind.file, 431 CommitItemStateFlags.Delete); 432 assertEquals("wrong revision number from commit", 433 rev = client.commit(new String[] {thisTest.getWCPath()}, 434 "log msg", true), 435 expectedRev++); 436 thisTest.getWc().removeItem("A/D/G/pi"); 437 438 file = new File(thisTest.getWorkingCopy(), "A/D/H/chi"); 439 pw = new PrintWriter(new FileOutputStream(file)); 440 pw.print("This is the replacement file 'chi'."); 441 pw.close(); 442 client.add(file.getAbsolutePath(), false); 443 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 444 "A/D/H/chi", NodeKind.file, 445 CommitItemStateFlags.TextMods + 446 CommitItemStateFlags.Add); 447 assertEquals("wrong revision number from commit", 448 rev = client.commit(new String[] {thisTest.getWCPath()}, 449 "log msg", true), 450 expectedRev++); 451 thisTest.getWc().addItem("A/D/H/chi", 452 "This is the replacement file 'chi'."); 453 status = client.singleStatus(thisTest.getWCPath() + "/A/D/H/chi", 454 false); 455 long chiCommitDate = status.getLastChangedDate().getTime(); 456 long chiCommitRev = rev; 457 String chiAuthor = status.getLastCommitAuthor(); 458 459 // ----- r12: Delete dir A/B/E with children ---------------- 460 client.remove(new String[] {thisTest.getWCPath() + "/A/B/E"}, null, 461 false); 462 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 463 "A/B/E", NodeKind.dir, 464 CommitItemStateFlags.Delete); 465 assertEquals("wrong revision number from commit", 466 rev = client.commit(new String[] {thisTest.getWCPath()}, 467 "log msg", true), 468 expectedRev++); 469 thisTest.getWc().removeItem("A/B/E/alpha"); 470 thisTest.getWc().removeItem("A/B/E/beta"); 471 thisTest.getWc().removeItem("A/B/E"); 472 473 thisTest.getWc().setItemWorkingCopyRevision("A/B", rev); 474 assertEquals("wrong revision from update", 475 client.update(thisTest.getWCPath() + "/A/B", null, true), 476 rev); 477 Info Binfo = client.info(thisTest.getWCPath() + "/A/B"); 478 long BCommitDate = Binfo.getLastChangedDate().getTime(); 479 long BCommitRev = rev; 480 long ECommitRev = BCommitRev; 481 String BAuthor = Binfo.getAuthor(); 482 483 // ----- r13-14: Replace file A/D/H/psi with dir ------------ 484 client.remove(new String[]{thisTest.getWCPath() + "/A/D/H/psi"}, null, 485 false); 486 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 487 "A/D/H/psi", NodeKind.file, 488 CommitItemStateFlags.Delete); 489 assertEquals("wrong revision number from commit", 490 rev = client.commit(new String[] {thisTest.getWCPath()}, 491 "log msg", true), 492 expectedRev++); 493 thisTest.getWc().removeItem("A/D/H/psi"); 494 thisTest.getWc().setRevision(rev); 495 assertEquals("wrong revision from update", 496 client.update(thisTest.getWCPath(), null, true), rev); 497 thisTest.getWc().addItem("A/D/H/psi", null); 498 dir = new File(thisTest.getWorkingCopy(), "A/D/H/psi"); 499 dir.mkdir(); 500 client.add(dir.getAbsolutePath(), true); 501 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 502 "A/D/H/psi", NodeKind.dir, 503 CommitItemStateFlags.Add); 504 assertEquals("wrong revision number from commit", 505 rev = client.commit(new String[] {thisTest.getWCPath()}, 506 "log msg", true), 507 expectedRev++); 508 status = client.singleStatus(thisTest.getWCPath() + "/A/D/H/psi", 509 false); 510 long psiCommitDate = status.getLastChangedDate().getTime(); 511 long psiCommitRev = rev; 512 String psiAuthor = status.getLastCommitAuthor(); 513 514 // ----- Check status of modfied WC then update it back 515 // ----- to rev 1 so it's out of date 516 thisTest.checkStatus(); 517 518 assertEquals("wrong revision from update", 519 client.update(thisTest.getWCPath(), 520 Revision.getInstance(1), true), 521 1); 522 thisTest.getWc().setRevision(1); 523 524 thisTest.getWc().setItemOODInfo("A", psiCommitRev, psiAuthor, 525 psiCommitDate, NodeKind.dir); 526 527 thisTest.getWc().setItemOODInfo("A/B", BCommitRev, BAuthor, 528 BCommitDate, NodeKind.dir); 529 530 thisTest.getWc().addItem("A/B/I", null); 531 thisTest.getWc().setItemOODInfo("A/B/I", ICommitRev, IAuthor, 532 ICommitDate, NodeKind.dir); 533 thisTest.getWc().setItemTextStatus("A/B/I", Status.Kind.none); 534 thisTest.getWc().setItemNodeKind("A/B/I", NodeKind.unknown); 535 536 thisTest.getWc().addItem("A/C", null); 537 thisTest.getWc().setItemReposLastCmtRevision("A/C", CCommitRev); 538 thisTest.getWc().setItemReposKind("A/C", NodeKind.dir); 539 540 thisTest.getWc().addItem("A/B/E", null); 541 thisTest.getWc().setItemReposLastCmtRevision("A/B/E", ECommitRev); 542 thisTest.getWc().setItemReposKind("A/B/E", NodeKind.dir); 543 thisTest.getWc().addItem("A/B/E/alpha", "This is the file 'alpha'."); 544 thisTest.getWc().addItem("A/B/E/beta", "This is the file 'beta'."); 545 546 thisTest.getWc().setItemPropStatus("A/B/F", Status.Kind.none); 547 thisTest.getWc().setItemOODInfo("A/B/F", FCommitRev, FAuthor, 548 FCommitDate, NodeKind.dir); 549 550 thisTest.getWc().setItemOODInfo("A/D", psiCommitRev, psiAuthor, 551 psiCommitDate, NodeKind.dir); 552 553 thisTest.getWc().setItemOODInfo("A/D/G", tauCommitRev, tauAuthor, 554 tauCommitDate, NodeKind.dir); 555 556 thisTest.getWc().addItem("A/D/G/pi", "This is the file 'pi'."); 557 thisTest.getWc().setItemReposLastCmtRevision("A/D/G/pi", GCommitRev); 558 thisTest.getWc().setItemReposKind("A/D/G/pi", NodeKind.file); 559 560 thisTest.getWc().setItemContent("A/D/G/rho", 561 "This is the file 'rho'."); 562 thisTest.getWc().setItemOODInfo("A/D/G/rho", rhoCommitRev, rhoAuthor, 563 rhoCommitDate, NodeKind.file); 564 565 thisTest.getWc().setItemContent("A/D/G/tau", 566 "This is the file 'tau'."); 567 thisTest.getWc().setItemOODInfo("A/D/G/tau", tauCommitRev, tauAuthor, 568 tauCommitDate, NodeKind.file); 569 570 thisTest.getWc().setItemOODInfo("A/D/H", psiCommitRev, psiAuthor, 571 psiCommitDate, NodeKind.dir); 572 573 thisTest.getWc().setItemWorkingCopyRevision("A/D/H/nu", 574 Revision.SVN_INVALID_REVNUM); 575 thisTest.getWc().setItemTextStatus("A/D/H/nu", Status.Kind.none); 576 thisTest.getWc().setItemNodeKind("A/D/H/nu", NodeKind.unknown); 577 thisTest.getWc().setItemOODInfo("A/D/H/nu", nuCommitRev, nuAuthor, 578 nuCommitDate, NodeKind.file); 579 580 thisTest.getWc().setItemContent("A/D/H/chi", 581 "This is the file 'chi'."); 582 thisTest.getWc().setItemOODInfo("A/D/H/chi", chiCommitRev, chiAuthor, 583 chiCommitDate, NodeKind.file); 584 585 thisTest.getWc().removeItem("A/D/H/psi"); 586 thisTest.getWc().addItem("A/D/H/psi", "This is the file 'psi'."); 587 // psi was replaced with a directory 588 thisTest.getWc().setItemOODInfo("A/D/H/psi", psiCommitRev, psiAuthor, 589 psiCommitDate, NodeKind.dir); 590 591 thisTest.getWc().setItemPropStatus("", Status.Kind.none); 592 thisTest.getWc().setItemOODInfo("", psiCommitRev, psiAuthor, 593 psiCommitDate, NodeKind.dir); 594 595 thisTest.checkStatus(true); 596 } 597 598 /** 599 * Test the basic SVNClient.checkout functionality. 600 * @throws Throwable 601 */ testBasicCheckout()602 public void testBasicCheckout() throws Throwable 603 { 604 // build the test setup 605 OneTest thisTest = new OneTest(); 606 try 607 { 608 // obstructed checkout must fail 609 client.checkout(thisTest.getUrl() + "/A", thisTest.getWCPath(), 610 null, true); 611 fail("missing exception"); 612 } 613 catch (ClientException expected) 614 { 615 } 616 // modify file A/mu 617 File mu = new File(thisTest.getWorkingCopy(), "A/mu"); 618 PrintWriter muWriter = new PrintWriter(new FileOutputStream(mu, true)); 619 muWriter.print("appended mu text"); 620 muWriter.close(); 621 thisTest.getWc().setItemTextStatus("A/mu", Status.Kind.modified); 622 623 // delete A/B/lambda without svn 624 File lambda = new File(thisTest.getWorkingCopy(), "A/B/lambda"); 625 lambda.delete(); 626 thisTest.getWc().setItemTextStatus("A/B/lambda", Status.Kind.missing); 627 628 // remove A/D/G 629 client.remove(new String[]{thisTest.getWCPath() + "/A/D/G"}, null, 630 false); 631 thisTest.getWc().setItemTextStatus("A/D/G", Status.Kind.deleted); 632 thisTest.getWc().setItemTextStatus("A/D/G/pi", Status.Kind.deleted); 633 thisTest.getWc().setItemTextStatus("A/D/G/rho", Status.Kind.deleted); 634 thisTest.getWc().setItemTextStatus("A/D/G/tau", Status.Kind.deleted); 635 636 // check the status of the working copy 637 thisTest.checkStatus(); 638 639 // recheckout the working copy 640 client.checkout(thisTest.getUrl(), thisTest.getWCPath(), null, true); 641 642 // deleted file should reapear 643 thisTest.getWc().setItemTextStatus("A/B/lambda", Status.Kind.normal); 644 645 // check the status of the working copy 646 thisTest.checkStatus(); 647 } 648 649 /** 650 * Test the basic SVNClient.commit functionality. 651 * @throws Throwable 652 */ testBasicCommit()653 public void testBasicCommit() throws Throwable 654 { 655 // build the test setup 656 OneTest thisTest = new OneTest(); 657 658 // modify file A/mu 659 File mu = new File(thisTest.getWorkingCopy(), "A/mu"); 660 PrintWriter muWriter = new PrintWriter(new FileOutputStream(mu, true)); 661 muWriter.print("appended mu text"); 662 muWriter.close(); 663 thisTest.getWc().setItemWorkingCopyRevision("A/mu", 2); 664 thisTest.getWc().setItemContent("A/mu", 665 thisTest.getWc().getItemContent("A/mu") + "appended mu text"); 666 addExpectedCommitItem(thisTest.getWCPath(), 667 thisTest.getUrl(), "A/mu",NodeKind.file, 668 CommitItemStateFlags.TextMods); 669 670 // modify file A/D/G/rho 671 File rho = new File(thisTest.getWorkingCopy(), "A/D/G/rho"); 672 PrintWriter rhoWriter = 673 new PrintWriter(new FileOutputStream(rho, true)); 674 rhoWriter.print("new appended text for rho"); 675 rhoWriter.close(); 676 thisTest.getWc().setItemWorkingCopyRevision("A/D/G/rho", 2); 677 thisTest.getWc().setItemContent("A/D/G/rho", 678 thisTest.getWc().getItemContent("A/D/G/rho") 679 + "new appended text for rho"); 680 addExpectedCommitItem(thisTest.getWCPath(), 681 thisTest.getUrl(), "A/D/G/rho",NodeKind.file, 682 CommitItemStateFlags.TextMods); 683 684 // commit the changes 685 assertEquals("wrong revision number from commit", 686 client.commit(new String[]{thisTest.getWCPath()}, 687 "log msg", 688 true), 689 2); 690 691 // check the status of the working copy 692 thisTest.checkStatus(); 693 } 694 695 /** 696 * Test the basic property setting/getting functionality. 697 * @throws Throwable 698 */ testBasicProperties()699 public void testBasicProperties() throws Throwable 700 { 701 OneTest thisTest = new OneTest(); 702 WC wc = thisTest.getWc(); 703 704 // Check getting properties the non-callback way 705 String itemPath = fileToSVNPath(new File(thisTest.getWCPath(), 706 "iota"), 707 false); 708 709 client.propertySet(itemPath, "abc", "def", false); 710 PropertyData[] properties = client.properties(itemPath); 711 712 PropertyData prop = properties[0]; 713 assertEquals("abc", prop.getName()); 714 assertEquals("def", prop.getValue()); 715 716 wc.setItemPropStatus("iota", Status.Kind.modified); 717 thisTest.checkStatus(); 718 719 // Check getting properties the callback way 720 itemPath = fileToSVNPath(new File(thisTest.getWCPath(), 721 "/A/B/E/alpha"), 722 false); 723 client.propertyCreate(itemPath, "cqcq", "qrz", false, false); 724 ProplistCallbackImpl callback = new ProplistCallbackImpl(); 725 726 client.properties(itemPath, null, null, Depth.empty, null, callback); 727 Map propMap = callback.getProperties(itemPath); 728 Iterator it = propMap.keySet().iterator(); 729 730 while (it.hasNext()) 731 { 732 String key = (String) it.next(); 733 assertEquals("cqcq", key); 734 assertEquals("qrz", (String) propMap.get(key)); 735 } 736 737 wc.setItemPropStatus("A/B/E/alpha", Status.Kind.modified); 738 thisTest.checkStatus(); 739 } 740 741 /** 742 * Test the basic SVNClient.update functionality. 743 * @throws Throwable 744 */ testBasicUpdate()745 public void testBasicUpdate() throws Throwable 746 { 747 // build the test setup. Used for the changes 748 OneTest thisTest = new OneTest(); 749 750 // build the backup test setup. That is the one that will be updated 751 OneTest backupTest = thisTest.copy(".backup"); 752 753 // modify A/mu 754 File mu = new File(thisTest.getWorkingCopy(), "A/mu"); 755 PrintWriter muWriter = new PrintWriter(new FileOutputStream(mu, true)); 756 muWriter.print("appended mu text"); 757 muWriter.close(); 758 thisTest.getWc().setItemWorkingCopyRevision("A/mu", 2); 759 thisTest.getWc().setItemContent("A/mu", 760 thisTest.getWc().getItemContent("A/mu") + "appended mu text"); 761 addExpectedCommitItem(thisTest.getWCPath(), 762 thisTest.getUrl(), "A/mu",NodeKind.file, 763 CommitItemStateFlags.TextMods); 764 765 // modify A/D/G/rho 766 File rho = new File(thisTest.getWorkingCopy(), "A/D/G/rho"); 767 PrintWriter rhoWriter = 768 new PrintWriter(new FileOutputStream(rho, true)); 769 rhoWriter.print("new appended text for rho"); 770 rhoWriter.close(); 771 thisTest.getWc().setItemWorkingCopyRevision("A/D/G/rho", 2); 772 thisTest.getWc().setItemContent("A/D/G/rho", 773 thisTest.getWc().getItemContent("A/D/G/rho") 774 + "new appended text for rho"); 775 addExpectedCommitItem(thisTest.getWCPath(), 776 thisTest.getUrl(), "A/D/G/rho",NodeKind.file, 777 CommitItemStateFlags.TextMods); 778 779 // commit the changes 780 assertEquals("wrong revision number from commit", 781 client.commit(new String[]{thisTest.getWCPath()}, 782 "log msg", 783 true), 784 2); 785 786 // check the status of the working copy 787 thisTest.checkStatus(); 788 789 // update the backup test 790 assertEquals("wrong revision number from update", 791 client.update(backupTest.getWCPath(), null, true), 792 2); 793 794 // set the expected working copy layout for the backup test 795 backupTest.getWc().setItemWorkingCopyRevision("A/mu", 2); 796 backupTest.getWc().setItemContent("A/mu", 797 backupTest.getWc().getItemContent("A/mu") + "appended mu text"); 798 backupTest.getWc().setItemWorkingCopyRevision("A/D/G/rho", 2); 799 backupTest.getWc().setItemContent("A/D/G/rho", 800 backupTest.getWc().getItemContent("A/D/G/rho") 801 + "new appended text for rho"); 802 803 // check the status of the working copy of the backup test 804 backupTest.checkStatus(); 805 } 806 807 /** 808 * Test basic SVNClient.mkdir with URL parameter functionality. 809 * @throws Throwable 810 */ testBasicMkdirUrl()811 public void testBasicMkdirUrl() throws Throwable 812 { 813 // build the test setup. 814 OneTest thisTest = new OneTest(); 815 816 // create Y and Y/Z directories in the repository 817 addExpectedCommitItem(null, thisTest.getUrl(), "Y", NodeKind.none, 818 CommitItemStateFlags.Add); 819 addExpectedCommitItem(null, thisTest.getUrl(), "Y/Z", NodeKind.none, 820 CommitItemStateFlags.Add); 821 client.mkdir(new String[]{thisTest.getUrl() + "/Y", 822 thisTest.getUrl() + "/Y/Z"}, "log_msg"); 823 824 // add the new directories the expected working copy layout 825 thisTest.getWc().addItem("Y", null); 826 thisTest.getWc().setItemWorkingCopyRevision("Y", 2); 827 thisTest.getWc().addItem("Y/Z", null); 828 thisTest.getWc().setItemWorkingCopyRevision("Y/Z", 2); 829 830 // update the working copy 831 assertEquals("wrong revision from update", 832 client.update(thisTest.getWCPath(), null, true), 833 2); 834 835 // check the status of the working copy 836 thisTest.checkStatus(); 837 } 838 839 /** 840 * Test the {@link SVNClientInterface.copy()} API. 841 * @since 1.5 842 */ testCopy()843 public void testCopy() 844 throws SubversionException, IOException 845 { 846 OneTest thisTest = new OneTest(); 847 848 WC wc = thisTest.getWc(); 849 final Revision firstRevision = Revision.getInstance(1); 850 final Revision pegRevision = null; // Defaults to Revision.HEAD. 851 852 // Copy files from A/B/E to A/B/F. 853 String[] srcPaths = { "alpha", "beta" }; 854 CopySource[] sources = new CopySource[srcPaths.length]; 855 for (int i = 0; i < srcPaths.length; i++) 856 { 857 String fileName = srcPaths[i]; 858 sources[i] = 859 new CopySource(new File(thisTest.getWorkingCopy(), 860 "A/B/E/" + fileName).getPath(), 861 firstRevision, pegRevision); 862 wc.addItem("A/B/F/" + fileName, 863 wc.getItemContent("A/B/E/" + fileName)); 864 wc.setItemWorkingCopyRevision("A/B/F/" + fileName, 2); 865 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 866 "A/B/F/" + fileName, NodeKind.file, 867 CommitItemStateFlags.Add | 868 CommitItemStateFlags.IsCopy); 869 } 870 client.copy(sources, 871 new File(thisTest.getWorkingCopy(), "A/B/F").getPath(), 872 null, true, false, null); 873 874 // Commit the changes, and check the state of the WC. 875 assertEquals("Unexpected WC revision number after commit", 876 client.commit(new String[] { thisTest.getWCPath() }, 877 "Copy files", true), 878 2); 879 thisTest.checkStatus(); 880 881 assertExpectedSuggestion(thisTest.getUrl() + "/A/B/E/alpha", "A/B/F/alpha", thisTest); 882 883 // Now test a WC to URL copy 884 CopySource wcSource[] = new CopySource[1]; 885 wcSource[0] = new CopySource(new File(thisTest.getWorkingCopy(), 886 "A/B").getPath(), Revision.WORKING, Revision.WORKING); 887 client.commitMessageHandler(null); 888 client.copy(wcSource, 889 thisTest.getUrl() + "/parent/A/B", 890 "Copy WC to URL", true, true, null); 891 892 // update the WC to get new folder and confirm the copy 893 assertEquals("wrong revision number from update", 894 client.update(thisTest.getWCPath(), null, true), 895 3); 896 } 897 898 /** 899 * Test the {@link SVNClientInterface.move()} API. 900 * @since 1.5 901 */ testMove()902 public void testMove() 903 throws SubversionException, IOException 904 { 905 OneTest thisTest = new OneTest(); 906 WC wc = thisTest.getWc(); 907 908 // Move files from A/B/E to A/B/F. 909 String[] srcPaths = { "alpha", "beta" }; 910 for (int i = 0; i < srcPaths.length; i++) 911 { 912 String fileName = srcPaths[i]; 913 srcPaths[i] = new File(thisTest.getWorkingCopy(), 914 "A/B/E/" + fileName).getPath(); 915 916 wc.addItem("A/B/F/" + fileName, 917 wc.getItemContent("A/B/E/" + fileName)); 918 wc.setItemWorkingCopyRevision("A/B/F/" + fileName, 2); 919 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 920 "A/B/F/" + fileName, NodeKind.file, 921 CommitItemStateFlags.Add | 922 CommitItemStateFlags.IsCopy); 923 924 wc.removeItem("A/B/E/" + fileName); 925 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 926 "A/B/E/" + fileName, NodeKind.file, 927 CommitItemStateFlags.Delete); 928 } 929 client.move(srcPaths, 930 new File(thisTest.getWorkingCopy(), "A/B/F").getPath(), 931 null, false, true, false, null); 932 933 // Commit the changes, and check the state of the WC. 934 assertEquals("Unexpected WC revision number after commit", 935 client.commit(new String[] { thisTest.getWCPath() }, 936 "Move files", true), 2); 937 thisTest.checkStatus(); 938 939 assertExpectedSuggestion(thisTest.getUrl() + "/A/B/E/alpha", "A/B/F/alpha", thisTest); 940 } 941 942 /** 943 * Assert that the first merge source suggested for 944 * <code>destPath</code> at {@link Revision#WORKING} and {@link 945 * Revision#HEAD} is equivalent to <code>expectedSrc</code>. 946 * @exception SubversionException If retrieval of the copy source fails. 947 * @since 1.5 948 */ assertExpectedSuggestion(String expectedSrc, String destPath, OneTest thisTest)949 private void assertExpectedSuggestion(String expectedSrc, 950 String destPath, OneTest thisTest) 951 throws SubversionException 952 { 953 String wcPath = fileToSVNPath(new File(thisTest.getWCPath(), 954 destPath), false); 955 String[] suggestions = client.suggestMergeSources(wcPath, 956 Revision.WORKING); 957 assertNotNull(suggestions); 958 assertTrue(suggestions.length >= 1); 959 assertTrue("Unexpected copy source path, expected " + 960 expectedSrc + ", got " + suggestions[0], 961 expectedSrc.equals(suggestions[0])); 962 963 // Same test using URL 964 String url = thisTest.getUrl() + "/" + destPath; 965 suggestions = client.suggestMergeSources(url, Revision.HEAD); 966 assertNotNull(suggestions); 967 assertTrue(suggestions.length >= 1); 968 assertTrue("Unexpected copy source path, expected " + 969 expectedSrc + ", got " + suggestions[0], 970 expectedSrc.equals(suggestions[0])); 971 972 } 973 974 /** 975 * Tests that the passed start and end revision are contained 976 * within the array of revisions. 977 * @since 1.5 978 */ assertExpectedMergeRange(long start, long end, long[] revisions)979 private void assertExpectedMergeRange(long start, long end, 980 long[] revisions) 981 { 982 Arrays.sort(revisions); 983 for (int i = 0; i < revisions.length; i++) { 984 if (revisions[i] <= start) { 985 for (int j = i; j < revisions.length; j++) 986 { 987 if (end <= revisions[j]) 988 return; 989 } 990 fail("End revision: " + end + " was not in range: " + revisions[0] + 991 " : " + revisions[revisions.length - 1]); 992 return; 993 } 994 } 995 fail("Start revision: " + start + " was not in range: " + revisions[0] + 996 " : " + revisions[revisions.length - 1]); 997 } 998 999 /** 1000 * Test the basic SVNClient.update functionality with concurrent 1001 * changes in the repository and the working copy. 1002 * @throws Throwable 1003 */ testBasicMergingUpdate()1004 public void testBasicMergingUpdate() throws Throwable 1005 { 1006 // build the first working copy 1007 OneTest thisTest = new OneTest(); 1008 1009 // append 10 lines to A/mu 1010 File mu = new File(thisTest.getWorkingCopy(), "A/mu"); 1011 PrintWriter muWriter = new PrintWriter(new FileOutputStream(mu, true)); 1012 String muContent = thisTest.getWc().getItemContent("A/mu"); 1013 for (int i = 2; i < 11; i++) 1014 { 1015 muWriter.print("\nThis is line " + i + " in mu"); 1016 muContent = muContent + "\nThis is line " + i + " in mu"; 1017 } 1018 muWriter.close(); 1019 thisTest.getWc().setItemWorkingCopyRevision("A/mu", 2); 1020 thisTest.getWc().setItemContent("A/mu", muContent); 1021 addExpectedCommitItem(thisTest.getWorkingCopy().getAbsolutePath(), 1022 thisTest.getUrl(), "A/mu", NodeKind.file, 1023 CommitItemStateFlags.TextMods); 1024 1025 // append 10 line to A/D/G/rho 1026 File rho = new File(thisTest.getWorkingCopy(), "A/D/G/rho"); 1027 PrintWriter rhoWriter = 1028 new PrintWriter(new FileOutputStream(rho, true)); 1029 String rhoContent = thisTest.getWc().getItemContent("A/D/G/rho"); 1030 for (int i = 2; i < 11; i++) 1031 { 1032 rhoWriter.print("\nThis is line " + i + " in rho"); 1033 rhoContent = rhoContent + "\nThis is line " + i + " in rho"; 1034 } 1035 rhoWriter.close(); 1036 thisTest.getWc().setItemWorkingCopyRevision("A/D/G/rho", 2); 1037 thisTest.getWc().setItemContent("A/D/G/rho", rhoContent); 1038 addExpectedCommitItem(thisTest.getWCPath(), 1039 thisTest.getUrl(), "A/D/G/rho", NodeKind.file, 1040 CommitItemStateFlags.TextMods); 1041 1042 // commit the changes 1043 assertEquals("wrong revision number from commit", 1044 client.commit(new String[]{thisTest.getWCPath()}, 1045 "log msg", 1046 true), 1047 2); 1048 1049 // check the status of the first working copy 1050 thisTest.checkStatus(); 1051 1052 // create a backup copy of the working copy 1053 OneTest backupTest = thisTest.copy(".backup"); 1054 1055 // change the last line of A/mu in the first working copy 1056 muWriter = new PrintWriter(new FileOutputStream(mu, true)); 1057 muContent = thisTest.getWc().getItemContent("A/mu"); 1058 muWriter.print(" Appended to line 10 of mu"); 1059 muContent = muContent + " Appended to line 10 of mu"; 1060 muWriter.close(); 1061 thisTest.getWc().setItemWorkingCopyRevision("A/mu", 3); 1062 thisTest.getWc().setItemContent("A/mu", muContent); 1063 addExpectedCommitItem(thisTest.getWCPath(), 1064 thisTest.getUrl(), "A/mu", NodeKind.file, 1065 CommitItemStateFlags.TextMods); 1066 1067 // change the last line of A/mu in the first working copy 1068 rhoWriter = new PrintWriter(new FileOutputStream(rho, true)); 1069 rhoContent = thisTest.getWc().getItemContent("A/D/G/rho"); 1070 rhoWriter.print(" Appended to line 10 of rho"); 1071 rhoContent = rhoContent + " Appended to line 10 of rho"; 1072 rhoWriter.close(); 1073 thisTest.getWc().setItemWorkingCopyRevision("A/D/G/rho", 3); 1074 thisTest.getWc().setItemContent("A/D/G/rho", rhoContent); 1075 addExpectedCommitItem(thisTest.getWCPath(), 1076 thisTest.getUrl(), "A/D/G/rho", NodeKind.file, 1077 CommitItemStateFlags.TextMods); 1078 1079 // commit these changes to the repository 1080 assertEquals("wrong revision number from commit", 1081 client.commit(new String[]{thisTest.getWCPath()}, 1082 "log msg", 1083 true), 1084 3); 1085 1086 // check the status of the first working copy 1087 thisTest.checkStatus(); 1088 1089 // modify the first line of A/mu in the backup working copy 1090 mu = new File(backupTest.getWorkingCopy(), "A/mu"); 1091 muWriter = new PrintWriter(new FileOutputStream(mu)); 1092 muWriter.print("This is the new line 1 in the backup copy of mu"); 1093 muContent = "This is the new line 1 in the backup copy of mu"; 1094 for (int i = 2; i < 11; i++) 1095 { 1096 muWriter.print("\nThis is line " + i + " in mu"); 1097 muContent = muContent + "\nThis is line " + i + " in mu"; 1098 } 1099 muWriter.close(); 1100 backupTest.getWc().setItemWorkingCopyRevision("A/mu", 3); 1101 muContent = muContent + " Appended to line 10 of mu"; 1102 backupTest.getWc().setItemContent("A/mu", muContent); 1103 backupTest.getWc().setItemTextStatus("A/mu", Status.Kind.modified); 1104 1105 // modify the first line of A/D/G/rho in the backup working copy 1106 rho = new File(backupTest.getWorkingCopy(), "A/D/G/rho"); 1107 rhoWriter = new PrintWriter(new FileOutputStream(rho)); 1108 rhoWriter.print("This is the new line 1 in the backup copy of rho"); 1109 rhoContent = "This is the new line 1 in the backup copy of rho"; 1110 for (int i = 2; i < 11; i++) 1111 { 1112 rhoWriter.print("\nThis is line " + i + " in rho"); 1113 rhoContent = rhoContent + "\nThis is line " + i + " in rho"; 1114 } 1115 rhoWriter.close(); 1116 backupTest.getWc().setItemWorkingCopyRevision("A/D/G/rho", 3); 1117 rhoContent = rhoContent + " Appended to line 10 of rho"; 1118 backupTest.getWc().setItemContent("A/D/G/rho", rhoContent); 1119 backupTest.getWc().setItemTextStatus("A/D/G/rho", Status.Kind.modified); 1120 1121 // update the backup working copy 1122 assertEquals("wrong revision number from update", 1123 client.update(backupTest.getWCPath(), null, true), 1124 3); 1125 1126 // check the status of the backup working copy 1127 backupTest.checkStatus(); 1128 } 1129 1130 /** 1131 * Test the basic SVNClient.update functionality with concurrent 1132 * changes in the repository and the working copy that generate 1133 * conflicts. 1134 * @throws Throwable 1135 */ testBasicConflict()1136 public void testBasicConflict() throws Throwable 1137 { 1138 // build the first working copy 1139 OneTest thisTest = new OneTest(); 1140 1141 // copy the first working copy to the backup working copy 1142 OneTest backupTest = thisTest.copy(".backup"); 1143 1144 // append a line to A/mu in the first working copy 1145 File mu = new File(thisTest.getWorkingCopy(), "A/mu"); 1146 PrintWriter muWriter = new PrintWriter(new FileOutputStream(mu, true)); 1147 String muContent = thisTest.getWc().getItemContent("A/mu"); 1148 muWriter.print("\nOriginal appended text for mu"); 1149 muContent = muContent + "\nOriginal appended text for mu"; 1150 muWriter.close(); 1151 thisTest.getWc().setItemWorkingCopyRevision("A/mu", 2); 1152 thisTest.getWc().setItemContent("A/mu", muContent); 1153 addExpectedCommitItem(thisTest.getWCPath(), 1154 thisTest.getUrl(), "A/mu", NodeKind.file, 1155 CommitItemStateFlags.TextMods); 1156 1157 // append a line to A/D/G/rho in the first working copy 1158 File rho = new File(thisTest.getWorkingCopy(), "A/D/G/rho"); 1159 PrintWriter rhoWriter = 1160 new PrintWriter(new FileOutputStream(rho, true)); 1161 String rhoContent = thisTest.getWc().getItemContent("A/D/G/rho"); 1162 rhoWriter.print("\nOriginal appended text for rho"); 1163 rhoContent = rhoContent + "\nOriginal appended text for rho"; 1164 rhoWriter.close(); 1165 thisTest.getWc().setItemWorkingCopyRevision("A/D/G/rho", 2); 1166 thisTest.getWc().setItemContent("A/D/G/rho", rhoContent); 1167 addExpectedCommitItem(thisTest.getWCPath(), 1168 thisTest.getUrl(), "A/D/G/rho", NodeKind.file, 1169 CommitItemStateFlags.TextMods); 1170 1171 // commit the changes in the first working copy 1172 assertEquals("wrong revision number from commit", 1173 client.commit(new String[]{thisTest.getWCPath()}, 1174 "log msg", 1175 true), 1176 2); 1177 1178 // test the status of the working copy after the commit 1179 thisTest.checkStatus(); 1180 1181 // append a different line to A/mu in the backup working copy 1182 mu = new File(backupTest.getWorkingCopy(), "A/mu"); 1183 muWriter = new PrintWriter(new FileOutputStream(mu, true)); 1184 muWriter.print("\nConflicting appended text for mu"); 1185 muContent = "<<<<<<< .mine\nThis is the file 'mu'.\n"+ 1186 "Conflicting appended text for mu=======\n"+ 1187 "This is the file 'mu'.\n"+ 1188 "Original appended text for mu>>>>>>> .r2"; 1189 muWriter.close(); 1190 backupTest.getWc().setItemWorkingCopyRevision("A/mu", 2); 1191 backupTest.getWc().setItemContent("A/mu", muContent); 1192 backupTest.getWc().setItemTextStatus("A/mu", Status.Kind.conflicted); 1193 backupTest.getWc().addItem("A/mu.r1", ""); 1194 backupTest.getWc().setItemNodeKind("A/mu.r1", NodeKind.unknown); 1195 backupTest.getWc().setItemTextStatus("A/mu.r1", 1196 Status.Kind.unversioned); 1197 backupTest.getWc().addItem("A/mu.r2", ""); 1198 backupTest.getWc().setItemNodeKind("A/mu.r2", NodeKind.unknown); 1199 backupTest.getWc().setItemTextStatus("A/mu.r2", 1200 Status.Kind.unversioned); 1201 backupTest.getWc().addItem("A/mu.mine", ""); 1202 backupTest.getWc().setItemNodeKind("A/mu.mine", NodeKind.unknown); 1203 backupTest.getWc().setItemTextStatus("A/mu.mine", 1204 Status.Kind.unversioned); 1205 1206 // append a different line to A/D/G/rho in the backup working copy 1207 rho = new File(backupTest.getWorkingCopy(), "A/D/G/rho"); 1208 rhoWriter = new PrintWriter(new FileOutputStream(rho, true)); 1209 rhoWriter.print("\nConflicting appended text for rho"); 1210 rhoContent = "<<<<<<< .mine\nThis is the file 'rho'.\n"+ 1211 "Conflicting appended text for rho=======\n"+ 1212 "his is the file 'rho'.\n"+ 1213 "Original appended text for rho>>>>>>> .r2"; 1214 rhoWriter.close(); 1215 backupTest.getWc().setItemWorkingCopyRevision("A/D/G/rho", 2); 1216 backupTest.getWc().setItemContent("A/D/G/rho", rhoContent); 1217 backupTest.getWc().setItemTextStatus("A/D/G/rho", 1218 Status.Kind.conflicted); 1219 backupTest.getWc().addItem("A/D/G/rho.r1", ""); 1220 backupTest.getWc().setItemNodeKind("A/D/G/rho.r1", NodeKind.unknown); 1221 backupTest.getWc().setItemTextStatus("A/D/G/rho.r1", 1222 Status.Kind.unversioned); 1223 backupTest.getWc().addItem("A/D/G/rho.r2", ""); 1224 backupTest.getWc().setItemNodeKind("A/D/G/rho.r2", NodeKind.unknown); 1225 backupTest.getWc().setItemTextStatus("A/D/G/rho.r2", 1226 Status.Kind.unversioned); 1227 backupTest.getWc().addItem("A/D/G/rho.mine", ""); 1228 backupTest.getWc().setItemNodeKind("A/D/G/rho.mine", NodeKind.unknown); 1229 backupTest.getWc().setItemTextStatus("A/D/G/rho.mine", 1230 Status.Kind.unversioned); 1231 1232 // update the backup working copy from the repository 1233 assertEquals("wrong revision number from update", 1234 client.update(backupTest.getWCPath(), null, true), 1235 2); 1236 1237 // check the status of the backup working copy 1238 backupTest.checkStatus(); 1239 1240 // flag A/mu as resolved 1241 client.resolved(backupTest.getWCPath()+"/A/mu", false); 1242 backupTest.getWc().setItemTextStatus("A/mu", Status.Kind.modified); 1243 backupTest.getWc().removeItem("A/mu.r1"); 1244 backupTest.getWc().removeItem("A/mu.r2"); 1245 backupTest.getWc().removeItem("A/mu.mine"); 1246 1247 // flag A/D/G/rho as resolved 1248 client.resolved(backupTest.getWCPath()+"/A/D/G/rho", false); 1249 backupTest.getWc().setItemTextStatus("A/D/G/rho", 1250 Status.Kind.modified); 1251 backupTest.getWc().removeItem("A/D/G/rho.r1"); 1252 backupTest.getWc().removeItem("A/D/G/rho.r2"); 1253 backupTest.getWc().removeItem("A/D/G/rho.mine"); 1254 1255 // check the status after the conflicts are flaged as resolved 1256 backupTest.checkStatus(); 1257 } 1258 1259 /** 1260 * Test the basic SVNClient.cleanup functionality. 1261 * Without a way to force a lock, this test just verifies 1262 * the method can be called successfully. 1263 * @throws Throwable 1264 */ testBasicCleanup()1265 public void testBasicCleanup() throws Throwable 1266 { 1267 // create a test working copy 1268 OneTest thisTest = new OneTest(); 1269 1270 // run cleanup 1271 client.cleanup(thisTest.getWCPath()); 1272 1273 } 1274 1275 /** 1276 * Test the basic SVNClient.revert functionality. 1277 * @throws Throwable 1278 */ testBasicRevert()1279 public void testBasicRevert() throws Throwable 1280 { 1281 // create a test working copy 1282 OneTest thisTest = new OneTest(); 1283 1284 // modify A/B/E/beta 1285 File file = new File(thisTest.getWorkingCopy(), "A/B/E/beta"); 1286 PrintWriter pw = new PrintWriter(new FileOutputStream(file, true)); 1287 pw.print("Added some text to 'beta'."); 1288 pw.close(); 1289 thisTest.getWc().setItemTextStatus("A/B/E/beta", Status.Kind.modified); 1290 1291 // modify iota 1292 file = new File(thisTest.getWorkingCopy(), "iota"); 1293 pw = new PrintWriter(new FileOutputStream(file, true)); 1294 pw.print("Added some text to 'iota'."); 1295 pw.close(); 1296 thisTest.getWc().setItemTextStatus("iota", Status.Kind.modified); 1297 1298 // modify A/D/G/rho 1299 file = new File(thisTest.getWorkingCopy(), "A/D/G/rho"); 1300 pw = new PrintWriter(new FileOutputStream(file, true)); 1301 pw.print("Added some text to 'rho'."); 1302 pw.close(); 1303 thisTest.getWc().setItemTextStatus("A/D/G/rho", Status.Kind.modified); 1304 1305 // create new file A/D/H/zeta and add it to subversion 1306 file = new File(thisTest.getWorkingCopy(), "A/D/H/zeta"); 1307 pw = new PrintWriter(new FileOutputStream(file, true)); 1308 pw.print("Added some text to 'zeta'."); 1309 pw.close(); 1310 thisTest.getWc().addItem("A/D/H/zeta", "Added some text to 'zeta'."); 1311 thisTest.getWc().setItemTextStatus("A/D/H/zeta", Status.Kind.added); 1312 client.add(file.getAbsolutePath(), false); 1313 1314 // test the status of the working copy 1315 thisTest.checkStatus(); 1316 1317 // revert the changes 1318 client.revert(thisTest.getWCPath()+"/A/B/E/beta", false); 1319 thisTest.getWc().setItemTextStatus("A/B/E/beta", Status.Kind.normal); 1320 client.revert(thisTest.getWCPath()+"/iota", false); 1321 thisTest.getWc().setItemTextStatus("iota", Status.Kind.normal); 1322 client.revert(thisTest.getWCPath()+"/A/D/G/rho", false); 1323 thisTest.getWc().setItemTextStatus("A/D/G/rho", Status.Kind.normal); 1324 client.revert(thisTest.getWCPath()+"/A/D/H/zeta", false); 1325 thisTest.getWc().setItemTextStatus("A/D/H/zeta", 1326 Status.Kind.unversioned); 1327 thisTest.getWc().setItemNodeKind("A/D/H/zeta", NodeKind.unknown); 1328 1329 // test the status of the working copy 1330 thisTest.checkStatus(); 1331 1332 // delete A/B/E/beta and revert the change 1333 file = new File(thisTest.getWorkingCopy(), "A/B/E/beta"); 1334 file.delete(); 1335 client.revert(file.getAbsolutePath(), false); 1336 1337 // resurected file should not be readonly 1338 assertTrue("reverted file is not readonly", 1339 file.canWrite()&& file.canRead()); 1340 1341 // test the status of the working copy 1342 thisTest.checkStatus(); 1343 1344 // create & add the directory X 1345 client.mkdir(new String[] {thisTest.getWCPath()+"/X"}, null); 1346 thisTest.getWc().addItem("X", null); 1347 thisTest.getWc().setItemTextStatus("X", Status.Kind.added); 1348 1349 // test the status of the working copy 1350 thisTest.checkStatus(); 1351 1352 // remove & revert X 1353 removeDirOrFile(new File(thisTest.getWorkingCopy(), "X")); 1354 client.revert(thisTest.getWCPath()+"/X", false); 1355 thisTest.getWc().removeItem("X"); 1356 1357 // test the status of the working copy 1358 thisTest.checkStatus(); 1359 1360 // delete the directory A/B/E 1361 client.remove(new String[] {thisTest.getWCPath()+"/A/B/E"}, null, true); 1362 removeDirOrFile(new File(thisTest.getWorkingCopy(), "A/B/E")); 1363 thisTest.getWc().setItemTextStatus("A/B/E", Status.Kind.deleted); 1364 thisTest.getWc().setItemTextStatus("A/B/E/alpha", Status.Kind.deleted); 1365 thisTest.getWc().setItemTextStatus("A/B/E/beta", Status.Kind.deleted); 1366 1367 // test the status of the working copy 1368 thisTest.checkStatus(); 1369 1370 // revert A/B/E -> this will resurect it 1371 client.revert(thisTest.getWCPath()+"/A/B/E", true); 1372 thisTest.getWc().setItemTextStatus("A/B/E", Status.Kind.normal); 1373 thisTest.getWc().setItemTextStatus("A/B/E/alpha", Status.Kind.normal); 1374 thisTest.getWc().setItemTextStatus("A/B/E/beta", Status.Kind.normal); 1375 1376 // test the status of the working copy 1377 thisTest.checkStatus(); 1378 } 1379 1380 /** 1381 * Test the basic SVNClient.switch functionality. 1382 * @throws Throwable 1383 */ testBasicSwitch()1384 public void testBasicSwitch() throws Throwable 1385 { 1386 // create the test working copy 1387 OneTest thisTest = new OneTest(); 1388 1389 // switch iota to A/D/gamma 1390 String iotaPath = thisTest.getWCPath() + "/iota"; 1391 String gammaUrl = thisTest.getUrl() + "/A/D/gamma"; 1392 thisTest.getWc().setItemContent("iota", 1393 greekWC.getItemContent("A/D/gamma")); 1394 thisTest.getWc().setItemIsSwitched("iota", true); 1395 client.doSwitch(iotaPath, gammaUrl, null, true); 1396 1397 // check the status of the working copy 1398 thisTest.checkStatus(); 1399 1400 // switch A/D/H to /A/D/G 1401 String adhPath = thisTest.getWCPath() + "/A/D/H"; 1402 String adgURL = thisTest.getUrl() + "/A/D/G"; 1403 thisTest.getWc().setItemIsSwitched("A/D/H",true); 1404 thisTest.getWc().removeItem("A/D/H/chi"); 1405 thisTest.getWc().removeItem("A/D/H/omega"); 1406 thisTest.getWc().removeItem("A/D/H/psi"); 1407 thisTest.getWc().addItem("A/D/H/pi", 1408 thisTest.getWc().getItemContent("A/D/G/pi")); 1409 thisTest.getWc().addItem("A/D/H/rho", 1410 thisTest.getWc().getItemContent("A/D/G/rho")); 1411 thisTest.getWc().addItem("A/D/H/tau", 1412 thisTest.getWc().getItemContent("A/D/G/tau")); 1413 client.doSwitch(adhPath, adgURL, null, true); 1414 1415 // check the status of the working copy 1416 thisTest.checkStatus(); 1417 } 1418 1419 /** 1420 * Test the basic SVNClient.remove functionality. 1421 * @throws Throwable 1422 */ testBasicDelete()1423 public void testBasicDelete() throws Throwable 1424 { 1425 // create the test working copy 1426 OneTest thisTest = new OneTest(); 1427 1428 // modify A/D/H/chi 1429 File file = new File(thisTest.getWorkingCopy(), "A/D/H/chi"); 1430 PrintWriter pw = new PrintWriter(new FileOutputStream(file, true)); 1431 pw.print("added to chi"); 1432 pw.close(); 1433 thisTest.getWc().setItemTextStatus("A/D/H/chi", Status.Kind.modified); 1434 1435 // set a property on A/D/G/rho file 1436 client.propertySet(thisTest.getWCPath()+"/A/D/G/rho", "abc", "def", 1437 true); 1438 thisTest.getWc().setItemPropStatus("A/D/G/rho", Status.Kind.modified); 1439 1440 // set a property on A/B/F directory 1441 client.propertySet(thisTest.getWCPath()+"/A/B/F", "abc", "def", false); 1442 thisTest.getWc().setItemPropStatus("A/B/F", Status.Kind.modified); 1443 1444 // create a unversioned A/C/sigma file 1445 file = new File(thisTest.getWCPath(),"A/C/sigma"); 1446 pw = new PrintWriter(new FileOutputStream(file)); 1447 pw.print("unversioned sigma"); 1448 pw.close(); 1449 thisTest.getWc().addItem("A/C/sigma", "unversioned sigma"); 1450 thisTest.getWc().setItemTextStatus("A/C/sigma", Status.Kind.unversioned); 1451 thisTest.getWc().setItemNodeKind("A/C/sigma", NodeKind.unknown); 1452 1453 // create unversioned directory A/C/Q 1454 file = new File(thisTest.getWCPath(), "A/C/Q"); 1455 file.mkdir(); 1456 thisTest.getWc().addItem("A/C/Q", null); 1457 thisTest.getWc().setItemNodeKind("A/C/Q", NodeKind.unknown); 1458 thisTest.getWc().setItemTextStatus("A/C/Q", Status.Kind.unversioned); 1459 1460 // create & add the directory A/B/X 1461 file = new File(thisTest.getWCPath(), "A/B/X"); 1462 client.mkdir(new String[] {file.getAbsolutePath()}, null); 1463 thisTest.getWc().addItem("A/B/X", null); 1464 thisTest.getWc().setItemTextStatus("A/B/X", Status.Kind.added); 1465 1466 // create & add the file A/B/X/xi 1467 file = new File(file, "xi"); 1468 pw = new PrintWriter(new FileOutputStream(file)); 1469 pw.print("added xi"); 1470 pw.close(); 1471 client.add(file.getAbsolutePath(), false); 1472 thisTest.getWc().addItem("A/B/X/xi", "added xi"); 1473 thisTest.getWc().setItemTextStatus("A/B/X/xi", Status.Kind.added); 1474 1475 // create & add the directory A/B/Y 1476 file = new File(thisTest.getWCPath(), "A/B/Y"); 1477 client.mkdir(new String[] {file.getAbsolutePath()}, null); 1478 thisTest.getWc().addItem("A/B/Y", null); 1479 thisTest.getWc().setItemTextStatus("A/B/Y", Status.Kind.added); 1480 1481 // test the status of the working copy 1482 thisTest.checkStatus(); 1483 1484 // the following removes should all fail without force 1485 1486 try 1487 { 1488 // remove of A/D/H/chi without force should fail, because it is 1489 // modified 1490 client.remove(new String[] {thisTest.getWCPath()+"/A/D/H/chi"}, 1491 null, false); 1492 fail("missing exception"); 1493 } 1494 catch(ClientException expected) 1495 { 1496 } 1497 1498 try 1499 { 1500 // remove of A/D/H without force should fail, because A/D/H/chi is 1501 // modified 1502 client.remove(new String[] {thisTest.getWCPath()+"/A/D/H"}, null, 1503 false); 1504 fail("missing exception"); 1505 } 1506 catch(ClientException expected) 1507 { 1508 } 1509 1510 try 1511 { 1512 // remove of A/D/G/rho without force should fail, because it has 1513 // a new property 1514 client.remove(new String[] {thisTest.getWCPath()+"/A/D/G/rho"}, 1515 null, false); 1516 fail("missing exception"); 1517 } 1518 catch(ClientException expected) 1519 { 1520 } 1521 1522 try 1523 { 1524 // remove of A/D/G without force should fail, because A/D/G/rho has 1525 // a new property 1526 client.remove(new String[] {thisTest.getWCPath()+"/A/D/G"}, null, 1527 false); 1528 fail("missing exception"); 1529 } 1530 catch(ClientException expected) 1531 { 1532 } 1533 1534 try 1535 { 1536 // remove of A/B/F without force should fail, because it has 1537 // a new property 1538 client.remove(new String[] {thisTest.getWCPath()+"/A/B/F"}, null, 1539 false); 1540 fail("missing exception"); 1541 } 1542 catch(ClientException expected) 1543 { 1544 } 1545 1546 try 1547 { 1548 // remove of A/B without force should fail, because A/B/F has 1549 // a new property 1550 client.remove(new String[] {thisTest.getWCPath()+"/A/B"}, null, 1551 false); 1552 fail("missing exception"); 1553 } 1554 catch(ClientException expected) 1555 { 1556 } 1557 1558 try 1559 { 1560 // remove of A/C/sigma without force should fail, because it is 1561 // unversioned 1562 client.remove(new String[] {thisTest.getWCPath()+"/A/C/sigma"}, 1563 null, false); 1564 fail("missing exception"); 1565 } 1566 catch(ClientException expected) 1567 { 1568 } 1569 1570 try 1571 { 1572 // remove of A/C without force should fail, because A/C/sigma is 1573 // unversioned 1574 client.remove(new String[] {thisTest.getWCPath()+"/A/C"}, null, 1575 false); 1576 fail("missing exception"); 1577 } 1578 catch(ClientException expected) 1579 { 1580 } 1581 1582 try 1583 { 1584 // remove of A/B/X without force should fail, because it is new 1585 client.remove(new String[] {thisTest.getWCPath()+"/A/B/X"}, null, 1586 false); 1587 fail("missing exception"); 1588 } 1589 catch(ClientException expected) 1590 { 1591 } 1592 1593 // check the status of the working copy 1594 thisTest.checkStatus(); 1595 1596 // the following removes should all work 1597 client.remove(new String[] {thisTest.getWCPath()+"/A/B/E"}, null, 1598 false); 1599 thisTest.getWc().setItemTextStatus("A/B/E",Status.Kind.deleted); 1600 thisTest.getWc().setItemTextStatus("A/B/E/alpha",Status.Kind.deleted); 1601 thisTest.getWc().setItemTextStatus("A/B/E/beta",Status.Kind.deleted); 1602 client.remove(new String[] {thisTest.getWCPath()+"/A/D/H"}, null, true); 1603 thisTest.getWc().setItemTextStatus("A/D/H",Status.Kind.deleted); 1604 thisTest.getWc().setItemTextStatus("A/D/H/chi",Status.Kind.deleted); 1605 thisTest.getWc().setItemTextStatus("A/D/H/omega",Status.Kind.deleted); 1606 thisTest.getWc().setItemTextStatus("A/D/H/psi",Status.Kind.deleted); 1607 client.remove(new String[] {thisTest.getWCPath()+"/A/D/G"}, null, true); 1608 thisTest.getWc().setItemTextStatus("A/D/G",Status.Kind.deleted); 1609 thisTest.getWc().setItemTextStatus("A/D/G/rho",Status.Kind.deleted); 1610 thisTest.getWc().setItemPropStatus("A/D/G/rho", Status.Kind.none); 1611 thisTest.getWc().setItemTextStatus("A/D/G/pi",Status.Kind.deleted); 1612 thisTest.getWc().setItemTextStatus("A/D/G/tau",Status.Kind.deleted); 1613 client.remove(new String[] {thisTest.getWCPath()+"/A/B/F"}, null, true); 1614 thisTest.getWc().setItemTextStatus("A/B/F",Status.Kind.deleted); 1615 thisTest.getWc().setItemPropStatus("A/B/F", Status.Kind.none); 1616 client.remove(new String[] {thisTest.getWCPath()+"/A/C"}, null, true); 1617 thisTest.getWc().setItemTextStatus("A/C",Status.Kind.deleted); 1618 client.remove(new String[] {thisTest.getWCPath()+"/A/B/X"}, null, true); 1619 file = new File(thisTest.getWorkingCopy(), "iota"); 1620 file.delete(); 1621 client.remove(new String[] {file.getAbsolutePath()}, null, true); 1622 thisTest.getWc().setItemTextStatus("iota",Status.Kind.deleted); 1623 file = new File(thisTest.getWorkingCopy(), "A/D/gamma"); 1624 file.delete(); 1625 client.remove(new String[] {file.getAbsolutePath()}, null, false); 1626 thisTest.getWc().setItemTextStatus("A/D/gamma",Status.Kind.deleted); 1627 client.remove(new String[] {file.getAbsolutePath()}, null, true); 1628 client.remove(new String[] {thisTest.getWCPath()+"/A/B/E"}, null, 1629 false); 1630 thisTest.getWc().removeItem("A/B/X"); 1631 thisTest.getWc().removeItem("A/B/X/xi"); 1632 thisTest.getWc().removeItem("A/C/sigma"); 1633 thisTest.getWc().removeItem("A/C/Q"); 1634 thisTest.checkStatus(); 1635 client.remove(new String[] {thisTest.getWCPath()+"/A/D"},null, true); 1636 thisTest.getWc().setItemTextStatus("A/D", Status.Kind.deleted); 1637 thisTest.getWc().removeItem("A/D/Y"); 1638 1639 // check the status of the working copy 1640 thisTest.checkStatus(); 1641 1642 // confirm that the file are really deleted 1643 assertFalse("failed to remove text modified file", 1644 new File(thisTest.getWorkingCopy(), "A/D/G/rho").exists()); 1645 assertFalse("failed to remove prop modified file", 1646 new File(thisTest.getWorkingCopy(), "A/D/H/chi").exists()); 1647 assertFalse("failed to remove unversioned file", 1648 new File(thisTest.getWorkingCopy(), "A/C/sigma").exists()); 1649 assertFalse("failed to remove unmodified file", 1650 new File(thisTest.getWorkingCopy(), "A/B/E/alpha").exists()); 1651 file = new File(thisTest.getWorkingCopy(),"A/B/F"); 1652 assertFalse("failed to remove versioned dir", file.exists()); 1653 assertFalse("failed to remove unversioned dir", 1654 new File(thisTest.getWorkingCopy(), "A/C/Q").exists()); 1655 assertFalse("failed to remove added dir", 1656 new File(thisTest.getWorkingCopy(), "A/B/X").exists()); 1657 1658 // delete unversioned file foo 1659 file = new File(thisTest.getWCPath(),"foo"); 1660 pw = new PrintWriter(new FileOutputStream(file)); 1661 pw.print("unversioned foo"); 1662 pw.close(); 1663 client.remove(new String[] {file.getAbsolutePath()}, null, true); 1664 assertFalse("failed to remove unversioned file foo", file.exists()); 1665 1666 try 1667 { 1668 // delete non-existent file foo 1669 client.remove(new String[] {file.getAbsolutePath()}, null, true); 1670 fail("missing exception"); 1671 } 1672 catch(ClientException expected) 1673 { 1674 } 1675 1676 // delete file iota in the repository 1677 addExpectedCommitItem(null, thisTest.getUrl(), "iota", NodeKind.none, 1678 CommitItemStateFlags.Delete); 1679 client.remove(new String[] {thisTest.getUrl()+"/iota"}, 1680 "delete iota URL", false); 1681 } 1682 testBasicCheckoutDeleted()1683 public void testBasicCheckoutDeleted() throws Throwable 1684 { 1685 // create working copy 1686 OneTest thisTest = new OneTest(); 1687 1688 // delete A/D and its content 1689 client.remove(new String[] {thisTest.getWCPath()+"/A/D"}, null, true); 1690 thisTest.getWc().setItemTextStatus("A/D", Status.Kind.deleted); 1691 thisTest.getWc().setItemTextStatus("A/D/G", Status.Kind.deleted); 1692 thisTest.getWc().setItemTextStatus("A/D/G/rho", Status.Kind.deleted); 1693 thisTest.getWc().setItemTextStatus("A/D/G/pi", Status.Kind.deleted); 1694 thisTest.getWc().setItemTextStatus("A/D/G/tau", Status.Kind.deleted); 1695 thisTest.getWc().setItemTextStatus("A/D/H", Status.Kind.deleted); 1696 thisTest.getWc().setItemTextStatus("A/D/H/chi", Status.Kind.deleted); 1697 thisTest.getWc().setItemTextStatus("A/D/H/psi", Status.Kind.deleted); 1698 thisTest.getWc().setItemTextStatus("A/D/H/omega", Status.Kind.deleted); 1699 thisTest.getWc().setItemTextStatus("A/D/gamma", Status.Kind.deleted); 1700 1701 // check the working copy status 1702 thisTest.checkStatus(); 1703 1704 // commit the change 1705 addExpectedCommitItem(thisTest.getWCPath(), 1706 thisTest.getUrl(), "A/D", NodeKind.dir, 1707 CommitItemStateFlags.Delete); 1708 assertEquals("wrong revision from commit", 1709 client.commit(new String[]{thisTest.getWCPath()}, "log message", 1710 true),2); 1711 thisTest.getWc().removeItem("A/D"); 1712 thisTest.getWc().removeItem("A/D/G"); 1713 thisTest.getWc().removeItem("A/D/G/rho"); 1714 thisTest.getWc().removeItem("A/D/G/pi"); 1715 thisTest.getWc().removeItem("A/D/G/tau"); 1716 thisTest.getWc().removeItem("A/D/H"); 1717 thisTest.getWc().removeItem("A/D/H/chi"); 1718 thisTest.getWc().removeItem("A/D/H/psi"); 1719 thisTest.getWc().removeItem("A/D/H/omega"); 1720 thisTest.getWc().removeItem("A/D/gamma"); 1721 1722 // check the working copy status 1723 thisTest.checkStatus(); 1724 1725 // check out the previous revision 1726 client.checkout(thisTest.getUrl()+"/A/D", thisTest.getWCPath()+"/new_D", 1727 new Revision.Number(1), true); 1728 } 1729 1730 /** 1731 * Test the basic SVNClient.import functionality. 1732 * @throws Throwable 1733 */ testBasicImport()1734 public void testBasicImport() throws Throwable 1735 { 1736 // create the working copy 1737 OneTest thisTest = new OneTest(); 1738 1739 // create new_file 1740 File file = new File(thisTest.getWCPath(),"new_file"); 1741 PrintWriter pw = new PrintWriter(new FileOutputStream(file)); 1742 pw.print("some text"); 1743 pw.close(); 1744 1745 // import new_file info dirA/dirB/newFile 1746 addExpectedCommitItem(thisTest.getWCPath(), 1747 null, "new_file", NodeKind.none, CommitItemStateFlags.Add); 1748 client.doImport(file.getAbsolutePath(), 1749 thisTest.getUrl()+"/dirA/dirB/new_file", 1750 "log message for new import", true); 1751 1752 // delete new_file 1753 file.delete(); 1754 1755 // update the working 1756 assertEquals("wrong revision from update", 1757 client.update(thisTest.getWCPath(), null, true),2); 1758 thisTest.getWc().addItem("dirA", null); 1759 thisTest.getWc().setItemWorkingCopyRevision("dirA",2); 1760 thisTest.getWc().addItem("dirA/dirB", null); 1761 thisTest.getWc().setItemWorkingCopyRevision("dirA/dirB",2); 1762 thisTest.getWc().addItem("dirA/dirB/new_file", "some text"); 1763 thisTest.getWc().setItemWorkingCopyRevision("dirA/dirB/new_file",2); 1764 1765 // test the working copy status 1766 thisTest.checkStatus(); 1767 } 1768 1769 /** 1770 * Test the basic SVNClient.fileContent functionality. 1771 * @throws Throwable 1772 */ testBasicCat()1773 public void testBasicCat() throws Throwable 1774 { 1775 // create the working copy 1776 OneTest thisTest = new OneTest(); 1777 1778 // modify A/mu 1779 File mu = new File(thisTest.getWorkingCopy(), "A/mu"); 1780 PrintWriter pw = new PrintWriter(new FileOutputStream(mu, true)); 1781 pw.print("some text"); 1782 pw.close(); 1783 // get the content from the repository 1784 byte[] content = client.fileContent(thisTest.getWCPath()+"/A/mu", null); 1785 byte[] testContent = thisTest.getWc().getItemContent("A/mu").getBytes(); 1786 1787 // the content should be the same 1788 assertTrue("content changed", Arrays.equals(content, testContent)); 1789 } 1790 1791 /** 1792 * Test the basic SVNClient.fileContent functionality. 1793 * @throws Throwable 1794 */ testBasicCatStream()1795 public void testBasicCatStream() throws Throwable 1796 { 1797 // create the working copy 1798 OneTest thisTest = new OneTest(); 1799 1800 // modify A/mu 1801 File mu = new File(thisTest.getWorkingCopy(), "A/mu"); 1802 PrintWriter pw = new PrintWriter(new FileOutputStream(mu, true)); 1803 pw.print("some text"); 1804 pw.close(); 1805 // get the content from the repository 1806 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 1807 client.streamFileContent(thisTest.getWCPath() + "/A/mu", null, null, 1808 100, baos); 1809 1810 byte[] content = baos.toByteArray(); 1811 byte[] testContent = thisTest.getWc().getItemContent("A/mu").getBytes(); 1812 1813 // the content should be the same 1814 assertTrue("content changed", Arrays.equals(content, testContent)); 1815 } 1816 1817 /** 1818 * Test the basic SVNClient.list functionality. 1819 * @throws Throwable 1820 */ testBasicLs()1821 public void testBasicLs() throws Throwable 1822 { 1823 // create the working copy 1824 OneTest thisTest = new OneTest(); 1825 1826 // list the repository root dir 1827 DirEntry[] entries = client.list(thisTest.getWCPath(), null, false); 1828 thisTest.getWc().check(entries, "", false); 1829 1830 // list directory A 1831 entries = client.list(thisTest.getWCPath() + "/A", null, false); 1832 thisTest.getWc().check(entries, "A", false); 1833 1834 // list directory A in BASE revision 1835 entries = client.list(thisTest.getWCPath() + "/A", Revision.BASE, 1836 false); 1837 thisTest.getWc().check(entries, "A", false); 1838 1839 // list file A/mu 1840 entries = client.list(thisTest.getWCPath() + "/A/mu", null, false); 1841 thisTest.getWc().check(entries, "A/mu"); 1842 } 1843 1844 /** 1845 * Test the basis SVNClient.add functionality with files that 1846 * should be ignored. 1847 * @throws Throwable 1848 */ testBasicAddIgnores()1849 public void testBasicAddIgnores() throws Throwable 1850 { 1851 // create working copy 1852 OneTest thisTest = new OneTest(); 1853 1854 // create dir 1855 File dir = new File(thisTest.getWorkingCopy(), "dir"); 1856 dir.mkdir(); 1857 1858 // create dir/foo.c 1859 File fileC = new File(dir, "foo.c"); 1860 new FileOutputStream(fileC).close(); 1861 1862 // create dir/foo.o (should be ignored) 1863 File fileO = new File(dir, "foo.o"); 1864 new FileOutputStream(fileO).close(); 1865 1866 // add dir 1867 client.add(dir.getAbsolutePath(), true); 1868 thisTest.getWc().addItem("dir", null); 1869 thisTest.getWc().setItemTextStatus("dir",Status.Kind.added); 1870 thisTest.getWc().addItem("dir/foo.c", ""); 1871 thisTest.getWc().setItemTextStatus("dir/foo.c",Status.Kind.added); 1872 thisTest.getWc().addItem("dir/foo.o", ""); 1873 thisTest.getWc().setItemTextStatus("dir/foo.o",Status.Kind.ignored); 1874 thisTest.getWc().setItemNodeKind("dir/foo.o", NodeKind.unknown); 1875 1876 // test the working copy status 1877 thisTest.checkStatus(); 1878 } 1879 1880 /** 1881 * Test the basis SVNClient.import functionality with files that 1882 * should be ignored. 1883 * @throws Throwable 1884 */ testBasicImportIgnores()1885 public void testBasicImportIgnores() throws Throwable 1886 { 1887 // create working copy 1888 OneTest thisTest = new OneTest(); 1889 1890 // create dir 1891 File dir = new File(thisTest.getWorkingCopy(), "dir"); 1892 dir.mkdir(); 1893 1894 // create dir/foo.c 1895 File fileC = new File(dir, "foo.c"); 1896 new FileOutputStream(fileC).close(); 1897 1898 // create dir/foo.o (should be ignored) 1899 File fileO = new File(dir, "foo.o"); 1900 new FileOutputStream(fileO).close(); 1901 1902 // import dir 1903 addExpectedCommitItem(thisTest.getWCPath(), 1904 null, "dir", NodeKind.none, CommitItemStateFlags.Add); 1905 client.doImport(dir.getAbsolutePath(), thisTest.getUrl()+"/dir", 1906 "log message for import", true); 1907 1908 // remove dir 1909 removeDirOrFile(dir); 1910 1911 // udpate the working copy 1912 assertEquals("wrong revision from update", 2, 1913 client.update(thisTest.getWCPath(), null, true)); 1914 thisTest.getWc().addItem("dir", null); 1915 thisTest.getWc().addItem("dir/foo.c", ""); 1916 1917 // test the working copy status 1918 thisTest.checkStatus(); 1919 } 1920 1921 /** 1922 * Test the basic SVNClient.info functionality. 1923 * @throws Throwable 1924 */ testBasicInfo()1925 public void testBasicInfo() throws Throwable 1926 { 1927 // create the working copy 1928 OneTest thisTest = new OneTest(); 1929 1930 // get the item information and test it 1931 Info info = client.info(thisTest.getWCPath()+"/A/mu"); 1932 assertEquals("wrong revision from info", 1, 1933 info.getLastChangedRevision()); 1934 assertEquals("wrong schedule kind from info", ScheduleKind.normal, 1935 info.getSchedule()); 1936 assertEquals("wrong node kind from info", NodeKind.file, 1937 info.getNodeKind()); 1938 } 1939 1940 /** 1941 * Test the basic SVNClient.logMessages functionality. 1942 * @throws Throwable 1943 */ testBasicLogMessage()1944 public void testBasicLogMessage() throws Throwable 1945 { 1946 // create the working copy 1947 OneTest thisTest = new OneTest(); 1948 1949 // get the commit message of the initial import and test it 1950 LogMessage lm[] = client.logMessages(thisTest.getWCPath(), null, 1951 null, false, true); 1952 assertEquals("wrong number of objects", 1, lm.length); 1953 assertEquals("wrong message", "Log Message", lm[0].getMessage()); 1954 assertEquals("wrong revision", 1, lm[0].getRevisionNumber()); 1955 assertEquals("wrong user", "jrandom", lm[0].getAuthor()); 1956 assertNotNull("changed paths set", lm[0].getChangedPaths()); 1957 ChangePath cp[] = lm[0].getChangedPaths(); 1958 assertEquals("wrong number of chang pathes", 20, cp.length); 1959 assertEquals("wrong path", "/A", cp[0].getPath()); 1960 assertEquals("wrong copy source rev", -1, cp[0].getCopySrcRevision()); 1961 assertNull("wrong copy source path", cp[0].getCopySrcPath()); 1962 assertEquals("wrong action", 'A', cp[0].getAction()); 1963 assertEquals("wrong time with getTimeMicros()", 1964 lm[0].getTimeMicros()/1000, 1965 lm[0].getDate().getTime()); 1966 assertEquals("wrong time with getTimeMillis()", 1967 lm[0].getTimeMillis(), 1968 lm[0].getDate().getTime()); 1969 assertEquals("wrong date with getTimeMicros()", 1970 lm[0].getDate(), 1971 new java.util.Date(lm[0].getTimeMicros()/1000)); 1972 assertEquals("wrong date with getTimeMillis()", 1973 lm[0].getDate(), 1974 new java.util.Date(lm[0].getTimeMillis())); 1975 1976 // Ensure that targets get canonicalized 1977 String non_canonical = thisTest.getUrl().toString() + "/"; 1978 LogMessage lm2[] = client.logMessages(non_canonical, null, 1979 null, false, true); 1980 } 1981 1982 /** 1983 * Test the basic SVNClient.getVersionInfo functionality. 1984 * @throws Throwable 1985 * @since 1.2 1986 */ testBasicVersionInfo()1987 public void testBasicVersionInfo() throws Throwable 1988 { 1989 // create the working copy 1990 OneTest thisTest = new OneTest(); 1991 assertEquals("wrong version info", 1992 "1", 1993 client.getVersionInfo(thisTest.getWCPath(), null, false)); 1994 } 1995 1996 /** 1997 * Test the basic SVNClient locking functionality. 1998 * @throws Throwable 1999 * @since 1.2 2000 */ testBasicLocking()2001 public void testBasicLocking() throws Throwable 2002 { 2003 // build the first working copy 2004 OneTest thisTest = new OneTest(); 2005 2006 client.propertySet(thisTest.getWCPath()+"/A/mu", 2007 PropertyData.NEEDS_LOCK, "*", false); 2008 2009 addExpectedCommitItem(thisTest.getWCPath(), 2010 thisTest.getUrl(), "A/mu",NodeKind.file, 2011 CommitItemStateFlags.PropMods); 2012 assertEquals("bad revision number on commit", 2, 2013 client.commit(new String[] {thisTest.getWCPath()}, 2014 "message", true)); 2015 File f = new File(thisTest.getWCPath()+"/A/mu"); 2016 assertEquals("file should be read only now", false, f.canWrite()); 2017 client.lock(new String[] {thisTest.getWCPath()+"/A/mu"}, 2018 "comment", false); 2019 assertEquals("file should be read write now", true, f.canWrite()); 2020 client.unlock(new String[]{thisTest.getWCPath()+"/A/mu"}, false); 2021 assertEquals("file should be read only now", false, f.canWrite()); 2022 client.lock(new String[]{thisTest.getWCPath()+"/A/mu"}, 2023 "comment", false); 2024 assertEquals("file should be read write now", true, f.canWrite()); 2025 addExpectedCommitItem(thisTest.getWCPath(), 2026 thisTest.getUrl(), "A/mu",NodeKind.file, 2027 0); 2028 assertEquals("rev number from commit", -1, 2029 client.commit(new String[]{thisTest.getWCPath()}, 2030 "message", true)); 2031 assertEquals("file should be read write now", true, f.canWrite()); 2032 2033 try 2034 { 2035 // Attempt to lock an invalid path 2036 client.lock(new String[]{thisTest.getWCPath()+"/A/mu2"}, "comment", 2037 false); 2038 fail("missing exception"); 2039 } 2040 catch (ClientException expected) 2041 { 2042 } 2043 } 2044 2045 /** 2046 * Test the basic SVNClient.info2 functionality. 2047 * @throws Throwable 2048 * @since 1.2 2049 */ testBasicInfo2()2050 public void testBasicInfo2() throws Throwable 2051 { 2052 // build the first working copy 2053 OneTest thisTest = new OneTest(); 2054 2055 final String failureMsg = "Incorrect number of info objects"; 2056 Info2[] infos = client.info2(thisTest.getWCPath(), null, null, false); 2057 assertEquals(failureMsg, 1, infos.length); 2058 infos = client.info2(thisTest.getWCPath(), null, null, true); 2059 assertEquals(failureMsg, 21, infos.length); 2060 for (int i = 0; i < infos.length; i++) 2061 { 2062 Info2 info = infos[i]; 2063 assertNull("Unexpected changelist present", 2064 info.getChangelistName()); 2065 2066 boolean isFile = info.getKind() == NodeKind.file; 2067 assertTrue("Unexpected working file size " + info.getWorkingSize() 2068 + " for '" + info + '\'', 2069 (isFile ? info.getWorkingSize() > -1 : 2070 info.getWorkingSize() == -1)); 2071 // We shouldn't know the repository file size when only 2072 // examining the WC. 2073 assertEquals("Unexpected repos file size for '" + info + '\'', 2074 -1, info.getReposSize()); 2075 2076 // Examine depth 2077 assertEquals("Unexpected depth for '" + info + "'", 2078 (isFile ? Depth.unknown : Depth.infinity), 2079 info.getDepth()); 2080 } 2081 2082 // Create wc with a depth of Depth.empty 2083 String secondWC = thisTest.getWCPath() + ".empty"; 2084 removeDirOrFile(new File(secondWC)); 2085 2086 client.checkout(thisTest.getUrl(), secondWC, null, null, Depth.empty, 2087 false, true); 2088 2089 infos = client.info2(secondWC, null, null, false); 2090 2091 // Examine that depth is Depth.empty 2092 assertEquals(Depth.empty, infos[0].getDepth()); 2093 } 2094 2095 /** 2096 * Test basic changelist functionality. 2097 * @throws Throwable 2098 * @since 1.5 2099 */ testBasicChangelist()2100 public void testBasicChangelist() throws Throwable 2101 { 2102 // build the working copy 2103 OneTest thisTest = new OneTest(); 2104 String changelistName = "changelist1"; 2105 String[] changelists = new String[] { changelistName }; 2106 MyChangelistCallback clCallback = new MyChangelistCallback(); 2107 2108 String[] paths = new String[] 2109 {fileToSVNPath(new File(thisTest.getWCPath(), "iota"), true)}; 2110 // Add a path to a changelist, and check to see if it got added 2111 client.addToChangelist(paths, changelistName, Depth.infinity, null); 2112 String[] cl = new String[1]; 2113 client.getChangelists(thisTest.getWCPath(), changelists, 2114 Depth.infinity, clCallback); 2115 cl[0] = (String) clCallback.get(paths[0]).get(0); 2116 assertTrue(java.util.Arrays.equals(cl, changelists)); 2117 // Does status report this changelist? 2118 Status[] status = client.status(paths[0], false, false, false, false, 2119 false); 2120 assertEquals(status[0].getChangelist(), changelistName); 2121 2122 // Remove the path from the changelist, and check to see if the path is 2123 // actually removed. 2124 client.removeFromChangelists(paths, Depth.infinity, changelists); 2125 clCallback.clear(); 2126 client.getChangelists(thisTest.getWCPath(), changelists, 2127 Depth.infinity, clCallback); 2128 assertTrue(clCallback.isEmpty()); 2129 } 2130 2131 /** 2132 * Helper method for testing mergeinfo retrieval. Assumes 2133 * that <code>targetPath</code> has both merge history and 2134 * available merges. 2135 * @param expectedMergedStart The expected start revision from the 2136 * merge history for <code>mergeSrc</code>. 2137 * @param expectedMergedEnd The expected end revision from the 2138 * merge history for <code>mergeSrc</code>. 2139 * @param expectedAvailableStart The expected start available revision 2140 * from the merge history for <code>mergeSrc</code>. Zero if no need 2141 * to test the available range. 2142 * @param expectedAvailableEnd The expected end available revision 2143 * from the merge history for <code>mergeSrc</code>. 2144 * @param targetPath The path for which to acquire mergeinfo. 2145 * @param mergeSrc The URL from which to consider merges. 2146 */ acquireMergeinfoAndAssertEquals(long expectedMergeStart, long expectedMergeEnd, long expectedAvailableStart, long expectedAvailableEnd, String targetPath, String mergeSrc)2147 private void acquireMergeinfoAndAssertEquals(long expectedMergeStart, 2148 long expectedMergeEnd, 2149 long expectedAvailableStart, 2150 long expectedAvailableEnd, 2151 String targetPath, 2152 String mergeSrc) 2153 throws SubversionException 2154 { 2155 // Verify expected merge history. 2156 Mergeinfo mergeInfo = client.getMergeinfo(targetPath, Revision.HEAD); 2157 assertNotNull("Missing merge info on '" + targetPath + '\'', 2158 mergeInfo); 2159 List ranges = mergeInfo.getRevisions(mergeSrc); 2160 assertTrue("Missing merge info for source '" + mergeSrc + "' on '" + 2161 targetPath + '\'', ranges != null && !ranges.isEmpty()); 2162 RevisionRange range = (RevisionRange) ranges.get(0); 2163 String expectedMergedRevs = expectedMergeStart + "-" + expectedMergeEnd; 2164 assertEquals("Unexpected first merged revision range for '" + 2165 mergeSrc + "' on '" + targetPath + '\'', 2166 expectedMergedRevs, range.toString()); 2167 2168 // Verify expected available merges. 2169 if (expectedAvailableStart > 0) 2170 { 2171 long[] availableRevs = 2172 getMergeinfoRevisions(MergeinfoLogKind.eligible, targetPath, 2173 Revision.HEAD, mergeSrc, 2174 Revision.HEAD); 2175 assertNotNull("Missing eligible merge info on '"+targetPath + '\'', 2176 availableRevs); 2177 assertExpectedMergeRange(expectedAvailableStart, 2178 expectedAvailableEnd, availableRevs); 2179 } 2180 } 2181 2182 /** 2183 * Calls the API to get mergeinfo revisions and returns 2184 * the revision numbers in a sorted array, or null if there 2185 * are no revisions to return. 2186 * @since 1.5 2187 */ 2188 @SuppressWarnings("unchecked") getMergeinfoRevisions(int kind, String pathOrUrl, Revision pegRevision, String mergeSourceUrl, Revision srcPegRevision)2189 private long[] getMergeinfoRevisions(int kind, String pathOrUrl, 2190 Revision pegRevision, 2191 String mergeSourceUrl, 2192 Revision srcPegRevision) 2193 throws SubversionException 2194 { 2195 class Callback implements LogMessageCallback { 2196 2197 List revList = new ArrayList(); 2198 2199 public void singleMessage(ChangePath[] changedPaths, long revision, 2200 Map revprops, boolean hasChildren) { 2201 revList.add(new Long(revision)); 2202 } 2203 2204 public long[] getRevisions() { 2205 long[] revisions = new long[revList.size()]; 2206 int i = 0; 2207 for (Iterator iter = revList.iterator(); iter.hasNext();) { 2208 Long revision = (Long) iter.next(); 2209 revisions[i] = revision.longValue(); 2210 i++; 2211 } 2212 return revisions; 2213 } 2214 } 2215 Callback callback = new Callback(); 2216 client.getMergeinfoLog(kind, pathOrUrl, pegRevision, mergeSourceUrl, 2217 srcPegRevision, false, null, callback); 2218 return callback.getRevisions(); 2219 } 2220 2221 /** 2222 * Append the text <code>toAppend</code> to the WC file at 2223 * <code>path</code>, and update the expected WC state 2224 * accordingly. 2225 * 2226 * @param thisTest The test whose expected WC to tweak. 2227 * @param path The working copy-relative path to change. 2228 * @param toAppend The text to append to <code>path</code>. 2229 * @param rev The expected revision number for thisTest's WC. 2230 * @return The file created during the setup. 2231 * @since 1.5 2232 */ appendText(OneTest thisTest, String path, String toAppend, int rev)2233 private File appendText(OneTest thisTest, String path, String toAppend, 2234 int rev) 2235 throws FileNotFoundException 2236 { 2237 File f = new File(thisTest.getWorkingCopy(), path); 2238 PrintWriter writer = new PrintWriter(new FileOutputStream(f, true)); 2239 writer.print(toAppend); 2240 writer.close(); 2241 if (rev > 0) 2242 { 2243 WC wc = thisTest.getWc(); 2244 wc.setItemWorkingCopyRevision(path, rev); 2245 wc.setItemContent(path, wc.getItemContent(path) + toAppend); 2246 } 2247 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), path, 2248 NodeKind.file, CommitItemStateFlags.TextMods); 2249 return f; 2250 } 2251 2252 /** 2253 * Test the basic functionality of SVNClient.merge(). 2254 * @throws Throwable 2255 * @since 1.2 2256 */ testBasicMerge()2257 public void testBasicMerge() throws Throwable 2258 { 2259 OneTest thisTest = setupAndPerformMerge(); 2260 2261 // Verify that there are now potential merge sources. 2262 String[] suggestedSrcs = 2263 client.suggestMergeSources(thisTest.getWCPath() + "/branches/A", 2264 Revision.WORKING); 2265 assertNotNull(suggestedSrcs); 2266 assertEquals(1, suggestedSrcs.length); 2267 2268 // Test that getMergeinfo() returns null. 2269 assertNull(client.getMergeinfo(new File(thisTest.getWCPath(), "A") 2270 .toString(), Revision.HEAD)); 2271 2272 // Merge and commit some changes (r4). 2273 appendText(thisTest, "A/mu", "xxx", 4); 2274 appendText(thisTest, "A/D/G/rho", "yyy", 4); 2275 assertEquals("wrong revision number from commit", 2276 client.commit(new String[] { thisTest.getWCPath() }, 2277 "log msg", true), 2278 4); 2279 2280 // Add a "begin merge" notification handler. 2281 final Revision[] actualRange = new Revision[2]; 2282 Notify2 notify = new Notify2() 2283 { 2284 public void onNotify(NotifyInformation info) 2285 { 2286 if (info.getAction() == NotifyAction.merge_begin) 2287 { 2288 RevisionRange r = info.getMergeRange(); 2289 actualRange[0] = r.getFromRevision(); 2290 actualRange[1] = r.getToRevision(); 2291 } 2292 } 2293 }; 2294 client.notification2(notify); 2295 2296 // merge changes in A to branches/A 2297 String branchPath = thisTest.getWCPath() + "/branches/A"; 2298 String modUrl = thisTest.getUrl() + "/A"; 2299 // test --dry-run 2300 client.merge(modUrl, new Revision.Number(2), modUrl, Revision.HEAD, 2301 branchPath, false, true, false, true); 2302 assertEquals("Notification of beginning of merge reported incorrect " + 2303 "start revision", new Revision.Number(2), actualRange[0]); 2304 assertEquals("Notification of beginning of merge reported incorrect " + 2305 "end revision", new Revision.Number(4), actualRange[1]); 2306 2307 // now do the real merge 2308 client.merge(modUrl, new Revision.Number(2), modUrl, Revision.HEAD, 2309 branchPath, false, true, false, false); 2310 assertEquals("Notification of beginning of merge reported incorrect " + 2311 "start revision", new Revision.Number(2), actualRange[0]); 2312 assertEquals("Notification of beginning of merge reported incorrect " + 2313 "end revision", new Revision.Number(4), actualRange[1]); 2314 2315 // commit the changes so that we can verify merge 2316 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 2317 "branches/A", NodeKind.dir, 2318 CommitItemStateFlags.PropMods); 2319 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 2320 "branches/A/mu", NodeKind.file, 2321 CommitItemStateFlags.TextMods); 2322 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 2323 "branches/A/D/G/rho", NodeKind.file, 2324 CommitItemStateFlags.TextMods); 2325 assertEquals("wrong revision number from commit", 2326 client.commit(new String[] { thisTest.getWCPath() }, 2327 "log msg", true), 5); 2328 2329 // Merge and commit some more changes (r6). 2330 appendText(thisTest, "A/mu", "xxxr6", 6); 2331 appendText(thisTest, "A/D/G/rho", "yyyr6", 6); 2332 assertEquals("wrong revision number from commit", 2333 client.commit(new String[] { thisTest.getWCPath() }, 2334 "log msg", true), 2335 6); 2336 2337 // Test retrieval of mergeinfo from a WC path. 2338 String targetPath = 2339 new File(thisTest.getWCPath(), "branches/A/mu").getPath(); 2340 final String mergeSrc = thisTest.getUrl() + "/A/mu"; 2341 acquireMergeinfoAndAssertEquals(2, 4, 6, 6, targetPath, mergeSrc); 2342 2343 // Test retrieval of mergeinfo from the repository. 2344 targetPath = thisTest.getUrl() + "/branches/A/mu"; 2345 acquireMergeinfoAndAssertEquals(2, 4, 6, 6, targetPath, mergeSrc); 2346 } 2347 2348 /** 2349 * Test merge with automatic source and revision determination 2350 * (e.g. 'svn merge -g'). 2351 * @throws Throwable 2352 * @since 1.5 2353 */ testMergeUsingHistory()2354 public void testMergeUsingHistory() throws Throwable 2355 { 2356 OneTest thisTest = setupAndPerformMerge(); 2357 2358 // Test that getMergeinfo() returns null. 2359 assertNull(client.getMergeinfo(new File(thisTest.getWCPath(), "A") 2360 .toString(), Revision.HEAD)); 2361 2362 // Merge and commit some changes (r4). 2363 appendText(thisTest, "A/mu", "xxx", 4); 2364 assertEquals("wrong revision number from commit", 2365 client.commit(new String[] { thisTest.getWCPath() }, 2366 "log msg", true), 2367 4); 2368 2369 String branchPath = thisTest.getWCPath() + "/branches/A"; 2370 String modUrl = thisTest.getUrl() + "/A"; 2371 Revision unspec = new Revision(RevisionKind.unspecified); 2372 client.merge(modUrl, Revision.HEAD, 2373 new RevisionRange[] { new RevisionRange(unspec, unspec) }, 2374 branchPath, true, Depth.infinity, false, false, false); 2375 2376 // commit the changes so that we can verify merge 2377 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 2378 "branches/A", NodeKind.dir, 2379 CommitItemStateFlags.PropMods); 2380 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 2381 "branches/A/mu", NodeKind.file, 2382 CommitItemStateFlags.TextMods); 2383 assertEquals("wrong revision number from commit", 2384 client.commit(new String[] { thisTest.getWCPath() }, 2385 "log msg", true), 5); 2386 } 2387 2388 /** 2389 * Test reintegrating a branch with trunk 2390 * (e.g. 'svn merge --reintegrate'). 2391 * @throws Throwable 2392 * @since 1.5 2393 */ testMergeReintegrate()2394 public void testMergeReintegrate() throws Throwable 2395 { 2396 OneTest thisTest = setupAndPerformMerge(); 2397 2398 // Test that getMergeinfo() returns null. 2399 assertNull(client.getMergeinfo(new File(thisTest.getWCPath(), "A") 2400 .toString(), Revision.HEAD)); 2401 2402 // Merge and commit some changes to main (r4). 2403 appendText(thisTest, "A/mu", "xxx", 4); 2404 assertEquals("wrong revision number from main commit", 2405 client.commit(new String[] { thisTest.getWCPath() }, 2406 "log msg", true), 2407 4); 2408 // Merge and commit some changes to branch (r5). 2409 appendText(thisTest, "branches/A/D/G/rho", "yyy", -1); 2410 assertEquals("wrong revision number from branch commit", 2411 client.commit(new String[] { thisTest.getWCPath() }, 2412 "log msg", true), 2413 5); 2414 2415 // update the branch WC (to r5) before merge 2416 client.update(thisTest.getWCPath() + "/branches", Revision.HEAD, true); 2417 2418 String branchPath = thisTest.getWCPath() + "/branches/A"; 2419 String modUrl = thisTest.getUrl() + "/A"; 2420 Revision unspec = new Revision(RevisionKind.unspecified); 2421 client.merge(modUrl, Revision.HEAD, 2422 new RevisionRange[] { new RevisionRange(unspec, unspec) }, 2423 branchPath, true, Depth.infinity, false, false, false); 2424 2425 // commit the changes so that we can verify merge 2426 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 2427 "branches/A", NodeKind.dir, 2428 CommitItemStateFlags.PropMods); 2429 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 2430 "branches/A/mu", NodeKind.file, 2431 CommitItemStateFlags.TextMods); 2432 assertEquals("wrong revision number from commit", 2433 client.commit(new String[] { thisTest.getWCPath() }, 2434 "log msg", true), 6); 2435 2436 // now we --reintegrate the branch with main 2437 String branchUrl = thisTest.getUrl() + "/branches/A"; 2438 try 2439 { 2440 client.mergeReintegrate(branchUrl, Revision.HEAD, 2441 thisTest.getWCPath() + "/A", false); 2442 fail("reintegrate merged into a mixed-revision WC"); 2443 } 2444 catch(ClientException e) 2445 { 2446 // update the WC (to r6) and try again 2447 client.update(thisTest.getWCPath(), Revision.HEAD, true); 2448 client.mergeReintegrate(branchUrl, Revision.HEAD, 2449 thisTest.getWCPath() + "/A", false); 2450 } 2451 // commit the changes so that we can verify merge 2452 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 2453 "A", NodeKind.dir, 2454 CommitItemStateFlags.PropMods); 2455 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 2456 "A/D/G/rho", NodeKind.file, 2457 CommitItemStateFlags.TextMods); 2458 assertEquals("wrong revision number from commit", 2459 client.commit(new String[] { thisTest.getWCPath() }, 2460 "log msg", true), 7); 2461 2462 } 2463 2464 /** 2465 * Test automatic merge conflict resolution. 2466 * @throws Throwable 2467 * @since 1.5 2468 */ testMergeConflictResolution()2469 public void testMergeConflictResolution() throws Throwable 2470 { 2471 // Add a conflict resolution callback which always chooses the 2472 // user's version of a conflicted file. 2473 client.setConflictResolver(new ConflictResolverCallback() 2474 { 2475 public ConflictResult resolve(ConflictDescriptor descrip) 2476 { 2477 return new ConflictResult(ConflictResult.chooseTheirsConflict, 2478 null); 2479 } 2480 }); 2481 2482 OneTest thisTest = new OneTest(); 2483 String originalContents = thisTest.getWc().getItemContent("A/mu"); 2484 String expectedContents = originalContents + "xxx"; 2485 2486 // Merge and commit a change (r2). 2487 File mu = appendText(thisTest, "A/mu", "xxx", 2); 2488 assertEquals("wrong revision number from commit", 2, 2489 client.commit(new String[] { thisTest.getWCPath() }, 2490 "log msg", true)); 2491 2492 // Backdate the WC to the previous revision (r1). 2493 client.update(thisTest.getWCPath(), Revision.getInstance(1), true); 2494 2495 // Prep for a merge conflict by changing A/mu in a different 2496 // way. 2497 mu = appendText(thisTest, "A/mu", "yyy", 1); 2498 2499 // Merge in the previous changes to A/mu (from r2). 2500 RevisionRange[] ranges = new RevisionRange[1]; 2501 ranges[0] = new RevisionRange(new Revision.Number(1), 2502 new Revision.Number(2)); 2503 client.merge(thisTest.getUrl(), Revision.HEAD, ranges, 2504 thisTest.getWCPath(), false, Depth.infinity, false, 2505 false, false); 2506 2507 assertFileContentsEquals("Unexpected conflict resolution", 2508 expectedContents, mu); 2509 } 2510 2511 /** 2512 * Test merge --record-only 2513 * @throws Throwable 2514 * @since 1.5 2515 */ testRecordOnlyMerge()2516 public void testRecordOnlyMerge() throws Throwable 2517 { 2518 OneTest thisTest = setupAndPerformMerge(); 2519 2520 // Verify that there are now potential merge sources. 2521 String[] suggestedSrcs = 2522 client.suggestMergeSources(thisTest.getWCPath() + "/branches/A", 2523 Revision.WORKING); 2524 assertNotNull(suggestedSrcs); 2525 assertEquals(1, suggestedSrcs.length); 2526 2527 // Test that getMergeinfo() returns null. 2528 assertNull(client.getMergeinfo(new File(thisTest.getWCPath(), "A") 2529 .toString(), Revision.HEAD)); 2530 2531 // Merge and commit some changes (r4). 2532 appendText(thisTest, "A/mu", "xxx", 4); 2533 appendText(thisTest, "A/D/G/rho", "yyy", 4); 2534 assertEquals("wrong revision number from commit", 2535 client.commit(new String[] { thisTest.getWCPath() }, 2536 "log msg", true), 2537 4); 2538 2539 // --record-only merge changes in A to branches/A 2540 String branchPath = thisTest.getWCPath() + "/branches/A"; 2541 String modUrl = thisTest.getUrl() + "/A"; 2542 2543 RevisionRange[] ranges = new RevisionRange[1]; 2544 ranges[0] = new RevisionRange(new Revision.Number(2), 2545 new Revision.Number(4)); 2546 client.merge(modUrl, Revision.HEAD, ranges, 2547 branchPath, true, Depth.infinity, false, false, true); 2548 2549 // commit the changes so that we can verify merge 2550 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 2551 "branches/A", NodeKind.dir, 2552 CommitItemStateFlags.PropMods); 2553 assertEquals("wrong revision number from commit", 2554 client.commit(new String[] { thisTest.getWCPath() }, 2555 "log msg", true), 5); 2556 2557 // Test retrieval of mergeinfo from a WC path. 2558 String targetPath = 2559 new File(thisTest.getWCPath(), "branches/A").getPath(); 2560 final String mergeSrc = thisTest.getUrl() + "/A"; 2561 acquireMergeinfoAndAssertEquals(2, 4, 0, 0, targetPath, mergeSrc); 2562 } 2563 2564 /** 2565 * Setup a test with a WC. In the repository, create a 2566 * "/branches" directory, with a branch of "/A" underneath it. 2567 * Update the WC to reflect these modifications. 2568 * @return This test. 2569 */ setupAndPerformMerge()2570 private OneTest setupAndPerformMerge() 2571 throws Exception 2572 { 2573 OneTest thisTest = new OneTest(); 2574 2575 // Verify that there are initially no potential merge sources. 2576 String[] suggestedSrcs = 2577 client.suggestMergeSources(thisTest.getWCPath(), 2578 Revision.WORKING); 2579 assertNotNull(suggestedSrcs); 2580 assertEquals(0, suggestedSrcs.length); 2581 2582 // create branches directory in the repository (r2) 2583 addExpectedCommitItem(null, thisTest.getUrl(), "branches", 2584 NodeKind.none, CommitItemStateFlags.Add); 2585 client.mkdir(new String[]{thisTest.getUrl() + "/branches"}, "log_msg"); 2586 2587 // copy A to branches (r3) 2588 addExpectedCommitItem(null, thisTest.getUrl(), "branches/A", 2589 NodeKind.none, CommitItemStateFlags.Add); 2590 client.copy(thisTest.getUrl() + "/A", thisTest.getUrl() + 2591 "/branches/A", "create A branch", Revision.HEAD); 2592 2593 // update the WC (to r3) so that it has the branches folder 2594 client.update(thisTest.getWCPath(), Revision.HEAD, true); 2595 2596 return thisTest; 2597 } 2598 2599 /** 2600 * Test the {@link SVNClientInterface.diff()} APIs. 2601 * @since 1.5 2602 */ testDiff()2603 public void testDiff() 2604 throws SubversionException, IOException 2605 { 2606 OneTest thisTest = new OneTest(true); 2607 File diffOutput = new File(super.localTmp, thisTest.testName); 2608 final String NL = System.getProperty("line.separator"); 2609 final String sepLine = 2610 "===================================================================" + NL; 2611 final String underSepLine = 2612 "___________________________________________________________________" + NL; 2613 final String expectedDiffBody = 2614 "@@ -1 +1 @@" + NL + 2615 "-This is the file 'iota'." + NL + 2616 "\\ No newline at end of file" + NL + 2617 "+This is the file 'mu'." + NL + 2618 "\\ No newline at end of file" + NL; 2619 2620 final String iotaPath = thisTest.getWCPath().replace('\\', '/') + "/iota"; 2621 final String wcPath = fileToSVNPath(new File(thisTest.getWCPath()), 2622 false); 2623 2624 // make edits to iota 2625 PrintWriter writer = new PrintWriter(new FileOutputStream(iotaPath)); 2626 writer.print("This is the file 'mu'."); 2627 writer.flush(); 2628 writer.close(); 2629 2630 /* 2631 * This test does tests with and without svn:eol-style set to native 2632 * We will first run all of the tests where this does not matter so 2633 * that they are not run twice. 2634 */ 2635 2636 // Two-path diff of URLs. 2637 String expectedDiffOutput = "Index: iota" + NL + sepLine + 2638 "--- iota\t(.../iota)\t(revision 1)" + NL + 2639 "+++ iota\t(.../A/mu)\t(revision 1)" + NL + 2640 expectedDiffBody; 2641 client.diff(thisTest.getUrl() + "/iota", Revision.HEAD, 2642 thisTest.getUrl() + "/A/mu", Revision.HEAD, 2643 diffOutput.getPath(), false, true, true, false); 2644 assertFileContentsEquals("Unexpected diff output in file '" + 2645 diffOutput.getPath() + '\'', 2646 expectedDiffOutput, diffOutput); 2647 2648 // Test relativeToDir fails with urls. */ 2649 try 2650 { 2651 client.diff(thisTest.getUrl() + "/iota", Revision.HEAD, 2652 thisTest.getUrl() + "/A/mu", Revision.HEAD, 2653 thisTest.getUrl(), diffOutput.getPath(), 2654 Depth.infinity, null, true, true, false); 2655 2656 fail("This test should fail because the relativeToDir parameter " + 2657 "does not work with URLs"); 2658 } 2659 catch (Exception ignored) 2660 { 2661 } 2662 2663 /* Testing the expected failure when relativeToDir is not a parent 2664 path of the target. */ 2665 try 2666 { 2667 client.diff(iotaPath, Revision.BASE, iotaPath, Revision.WORKING, 2668 "/non/existent/path", diffOutput.getPath(), 2669 Depth.infinity, null, true, true, false); 2670 2671 fail("This test should fail because iotaPath is not a child of " + 2672 "the relativeToDir parameter"); 2673 } 2674 catch (Exception ignored) 2675 { 2676 } 2677 2678 // Test diff with a relative path on a directory with prop 2679 // changes. 2680 String aPath = fileToSVNPath(new File(thisTest.getWCPath() + "/A"), 2681 false); 2682 2683 expectedDiffOutput = "Index: A" + NL + sepLine + 2684 "--- A\t(revision 1)" + NL + 2685 "+++ A\t(working copy)" + NL + 2686 NL + "Property changes on: A" + NL + 2687 underSepLine + 2688 "Added: testprop" + NL + 2689 "## -0,0 +1 ##" + NL + 2690 "+Test property value." + NL; 2691 2692 client.propertySet(aPath, "testprop", "Test property value." + NL, 2693 false); 2694 client.diff(aPath, Revision.BASE, aPath, Revision.WORKING, wcPath, 2695 diffOutput.getPath(), Depth.infinity, null, true, true, 2696 false); 2697 assertFileContentsEquals("Unexpected diff output in file '" + 2698 diffOutput.getPath() + '\'', 2699 expectedDiffOutput, diffOutput); 2700 2701 // Test diff where relativeToDir and path are the same. 2702 expectedDiffOutput = "Index: ." + NL + sepLine + 2703 "--- .\t(revision 1)" + NL + 2704 "+++ .\t(working copy)" + NL + 2705 NL + "Property changes on: ." + NL + 2706 underSepLine + 2707 "Added: testprop" + NL + 2708 "## -0,0 +1 ##" + NL + 2709 "+Test property value." + NL; 2710 2711 client.propertySet(aPath, "testprop", "Test property value." + NL, 2712 false); 2713 client.diff(aPath, Revision.BASE, aPath, Revision.WORKING, aPath, 2714 diffOutput.getPath(), Depth.infinity, null, true, true, 2715 false); 2716 assertFileContentsEquals("Unexpected diff output in file '" + 2717 diffOutput.getPath() + '\'', 2718 expectedDiffOutput, diffOutput); 2719 2720 2721 /* 2722 * The rest of these tests are run twice. The first time 2723 * without svn:eol-style set and the second time with the 2724 * property set to native. This is tracked by the int named 2725 * operativeRevision. It will have a value = 2 after the 2726 * commit which sets the property 2727 */ 2728 2729 for (int operativeRevision = 1; operativeRevision < 3; operativeRevision++) 2730 { 2731 String revisionPrefix = "While processing operativeRevison=" + operativeRevision + ". "; 2732 String assertPrefix = revisionPrefix + "Unexpected diff output in file '"; 2733 2734 // Undo previous edits to working copy 2735 client.revert(wcPath, true); 2736 2737 if (operativeRevision == 2) { 2738 // Set svn:eol-style=native on iota 2739 client.propertyCreate(iotaPath, "svn:eol-style", "native", false); 2740 String[] paths = new String[] {iotaPath}; 2741 addExpectedCommitItem(thisTest.getWCPath(), 2742 thisTest.getUrl(), "iota",NodeKind.file, 2743 CommitItemStateFlags.PropMods); 2744 client.commit(paths, "Set svn:eol-style to native", false); 2745 } 2746 2747 // make edits to iota and set expected output. 2748 writer = new PrintWriter(new FileOutputStream(iotaPath)); 2749 writer.print("This is the file 'mu'."); 2750 writer.flush(); 2751 writer.close(); 2752 expectedDiffOutput = "Index: " + iotaPath + NL + sepLine + 2753 "--- " + iotaPath + "\t(revision " + operativeRevision + ")" + NL + 2754 "+++ " + iotaPath + "\t(working copy)" + NL + 2755 expectedDiffBody; 2756 2757 try 2758 { 2759 // Two-path diff of WC paths. 2760 client.diff(iotaPath, Revision.BASE, 2761 iotaPath, Revision.WORKING, 2762 diffOutput.getPath(), false, true, true, false); 2763 assertFileContentsEquals(assertPrefix + 2764 diffOutput.getPath() + '\'', 2765 expectedDiffOutput, diffOutput); 2766 diffOutput.delete(); 2767 } 2768 catch (ClientException e) 2769 { 2770 fail(revisionPrefix + e.getMessage()); 2771 } 2772 2773 try 2774 { 2775 // Peg revision diff of a single file. 2776 client.diff(thisTest.getUrl() + "/iota", Revision.HEAD, 2777 new Revision.Number(operativeRevision), Revision.HEAD, 2778 diffOutput.getPath(), false, true, true, false); 2779 assertFileContentsEquals(assertPrefix + 2780 diffOutput.getPath() + '\'', 2781 "", diffOutput); 2782 2783 diffOutput.delete(); 2784 } 2785 catch (ClientException e) 2786 { 2787 fail(revisionPrefix + e.getMessage()); 2788 } 2789 2790 // Test svn diff with a relative path. 2791 expectedDiffOutput = "Index: iota" + NL + sepLine + 2792 "--- iota\t(revision " + operativeRevision + ")" + NL + 2793 "+++ iota\t(working copy)" + NL + 2794 expectedDiffBody; 2795 try 2796 { 2797 client.diff(iotaPath, Revision.BASE, iotaPath, 2798 Revision.WORKING, wcPath, diffOutput.getPath(), 2799 Depth.infinity, null, true, true, false); 2800 assertFileContentsEquals(assertPrefix + 2801 diffOutput.getPath() + '\'', 2802 expectedDiffOutput, diffOutput); 2803 diffOutput.delete(); 2804 } 2805 catch (ClientException e) 2806 { 2807 fail(revisionPrefix + e.getMessage()); 2808 } 2809 2810 try 2811 { 2812 // Test svn diff with a relative path and trailing slash. 2813 client.diff(iotaPath, Revision.BASE, iotaPath, 2814 Revision.WORKING, wcPath + "/", 2815 diffOutput.getPath(), Depth.infinity, null, 2816 true, true, false); 2817 assertFileContentsEquals(assertPrefix + 2818 diffOutput.getPath() + '\'', 2819 expectedDiffOutput, diffOutput); 2820 diffOutput.delete(); 2821 } 2822 catch (ClientException e) 2823 { 2824 fail(revisionPrefix + e.getMessage()); 2825 } 2826 2827 } 2828 2829 } 2830 assertFileContentsEquals(String msg, String expected, File actual)2831 private void assertFileContentsEquals(String msg, String expected, 2832 File actual) 2833 throws IOException 2834 { 2835 FileReader reader = new FileReader(actual); 2836 StringBuffer buf = new StringBuffer(); 2837 int ch; 2838 while ((ch = reader.read()) != -1) 2839 { 2840 buf.append((char) ch); 2841 } 2842 assertEquals(msg, expected, buf.toString()); 2843 } 2844 2845 /** 2846 * Test the {@link SVNClientInterface.diffSummarize()} API. 2847 * @since 1.5 2848 */ testDiffSummarize()2849 public void testDiffSummarize() 2850 throws SubversionException, IOException 2851 { 2852 OneTest thisTest = new OneTest(false); 2853 DiffSummaries summaries = new DiffSummaries(); 2854 // Perform a recursive diff summary, ignoring ancestry. 2855 client.diffSummarize(thisTest.getUrl(), new Revision.Number(0), 2856 thisTest.getUrl(), Revision.HEAD, Depth.infinity, 2857 null, false, summaries); 2858 assertExpectedDiffSummaries(summaries); 2859 2860 summaries.clear(); 2861 // Perform a recursive diff summary with a peg revision, 2862 // ignoring ancestry. 2863 client.diffSummarize(thisTest.getUrl(), Revision.HEAD, 2864 new Revision.Number(0), Revision.HEAD, 2865 Depth.infinity, null, false, summaries); 2866 assertExpectedDiffSummaries(summaries); 2867 } 2868 assertExpectedDiffSummaries(DiffSummaries summaries)2869 private void assertExpectedDiffSummaries(DiffSummaries summaries) 2870 { 2871 assertEquals("Wrong number of diff summary descriptors", 20, 2872 summaries.size()); 2873 2874 // Rigorously inspect one of our DiffSummary notifications. 2875 final String BETA_PATH = "A/B/E/beta"; 2876 DiffSummary betaDiff = (DiffSummary) summaries.get(BETA_PATH); 2877 assertNotNull("No diff summary for " + BETA_PATH, betaDiff); 2878 assertEquals("Incorrect path for " + BETA_PATH, BETA_PATH, 2879 betaDiff.getPath()); 2880 assertTrue("Incorrect diff kind for " + BETA_PATH, 2881 DiffSummary.DiffKind.ADDED.equals(betaDiff.getDiffKind())); 2882 assertEquals("Incorrect props changed notice for " + BETA_PATH, 2883 false, betaDiff.propsChanged()); 2884 assertEquals("Incorrect node kind for " + BETA_PATH, 1, 2885 betaDiff.getNodeKind()); 2886 } 2887 2888 /** 2889 * test the basic SVNClient.isAdminDirectory functionality 2890 * @throws Throwable 2891 * @since 1.2 2892 */ testBasicIsAdminDirectory()2893 public void testBasicIsAdminDirectory() throws Throwable 2894 { 2895 // build the test setup 2896 OneTest thisTest = new OneTest(); 2897 Notify2 notify = new Notify2() 2898 { 2899 public void onNotify(NotifyInformation info) 2900 { 2901 client.isAdminDirectory(".svn"); 2902 } 2903 }; 2904 client.notification2(notify); 2905 // update the test 2906 assertEquals("wrong revision number from update", 2907 client.update(thisTest.getWCPath(), null, true), 1); 2908 } 2909 testBasicCancelOperation()2910 public void testBasicCancelOperation() throws Throwable 2911 { 2912 // build the test setup 2913 OneTest thisTest = new OneTest(); 2914 Notify2 notify = new Notify2() 2915 { 2916 public void onNotify(NotifyInformation info) 2917 { 2918 try 2919 { 2920 client.cancelOperation(); 2921 } 2922 catch (ClientException e) 2923 { 2924 fail(e.getMessage()); 2925 } 2926 } 2927 }; 2928 client.notification2(notify); 2929 // update the test to try to cancel an operation 2930 try 2931 { 2932 client.update(thisTest.getWCPath(), null, true); 2933 fail("missing exception for canceled operation"); 2934 } 2935 catch (ClientException e) 2936 { 2937 // this is expected 2938 } 2939 } 2940 2941 private static class CountingProgressListener implements ProgressListener 2942 { onProgress(ProgressEvent event)2943 public void onProgress(ProgressEvent event) 2944 { 2945 // TODO: Examine the byte counts from "event". 2946 gotProgress = true; 2947 } 2948 public boolean gotProgress = false; 2949 } 2950 testDataTransferProgressReport()2951 public void testDataTransferProgressReport() throws Throwable 2952 { 2953 // ### FIXME: This isn't working over ra_local, because 2954 // ### ra_local is not invoking the progress callback. 2955 if (SVNTests.rootUrl.startsWith("file://")) 2956 return; 2957 2958 // build the test setup 2959 OneTest thisTest = new OneTest(); 2960 CountingProgressListener listener = new CountingProgressListener(); 2961 client.setProgressListener(listener); 2962 2963 // Perform an update to exercise the progress notification. 2964 client.update(thisTest.getWCPath(), null, true); 2965 if (!listener.gotProgress) 2966 fail("No progress reported"); 2967 } 2968 2969 /** 2970 * Test the basic tree conflict functionality. 2971 * @throws Throwable 2972 */ testTreeConflict()2973 public void testTreeConflict() throws Throwable 2974 { 2975 // build the test setup. Used for the changes 2976 OneTest thisTest = new OneTest(); 2977 WC wc = thisTest.getWc(); 2978 2979 // build the backup test setup. That is the one that will be updated 2980 OneTest tcTest = thisTest.copy(".tree-conflict"); 2981 2982 2983 // Move files from A/B/E to A/B/F. 2984 String[] srcPaths = { "alpha" }; 2985 for (int i = 0; i < srcPaths.length; i++) 2986 { 2987 String fileName = srcPaths[i]; 2988 srcPaths[i] = new File(thisTest.getWorkingCopy(), 2989 "A/B/E/" + fileName).getPath(); 2990 2991 wc.addItem("A/B/F/" + fileName, 2992 wc.getItemContent("A/B/E/" + fileName)); 2993 wc.setItemWorkingCopyRevision("A/B/F/" + fileName, 2); 2994 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 2995 "A/B/F/" + fileName, NodeKind.file, 2996 CommitItemStateFlags.Add | 2997 CommitItemStateFlags.IsCopy); 2998 2999 wc.removeItem("A/B/E/" + fileName); 3000 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 3001 "A/B/E/" + fileName, NodeKind.file, 3002 CommitItemStateFlags.Delete); 3003 } 3004 client.move(srcPaths, 3005 new File(thisTest.getWorkingCopy(), "A/B/F").getPath(), 3006 null, false, true, false, null); 3007 3008 // Commit the changes, and check the state of the WC. 3009 assertEquals("Unexpected WC revision number after commit", 3010 client.commit(new String[] { thisTest.getWCPath() }, 3011 "Move files", true), 2); 3012 thisTest.checkStatus(); 3013 3014 // modify A/B/E/alpha in second working copy 3015 File alpha = new File(tcTest.getWorkingCopy(), "A/B/E/alpha"); 3016 PrintWriter alphaWriter = new PrintWriter(new FileOutputStream(alpha, true)); 3017 alphaWriter.print("appended alpha text"); 3018 alphaWriter.close(); 3019 3020 // update the tc test 3021 assertEquals("wrong revision number from update", 3022 client.update(tcTest.getWCPath(), null, true), 3023 2); 3024 3025 // set the expected working copy layout for the tc test 3026 tcTest.getWc().addItem("A/B/F/alpha", 3027 tcTest.getWc().getItemContent("A/B/E/alpha")); 3028 tcTest.getWc().setItemWorkingCopyRevision("A/B/F/alpha", 2); 3029 // we expect the tree conflict to turn the existing item into 3030 // a scheduled-add with history. 3031 tcTest.getWc().setItemTextStatus("A/B/E/alpha", StatusKind.added); 3032 tcTest.getWc().setItemTextStatus("A/B/F/alpha", StatusKind.normal); 3033 3034 // check the status of the working copy of the tc test 3035 tcTest.checkStatus(); 3036 3037 // get the Info2 of the tree conflict 3038 MyInfoCallback callback = new MyInfoCallback(); 3039 client.info2(tcTest.getWCPath() + "/A/B/E/alpha", null, 3040 null, Depth.unknown, null, callback); 3041 ConflictDescriptor conflict = callback.getInfo().getConflictDescriptor(); 3042 3043 assertNotNull("Conflict should not be null", conflict); 3044 3045 assertEquals(conflict.getSrcLeftVersion().getNodeKind(), NodeKind.file); 3046 assertEquals(conflict.getSrcLeftVersion().getReposURL() + "/" + 3047 conflict.getSrcLeftVersion().getPathInRepos(), tcTest.getUrl() + "/A/B/E/alpha"); 3048 assertEquals(conflict.getSrcLeftVersion().getPegRevision(), 1L); 3049 3050 if (conflict.getSrcRightVersion() != null) 3051 { 3052 assertEquals(conflict.getSrcRightVersion().getNodeKind(), NodeKind.none); 3053 assertEquals(conflict.getSrcRightVersion().getReposURL(), tcTest.getUrl()); 3054 assertEquals(conflict.getSrcRightVersion().getPegRevision(), 2L); 3055 } 3056 } 3057 3058 /** 3059 * Test tolerance of unversioned obstructions when adding paths with 3060 * {@link org.tigris.subversion.javahl.SVNClient#checkout()}, 3061 * {@link org.tigris.subversion.javahl.SVNClient#update()}, and 3062 * {@link org.tigris.subversion.javahl.SVNClient#doSwitch()} 3063 * @throws IOException 3064 * @throws SubversionException 3065 */ 3066 /* 3067 This is currently commented out, because we don't have an XFail method 3068 for JavaHL. The resolution is pending the result of issue #3680: 3069 https://issues.apache.org/jira/browse/SVN-3680 3070 public void testObstructionTolerance() 3071 throws SubversionException, IOException 3072 { 3073 // build the test setup 3074 OneTest thisTest = new OneTest(); 3075 3076 File file; 3077 PrintWriter pw; 3078 3079 // ----- TEST CHECKOUT ----- 3080 // Use export to make unversioned obstructions for a second 3081 // WC checkout (deleting export target from previous tests 3082 // first if it exists). 3083 String secondWC = thisTest.getWCPath() + ".backup1"; 3084 removeDirOrFile(new File(secondWC)); 3085 client.doExport(thisTest.getUrl(), secondWC, null, false); 3086 3087 // Make an obstructing file that conflicts with add coming from repos 3088 file = new File(secondWC, "A/B/lambda"); 3089 pw = new PrintWriter(new FileOutputStream(file)); 3090 pw.print("This is the conflicting obstructiong file 'lambda'."); 3091 pw.close(); 3092 3093 // Attempt to checkout backup WC without "--force"... 3094 try 3095 { 3096 // ...should fail 3097 client.checkout(thisTest.getUrl(), secondWC, null, null, 3098 Depth.infinity, false, false); 3099 fail("obstructed checkout should fail by default"); 3100 } 3101 catch (ClientException expected) 3102 { 3103 } 3104 3105 // Attempt to checkout backup WC with "--force" 3106 // so obstructions are tolerated 3107 client.checkout(thisTest.getUrl(), secondWC, null, null, 3108 Depth.infinity, false, true); 3109 3110 // Check the WC status, the only status should be a text 3111 // mod to lambda. All the other obstructing files were identical 3112 Status[] secondWCStatus = client.status(secondWC, true, false, 3113 false, false, false); 3114 if (!(secondWCStatus.length == 1 && 3115 secondWCStatus[0].getPath().endsWith("A/B/lambda") && 3116 secondWCStatus[0].getTextStatus() == StatusKind.modified && 3117 secondWCStatus[0].getPropStatus() == StatusKind.none)) 3118 { 3119 fail("Unexpected WC status after co with " + 3120 "unversioned obstructions"); 3121 } 3122 3123 // Make a third WC to test obstruction tolerance of sw and up. 3124 OneTest backupTest = thisTest.copy(".backup2"); 3125 3126 // ----- TEST UPDATE ----- 3127 // r2: Add a file A/D/H/nu 3128 file = new File(thisTest.getWorkingCopy(), "A/D/H/nu"); 3129 pw = new PrintWriter(new FileOutputStream(file)); 3130 pw.print("This is the file 'nu'."); 3131 pw.close(); 3132 client.add(file.getAbsolutePath(), false); 3133 addExpectedCommitItem(thisTest.getWCPath(), thisTest.getUrl(), 3134 "A/D/H/nu", NodeKind.file, 3135 CommitItemStateFlags.TextMods + 3136 CommitItemStateFlags.Add); 3137 assertEquals("wrong revision number from commit", 3138 client.commit(new String[] {thisTest.getWCPath()}, 3139 "log msg", true), 2); 3140 thisTest.getWc().addItem("A/D/H/nu", "This is the file 'nu'."); 3141 Status status = client.singleStatus(thisTest.getWCPath() + 3142 "/A/D/H/nu", 3143 false); 3144 3145 // Add an unversioned file A/D/H/nu to the backup WC 3146 file = new File(backupTest.getWorkingCopy(), "A/D/H/nu"); 3147 pw = new PrintWriter(new FileOutputStream(file)); 3148 pw.print("This is the file 'nu'."); 3149 pw.close(); 3150 3151 // Attempt to update backup WC without "--force" 3152 try 3153 { 3154 // obstructed update should fail 3155 client.update(backupTest.getWCPath(), null, true); 3156 fail("obstructed update should fail by default"); 3157 } 3158 catch (ClientException expected) 3159 { 3160 } 3161 3162 // Attempt to update backup WC with "--force" 3163 assertEquals("wrong revision from update", 3164 client.update(backupTest.getWCPath(), 3165 null, Depth.infinity, false, false, true), 3166 2); 3167 3168 // ----- TEST SWITCH ----- 3169 // Add an unversioned file A/B/E/nu to the backup WC 3170 // The file differs from A/D/H/nu 3171 file = new File(backupTest.getWorkingCopy(), "A/B/E/nu"); 3172 pw = new PrintWriter(new FileOutputStream(file)); 3173 pw.print("This is yet another file 'nu'."); 3174 pw.close(); 3175 3176 // Add an unversioned file A/B/E/chi to the backup WC 3177 // The file is identical to A/D/H/chi. 3178 file = new File(backupTest.getWorkingCopy(), "A/B/E/chi"); 3179 pw = new PrintWriter(new FileOutputStream(file)); 3180 pw.print("This is the file 'chi'."); 3181 pw.close(); 3182 3183 // Attempt to switch A/B/E to A/D/H without "--force" 3184 try 3185 { 3186 // obstructed switch should fail 3187 client.doSwitch(backupTest.getWCPath() + "/A/B/E", 3188 backupTest.getUrl() + "/A/D/H", 3189 null, true); 3190 fail("obstructed switch should fail by default"); 3191 } 3192 catch (ClientException expected) 3193 { 3194 } 3195 3196 // Complete the switch using "--force" and check the status 3197 client.doSwitch(backupTest.getWCPath() + "/A/B/E", 3198 backupTest.getUrl() + "/A/D/H", 3199 Revision.HEAD, Revision.HEAD, Depth.infinity, 3200 false, false, true); 3201 3202 backupTest.getWc().setItemIsSwitched("A/B/E",true); 3203 backupTest.getWc().removeItem("A/B/E/alpha"); 3204 backupTest.getWc().removeItem("A/B/E/beta"); 3205 backupTest.getWc().addItem("A/B/E/nu", 3206 "This is yet another file 'nu'."); 3207 backupTest.getWc().setItemTextStatus("A/B/E/nu", Status.Kind.modified); 3208 backupTest.getWc().addItem("A/D/H/nu", 3209 "This is the file 'nu'."); 3210 backupTest.getWc().addItem("A/B/E/chi", 3211 backupTest.getWc().getItemContent("A/D/H/chi")); 3212 backupTest.getWc().addItem("A/B/E/psi", 3213 backupTest.getWc().getItemContent("A/D/H/psi")); 3214 backupTest.getWc().addItem("A/B/E/omega", 3215 backupTest.getWc().getItemContent("A/D/H/omega")); 3216 3217 backupTest.checkStatus(); 3218 }*/ 3219 3220 /** 3221 * Test basic blame functionality. This test marginally tests blame 3222 * correctness, mainly just that the blame APIs link correctly. 3223 * @throws Throwable 3224 * @since 1.5 3225 */ testBasicBlame()3226 public void testBasicBlame() throws Throwable 3227 { 3228 OneTest thisTest = new OneTest(); 3229 // Test the old interface to be sure it still works 3230 byte[] result = client.blame(thisTest.getWCPath() + "/iota", Revision 3231 .getInstance(1), Revision.getInstance(1)); 3232 assertEquals(" 1 jrandom This is the file 'iota'.\n", 3233 new String(result)); 3234 3235 // Test the current interface 3236 BlameCallbackImpl callback = new BlameCallbackImpl(); 3237 client.blame(thisTest.getWCPath() + "/iota", Revision.getInstance(1), 3238 Revision.getInstance(1), callback); 3239 assertEquals(1, callback.numberOfLines()); 3240 BlameCallbackImpl.BlameLine line = callback.getBlameLine(0); 3241 if (line != null) 3242 { 3243 assertEquals(1, line.getRevision()); 3244 assertEquals("jrandom", line.getAuthor()); 3245 } 3246 } 3247 3248 /** 3249 * Test commit of arbitrary revprops. 3250 * @throws Throwable 3251 * @since 1.5 3252 */ 3253 @SuppressWarnings("unchecked") testCommitRevprops()3254 public void testCommitRevprops() throws Throwable 3255 { 3256 3257 class RevpropLogCallback implements LogMessageCallback 3258 { 3259 Map revprops; 3260 3261 public void singleMessage(ChangePath[] changedPaths, 3262 long revision, 3263 Map revprops, 3264 boolean hasChildren) 3265 { 3266 this.revprops = revprops; 3267 } 3268 3269 public Map getRevprops() 3270 { 3271 return revprops; 3272 } 3273 } 3274 3275 // build the test setup 3276 OneTest thisTest = new OneTest(); 3277 3278 // modify file A/mu 3279 File mu = new File(thisTest.getWorkingCopy(), "A/mu"); 3280 PrintWriter muWriter = new PrintWriter(new FileOutputStream(mu, true)); 3281 muWriter.print("appended mu text"); 3282 muWriter.close(); 3283 thisTest.getWc().setItemWorkingCopyRevision("A/mu", 2); 3284 thisTest.getWc().setItemContent("A/mu", 3285 thisTest.getWc().getItemContent("A/mu") + "appended mu text"); 3286 addExpectedCommitItem(thisTest.getWCPath(), 3287 thisTest.getUrl(), "A/mu",NodeKind.file, 3288 CommitItemStateFlags.TextMods); 3289 3290 // commit the changes, with some extra revprops 3291 Map revprops = new HashMap(); 3292 revprops.put("kfogel", "rockstar"); 3293 revprops.put("cmpilato", "theman"); 3294 assertEquals("wrong revision number from commit", 3295 client.commit(new String[]{thisTest.getWCPath()}, 3296 "log msg", Depth.infinity, true, true, 3297 null, revprops), 3298 2); 3299 3300 // check the status of the working copy 3301 thisTest.checkStatus(); 3302 3303 // Fetch our revprops from the server 3304 RevpropLogCallback callback = new RevpropLogCallback(); 3305 client.logMessages(thisTest.getWCPath(), Revision.getInstance(2), 3306 Revision.getInstance(2), 3307 Revision.getInstance(2), false, false, false, 3308 new String[] {"kfogel", "cmpilato"}, 0, 3309 callback); 3310 Map fetchedProps = callback.getRevprops(); 3311 3312 assertEquals("wrong number of fetched revprops", revprops.size(), 3313 fetchedProps.size()); 3314 Set keys = fetchedProps.keySet(); 3315 for (Iterator it = keys.iterator(); it.hasNext(); ) 3316 { 3317 String key = (String) it.next(); 3318 assertEquals("revprops check", revprops.get(key), 3319 fetchedProps.get(key)); 3320 } 3321 } 3322 3323 /** 3324 * @return <code>file</code> converted into a -- possibly 3325 * <code>canonical</code>-ized -- Subversion-internal path 3326 * representation. 3327 */ fileToSVNPath(File file, boolean canonical)3328 private String fileToSVNPath(File file, boolean canonical) 3329 { 3330 // JavaHL need paths with '/' separators 3331 if (canonical) 3332 { 3333 try 3334 { 3335 return file.getCanonicalPath().replace('\\', '/'); 3336 } 3337 catch (IOException e) 3338 { 3339 return null; 3340 } 3341 } 3342 else 3343 { 3344 return file.getPath().replace('\\', '/'); 3345 } 3346 } 3347 3348 3349 /** 3350 * A DiffSummaryReceiver implementation which collects all DiffSummary 3351 * notifications. 3352 */ 3353 private static class DiffSummaries extends HashMap 3354 implements DiffSummaryReceiver 3355 { 3356 // Update the serialVersionUID when there is a incompatible 3357 // change made to this class. 3358 private static final long serialVersionUID = 1L; 3359 3360 @SuppressWarnings("unchecked") onSummary(DiffSummary descriptor)3361 public void onSummary(DiffSummary descriptor) 3362 { 3363 super.put(descriptor.getPath(), descriptor); 3364 } 3365 } 3366 3367 private class MyChangelistCallback extends HashMap 3368 implements ChangelistCallback 3369 { 3370 private static final long serialVersionUID = 1L; 3371 3372 @SuppressWarnings("unchecked") doChangelist(String path, String changelist)3373 public void doChangelist(String path, String changelist) 3374 { 3375 path = fileToSVNPath(new File(path), true); 3376 if (super.containsKey(path)) 3377 { 3378 // Append the changelist to the existing list 3379 List changelistList = (List) super.get(path); 3380 changelistList.add(changelist); 3381 } 3382 else 3383 { 3384 // Create a new changelist with that list 3385 List changelistList = new ArrayList(); 3386 changelistList.add(changelist); 3387 super.put(path, changelistList); 3388 } 3389 } 3390 get(String path)3391 public List get(String path) 3392 { 3393 return (List) super.get(path); 3394 } 3395 } 3396 3397 private class MyInfoCallback implements InfoCallback { 3398 private Info2 info; 3399 singleInfo(Info2 info)3400 public void singleInfo(Info2 info) { 3401 this.info = info; 3402 } 3403 getInfo()3404 public Info2 getInfo() { 3405 return info; 3406 } 3407 3408 } 3409 } 3410