1 19 20 package org.netbeans.editor; 21 22 import java.util.ArrayList ; 23 import java.util.List ; 24 import java.util.Random ; 25 import javax.swing.event.DocumentEvent ; 26 import javax.swing.event.DocumentListener ; 27 import javax.swing.text.BadLocationException ; 28 import javax.swing.text.Document ; 29 import javax.swing.text.Element ; 30 import javax.swing.text.PlainDocument ; 31 import javax.swing.text.Position ; 32 import javax.swing.undo.UndoManager ; 33 import junit.framework.TestCase; 34 35 41 public class PlainDocumentCompatibilityRandomTest extends TestCase 42 implements DocumentListener { 43 44 private static final boolean debug = false; 45 private static final boolean debugLines = false; 46 47 private static final int OP_COUNT_1 = 10000; 48 private static final int INSERT_RATIO_1 = 100; 49 private static final int INSERT_MAX_LENGTH_1 = 10; 50 private static final float INSERT_NL_RATIO_1 = 0.5f; 51 private static final int REMOVE_RATIO_1 = 70; 52 private static final int REMOVE_MAX_LENGTH_1 = 10; 53 private static final int CREATE_POSITION_RATIO_1 = 0; 56 private static final int RELEASE_POSITION_RATIO_1 = 20; 57 private static final int UNDO_RATIO_1 = 30; 58 private static final int UNDO_MAX_COUNT_1 = 5; 59 private static final int REDO_RATIO_1 = 30; 60 private static final int REDO_MAX_COUNT_1 = 5; 61 62 private static final int OP_COUNT_2 = 10000; 63 private static final int INSERT_RATIO_2 = 70; 64 private static final int INSERT_MAX_LENGTH_2 = 10; 65 private static final float INSERT_NL_RATIO_2 = 0.2f; 66 private static final int REMOVE_RATIO_2 = 100; 67 private static final int REMOVE_MAX_LENGTH_2 = 10; 68 private static final int CREATE_POSITION_RATIO_2 = 0; 71 private static final int RELEASE_POSITION_RATIO_2 = 40; 72 private static final int UNDO_RATIO_2 = 30; 73 private static final int UNDO_MAX_COUNT_2 = 5; 74 private static final int REDO_RATIO_2 = 30; 75 private static final int REDO_MAX_COUNT_2 = 5; 76 77 private PlainDocument masterDoc; 78 79 private BaseDocument testDoc; 80 81 private DocumentEvent masterEvent; 82 83 private List masterPositions = new ArrayList (); 84 85 private List testPositions = new ArrayList (); 86 87 private UndoManager masterUndoManager = new UndoManager (); 88 89 private UndoManager testUndoManager = new UndoManager (); 90 91 public PlainDocumentCompatibilityRandomTest(String testName) { 92 super(testName); 93 } 94 95 public void test() { 96 testFresh(0); 97 } 98 99 public void testFresh(long seed) { 100 if (seed == 0) { 101 seed = System.currentTimeMillis(); 102 System.err.println("Chosen SEED=" + seed); 103 } 104 Random random = new Random (seed); 105 106 107 if (debug) { 108 System.err.println("TESTING with SEED=" + seed); 109 } 110 111 masterDoc = new PlainDocument (); 112 testDoc = new BaseDocument(BaseKit.class, false); 113 114 masterDoc.addDocumentListener(this); 116 testDoc.addDocumentListener(this); 117 118 masterDoc.addUndoableEditListener(masterUndoManager); 120 testDoc.addUndoableEditListener(testUndoManager); 121 122 testRound(random, OP_COUNT_1, 123 INSERT_RATIO_1, INSERT_MAX_LENGTH_1, INSERT_NL_RATIO_1, 124 REMOVE_RATIO_1, REMOVE_MAX_LENGTH_1, 125 CREATE_POSITION_RATIO_1, RELEASE_POSITION_RATIO_1, 126 UNDO_RATIO_1, UNDO_MAX_COUNT_1, 127 REDO_RATIO_1, REDO_MAX_COUNT_1 128 ); 129 130 testRound(random, OP_COUNT_2, 131 INSERT_RATIO_2, INSERT_MAX_LENGTH_2, INSERT_NL_RATIO_2, 132 REMOVE_RATIO_2, REMOVE_MAX_LENGTH_2, 133 CREATE_POSITION_RATIO_2, RELEASE_POSITION_RATIO_2, 134 UNDO_RATIO_2, UNDO_MAX_COUNT_2, 135 REDO_RATIO_2, REDO_MAX_COUNT_2 136 ); 137 138 masterDoc.removeUndoableEditListener(masterUndoManager); 140 testDoc.removeUndoableEditListener(testUndoManager); 141 142 masterUndoManager.discardAllEdits(); 144 testUndoManager.discardAllEdits(); 145 146 masterDoc.removeDocumentListener(this); 148 testDoc.removeDocumentListener(this); 149 } 150 151 private void testRound(Random random, int opCount, 152 int insertRatio, int insertMaxLength, float insertNlRatio, 153 int removeRatio, int removeMaxLength, 154 int createPositionRatio, int releasePositionRatio, 155 int undoRatio, int undoMaxCount, 156 int redoRatio, int redoMaxCount) { 157 158 int ratioSum = insertRatio + removeRatio 159 + createPositionRatio + releasePositionRatio 160 + undoRatio + redoRatio; 161 162 for (int op = 0; op < opCount; op++) { 163 double r = random.nextDouble() * ratioSum; 164 int docLength = masterDoc.getLength(); 165 166 if (debugLines) { 167 System.err.println("LINES:\n" + linesToString()); 168 } 169 170 if ((r -= insertRatio) < 0) { 171 int offset = (int)((docLength + 1) * random.nextDouble()); 172 int length = (int)(insertMaxLength * random.nextDouble()); 173 StringBuffer sb = new StringBuffer (); 174 StringBuffer debugSb = debug ? new StringBuffer () : null; 175 176 for (int i = length - 1; i >= 0; i--) { 177 char ch; 178 if (random.nextDouble() < insertNlRatio) { ch = '\n'; 180 if (debug) { 181 debugSb.append("\\n"); 182 } 183 184 } else { ch = (char)('a' + (int)(26 * random.nextDouble())); 186 if (debug) { 187 debugSb.append(ch); 188 } 189 } 190 sb.append(ch); 191 } 192 if (debug) { 193 debugOp(op, "insertString(" + offset + ", \"" + debugSb + "\")"); 194 } 195 196 try { 197 masterDoc.insertString(offset, sb.toString(), null); 198 testDoc.insertString(offset, sb.toString(), null); 199 testDoc.resetUndoMerge(); 201 } catch (BadLocationException e) { 202 throw new RuntimeException (e); 203 } 204 205 206 } else if ((r -= removeRatio) < 0) { 207 int offset = (int)((docLength + 1) * random.nextDouble()); 208 int length = (int)(removeMaxLength * random.nextDouble()); 209 length = Math.min(length, docLength - offset); 210 211 if (debug) { 212 debugOp(op, "remove(" + offset + ", " + length + ")"); 213 } 214 215 try { 216 masterDoc.remove(offset, length); 217 testDoc.remove(offset, length); 218 testDoc.resetUndoMerge(); 220 } catch (BadLocationException e) { 221 throw new RuntimeException (e); 222 } 223 224 } else if ((r -= createPositionRatio) < 0) { 225 int offset = (int)((docLength + 2) * random.nextDouble()); 227 228 if (debug) { 229 debugOp(op, "createPosition(" + offset + ")"); 230 } 231 try { 232 masterPositions.add(masterDoc.createPosition(offset)); 233 testPositions.add(testDoc.createPosition(offset)); 234 } catch (BadLocationException e) { 235 throw new RuntimeException (e); 236 } 237 238 239 } else if ((r -= releasePositionRatio) < 0) { 240 int masterPositionsCount = masterPositions.size(); 241 if (masterPositionsCount > 0) { 242 int index = (int)(masterPositionsCount * random.nextDouble()); 243 244 if (debug) { 245 debugOp(op, "release position at index=" + index); 246 } 247 248 masterPositions.remove(index); 249 testPositions.remove(index); 250 } 251 252 } else if ((r -= undoRatio) < 0) { 253 int undoCount = (int)(undoMaxCount * random.nextDouble()); 254 255 if (debug) { 256 debugOp(op, "undo(" + undoCount + ")"); 257 } 258 259 while (undoCount > 0) { 260 undoCount--; 261 if (masterUndoManager.canUndo()) { 262 masterUndoManager.undo(); 263 testUndoManager.undo(); 264 if (undoCount > 0) { 265 checkConsistency(); } 267 } 268 } 269 270 } else if ((r -= redoRatio) < 0) { 271 int redoCount = (int)(redoMaxCount * random.nextDouble()); 272 273 if (debug) { 274 debugOp(op, "redo(" + redoCount + ")"); 275 } 276 277 while (redoCount > 0) { 278 redoCount--; 279 if (masterUndoManager.canRedo()) { 280 masterUndoManager.redo(); 281 testUndoManager.redo(); 282 if (redoCount > 0) { 283 checkConsistency(); } 285 } 286 } 287 } 288 289 checkConsistency(); 290 } 291 292 } 293 294 private void debugOp(int op, String s) { 295 System.err.println("op: " + op + ", " + s); 296 } 297 298 private void checkConsistency() { 299 try { 300 int docLength = masterDoc.getLength(); 301 assertEquals(docLength, testDoc.getLength()); 302 303 String masterText = masterDoc.getText(0, docLength); 304 String testText = testDoc.getText(0, docLength); 305 assertEquals(masterText, testText); 306 307 Element lineRoot = masterDoc.getDefaultRootElement(); 308 Element testLineRoot = testDoc.getDefaultRootElement(); 309 int lineCount = lineRoot.getElementCount(); 310 if (lineCount != testLineRoot.getElementCount()) { 311 fail("Line count " + testLineRoot.getElementCount() 312 + " != " + lineCount); 313 } 314 for (int i = 0; i < lineCount; i++) { 316 Element masterLine = lineRoot.getElement(i); 317 Element testLine = testLineRoot.getElement(i); 318 if (masterLine.getStartOffset() != testLine.getStartOffset()) { 319 fail("Start of line " + i + ": Offset " + testLine.getStartOffset() 320 + " != " + masterLine.getStartOffset()); 321 } 322 if (masterLine.getEndOffset() != testLine.getEndOffset()) { 323 fail("End of line " + i + ": Offset " + testLine.getEndOffset() 324 + " != " + masterLine.getEndOffset()); 325 } 326 } 327 328 int positionCount = masterPositions.size(); 329 for (int i = 0; i < positionCount; i++) { 330 Position masterPos = (Position )masterPositions.get(i); 331 Position testPos = (Position )testPositions.get(i); 332 if (masterPos.getOffset() != testPos.getOffset()) { 333 fail("Tested position " + (i + 1) + " of " + positionCount 334 + ": " + testPos.getOffset() 335 + " != " + masterPos.getOffset()); 336 } 337 } 338 } catch (BadLocationException e) { 339 throw new RuntimeException (e); 340 } 341 } 342 343 private String linesToString() { 344 StringBuffer sb = new StringBuffer (); 345 Element masterLineRoot = masterDoc.getDefaultRootElement(); 346 Element testLineRoot = testDoc.getDefaultRootElement(); 347 int masterLineCount = masterLineRoot.getElementCount(); 348 int testLineCount = testLineRoot.getElementCount(); 349 int lineCount = Math.max(masterLineCount, testLineCount); 350 sb.append("Line count=" + lineCount + "\n"); 351 for (int i = 0; i < lineCount; i++) { 352 if (i < testLineCount) { 353 Element line = testLineRoot.getElement(i); 354 sb.append("[" + i + "]: <" + line.getStartOffset() + ", " + line.getEndOffset() + "> "); 355 } else { 356 sb.append(" <!NONE!> "); 357 } 358 359 if (i < masterLineCount) { 360 Element line = masterLineRoot.getElement(i); 361 sb.append("[" + i + "]: <" + line.getStartOffset() + ", " + line.getEndOffset() + ">\n"); 362 } else { 363 sb.append(" <!NONE!>\n"); 364 } 365 } 366 return sb.toString(); 367 } 368 369 private void checkEventsEqual(DocumentEvent testEvent) { 370 if (masterEvent.getOffset() != testEvent.getOffset()) { 371 fail("masterEvent.getOffset()=" + masterEvent.getOffset() 372 + " != testEvent.getOffset()=" + testEvent.getOffset()); 373 } 374 if (masterEvent.getLength() != testEvent.getLength()) { 375 fail("masterEvent.getLength()=" + masterEvent.getLength() 376 + " != testEvent.getLength()=" + testEvent.getLength()); 377 } 378 if (masterEvent.getType() != testEvent.getType()) { 379 fail("masterEvent.getType()=" + masterEvent.getType() 380 + " != testEvent.getType()=" + testEvent.getType()); 381 } 382 DocumentEvent.ElementChange masterChange = masterEvent.getChange(masterDoc.getDefaultRootElement()); 383 DocumentEvent.ElementChange testChange = testEvent.getChange(testDoc.getDefaultRootElement()); 384 checkElementChangesEqual(masterChange, testChange); 385 } 386 387 private void checkElementChangesEqual(DocumentEvent.ElementChange masterChange, 388 DocumentEvent.ElementChange testChange) { 389 390 if (masterChange == null && testChange == null) { return; 392 } 393 394 if (masterChange == null && testChange != null) { 395 fail("masterChange is null"); 396 } 397 if (masterChange != null && testChange == null) { 398 fail("testChange is null"); 399 } 400 401 int masterIndex = masterChange.getIndex(); 403 int testIndex = testChange.getIndex(); 404 if (masterIndex != testIndex) { 405 fail("masterIndex=" + masterIndex + " != testIndex=" + testIndex); 406 } 407 Element [] masterAdded = masterChange.getChildrenAdded(); 408 Element [] testAdded = testChange.getChildrenAdded(); 409 if (masterAdded.length != testAdded.length) { 410 fail("masterAdded.length=" + masterAdded.length 411 + "!= testAdded.length=" + testAdded.length); 412 } 413 Element [] masterRemoved = masterChange.getChildrenRemoved(); 414 Element [] testRemoved = testChange.getChildrenRemoved(); 415 if (masterRemoved.length != testRemoved.length) { 416 fail("masterRemoved.length=" + masterRemoved.length 417 + "!= testRemoved.length=" + testRemoved.length); 418 } 419 for (int i = 0; i < masterAdded.length; i++) { 420 Element masterElem = masterAdded[i]; 421 Element testElem = testAdded[i]; 422 checkElementOffsetsEqual(masterElem, testElem); 423 } 424 for (int i = 0; i < masterRemoved.length; i++) { 425 Element masterElem = masterRemoved[i]; 426 Element testElem = testRemoved[i]; 427 checkElementOffsetsEqual(masterElem, testElem); 428 } 429 } 430 431 private void checkElementOffsetsEqual(Element masterElem, Element testElem) { 432 if (masterElem.getStartOffset() != testElem.getStartOffset()) { 433 fail("masterElem.getStartOffset()=" + masterElem.getStartOffset() 434 + " != testElem.getStartOffset()=" + testElem.getStartOffset()); 435 } 436 if (masterElem.getEndOffset() != testElem.getEndOffset()) { 437 fail("masterElem.getEndOffset()=" + masterElem.getEndOffset() 438 + " != testElem.getEndOffset()=" + testElem.getEndOffset()); 439 } 440 } 441 442 private void processEvent(DocumentEvent evt) { 443 Document doc = evt.getDocument(); 445 if (doc == masterDoc) { 446 masterEvent = evt; 447 } else if (doc == testDoc) { 448 checkEventsEqual(evt); 449 masterEvent = null; 450 } else { 451 fail("Unknown document."); 452 } 453 } 454 455 public void insertUpdate(DocumentEvent e) { 456 processEvent(e); 457 } 458 459 public void removeUpdate(DocumentEvent e) { 460 processEvent(e); 461 } 462 463 public void changedUpdate(DocumentEvent e) { 464 } 465 466 467 } 468 | Popular Tags |