
junit.extensions.jfcunit.finder.Finder Maven / Gradle / Ivy
package junit.extensions.jfcunit.finder;
import java.awt.AWTException;
import java.awt.Component;
import java.awt.Container;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.swing.JOptionPane;
import junit.extensions.jfcunit.PatternHelper;
import junit.extensions.jfcunit.RobotTestHelper;
import junit.extensions.jfcunit.WindowMonitor;
import junit.extensions.jfcunit.eventdata.MouseEventDataEx;
/**
* Abstract class for defining call back classes to test whether a
* {@link java.awt.Component} that is being searched for has been found.
*
* @author Vijay Aravamudhan :
* ThoughtWorks Inc.
*/
public abstract class Finder
{
/**
* Robot for debug mode of finders.
*/
private static RobotTestHelper s_robot = null;
/**
* Robot Exception received.
*/
private static boolean s_robotException = false;
/**
* String so for the OP codes.
*/
private static final String[] OP_CODE_STRINGS = new String[]
{ "match", "startswith", "endswith", "equals", "contains" };
/**
* Match the item using a Regular expression.
*/
public static final int OP_MATCH = 0;
/**
* Check that the value starts with the given value.
*/
public static final int OP_STARTSWITH = 1;
/**
* Check that the value ends with the given value.
*/
public static final int OP_ENDSWITH = 2;
/**
* Check that the values are equal.
*/
public static final int OP_EQUALS = 3;
/**
* Check that the value is contained.
*/
public static final int OP_CONTAINS = 4;
/**
* This member is used to evaluate regular expressions.
*/
private Pattern m_patternMatcher;
/**
* Ignore case.
*/
private boolean m_caseIndependent = false;
/**
* The debug state of the finder.
*/
private boolean m_debug = false;
/**
* visibility property defaults to false.
*/
private boolean m_ignoreVisiblity = false;
/**
* Show Debug.
*/
private boolean m_showDebug = false;
/**
* Operation to be performed when selecting items.
*/
private int m_operation = OP_MATCH;
/**
* Default wait time.
*/
private static int s_defaultWait = 30;
/**
* The max wait time for a window to appear in milliseconds.
*/
private int m_wait = s_defaultWait;
/**
* Convert the String to a Operation code.
*
* @param code
* String version of the Operation.
* @return int version of the operation.
*/
public static final int getOperation(final String code)
{
for (int i = 0; i < OP_CODE_STRINGS.length; i++)
{
if (OP_CODE_STRINGS[i].equalsIgnoreCase(code))
{
return i;
}
}
throw new java.lang.IllegalArgumentException("Operation not found:" + code);
}
/**
* Get the string version of the operation.
*
* @param code
* int Finder.OP_code
* @return String version of the operation.
*/
public static final String getOperationString(final int code)
{
if (code < 0 || code >= OP_CODE_STRINGS.length)
{
throw new IllegalArgumentException("Invalid Operation code:" + code);
}
return OP_CODE_STRINGS[code];
}
/**
* Get the debug state of the finder.
*
* @return true if debugging should be enabled.
*/
public final boolean getDebug()
{
return this.m_debug;
}
/**
* Set the operation to be performed by this finder.
*
* @param operation
* Operation to be performed.
* @see OP_EQUALS Exact match
* @see OP_MATCH Matches a Regular Expression
* @see OP_STARTSWITH Starts with
* @see OP_ENDSWITH Ends with
* @see OP_CONTAINS Contains
*/
public final void setOperation(final int operation)
{
this.m_operation = operation;
}
/**
* Get the operation.
*
* @return the operation to be performed by the finder.
*/
public final int getOperation()
{
return this.m_operation;
}
/**
* Set the debug state of the finder.
*
* @param value
* true if debugging should be enabled.
*/
public final void setShowDebug(final boolean value)
{
if (value && s_robot == null && !s_robotException)
{
try
{
s_robot = new RobotTestHelper();
} catch (final AWTException ex)
{
System.err.println("Could not create robot:");
ex.printStackTrace();
s_robotException = true;
}
}
this.m_showDebug = value;
}
/**
* Get the debug state of the finder.
*
* @return true if debugging should be enabled.
*/
public final boolean getShowDebug()
{
return this.m_showDebug;
}
/**
* Set the max wait time for a window to appear.
*
* @param wait
* time in seconds.
*/
public final Finder setWait(final int wait)
{
this.m_wait = wait;
return this;
}
/**
* Get the wait time.
*
* @return Wait time in seconds. Default wait time is 10 seconds.
*/
public final int getWait()
{
return this.m_wait;
}
/**
* Set the default wait time for the finders. This effects all new Finders
* which are created.
*
* @param wait
* int duration to wait by default.
*/
public static final void setDefaultWait(final int wait)
{
s_defaultWait = wait;
}
/**
* Get the default wait duration in seconds. The default effects all new
* finders created.
*
* @return int default duration to wait.
*/
public static final int getDefaultWait()
{
return s_defaultWait;
}
/**
* Evaluate the current operation.
*
* @param leftside
* String to be compared.
* @param rightside
* String or Regular expression.
* @return result of operation
*/
public final boolean evaluate(final String leftside, final String rightside)
{
if (leftside == null)
{
// If left and right are null then return true.
// otherwise return false.
return rightside == null;
}
if (rightside == null)
{
return false;
}
if (this.m_operation == OP_CONTAINS)
{
return leftside.indexOf(rightside) >= 0;
} else if (this.m_operation == OP_ENDSWITH)
{
return leftside.endsWith(rightside);
} else if (this.m_operation == OP_STARTSWITH)
{
return leftside.startsWith(rightside);
} else if (this.m_operation == OP_EQUALS)
{
return leftside.equals(rightside);
} else if (this.m_operation == OP_MATCH)
{
return matchPattern(leftside, rightside);
}
throw new java.lang.IllegalStateException("Invalid operation for finder:" + this.m_operation);
}
/**
* Set the finder into a case independent mode.
*
* @param ignoreCase
* true if case should be ignored.
*/
public void setCaseIndependent(final boolean ignoreCase)
{
this.m_caseIndependent = ignoreCase;
}
/**
* Get the state of ignore case.
*
* @return boolean true if the case is ignored.
*/
public boolean isCaseIndependent()
{
return this.m_caseIndependent;
}
/**
* Set the debug state of the finder.
*
* @param value
* true if debugging should be enabled.
*/
public final void setDebug(final boolean value)
{
if (value && s_robot == null && !s_robotException)
{
try
{
s_robot = new RobotTestHelper();
} catch (final AWTException ex)
{
System.err.println("Could not create robot:");
ex.printStackTrace();
s_robotException = true;
}
}
this.m_debug = value;
}
/**
* Set the ignore visiblity property, to generate the proper index when a
* dialog is closed.
*
* @param value
* true if the visibility should be ignored.
*/
public final void setIgnoreVisibility(final boolean value)
{
this.m_ignoreVisiblity = value;
}
/**
* Method that returns true if the given component matches the search
* criteria.
*
* @param comp
* The {@link Component} to test
* @return true if this {@link Component} is a match
*/
public abstract boolean testComponent(final Component comp);
/**
* Find the Component matching this finder at the given index within the
* container specified.
*
* @param conts
* Container to be searched.
* @param index
* Index of the item.
* @return Component found.
*/
protected T find(final Container[] conts, final int index)
{
final long abortAfter = System.currentTimeMillis() + getWait() * 1000;
Container[] search = null;
do
{
int idx = 0;
if (conts == null)
{
search = WindowMonitor.getWindows();
} else
{
search = conts;
}
if (this instanceof AbstractWindowFinder)
{
final Object[] all = ((AbstractWindowFinder) this).findAll().toArray();
if (all.length <= index)
{
continue;
}
return (T) all[index];
}
for (int window = 0; window < search.length; window++)
{
final List comps = findComponentList(this, search[window], new ArrayList(), index - idx);
final int size = comps.size();
if (size > 0 && size > index - idx)
{
final T comp = comps.get(index - idx);
return comp;
}
idx += comps.size();
}
pause(abortAfter);
} while (System.currentTimeMillis() < abortAfter);
return null;
}
/**
* Find the component at the index. Scope to search is all frames/dialogs.
*
* @param index
* Index of the item to be found.
* @return Item at the given index.
*/
public final T find(final int index)
{
return find((Container[]) null, index);
}
/**
* Find the Component matching this finder at the given index within the
* container specified.
*
* @param cont
* Container to be searched.
* @param index
* Index of the item.
* @return Component found.
*/
public Component find(final Container cont, final int index)
{
return find(new Container[]
{ cont }, index);
}
/**
* Find the first component. Scope to search is all frames/dialogs.
*
* @return First Item.
*/
public final T find()
{
return find(0);
}
/**
* Find all of the resulting items in the entire GUI application.
*
* @return List resulting items matching finder.
*/
public List findAll()
{
return findAll((Container[]) null);
}
/**
* Find all of the items matching this finder in the container give.
*
* @param cont
* Container to be searched.
* @return List resulting items matching finder.
*/
public List findAll(final Container cont)
{
return findAll(new Container[]
{ cont });
}
/**
* Find all of the components for this finder in the set of containers
* given.
*
* @param cont
* Container[] Set of containers to search.
* @return List resulting items matching finder.
*/
public List findAll(final Container[] cont)
{
return findAll(cont, new ArrayList());
}
/**
* This find all uses a recursive pattern for internal processing.
*
* @param cont
* Container[] Container list.
* @param results
* List to which resulting items should be added.
* @return List resulting list.
*/
protected List findAll(final Container[] cont, final List results)
{
Container[] containers = cont;
if (containers == null)
{
containers = WindowMonitor.getWindows();
}
for (int i = 0; i < containers.length; i++)
{
findComponentList(this, containers[i], results, Integer.MAX_VALUE);
}
return results;
}
/**
* Method that calls itself repetitively to build up a list of all
* components in the container instance that is passed in.
*
* @param finder
* An instance of the finder which implements the testComponent()
* method.
* @param cont
* The Container inside which the component is to be found.
* @param pList
* The return list.
* @param index
* The index of the component. The first component matching the
* criteria will have index 0, the second 1, etc.
* @return The component that has been found (or null if none found).
*/
public static final List findComponentList(final Finder finder, final Container cont,
final List pList, final int index)
{
List outList = pList;
if (outList == null)
{
outList = new ArrayList();
}
if (cont == null || finder == null)
{
return outList;
}
final Component[] children = cont.getComponents();
for (int i = 0; i < children.length; i++)
{
if (finder.testComponent(children[i]))
{
if (finder.getDebug())
{
System.err.println("Finder Candidate(" + outList.size() + ") " + children[i].getClass().getName());
}
if (finder.getShowDebug() && s_robot != null)
{
try
{
s_robot.enterClickAndLeave(new MouseEventDataEx(children[i], 0, 0, false));
JOptionPane.showMessageDialog(null, "Finder Candidate Index:" + outList.size()
+ "" + children[i].getClass().getName() + "");
} catch (final Exception ae)
{
ae.printStackTrace();
// Ignore
}
}
if (!outList.contains(children[i]))
{
outList.add((T) children[i]);
}
if (outList.size() > index)
{
return outList;
}
} else if (children[i] instanceof Container)
{
findComponentList(finder, (Container) children[i], outList, index);
if (outList.size() > index)
{
return outList;
}
}
}
return outList;
}
/**
* This method is used to check that the window object is an instance of the
* specified class and is also visible.
*
* @param comp
* The {@link Component} to be checked
* @param cls
* The type of the component
* @return true if the component is of the specified type and is visible.
*/
protected final boolean isValidForProcessing(final Component comp, final Class cls)
{
final boolean value = comp != null && cls != null && cls.isInstance(comp)
&& (this.m_ignoreVisiblity || comp.isShowing());
return value;
}
/**
* Recreate the pattern.
*
* @param patternString
* String pattern string.
* @param caseIndependent
* boolean true if the case should be ignored.
*/
protected void recreatePatternMatcher(final String patternString, final boolean caseIndependent)
{
this.m_patternMatcher = null;
createPatternMatcher(patternString, caseIndependent);
}
/**
* This method is used to filter components' attributes based on a pattern
* specified by the user. For example, to search for all windows with title
* matching 'testWindow*'. Note: If the patternString is null, we need to
* avoid the PatternCompiler.compile()
throwing a
* NullPointerException and in this case, return true if the
* componentAttribute is also null. The pattern syntax can be found at the
* Jakarta RegExp API Documentation in {@link org.apache.regexp.RE}.
*
* @param patternString
* The pattern to match with
* @param caseIndependent
* Whether the match should be case independent (true) or not
* (false)
*/
protected void createPatternMatcher(final String patternString, final boolean caseIndependent)
{
if (this.m_patternMatcher == null)
{
try
{
this.m_patternMatcher = PatternHelper.compile(patternString, caseIndependent);
} catch (final PatternSyntaxException e)
{
this.m_patternMatcher = null;
}
}
}
/**
* This method is used to filter components' attributes based on a pattern
* specified by the user. For example, to search for all windows with title
* matching 'testWindow*'. Note: If the patternString is null, we need to
* avoid the PatternCompiler.compile()
throwing a
* NullPointerException and in this case, return true if the
* componentAttribute is also null. The pattern syntax can be found at the
* Jakarta RegExp API Documentation in {@link org.apache.regexp.RE}.
*
* @param componentAttribute
* The attribute text of the component to match against
* @param patternString
* The pattern to match with
* @param caseIndependent
* Whether the match should be case independent (true) or not
* (false)
* @return boolean whether the pattern is contained within the components'
* attribute text
* @see #createPatternMatcher(String, boolean)
* @see #matchPattern(String, String)
*/
protected boolean matchPattern(final String componentAttribute, final String patternString,
final boolean caseIndependent)
{
createPatternMatcher(patternString, caseIndependent);
return matchPattern(componentAttribute, patternString);
}
/**
* This method is used to filter components' attributes based on a pattern
* specified by the user. For example, to search for all windows with title
* matching 'testWindow*'. Note: If the patternString is null, we need to
* avoid the PatternCompiler.compile()
throwing a
* NullPointerException and in this case, return true if the
* componentAttribute is also null. The pattern syntax can be found at the
* Jakarta RegExp API Documentation in {@link org.apache.regexp.RE}.
*
* @param componentAttribute
* The attribute text of the component to match against
* @param patternString
* The pattern to match with
* @return boolean whether the pattern is contained within the components'
* attribute text
*/
protected boolean matchPattern(final String componentAttribute, final String patternString)
{
return matchPattern(componentAttribute, patternString, this.m_patternMatcher);
}
/**
* This method is used to filter components' attributes based on a pattern
* specified by the user. For example, to search for all windows with title
* matching 'testWindow*'. Note: If the patternString is null, we need to
* avoid the PatternCompiler.compile()
throwing a
* NullPointerException and in this case, return true if the
* componentAttribute is also null. The pattern syntax can be found at the
* Jakarta RegExp API Documentation in {@link org.apache.regexp.RE}.
*
* @param componentAttribute
* The attribute text of the component to match against
* @param patternString
* The pattern to match with
* @param re
* The RE pattern matcher to be used
* @return boolean whether the pattern is contained within the components'
* attribute text
*/
protected final boolean matchPattern(final String componentAttribute, final String patternString, final Pattern re)
{
// if the patternString is null, we need to avoid a NullPointerException
// but at the same time, return true if the componentAttribute is also
// null
if (patternString == null)
{
return componentAttribute == null;
}
return componentAttribute != null && re != null && re.matcher(componentAttribute).matches();
}
/**
* Puase the finder for a bit.
*
* @param date
* Termination time of the finder.
*/
protected final void pause(final long date)
{
int sleep = 1000;
if (System.currentTimeMillis() + 3000 < date)
{
sleep = 3000;
}
try
{
Thread.currentThread();
Thread.sleep(sleep);
} catch (final InterruptedException ex)
{
; // Ignore
}
}
}