Example #1
0
 /** Eliminate redundant modifier keys surrounding keystrokes or keystrings. */
 private void removeExtraModifiers() {
   setStatus("Removing extra modifiers");
   for (int i = 0; i < steps.size(); i++) {
     Step step = (Step) steps.get(i);
     if (isKey(step, ANY_KEY, PRESS)) {
       Event se = (Event) step;
       String cs = se.getAttribute(XMLConstants.TAG_KEYCODE);
       int code = AWT.getKeyCode(cs);
       boolean remove = false;
       boolean foundKeyStroke = false;
       if (AWT.isModifier(code)) {
         for (int j = i + 1; j < steps.size(); j++) {
           Step next = (Step) steps.get(j);
           if (isKey(next, cs, RELEASE)) {
             if (foundKeyStroke) {
               steps.remove(j);
               remove = true;
             }
             break;
           } else if (isKeyStroke(next, ANY_KEY) || isKeyString(next)) {
             foundKeyStroke = true;
             remove = true;
           } else if (!isKey(next, ANY_KEY, EITHER)) {
             break;
           }
         }
       }
       if (remove) {
         steps.remove(i--);
       }
     }
   }
 }
Example #2
0
 /** 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;
   }
 }
Example #3
0
/** Provides shared UI- and action-related constants. */
public interface AWTConstants {

  int MULTI_CLICK_INTERVAL = 250; // a guess
  /** Number of pixels traversed before a drag starts. */
  // OSX 10(1.3.1), 5(1.4.1)
  // Linux/X11: delay+16
  // NOTE: could maybe install a drag gesture recognizer, but that's kinda
  // complex for what you get out of it.
  int DRAG_THRESHOLD = Platform.isWindows() || Platform.isMacintosh() ? 10 : 16;

