1 19 20 package org.netbeans.modules.editor.lib2.highlighting; 21 22 import java.util.ConcurrentModificationException ; 23 import javax.swing.text.BadLocationException ; 24 import javax.swing.text.DefaultStyledDocument ; 25 import javax.swing.text.Document ; 26 import javax.swing.text.SimpleAttributeSet ; 27 import junit.textui.TestRunner; 28 import org.netbeans.api.lexer.Language; 29 import org.netbeans.api.lexer.TokenHierarchy; 30 import org.netbeans.api.lexer.TokenId; 31 import org.netbeans.api.lexer.TokenSequence; 32 import org.netbeans.junit.NbTestCase; 33 import org.netbeans.lib.lexer.test.simple.SimplePlainTokenId; 34 import org.netbeans.lib.lexer.test.simple.SimpleTokenId; 35 import org.netbeans.spi.editor.highlighting.HighlightsChangeEvent; 36 import org.netbeans.spi.editor.highlighting.HighlightsChangeListener; 37 import org.netbeans.spi.editor.highlighting.HighlightsSequence; 38 39 43 public class SyntaxHighlightingTest extends NbTestCase { 44 45 public static void main(String ... args) { 46 TestRunner.run(SyntaxHighlightingTest.class); 47 } 48 49 50 public SyntaxHighlightingTest(String name) { 51 super(name); 52 } 53 54 public void testSimple() { 55 checkText("+ - / * public", SimpleTokenId.language()); 56 } 57 58 public void testEmbedded() { 59 checkText("/**//* this is a comment */", SimpleTokenId.language()); 60 } 61 62 public void testComplex() { 63 checkText( 64 "public /**/ +/- private /** hello */ something /* this is a comment */ \"hi hi hi\" xyz ", 65 SimpleTokenId.language()); 66 } 67 68 public void testNoPrologEpilogEmbedding() { 69 checkText( 70 "hello world 0-1-2-3-4-5-6-7-8-9-A-B-C-D-E-F Ooops", 71 SimplePlainTokenId.language()); 72 } 73 74 public void testConcurrentModifications() throws BadLocationException { 75 Document doc = createDocument(SimpleTokenId.language(), "NetBeans NetBeans NetBeans"); 76 SyntaxHighlighting layer = new SyntaxHighlighting(doc); 77 78 { 79 HighlightsSequence hs = layer.getHighlights(Integer.MIN_VALUE, Integer.MAX_VALUE); 80 assertTrue("There should be some highlights", hs.moveNext()); 81 82 doc.insertString(0, "Hey", SimpleAttributeSet.EMPTY); 84 85 try { 86 hs.moveNext(); 87 fail("ConcurrentModificationException has not been thrown from moveNext()"); 88 } catch (ConcurrentModificationException e) { 89 } 91 } 92 { 93 HighlightsSequence hs = layer.getHighlights(Integer.MIN_VALUE, Integer.MAX_VALUE); 94 assertTrue("There should be some highlights", hs.moveNext()); 95 96 doc.insertString(0, "Hey", SimpleAttributeSet.EMPTY); 98 99 try { 100 hs.getStartOffset(); 101 fail("ConcurrentModificationException has not been thrown from getStartOffset()"); 102 } catch (ConcurrentModificationException e) { 103 } 105 } 106 { 107 HighlightsSequence hs = layer.getHighlights(Integer.MIN_VALUE, Integer.MAX_VALUE); 108 assertTrue("There should be some highlights", hs.moveNext()); 109 110 doc.insertString(0, "Hey", SimpleAttributeSet.EMPTY); 112 113 try { 114 hs.getEndOffset(); 115 fail("ConcurrentModificationException has not been thrown from getEndOffset()"); 116 } catch (ConcurrentModificationException e) { 117 } 119 } 120 { 121 HighlightsSequence hs = layer.getHighlights(Integer.MIN_VALUE, Integer.MAX_VALUE); 122 assertTrue("There should be some highlights", hs.moveNext()); 123 124 doc.insertString(0, "Hey", SimpleAttributeSet.EMPTY); 126 127 try { 128 hs.getAttributes(); 129 fail("ConcurrentModificationException has not been thrown from getAttributes()"); 130 } catch (ConcurrentModificationException e) { 131 } 133 } 134 } 135 136 public void testEvents() throws BadLocationException { 137 final String text = "Hello !"; 138 Document doc = createDocument(SimpleTokenId.language(), text); 139 SyntaxHighlighting layer = new SyntaxHighlighting(doc); 140 L listener = new L(); 141 layer.addHighlightsChangeListener(listener); 142 143 assertHighlights( 144 TokenHierarchy.create(text, SimpleTokenId.language()).tokenSequence(), 145 layer.getHighlights(Integer.MIN_VALUE, Integer.MAX_VALUE), 146 true, 147 "" 148 ); 149 150 assertEquals("There should be no events", 0, listener.eventsCnt); 151 152 final String addedText = "World"; 153 doc.insertString(6, addedText, SimpleAttributeSet.EMPTY); 154 155 assertEquals("Wrong number of events", 1, listener.eventsCnt); 156 assertTrue("Wrong change start offset", 6 >= listener.lastStartOffset); 157 assertTrue("Wrong change end offset", 6 + addedText.length() <= listener.lastEndOffset); 158 } 159 160 private void checkText(String text, Language<? extends TokenId> lang) { 161 System.out.println("Checking text: '" + text + "'\n"); 162 Document doc = createDocument(lang, text); 163 SyntaxHighlighting layer = new SyntaxHighlighting(doc); 164 165 HighlightsSequence hs = layer.getHighlights(Integer.MIN_VALUE, Integer.MAX_VALUE); 166 TokenHierarchy<Void > tokens = TokenHierarchy.create(text, lang); 167 assertHighlights(tokens.tokenSequence(), hs, true, ""); 168 assertFalse("Unexpected highlights at the end of the sequence", hs.moveNext()); 169 System.out.println("------------------------\n"); 170 } 171 172 private Document createDocument(Language lang, String text) { 173 try { 174 DefaultStyledDocument doc = new DefaultStyledDocument (); 175 doc.putProperty(Language.class, lang); 176 doc.insertString(0, text, SimpleAttributeSet.EMPTY); 177 return doc; 178 } catch (BadLocationException e) { 179 fail(e.getMessage()); 180 return null; 181 } 182 } 183 184 private void assertHighlights(TokenSequence<? extends TokenId> ts, HighlightsSequence hs, boolean moveHs, String indent) { 185 while (ts.moveNext()) { 186 boolean hasHighlight; 187 if (moveHs) { 188 hasHighlight = hs.moveNext(); 189 } else { 190 hasHighlight = moveHs = true; 191 } 192 assertTrue("Wrong number of highlights", hasHighlight); 193 194 System.out.println(indent + "Token : <" + 195 ts.offset() + ", " + 196 (ts.offset() + ts.token().length()) + ", '" + 197 ts.token().text() + "', " + 198 ts.token().id().name() + ">"); 199 200 TokenSequence<? extends TokenId> embeddedSeq = ts.embedded(); 201 if (embeddedSeq == null) { 202 System.out.println(indent + "Highlight: <" + hs.getStartOffset() + ", " + hs.getEndOffset() + ">"); 203 assertEquals("Wrong starting offset", ts.offset(), hs.getStartOffset()); 204 assertEquals("Wrong ending offset", ts.offset() + ts.token().length(), hs.getEndOffset()); 205 } else { 207 int prologueLength = embeddedPrologLength(ts, embeddedSeq); 208 int epilogLength = embeddedEpilogLength(ts, embeddedSeq); 209 210 if (prologueLength != -1 && epilogLength != -1) { 211 if (prologueLength > 0) { 212 System.out.println(indent + "Prolog : <" + hs.getStartOffset() + ", " + hs.getEndOffset() + ">"); 213 assertEquals("Wrong starting offset", ts.offset(), hs.getStartOffset()); 214 assertEquals("Wrong ending offset", ts.offset() + prologueLength, hs.getEndOffset()); 215 } 217 218 assertHighlights(ts.embedded(), hs, prologueLength > 0, indent + " "); 219 220 if (epilogLength > 0) { 221 assertTrue("Wrong number of highlights", hs.moveNext()); 222 System.out.println(indent + "Epilog : <" + hs.getStartOffset() + ", " + hs.getEndOffset() + ">"); 223 224 assertEquals("Wrong starting offset", ts.offset() + ts.token().length() - epilogLength, hs.getStartOffset()); 225 assertEquals("Wrong ending offset", ts.offset() + ts.token().length(), hs.getEndOffset()); 226 } 228 } else { 229 System.out.println(indent + "Highlight: <" + hs.getStartOffset() + ", " + hs.getEndOffset() + ">"); 230 assertEquals("Wrong starting offset", ts.offset(), hs.getStartOffset()); 231 assertEquals("Wrong ending offset", ts.offset() + ts.token().length(), hs.getEndOffset()); 232 } 234 } 235 } 236 } 237 238 private int embeddedPrologLength( 239 TokenSequence<? extends TokenId> embeddingSeq, 240 TokenSequence<? extends TokenId> embeddedSeq) 241 { 242 embeddedSeq.moveStart(); 243 if (embeddedSeq.moveNext()) { 244 return embeddedSeq.offset() - embeddingSeq.offset(); 245 } else { 246 return -1; 247 } 248 } 249 250 private int embeddedEpilogLength( 251 TokenSequence<? extends TokenId> embeddingSeq, 252 TokenSequence<? extends TokenId> embeddedSeq) 253 { 254 embeddedSeq.moveEnd(); 255 if (embeddedSeq.movePrevious()) { 256 return (embeddingSeq.offset() + embeddingSeq.token().length()) - (embeddedSeq.offset() + embeddedSeq.token().length()); 257 } else { 258 return -1; 259 } 260 } 261 262 private void dumpSequence(HighlightsSequence hs) { 263 System.out.println("Dumping sequence: " + hs + " {"); 264 while(hs.moveNext()) { 265 System.out.println("<" + hs.getStartOffset() + ", " + hs.getEndOffset() + ">"); 266 } 267 System.out.println("} End of sequence: " + hs + " dump ------------"); 268 } 269 270 private static final class L implements HighlightsChangeListener { 271 public int eventsCnt = 0; 272 public int lastStartOffset; 273 public int lastEndOffset; 274 275 public void highlightChanged(HighlightsChangeEvent event) { 276 eventsCnt++; 277 lastStartOffset = event.getStartOffset(); 278 lastEndOffset = event.getEndOffset(); 279 } 280 } } 282 | Popular Tags |