All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.objogate.wl.swing.driver.ComponentDriver Maven / Gradle / Ivy

The newest version!
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 parentOrOwner, ComponentSelector selector) {
        this.selector = selector;
        this.prober = parentOrOwner.prober;
        this.gesturePerformer = parentOrOwner.gesturePerformer;
    }

    public ComponentDriver(ComponentDriver parentOrOwner, Class componentType, Matcher... 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 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 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 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 query, Matcher 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 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 propertyQuery, Matcher valueMatcher) { return new QueryResultMatcher(propertyQuery, valueMatcher); } public static class QueryResultMatcher extends BaseMatcher { private final Query query; private final Matcher resultMatcher; public QueryResultMatcher(Query query, Matcher 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(); } }; } }