Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(feat) Assert, Matcher: Improve type-aware matchers. #195

Merged
merged 11 commits into from
Feb 21, 2015
Merged
78 changes: 58 additions & 20 deletions subprojects/testfx-core/src/main/java/org/testfx/api/FxAssert.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,18 @@
*/
package org.testfx.api;

import java.util.Set;
import javafx.scene.Node;

import com.google.common.base.Predicate;
import org.hamcrest.Matcher;
import org.hamcrest.MatcherAssert;
import org.testfx.api.annotation.Unstable;
import org.testfx.matcher.base.BaseMatchers;
import org.testfx.matcher.base.GeneralMatchers;
import org.testfx.service.finder.NodeFinder;
import org.testfx.service.query.NodeQuery;

@Unstable(reason = "class was recently added")
@Unstable(reason = "method signatures need fine-tuning")
public class FxAssert {

//---------------------------------------------------------------------------------------------
Expand All @@ -43,41 +45,64 @@ public class FxAssert {
// STATIC METHODS.
//---------------------------------------------------------------------------------------------

// ASSERTIONS WITH EMPTY REASON.
// ASSERTIONS: GENERAL.

public static <T> void verifyThat(T value,
Matcher<? super T> matcher) {
verifyThatImpl(emptyReason(), value, matcher);
}

// ASSERTIONS: {NODE, NODES} + MATCHER.

public static <T extends Node> void verifyThat(T node,
Matcher<T> nodeMatcher) {
verifyThatImpl(emptyReason(), node, nodeMatcher);
}

public static <T extends Node> void verifyThatIter(Iterable<T> nodes,
Matcher<Iterable<T>> nodesMatcher) {
verifyThatImpl(emptyReason(), nodes, nodesMatcher);
}

// ASSERTIONS: STRING QUERY + MATCHER.

public static <T extends Node> void verifyThat(String nodeQuery,
Matcher<T> nodeMatcher) {
verifyThatImpl(emptyReason(), toNode(nodeQuery), nodeMatcher);
}

public static <T extends Node> void verifyThat(T node,
Predicate<T> nodePredicate) {
verifyThatImpl(emptyReason(), node, toNodeMatcher(nodePredicate));
public static <T extends Node> void verifyThatIter(String nodeQuery,
Matcher<Iterable<T>> nodesMatcher) {
verifyThatImpl(emptyReason(), toNodeSet(nodeQuery), nodesMatcher);
}

// ASSERTIONS WITH REASON.
// ASSERTIONS: NODE QUERY + MATCHER.

public static <T> void verifyThat(String reason,
T value,
Matcher<? super T> matcher) {
verifyThatImpl(reason, value, matcher);
public static <T extends Node> void verifyThat(NodeQuery nodeQuery,
Matcher<T> nodeMatcher) {
verifyThatImpl(emptyReason(), toNode(nodeQuery), nodeMatcher);
}

public static <T extends Node> void verifyThat(String reason,
String nodeQuery,
Matcher<T> nodeMatcher) {
verifyThatImpl(reason, toNode(nodeQuery), nodeMatcher);
public static <T extends Node> void verifyThatIter(NodeQuery nodeQuery,
Matcher<Iterable<T>> nodesMatcher) {
verifyThatImpl(emptyReason(), toNodeSet(nodeQuery), nodesMatcher);
}

// ASSERTIONS: {NODE, STRING QUERY, NODE QUERY} + PREDICATE.

public static <T extends Node> void verifyThat(T node,
Predicate<T> nodePredicate) {
verifyThatImpl(emptyReason(), node, toNodeMatcher(nodePredicate));
}

public static <T extends Node> void verifyThat(String nodeQuery,
Predicate<T> nodePredicate) {
verifyThatImpl(emptyReason(), toNode(nodeQuery), toNodeMatcher(nodePredicate));
}

public static <T extends Node> void verifyThat(String reason,
T node,
public static <T extends Node> void verifyThat(NodeQuery nodeQuery,
Predicate<T> nodePredicate) {
verifyThatImpl(reason, node, toNodeMatcher(nodePredicate));
verifyThatImpl(emptyReason(), toNode(nodeQuery), toNodeMatcher(nodePredicate));
}

// INTERNAL CONTEXT.
Expand Down Expand Up @@ -111,11 +136,24 @@ private static String emptyReason() {

private static <T extends Node> T toNode(String nodeQuery) {
NodeFinder nodeFinder = assertContext().getNodeFinder();
return nodeFinder.nodes(nodeQuery).queryFirst();
return toNode(nodeFinder.nodes(nodeQuery));
}

private static <T extends Node> Set<T> toNodeSet(String nodeQuery) {
NodeFinder nodeFinder = assertContext().getNodeFinder();
return toNodeSet(nodeFinder.nodes(nodeQuery));
}

private static <T extends Node> T toNode(NodeQuery nodeQuery) {
return nodeQuery.queryFirst();
}

private static <T extends Node> Set<T> toNodeSet(NodeQuery nodeQuery) {
return nodeQuery.queryAll();
}

private static <T extends Node> Matcher<T> toNodeMatcher(Predicate<T> nodePredicate) {
return BaseMatchers.baseMatcher("applies on Predicate", nodePredicate);
return GeneralMatchers.baseMatcher("applies on Predicate", nodePredicate);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ public PointQuery point(String query) {
@Override
public <T> PointQuery point(Matcher<T> matcher) {
NodeQuery nodeQuery = nodes(matcher);
Node node = queryFirstNode(nodeQuery, "the matcher");
Node node = queryFirstNode(nodeQuery, "the matcher \"" + matcher.toString() + "\"");
return point(node).atPosition(context.getPointPosition());
}

Expand Down Expand Up @@ -846,7 +846,7 @@ private PointQuery pointOfVisibleNode(String query) {

private <T> PointQuery pointOfVisibleNode(Matcher<T> matcher) {
NodeQuery nodeQuery = nodes(matcher);
Node node = queryFirstVisibleNode(nodeQuery, "the matcher");
Node node = queryFirstVisibleNode(nodeQuery, "the matcher \"" + matcher.toString() + "\"");
return point(node);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
*/
package org.testfx.matcher.base;

import javafx.scene.Node;

import com.google.common.base.Predicate;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
Expand All @@ -25,16 +23,16 @@
import org.hamcrest.TypeSafeMatcher;
import org.testfx.api.annotation.Unstable;

@Unstable(reason = "needs more tests")
public class BaseMatchers {
@Unstable(reason = "requires more testing; likely to be replaced by a builder")
public class GeneralMatchers {

//---------------------------------------------------------------------------------------------
// STATIC FACTORY METHODS.
// STATIC METHODS.
//---------------------------------------------------------------------------------------------

@Factory
public static <T extends Node> Matcher<T> baseMatcher(final String descriptionText,
final Predicate<T> nodePredicate) {
public static <T> Matcher<T> baseMatcher(final String descriptionText,
final Predicate<T> predicate) {
return new BaseMatcher<T>() {
@Override
public void describeTo(Description description) {
Expand All @@ -43,39 +41,40 @@ public void describeTo(Description description) {

@Override
@SuppressWarnings("unchecked")
public boolean matches(Object node) {
return nodePredicate.apply((T) node);
public boolean matches(Object object) {
return predicate.apply((T) object);
}

@Override
public void describeMismatch(Object node,
public void describeMismatch(Object object,
Description description) {
description.appendText("was ").appendValue(node);
description.appendText("was ").appendValue(object);
}
};
}

@Factory
public static <T extends Node> Matcher<T> typeSafeMatcher(final Class<T> expectedType,
public static <S, T extends S> Matcher<S> typeSafeMatcher(final Class<T> expectedType,
final String descriptionText,
final Predicate<T> nodePredicate) {
final Predicate<T> predicate) {
// This simply implements the null check, checks the type and then casts.
return new TypeSafeMatcher<T>(expectedType) {
return new TypeSafeMatcher<S>(expectedType) {
@Override
public void describeTo(Description description) {
description.appendText(expectedType.getSimpleName());
description.appendText(" ").appendText(descriptionText);
}

@Override
protected boolean matchesSafely(T node) {
return nodePredicate.apply(node);
@SuppressWarnings("unchecked")
protected boolean matchesSafely(S object) {
return predicate.apply((T) object);
}

@Override
protected void describeMismatchSafely(Node node,
protected void describeMismatchSafely(S object,
Description description) {
description.appendText("was ").appendValue(node);
description.appendText("was ").appendValue(object);
}
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2013-2014 SmartBear Software
*
* Licensed under the EUPL, Version 1.1 or - as soon they will be approved by the European
* Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work
* except in compliance with the Licence.
*
* You may obtain a copy of the Licence at:
* http://ec.europa.eu/idabc/eupl
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the Licence for the specific language governing permissions
* and limitations under the Licence.
*/
package org.testfx.matcher.base;

import javafx.geometry.Dimension2D;

import org.hamcrest.Factory;
import org.hamcrest.Matcher;
import org.testfx.api.annotation.Unstable;

import static org.testfx.matcher.base.GeneralMatchers.typeSafeMatcher;

@Unstable(reason = "needs more tests")
public class GeometryMatchers {

//---------------------------------------------------------------------------------------------
// STATIC METHODS.
//---------------------------------------------------------------------------------------------

@Factory
public static Matcher<Object> hasDimension(double width,
double height) {
String descriptionText = "has dimension (" + width + ", " + height + ")";
return typeSafeMatcher(Dimension2D.class, descriptionText,
dimension -> hasDimension(dimension, width, height));
}

//---------------------------------------------------------------------------------------------
// PRIVATE STATIC METHODS.
//---------------------------------------------------------------------------------------------

private static boolean hasDimension(Dimension2D dimension,
double width,
double height) {
return dimension.getWidth() == width && dimension.getHeight() == height;
}

}