1 19 20 package org.openide.text; 21 22 23 import java.beans.PropertyChangeSupport ; 24 import java.io.StringWriter ; 25 import javax.swing.text.*; 26 import junit.framework.AssertionFailedError; 27 import org.netbeans.junit.NbTestCase; 28 import org.openide.ErrorManager.Annotation; 29 import org.openide.util.Exceptions; 30 import org.openide.util.Lookup; 31 import org.openide.util.lookup.*; 32 33 34 38 public class NotifyModifiedTest extends NbTestCase 39 implements CloneableEditorSupport.Env { 40 static { 41 System.setProperty("org.openide.util.Lookup", "org.openide.text.NotifyModifiedTest$Lkp"); 42 } 43 44 45 protected CES support; 46 47 private InstanceContent ic; 48 49 private org.openide.ErrorManager err; 50 51 52 private String content = ""; 54 private boolean valid = true; 55 private volatile boolean modified = false; 56 private java.util.Date date = new java.util.Date (); 57 private PropertyChangeSupport propL = new PropertyChangeSupport (this); 58 private java.beans.VetoableChangeListener vetoL; 59 private boolean shouldVetoNotifyModified; 60 61 private javax.swing.text.EditorKit editorKit; 62 63 64 public NotifyModifiedTest(java.lang.String testName) { 65 super(testName); 66 } 67 68 72 protected void setUp () { 73 ic = new InstanceContent (); 74 support = new CES (this, new AbstractLookup (ic)); 75 76 assertNotNull("ErrManager has to be in lookup", org.openide.util.Lookup.getDefault().lookup(ErrManager.class)); 77 ErrManager.resetMessages(); 78 ErrManager.log = getLog (); 79 80 err = ErrManager.getDefault().getInstance(getName()); 81 } 82 83 protected void runTest () throws Throwable { 84 try { 85 super.runTest (); 86 } catch (AssertionFailedError err) { 87 AssertionFailedError n = new AssertionFailedError (err.getMessage () + "\n" + ErrManager.messages); 88 n.initCause (err); 89 throw n; 90 } 91 } 92 93 97 protected javax.swing.text.EditorKit createEditorKit () { 98 return null; 99 } 100 101 protected void checkThatDocumentLockIsNotHeld () { 102 } 103 104 protected void doesVetoedInsertFireBadLocationException (javax.swing.text.BadLocationException e) { 105 if (e != null) { 106 fail("On non-nblike documents, vetoed insert does not generate BadLocationException"); 107 } 108 } 109 110 114 115 public void testJustOneCallToModified () throws Exception { 116 content = "Line1\nLine2\n"; 117 118 javax.swing.text.Document doc = support.openDocument(); 120 assertEquals ("No modification", 0, support.notifyModified); 121 122 doc.insertString (3, "Ahoj", null); 123 assertEquals ("One modification", 1, support.notifyModified); 124 125 doc.insertString (7, "Kuk", null); 126 assertEquals ("Still one modification", 1, support.notifyModified); 127 128 doc.remove (7, 3); 129 assertEquals ("Still one modification2", 1, support.notifyModified); 130 131 support.saveDocument (); Thread.sleep(300); 132 assertEquals ("Marked unmodified", 1, support.notifyUnmodified); 133 134 doc.remove (0, 1); 135 assertEquals ("Modifies again", 2, support.notifyModified); 136 } 137 138 public void testTheDocumentReturnsBackIfModifyIsNotAllowed () throws Exception { 139 content = "Nic\n"; 140 141 javax.swing.text.Document doc = support.openDocument(); 143 assertEquals ("No modification", 0, support.notifyModified); 144 145 shouldVetoNotifyModified = true; 146 147 try { 149 doc.insertString (0, "Ahoj", null); 150 doesVetoedInsertFireBadLocationException (null); 152 } catch (javax.swing.text.BadLocationException e) { 153 doesVetoedInsertFireBadLocationException (e); 155 } 156 waitEQ (); 157 158 assertEquals ("One modification called (but it was vetoed)", 1, support.notifyModified); 159 assertEquals ("No unmodification called", 0, support.notifyUnmodified); 160 161 String first = doc.getText (0, 1); 162 assertEquals ("First letter is N", "N", first); 163 } 164 165 public void testTheDocumentReturnsBackIfModifyIsNotAllowedMultipleTimes () throws Exception { 166 class R implements Runnable { 167 int[] i = { 0 }; 168 Document[] doc = { null }; 169 170 public void run () { 171 try { 172 if (i[0] % 2 == 0) { 173 doc[0].insertString (0, "Ahoj", null); 174 } else { 175 doc[0].remove (0, 2); 176 } 177 doesVetoedInsertFireBadLocationException (null); 179 } catch (javax.swing.text.BadLocationException e) { 180 doesVetoedInsertFireBadLocationException (e); 182 } 183 } 184 } 185 186 R r = new R (); 187 doTheDocumentReturnsBackIfModifyIsNotAllowedMultipleTimes (r.i, r.doc, r); 188 } 189 190 public void testTheDocumentReturnsBackIfModifyIsNotAllowedMultipleTimesInAtomicSection () throws Exception { 191 class R implements Runnable { 192 int[] i = { 0 }; 193 javax.swing.text.StyledDocument [] doc = { null }; 194 195 private boolean inAtomic; 196 197 public void run () { 198 if (!inAtomic) { 199 inAtomic = true; 200 NbDocument.runAtomic(doc[0], this); 201 inAtomic = false; 202 } else { 203 try { 204 doc[0].insertString (0, "Ahoj", null); 205 } catch (javax.swing.text.BadLocationException e) { 206 fail ("Inside atomic no BadLocationException due to unmodifiable source"); 207 } 208 } 209 } 210 } 211 212 R r = new R (); 213 doTheDocumentReturnsBackIfModifyIsNotAllowedMultipleTimes (r.i, r.doc, r); 214 } 215 216 217 private void doTheDocumentReturnsBackIfModifyIsNotAllowedMultipleTimes (int[] i, Document[] doc, Runnable op) throws Exception { 218 content = "EmptyContentForTheDocument\n"; 219 220 doc[0] = support.openDocument(); 222 assertEquals ("No modification", 0, support.notifyModified); 223 224 shouldVetoNotifyModified = true; 225 226 for (i[0] = 0; i[0] < 10; i[0]++) { 227 op.run (); 229 waitEQ (); 230 231 support.assertModified (false, "Is still unmodified"); 232 } 233 234 String first = doc[0].getText (0, doc[0].getLength ()); 235 if (!first.equals (content)) { 236 fail ("Expected: " + content + 237 " but was: " + first); 238 } 239 240 assertEquals ("Five vetoed modifications", 10, support.notifyModified); 241 assertEquals ("No unmodification called", 0, support.notifyUnmodified); 242 } 243 244 245 public void testBadLocationException () throws Exception { 246 content = "Nic\n"; 247 248 javax.swing.text.Document doc = support.openDocument(); 250 assertEquals ("No modification", 0, support.notifyModified); 251 252 try { 253 doc.insertString (10, "Ahoj", null); 254 fail ("This should generate bad location exception"); 255 } catch (javax.swing.text.BadLocationException ex) { 256 } 258 259 int expected = createEditorKit () instanceof NbLikeEditorKit ? 1 : 0; 260 assertEquals (expected + " modification called (but it was vetoed)", expected, support.notifyModified); 261 assertEquals (expected + " unmodification called", expected, support.notifyUnmodified); 262 263 String first = doc.getText (0, 1); 264 assertEquals ("First letter is N", "N", first); 265 } 266 267 public void testDoModificationsInAtomicBlock () throws Exception { 268 content = "Something"; 269 270 final javax.swing.text.StyledDocument doc = support.openDocument(); 271 272 273 class R implements Runnable { 274 public void run () { 275 try { 276 doc.insertString (0, "Ahoj", null); 277 } catch (javax.swing.text.BadLocationException ex) { 278 AssertionFailedError e = new AssertionFailedError (ex.getMessage ()); 279 e.initCause (ex); 280 throw e; 281 } 282 } 283 } 284 285 R r = new R (); 286 287 NbDocument.runAtomic (doc, r); 288 289 assertEquals ("One modification", 1, support.notifyModified); 290 assertEquals ("no unmod", 0, support.notifyUnmodified); 291 } 292 293 public void testDoModificationsInAtomicBlockAndRefuseThem () throws Exception { 294 content = "Something"; 295 296 final javax.swing.text.StyledDocument doc = support.openDocument(); 297 298 shouldVetoNotifyModified = true; 299 300 class R implements Runnable { 301 public boolean gotIntoRunnable; 302 303 public void run () { 304 gotIntoRunnable = true; 305 306 try { 307 doc.insertString (0, "Ahoj", null); 308 doc.remove (0, 1); 309 doc.remove (0, 1); 310 } catch (javax.swing.text.BadLocationException ex) { 311 AssertionFailedError e = new AssertionFailedError (ex.getMessage ()); 312 e.initCause (ex); 313 throw e; 314 } 315 } 316 } 317 318 R r = new R (); 319 320 NbDocument.runAtomic (doc, r); 321 waitEQ (); 322 323 324 assertTrue ("Runable started", r.gotIntoRunnable); 325 326 if (support.notifyModified == 0) { 327 fail ("At least One notification expected"); 328 } 329 assertEquals ("no unmod", 0, support.notifyUnmodified); 330 331 support.assertModified (false, "Document is not modified"); 332 333 String text = doc.getText (0, doc.getLength ()); 334 assertEquals ("The text is the same as original content", content, text); 335 } 336 337 public void testRevertModificationAfterSave () throws Exception { 338 content = "Ahoj"; 339 340 final javax.swing.text.StyledDocument doc = support.openDocument(); 341 342 doc.insertString (4, " Jardo", null); 343 doc.insertString (0, ":", null); 344 345 String text = doc.getText (0, doc.getLength ()); 346 347 support.saveDocument (); Thread.sleep(300); 348 support.assertModified (false, "Not modified"); 349 350 shouldVetoNotifyModified = true; 351 try { 352 doc.remove (0, 5); 353 doesVetoedInsertFireBadLocationException (null); 354 } catch (BadLocationException ex) { 355 doesVetoedInsertFireBadLocationException (ex); 356 } 357 waitEQ (); 358 359 support.assertModified (false, "Not modified"); 360 361 text = doc.getText (0, doc.getLength ()); 362 if (!":Ahoj Jardo".equals (text)) { 363 fail ("The text as after save ':Ahoj Jardo' but was: " + text); 364 } 365 } 366 367 public void testAtomicBlockWithoutModifications () throws Exception { 368 content = "Something"; 369 370 final javax.swing.text.StyledDocument doc = support.openDocument(); 371 372 class R implements Runnable { 373 public void run () { 374 } 375 } 376 377 R r = new R (); 378 379 NbDocument.runAtomic (doc, r); 380 381 assertEquals ("The same number of modification and unmodifications", support.notifyModified, support.notifyUnmodified); 382 assertEquals ("Actually it is zero", 0, support.notifyUnmodified); 383 } 384 385 public void testDoInsertAfterEmptyBlock () throws Exception { 386 testAtomicBlockWithoutModifications (); 387 388 support.getDocument ().insertString (0, "Ahoj", null); 389 390 assertEquals ("One modification now", 1, support.notifyModified); 391 assertEquals ("No unmodified", 0, support.notifyUnmodified); 392 support.assertModified (true, "Is modified"); 393 } 394 395 public void testDoRemoveAfterEmptyBlock () throws Exception { 396 testAtomicBlockWithoutModifications (); 397 398 support.getDocument ().remove (0, 4); 399 400 assertEquals ("One modification now", 1, support.notifyModified); 401 assertEquals ("No unmodified", 0, support.notifyUnmodified); 402 support.assertModified (true, "Is modified"); 403 } 404 405 public void testAtomicBlockWithoutModificationsAfterInsert () throws Exception { 406 doAtomicBlockWithoutModificationsAfterInsert (false, 1); 407 } 408 public void testAtomicBlockWithoutModificationsAfterInsertDouble () throws Exception { 409 doAtomicBlockWithoutModificationsAfterInsert (false, 2); 410 } 411 public void testAtomicUserBlockWithoutModificationsAfterInsert () throws Exception { 412 doAtomicBlockWithoutModificationsAfterInsert (true, 1); 413 } 414 public void testAtomicUserBlockWithoutModificationsAfterInsertDouble () throws Exception { 415 doAtomicBlockWithoutModificationsAfterInsert (true, 2); 416 } 417 418 private void doAtomicBlockWithoutModificationsAfterInsert (final boolean asUser, final int cnt) throws Exception { 419 content = "Something"; 420 421 final javax.swing.text.StyledDocument doc = support.openDocument(); 422 423 doc.insertString(0, "Ahoj", null); 424 425 class R implements Runnable { 426 427 public int counter = cnt; 428 429 public void run () { 430 if (--counter > 0) { 431 if (asUser) { 432 try { 433 NbDocument.runAtomicAsUser(doc, this); 434 } catch (javax.swing.text.BadLocationException ex) { 435 throw (AssertionFailedError)new AssertionFailedError (ex.getMessage()).initCause(ex); 436 } 437 } else { 438 NbDocument.runAtomic(doc, this); 439 } 440 } 441 } 442 } 443 444 R r = new R (); 445 446 support.assertModified (true, "Document must be modified"); 447 448 if (asUser) { 449 NbDocument.runAtomicAsUser(doc, r); 450 } else { 451 NbDocument.runAtomic (doc, r); 452 } 453 454 support.assertModified (true, "Document must stay modified"); 455 } 456 457 public void testUndoDoesMarkFileAsDirtyIssue56963 () throws Exception { 458 content = "Somecontent"; 459 460 err.log("Going to open"); 461 final javax.swing.text.StyledDocument doc = support.openDocument(); 462 err.log("Opened: " + doc); 463 464 int len = doc.getLength (); 465 466 assertEquals ("Content opened", "Somecontent", doc.getText (0, len)); 467 468 err.log("Going to remove " + len + " characters"); 469 doc.remove (0, len); 470 err.log("Removed");Thread.sleep(300); 471 472 assertEquals ("Empty", 0, doc.getLength ()); 473 assertTrue ("Can undo", support.getUndoRedo ().canUndo ()); 474 475 err.log("Going to save"); 476 support.saveDocument (); Thread.sleep(300); 477 waitEQ (); 478 err.log("Saved"); 479 480 assertTrue ("Can undo as well", support.getUndoRedo ().canUndo ()); 481 482 err.log("Going to undo"); 483 support.getUndoRedo ().undo (); 484 waitEQ (); 485 err.log("Undoed"); 486 487 assertEquals ("Lengh it back", len, doc.getLength ()); 488 assertEquals ("Content is back", "Somecontent", doc.getText (0, len)); 489 490 err.log("Before assertModified"); 491 support.assertModified (true, "Document is Modified"); 492 493 err.log("Before redo"); 494 support.getUndoRedo ().redo (); 495 waitEQ (); 496 err.log("After redo"); 497 498 assertEquals ("Zero length", 0, doc.getLength ()); 499 500 support.assertModified (false, "Document is UnModified"); 501 } 502 503 public void testReloadWithoutModifiedIssue57104 () throws Exception { 504 content = "Somecontent"; 505 506 final javax.swing.text.StyledDocument doc = support.openDocument(); 507 508 int len = doc.getLength (); 509 510 assertEquals ("Content opened", "Somecontent", doc.getText (0, len)); 511 512 doc.remove (0, len); 513 514 assertEquals ("Empty", 0, doc.getLength ()); 515 assertTrue ("Can undo", support.getUndoRedo ().canUndo ()); 516 517 support.saveDocument (); Thread.sleep(300); 518 waitEQ (); 519 520 assertTrue ("Can undo as well", support.getUndoRedo ().canUndo ()); 521 522 523 content = "Newcontent"; 524 int newLen = content.length (); 525 526 assertEquals ("Once modified", 1, support.notifyModified); 527 assertEquals ("Once unmodified after save", 1, support.notifyUnmodified); 528 529 propL.firePropertyChange (PROP_TIME, null, null); 530 waitEQ (); 531 532 Object newDoc = support.openDocument (); 533 assertSame ("Reload does not change the document", newDoc, doc); 534 535 assertEquals ("Length it new", newLen, doc.getLength ()); 536 assertEquals ("Content is new", "Newcontent", doc.getText (0, newLen)); 537 538 assertEquals ("Still one modified", 1, support.notifyModified); 539 assertEquals ("Still one unmodified", 1, support.notifyUnmodified); 540 } 541 542 public void testUndoMarksFileUnmodified () throws Exception { 543 content = "Somecontent"; 544 545 final javax.swing.text.StyledDocument doc = support.openDocument(); 546 547 int len = doc.getLength (); 548 549 assertEquals ("Content opened", "Somecontent", doc.getText (0, len)); 550 551 doc.remove (0, len); 552 553 support.assertModified (true, "Document is modified"); 554 assertTrue ("Can undo", support.getUndoRedo ().canUndo ()); 555 556 support.getUndoRedo ().undo (); 557 558 support.assertModified (false, "Document is unmodified"); 559 } 560 561 public void testReloadWhenModifiedIssue57104 () throws Exception { 562 content = "Somecontent"; 563 564 final javax.swing.text.StyledDocument doc = support.openDocument(); 565 566 int len = doc.getLength (); 567 568 assertEquals ("Content opened", "Somecontent", doc.getText (0, len)); 569 570 err.log("wait so first modification really happens later in time then the lastSaveTime is set to"); 571 Thread.sleep(300); 572 573 doc.remove (0, len); 574 575 err.log("After remove"); 576 assertEquals ("Empty", 0, doc.getLength ()); 577 assertTrue ("Can undo", support.getUndoRedo ().canUndo ()); 578 579 err.log("Before save"); 580 Thread.sleep(300); support.saveDocument (); Thread.sleep(300); 581 waitEQ (); 582 err.log("After save"); 583 584 assertTrue ("Can undo as well", support.getUndoRedo ().canUndo ()); 585 assertEquals ("Once modified", 1, support.notifyModified); 586 assertEquals ("Once unmodified after save", 1, support.notifyUnmodified); 587 588 err.log("Before undo"); 589 support.getUndoRedo ().undo (); 590 waitEQ (); 591 err.log("After undo"); 592 593 assertEquals ("Lengh it back", len, doc.getLength ()); 594 assertEquals ("Content is back", "Somecontent", doc.getText (0, len)); 595 596 waitEQ (); 597 support.assertModified (true, "Document is Modified"); 598 599 assertEquals ("One more modified", 2, support.notifyModified); 600 assertEquals ("No unmodifications", 1, support.notifyUnmodified); 601 602 603 content = "Newcontent"; 604 int newLen = content.length (); 605 606 propL.firePropertyChange (PROP_TIME, null, null); 608 waitEQ (); 610 611 Object newDoc = support.openDocument (); 612 assertSame ("Reload does not change the document", newDoc, doc); 613 614 assertEquals ("Length it new", newLen, doc.getLength ()); 615 assertEquals ("Content is new", "Newcontent", doc.getText (0, newLen)); 616 617 assertEquals ("No more modified", 2, support.notifyModified); 618 assertEquals ("But one more unmodified", 2, support.notifyUnmodified); 619 } 620 621 private void waitEQ () throws Exception { 622 for (int i = 0; i < 5; i++) { 624 javax.swing.SwingUtilities.invokeAndWait (new Runnable () { public void run () { } }); 625 } 626 } 627 628 632 public synchronized void addPropertyChangeListener(java.beans.PropertyChangeListener l) { 633 propL.addPropertyChangeListener (l); 634 } 635 public synchronized void removePropertyChangeListener(java.beans.PropertyChangeListener l) { 636 propL.removePropertyChangeListener (l); 637 } 638 639 public synchronized void addVetoableChangeListener(java.beans.VetoableChangeListener l) { 640 assertNull ("This is the first veto listener", vetoL); 641 vetoL = l; 642 } 643 public void removeVetoableChangeListener(java.beans.VetoableChangeListener l) { 644 assertEquals ("Removing the right veto one", vetoL, l); 645 vetoL = null; 646 } 647 648 public org.openide.windows.CloneableOpenSupport findCloneableOpenSupport() { 649 return support; 650 } 651 652 public String getMimeType() { 653 return "text/plain"; 654 } 655 656 public java.util.Date getTime() { 657 return date; 658 } 659 660 public java.io.InputStream inputStream() throws java.io.IOException { 661 return new java.io.ByteArrayInputStream (content.getBytes ()); 662 } 663 public java.io.OutputStream outputStream() throws java.io.IOException { 664 class ContentStream extends java.io.ByteArrayOutputStream { 665 public void close () throws java.io.IOException { 666 super.close (); 667 content = new String (toByteArray ()); 668 } 669 } 670 671 return new ContentStream (); 672 } 673 674 public boolean isValid() { 675 return valid; 676 } 677 678 public boolean isModified() { 679 return modified; 680 } 681 682 public void markModified() throws java.io.IOException { 683 modified = true; 684 checkThatDocumentLockIsNotHeld (); 686 } 687 688 public void unmarkModified() { 689 modified = false; 690 checkThatDocumentLockIsNotHeld (); 692 } 693 694 695 protected final class CES extends CloneableEditorSupport { 696 public int notifyUnmodified; 697 public int notifyModified; 698 699 public CES (Env env, Lookup l) { 700 super (env, l); 701 } 702 703 protected String messageName() { 704 return "Name"; 705 } 706 707 protected String messageOpened() { 708 return "Opened"; 709 } 710 711 protected String messageOpening() { 712 return "Opening"; 713 } 714 715 protected String messageSave() { 716 return "Save"; 717 } 718 719 protected String messageToolTip() { 720 return "ToolTip"; 721 } 722 723 protected void notifyUnmodified () { 724 notifyUnmodified++; 725 Exceptions.printStackTrace(new java.lang.Exception ("notifyUnmodified: " + 726 notifyUnmodified)); 727 728 super.notifyUnmodified(); 729 } 730 731 protected boolean notifyModified () { 732 notifyModified++; 733 734 if (shouldVetoNotifyModified) { 735 return false; 736 } 737 738 Exceptions.printStackTrace(new java.lang.Exception ("notifyModified: " + 739 notifyModified)); 740 741 boolean retValue; 742 retValue = super.notifyModified(); 743 return retValue; 744 } 745 746 protected javax.swing.text.EditorKit createEditorKit() { 747 javax.swing.text.EditorKit k = NotifyModifiedTest.this.createEditorKit (); 748 if (k != null) { 749 return k; 750 } 751 return super.createEditorKit (); 752 } 753 754 public void assertModified (boolean modified, String msg) { 755 assertEquals (msg, modified, isModified ()); 756 } 757 } 758 759 public static final class Lkp extends org.openide.util.lookup.AbstractLookup { 760 public Lkp() { 761 this(new org.openide.util.lookup.InstanceContent()); 762 } 763 764 private Lkp(org.openide.util.lookup.InstanceContent ic) { 765 super(ic); 766 ic.add(new ErrManager()); 767 } 768 } 769 770 private static final class ErrManager extends org.openide.ErrorManager { 771 static final StringBuffer messages = new StringBuffer (); 772 static int nOfMessages; 773 static final String DELIMITER = ": "; 774 static final String WARNING_MESSAGE_START = WARNING + DELIMITER; 775 776 static java.io.PrintStream log = System.err; 777 778 private String prefix; 779 780 public ErrManager () { 781 prefix = ""; 782 } 783 784 private ErrManager (String pr) { 785 this.prefix = pr; 786 } 787 788 static void resetMessages() { 789 messages.delete(0, ErrManager.messages.length()); 790 nOfMessages = 0; 791 } 792 793 public void log(int severity, String s) { 794 synchronized (ErrManager.messages) { 795 nOfMessages++; 796 messages.append('['); log.print ('['); 797 messages.append(prefix); log.print (prefix); 798 messages.append("] - "); log.print ("] - "); 799 messages.append(s); log.println (s); 800 messages.append('\n'); 801 } 802 } 803 804 public Throwable annotate(Throwable t, int severity, 805 String message, String localizedMessage, 806 Throwable stackTrace, java.util.Date date) { 807 return t; 808 } 809 810 public Throwable attachAnnotations(Throwable t, Annotation[] arr) { 811 return t; 812 } 813 814 public org.openide.ErrorManager.Annotation[] findAnnotations(Throwable t) { 815 return null; 816 } 817 818 public org.openide.ErrorManager getInstance(String name) { 819 return new ErrManager (name); 820 } 821 822 public void notify(int severity, Throwable t) { 823 StringWriter w = new StringWriter (); 824 t.printStackTrace (new java.io.PrintWriter (w)); 825 log (severity, w.toString ()); 826 } 827 } 828 } 829 | Popular Tags |