001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.tests.harness.util;
011:
012: import java.io.IOException;
013: import java.io.OutputStream;
014: import java.io.PrintStream;
015: import java.util.ArrayList;
016: import java.util.Iterator;
017: import java.util.List;
018:
019: import junit.framework.TestCase;
020:
021: import org.eclipse.core.resources.ResourcesPlugin;
022: import org.eclipse.core.runtime.CoreException;
023: import org.eclipse.core.runtime.IAdaptable;
024: import org.eclipse.core.runtime.IStatus;
025: import org.eclipse.swt.widgets.Display;
026: import org.eclipse.swt.widgets.Shell;
027: import org.eclipse.ui.IWindowListener;
028: import org.eclipse.ui.IWorkbench;
029: import org.eclipse.ui.IWorkbenchPage;
030: import org.eclipse.ui.IWorkbenchWindow;
031: import org.eclipse.ui.PlatformUI;
032: import org.eclipse.ui.WorkbenchException;
033:
034: /**
035: * <code>UITestCase</code> is a useful super class for most
036: * UI tests cases. It contains methods to create new windows
037: * and pages. It will also automatically close the test
038: * windows when the tearDown method is called.
039: */
040: public abstract class UITestCase extends TestCase {
041:
042: /**
043: * Returns the workbench page input to use for newly created windows.
044: *
045: * @return the page input to use for newly created windows
046: * @since 3.1
047: */
048: public static IAdaptable getPageInput() {
049: return ResourcesPlugin.getWorkspace().getRoot();
050: }
051:
052: class TestWindowListener implements IWindowListener {
053: private boolean enabled = true;
054:
055: public void setEnabled(boolean enabled) {
056: this .enabled = enabled;
057: }
058:
059: public void windowActivated(IWorkbenchWindow window) {
060: // do nothing
061: }
062:
063: public void windowDeactivated(IWorkbenchWindow window) {
064: // do nothing
065: }
066:
067: public void windowClosed(IWorkbenchWindow window) {
068: if (enabled)
069: testWindows.remove(window);
070: }
071:
072: public void windowOpened(IWorkbenchWindow window) {
073: if (enabled)
074: testWindows.add(window);
075: }
076: }
077:
078: protected IWorkbench fWorkbench;
079:
080: private List testWindows;
081:
082: private TestWindowListener windowListener;
083:
084: public UITestCase(String testName) {
085: super (testName);
086: // ErrorDialog.NO_UI = true;
087: fWorkbench = PlatformUI.getWorkbench();
088: testWindows = new ArrayList(3);
089: }
090:
091: /**
092: * Fails the test due to the given throwable.
093: */
094: public static void fail(String message, Throwable e) {
095: // If the exception is a CoreException with a multistatus
096: // then print out the multistatus so we can see all the info.
097: if (e instanceof CoreException) {
098: IStatus status = ((CoreException) e).getStatus();
099: write(status, 0);
100: } else
101: e.printStackTrace();
102: fail(message + ": " + e);
103: }
104:
105: private static void indent(OutputStream output, int indent) {
106: for (int i = 0; i < indent; i++)
107: try {
108: output.write("\t".getBytes());
109: } catch (IOException e) {
110: // ignore
111: }
112: }
113:
114: private static void write(IStatus status, int indent) {
115: PrintStream output = System.out;
116: indent(output, indent);
117: output.println("Severity: " + status.getSeverity());
118:
119: indent(output, indent);
120: output.println("Plugin ID: " + status.getPlugin());
121:
122: indent(output, indent);
123: output.println("Code: " + status.getCode());
124:
125: indent(output, indent);
126: output.println("Message: " + status.getMessage());
127:
128: if (status.getException() != null) {
129: indent(output, indent);
130: output.print("Exception: ");
131: status.getException().printStackTrace(output);
132: }
133:
134: if (status.isMultiStatus()) {
135: IStatus[] children = status.getChildren();
136: for (int i = 0; i < children.length; i++)
137: write(children[i], indent + 1);
138: }
139: }
140:
141: /**
142: * Adds a window listener to the workbench to keep track of
143: * opened test windows.
144: */
145: private void addWindowListener() {
146: windowListener = new TestWindowListener();
147: fWorkbench.addWindowListener(windowListener);
148: }
149:
150: /**
151: * Removes the listener added by <code>addWindowListener</code>.
152: */
153: private void removeWindowListener() {
154: if (windowListener != null) {
155: fWorkbench.removeWindowListener(windowListener);
156: }
157: }
158:
159: /**
160: * Outputs a trace message to the trace output device, if enabled.
161: * By default, trace messages are sent to <code>System.out</code>.
162: *
163: * @param msg the trace message
164: */
165: protected void trace(String msg) {
166: System.err.println(msg);
167: }
168:
169: /**
170: * Simple implementation of setUp. Subclasses are prevented
171: * from overriding this method to maintain logging consistency.
172: * doSetUp() should be overriden instead.
173: */
174: protected final void setUp() throws Exception {
175: super .setUp();
176: trace("----- " + this .getName()); //$NON-NLS-1$
177: trace(this .getName() + ": setUp..."); //$NON-NLS-1$
178: addWindowListener();
179: doSetUp();
180:
181: }
182:
183: /**
184: * Sets up the fixture, for example, open a network connection.
185: * This method is called before a test is executed.
186: * The default implementation does nothing.
187: * Subclasses may extend.
188: */
189: protected void doSetUp() throws Exception {
190: // do nothing.
191: }
192:
193: /**
194: * Simple implementation of tearDown. Subclasses are prevented
195: * from overriding this method to maintain logging consistency.
196: * doTearDown() should be overriden instead.
197: */
198: protected final void tearDown() throws Exception {
199: super .tearDown();
200: trace(this .getName() + ": tearDown...\n"); //$NON-NLS-1$
201: removeWindowListener();
202: doTearDown();
203: }
204:
205: /**
206: * Tears down the fixture, for example, close a network connection.
207: * This method is called after a test is executed.
208: * The default implementation closes all test windows, processing events both before
209: * and after doing so.
210: * Subclasses may extend.
211: */
212: protected void doTearDown() throws Exception {
213: processEvents();
214: closeAllTestWindows();
215: processEvents();
216: }
217:
218: protected static void processEvents() {
219: Display display = PlatformUI.getWorkbench().getDisplay();
220: if (display != null)
221: while (display.readAndDispatch())
222: ;
223: }
224:
225: /**
226: * Open a test window with the empty perspective.
227: */
228: public IWorkbenchWindow openTestWindow() {
229: return openTestWindow(EmptyPerspective.PERSP_ID);
230: }
231:
232: /**
233: * Open a test window with the provided perspective.
234: */
235: public IWorkbenchWindow openTestWindow(String perspectiveId) {
236: try {
237: IWorkbenchWindow window = fWorkbench.openWorkbenchWindow(
238: perspectiveId, getPageInput());
239: waitOnShell(window.getShell());
240: return window;
241: } catch (WorkbenchException e) {
242: fail();
243: return null;
244: }
245: }
246:
247: /**
248: * Try and process events until the new shell is the active shell. This may
249: * never happen, so time out after a suitable period.
250: *
251: * @param shell
252: * the shell to wait on
253: * @since 3.2
254: */
255: private void waitOnShell(Shell shell) {
256:
257: processEvents();
258: // long endTime = System.currentTimeMillis() + 5000;
259: //
260: // while (shell.getDisplay().getActiveShell() != shell
261: // && System.currentTimeMillis() < endTime) {
262: // processEvents();
263: // }
264: }
265:
266: /**
267: * Close all test windows.
268: */
269: public void closeAllTestWindows() {
270: Iterator iter = new ArrayList(testWindows).iterator();
271: while (iter.hasNext()) {
272: IWorkbenchWindow win = (IWorkbenchWindow) iter.next();
273: win.close();
274: }
275: testWindows.clear();
276: }
277:
278: /**
279: * Open a test page with the empty perspective in a window.
280: */
281: public IWorkbenchPage openTestPage(IWorkbenchWindow win) {
282: IWorkbenchPage[] pages = openTestPage(win, 1);
283: if (pages != null)
284: return pages[0];
285: else
286: return null;
287: }
288:
289: /**
290: * Open "n" test pages with the empty perspective in a window.
291: */
292: public IWorkbenchPage[] openTestPage(IWorkbenchWindow win,
293: int pageTotal) {
294: try {
295: IWorkbenchPage[] pages = new IWorkbenchPage[pageTotal];
296: IAdaptable input = getPageInput();
297:
298: for (int i = 0; i < pageTotal; i++) {
299: pages[i] = win.openPage(EmptyPerspective.PERSP_ID,
300: input);
301: }
302: return pages;
303: } catch (WorkbenchException e) {
304: fail();
305: return null;
306: }
307: }
308:
309: /**
310: * Close all pages within a window.
311: */
312: public void closeAllPages(IWorkbenchWindow window) {
313: IWorkbenchPage[] pages = window.getPages();
314: for (int i = 0; i < pages.length; i++)
315: pages[i].close();
316: }
317:
318: /**
319: * Set whether the window listener will manage opening and closing of created windows.
320: */
321: protected void manageWindows(boolean manage) {
322: windowListener.setEnabled(manage);
323: }
324:
325: /**
326: * Returns the workbench.
327: *
328: * @return the workbench
329: * @since 3.1
330: */
331: protected IWorkbench getWorkbench() {
332: return fWorkbench;
333: }
334: }
|