Clover coverage report - JFCUnit Test Coverage
Coverage timestamp: Mon Dec 20 2004 23:38:10 MST
file stats: LOC: 666   Methods: 32
NCLOC: 295   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
Finder.java 70% 67.7% 68.8% 68.6%
coverage coverage
 1   
 package junit.extensions.jfcunit.finder;
 2   
 
 3   
 import junit.extensions.jfcunit.RobotTestHelper;
 4   
 import junit.extensions.jfcunit.TestHelper;
 5   
 import junit.extensions.jfcunit.eventdata.MouseEventData;
 6   
 
 7   
 import org.apache.regexp.RE;
 8   
 import org.apache.regexp.RESyntaxException;
 9   
 
 10   
 import java.awt.AWTException;
 11   
 import java.awt.Component;
 12   
 import java.awt.Container;
 13   
 
 14   
 import java.util.ArrayList;
 15   
 import java.util.List;
 16   
 
 17   
 import javax.swing.JOptionPane;
 18   
 import junit.extensions.jfcunit.WindowMonitor;
 19   
 
 20   
 
 21   
 /**
 22   
  * Abstract class for defining call back classes to test whether a {@link java.awt.Component}
 23   
  * that is being searched for has been found.
 24   
  *
 25   
  * @author <a href="mailto:vraravam@thoughtworks.com">Vijay Aravamudhan : ThoughtWorks Inc.</a>
 26   
  */
 27   
 public abstract class Finder {
 28   
     /**
 29   
      * Robot for debug mode of finders.
 30   
      */
 31   
     private static RobotTestHelper s_robot = null;
 32   
 
 33   
     /**
 34   
      * Robot Exception received.
 35   
      */
 36   
     private static boolean s_robotException = false;
 37   
 
 38   
     /**
 39   
      * String so for the OP codes.
 40   
      */
 41   
     private static final String[] OP_CODE_STRINGS = new String[] {
 42   
             "match", "startswith", "endswith", "equals", "contains"
 43   
         };
 44   
 
 45   
     /**
 46   
      * Match the item using a Regular expression.
 47   
      */
 48   
     public static final int OP_MATCH = 0;
 49   
 
 50   
     /**
 51   
      * Check that the value starts with the given
 52   
      * value.
 53   
      */
 54   
     public static final int OP_STARTSWITH = 1;
 55   
 
 56   
     /**
 57   
      * Check that the value ends with the given
 58   
      * value.
 59   
      */
 60   
     public static final int OP_ENDSWITH = 2;
 61   
 
 62   
     /**
 63   
      * Check that the values are equal.
 64   
      */
 65   
     public static final int OP_EQUALS = 3;
 66   
 
 67   
     /**
 68   
      * Check that the value is contained.
 69   
      */
 70   
     public static final int OP_CONTAINS = 4;
 71   
 
 72   
     /**
 73   
      * This member is used to evaluate regular expressions.
 74   
      */
 75   
     private RE m_patternMatcher;
 76   
 
 77   
     /**
 78   
      * Ignore case.
 79   
      */
 80   
     private boolean m_caseIndependent = false;
 81   
 
 82   
     /**
 83   
      * The debug state of the finder.
 84   
      */
 85   
     private boolean m_debug = false;
 86   
 
 87   
     /**
 88   
      * visibility property defaults to false.
 89   
      */
 90   
     private boolean m_ignoreVisiblity = false;
 91   
 
 92   
     /**
 93   
      * Show Debug.
 94   
      */
 95   
     private boolean m_showDebug = false;
 96   
 
 97   
     /**
 98   
      * Operation to be performed when selecting items.
 99   
      */
 100   
     private int m_operation = OP_MATCH;
 101   
 
 102   
     /**
 103   
      * Default wait time.
 104   
      */
 105   
     private static int s_defaultWait = 30;
 106   
     /**
 107   
      * The max wait time for a window to appear in milliseconds.
 108   
      */
 109   
     private int m_wait = s_defaultWait;
 110   
 
 111   
     /**
 112   
      * Convert the String to a Operation code.
 113   
      * @param code String version of the Operation.
 114   
      * @return int version of the operation.
 115   
      */
 116  0
     public static final int getOperation(final String code) {
 117  0
         for (int i = 0; i < OP_CODE_STRINGS.length; i++) {
 118  0
             if (OP_CODE_STRINGS[i].equalsIgnoreCase(code)) {
 119  0
                 return i;
 120   
             }
 121   
         }
 122   
 
 123  0
         throw new java.lang.IllegalArgumentException("Operation not found:"
 124   
             + code);
 125   
     }
 126   
 
 127   
     /**
 128   
      * Get the string version of the operation.
 129   
      * @param code int Finder.OP_code
 130   
      * @return String version of the operation.
 131   
      */
 132  0
     public static final String getOperationString(final int code) {
 133  0
         if ((code < 0) || (code >= OP_CODE_STRINGS.length)) {
 134  0
             throw new IllegalArgumentException("Invalid Operation code:" + code);
 135   
         }
 136   
 
 137  0
         return OP_CODE_STRINGS[code];
 138   
     }
 139   
 
 140   
     /**
 141   
      * Get the debug state of the finder.
 142   
      * @return true if debugging should be enabled.
 143   
      */
 144  1274
     public final boolean getDebug() {
 145  1274
         return m_debug;
 146   
     }
 147   
 
 148   
     /**
 149   
      * Set the operation to be performed by this
 150   
      * finder.
 151   
      * @param operation Operation to be performed.
 152   
      * @see OP_EQUALS     Exact match
 153   
      * @see OP_MATCH      Matches a Regular Expression
 154   
      * @see OP_STARTSWITH Starts with
 155   
      * @see OP_ENDSWITH   Ends with
 156   
      * @see OP_CONTAINS   Contains
 157   
      */
 158  159
     public final void setOperation(final int operation) {
 159  159
         this.m_operation = operation;
 160   
     }
 161   
 
 162   
     /**
 163   
      * Get the operation.
 164   
      * @return the operation to be performed by the finder.
 165   
      */
 166  0
     public final int getOperation() {
 167  0
         return m_operation;
 168   
     }
 169   
 
 170   
     /**
 171   
      * Set the debug state of the finder.
 172   
      * @param value true if debugging should be enabled.
 173   
      */
 174  151
     public final void setShowDebug(final boolean value) {
 175  151
         if (value && (s_robot == null) && !s_robotException) {
 176  0
             try {
 177  0
                 s_robot = new RobotTestHelper();
 178   
             } catch (AWTException ex) {
 179  0
                 System.err.println("Could not create robot:");
 180  0
                 ex.printStackTrace();
 181  0
                 s_robotException = true;
 182   
             }
 183   
         }
 184   
 
 185  151
         m_showDebug = value;
 186   
     }
 187   
 
 188   
     /**
 189   
      * Get the debug state of the finder.
 190   
      * @return true if debugging should be enabled.
 191   
      */
 192  979
     public final boolean getShowDebug() {
 193  979
         return m_showDebug;
 194   
     }
 195   
 
 196   
     /**
 197   
      * Set the max wait time for a window to appear.
 198   
      * @param wait time in seconds.
 199   
      */
 200  300
     public final void setWait(final int wait) {
 201  300
         this.m_wait = wait;
 202   
     }
 203   
 
 204   
     /**
 205   
      * Get the wait time.
 206   
      * @return Wait time in seconds. Default wait
 207   
      * time is 10 seconds.
 208   
      */
 209  628
     public final int getWait() {
 210  628
         return m_wait;
 211   
     }
 212   
 
 213   
     /**
 214   
      * Set the default wait time for the finders.
 215   
      * This effects all new Finders which are created.
 216   
      *
 217   
      * @param wait int duration to wait by default.
 218   
      */
 219  0
     public static final void setDefaultWait(final int wait) {
 220  0
         s_defaultWait = wait;
 221   
     }
 222   
 
 223   
     /**
 224   
      * Get the default wait duration in seconds.
 225   
      * The default effects all new finders created.
 226   
      *
 227   
      * @return int default duration to wait.
 228   
      */
 229  0
     public static final int getDefaultWait() {
 230  0
         return s_defaultWait;
 231   
     }
 232   
 
 233   
     /**
 234   
      * Evaluate the current operation.
 235   
      * @param leftside String to be compared.
 236   
      * @param rightside String or Regular expression.
 237   
      * @return result of operation
 238   
      */
 239  754
     public final boolean evaluate(final String leftside, final String rightside) {
 240  754
         if (leftside == null) {
 241   
             // If left and right are null then return true.
 242   
             // otherwise return false.
 243  19
             return rightside == null;
 244   
         }
 245  735
         if (rightside == null) {
 246  3
             return false;
 247   
         }
 248   
 
 249  732
         if (m_operation == OP_CONTAINS) {
 250  0
             return (leftside.indexOf(rightside) >= 0);
 251  732
         } else if (m_operation == OP_ENDSWITH) {
 252  0
             return (leftside.endsWith(rightside));
 253  732
         } else if (m_operation == OP_STARTSWITH) {
 254  0
             return (leftside.startsWith(rightside));
 255  732
         } else if (m_operation == OP_EQUALS) {
 256  4
             return (leftside.equals(rightside));
 257  728
         } else if (m_operation == OP_MATCH) {
 258  728
             return matchPattern(leftside, rightside);
 259   
         }
 260   
 
 261  0
         throw new java.lang.IllegalStateException(
 262   
             "Invalid operation for finder:" + m_operation);
 263   
     }
 264   
 
 265   
     /**
 266   
      * Set the finder into a case independent mode.
 267   
      * @param ignoreCase true if case should be ignored.
 268   
      */
 269  0
     public void setCaseIndependent(final boolean ignoreCase) {
 270  0
         m_caseIndependent = ignoreCase;
 271   
     }
 272   
 
 273   
     /**
 274   
      * Get the state of ignore case.
 275   
      * @return boolean true if the case is ignored.
 276   
      */
 277  0
     public boolean isCaseIndependent() {
 278  0
         return m_caseIndependent;
 279   
     }
 280   
 
 281   
     /**
 282   
      * Set the debug state of the finder.
 283   
      * @param value true if debugging should be enabled.
 284   
      */
 285  5
     public final void setDebug(final boolean value) {
 286  5
         if (value && (s_robot == null) && !s_robotException) {
 287  1
             try {
 288  1
                 s_robot = new RobotTestHelper();
 289   
             } catch (AWTException ex) {
 290  0
                 System.err.println("Could not create robot:");
 291  0
                 ex.printStackTrace();
 292  0
                 s_robotException = true;
 293   
             }
 294   
         }
 295   
 
 296  5
         m_debug = value;
 297   
     }
 298   
 
 299   
     /**
 300   
      * Set the ignore visiblity property, to generate the
 301   
      * proper index when a dialog is closed.
 302   
      * @param value true if the visibility should be ignored.
 303   
      */
 304  0
     public final void setIgnoreVisibility(final boolean value) {
 305  0
         m_ignoreVisiblity = value;
 306   
     }
 307   
 
 308   
     /**
 309   
      * Method that returns true if the given component matches the search
 310   
      * criteria.
 311   
      *
 312   
      * @param comp   The {@link Component} to test
 313   
      * @return true if this {@link Component} is a match
 314   
      */
 315   
     public abstract boolean testComponent(final Component comp);
 316   
 
 317   
     /**
 318   
      * Find the Component matching this finder at the given
 319   
      * index within the container specified.
 320   
      * @param conts Container to be searched.
 321   
      * @param index Index of the item.
 322   
      * @return Component found.
 323   
      */
 324  522
     protected Component find(final Container[] conts, final int index) {
 325  522
         long abortAfter = System.currentTimeMillis() + (getWait() * 1000);
 326   
 
 327  522
         Container[] search = null;
 328  522
         do {
 329  522
             int idx = 0;
 330  522
             if (conts == null) {
 331  144
                 search = WindowMonitor.getWindows();
 332   
             } else {
 333  378
                 search = conts;
 334   
             }
 335   
 
 336  522
             if (this instanceof AbstractWindowFinder) {
 337  18
               Object[] all = ((AbstractWindowFinder) this).findAll().toArray();
 338  18
               if (all.length <= index) {
 339  1
                 continue;
 340   
               }
 341  17
               return (Component) all[index];
 342   
             }
 343   
 
 344  504
             for (int window = 0; window < search.length; window++) {
 345  510
                 List comps = findComponentList(
 346   
                         this,
 347   
                         search[window],
 348   
                         new ArrayList(),
 349   
                         index - idx);
 350  510
                 int  size = comps.size();
 351   
 
 352  510
                 if ((size > 0) && (size > (index - idx))) {
 353  503
                     Component comp = (Component) comps.get(index - idx);
 354   
 
 355  503
                     return comp;
 356   
                 }
 357   
 
 358  7
                 idx += comps.size();
 359   
             }
 360   
 
 361  1
             pause(abortAfter);
 362  2
         } while (System.currentTimeMillis() < abortAfter);
 363   
 
 364  2
         return null;
 365   
     }
 366   
 
 367   
     /**
 368   
      * Find the component at the index. Scope to search is all
 369   
      * frames/dialogs.
 370   
      *
 371   
      * @param index Index of the item to be found.
 372   
      * @return Item at the given index.
 373   
      */
 374  144
     public final Component find(final int index) {
 375  144
         return find((Container[]) null, index);
 376   
     }
 377   
 
 378   
     /**
 379   
      * Find the Component matching this finder at the given
 380   
      * index within the container specified.
 381   
      * @param cont Container to be searched.
 382   
      * @param index Index of the item.
 383   
      * @return Component found.
 384   
      */
 385  378
     public Component find(final Container cont, final int index) {
 386  378
         return find(new Container[] {cont}, index);
 387   
     }
 388   
 
 389   
     /**
 390   
      * Find the first component. Scope to search is all
 391   
      * frames/dialogs.
 392   
      *
 393   
      * @return First Item.
 394   
      */
 395  20
     public final Component find() {
 396  20
         return find(0);
 397   
     }
 398   
 
 399   
     /**
 400   
      * Find all of the resulting items in the entire
 401   
      * GUI application.
 402   
      *
 403   
      * @return List resulting items matching finder.
 404   
      */
 405  104
     public List findAll() {
 406  104
         return findAll((Container[]) null);
 407   
     }
 408   
 
 409   
     /**
 410   
      * Find all of the items matching this finder
 411   
      * in the container give.
 412   
      *
 413   
      * @param cont Container to be searched.
 414   
      * @return List resulting items matching finder.
 415   
      */
 416  4
     public List findAll(final Container cont) {
 417  4
         return findAll(new Container[] {cont});
 418   
     }
 419   
 
 420   
     /**
 421   
      * Find all of the components for this finder in
 422   
      * the set of containers given.
 423   
      *
 424   
      * @param cont Container[] Set of containers to search.
 425   
      * @return List resulting items matching finder.
 426   
      */
 427  2
     public List findAll(final Container[] cont) {
 428  2
         return findAll(cont, new ArrayList());
 429   
     }
 430   
 
 431   
     /**
 432   
      * This find all uses a recursive pattern for
 433   
      * internal processing.
 434   
      *
 435   
      * @param cont    Container[] Container list.
 436   
      * @param results List to which resulting items should
 437   
      *                be added.
 438   
      * @return List   resulting list.
 439   
      */
 440  0
     protected List findAll(final Container[] cont, final List results) {
 441  0
         Container[] containers = cont;
 442  0
         if (containers == null) {
 443  0
             containers = WindowMonitor.getWindows();
 444   
         }
 445  0
         for (int i = 0; i < containers.length; i++) {
 446  0
             findComponentList(this, containers[i], results, Integer.MAX_VALUE);
 447   
         }
 448  0
         return results;
 449   
     }
 450   
 
 451   
     /**
 452   
      * Method that calls itself repetitively to build up a list of all components
 453   
      * in the container instance that is passed in.
 454   
      *
 455   
      * @param finder  An instance of the finder which implements the testComponent()
 456   
      *                method.
 457   
      * @param cont    The Container inside which the component is to be found.
 458   
      * @param pList The return list.
 459   
      * @param index   The index of the component. The first component matching the
 460   
      *                criteria will have index 0, the second 1, etc.
 461   
      * @return The component that has been found (or null if none found).
 462   
      */
 463  30346
     public static final List findComponentList(final Finder finder,
 464   
         final Container cont, final List pList, final int index) {
 465  30346
         List outList = pList;
 466   
 
 467  30346
         if (outList == null) {
 468  0
             outList = new ArrayList();
 469   
         }
 470   
 
 471  30346
         if ((cont == null) || (finder == null)) {
 472  0
             return outList;
 473   
         }
 474   
 
 475  30346
         Component[] children = cont.getComponents();
 476   
 
 477  30346
         for (int i = 0; i < children.length; i++) {
 478  30824
             if (finder.testComponent(children[i])) {
 479  979
                 if (finder.getDebug()) {
 480  2
                     System.err.println("Finder Candidate(" + outList.size()
 481   
                         + ") " + children[i].getClass().getName());
 482   
                 }
 483   
 
 484  979
                 if (finder.getShowDebug() && (s_robot != null)) {
 485  0
                     try {
 486  0
                         s_robot.enterClickAndLeave(
 487   
                             new MouseEventData(
 488   
                                 TestHelper.getCurrentTestCase(),
 489   
                                 children[i],
 490   
                                 0,
 491   
                                 0,
 492   
                                 false));
 493  0
                         JOptionPane.showMessageDialog(null,
 494   
                             "<HTML><BODY>Finder Candidate Index:"
 495   
                             + outList.size() + "<p>"
 496   
                             + children[i].getClass().getName()
 497   
                             + "</BODY></HTML>");
 498   
                     } catch (Exception ae) {
 499  0
                         ae.printStackTrace();
 500   
 
 501   
                         // Ignore
 502   
                     }
 503   
                 }
 504   
 
 505  979
                 if (!outList.contains(children[i])) {
 506  979
                     outList.add(children[i]);
 507   
                 }
 508   
 
 509  979
                 if (outList.size() > index) {
 510  503
                     return outList;
 511   
                 }
 512  29845
             } else if (children[i] instanceof Container) {
 513  29823
                 findComponentList(finder, (Container) children[i], outList,
 514   
                     index);
 515   
 
 516  29823
                 if (outList.size() > index) {
 517  1226
                     return outList;
 518   
                 }
 519   
             }
 520   
         }
 521   
 
 522  28617
         return outList;
 523   
     }
 524   
 
 525   
     /**
 526   
      * This method is used to check that the window object is an instance
 527   
      * of the specified class and is also visible.
 528   
      *
 529   
      * @param comp   The {@link Component} to be checked
 530   
      * @param cls    The type of the component
 531   
      * @return true if the component is of the specified type and is visible.
 532   
      */
 533  26087
     protected final boolean isValidForProcessing(final Component comp,
 534   
         final Class cls) {
 535  26087
         boolean value = ((comp != null) && (cls != null)
 536   
             && cls.isInstance(comp) && (m_ignoreVisiblity || comp.isShowing()));
 537   
 
 538  26087
         return value;
 539   
     }
 540   
 
 541   
     /**
 542   
      * Recreate the pattern.
 543   
      *
 544   
      * @param patternString String pattern string.
 545   
      * @param caseIndependent boolean true if the case
 546   
      * should be ignored.
 547   
      */
 548  858
     protected void recreatePatternMatcher(final String patternString,
 549   
                                           final boolean caseIndependent) {
 550  858
         m_patternMatcher = null;
 551  858
         createPatternMatcher(patternString, caseIndependent);
 552   
     }
 553   
 
 554   
     /**
 555   
      * This method is used to filter components' attributes based on a pattern specified by the user.
 556   
      * For example, to search for all windows with title matching 'testWindow*'.
 557   
      * Note: If the patternString is null, we need to avoid the <code>PatternCompiler.compile()</code>
 558   
      * throwing a NullPointerException and in this case, return true if the componentAttribute
 559   
      * is also null.
 560   
      * The pattern syntax can be found at the Jakarta RegExp API Documentation in {@link org.apache.regexp.RE}.
 561   
      *
 562   
      * @param patternString      The pattern to match with
 563   
      * @param caseIndependent    Whether the match should be case independent (true) or not (false)
 564   
      */
 565  880
     protected void createPatternMatcher(final String patternString,
 566   
         final boolean caseIndependent) {
 567  880
         if (m_patternMatcher == null) {
 568  874
             try {
 569  874
                 if (patternString != null) {
 570  532
                     m_patternMatcher = new RE(patternString);
 571   
                 } else {
 572  342
                     m_patternMatcher = new RE("");
 573   
                 }
 574   
 
 575  874
                 if (caseIndependent) {
 576  16
                     m_patternMatcher.setMatchFlags(RE.MATCH_CASEINDEPENDENT);
 577   
                 }
 578   
             } catch (RESyntaxException e) {
 579  0
                 m_patternMatcher = null;
 580   
             }
 581   
         }
 582   
     }
 583   
 
 584   
     /**
 585   
      * This method is used to filter components' attributes based on a pattern specified by the user.
 586   
      * For example, to search for all windows with title matching 'testWindow*'.
 587   
      * Note: If the patternString is null, we need to avoid the <code>PatternCompiler.compile()</code>
 588   
      * throwing a NullPointerException and in this case, return true if the componentAttribute
 589   
      * is also null.
 590   
      * The pattern syntax can be found at the Jakarta RegExp API Documentation in {@link org.apache.regexp.RE}.
 591   
      *
 592   
      * @param componentAttribute    The attribute text of the component to match against
 593   
      * @param patternString         The pattern to match with
 594   
      * @param caseIndependent       Whether the match should be case independent (true) or not (false)
 595   
      * @return boolean whether the pattern is contained within the components' attribute text
 596   
      * @see #createPatternMatcher(String, boolean)
 597   
      * @see #matchPattern(String, String)}
 598   
      */
 599  0
     protected boolean matchPattern(final String componentAttribute,
 600   
         final String patternString, final boolean caseIndependent) {
 601  0
         createPatternMatcher(patternString, caseIndependent);
 602   
 
 603  0
         return matchPattern(componentAttribute, patternString);
 604   
     }
 605   
 
 606   
     /**
 607   
      * This method is used to filter components' attributes based on a pattern specified by the user.
 608   
      * For example, to search for all windows with title matching 'testWindow*'.
 609   
      * Note: If the patternString is null, we need to avoid the <code>PatternCompiler.compile()</code>
 610   
      * throwing a NullPointerException and in this case, return true if the componentAttribute
 611   
      * is also null.
 612   
      * The pattern syntax can be found at the Jakarta RegExp API Documentation in {@link org.apache.regexp.RE}.
 613   
      *
 614   
      * @param componentAttribute    The attribute text of the component to match against
 615   
      * @param patternString         The pattern to match with
 616   
      * @return boolean whether the pattern is contained within the components' attribute text
 617   
      */
 618  728
     protected boolean matchPattern(final String componentAttribute,
 619   
         final String patternString) {
 620  728
         return matchPattern(componentAttribute, patternString, m_patternMatcher);
 621   
     }
 622   
 
 623   
     /**
 624   
      * This method is used to filter components' attributes based on a pattern specified by the user.
 625   
      * For example, to search for all windows with title matching 'testWindow*'.
 626   
      * Note: If the patternString is null, we need to avoid the <code>PatternCompiler.compile()</code>
 627   
      * throwing a NullPointerException and in this case, return true if the componentAttribute
 628   
      * is also null.
 629   
      * The pattern syntax can be found at the Jakarta RegExp API Documentation in {@link org.apache.regexp.RE}.
 630   
      *
 631   
      * @param componentAttribute    The attribute text of the component to match against
 632   
      * @param patternString         The pattern to match with
 633   
      * @param re                    The RE pattern matcher to be used
 634   
      * @return boolean whether the pattern is contained within the components' attribute text
 635   
      */
 636  728
     protected final boolean matchPattern(final String componentAttribute,
 637   
         final String patternString, final RE re) {
 638   
         // if the patternString is null, we need to avoid a NullPointerException
 639   
         // but at the same time, return true if the componentAttribute is also null
 640  728
         if (patternString == null) {
 641  0
             return (componentAttribute == null);
 642   
         }
 643   
 
 644  728
         return ((componentAttribute != null) && (re != null)
 645   
         && re.match(componentAttribute));
 646   
     }
 647   
 
 648   
     /**
 649   
      * Puase the finder for a bit.
 650   
      * @param date Termination time of the finder.
 651   
      */
 652  76
     protected final void pause(final long date) {
 653  76
         int sleep = 1000;
 654   
 
 655  76
         if ((System.currentTimeMillis() + 3000) < date) {
 656  4
             sleep = 3000;
 657   
         }
 658   
 
 659  76
         try {
 660  76
             Thread.currentThread().sleep(sleep);
 661   
         } catch (InterruptedException ex) {
 662   
             ; // Ignore
 663   
         }
 664   
     }
 665   
 }
 666