001: package abbot.tester;
002:
003: import java.applet.Applet;
004: import java.awt.*;
005: import java.awt.event.*;
006: import java.io.*;
007: import java.lang.reflect.*;
008: import java.util.*;
009: import javax.swing.*;
010: import sun.awt.AppContext;
011: import sun.awt.SunToolkit;
012: import sun.applet.AppletPanel;
013:
014: import abbot.*;
015: import abbot.util.AWT;
016: import abbot.script.*;
017: import abbot.tester.Robot;
018: import junit.extensions.abbot.*;
019: import junit.extensions.abbot.Timer;
020:
021: /** Unit test to verify Robot operation on applets.<p> */
022:
023: public class RobotAppletTest extends ComponentTestFixture {
024:
025: private static boolean manual;
026:
027: // TODO: figure out a way to kill the event dispatch threads started by
028: // each instantiation of AppletViewer; they should die on their own but
029: // something seems to be resurrecting them (Robot.waitForIdle may be
030: // partly responsible).
031:
032: private Robot robot;
033:
034: protected void setUp() {
035: robot = getRobot();
036: appletStartCount = 0;
037: }
038:
039: // Until applet disposal is worked out, only run these tests manually
040: public void runBare() throws Throwable {
041: if (manual) {
042: super .runBare();
043: }
044: }
045:
046: // Ensure the applet is properly shut down before automatic window
047: // disposal happens, or we're left with lingering EDTs and event queues.
048: protected void tearDown() throws Exception {
049: // must close via menu "File|Quit" (not dispose)
050: // to properly get rid of appletviewer
051: for (Iterator i = getHierarchy().getRoots().iterator(); i
052: .hasNext();) {
053: Window w = (Window) i.next();
054: if (w instanceof Frame
055: && "sun.applet.AppletViewer".equals(w.getClass()
056: .getName())) {
057: robot.selectAWTMenuItem((Frame) w, "Applet|Close");
058: }
059: }
060: while (System.getSecurityManager() != oldsm) {
061: Thread.sleep(10);
062: }
063: oldsm = null;
064: }
065:
066: static Object lock = new Object();
067: private static final String TAG = " (applet test)";
068:
069: public static class TestApplet extends Applet {
070: public static volatile Applet testInstance;
071:
072: public void start() {
073: ++appletStartCount;
074: }
075:
076: public void init() {
077: String name = Thread.currentThread().getName();
078: Thread.currentThread().setName(name + TAG);
079: testInstance = this ;
080: System.out.println("applet context="
081: + sun.awt.AppContext.getAppContext());
082: SwingUtilities.invokeLater(new Runnable() {
083: public void run() {
084: Thread thread = Thread.currentThread();
085: String name = thread.getName();
086: if (name.indexOf(TAG) == -1) {
087: thread.setName(name + TAG);
088: }
089: }
090: });
091: }
092: }
093:
094: public static class ColoredApplet extends TestApplet {
095: public TextField text;
096:
097: public ColoredApplet() {
098: setName(getClass().getName());
099: }
100:
101: public ColoredApplet(Color c) {
102: setBackground(c);
103: }
104:
105: public void init() {
106: super .init();
107: text = new TextField(ColoredApplet.this .getName());
108: text.setBackground(getBackground());
109: add(text);
110: }
111: }
112:
113: public static class RedApplet extends ColoredApplet {
114: public static volatile ColoredApplet instance = null;
115: public static volatile boolean destroyed = false;
116:
117: public RedApplet() {
118: super (Color.red);
119: }
120:
121: public void start() {
122: super .start();
123: instance = this ;
124: }
125:
126: public void destroy() {
127: super .destroy();
128: instance = null;
129: }
130: }
131:
132: public static class GreenApplet extends ColoredApplet {
133: public static volatile ColoredApplet instance = null;
134: public static volatile boolean destroyed = false;
135:
136: public GreenApplet() {
137: super (Color.green);
138: }
139:
140: public void start() {
141: super .start();
142: instance = this ;
143: }
144:
145: public void destroy() {
146: super .destroy();
147: instance = null;
148: }
149: }
150:
151: private class FocusWatcher extends FocusAdapter {
152: public volatile boolean gotFocus = false;
153:
154: public void focusGained(FocusEvent f) {
155: gotFocus = true;
156: Log.log("AppContext="
157: + AWT.getAppContext(f.getComponent()).hashCode());
158: }
159: }
160:
161: private volatile int appletCount;
162: private volatile static int appletStartCount;
163: private File htmlFile;
164: private SecurityManager oldsm;
165: private AppContext appletContext;
166:
167: private void launch(String[] classNames) throws Exception {
168: appletCount = classNames.length;
169: StringBuffer html = new StringBuffer();
170: for (int i = 0; i < classNames.length; i++) {
171: html
172: .append("<html><applet codebase=\"build/classes\" code=\"");
173: html.append(classNames[i]);
174: html.append("\" width=\"100\" height=\"100\"></applet>");
175: }
176: html.append("</html>");
177: // HTML file must be a relative path
178: File dir = new File(System.getProperty("user.dir"));
179: htmlFile = File.createTempFile(getName(), ".html", dir);
180: htmlFile.deleteOnExit();
181: FileOutputStream os = new FileOutputStream(htmlFile);
182: os.write(html.toString().getBytes());
183: os.close();
184: // The appletviewer and security manager must share a class loader
185: // We use AppClassLoader b/c it knows how to reload AppletViewer
186: final AppClassLoader cl = new AppClassLoader(".");
187: oldsm = System.getSecurityManager();
188: // Make sure we catch the appletviewer exit exception
189: String tgname = getName() + " Thread Group for catching exit";
190: final ThreadGroup group = new ThreadGroup(tgname) {
191: public void uncaughtException(Thread t, Throwable thrown) {
192: if (!(thrown instanceof ExitException)
193: && !(thrown instanceof ThreadDeath))
194: Log.warn(thrown);
195: }
196: };
197: Thread thread = new Thread(group, "AppletViewer Launcher") {
198: public void run() {
199: //appletContext = SunToolkit.createNewAppContext();
200: try {
201: Class cls = Class.forName(
202: "abbot.script.AppletSecurityManager", true,
203: cl);
204: Constructor ctor = cls.getConstructor(new Class[] {
205: SecurityManager.class, boolean.class, });
206: SecurityManager asm = (SecurityManager) ctor
207: .newInstance(new Object[] { oldsm,
208: Boolean.TRUE, });
209: // Ensure AppletViewer is loaded by an instance of
210: // AppClassLoader, which can ensure the class gets
211: // discarded after the test.
212: cls = Class.forName("sun.applet.Main", true, cl);
213: System.setSecurityManager(asm);
214: cls.getMethod("main",
215: new Class[] { String[].class }).invoke(
216: null,
217: new Object[] { new String[] { htmlFile
218: .getName() } });
219: } catch (Exception e) {
220: Log.warn(e);
221: }
222: }
223: };
224: thread.setContextClassLoader(cl);
225: thread.start();
226:
227: getWindowTracker();
228: Timer timer = new Timer();
229: while (appletStartCount < appletCount) {
230: if (timer.elapsed() > 60000) {
231: fail("AppletViewer failed to launch");
232: }
233: robot.sleep();
234: }
235: }
236:
237: // NOTE: maybe abstract this to an applet test fixture, which takes the
238: // applet class (or a list of them) as an argument and makes appletviewer
239: // display them
240: public void testFocusApplet() throws Exception {
241: launch(new String[] { RedApplet.class.getName(),
242: GreenApplet.class.getName() });
243: ColoredApplet green = GreenApplet.instance;
244: ColoredApplet red = RedApplet.instance;
245:
246: FocusWatcher fw = new FocusWatcher();
247: red.text.addFocusListener(fw);
248: robot.focus(red.text, true);
249: Timer timer = new Timer();
250: while (!fw.gotFocus) {
251: if (timer.elapsed() > EVENT_GENERATION_DELAY) {
252: Log.log("Failing applet focus");
253: fail("Red applet text field never received focus");
254: }
255: robot.sleep();
256: }
257: fw = new FocusWatcher();
258: green.text.addFocusListener(fw);
259: robot.focus(green.text, true);
260: timer.reset();
261: while (!fw.gotFocus) {
262: if (timer.elapsed() > EVENT_GENERATION_DELAY) {
263: Log.log("Failing text field focus");
264: fail("Green applet text field never received focus");
265: }
266: robot.sleep();
267: }
268: }
269:
270: private static abstract class AbstractComponentApplet extends
271: TestApplet {
272: public static Component component;
273:
274: protected abstract Component getComponent();
275:
276: public void init() {
277: super .init();
278: add(component = getComponent());
279: }
280: }
281:
282: public static class TextFieldApplet extends AbstractComponentApplet {
283: protected Component getComponent() {
284: return new TextField("wider field");
285: }
286: }
287:
288: public static class JTextFieldApplet extends
289: AbstractComponentApplet {
290: protected Component getComponent() {
291: return new JTextField("wider field");
292: }
293: }
294:
295: // FIXME fails on linux 1.4.2_04, AWT mode, pointer focus
296: // Can't stuff a TextField with AWT events
297: public void testTextFieldEntry() throws Exception {
298: launch(new String[] { TextFieldApplet.class.getName() });
299: String TEXT = "a few more";
300: TextField tf = (TextField) TextFieldApplet.component;
301: tf.setText("");
302: robot.waitForIdle();
303: robot.focus(tf, true);
304: robot.keyString(TEXT);
305: robot.waitForIdle();
306: assertEquals("Text not entered", TEXT, tf.getText());
307: }
308:
309: // This fails on linux/twm/pointer focus/1.4.1_02; the text
310: // isn't directed to the proper window
311: public void testJTextFieldEntry() throws Exception {
312: launch(new String[] { JTextFieldApplet.class.getName() });
313: JTextField tf = (JTextField) JTextFieldApplet.component;
314: tf.setText("");
315: robot.waitForIdle();
316: robot.focus(tf, true);
317: String TEXT = "a few more";
318: robot.keyString(TEXT);
319: robot.waitForIdle();
320: assertEquals("Text not entered", TEXT, tf.getText());
321: }
322:
323: public static class JButtonApplet extends AbstractComponentApplet {
324: protected Component getComponent() {
325: return new JButton("button");
326: }
327: }
328:
329: public void testJButtonPress() throws Exception {
330: launch(new String[] { JButtonApplet.class.getName() });
331: final JButton b = (JButton) JButtonApplet.component;
332: final String expected = "Text changed";
333: b.addActionListener(new ActionListener() {
334: public void actionPerformed(ActionEvent e) {
335: b.setText(expected);
336: }
337: });
338: robot.click(b);
339: robot.waitForIdle();
340: assertEquals("Button not hit", expected, b.getText());
341: }
342:
343: private void closeAll(Window w) {
344: Window[] owned = w.getOwnedWindows();
345: for (int i = 0; i < owned.length; i++) {
346: closeAll(owned[i]);
347: }
348: robot.close(w);
349: }
350:
351: /*
352: public void testZZZ() {
353: System.out.println("Get stack trace now");
354: while(true);
355: }
356: */
357: /** Create a new test case with the given name. */
358: public RobotAppletTest(String name) {
359: super (name);
360: }
361:
362: /** Provide for repetitive testing on individual tests. */
363: public static void main(String[] args) {
364: manual = true;
365: RepeatHelper.runTests(args, RobotAppletTest.class);
366: }
367: }
|