1 19 20 package org.netbeans.test.web.core.syntax; 21 import java.awt.Color ; 22 import java.awt.Component ; 23 import java.awt.EventQueue ; 24 import java.awt.Font ; 25 import java.awt.Graphics ; 26 import java.beans.PropertyChangeEvent ; 27 import java.beans.PropertyChangeListener ; 28 import java.io.File ; 29 import java.lang.reflect.Method ; 30 import java.util.ArrayList ; 31 import java.util.Arrays ; 32 import java.util.Iterator ; 33 import java.util.LinkedList ; 34 import java.util.List ; 35 import javax.swing.JEditorPane ; 36 import javax.swing.JLabel ; 37 import javax.swing.JList ; 38 import javax.swing.SwingUtilities ; 39 import javax.swing.text.Caret ; 40 import junit.framework.Test; 41 import org.netbeans.editor.Utilities; 42 import org.netbeans.editor.ext.CompletionQuery.ResultItem; 43 import org.netbeans.jellytools.JellyTestCase; 44 import org.netbeans.jellytools.modules.editor.CompletionJListOperator; 45 import org.netbeans.jemmy.JemmyException; 46 import org.netbeans.jemmy.util.PNGEncoder; 47 import org.netbeans.junit.AssertionFailedErrorException; 48 import org.netbeans.editor.BaseDocument; 49 import org.netbeans.editor.TokenID; 50 import org.netbeans.editor.TokenItem; 51 import org.netbeans.editor.ext.ExtSyntaxSupport; 52 import org.netbeans.spi.editor.completion.CompletionItem; 53 import org.netbeans.test.web.FileObjectFilter; 54 import org.netbeans.test.web.RecurrentSuiteFactory; 55 import org.netbeans.test.web.TextGraphics2D; 56 import org.netbeans.test.web.Waiter; 57 import org.openide.actions.UndoAction; 58 import org.openide.cookies.EditorCookie; 59 import org.openide.cookies.EditorCookie.Observable; 60 import org.openide.filesystems.FileObject; 61 import org.openide.loaders.DataObject; 62 import org.openide.util.actions.SystemAction; 63 64 65 66 96 public class CompletionTest extends JellyTestCase { 97 private static boolean GenerateGoldenFiles = false; 99 protected FileObject testFileObj; 100 protected boolean debug = false; 101 protected final static List xmlExts = Arrays.asList(new String [] 102 {"xml","xsd","html","tld","jspx","tagx"}); 103 protected final static List jspExts = Arrays.asList(new String [] {"jsp","tag"}); 104 protected final static List jsExts = Arrays.asList(new String [] {"js"}); 105 106 public CompletionTest(String name, FileObject testFileObj) { 107 super(name); 108 this.testFileObj = testFileObj; 109 } 110 111 public void setUp() { 112 System.out.println("######## "+getName()+" #######"); 113 } 114 115 public static Test suite() { 116 File datadir = new CompletionTest(null, null).getDataDir(); 118 File projectsDir = new File (datadir, "CompletionTestProjects"); 119 FileObjectFilter filter = new FileObjectFilter() { 120 public boolean accept(FileObject fo) { 121 String ext = fo.getExt(); 122 String name = fo.getName(); 123 return (name.startsWith("test") || name.startsWith("Test")) 124 && (xmlExts.contains(ext) || jspExts.contains(ext) || jsExts.contains(ext)); 125 } 126 }; 127 return RecurrentSuiteFactory.createSuite(CompletionTest.class, 128 projectsDir, filter); 129 } 130 131 public void runTest() throws Exception { 132 String ext = testFileObj.getExt(); 133 if (jspExts.contains(ext)) { 134 test(testFileObj, "<%--CC", "--%>"); 135 } else if (xmlExts.contains(ext)) { 136 test(testFileObj, "<!--CC", "-->"); 137 } else if (ext.equals("java")) { 138 test(testFileObj, "/**CC", "*/"); 139 }else if (ext.equals("js")) { 140 test(testFileObj, "/**CC", "*/",true); 141 } 142 else { 143 throw new JemmyException("File extension of: "+testFileObj.getNameExt() 144 +" is unsupported."); 145 } 146 } 147 private void test(FileObject fileObj, String stepStart, String stepEnd) throws Exception { 148 test(fileObj,stepStart,stepEnd,false); 149 } 150 private void test(FileObject fileObj, String stepStart, String stepEnd,boolean isJS) throws Exception { 151 boolean inStepData = false; 152 String [] stepData = new String [3]; 153 int dataLineIdx = 0; 154 155 try { 156 DataObject dataObj = DataObject.find(fileObj); 158 final EditorCookie.Observable ed = (Observable) dataObj.getCookie(Observable.class); 159 160 final Waiter waiter = new Waiter(); 162 final PropertyChangeListener pcl = new PropertyChangeListener () { 163 public void propertyChange(PropertyChangeEvent evt) { 164 if (evt.getPropertyName().equals(Observable.PROP_OPENED_PANES)) { 165 waiter.notifyFinished(); 166 } 167 } 168 }; 169 ed.addPropertyChangeListener(pcl); 170 BaseDocument doc = (BaseDocument) ed.openDocument(); 172 ed.open(); 173 assertTrue("The editor pane was not opened in 10 secs.", waiter.waitFinished(10000)); 175 ed.removePropertyChangeListener(pcl); 176 Thread.sleep(3000); 178 final List <JEditorPane > editorPane = new LinkedList <JEditorPane >(); 179 Runnable runnable = new Runnable (){ 180 public void run(){ 181 editorPane.add(ed.getOpenedPanes()[0]); 182 } 183 }; 184 EventQueue.invokeAndWait(runnable); 185 JEditorPane editor = editorPane.get(0); 186 ExtSyntaxSupport ess = (ExtSyntaxSupport) doc.getSyntaxSupport(); 187 TokenItem token = ess.getTokenChain(0, doc.getLength()); 188 List <TestStep> steps = new java.util.ArrayList <TestStep>(); 189 while (token != null) { 191 TokenID tokenID = token.getTokenID(); 192 if (debug) { 193 String tImage = token.getImage(); 194 int tEnd = token.getOffset() + tImage.length(); 195 System.err.println("# [" + token.getOffset() + "," + tEnd + "] " 196 + tokenID.getName() + " :: " + token.getImage()); 197 } 198 String tag="comment"; 199 if(isJS) 200 tag="text"; 201 if (tokenID.getName().indexOf(tag) == -1) { 202 token = token.getNext(); 203 continue; 204 } 205 if (inStepData){ 206 if (token.getImage().indexOf(stepEnd) > -1) { 208 inStepData = false; 209 if (dataLineIdx == 3) { 211 int offset = token.getOffset() + token.getImage() 212 .length(); 213 TestStep step = new TestStep(stepData, offset); 214 steps.add(step); 215 } else { 216 ref("EE: expected data lines number: 3 but was: " 217 + dataLineIdx); 218 } 219 } else { 220 if (dataLineIdx > 2) { 222 String msg = "EE: to much lines in CC Test Data"; 223 ref(msg); 224 ref(dumpToken(token)); 225 fail(msg); 226 } 227 String str = token.getImage(); 228 if (str.endsWith("\n")) { 230 str = str.substring(0, str.length()-1); 231 } 232 stepData[dataLineIdx++] = str; 233 } 234 } else { 235 String text = token.getImage(); 236 if(text.startsWith(stepStart)) { 237 if (text.endsWith(stepEnd)) { 238 String [] lines = text.split("\n\r?|\r\n?"); 240 if (lines.length == 5) { 241 int offset = token.getOffset() + token.getImage().length(); 242 for (int i = 0; i < 3; i++) { 243 stepData[i] = lines[i+1]; 244 } 245 TestStep step = new TestStep(stepData, offset); 246 steps.add(step); 247 } else { 248 String msg = "EE: expected 5 lines lenght token but got: " 249 + lines.length; 250 ref(msg); 251 ref(text); 252 for (int i = 0; i < lines.length; i++) { 253 ref(i+"::"+lines[i]); 254 } 255 } 256 } else { 257 inStepData = true; 259 dataLineIdx = 0; 260 } 261 } 262 } 263 token = token.getNext(); 264 } run(editor, steps,isJS); 266 } catch (Exception ex) { 267 throw new AssertionFailedErrorException(ex); 268 } 269 ending(); 270 } 271 272 protected void run(JEditorPane editor, List steps, boolean isJS) throws Exception { 273 Iterator it = steps.iterator(); 274 while (it.hasNext()) { 275 exec(editor, (TestStep) it.next(),isJS); 276 } 277 } 278 279 protected void exec(JEditorPane editor, TestStep step,boolean isJS) throws Exception { 280 boolean ccError = false; 281 try { 282 ref(step.toString()); 283 BaseDocument doc = (BaseDocument) editor.getDocument(); 284 doc.insertString(step.getOffset(), "\n" + step.getPrefix(), null); 286 Caret caret = editor.getCaret(); 287 caret.setDot(step.getCursorPos()); 288 Thread.sleep(500); 290 CompletionJListOperator comp = null; 293 try { 294 comp = CompletionJListOperator.showCompletion(); 295 } catch (JemmyException e) { 296 ccError = true; 297 log("EE: The CC window did not appear"); 298 e.printStackTrace(getLog()); 299 } 300 try{ 301 if (comp!= null){ 302 Object o = comp.getCompletionItems().get(0); 303 if (o.toString().contains("No suggestions")){ Thread.sleep(1000); 305 log(step.toString() + " " + o.toString() + " trying again\n"); 306 comp = new CompletionJListOperator(); 307 } 308 }else{ Thread.sleep(1000); 310 log(step.toString() + " trying again\n"); 311 comp = new CompletionJListOperator(); 312 } 313 } catch (JemmyException e) { 314 ccError = true; 315 log("EE: The CC window did not appear for the second time"); 316 e.printStackTrace(getLog()); 317 } 318 Thread.sleep(1500); 320 if (comp != null) { 321 Iterator items = comp.getCompletionItems().iterator(); 323 CompletionItem selectedItem = null; 324 while (items.hasNext()) { 325 TextGraphics2D g = new TextGraphics2D(comp.getSource()); 326 Object next = items.next(); 327 String dispText = null; 328 if (next instanceof ResultItem) { 329 ResultItem resItem = (ResultItem) next; 330 Component component = resItem.getPaintComponent((JList )comp.getSource(), 331 false, true); 332 Method drawM = findMethod(component.getClass(), "draw", new Class [] {Graphics .class}); 334 if(drawM != null) { 335 drawM.setAccessible(true); 336 drawM.invoke(component, new Object [] {g}); 337 } else if (component instanceof JLabel ) { 338 g.drawString(((JLabel ) component).getText().trim(), 0, 0); 340 } else { 341 g.drawString(component.toString(), 0, 0); 342 } 343 } else if (next instanceof CompletionItem) { 344 CompletionItem cItem = (CompletionItem) next; 345 if(isJS) 346 g.setText(cItem.getSortText()); 347 else 348 349 cItem.render(g, Font.decode("Dialog-Plain-12"), Color.BLACK, Color.WHITE, 400, 30, false); 350 351 352 } else { 353 g.drawString(next.toString(),0 ,0); 354 } 355 dispText = g.getTextUni(); 356 if (dispText.equals(step.getChoice())) { 358 assertInstanceOf(CompletionItem.class, next); 359 selectedItem = (CompletionItem) next; 360 } 361 ref(g.getTextUni()); 362 } 363 class DefaultActionRunner implements Runnable { 364 CompletionItem item; 365 JEditorPane editor; 366 public DefaultActionRunner(CompletionItem item, 367 JEditorPane editor) { 368 this.item=item; 369 this.editor=editor; 370 } 371 372 public void run() { 373 item.defaultAction(editor); 374 } 375 376 } 377 if (selectedItem != null) { 379 Runnable run = new DefaultActionRunner(selectedItem, editor); 381 Thread.currentThread().sleep(1000); 383 runInAWT(run); 384 } else { 385 ref("EE: cannot find completion item: " + step.getChoice()); 386 } 387 } else if (!ccError) { 388 ref("Instant substitution performed"); 390 } 391 if (comp != null) { 393 int i = 0; 394 while (comp.isShowing()) { 395 Thread.currentThread().sleep(500); 396 if (i++ >= 12) { 397 long time = System.currentTimeMillis(); 399 String screenFile = time + "-screen.png"; 400 log("["+time+"]The CompletionJList was not hidden in 5 secs"); 401 log("step: "+step); 402 log("captureScreen:" + screenFile); 403 try { 404 PNGEncoder.captureScreen(getWorkDir().getAbsolutePath() 405 +File.separator+screenFile); 406 } catch (Exception e1) {} 407 break; 408 } 409 } 410 } 411 Thread.currentThread().sleep(500); int rowStart = Utilities.getRowStart(doc, step.getOffset() + 1); 413 int rowEnd = Utilities.getRowEnd(doc, step.getOffset() + 1); 414 String result = doc.getText(new int[] {rowStart, rowEnd}); 415 if (!result.equals(step.getResult())) { 416 ref("EE: unexpected CC result:\n< " + result + "\n> " 417 + step.getResult()); 418 } 419 ref("End cursor position = " + caret.getDot()); 420 } finally { 421 Thread.currentThread().sleep(500); final UndoAction ua = (UndoAction)SystemAction.get(UndoAction.class); 424 assertNotNull("Cannot obtain UndoAction", ua); 425 while (ua.isEnabled()) { 426 runInAWT(new Runnable () { 427 public void run() { 428 ua.performAction(); 429 } 430 }); 431 Thread.currentThread().sleep(50); } 433 Thread.currentThread().sleep(500); 434 } 435 436 } 437 438 protected static void runInAWT(Runnable r) { 439 if (SwingUtilities.isEventDispatchThread()) { 440 r.run(); 441 } else { 442 SwingUtilities.invokeLater(r); 443 } 444 } 445 446 protected Method findMethod(Class clazz, String name, Class [] paramTypes) { 447 Method method = null; 448 for (Class cls=clazz; cls.getSuperclass() != null; cls=cls.getSuperclass()) { 449 try { 450 method = cls.getDeclaredMethod(name, paramTypes); 451 } catch (NoSuchMethodException e) { 452 } 454 if (method != null) { 455 return method; 456 } 457 } 458 return null; 459 } 460 461 protected void assertInstanceOf(Class expectedType, Object actual) { 462 if (!expectedType.isAssignableFrom(actual.getClass())) { 463 fail("Expected type: "+expectedType.getName()+"\nbut was: "+ 464 actual.getClass().getName()); 465 } 466 } 467 468 protected static class TestStep { 469 private String prefix; 470 private String choice; 471 private String result; 472 private int offset; 473 private int cursorPos; 474 475 public TestStep(String data[], int offset) { 476 this.prefix = data[0]; 477 this.choice = data[1]; 478 this.result = data[2]; 479 this.offset = offset; 480 481 cursorPos = prefix.indexOf('|'); 482 if (cursorPos != -1) { 483 prefix = prefix.replaceFirst("\\|", ""); 484 } else { 485 cursorPos = prefix.length(); 486 } 487 cursorPos += offset + 1; 488 } 489 490 public String toString() { 491 StringBuffer sb = new StringBuffer (prefix); 492 sb.insert(cursorPos - offset - 1, '|'); 493 return "[" + sb + ", " + choice + ", "+ result + ", " + offset + "]"; 494 } 495 496 public String getPrefix() { 497 return prefix; 498 } 499 500 public String getChoice() { 501 return choice; 502 } 503 504 public String getResult() { 505 return result; 506 } 507 508 public int getOffset() { 509 return offset; 510 } 511 512 public int getCursorPos() { 513 return cursorPos; 514 } 515 516 }; 517 518 private String dumpToken(TokenItem tokenItem) { 519 StringBuffer sb = new StringBuffer (); 520 sb.append("<token \name='"); 521 sb.append(tokenItem.getTokenID().getName()); 522 sb.append("'>\n"); 523 sb.append(tokenItem.getTokenContextPath()); 524 sb.append("</token>"); 525 return sb.toString(); 526 } 527 528 protected void ending() throws Exception { 529 if (!GenerateGoldenFiles) compareReferenceFiles(); 530 else { 531 getRef().flush(); 532 File ref = new File (getWorkDir(),this.getName()+".ref"); 533 File f = getDataDir(); 534 ArrayList <String > names = new ArrayList <String >(); 535 names.add("goldenfiles"); 536 names.add("data"); 537 names.add("qa-functional"); 538 while (!f.getName().equals("test")) f = f.getParentFile(); 539 for (int i=names.size()-1;i > -1;i--) { 541 f=new File (f,names.get(i)); 542 } 543 f=new File (f, getClass().getName().replace('.', File.separatorChar)); 544 f=new File (f, this.getName()+".pass"); 545 if (!f.getParentFile().exists()) f.getParentFile().mkdirs(); 546 ref.renameTo(f); 547 assertTrue("Generating golden files to " + f.getAbsolutePath(), false); 548 } 549 550 } 551 552 553 public static void main(java.lang.String [] args) { 554 junit.textui.TestRunner.run(suite()); 563 } 564 565 } 566 | Popular Tags |