  int BUTTON_MASK = (InputEvent.BUTTON1_MASK | InputEvent.BUTTON2_MASK | InputEvent.BUTTON3_MASK);
  int POPUP_MASK = AWT.getPopupMask();
  String POPUP_MODIFIER = AWT.getMouseModifiers(POPUP_MASK);
  boolean POPUP_ON_PRESS = AWT.getPopupOnPress();
  int TERTIARY_MASK = AWT.getTertiaryMask();
  String TERTIARY_MODIFIER = AWT.getMouseModifiers(TERTIARY_MASK);
  int MENU_SHORTCUT_MASK = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
  String MENU_SHORTCUT_MODIFIER = AWT.getKeyModifiers(MENU_SHORTCUT_MASK);
  String MENU_SHORTCUT_STRING =
      MENU_SHORTCUT_MASK == InputEvent.ALT_MASK
          ? "alt "
          : MENU_SHORTCUT_MASK == InputEvent.META_MASK
              ? "meta "
              : MENU_SHORTCUT_MASK == InputEvent.SHIFT_MASK ? "shift " : "control ";
  String MENU_SHORTCUT_KEYCODE = AWT.getKeyCode(AWT.maskToKeyCode(MENU_SHORTCUT_MASK));
}
  /** 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;
  }
Example #5
0
 /** Return the semantic recorder for the given component. */
 private SemanticRecorder getSemanticRecorder(Component comp) {
   // FIXME extract into AWT.getLAFParent?
   // Account for LAF implementations that use a JButton on top
   // of the combo box
   if ((comp instanceof JButton) && (comp.getParent() instanceof JComboBox)) {
     comp = comp.getParent();
   }
   // Account for LAF components of JInternalFrame
   else if (AWT.isInternalFrameDecoration(comp)) {
     while (!(comp instanceof JInternalFrame)) comp = comp.getParent();
   }
   return getSemanticRecorder(comp.getClass());
 }
 /** Assert the currently active window has the specified name */
 protected static void assertWindowname(String name)
     throws InterruptedException, ComponentNotFoundException {
   logger.fine("Expecting window name: " + name);
   Window w = null;
   for (int i = 0; i < 100; i++) {
     guiSleep();
     w = AWT.getActiveWindow();
     if (w == null) continue;
     if (name.equals(w.getName())) return;
     Thread.sleep(100);
   }
   throw new ComponentNotFoundException(
       "Window name not found: "
           + name
           + (w != null ? (" (currently focused: " + w.getName() + ")") : ""));
 }
 /** Gives focus to a {@linkplain Component} by its name */
 protected static boolean focusByName(final String name)
     throws ComponentNotFoundException, MultipleComponentsFoundException {
   Component c = findByName(name);
   if (c.hasFocus()) return true;
   // try ordinary method
   if (c.requestFocusInWindow()) {
     while (!c.hasFocus()) guiSleep();
     return true;
   }
   // press tab until we have the correct focus
   for (int i = 0; i < 25 /* TODO proper number */; i++) {
     tester.keyStroke('\t');
     guiSleep();
     if (name.equals(AWT.getActiveWindow().getFocusOwner().getName())) return true;
   }
   // failed ...
   logger.warning("Could not give focus to component: " + name);
   return true;
 }
 /** Make screenshot taking part of unit tests */
 @Test
 public static void testScreenshots() throws Exception {
   File shotdir = FileUtils.createTempDir("jgridstart-screenshots-");
   try {
     doScreenshots(shotdir);
   } catch (Throwable e) {
     // on error, output final screenshot as base64 on debug log
     File errorshot = new File(shotdir, "error.png");
     saveScreenshot(errorshot);
     Thread.sleep(500);
     FileInputStream in = new FileInputStream(errorshot);
     byte[] data = new byte[(int) errorshot.length()];
     in.read(data, 0, data.length);
     // need to log in chunks because logger doesn't seem to be able to support >4096 chars
     String basedata = new String(Base64.encode(data));
     logger.finest("Interactive UI testing failed, last screenshot (base64 encoded):");
     logger.finest("=== BEGIN PNG ===");
     int pos = 0;
     while (pos < basedata.length()) {
       int len = 1024;
       if (pos + len < basedata.length()) logger.finest(basedata.substring(pos, pos + len));
       else logger.finest(basedata.substring(pos));
       pos += len;
     }
     logger.finest("=== END PNG ===");
     // destroy window
     Window mainwnd = AWT.getActiveWindow();
     if (mainwnd != null && mainwnd.isVisible()) mainwnd.dispose();
     // pass on error
     if (e instanceof Exception) throw (Exception) e;
     else if (e instanceof Error) throw (Error) e;
     else throw new Exception("Unknown throwable: ", e);
   } finally {
     // remove screenshot directory again
     FileUtils.recursiveDelete(shotdir);
   }
 }
