/** * Factory method, equivalent to a "fromXML" for step creation. Looks for a class with the same * name as the XML tag, with the first letter capitalized. For example, <call /> is * abbot.script.Call. */ public static Step createStep(Resolver resolver, Element el) throws InvalidScriptException { String tag = el.getName(); Map attributes = createAttributeMap(el); String name = tag.substring(0, 1).toUpperCase() + tag.substring(1); if (tag.equals(TAG_WAIT)) { attributes.put(TAG_WAIT, "true"); name = "Assert"; } try { name = "abbot.script." + name; Log.debug("Instantiating " + name); Class cls = Class.forName(name); try { // Steps with contents require access to the XML element Class[] argTypes = new Class[] {Resolver.class, Element.class, Map.class}; Constructor ctor = cls.getConstructor(argTypes); return (Step) ctor.newInstance(new Object[] {resolver, el, attributes}); } catch (NoSuchMethodException nsm) { // All steps must support this ctor Class[] argTypes = new Class[] {Resolver.class, Map.class}; Constructor ctor = cls.getConstructor(argTypes); return (Step) ctor.newInstance(new Object[] {resolver, attributes}); } } catch (ClassNotFoundException cnf) { String msg = Strings.get("step.unknown_tag", new Object[] {tag}); throw new InvalidScriptException(msg); } catch (InvocationTargetException ite) { Log.warn(ite); throw new InvalidScriptException(ite.getTargetException().getMessage()); } catch (Exception exc) { Log.warn(exc); throw new InvalidScriptException(exc.getMessage()); } }
/** * Return whether an event was generated. Assumes a SemanticRecorder is active. * * @throws RecordingFailedException if an error was encountered. */ private boolean saveSemanticEvent() throws RecordingFailedException { Log.log("Storing event from current semantic recorder"); try { Step step = semanticRecorder.getStep(); if (step != null) { insertStep(step); setStatus("Added " + step); } else { setStatus("No semantic event found, events skipped"); } semanticRecorder = null; return step != null; } catch (BugReport bug) { // changed to windowtester exception // throw new RecordingFailedException(bug); throw new com.windowtester.swing.recorder.RecordingFailedException(bug); } catch (Exception e) { Log.log("Recording failed when saving action: " + e); // 1/3/07 kp: change message to windowtester message // String msg = Strings.get("editor.recording.exception"); String msg = "Windowtester recording exception"; // throw new RecordingFailedException(new BugReport(msg, e)); throw new com.windowtester.swing.recorder.RecordingFailedException(new BugReport(msg, e)); } }
/** * Handle an event. This can either be ignored or contribute to the recording. For a given event, * if no current semantic recorder is active, select one based on the event's component. If the * semantic recorder accepts the event, then it is used to consume each subsequent event, until * its recordEvent method returns true, indicating that the semantic event has completed. */ protected void recordEvent(java.awt.AWTEvent event) throws RecordingFailedException { // Discard any key/button release events at the start of the recording. if (steps.size() == 0 && event.getID() == KeyEvent.KEY_RELEASED) { Log.log("Ignoring initial release event"); return; } SemanticRecorder newRecorder = null; // Process extraneous key modifiers used to simulate mouse buttons // Only check events while we have no semantic recorder, though, // because we wish to ignore everything between the modifiers if (Platform.isMacintosh() && semanticRecorder == null) { if (pruneClickModifiers(event)) return; } if (semanticRecorder == null) { SemanticRecorder sr = (event.getSource() instanceof Component) ? getSemanticRecorder((Component) event.getSource()) // Use ComponentRecorder for MenuComponents : getSemanticRecorder(Component.class); if (sr.accept(event)) { semanticRecorder = newRecorder = sr; setStatus("Recording semantic event with " + sr); if (event.getSource() instanceof JInternalFrame) { // Ideally, adding an extra listener would be done by the // JInternalFrameRecorder, but the object needs more state // than is available to the recorder (notably to be able // to send events to the primary recorder). If something // else turns up similar to this, then the EventRecorder // should be made available to the semantic recorders. // // Must add a listener, since COMPONENT_HIDDEN is not sent // on JInternalFrame close (1.4.1). JInternalFrame f = (JInternalFrame) event.getSource(); new InternalFrameWatcher(f); } } } // If we're currently recording a semantic event, continue to do so if (semanticRecorder != null) { boolean consumed = semanticRecorder.record(event); boolean finished = semanticRecorder.isFinished(); if (finished) { Log.debug("Semantic recorder is finished"); saveSemanticEvent(); } // If not consumed, need to check for semantic recorder (again) // (but avoid recursing indefinitely) if (!consumed && newRecorder == null) { Log.debug("Event was not consumed, parse it again"); recordEvent(event); } } else { captureRawEvent(event); } }
/** Remove keypress events preceding and following ActionMap actions. */ private void removeShortcutModifierKeyPresses() { int current = 0; int mask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); String modifier = AWT.getKeyCode(AWT.maskToKeyCode(mask)); while (current < steps.size()) { Step step = (Step) steps.get(current); if (isKey(step, modifier, PRESS)) { Log.debug("Found possible extraneous modifier"); int keyDown = current; Action action = null; while (++current < steps.size()) { step = (Step) steps.get(current); if (step instanceof Action) { if ("actionActionMap".equals(((Action) step).getMethodName())) { action = (Action) step; continue; } } else if (isKey(step, modifier, RELEASE)) { if (action != null) { Log.debug("Removing extraneous shortcut modifier"); steps.remove(current); steps.remove(keyDown); current = keyDown - 1; } } break; } } ++current; } }
/** * For use by subclasses when an error is encountered during parsing. Should only be used by the * XML parsing ctors. */ protected void setScriptError(Throwable thr) { if (invalidScriptError == null) { invalidScriptError = thr; } else { Log.warn("More than one script error encountered: " + thr); Log.warn("Already have: " + invalidScriptError); } }
public Step(Resolver resolver, Map attributes) { this(resolver, ""); Log.debug("Instantiating " + getClass()); if (Log.expectDebugOutput) { Iterator iter = attributes.keySet().iterator(); while (iter.hasNext()) { String key = (String) iter.next(); Log.debug(key + "=" + attributes.get(key)); } } parseStepAttributes(attributes); }
/** Convert the attributes in the given XML Element into a Map of name/value pairs. */ protected static Map createAttributeMap(Element el) { Log.debug("Creating attribute map for " + el); Map attributes = new HashMap(); Iterator iter = el.getAttributes().iterator(); while (iter.hasNext()) { Attribute att = (Attribute) iter.next(); attributes.put(att.getName(), att.getValue()); } return attributes; }
/** Parse clicks to cancel the recording if we get a click that's not in the JList (or ESC). */ protected boolean parseClick(AWTEvent event) { if (isFinished()) { return false; } // FIXME add key-based activation/termination? boolean consumed = true; if (combo == null) { combo = getComboBox(event); listener = new ActionListener() { public void actionPerformed(ActionEvent ev) { index = combo.getSelectedIndex(); if (!combo.isPopupVisible()) { combo.removeActionListener(listener); setFinished(true); } } }; combo.addActionListener(listener); setStatus("Waiting for selection"); } else if (event.getID() == KeyEvent.KEY_RELEASED && (((KeyEvent) event).getKeyCode() == KeyEvent.VK_SPACE || ((KeyEvent) event).getKeyCode() == KeyEvent.VK_ENTER)) { index = combo.getSelectedIndex(); setFinished(true); } // Cancel via click somewhere else else if (event.getID() == MouseEvent.MOUSE_PRESSED && !AWT.isOnPopup((Component) event.getSource()) && combo != getComboBox(event)) { setFinished(true); consumed = false; } // Cancel via ESC key else if (event.getID() == KeyEvent.KEY_RELEASED && ((KeyEvent) event).getKeyCode() == KeyEvent.VK_ESCAPE) { setStatus("Selection canceled"); setFinished(true); } else { Log.debug("Event ignored"); } if (list == null && combo.isPopupVisible()) list = tester.findComboList(combo); if (isFinished()) { combo.removeActionListener(listener); listener = null; } return consumed; }
/** Compare two images. May be BufferedImages or File arguments. */ public int compare(Object obj1, Object obj2) { try { obj1 = convertToJPEGFile(obj1); } catch (IOException io) { obj1 = null; } try { obj2 = convertToJPEGFile(obj2); } catch (IOException io) { obj2 = null; } Log.debug("Comparing " + obj1 + " and " + obj2); return comparator.compare(obj1, obj2); }
/** Provide a one-line XML string representation. */ public static String toXMLString(XMLifiable obj) { // Comments are the only things that aren't actually elements... if (obj instanceof Comment) { return "<!-- " + ((Comment) obj).getDescription() + " -->"; } Element el = obj.toXML(); StringWriter writer = new StringWriter(); try { XMLOutputter outputter = new XMLOutputter(); outputter.output(el, writer); } catch (IOException io) { Log.warn(io); } return writer.toString(); }
/** Add an attribute to the given XML Element. Attributes are kept in alphabetical order. */ protected Element addAttributes(Element el) { // Use a TreeMap to keep the attributes sorted on output Map atts = new TreeMap(getAttributes()); Iterator iter = atts.keySet().iterator(); while (iter.hasNext()) { String key = (String) iter.next(); String value = (String) atts.get(key); if (value == null) { Log.warn("Attribute '" + key + "' value was null in step " + getXMLTag()); value = ""; } el.setAttribute(key, value); } return el; }
private static File convertToJPEGFile(Object obj) throws IOException { if (obj != null) { if (obj instanceof String) { obj = new File((String) obj); } if (obj instanceof BufferedImage) { File file = File.createTempFile("ImageComparator", ".jpg"); Log.debug("Creating " + file); writeJPEG(file, (BufferedImage) obj); file.deleteOnExit(); return file; } if (obj instanceof File) { return (File) obj; } } return null; }
/** Return the semantic recorder for the given component class. */ protected SemanticRecorder getSemanticRecorder(Class cls) { // System.out.println("getting recorder for: " + cls); if (!(Component.class.isAssignableFrom(cls))) { throw new IllegalArgumentException("Class (" + cls + ") must derive from " + "Component"); } SemanticRecorder sr = (SemanticRecorder) semanticRecorders.get(cls); if (sr == null) { Class ccls = Robot.getCanonicalClass(cls); if (ccls != cls) { sr = getSemanticRecorder(ccls); // Additionally cache the mapping from the non-canonical class semanticRecorders.put(cls, sr); return sr; } String cname = Robot.simpleClassName(cls); try { // cname = "abbot.editor.recorder." + cname + "Recorder"; cname = getRecoderName(cname); Class recorderClass = Class.forName(cname); Constructor ctor = recorderClass.getConstructor( new Class[] { Resolver.class, }); sr = (SemanticRecorder) ctor.newInstance(new Object[] {getResolver()}); sr.addActionListener(getListener()); } catch (InvocationTargetException e) { Log.warn(e); } catch (NoSuchMethodException e) { sr = getSemanticRecorder(cls.getSuperclass()); } catch (InstantiationException e) { sr = getSemanticRecorder(cls.getSuperclass()); } catch (IllegalAccessException iae) { sr = getSemanticRecorder(cls.getSuperclass()); } catch (ClassNotFoundException cnf) { sr = getSemanticRecorder(cls.getSuperclass()); } // Cache the results for future reference semanticRecorders.put(cls, sr); } return sr; }
/** * Copies the gold folder to the runtime workspace CONTRACT: folder exists in the devspace, * goldFolder has been set In this implementation, the gold folder is copied from * bin/test/GoldFolder */ public static void copyGoldFolder() { /* goldFolder (location where goldfolder should go in runspace) must not be null */ Assert.assertTrue(goldFolder != null); Bundle model2testsBundle = EclipsePlugin.getDefault().getBundle(); /* this is the source for our goldfolder in the devspace that we're copying to the runspace */ URL gfURL = model2testsBundle.getEntry("/"); /* devspace GoldFolder must exist */ // Assert.assertTrue(goldFolder.exists()); // Assert.assertTrue(gf.exists()); IWorkspace workspace = ResourcesPlugin.getWorkspace(); IWorkspaceRoot workspaceRoot = workspace.getRoot(); IPath rootPath = workspaceRoot.getLocation(); try { gfURL = Platform.asLocalURL(gfURL); } catch (IOException e) { e.printStackTrace(); } System.out.println("URL path: " + gfURL.getPath()); System.out.println("URL file: " + gfURL.getFile()); System.out.println("URL ref: " + gfURL.getRef()); File srcDir = new File(gfURL.getPath(), "GoldFolder"); Path p = new Path(gfURL.getPath()); IResource igf = ((Workspace) workspace).newResource(p, IResource.FOLDER); IPath gfpath = goldFolder.getFullPath(); File destDir = new File(gfpath.toOSString()); /* Make sure both of these directories exist */ System.out.println("Source directory exists: " + srcDir.exists()); /* destination directory shouldn't exist because we're going to create it */ // System.out.println ("Dest directory exists: " + destDir.exists()); /* Since assert isn't working for the moment... */ if (!srcDir.exists()) { System.out.println("GoldFolder not found"); Log.log("GoldFolder not found"); Assert.fail("GoldFolder not found"); } // Assert.assertTrue("Source goldfolder does not exist", srcDir.exists()); // Assert.assertTrue("Destination goldfolder does not exist", destDir.exists()); copyFolder(srcDir, destDir); }
/** Capture the given event as a raw event. */ private void captureRawEvent(AWTEvent event) { // FIXME maybe measure time delay between events and insert delay // events? int id = event.getID(); boolean capture = false; switch (id) { case MouseEvent.MOUSE_PRESSED: case MouseEvent.MOUSE_RELEASED: capture = true; break; case KeyEvent.KEY_PRESSED: case KeyEvent.KEY_RELEASED: KeyEvent e = (KeyEvent) event; capture = e.getKeyCode() != KeyEvent.VK_UNDEFINED; if (!capture) { Log.warn( "VM bug: no valid keycode on key " + (id == KeyEvent.KEY_PRESSED ? "press" : "release")); } break; case MouseEvent.MOUSE_ENTERED: case MouseEvent.MOUSE_EXITED: // case MouseEvent.MOUSE_MOVED: case MouseEvent.MOUSE_DRAGGED: capture = captureMotion; break; default: break; } if (capture) { Event step = new Event(getResolver(), null, event); capturedEvent = event; insertStep(step); setStatus("Added event " + step); } }
/** Only exposed so that Script may invoke it on load from disk. */ protected final void parseStepAttributes(Map attributes) { Log.debug("Parsing attributes for " + getClass()); description = (String) attributes.get(TAG_DESC); }
/** * Main run method. Should <b>never</b> be run on the event dispatch thread, although no check is * explicitly done here. */ public final void run() throws Throwable { if (invalidScriptError != null) throw invalidScriptError; Log.debug("Running " + toString()); runStep(); }
public void terminate() throws RecordingFailedException { Log.log("EventRecorder terminated"); if (semanticRecorder != null) { saveSemanticEvent(); } }