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-2007 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 bookmarks;
049:
050: import java.awt.datatransfer.Transferable;
051: import java.io.File;
052: import java.util.StringTokenizer;
053: import javax.swing.text.BadLocationException;
054: import javax.swing.text.Document;
055: import org.netbeans.jellytools.EditorOperator;
056: import org.netbeans.jellytools.JellyTestCase;
057: import org.netbeans.jellytools.NbDialogOperator;
058: import org.netbeans.jellytools.ProjectsTabOperator;
059: import org.netbeans.jellytools.nodes.Node;
060: import org.netbeans.jellytools.nodes.ProjectRootNode;
061: import org.netbeans.jemmy.JemmyException;
062: import org.netbeans.jemmy.JemmyProperties;
063: import org.netbeans.jemmy.TimeoutExpiredException;
064: import org.netbeans.jemmy.Waitable;
065: import org.netbeans.jemmy.Waiter;
066: import org.netbeans.jemmy.operators.ComponentOperator;
067: import org.netbeans.jemmy.operators.JEditorPaneOperator;
068: import org.netbeans.jemmy.operators.JTextFieldOperator;
069: import org.netbeans.junit.ide.ProjectSupport;
070:
071: /**
072: *
073: * @author Petr Felenda, Martin Roskanin
074: */
075: public class EditorTestCase extends JellyTestCase {
076:
077: private static final int OPENED_PROJECT_ACCESS_TIMEOUT = 1000;
078:
079: /** Default name of project is used if not specified in openProject method. */
080: private String defaultProjectName = "editor_test";
081: private String defaultSamplePackage = "dummy";
082: private String defaultSampleName = "sample1";
083:
084: private static final char treeSeparator = '|';
085: private final String defaultPackageNameTreePath = "Source packages"
086: + treeSeparator + "dummy";
087: private final String defaultFileName = "sample1";
088: private String projectName = null;
089: private String treeSubPackagePathToFile = null;
090: private String fileName = null;
091: private final String dialogSaveTitle = "Save"; // I18N
092: public static final int WAIT_MAX_MILIS_FOR_CLIPBOARD = 4000;
093:
094: /**
095: * Creates a new instance of EditorTestCase.
096: *
097: * <p>
098: * Initializes default sample file name (package and name)
099: * so that {@link #openDefaultSampleFile()} can be used.
100: * <br>
101: * The rule for naming is the same like for golden files
102: * i.e. package corresponds to the class name and the file
103: * name corresponds to test method name.
104: *
105: * @param testMethodName name of the test method
106: * that should be executed.
107: */
108: public EditorTestCase(String testMethodName) {
109: super (testMethodName);
110:
111: defaultSamplePackage = getClass().getName();
112: defaultSampleName = getName();
113: }
114:
115: /** Open project. Before opening the project is checked opened projects.
116: * @param projectName is name of the project stored in .../editor/test/qa-functional/data/ directory.
117: */
118: public void openProject(String projectName) {
119: this .projectName = projectName;
120: File projectPath = new File(this .getDataDir() + "/projects",
121: projectName);
122: log("data dir = " + this .getDataDir().toString());
123:
124: /* 1. check if project is open */
125: ProjectsTabOperator pto = new ProjectsTabOperator();
126: pto.invoke();
127: boolean isOpen = true;
128: try {
129: JemmyProperties.setCurrentTimeout(
130: "JTreeOperator.WaitNextNodeTimeout",
131: OPENED_PROJECT_ACCESS_TIMEOUT);
132: ProjectRootNode prn = pto.getProjectRootNode(projectName);
133: } catch (TimeoutExpiredException ex) {
134: // This excpeiton is ok, project is not open;
135: //ex.printStackTrace();
136: isOpen = false;
137: }
138:
139: if (isOpen) {
140: log("Project is open!");
141: return;
142: }
143:
144: /* 2. open project */
145: Object prj = ProjectSupport.openProject(projectPath);
146: }
147:
148: /**
149: * Get the default project name to be used
150: * in {@link openDefaultProject()}.
151: * <br>
152: * The default value is "editor_test".
153: *
154: * @return default project name
155: */
156: protected String getDefaultProjectName() {
157: return defaultProjectName;
158: }
159:
160: /**
161: * Open default project determined
162: * by {@link #getDefaultProjectName()}.
163: */
164: protected void openDefaultProject() {
165: openProject(getDefaultProjectName());
166: }
167:
168: /**
169: * Close the default project.
170: */
171: protected void closeDefaultProject() {
172: closeProject(getDefaultProjectName());
173: }
174:
175: protected void closeProject(String projectName) {
176: ProjectSupport.closeProject(projectName);
177: }
178:
179: /** Open file in open project
180: * @param treeSubPath e.g. "Source Packages|test","sample1" */
181: public void openFile(String treeSubPackagePathToFile,
182: String fileName) {
183: // debug info, to be removed
184: this .treeSubPackagePathToFile = treeSubPackagePathToFile;
185: ProjectsTabOperator pto = new ProjectsTabOperator();
186: pto.invoke();
187: ProjectRootNode prn = pto.getProjectRootNode(projectName);
188: prn.select();
189:
190: // fix of issue #51191
191: // each of nodes is checked by calling method waitForChildNode
192: // before they are actually opened
193: StringTokenizer st = new StringTokenizer(
194: treeSubPackagePathToFile, treeSeparator + "");
195: String token = "";
196: String oldtoken = "";
197: // if there are more then one tokens process each of them
198: if (st.countTokens() > 1) {
199: token = st.nextToken();
200: String fullpath = token;
201: while (st.hasMoreTokens()) {
202: token = st.nextToken();
203: waitForChildNode(fullpath, token);
204: fullpath += treeSeparator + token;
205: }
206: }
207: // last node
208: waitForChildNode(treeSubPackagePathToFile, fileName);
209: // end of fix of issue #51191
210:
211: Node node = new Node(prn, treeSubPackagePathToFile
212: + treeSeparator + fileName);
213: node.performPopupAction("Open");
214: }
215:
216: /**
217: * Waits for a child node to be shown in the IDE. Needed for test
218: * stabilization on slow machines.
219: * @param parentPath full path for parent, | used as a delimiter
220: * @param childName name of the child node
221: */
222: public void waitForChildNode(String parentPath, String childName) {
223: ProjectsTabOperator pto = new ProjectsTabOperator();
224: ProjectRootNode prn = pto.getProjectRootNode(projectName);
225: prn.select();
226: Node parent = new Node(prn, parentPath);
227: final String finalFileName = childName;
228: try {
229: // wait for max. 30 seconds for the file node to appear
230: JemmyProperties.setCurrentTimeout("Waiter.WaitingTime",
231: 30000);
232: new Waiter(new Waitable() {
233: public Object actionProduced(Object parent) {
234: return ((Node) parent)
235: .isChildPresent(finalFileName) ? Boolean.TRUE
236: : null;
237: }
238:
239: public String getDescription() {
240: return ("Waiting for the tree to load.");
241: }
242: }).waitAction(parent);
243: } catch (InterruptedException e) {
244: throw new JemmyException("Interrupted.", e);
245: }
246: }
247:
248: /** Open the default file in open project */
249: public void openFile() {
250: openFile(defaultPackageNameTreePath, defaultFileName);
251: }
252:
253: /** Close file in open project.
254: */
255: public void closeFile() {
256: try {
257: new EditorOperator(fileName).close();
258: } catch (TimeoutExpiredException ex) {
259: log(ex.getMessage());
260: log("Can't close the file");
261: }
262: }
263:
264: /** Close file in open project.
265: */
266: public void closeFileWithSave() {
267: try {
268: new EditorOperator(fileName).close(true);
269: } catch (TimeoutExpiredException ex) {
270: log(ex.getMessage());
271: log("Can't close the file");
272: }
273: }
274:
275: /** Close file in open project.
276: */
277: public void closeFileWithDiscard() {
278: try {
279: new EditorOperator(fileName).closeDiscard();
280: } catch (TimeoutExpiredException ex) {
281: log(ex.getMessage());
282: log("Can't close the file");
283: }
284: }
285:
286: /** Close dialog with added title
287: * @param title dialog title */
288: public void closeDialog(String title) {
289: NbDialogOperator dialog = new NbDialogOperator(title);
290: dialog.closeByButton();
291: }
292:
293: /**
294: * Write the text of the passed document to the ref file
295: * and compare the created .ref file with the golden file.
296: * <br>
297: * If the two files differ the test fails and generates the diff file.
298: *
299: * @param testDoc document to be written to the .ref file and compared.
300: */
301: protected void compareReferenceFiles(Document testDoc) {
302: try {
303: ref(testDoc.getText(0, testDoc.getLength()));
304: compareReferenceFiles();
305: } catch (BadLocationException e) {
306: e.printStackTrace(getLog());
307: fail();
308: }
309: }
310:
311: /**
312: * Open a source file located in the "Source packages" in the editor.
313: *
314: * @param dir directory path with "|" separator.
315: * @param srcName source name without suffix.
316: */
317: protected void openSourceFile(String dir, String srcName) {
318: openFile(org.netbeans.jellytools.Bundle.getString(
319: "org.netbeans.modules.java.j2seproject.Bundle",
320: "NAME_src.dir")
321: + treeSeparator + dir, srcName);
322: }
323:
324: protected final String getDefaultSamplePackage() {
325: return defaultSamplePackage;
326: }
327:
328: protected final String getDefaultSampleName() {
329: return defaultSampleName;
330: }
331:
332: protected void openDefaultSampleFile() {
333: openSourceFile(defaultSamplePackage, defaultSampleName);
334: }
335:
336: protected EditorOperator getDefaultSampleEditorOperator() {
337: return new EditorOperator(defaultSampleName);
338: }
339:
340: /** Method will wait max. <code> maxMiliSeconds </code> miliseconds for the <code> requiredValue </code>
341: * gathered by <code> resolver </code>.
342: *
343: * @param maxMiliSeconds maximum time to wait for requiredValue
344: * @param resolver resolver, which is gathering an actual value
345: * @param requiredValue if resolver value equals requiredValue the wait cycle is finished
346: *
347: * @return false if the given maxMiliSeconds time elapsed and the requiredValue wasn't obtained
348: */
349: protected boolean waitMaxMilisForValue(int maxMiliSeconds,
350: ValueResolver resolver, Object requiredValue) {
351: int time = (int) maxMiliSeconds / 100;
352: while (time > 0) {
353: Object resolvedValue = resolver.getValue();
354: if (requiredValue == null && resolvedValue == null) {
355: return true;
356: }
357: if (requiredValue != null
358: && requiredValue.equals(resolvedValue)) {
359: return true;
360: }
361: try {
362: Thread.currentThread().sleep(100);
363: } catch (InterruptedException ex) {
364: time = 0;
365: }
366: time--;
367: }
368: return false;
369: }
370:
371: /** Interface for value resolver needed for i.e. waitMaxMilisForValue method.
372: * For more details, please look at {@link #waitMaxMilisForValue()}.
373: */
374: public static interface ValueResolver {
375: /** Returns checked value */
376: Object getValue();
377: }
378:
379: }
|