Example #9
0
  /** Eliminate redundant key press/release events surrounding a keytyped event. */
  private void coalesceKeyEvents() {
    setStatus("Coalescing key events");
    for (int i = 0; i < steps.size(); i++) {
      Step step = (Step) steps.get(i);
      if (isKey(step, ANY_KEY, PRESS)) {
        // In the case of modifiers, remove only if the presence of
        // the key down/up is redundant.
        Event se = (Event) step;
        String cs = se.getAttribute(XMLConstants.TAG_KEYCODE);
        int code = AWT.getKeyCode(cs);
        // OSX option modifier should be ignored, since it is used to
        // generate input method events.
        boolean isOSXOption = Platform.isOSX() && code == KeyEvent.VK_ALT;
        if (AWT.isModifier(code) && !isOSXOption) continue;

        // In the case of non-modifier keys, walk the steps until we
        // find the key release, then optionally replace the key press
        // with a keystroke, or remove it if the keystroke was already
        // recorded.  This sorts out jumbled key press/release events.
        boolean foundKeyStroke = false;
        boolean foundRelease = false;
        for (int j = i + 1; j < steps.size(); j++) {
          Step next = (Step) steps.get(j);
          // If we find the release, remove it and this
          if (isKey(next, cs, RELEASE)) {
            foundRelease = true;
            String target = ((Event) next).getComponentID();
            steps.remove(j);
            steps.remove(i);
            // Add a keystroke only if we didn't find any key
            // input between press and release (except on OSX,
            // where the option key generates input method events
            // which aren't recorded).
            if (!foundKeyStroke && !isOSXOption) {
              String mods = se.getAttribute(XMLConstants.TAG_MODIFIERS);
              String[] args =
                  (mods == null || "0".equals(mods)
                      ? new String[] {target, cs}
                      : new String[] {target, cs, mods});
              Step typed = new Action(getResolver(), null, "actionKeyStroke", args);
              steps.add(i, typed);
              setStatus("Insert artifical " + typed);
            } else {
              setStatus("Removed redundant key events (" + cs + ")");
              --i;
            }
            break;
          } else if (isKeyStroke(next, ANY_KEY) || isKeyString(next)) {
            foundKeyStroke = true;
            // If it's a numpad keycode, use the numpad
            // keycode instead of the resulting numeric character
            // keystroke.
            if (cs.startsWith("VK_NUMPAD")) {
              foundKeyStroke = false;
              steps.remove(j--);
            }
          }
        }
        // We don't like standalone key presses
        if (!foundRelease) {
          setStatus("Removed extraneous key press (" + cs + ")");
          steps.remove(i--);
        }
      }
    }
  }
  public static void doScreenshots(File shotdir) throws Exception {
    shotdir.mkdirs();
    String prefix = "jgridstart-screenshot-";
    // setup temporary environment
    logger.info("Setting up jGridstart interactive screenshot and testing environment");
    File tmphome = FileUtils.createTempDir("jgridstart-home");
    Window mainwnd = null;
    try {
      System.setProperty("jgridstart.ca.provider", "LocalCA");
      System.setProperty("jgridstart.ca.local.hold", "true");
      System.setProperty("user.home", tmphome.getCanonicalPath());
      // create standard gui
      nl.nikhef.jgridstart.gui.Main.main(new String[] {});
      LogHelper.setupLogging(true);
      // move mouse here since closing window may give up focus later
      Thread.sleep(2000);
      guiSleep();
      mainwnd = AWT.getActiveWindow();
      assertNotNull(mainwnd);
      tester.mouseMove(mainwnd.getComponents()[0]);
      assertWindowname("jgridstart-main-window");

      /*
       * Request new
       */
      logger.info("Interactive testing scenario: Request New");
      // start screen
      saveScreenshot(new File(shotdir, prefix + "newrequest01.png"));
      // new request wizard
      guiSleep();
      tester.key(new Integer('N'), InputEvent.CTRL_MASK);
      guiSleep();
      saveScreenshot(new File(shotdir, prefix + "newrequest02.png"));
      // enter details
      guiSleep();
      assertWindowname("jgridstart-requestwizard-0");
      focusByName("givenname");
      keyString("John\t");
      keyString("Doe\t");
      keyString("[email protected]\t");
      keyString("N\t");
      keyString(password + "\t");
      keyString(password + "\t");
      // wait for submission
      tester.key(new Integer('N'), InputEvent.ALT_MASK);
      guiSleep();
      saveScreenshot(new File(shotdir, prefix + "newrequest03.png"));
      assertWindowname("jgridstart-requestwizard-1");
      waitEnabled(JButton.class, "Next");
      // verification form
      System.setProperty("wizard.show.help1", "true"); // simulate help btn1 pressed
      tester.key(new Integer('N'), InputEvent.ALT_MASK);
      guiSleep();
      guiSleep();
      saveScreenshot(new File(shotdir, prefix + "newrequest04.png"));
      assertWindowname("jgridstart-requestwizard-2");
      // form display
      JButton btn =
          (JButton)
              new BasicFinder()
                  .find(
                      new Matcher() {
                        public boolean matches(Component c) {
                          return c instanceof JButton
                              && ((JButton) c).getText().startsWith("display form");
                        }
                      });
      btn.doClick();
      waitEnabled(JButton.class, "Close");
      guiSleep();
      saveScreenshot(new File(shotdir, prefix + "newrequest05.png"));
      assertWindowname("jgridstart-verification-form");
      tester.key(new Integer('C'), InputEvent.ALT_MASK);
      // close wizard
      guiSleep();
      assertWindowname("jgridstart-requestwizard-2");
      tester.key(new Integer('C'), InputEvent.ALT_MASK);
      guiSleep();
      saveScreenshot(new File(shotdir, prefix + "newrequest06.png"));
      assertWindowname("jgridstart-main-window");
      // enable certificate in LocalCA and refresh pane
      System.setProperty("jgridstart.ca.local.hold", "false");
      tester.key(KeyEvent.VK_F5);
      Thread.sleep(1000);
      guiSleep();
      saveScreenshot(new File(shotdir, prefix + "newrequest07.png"));
      assertWindowname("jgridstart-main-window");
      // show request wizard again
      tester.key(new Integer('A'), InputEvent.ALT_MASK);
      tester.key('R');
      guiSleep();
      guiSleep();
      saveScreenshot(new File(shotdir, prefix + "newrequest08.png"));
      assertWindowname("jgridstart-requestwizard-2");
      // install step
      tester.key(new Integer('N'), InputEvent.ALT_MASK);
      Thread.sleep(1000);
      guiSleep();
      saveScreenshot(new File(shotdir, prefix + "newrequest09.png"));
      assertWindowname("jgridstart-requestwizard-3");
      // show final screen
      tester.key(new Integer('N'), InputEvent.ALT_MASK);
      guiSleep();
      saveScreenshot(new File(shotdir, prefix + "newrequest10.png"));
      assertWindowname("jgridstart-requestwizard-4");
      // exit wizard
      tester.key(new Integer('C'), InputEvent.ALT_MASK);
      // save final screenshot
      guiSleep();
      saveScreenshot(new File(shotdir, prefix + "newrequest11.png"));
      assertWindowname("jgridstart-main-window");
      guiSleep();

      /*
       * Renewal
       */
      logger.info("Interactive testing scenario: Renewal");
      System.setProperty("jgridstart.ca.local.hold", "true");
      // forget password so we certainly get the password dialog
      PasswordCache.getInstance().clear();
      // start screen
      guiSleep();
      saveScreenshot(new File(shotdir, prefix + "renew01.png"));
      assertWindowname("jgridstart-main-window");
      // personal details
      tester.key(new Integer('A'), InputEvent.ALT_MASK);
      tester.key('W');
      Thread.sleep(500);
      guiSleep();
      saveScreenshot(new File(shotdir, prefix + "renew02.png"));
      assertWindowname("jgridstart-requestwizard-0");
      focusByName("email");
      keyString("\t");
      keyString(password + "\t");
      keyString(password + "\t");
      keyString(password + "\t");
      // wait for submission screen
      tester.key(new Integer('N'), InputEvent.ALT_MASK);
      // renew03.png used to be a password dialog, which was removed
      // submit page
      guiSleep();
      saveScreenshot(new File(shotdir, prefix + "renew04.png"));
      assertWindowname("jgridstart-requestwizard-1");
      waitEnabled(JButton.class, "Next");
      // wait for approval page
      tester.key(new Integer('N'), InputEvent.ALT_MASK);
      guiSleep();
      saveScreenshot(new File(shotdir, prefix + "renew05.png"));
      assertWindowname("jgridstart-requestwizard-2");
      // close wizard
      guiSleep();
      tester.key(new Integer('C'), InputEvent.ALT_MASK);
      guiSleep();
      saveScreenshot(new File(shotdir, prefix + "renew06.png"));
      assertWindowname("jgridstart-main-window");
      // enable certificate in LocalCA and refresh pane
      System.setProperty("jgridstart.ca.local.hold", "false");
      tester.key(KeyEvent.VK_F5);
      Thread.sleep(1000);
      guiSleep();
      saveScreenshot(new File(shotdir, prefix + "renew07.png"));
      assertWindowname("jgridstart-main-window");
      // show request wizard again
      tester.key(new Integer('A'), InputEvent.ALT_MASK);
      tester.key('R');
      waitEnabled(JButton.class, "Next");
      Thread.sleep(500);
      guiSleep();
      saveScreenshot(new File(shotdir, prefix + "renew08.png"));
      assertWindowname("jgridstart-requestwizard-2");
      // install step
      tester.key(new Integer('N'), InputEvent.ALT_MASK);
      Thread.sleep(1000);
      guiSleep();
      saveScreenshot(new File(shotdir, prefix + "renew09.png"));
      assertWindowname("jgridstart-requestwizard-3");
      // exit wizard
      tester.key(new Integer('C'), InputEvent.ALT_MASK);
      // save final screenshot
      guiSleep();
      saveScreenshot(new File(shotdir, prefix + "renew10.png"));
      assertWindowname("jgridstart-main-window");
      guiSleep();

      /*
       * Import/export
       */
      logger.info("Interactive testing scenario: Import/Export");
      // forget password so we certainly get the password dialog
      PasswordCache.getInstance().clear();
      // starting screenshot (multiple certificates)
      guiSleep();
      saveScreenshot(new File(shotdir, prefix + "importexport01.png"));
      assertWindowname("jgridstart-main-window");
      // export dialog
      tester.key(new Integer('E'), InputEvent.CTRL_MASK);
      waitEnabled(JButton.class, "Export");
      guiSleep();
      saveScreenshot(new File(shotdir, prefix + "importexport02.png"));
      assertWindowname("jgridstart-export-file-dialog");
      // enter name and do export
      tester.keyString("jgridstart_test_certificate.p12\n");
      Thread.sleep(2000);
      saveScreenshot(new File(shotdir, prefix + "importexport03.png"));
      assertWindowname("jgridstart-password-entry-decrypt");
      tester.keyString(password + "\n");
      guiSleep();
      assertWindowname("jgridstart-main-window");

      // forget password so we certainly get the password dialog
      PasswordCache.getInstance().clear();

      // import dialog
      tester.key(new Integer('I'), InputEvent.CTRL_MASK);
      waitEnabled(JButton.class, "Import");
      guiSleep();
      saveScreenshot(new File(shotdir, prefix + "importexport04.png"));
      assertWindowname("jgridstart-import-file-dialog");
      guiSleep();
      // enter name and do import
      tester.keyString("jgridstart_test_certificate.p12\n");
      Thread.sleep(1000);
      saveScreenshot(new File(shotdir, prefix + "importexport05.png"));
      assertWindowname("jgridstart-password-entry-decrypt");
      keyString(password + "\n");
      guiSleep();

      /*
       * Certificate details
       */
      logger.info("Interactive testing scenario: Certificate details");
      // certificate details view
      mainwnd.setSize(750, 480);
      System.setProperty("view.showdetails", "true");
      URLLauncherCertificate.performAction("viewlist(false)", mainwnd);
      tester.key(KeyEvent.VK_F5);
      Thread.sleep(500);
      guiSleep();
      saveScreenshot(new File(shotdir, prefix + "viewdetails01.png"));
      assertWindowname("jgridstart-main-window");

      /*
       * Exit!
       */
      logger.info("Interactive testing finished");
      /* Quit does a {@link System.exit}, which JUnit doesn't like. The
       * error it gives is something like:
       *   [junit] Test <testclass> FAILED (crashed)
       * So we leave it to the calling function to dispose of the window.
       */
      // tester.key(new Integer('Q'), InputEvent.CTRL_MASK);

    } finally {
      guiSleep();
      Thread.sleep(500); // for screenshot to complete ...
      FileUtils.recursiveDelete(tmphome);
    }
    // exit!
    return;
  }