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: * UMLTestCase.java
044: *
045: * Created on March 16, 2006, 12:17 PM
046: *
047: * To change this template, choose Tools | Options and locate the template under
048: * the Source Creation and Management node. Right-click the template and choose
049: * Open. You can then make changes to the template in the Source Editor.
050: */
051:
052: package org.netbeans.test.umllib.testcases;
053:
054: import java.awt.Component;
055: import java.io.File;
056: import java.io.FileWriter;
057: import java.lang.reflect.Method;
058: import java.lang.reflect.Modifier;
059: import java.util.Date;
060: import javax.swing.JButton;
061: import javax.swing.JComponent;
062: import javax.swing.JDialog;
063: import javax.swing.JFrame;
064: import org.netbeans.jellytools.JellyTestCase;
065: import org.netbeans.jellytools.MainWindowOperator;
066: import org.netbeans.jellytools.TopComponentOperator;
067: import org.netbeans.jemmy.ComponentChooser;
068: import org.netbeans.jemmy.JemmyProperties;
069: import org.netbeans.jemmy.operators.JButtonOperator;
070: import org.netbeans.jemmy.operators.JDialogOperator;
071: import org.netbeans.jemmy.operators.Operator;
072: import org.netbeans.jemmy.operators.Operator.StringComparator;
073: import org.netbeans.jemmy.operators.WindowOperator;
074: import org.netbeans.junit.NbTestCase;
075:
076: /**
077: *
078: * @author sp153251
079: */
080: public class UMLTestCase extends JellyTestCase {
081:
082: /**
083: * XTEST_WORK_DIR - xtest work dir
084: */
085: public static String XTEST_WORK_DIR = System
086: .getProperty("xtest.workdir");
087: public static String XTEST_PROJECT_DIR = XTEST_WORK_DIR
088: + "/sys/data/data";
089:
090: private static Thread save;
091: private static Thread exit;
092: //srore already reported issues
093: private static int[] reportedIssues = new int[1024];
094:
095: /** Creates a new instance of UMLTestCase */
096: /**
097: * Need to be defined because of JUnit
098: * @param name
099: */
100: public UMLTestCase(String name) {
101: super (name);
102: //maximize if it's possible with api
103: JFrame mw = (JFrame) (MainWindowOperator.getDefault()
104: .getSource());
105: if (mw.getToolkit()
106: .isFrameStateSupported(JFrame.MAXIMIZED_BOTH))
107: mw.setExtendedState(JFrame.MAXIMIZED_BOTH);
108: else
109: MainWindowOperator.getDefault().maximize();
110: //start dialog checkers/ avoid multiple threads creation
111: if (exit == null || !exit.isAlive()) {
112: exit = new Thread(
113: new TerminationDialogHandler(
114: TerminationDialogHandler.NON_TERMINATED_PROCESSES_DIALOG,
115: TerminationDialogHandler.NON_TERMINATED_PROCESSES_BUTTON));
116: exit.start();
117: }
118: if (save == null || !save.isAlive()) {
119: save = new Thread(new TerminationDialogHandler(
120: TerminationDialogHandler.SAVE_UNSAVED_DATA_DIALOG,
121: TerminationDialogHandler.SAVE_UNSAVED_DATA_BUTTON));
122: save.start();
123: }
124: JComponent nav = TopComponentOperator.findTopComponent(
125: "Navigator", 0);
126: if (nav != null)
127: new TopComponentOperator(nav).close();
128: }
129:
130: /**
131: * find name for current (executing now) test method
132: * should be called directly from method body
133: * @return returns current test method name using stacktrace
134: */
135: protected String getCurrentTestMethodName() {
136: return getCurrentTestMethodName(0);
137: }
138:
139: /**
140: * find name for current (executing now) test method
141: * can be called directly from method body or from any method called from test method with appropriate stack shift parameter
142: * @param addShift adds shift in stack to get correct method
143: * @return returns current test method name using stacktrace
144: */
145: protected String getCurrentTestMethodName(int addShift) {
146: int shift = java.lang.System.getProperty("java.version")
147: .startsWith("1.5") ? 1 : 0;
148: return Thread.currentThread().getStackTrace()[3 + shift
149: + addShift].getMethodName();
150: }
151:
152: /**
153: * find name for current (executing now) test method
154: * can be called from any level of stack, methods will find first class folowing test class requirenments
155: * test should starts with test, be public, has no argument, return void and should be in class hierarchy with org.netbeans.test.umllib.testcases.UMLTestCase
156: * @return returns current class name[0] and test method name[1] using stacktrace
157: */
158: static public String[] getCurrentTestNamesWithCheck() {
159: String[] ret = new String[2];
160: //
161: StackTraceElement[] els = Thread.currentThread()
162: .getStackTrace();
163: String className = null;
164: String methodName = null;
165:
166: for (int i = 0; i < els.length; i++) {
167: String tmpClassName = els[i].getClassName();
168: String tmpMethodName = els[i].getMethodName();
169: //first level check - test method should starts with "test"
170: if (tmpMethodName.startsWith("test")) {
171: Class testClass = null;
172: Method[] ms = null;
173: Method m = null;
174: //
175: try {
176: testClass = Class.forName(tmpClassName);
177: } catch (ClassNotFoundException ex) {
178: ex.printStackTrace();
179: }
180: if (testClass != null) {
181: //check if class
182: boolean isGoodClass = false;
183: for (Class par = testClass.getSuperclass(); par != null; par = par
184: .getSuperclass()) {
185: if (par.getName().equals(
186: UMLTestCase.class.getName())) {
187: isGoodClass = true;
188: break;
189: }
190: }
191: //
192: if (!isGoodClass)
193: continue;
194: //
195: ms = testClass.getMethods();
196: for (int j = 0; j < ms.length; j++) {
197: //check only methods with name from stack
198: if (tmpMethodName.equals(ms[j].getName())) {
199: int md = ms[j].getModifiers();
200: //if name and visibility and return type and parameters are correct we
201: //test methods can be only public
202: //no parameters,
203: if (Modifier.isPublic(md)
204: && ms[j].getParameterAnnotations().length == 0
205: && ms[j].getReturnType().getName()
206: .indexOf("void") > -1) {
207: //we got it
208: className = tmpClassName;
209: methodName = tmpMethodName;
210: break;
211: }
212: }
213: }
214: if (className != null)
215: break;
216: }
217: }
218: }
219: ret[0] = className;
220: ret[1] = methodName;
221: return ret;
222: }
223:
224: /**
225: * find name for currently executing test class, can be called if test class in current stack
226: * can be called from any level of stack, methods will find first class folowing test class requirenments
227: * public, has no argument, return void and should be in class hierarchy with org.netbeans.test.umllib.testcases.UMLTestCase
228: * @param testName - name of test method (if null class with any test method compartible method will be returned)
229: * @return returns current class name[0] and test method name[1] using stacktrace
230: */
231: static public String getCurrentClassNameWithCheck(String testName) {
232: //
233: StackTraceElement[] els = Thread.currentThread()
234: .getStackTrace();
235: String className = null;
236:
237: for (int i = 0; i < els.length; i++) {
238: String tmpClassName = els[i].getClassName();
239: //first level check
240: Class testClass = null;
241: Method[] ms = null;
242: Method m = null;
243: //
244: try {
245: testClass = Class.forName(tmpClassName);
246: } catch (Exception ex) {
247: //can't find and nothing to do
248: } catch (NoClassDefFoundError ex) {
249: //can't find and nothing to do
250: }
251: if (testClass != null
252: && !Modifier.isAbstract(testClass.getModifiers())) {
253: //check if class
254: boolean isGoodClass = false;
255: for (Class par = testClass.getSuperclass(); par != null; par = par
256: .getSuperclass()) {
257:
258: if (par.getName().equals(
259: UMLTestCase.class.getName())) {
260: isGoodClass = true;
261: break;
262: }
263: }
264: //
265: if (!isGoodClass)
266: continue;
267: //
268: ms = testClass.getMethods();
269: for (int j = 0; j < ms.length; j++) {
270: //check only methods with name from stack or if testcase unknown, check if test method only
271: if (testName == null
272: || testName.equals(ms[j].getName())) {
273: int md = ms[j].getModifiers();
274: //if name and visibility and return type and parameters are correct we
275: //test methods can be only public
276: //no parameters,
277: if (Modifier.isPublic(md)
278: && ms[j].getParameterAnnotations().length == 0
279: && ms[j].getReturnType().getName()
280: .indexOf("void") > -1) {
281: //we got it
282: className = tmpClassName;
283: break;
284: }
285: }
286: }
287: if (className != null)
288: break;
289: }
290: }
291: return className;
292: }
293:
294: /**
295: * class works until MainWindow is showing and wait for different times of dialogs
296: * if it find dialog it waits some time and close if it's unhandled by tests after some timeout
297: */
298: class TerminationDialogHandler implements Runnable {
299: private long startTime;
300: private long timeout;
301: private long prevTime;
302: //
303: private int lastBtnIndex = 0;
304: protected JDialogOperator tDlg = null;
305: //
306: private String dialogTitle;
307: private String buttonTitle[];
308: //
309: final private long EXEC_TIMEOUT = 60 * 60 * 6 * 1000;//6 hours to exit thread
310: final private long DEFAULT_TIMEOUT = 60 * 1000;//wait 60 seconds and close unused dialog
311: //
312: final static public String NON_TERMINATED_PROCESSES_DIALOG = "Exit IDE";
313: final static public String NON_TERMINATED_PROCESSES_BUTTON = "Exit IDE";
314: //
315: final static public String SAVE_UNSAVED_DATA_DIALOG = "Save";
316: final static public String SAVE_UNSAVED_DATA_BUTTON = "Save All";
317:
318: /**
319: *
320: * @param dlg
321: * @param btn
322: */
323: TerminationDialogHandler(String dlg, String btn) {
324: String tmp[] = { btn };
325: init(dlg, tmp, DEFAULT_TIMEOUT);
326: }
327:
328: /**
329: *
330: * @param dlg
331: * @param btn
332: * @param waitUntilSave
333: */
334: TerminationDialogHandler(String dlg, String btn,
335: long waitUntilSave) {
336: String tmp[] = { btn };
337: init(dlg, tmp, waitUntilSave);
338: }
339:
340: /*
341: * if press on i-throws button do not close the window, next time tries to press i+1-th button
342: */
343: /**
344: *
345: * @param dlg
346: * @param btn
347: */
348: TerminationDialogHandler(String dlg, String btn[]) {
349: init(dlg, btn, DEFAULT_TIMEOUT);
350: }
351:
352: /**
353: *
354: * @param dlg
355: * @param btn
356: * @param waitUntilSave
357: */
358: TerminationDialogHandler(String dlg, String btn[],
359: long waitUntilSave) {
360: init(dlg, btn, waitUntilSave);
361: }
362:
363: private void init(String dlg, String btn[], long waitUntilSave) {
364: dialogTitle = dlg;
365: buttonTitle = btn;
366: timeout = waitUntilSave;
367: startTime = new Date().getTime();
368: }
369:
370: public void run() {
371: MainWindowOperator mw = null;
372: while (true) {
373: try {
374: //try dialog every 30 second
375: try {
376: Thread.sleep(30 * 1000);
377: } catch (Exception ex) {
378: }
379: ;
380: mw = MainWindowOperator.getDefault();
381: if (!(mw != null && mw.isShowing() && mw
382: .isVisible())) {
383: break;
384: }
385: if ((new Date().getTime() - startTime) > EXEC_TIMEOUT) {
386: break;
387: }
388: //check if dialog was found before and still exists
389: if (tDlg != null && tDlg.isShowing()) {
390: //we are going to try another button
391: lastBtnIndex++;
392: if (lastBtnIndex >= buttonTitle.length)
393: lastBtnIndex = 0;
394: //
395: } else {
396: tDlg = null;
397: //try to find dialog
398: try {
399: tDlg = new JDialogOperator(
400: new ChooseDialogByTitleAndButton(
401: dialogTitle, buttonTitle));
402: } catch (Exception ex) {
403: //no dialog
404: }
405: }
406: JButtonOperator tBtn = null;
407: try {
408: if (tDlg != null) {
409: JButton tmp = JButtonOperator
410: .findJButton(
411: (java.awt.Dialog) (tDlg
412: .getSource()),
413: buttonTitle[lastBtnIndex],
414: true, true);
415: if (tmp != null)
416: tBtn = new JButtonOperator(tmp);
417: }
418: } catch (Exception ex) {
419: //no save button
420: }
421: //if there save dialog
422: if (tBtn != null) {
423: //wait timeout seconds
424: try {
425: Thread.sleep(timeout);
426: } catch (Exception ex) {
427: ex.printStackTrace();
428: }
429: //if dialog still here save all
430: if (tDlg.isShowing() && tDlg.isDisplayable()) {
431: tBtn.push();
432: }
433: }
434: } catch (Exception ex) {
435: }
436: }
437: }
438: }
439:
440: /**
441: * choose JDialog with appropriate exaqct title and appropriate exact button within
442: */
443: class ChooseDialogByTitleAndButton implements ComponentChooser {
444: private String title;
445: private String btn[];
446:
447: /**
448: *
449: * @param ttl
450: * @param bt
451: */
452: ChooseDialogByTitleAndButton(String ttl, String bt[]) {
453: title = ttl;
454: btn = bt;
455: }
456:
457: /**
458: *
459: * @return
460: */
461: public String getDescription() {
462: return "find dialog with " + title + " title and buttons "
463: + btn;
464: }
465:
466: /**
467: *
468: * @param component
469: * @return
470: */
471: public boolean checkComponent(Component component) {
472: if (component instanceof java.awt.Dialog) {
473: if (((java.awt.Dialog) component).getTitle().equals(
474: title)) {
475: boolean all_btns = true;
476: for (int i = 0; i < btn.length && all_btns; i++) {
477: all_btns &= JButtonOperator.findJButton(
478: (java.awt.Dialog) component, btn[i],
479: true, true) != null;
480: }
481: return all_btns;
482: }
483: }
484: return false;
485: }
486: }
487:
488: /**
489: * Backward compartibility section
490: */
491: /**
492: * @deprecated use failByBug method directly
493: */
494: public void assertTrue(int bugId, String message, boolean condition) {
495: if (!condition)
496: failByBug(bugId, message);
497: }
498:
499: /**
500: * @deprecated use failByBug method directly
501: */
502: public void assertFalse(int bugId, String message, boolean condition) {
503: if (condition)
504: failByBug(bugId, message);
505: }
506:
507: /**
508: * @deprecated use failByBug method directly
509: */
510: public void fail(int bugId, String message) {
511: failByBug(bugId, message);
512: }
513:
514: /**
515: * @deprecated use failByBug method directly
516: */
517: public void fail(int bugId) {
518: failByBug(bugId);
519: }
520:
521: }
|