001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: /*
043: * EditorTestCase.java
044: *
045: * Created on 24. srpen 2004, 12:32
046: */
047:
048: package lib;
049:
050: import java.awt.datatransfer.DataFlavor;
051: import java.awt.datatransfer.Transferable;
052: import java.awt.datatransfer.UnsupportedFlavorException;
053: import java.io.File;
054: import java.io.IOException;
055: import java.util.StringTokenizer;
056: import javax.swing.text.BadLocationException;
057: import javax.swing.text.Document;
058: import org.netbeans.jellytools.EditorOperator;
059: import org.netbeans.jellytools.JellyTestCase;
060: import org.netbeans.jellytools.NbDialogOperator;
061: import org.netbeans.jellytools.ProjectsTabOperator;
062: import org.netbeans.jellytools.nodes.Node;
063: import org.netbeans.jellytools.nodes.ProjectRootNode;
064: import org.netbeans.jemmy.JemmyException;
065: import org.netbeans.jemmy.JemmyProperties;
066: import org.netbeans.jemmy.TimeoutExpiredException;
067: import org.netbeans.jemmy.Waitable;
068: import org.netbeans.jemmy.Waiter;
069: import org.netbeans.jemmy.operators.ComponentOperator;
070: import org.netbeans.jemmy.operators.JEditorPaneOperator;
071: import org.netbeans.jemmy.operators.JTextFieldOperator;
072:
073: //retouche:
074: //import org.netbeans.junit.ide.ProjectSupport;
075:
076: /**
077: *
078: * @author Petr Felenda, Martin Roskanin
079: */
080: public class EditorTestCase extends JellyTestCase {
081:
082: private static final int OPENED_PROJECT_ACCESS_TIMEOUT = 1000;
083:
084: /** Default name of project is used if not specified in openProject method. */
085: private String defaultProjectName = "SampleProject";
086: // private String defaultSamplePackage = "dummy";
087: // private String defaultSampleName = "sample1";
088:
089: private static final char treeSeparator = '|';
090: private final String defaultPackageNameTreePath = "Source packages"
091: + treeSeparator + "dummy";
092: private final String defaultFileName = "sample1";
093: private String projectName = null;
094: private String treeSubPackagePathToFile = null;
095: private String fileName = null;
096: private final String dialogSaveTitle = "Save"; // I18N
097: public static final int WAIT_MAX_MILIS_FOR_CLIPBOARD = 4000;
098:
099: /**
100: * Creates a new instance of EditorTestCase.
101: *
102: * <p>
103: * Initializes default sample file name (package and name)
104: * so that {@link #openDefaultSampleFile()} can be used.
105: * <br>
106: * The rule for naming is the same like for golden files
107: * i.e. package corresponds to the class name and the file
108: * name corresponds to test method name.
109: *
110: * @param testMethodName name of the test method
111: * that should be executed.
112: */
113: public EditorTestCase(String testMethodName) {
114: super (testMethodName);
115:
116: // defaultSamplePackage = getClass().getName();
117: // defaultSampleName = getName();
118: }
119:
120: /**
121: * Split class full name into package name and class name.
122: *
123: * @param full name of the class
124: * @return array containing package name and the class name.
125: */
126: /* public static String[] splitClassName(String classFullName) {
127: int lastDotIndex = classFullName.lastIndexOf('.');
128: return new String[] {
129: (lastDotIndex >= 0) ? classFullName.substring(0, lastDotIndex) : "", // pkg name
130: classFullName.substring(lastDotIndex + 1) // class name
131: };
132: }
133: */
134:
135: /** Open project. Before opening the project is checked opened projects.
136: * @param projectName is name of the project stored in .../editor/test/qa-functional/data/ directory.
137: */
138: public void openProject(String projectName) {
139: this .projectName = projectName;
140: File projectPath = new File(this .getDataDir() + "/projects",
141: projectName);
142: log("data dir = " + this .getDataDir().toString());
143:
144: /* 1. check if project is open */
145: ProjectsTabOperator pto = new ProjectsTabOperator();
146: pto.invoke();
147: boolean isOpen = true;
148: try {
149: JemmyProperties.setCurrentTimeout(
150: "JTreeOperator.WaitNextNodeTimeout",
151: OPENED_PROJECT_ACCESS_TIMEOUT);
152: ProjectRootNode prn = pto.getProjectRootNode(projectName);
153: } catch (TimeoutExpiredException ex) {
154: // This excpeiton is ok, project is not open;
155: //ex.printStackTrace();
156: isOpen = false;
157: }
158:
159: if (isOpen) {
160: log("Project is open!");
161: return;
162: }
163:
164: /* 2. open project */
165: //retouche:
166: // Object prj= ProjectSupport.openProject(projectPath);
167: }
168:
169: /**
170: * Get the default project name to be used
171: * in {@link openDefaultProject()}.
172: * <br>
173: * The default value is "editor_test".
174: *
175: * @return default project name
176: */
177: protected String getDefaultProjectName() {
178: return defaultProjectName;
179: }
180:
181: /**
182: * Set the default project name to be used
183: * in {@link openDefaultProject()}.
184: *
185: * @param defaultProjectName new default project name.
186: */
187: /*
188: protected void setDefaultProjectName(String defaultProjectName) {
189: this.defaultProjectName = defaultProjectName;
190: }
191: */
192:
193: /**
194: * Open default project determined
195: * by {@link #getDefaultProjectName()}.
196: */
197: protected void openDefaultProject() {
198: openProject(getDefaultProjectName());
199: }
200:
201: /**
202: * Close the default project.
203: */
204: protected void closeDefaultProject() {
205: closeProject(getDefaultProjectName());
206: }
207:
208: protected void closeProject(String projectName) {
209: //retouche:
210: // ProjectSupport.closeProject(projectName);
211: }
212:
213: /** Open file in open project
214: * @param treeSubPath e.g. "Source Packages|test","sample1" */
215: public void openFile(String treeSubPackagePathToFile,
216: String fileName) {
217: // debug info, to be removed
218: this .treeSubPackagePathToFile = treeSubPackagePathToFile;
219: ProjectsTabOperator pto = new ProjectsTabOperator();
220: pto.invoke();
221: ProjectRootNode prn = pto.getProjectRootNode(projectName);
222: prn.select();
223:
224: // fix of issue #51191
225: // each of nodes is checked by calling method waitForChildNode
226: // before they are actually opened
227: StringTokenizer st = new StringTokenizer(
228: treeSubPackagePathToFile, treeSeparator + "");
229: String token = "";
230: String oldtoken = "";
231: // if there are more then one tokens process each of them
232: if (st.countTokens() > 1) {
233: token = st.nextToken();
234: String fullpath = token;
235: while (st.hasMoreTokens()) {
236: token = st.nextToken();
237: waitForChildNode(fullpath, token);
238: fullpath += treeSeparator + token;
239: }
240: }
241: // last node
242: waitForChildNode(treeSubPackagePathToFile, fileName);
243: // end of fix of issue #51191
244:
245: Node node = new Node(prn, treeSubPackagePathToFile
246: + treeSeparator + fileName);
247: node.performPopupAction("Edit");
248: }
249:
250: /**
251: * Waits for a child node to be shown in the IDE. Needed for test
252: * stabilization on slow machines.
253: * @param parentPath full path for parent, | used as a delimiter
254: * @param childName name of the child node
255: */
256: public void waitForChildNode(String parentPath, String childName) {
257: ProjectsTabOperator pto = new ProjectsTabOperator();
258: ProjectRootNode prn = pto.getProjectRootNode(projectName);
259: prn.select();
260: Node parent = new Node(prn, parentPath);
261: final String finalFileName = childName;
262: try {
263: // wait for max. 30 seconds for the file node to appear
264: JemmyProperties.setCurrentTimeout("Waiter.WaitingTime",
265: 30000);
266: new Waiter(new Waitable() {
267: public Object actionProduced(Object parent) {
268: return ((Node) parent)
269: .isChildPresent(finalFileName) ? Boolean.TRUE
270: : null;
271: }
272:
273: public String getDescription() {
274: return ("Waiting for the tree to load.");
275: }
276: }).waitAction(parent);
277: } catch (InterruptedException e) {
278: throw new JemmyException("Interrupted.", e);
279: }
280: }
281:
282: /** Open the default file in open project */
283: public void openFile() {
284: openFile(defaultPackageNameTreePath, defaultFileName);
285: }
286:
287: /** Close file in open project.
288: */
289: public void closeFile() {
290: try {
291: new EditorOperator(fileName).close();
292: } catch (TimeoutExpiredException ex) {
293: log(ex.getMessage());
294: log("Can't close the file");
295: }
296: }
297:
298: /** Close file in open project.
299: */
300: public void closeFileWithSave() {
301: try {
302: new EditorOperator(fileName).close(true);
303: } catch (TimeoutExpiredException ex) {
304: log(ex.getMessage());
305: log("Can't close the file");
306: }
307: }
308:
309: /** Close file in open project.
310: */
311: public void closeFileWithDiscard() {
312: try {
313: new EditorOperator(fileName).closeDiscard();
314: } catch (TimeoutExpiredException ex) {
315: log(ex.getMessage());
316: log("Can't close the file");
317: }
318: }
319:
320: /** Close dialog with added title
321: * @param title dialog title */
322: public void closeDialog(String title) {
323: NbDialogOperator dialog = new NbDialogOperator(title);
324: dialog.closeByButton();
325: }
326:
327: /**
328: * Write the text of the passed document to the ref file
329: * and compare the created .ref file with the golden file.
330: * <br>
331: * If the two files differ the test fails and generates the diff file.
332: *
333: * @param testDoc document to be written to the .ref file and compared.
334: */
335: protected void compareReferenceFiles(Document testDoc) {
336: try {
337: ref(testDoc.getText(0, testDoc.getLength()));
338: compareReferenceFiles();
339: } catch (BadLocationException e) {
340: e.printStackTrace(getLog());
341: fail();
342: }
343: }
344:
345: /**
346: * Open a source file located in the "Source packages" in the editor.
347: *
348: * @param dir directory path with "|" separator.
349: * @param srcName source name without suffix.
350: */
351: protected void openSourceFile(String dir, String srcName) {
352: openFile(org.netbeans.jellytools.Bundle.getString(
353: "org.netbeans.modules.java.j2seproject.Bundle",
354: "NAME_src.dir")
355: + treeSeparator + dir, srcName);
356: }
357:
358: // protected final String getDefaultSamplePackage() {
359: // return defaultSamplePackage;
360: // }
361: //
362: // protected final String getDefaultSampleName() {
363: // return defaultSampleName;
364: // }
365:
366: // protected void openDefaultSampleFile() {
367: // openSourceFile(defaultSamplePackage, defaultSampleName);
368: // }
369:
370: // protected EditorOperator getDefaultSampleEditorOperator() {
371: // return new EditorOperator(defaultSampleName);
372: // }
373:
374: /** Method will wait max. <code> maxMiliSeconds </code> miliseconds for the <code> requiredValue </code>
375: * gathered by <code> resolver </code>.
376: *
377: * @param maxMiliSeconds maximum time to wait for requiredValue
378: * @param resolver resolver, which is gathering an actual value
379: * @param requiredValue if resolver value equals requiredValue the wait cycle is finished
380: *
381: * @return false if the given maxMiliSeconds time elapsed and the requiredValue wasn't obtained
382: */
383: protected boolean waitMaxMilisForValue(int maxMiliSeconds,
384: ValueResolver resolver, Object requiredValue) {
385: int time = (int) maxMiliSeconds / 100;
386: while (time > 0) {
387: Object resolvedValue = resolver.getValue();
388: if (requiredValue == null && resolvedValue == null) {
389: return true;
390: }
391: if (requiredValue != null
392: && requiredValue.equals(resolvedValue)) {
393: return true;
394: }
395: try {
396: Thread.currentThread().sleep(100);
397: } catch (InterruptedException ex) {
398: time = 0;
399: }
400: time--;
401: }
402: return false;
403: }
404:
405: /** Interface for value resolver needed for i.e. waitMaxMilisForValue method.
406: * For more details, please look at {@link #waitMaxMilisForValue()}.
407: */
408: public static interface ValueResolver {
409: /** Returns checked value */
410: Object getValue();
411: }
412:
413: protected ValueResolver getClipboardResolver(
414: final JEditorPaneOperator txtOper, final int key,
415: final int mod, final String oldVal) {
416:
417: ValueResolver clipboardValueResolver = new ValueResolver() {
418: public Object getValue() {
419: txtOper.pushKey(key, mod);
420: Transferable newClipValue = txtOper.getToolkit()
421: .getSystemClipboard().getContents(txtOper);
422: String newVal = getClipBoardContent(newClipValue);
423: log("newClipValue:" + newVal);
424: return (newVal.equals(oldVal)) ? Boolean.TRUE
425: : Boolean.FALSE;
426: }
427: };
428:
429: return clipboardValueResolver;
430: }
431:
432: protected ValueResolver getTextFieldResolver(
433: final JTextFieldOperator oper, final String newValue) {
434: ValueResolver textFieldResolver = new ValueResolver() {
435: public Object getValue() {
436: String actVal = oper.getText();
437: log("actual value:" + actVal);
438: return (newValue.equals(actVal)) ? Boolean.TRUE
439: : Boolean.FALSE;
440: }
441: };
442:
443: return textFieldResolver;
444: }
445:
446: private String getClipBoardContent(Transferable clip) {
447: DataFlavor[] df = clip.getTransferDataFlavors();
448: for (int i = 0; i < df.length; i++) {
449: DataFlavor dataFlavor = df[i];
450: log("Mime: " + dataFlavor.getMimeType());
451: log("Class: "
452: + dataFlavor.getRepresentationClass().getName());
453: log("Class2: "
454: + dataFlavor.getDefaultRepresentationClass()
455: .getName());
456: try {
457: log(clip.getTransferData(dataFlavor).getClass()
458: .getName());
459: } catch (IOException ioe) {
460:
461: } catch (UnsupportedFlavorException ufe) {
462:
463: }
464: }
465:
466: String val = null;
467: try {
468: val = (String) clip
469: .getTransferData(new DataFlavor(
470: "text/plain; class=java.lang.String; charset=Unicode"));
471: } catch (UnsupportedFlavorException ex) {
472: fail(ex);
473: } catch (IOException ex) {
474: fail(ex);
475: } catch (ClassNotFoundException ex) {
476: fail(ex);
477: }
478: return val;
479: }
480:
481: protected void cutCopyViaStrokes(JEditorPaneOperator txtOper,
482: int key, int mod) {
483: Transferable oldClipValue = txtOper.getToolkit()
484: .getSystemClipboard().getContents(txtOper);
485: String oldVal = getClipBoardContent(oldClipValue);
486: log("");
487: log("oldClipValue:" + oldVal);
488: txtOper.requestFocus();
489: txtOper.pushKey(key, mod);
490: // give max WAIT_MAX_MILIS_FOR_CLIPBOARD milis for clipboard to change
491: boolean success = waitMaxMilisForValue(
492: WAIT_MAX_MILIS_FOR_CLIPBOARD, getClipboardResolver(
493: txtOper, key, mod, oldVal), Boolean.FALSE);
494: if (success == false) {
495: // give it one more chance. maybe selection was not ready at the time of
496: // copying
497: log("!!!! ONCE AGAIN");
498: txtOper.pushKey(key, mod);
499: // give max WAIT_MAX_MILIS_FOR_CLIPBOARD milis for clipboard to change
500: waitMaxMilisForValue(WAIT_MAX_MILIS_FOR_CLIPBOARD,
501: getClipboardResolver(txtOper, key, mod, oldVal),
502: Boolean.FALSE);
503: }
504: }
505:
506: protected void pasteViaStrokes(ComponentOperator compOper, int key,
507: int mod, ValueResolver resolver) {
508: compOper.pushKey(key, mod);
509: // give max WAIT_MAX_MILIS_FOR_CLIPBOARD milis for clipboard to change
510: if (resolver != null) {
511: boolean success = waitMaxMilisForValue(
512: WAIT_MAX_MILIS_FOR_CLIPBOARD, resolver,
513: Boolean.TRUE);
514: if (success == false) {
515: // give it one more chance.
516: compOper.pushKey(key, mod);
517: // give max WAIT_MAX_MILIS_FOR_CLIPBOARD milis for clipboard to change
518: waitMaxMilisForValue(WAIT_MAX_MILIS_FOR_CLIPBOARD,
519: resolver, Boolean.TRUE);
520: }
521: }
522: }
523:
524: }
|