1 19 20 26 27 package org.netbeans.modules.editor.lib2.highlighting; 28 29 import java.lang.reflect.InvocationTargetException ; 30 import java.lang.reflect.Method ; 31 import java.util.ArrayList ; 32 import java.util.ConcurrentModificationException ; 33 import java.util.Enumeration ; 34 import java.util.Random ; 35 import javax.swing.text.AttributeSet ; 36 import javax.swing.text.Document ; 37 import javax.swing.text.PlainDocument ; 38 import javax.swing.text.Position ; 39 import javax.swing.text.SimpleAttributeSet ; 40 import org.netbeans.api.editor.settings.AttributesUtilities; 41 import org.netbeans.spi.editor.highlighting.support.PositionsBag; 42 import org.netbeans.spi.editor.highlighting.HighlightsContainer; 43 import org.netbeans.spi.editor.highlighting.HighlightsChangeEvent; 44 import org.netbeans.spi.editor.highlighting.HighlightsChangeListener; 45 import org.netbeans.spi.editor.highlighting.HighlightsSequence; 46 import org.netbeans.junit.NbTestCase; 47 import org.netbeans.spi.editor.highlighting.support.OffsetsBag; 48 49 53 public class ProxyHighlightsContainerTest extends NbTestCase { 54 55 public ProxyHighlightsContainerTest(String testName) { 56 super(testName); 57 } 58 59 public void testSequence2Marks() { 60 OffsetsBag bag = new OffsetsBag(new PlainDocument ()); 61 SimpleAttributeSet attrsA = new SimpleAttributeSet (); 62 SimpleAttributeSet attrsB = new SimpleAttributeSet (); 63 SimpleAttributeSet attrsC = new SimpleAttributeSet (); 64 65 attrsA.addAttribute("set-name", "attrsA"); 66 attrsB.addAttribute("set-name", "attrsB"); 67 attrsC.addAttribute("set-name", "attrsC"); 68 69 bag.addHighlight(10, 20, attrsA); 70 ProxyHighlightsContainer.Sequence2Marks s2m = 71 new ProxyHighlightsContainer.Sequence2Marks(bag.getHighlights(0, 100), 0, 100); 72 checkSequence2Marks(s2m, new Object [] { 10, attrsA, 20, null }); 73 74 bag.addHighlight(30, 40, attrsB); 75 s2m = new ProxyHighlightsContainer.Sequence2Marks(bag.getHighlights(0, 100), 0, 100); 76 checkSequence2Marks(s2m, new Object [] { 10, attrsA, 20, null, 30, attrsB, 40, null }); 77 78 bag.addHighlight(20, 30, attrsC); 79 s2m = new ProxyHighlightsContainer.Sequence2Marks(bag.getHighlights(0, 100), 0, 100); 80 checkSequence2Marks(s2m, new Object [] { 10, attrsA, 20, attrsC, 30, attrsB, 40, null }); 81 82 s2m = new ProxyHighlightsContainer.Sequence2Marks(bag.getHighlights(0, 100), 15, 35); 83 checkSequence2Marks(s2m, new Object [] { 15, attrsA, 20, attrsC, 30, attrsB, 35, null }); 84 85 s2m = new ProxyHighlightsContainer.Sequence2Marks(bag.getHighlights(0, 100), 22, 28); 86 checkSequence2Marks(s2m, new Object [] { 22, attrsC, 28, null }); 87 } 88 89 private void checkSequence2Marks(ProxyHighlightsContainer.Sequence2Marks s2m, Object ... marks) { 90 int cnt = 0; 91 while (s2m.moveNext()) { 92 assertTrue("Too many marks", cnt < marks.length); 93 assertFalse("isFinished flag is not false", s2m.isFinished()); 94 95 assertEquals("Wrong mark[" + cnt + "] offset", ((Integer ) marks[2 * cnt]).intValue(), s2m.getMarkOffset()); 96 assertSame("Wrong mark[" + cnt + "] Attributes", marks[2 * cnt + 1], s2m.getMarkAttributes()); 97 98 if (cnt == 0) { 99 assertEquals("Wrong previous mark offset", -1, s2m.getPreviousMarkOffset()); 100 assertNull("Wrong previous mark Attributes", s2m.getPreviousMarkAttributes()); 101 } else { 102 assertEquals("Wrong previous mark offset", 103 ((Integer ) marks[2 * (cnt - 1)]).intValue(), 104 s2m.getPreviousMarkOffset()); 105 assertSame("Wrong previous mark Attributes", 106 marks[2 * (cnt - 1) + 1], 107 s2m.getPreviousMarkAttributes()); 108 } 109 110 cnt++; 111 } 112 113 assertEquals("Wrong number of marks", marks.length / 2, cnt); 114 assertTrue("isFinished flag is not true", s2m.isFinished()); 115 } 116 117 public void testSimple() { 118 PlainDocument doc = new PlainDocument (); 119 HighlightsContainer layer = createRandomBag(doc, "layer"); 120 HighlightsSequence highlights = layer.getHighlights(0, 100); 121 122 ProxyHighlightsContainer proxyLayer = new ProxyHighlightsContainer(new HighlightsContainer [] { layer }); 123 HighlightsSequence proxyHighlights = proxyLayer.getHighlights(0, 100); 124 125 for ( ; highlights.moveNext(); ) { 126 if (highlights.getStartOffset() == highlights.getEndOffset()) { 128 continue; 129 } 130 131 assertTrue("Wrong number of proxy highlights", proxyHighlights.moveNext()); 132 133 assertEquals("Start offset does not match", highlights.getStartOffset(), proxyHighlights.getStartOffset()); 134 assertEquals("End offset does not match", highlights.getEndOffset(), proxyHighlights.getEndOffset()); 135 assertTrue("Attributes do not match", highlights.getAttributes().isEqual(proxyHighlights.getAttributes())); 136 } 137 } 138 139 public void testOrdering() { 140 PlainDocument doc = new PlainDocument (); 141 PositionsBag hsA = new PositionsBag(doc); 142 PositionsBag hsB = new PositionsBag(doc); 143 144 SimpleAttributeSet attribsA = new SimpleAttributeSet (); 145 SimpleAttributeSet attribsB = new SimpleAttributeSet (); 146 147 attribsA.addAttribute("attribute", "value-A"); 148 attribsB.addAttribute("attribute", "value-B"); 149 150 hsA.addHighlight(new SimplePosition(5), new SimplePosition(15), attribsA); 151 hsB.addHighlight(new SimplePosition(10), new SimplePosition(20), attribsB); 152 153 ProxyHighlightsContainer chc = new ProxyHighlightsContainer(new HighlightsContainer [] { hsA, hsB }); 154 HighlightsSequence highlights = chc.getHighlights(0, Integer.MAX_VALUE); 155 156 assertTrue("Wrong number of highlights", highlights.moveNext()); 157 assertEquals("1. highlight - wrong attribs", "value-A", highlights.getAttributes().getAttribute("attribute")); 158 159 assertTrue("Wrong number of highlights", highlights.moveNext()); 160 assertEquals("2. highlight - wrong attribs", "value-B", highlights.getAttributes().getAttribute("attribute")); 161 162 assertTrue("Wrong number of highlights", highlights.moveNext()); 163 assertEquals("3. highlight - wrong attribs", "value-B", highlights.getAttributes().getAttribute("attribute")); 164 } 165 166 public void testConcurrentModification() throws Exception { 167 checkConcurrentModificationOnMethod("moveNext"); 168 checkConcurrentModificationOnMethod("getStartOffset"); 169 checkConcurrentModificationOnMethod("getEndOffset"); 170 checkConcurrentModificationOnMethod("getAttributes"); 171 } 172 173 private void checkConcurrentModificationOnMethod(String methodName) throws Exception { 174 PlainDocument doc = new PlainDocument (); 175 PositionsBag bag = createRandomBag(doc, "layer"); 176 HighlightsContainer [] layers = new HighlightsContainer [] { bag }; 177 178 { 179 ProxyHighlightsContainer hb = new ProxyHighlightsContainer(layers); 180 HighlightsSequence hs = hb.getHighlights(0, Integer.MAX_VALUE); 181 182 hb.setLayers(layers); 184 185 Throwable exc = null; 186 try { 187 Method m = hs.getClass().getMethod(methodName); 188 m.invoke(hs); 189 } catch (InvocationTargetException e) { 190 exc = e.getCause(); 191 } 192 193 assertTrue("ConcurrentModificationException has not been thrown from " + 194 methodName + "() after setLayers", exc instanceof ConcurrentModificationException ); 195 } 196 { 197 ProxyHighlightsContainer hb = new ProxyHighlightsContainer(layers); 198 HighlightsSequence hs = hb.getHighlights(0, Integer.MAX_VALUE); 199 200 bag.addHighlight(new SimplePosition(20), new SimplePosition(30), SimpleAttributeSet.EMPTY); 202 203 Throwable exc = null; 204 try { 205 Method m = hs.getClass().getMethod(methodName); 206 m.invoke(hs); 207 } catch (InvocationTargetException e) { 208 exc = e.getCause(); 209 } 210 211 assertTrue("ConcurrentModificationException has not been thrown from " + 212 methodName + "() after changing the original bag", 213 exc instanceof ConcurrentModificationException ); 214 } 215 } 216 217 public void testRandomMerging() { 218 String [] layerNames = new String [] { 219 "layer-1", 220 "layer-2", 221 "layer-3", 222 }; 223 224 PlainDocument doc = new PlainDocument (); 225 HighlightsContainer [] layers = new HighlightsContainer [layerNames.length]; 226 for(int i = 0; i < layers.length; i++) { 227 layers[i] = createRandomBag(doc, layerNames[i]); 228 }; 229 230 ProxyHighlightsContainer proxyLayer = new ProxyHighlightsContainer(layers); 231 232 for (int pointer = 0; pointer <= 100; pointer++) { 233 234 String failMsg = null; 236 Highlight [] highestPair = new Highlight [] { null, null }; 237 Highlight [] proxyPair = new Highlight [] { null, null }; 238 239 240 try { 241 highestPair = new Highlight [] { null, null }; 242 proxyPair = new Highlight [] { null, null }; 243 244 ArrayList <AttributeSet > leftHighlights = new ArrayList <AttributeSet >(); 246 ArrayList <AttributeSet > rightHighlights = new ArrayList <AttributeSet >(); 247 for (int i = 0; i < layers.length; i++) { 248 Highlight [] layerPair = findPair(pointer, layers[i].getHighlights(0, 100)); 249 if (layerPair[0] != null) { 250 leftHighlights.add(layerPair[0].getAttributes()); 251 } 252 if (layerPair[1] != null) { 253 rightHighlights.add(layerPair[1].getAttributes()); 254 } 255 } 256 257 if (!leftHighlights.isEmpty()) { 258 highestPair[0] = new Highlight(pointer, pointer, AttributesUtilities.createComposite( 259 leftHighlights.toArray(new AttributeSet [leftHighlights.size()]))); 260 } 261 if (!rightHighlights.isEmpty()) { 262 highestPair[1] = new Highlight(pointer, pointer, AttributesUtilities.createComposite( 263 rightHighlights.toArray(new AttributeSet [rightHighlights.size()]))); 264 } 265 266 proxyPair = findPair(pointer, proxyLayer.getHighlights(0, 100)); 268 269 for (int i = 0; i < 2; i++) { 270 if (highestPair[i] != null && proxyPair[i] != null) { 271 if (!highestPair[i].getAttributes().isEqual(proxyPair[i].getAttributes())) { 273 failMsg = (i == 0 ? "Left" : "Right") + "pair attributes do not match"; 274 } 275 } else if (highestPair[i] != null || proxyPair[i] != null) { 276 failMsg = (i == 0 ? "Left" : "Right") + " highlight doesn't match"; 278 } 279 } 280 } catch (Throwable e) { 281 failMsg = e.getMessage(); 282 } 283 284 if (failMsg != null) { 285 System.out.println("Dumping layers:"); 287 for (int i = 0; i < layers.length; i++) { 288 System.out.println(" layer[" + i + "] = " + layerNames[i] + "{"); 289 for (HighlightsSequence highlights = layers[i].getHighlights(0, 100); highlights.moveNext(); ) { 290 Highlight h = copyCurrentHighlight(highlights); 291 System.out.println(" " + dumpHighlight(h)); 292 } 293 System.out.println(" } End of layer[" + i + "] -----------------"); 294 } 295 System.out.println("Dumping proxy layer: {"); 296 for (HighlightsSequence proxyHighlights = proxyLayer.getHighlights(0, 100); proxyHighlights.moveNext(); ) { 297 Highlight h = copyCurrentHighlight(proxyHighlights); 298 System.out.println(" " + dumpHighlight(h)); 299 } 300 System.out.println("} End of proxy layer -----------------------"); 301 302 System.out.println("highest pair (pos = " + pointer + ") : " + dumpHighlight(highestPair[0]) + ", " + dumpHighlight(highestPair[1])); 304 System.out.println(" proxy pair (pos = " + pointer + ") : " + dumpHighlight(proxyPair[0]) + ", " + dumpHighlight(proxyPair[1])); 305 306 fail(failMsg + " (position = " + pointer + ")"); 307 } 308 } 309 } 310 311 public void testEvents() { 312 PlainDocument doc = new PlainDocument (); 313 PositionsBag hsA = new PositionsBag(doc); 314 PositionsBag hsB = new PositionsBag(doc); 315 316 ProxyHighlightsContainer chc = new ProxyHighlightsContainer(new HighlightsContainer [] { hsA, hsB }); 317 Listener listener = new Listener(); 318 chc.addHighlightsChangeListener(listener); 319 320 hsA.addHighlight(new SimplePosition(10), new SimplePosition(20), new SimpleAttributeSet ()); 321 assertEquals("Wrong number of events", 1, listener.eventsCnt); 322 assertEquals("Wrong change start offset", 10, listener.lastEventStartOffset); 323 assertEquals("Wrong change end offset", 20, listener.lastEventEndOffset); 324 325 listener.reset(); 326 hsB.addHighlight(new SimplePosition(11), new SimplePosition(12), new SimpleAttributeSet ()); 327 assertEquals("Wrong number of events", 1, listener.eventsCnt); 328 assertEquals("Wrong change start offset", 11, listener.lastEventStartOffset); 329 assertEquals("Wrong change end offset", 12, listener.lastEventEndOffset); 330 } 331 332 public void testEvents2() { 333 PlainDocument doc = new PlainDocument (); 334 PositionsBag hsA = new PositionsBag(doc); 335 PositionsBag hsB = new PositionsBag(doc); 336 337 hsA.addHighlight(new SimplePosition(10), new SimplePosition(20), new SimpleAttributeSet ()); 338 hsB.addHighlight(new SimplePosition(11), new SimplePosition(12), new SimpleAttributeSet ()); 339 340 ProxyHighlightsContainer chc = new ProxyHighlightsContainer(); 341 Listener listener = new Listener(); 342 chc.addHighlightsChangeListener(listener); 343 344 chc.setLayers(new HighlightsContainer [] { hsA, hsB }); 346 assertEquals("Wrong number of events", 1, listener.eventsCnt); 347 assertEquals("Wrong change start offset", 0, listener.lastEventStartOffset); 348 assertEquals("Wrong change end offset", Integer.MAX_VALUE, listener.lastEventEndOffset); 349 } 350 351 private Highlight [] findPair(int offset, HighlightsSequence highlights) { 352 Highlight left = null; 353 Highlight right = null; 354 355 for ( ; highlights.moveNext(); ) { 356 if (highlights.getStartOffset() == highlights.getEndOffset()) { 357 continue; 359 } 360 361 if (offset > highlights.getStartOffset() && offset < highlights.getEndOffset()) { 362 left = right = copyCurrentHighlight(highlights); 363 } else if (offset == highlights.getEndOffset()) { 364 left = copyCurrentHighlight(highlights); 365 } else if (offset == highlights.getStartOffset()) { 366 right = copyCurrentHighlight(highlights); 367 } 368 } 369 370 return new Highlight [] { left, right }; 371 } 372 373 private Highlight copyCurrentHighlight(HighlightsSequence iterator) { 374 return new Highlight( 375 iterator.getStartOffset(), 376 iterator.getEndOffset(), 377 iterator.getAttributes() 378 ); 379 } 380 381 private String dumpHighlight(Highlight h) { 382 if (h == null) { 383 return "< , , >"; 384 } else { 385 StringBuilder sb = new StringBuilder (); 386 387 sb.append("<"); 388 sb.append(h.getStartOffset()); 389 sb.append(","); 390 sb.append(h.getEndOffset()); 391 sb.append(","); 392 393 Enumeration en = h.getAttributes().getAttributeNames(); 394 while (en.hasMoreElements()) { 395 Object attrName = en.nextElement(); 396 Object attrValue = h.getAttributes().getAttribute(attrName); 397 398 sb.append("'"); 399 sb.append(attrName.toString()); 400 sb.append("' = '"); 401 sb.append(attrValue == null ? "null" : attrValue.toString()); 402 sb.append("'"); 403 if (en.hasMoreElements()) { 404 sb.append(", "); 405 } 406 } 407 408 sb.append(">"); 409 410 return sb.toString(); 411 } 412 } 413 414 private PositionsBag createRandomBag(Document doc, String bagId) { 415 416 PositionsBag bag = new PositionsBag(doc, false); 417 418 Random rand = new Random (System.currentTimeMillis()); 419 int attrIdx = 0; 420 int startOffset = 0; 421 int endOffset = 100; 422 423 int maxGapSize = Math.max((int) (endOffset - startOffset) / 10, 1); 424 int maxHighlightSize = Math.max((int) (endOffset - startOffset) / 2, 1); 425 426 for (int pointer = startOffset + rand.nextInt(maxGapSize); pointer <= endOffset; ) { 427 int highlightSize = rand.nextInt(maxHighlightSize); 428 SimpleAttributeSet attributes = new SimpleAttributeSet (); 429 attributes.addAttribute("AttrName-" + bagId + "-" + attrIdx, "AttrValue"); 430 attrIdx++; 431 432 if (pointer + highlightSize < endOffset) { 433 bag.addHighlight( 434 new SimplePosition(pointer), new SimplePosition(pointer + highlightSize), attributes); 435 } else { 436 bag.addHighlight( 437 new SimplePosition(pointer), new SimplePosition(endOffset), attributes); 438 } 439 440 pointer += highlightSize + rand.nextInt(maxGapSize); 442 } 443 444 return bag; 445 } 446 447 private static final class Highlight { 448 private int startOffset; 449 private int endOffset; 450 private AttributeSet attributes; 451 452 public Highlight(int startOffset, int endOffset, AttributeSet attributes) { 453 this.startOffset = startOffset; 454 this.endOffset = endOffset; 455 this.attributes = attributes; 456 } 457 458 public int getStartOffset() { 459 return startOffset; 460 } 461 462 public void setStartOffset(int startOffset) { 463 this.startOffset = startOffset; 464 } 465 466 public int getEndOffset() { 467 return endOffset; 468 } 469 470 public void setEndOffset(int endOffset) { 471 this.endOffset = endOffset; 472 } 473 474 public AttributeSet getAttributes() { 475 return attributes; 476 } 477 478 public void setAttributes(AttributeSet attributes) { 479 this.attributes = attributes; 480 } 481 482 } 484 private static final class Listener implements HighlightsChangeListener { 485 public int eventsCnt = 0; 486 public int lastEventStartOffset = 0; 487 public int lastEventEndOffset = 0; 488 489 public void highlightChanged(HighlightsChangeEvent event) { 490 eventsCnt++; 491 lastEventStartOffset = event.getStartOffset(); 492 lastEventEndOffset = event.getEndOffset(); 493 } 494 495 public void reset() { 496 eventsCnt = 0; 497 lastEventStartOffset = 0; 498 lastEventEndOffset = 0; 499 } 500 } 502 private static final class SimplePosition implements Position { 503 private int offset; 504 505 public SimplePosition(int offset) { 506 this.offset = offset; 507 } 508 509 public int getOffset() { 510 return offset; 511 } 512 } 514 private void dumpHighlights(HighlightsSequence seq) { 515 System.out.println("Dumping highlights from: " + seq + "{"); 516 while(seq.moveNext()) { 517 System.out.println("<" + seq.getStartOffset() + ", " + seq.getEndOffset() + ", " + seq.getAttributes() + ">"); 518 } 519 System.out.println("} --- End of Dumping highlights from: " + seq + " ---------------------"); 520 } 521 } 522 | Popular Tags |