![JAR search and dependency download from the Maven repository](/logo.png)
com.objogate.wl.swing.driver.ComponentDriver Maven / Gradle / Ivy
Show all versions of windowlicker-swing Show documentation
package com.objogate.wl.swing.driver;
import java.awt.Color;
import java.awt.Component;
import org.hamcrest.BaseMatcher;
import static org.hamcrest.CoreMatchers.allOf;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import static org.hamcrest.Matchers.equalTo;
import com.objogate.wl.Gesture;
import com.objogate.wl.Probe;
import com.objogate.wl.Prober;
import com.objogate.wl.Query;
import static com.objogate.wl.gesture.Gestures.*;
import com.objogate.wl.gesture.Tracker;
import com.objogate.wl.internal.PropertyQuery;
import com.objogate.wl.swing.ComponentFinder;
import com.objogate.wl.swing.ComponentManipulation;
import com.objogate.wl.swing.ComponentSelector;
import com.objogate.wl.swing.gesture.ComponentCenterTracker;
import com.objogate.wl.swing.gesture.ComponentOffsetTracker;
import com.objogate.wl.swing.gesture.GesturePerformer;
import com.objogate.wl.swing.matcher.ComponentEnabledMatcher;
import com.objogate.wl.swing.matcher.ComponentOpaqueMatcher;
import com.objogate.wl.swing.matcher.DisplayableComponentMatcher;
import com.objogate.wl.swing.matcher.ShowingOnScreenMatcher;
import com.objogate.wl.swing.probe.*;
public abstract class ComponentDriver {
private final Prober prober;
private final ComponentSelector selector;
//TODO: (nat) make drivers create gestures, not use a gesturePerformer directly
protected final GesturePerformer gesturePerformer;
public ComponentDriver(GesturePerformer gesturePerformer, ComponentSelector selector, Prober prober) {
this.selector = selector;
this.prober = prober;
this.gesturePerformer = gesturePerformer;
}
public ComponentDriver(ComponentDriver extends Component> parentOrOwner, ComponentSelector selector) {
this.selector = selector;
this.prober = parentOrOwner.prober;
this.gesturePerformer = parentOrOwner.gesturePerformer;
}
public ComponentDriver(ComponentDriver extends Component> parentOrOwner, Class componentType, Matcher super T>... matchers) {
this(parentOrOwner, new SingleComponentFinder(new RecursiveComponentFinder(componentType, allOf(matchers), parentOrOwner.selector)));
}
/**
* Check a probe.
*
* This is the fundamental hook for assertions and manipulations, upon which more convenient methods are
* built. It is exposed as a public method to act as an "escape route" so that
* users can extend drivers through a stable extension point.
*
* @param probe The probe to be run and checked.
*/
public void check(Probe probe) {
prober.check(probe);
}
/**
* Returns a selector that identifies the component driven by this driver. This can be used to make assertions
* about the component or search for subcomponents.
*
* @return a selector that identifies the component driven by this driver.
* @see #check(com.objogate.wl.Probe)
* @see #all(Class,org.hamcrest.Matcher)
* @see #the(Class,org.hamcrest.Matcher)
* @see #is(org.hamcrest.Matcher)
* @see #has(com.objogate.wl.Query,org.hamcrest.Matcher)
*/
public ComponentSelector component() {
return selector;
}
/**
* Returns a selector that identifies all subcomponents of the component driven by this driver that match
* the given criteria.
*
* @param type The type of subcomponents to finde
* @param criteria The criteria by which to select subcomponents
* @return a selector that identifies the component driven by this driver.
*/
public ComponentFinder all(Class type, Matcher super U> criteria) {
return ComponentFinders.all(type, criteria, selector);
}
/**
* Returns a selector that identifies a single subcomponent of the component driven by this driver that matches
* the given criteria.
*
* @param type The type of subcomponents to finde
* @param criteria The criteria by which to select subcomponents
* @return a selector that identifies the component driven by this driver.
*/
public ComponentSelector the(Class type, Matcher super U> criteria) {
return ComponentFinders.the(type, criteria, selector);
}
/**
* Make an assertion about the component's state. The component must meet all the
* given criteria.
*
* This is a simpler hook for assertions, upon which more convenient methods can be
* built. It is exposed as a public method to act as an "escape route" so that
* users can extend drivers through a stable extension point.
*
* @param criteria The criteria that the component must meet.
*/
public void is(Matcher super T> criteria) {
check(new ComponentAssertionProbe(selector, criteria));
}
/**
* Make an assertion about the value of a component property of the component.
* The property value must meet all the given criteria.
*
* This is a simpler hook for assertions, upon which more convenient methods can be
* built. It is exposed as a public method to act as an "escape route" so that
* users can extend drivers through a stable extension point.
*
* @param query A query that returns the value of a property of the component
* @param criteria The criteria that the property value must meet.
*/
public void has(Query super T, P> query, Matcher super P> criteria) {
check(new ComponentPropertyAssertionProbe(selector, query, criteria));
}
/**
* Manipulate the component through it's API, not through the input devices. The manipulation
* is performed on the AWT event dispatch thread.
*
* This is the fundamental hook for calling the component, upon which more convenient methods are
* built. It is exposed as a public method to act as an "escape route" so that
* users can extend drivers through a stable extension point.
*
* @param description A description of the manipulation, reported if the component selector fails.
* @param manipulation The manipulation to perform
*/
public void perform(String description, ComponentManipulation super T> manipulation) {
check(new ComponentManipulatorProbe(selector, manipulation));
}
//TODO: (nat) make drivers create gestures, not use a gesturePerformer directly
public void performGesture(Gesture... gestures) {
gesturePerformer.perform(gestures);
}
protected Tracker offset(int offsetX, int offsetY) {
return new ComponentOffsetTracker(prober, selector, offsetX, offsetY);
}
protected Tracker centerOfComponent() {
return new ComponentCenterTracker(prober, selector);
}
protected Prober prober() {
return prober;
}
public void leftClickOnComponent() {
isShowingOnScreen();
performGesture(moveMouseTo(centerOfComponent()), clickMouseButton(BUTTON1));
}
protected void isShowingOnScreen() {
is(ComponentDriver.showingOnScreen());
}
/**
* Move to centre of component.
*/
public void moveMouseToCenter() {
performGesture(moveMouseTo(centerOfComponent()));
}
public void moveMouseToOffset(int offsetX, int offsetY) {
performGesture(moveMouseTo(offset(offsetX, offsetY)));
}
public void hasForegroundColor(Color color) {
hasForegroundColor(equalTo(color));
}
public void hasForegroundColor(Matcher color) {
has(foregroundColor(), color);
}
public void hasBackgroundColor(Color color) {
hasBackgroundColor(equalTo(color));
}
//TODO (nick): what is a nice way of combining these to produce decent error messages?
public void hasBackgroundColor(Matcher color) {
has(backgroundColor(), color);
//need to check opacity else the background color isn't visible
// -- nat: not necessarily true, depends on component type
is(opaque());
}
public static Matcher with(Query super T, P> propertyQuery,
Matcher super P> valueMatcher) {
return new QueryResultMatcher(propertyQuery, valueMatcher);
}
public static class QueryResultMatcher extends BaseMatcher {
private final Query super C, P> query;
private final Matcher super P> resultMatcher;
public QueryResultMatcher(Query super C, P> query, Matcher super P> resultMatcher) {
this.query = query;
this.resultMatcher = resultMatcher;
}
//TODO: any way to check the dynamic type of item?
@SuppressWarnings("unchecked")
public boolean matches(Object item) {
return item != null && resultMatcher.matches(query.query((C) item));
}
public void describeTo(Description description) {
description
.appendText("with ")
.appendDescriptionOf(query)
.appendText(" ")
.appendDescriptionOf(resultMatcher);
}
}
public static Query name() {
return new PropertyQuery("name") {
public String query(Component component) {
return component.getName();
}
};
}
public static Query backgroundColor() {
return new PropertyQuery("background color") {
public Color query(Component component) {
return component.getBackground();
}
};
}
public static Matcher named(String nameValue) {
return with(name(), equalTo(nameValue));
}
public static Matcher showingOnScreen() {
return new ShowingOnScreenMatcher();
}
public static Matcher displayable() {
return new DisplayableComponentMatcher();
}
public static Matcher opaque() {
return new ComponentOpaqueMatcher();
}
public static Matcher enabled() {
return new ComponentEnabledMatcher();
}
public static Query foregroundColor() {
return new PropertyQuery("foreground color") {
public Color query(Component component) {
return component.getForeground();
}
};
}
}