From c1dbb44e71e47410ad5685aba3ef3fccb095a2b4 Mon Sep 17 00:00:00 2001 From: Paul Duffin Date: Fri, 20 Jan 2017 15:04:28 +0000 Subject: Upgrade to almost 2.0.0.0 See the README.android for the exact version used and an explanation as to why it was chosen. Bug: 30946317 Test: make checkbuild Change-Id: Icae106f5e4a62d2a34f4cf03506fd63676814c07 --- .../main/java/org/hamcrest/BaseDescription.java | 271 +++++++------ .../src/main/java/org/hamcrest/BaseMatcher.java | 9 +- .../src/main/java/org/hamcrest/Condition.java | 69 ++++ .../src/main/java/org/hamcrest/CoreMatchers.java | 427 +++++++++++++++++---- .../src/main/java/org/hamcrest/CustomMatcher.java | 37 ++ .../java/org/hamcrest/CustomTypeSafeMatcher.java | 39 ++ .../src/main/java/org/hamcrest/Description.java | 133 ++++--- .../main/java/org/hamcrest/DiagnosingMatcher.java | 21 + .../src/main/java/org/hamcrest/Factory.java | 17 - .../src/main/java/org/hamcrest/FeatureMatcher.java | 54 +++ .../src/main/java/org/hamcrest/Matcher.java | 34 +- .../src/main/java/org/hamcrest/MatcherAssert.java | 51 +-- .../src/main/java/org/hamcrest/SelfDescribing.java | 2 +- .../main/java/org/hamcrest/StringDescription.java | 123 +++--- .../org/hamcrest/TypeSafeDiagnosingMatcher.java | 69 ++++ .../main/java/org/hamcrest/TypeSafeMatcher.java | 81 ++-- .../src/main/java/org/hamcrest/core/AllOf.java | 49 +-- .../src/main/java/org/hamcrest/core/AnyOf.java | 49 ++- .../java/org/hamcrest/core/CombinableMatcher.java | 82 ++++ .../main/java/org/hamcrest/core/DescribedAs.java | 124 +++--- .../src/main/java/org/hamcrest/core/Every.java | 44 +++ .../src/main/java/org/hamcrest/core/Is.java | 64 +-- .../main/java/org/hamcrest/core/IsAnything.java | 41 +- .../org/hamcrest/core/IsCollectionContaining.java | 133 +++++++ .../src/main/java/org/hamcrest/core/IsEqual.java | 82 ++-- .../main/java/org/hamcrest/core/IsInstanceOf.java | 81 +++- .../src/main/java/org/hamcrest/core/IsNot.java | 36 +- .../src/main/java/org/hamcrest/core/IsNull.java | 61 ++- .../src/main/java/org/hamcrest/core/IsSame.java | 39 +- .../org/hamcrest/core/ShortcutCombination.java | 33 ++ .../java/org/hamcrest/core/StringContains.java | 46 +++ .../java/org/hamcrest/core/StringEndsWith.java | 42 ++ .../java/org/hamcrest/core/StringStartsWith.java | 40 ++ .../java/org/hamcrest/core/SubstringMatcher.java | 44 +++ .../java/org/hamcrest/internal/ArrayIterator.java | 43 ++- .../java/org/hamcrest/internal/NullSafety.java | 18 + .../hamcrest/internal/ReflectiveTypeFinder.java | 70 ++++ .../org/hamcrest/internal/SelfDescribingValue.java | 1 + .../internal/SelfDescribingValueIterator.java | 7 +- .../main/java/org/hamcrest/internal/package.html | 5 - .../src/main/java/org/hamcrest/package.html | 9 - 41 files changed, 2006 insertions(+), 674 deletions(-) create mode 100644 hamcrest-core/src/main/java/org/hamcrest/Condition.java create mode 100644 hamcrest-core/src/main/java/org/hamcrest/CustomMatcher.java create mode 100644 hamcrest-core/src/main/java/org/hamcrest/CustomTypeSafeMatcher.java create mode 100644 hamcrest-core/src/main/java/org/hamcrest/DiagnosingMatcher.java delete mode 100644 hamcrest-core/src/main/java/org/hamcrest/Factory.java create mode 100644 hamcrest-core/src/main/java/org/hamcrest/FeatureMatcher.java create mode 100644 hamcrest-core/src/main/java/org/hamcrest/TypeSafeDiagnosingMatcher.java create mode 100644 hamcrest-core/src/main/java/org/hamcrest/core/CombinableMatcher.java create mode 100644 hamcrest-core/src/main/java/org/hamcrest/core/Every.java create mode 100644 hamcrest-core/src/main/java/org/hamcrest/core/IsCollectionContaining.java create mode 100644 hamcrest-core/src/main/java/org/hamcrest/core/ShortcutCombination.java create mode 100644 hamcrest-core/src/main/java/org/hamcrest/core/StringContains.java create mode 100644 hamcrest-core/src/main/java/org/hamcrest/core/StringEndsWith.java create mode 100644 hamcrest-core/src/main/java/org/hamcrest/core/StringStartsWith.java create mode 100644 hamcrest-core/src/main/java/org/hamcrest/core/SubstringMatcher.java create mode 100644 hamcrest-core/src/main/java/org/hamcrest/internal/NullSafety.java create mode 100644 hamcrest-core/src/main/java/org/hamcrest/internal/ReflectiveTypeFinder.java delete mode 100644 hamcrest-core/src/main/java/org/hamcrest/internal/package.html delete mode 100644 hamcrest-core/src/main/java/org/hamcrest/package.html (limited to 'hamcrest-core/src/main/java/org/hamcrest') diff --git a/hamcrest-core/src/main/java/org/hamcrest/BaseDescription.java b/hamcrest-core/src/main/java/org/hamcrest/BaseDescription.java index 4c98e5f..6e62e69 100644 --- a/hamcrest-core/src/main/java/org/hamcrest/BaseDescription.java +++ b/hamcrest-core/src/main/java/org/hamcrest/BaseDescription.java @@ -1,127 +1,144 @@ -package org.hamcrest; - -import static java.lang.String.valueOf; - -import java.util.Arrays; -import java.util.Iterator; - -import org.hamcrest.internal.ArrayIterator; -import org.hamcrest.internal.SelfDescribingValueIterator; - -/** - * A {@link Description} that is stored as a string. - */ -public abstract class BaseDescription implements Description { - public Description appendText(String text) { - append(text); - return this; - } - - public Description appendDescriptionOf(SelfDescribing value) { - value.describeTo(this); - return this; - } - - public Description appendValue(Object value) { - if (value == null) { - append("null"); - } else if (value instanceof String) { - toJavaSyntax((String) value); - } else if (value instanceof Character) { - append('"'); - toJavaSyntax((Character) value); - append('"'); - } else if (value instanceof Short) { - append('<'); - append(valueOf(value)); - append("s>"); - } else if (value instanceof Long) { - append('<'); - append(valueOf(value)); - append("L>"); - } else if (value instanceof Float) { - append('<'); - append(valueOf(value)); - append("F>"); - } else if (value.getClass().isArray()) { - appendValueList("[",", ","]", new ArrayIterator(value)); - } else { - append('<'); - append(valueOf(value)); - append('>'); - } - return this; - } - - public Description appendValueList(String start, String separator, String end, T... values) { - return appendValueList(start, separator, end, Arrays.asList(values)); - } - - public Description appendValueList(String start, String separator, String end, Iterable values) { - return appendValueList(start, separator, end, values.iterator()); - } - - private Description appendValueList(String start, String separator, String end, Iterator values) { - return appendList(start, separator, end, new SelfDescribingValueIterator(values)); - } - - public Description appendList(String start, String separator, String end, Iterable values) { - return appendList(start, separator, end, values.iterator()); - } - - private Description appendList(String start, String separator, String end, Iterator i) { - boolean separate = false; - - append(start); - while (i.hasNext()) { - if (separate) append(separator); - appendDescriptionOf(i.next()); - separate = true; - } - append(end); - - return this; - } - - - /** Append the String str to the description. - * The default implementation passes every character to {@link #append(char)}. - * Override in subclasses to provide an efficient implementation. - */ - protected void append(String str) { - for (int i = 0; i < str.length(); i++) { - append(str.charAt(i)); - } - } - - /** Append the char c to the description. - */ - protected abstract void append(char c); - - private void toJavaSyntax(String unformatted) { - append('"'); - for (int i = 0; i < unformatted.length(); i++) { - toJavaSyntax(unformatted.charAt(i)); - } - append('"'); - } - - private void toJavaSyntax(char ch) { - switch (ch) { - case '"': - append("\\\""); - break; - case '\n': - append("\\n"); - break; - case '\r': - append("\\r"); - break; - case '\t': - append("\\t"); - break; - default: - append(ch); - } - } -} +package org.hamcrest; + +import org.hamcrest.internal.ArrayIterator; +import org.hamcrest.internal.SelfDescribingValueIterator; + +import java.util.Arrays; +import java.util.Iterator; + +import static java.lang.String.valueOf; + +/** + * A {@link Description} that is stored as a string. + */ +public abstract class BaseDescription implements Description { + + @Override + public Description appendText(String text) { + append(text); + return this; + } + + @Override + public Description appendDescriptionOf(SelfDescribing value) { + value.describeTo(this); + return this; + } + + @Override + public Description appendValue(Object value) { + if (value == null) { + append("null"); + } else if (value instanceof String) { + toJavaSyntax((String) value); + } else if (value instanceof Character) { + append('"'); + toJavaSyntax((Character) value); + append('"'); + } else if (value instanceof Short) { + append('<'); + append(descriptionOf(value)); + append("s>"); + } else if (value instanceof Long) { + append('<'); + append(descriptionOf(value)); + append("L>"); + } else if (value instanceof Float) { + append('<'); + append(descriptionOf(value)); + append("F>"); + } else if (value.getClass().isArray()) { + appendValueList("[",", ","]", new ArrayIterator(value)); + } else { + append('<'); + append(descriptionOf(value)); + append('>'); + } + return this; + } + + private String descriptionOf(Object value) { + try { + return valueOf(value); + } + catch (Exception e) { + return value.getClass().getName() + "@" + Integer.toHexString(value.hashCode()); + } + } + + @Override + public Description appendValueList(String start, String separator, String end, T... values) { + return appendValueList(start, separator, end, Arrays.asList(values)); + } + + @Override + public Description appendValueList(String start, String separator, String end, Iterable values) { + return appendValueList(start, separator, end, values.iterator()); + } + + private Description appendValueList(String start, String separator, String end, Iterator values) { + return appendList(start, separator, end, new SelfDescribingValueIterator(values)); + } + + @Override + public Description appendList(String start, String separator, String end, Iterable values) { + return appendList(start, separator, end, values.iterator()); + } + + private Description appendList(String start, String separator, String end, Iterator i) { + boolean separate = false; + + append(start); + while (i.hasNext()) { + if (separate) append(separator); + appendDescriptionOf(i.next()); + separate = true; + } + append(end); + + return this; + } + + /** + * Append the String str to the description. + * The default implementation passes every character to {@link #append(char)}. + * Override in subclasses to provide an efficient implementation. + */ + protected void append(String str) { + for (int i = 0; i < str.length(); i++) { + append(str.charAt(i)); + } + } + + /** + * Append the char c to the description. + */ + protected abstract void append(char c); + + private void toJavaSyntax(String unformatted) { + append('"'); + for (int i = 0; i < unformatted.length(); i++) { + toJavaSyntax(unformatted.charAt(i)); + } + append('"'); + } + + private void toJavaSyntax(char ch) { + switch (ch) { + case '"': + append("\\\""); + break; + case '\n': + append("\\n"); + break; + case '\r': + append("\\r"); + break; + case '\t': + append("\\t"); + break; + default: + append(ch); + } + } +} diff --git a/hamcrest-core/src/main/java/org/hamcrest/BaseMatcher.java b/hamcrest-core/src/main/java/org/hamcrest/BaseMatcher.java index 3fdd6f7..484c101 100644 --- a/hamcrest-core/src/main/java/org/hamcrest/BaseMatcher.java +++ b/hamcrest-core/src/main/java/org/hamcrest/BaseMatcher.java @@ -1,5 +1,3 @@ -/* Copyright (c) 2000-2006 hamcrest.org - */ package org.hamcrest; /** @@ -12,10 +10,17 @@ public abstract class BaseMatcher implements Matcher { /** * @see Matcher#_dont_implement_Matcher___instead_extend_BaseMatcher_() */ + @Override + @Deprecated public final void _dont_implement_Matcher___instead_extend_BaseMatcher_() { // See Matcher interface for an explanation of this method. } + @Override + public void describeMismatch(Object item, Description description) { + description.appendText("was ").appendValue(item); + } + @Override public String toString() { return StringDescription.toString(this); diff --git a/hamcrest-core/src/main/java/org/hamcrest/Condition.java b/hamcrest-core/src/main/java/org/hamcrest/Condition.java new file mode 100644 index 0000000..02ce09e --- /dev/null +++ b/hamcrest-core/src/main/java/org/hamcrest/Condition.java @@ -0,0 +1,69 @@ +package org.hamcrest; + +/** + * A Condition implements part of a multi-step match. We sometimes need to write matchers + * that have a sequence of steps, where each step depends on the result of the previous + * step and we can stop processing as soon as a step fails. These classes provide + * infrastructure for writing such a sequence. + * + * Based on https://github.com/npryce/maybe-java + * @author Steve Freeman 2012 http://www.hamcrest.com + */ + +public abstract class Condition { + public static final NotMatched NOT_MATCHED = new NotMatched(); + + public interface Step { + Condition apply(I value, Description mismatch); + } + + private Condition() { } + + public abstract boolean matching(Matcher match, String message); + public abstract Condition and(Step mapping); + + public final boolean matching(Matcher match) { return matching(match, ""); } + public final Condition then(Step mapping) { return and(mapping); } + + @SuppressWarnings("unchecked") + public static Condition notMatched() { + return (Condition) NOT_MATCHED; + } + + public static Condition matched(final T theValue, final Description mismatch) { + return new Matched(theValue, mismatch); + } + + private static final class Matched extends Condition { + private final T theValue; + private final Description mismatch; + + private Matched(T theValue, Description mismatch) { + this.theValue = theValue; + this.mismatch = mismatch; + } + + @Override + public boolean matching(Matcher matcher, String message) { + if (matcher.matches(theValue)) { + return true; + } + mismatch.appendText(message); + matcher.describeMismatch(theValue, mismatch); + return false; + } + + @Override + public Condition and(Step next) { + return next.apply(theValue, mismatch); + } + } + + private static final class NotMatched extends Condition { + @Override public boolean matching(Matcher match, String message) { return false; } + + @Override public Condition and(Step mapping) { + return notMatched(); + } + } +} diff --git a/hamcrest-core/src/main/java/org/hamcrest/CoreMatchers.java b/hamcrest-core/src/main/java/org/hamcrest/CoreMatchers.java index 400a491..d690f7b 100644 --- a/hamcrest-core/src/main/java/org/hamcrest/CoreMatchers.java +++ b/hamcrest-core/src/main/java/org/hamcrest/CoreMatchers.java @@ -1,171 +1,448 @@ -// Generated source. package org.hamcrest; +@SuppressWarnings("UnusedDeclaration") public class CoreMatchers { /** - * Decorates another Matcher, retaining the behavior but allowing tests - * to be slightly more expressive. + * Creates a matcher that matches if the examined object matches ALL of the specified matchers. + * For example: + *
assertThat("myValue", allOf(startsWith("my"), containsString("Val")))
+ */ + public static org.hamcrest.Matcher allOf(java.lang.Iterable> matchers) { + return org.hamcrest.core.AllOf.allOf(matchers); + } + + /** + * Creates a matcher that matches if the examined object matches ALL of the specified matchers. + * For example: + *
assertThat("myValue", allOf(startsWith("my"), containsString("Val")))
+ */ + @SafeVarargs + public static org.hamcrest.Matcher allOf(org.hamcrest.Matcher... matchers) { + return org.hamcrest.core.AllOf.allOf(matchers); + } + + + /** + * Creates a matcher that matches if the examined object matches ANY of the specified matchers. + * For example: + *
assertThat("myValue", anyOf(startsWith("foo"), containsString("Val")))
+ */ + public static org.hamcrest.core.AnyOf anyOf(java.lang.Iterable> matchers) { + return org.hamcrest.core.AnyOf.anyOf(matchers); + } + + /** + * Creates a matcher that matches if the examined object matches ANY of the specified matchers. + * For example: + *
assertThat("myValue", anyOf(startsWith("foo"), containsString("Val")))
+ */ + @SafeVarargs + public static org.hamcrest.core.AnyOf anyOf(org.hamcrest.Matcher... matchers) { + return org.hamcrest.core.AnyOf.anyOf(matchers); + } + + /** + * Creates a matcher that matches when both of the specified matchers match the examined object. + * For example: + *
assertThat("fab", both(containsString("a")).and(containsString("b")))
+ */ + public static org.hamcrest.core.CombinableMatcher.CombinableBothMatcher both(org.hamcrest.Matcher matcher) { + return org.hamcrest.core.CombinableMatcher.both(matcher); + } + + /** + * Creates a matcher that matches when either of the specified matchers match the examined object. + * For example: + *
assertThat("fan", either(containsString("a")).or(containsString("b")))
+ */ + public static org.hamcrest.core.CombinableMatcher.CombinableEitherMatcher either(org.hamcrest.Matcher matcher) { + return org.hamcrest.core.CombinableMatcher.either(matcher); + } + + /** + * Wraps an existing matcher, overriding its description with that specified. All other functions are + * delegated to the decorated matcher, including its mismatch description. + * For example: + *
describedAs("a big decimal equal to %0", equalTo(myBigDecimal), myBigDecimal.toPlainString())
* - * eg. assertThat(cheese, equalTo(smelly)) - * vs assertThat(cheese, is(equalTo(smelly))) + * @param description + * the new description for the wrapped matcher + * @param matcher + * the matcher to wrap + * @param values + * optional values to insert into the tokenised description + */ + public static org.hamcrest.Matcher describedAs(java.lang.String description, org.hamcrest.Matcher matcher, java.lang.Object... values) { + return org.hamcrest.core.DescribedAs.describedAs(description, matcher, values); + } + + /** + * Creates a matcher for {@link Iterable}s that only matches when a single pass over the + * examined {@link Iterable} yields items that are all matched by the specified + * itemMatcher. + * For example: + *
assertThat(Arrays.asList("bar", "baz"), everyItem(startsWith("ba")))
+ * + * @param itemMatcher + * the matcher to apply to every item provided by the examined {@link Iterable} + */ + public static org.hamcrest.Matcher> everyItem(org.hamcrest.Matcher itemMatcher) { + return org.hamcrest.core.Every.everyItem(itemMatcher); + } + + /** + * Decorates another Matcher, retaining its behaviour, but allowing tests + * to be slightly more expressive. + * For example: + *
assertThat(cheese, is(equalTo(smelly)))
+ * instead of: + *
assertThat(cheese, equalTo(smelly))
*/ public static org.hamcrest.Matcher is(org.hamcrest.Matcher matcher) { return org.hamcrest.core.Is.is(matcher); } /** - * This is a shortcut to the frequently used is(equalTo(x)). - * - * eg. assertThat(cheese, is(equalTo(smelly))) - * vs assertThat(cheese, is(smelly)) + * A shortcut to the frequently used is(equalTo(x)). + * For example: + *
assertThat(cheese, is(smelly))
+ * instead of: + *
assertThat(cheese, is(equalTo(smelly)))
*/ public static org.hamcrest.Matcher is(T value) { return org.hamcrest.core.Is.is(value); } /** - * Provided to cause compile time error when used in preference to a possible runtime error if - * this was not here. - * - *

This method was removed upstream between Hamcrest 1.1 and 1.3 in favour of the - * instanceOf(Class) method. Unfortunately, existing usages of it could still compile against the - * {@link #is(Object)} method instead. Although not every existing usage would compile - * successfully it is possible that some could and that would result in a change in the runtime - * behavior that could be difficult to detect and fix. This change aims to turn any significant - * usage of this method into a compile time error. - * - * @deprecated Use instanceOf(SomeClass.class) instead. + * A shortcut to the frequently used is(instanceOf(SomeClass.class)). + * For example: + *

assertThat(cheese, isA(Cheddar.class))
+ * instead of: + *
assertThat(cheese, is(instanceOf(Cheddar.class)))
*/ - public static void is(java.lang.Class type) { + public static org.hamcrest.Matcher isA(java.lang.Class type) { + return org.hamcrest.core.Is.isA(type); } /** - * Inverts the rule. + * Creates a matcher that always matches, regardless of the examined object. */ - public static org.hamcrest.Matcher not(org.hamcrest.Matcher matcher) { - return org.hamcrest.core.IsNot.not(matcher); + public static org.hamcrest.Matcher anything() { + return org.hamcrest.core.IsAnything.anything(); } /** - * This is a shortcut to the frequently used not(equalTo(x)). + * Creates a matcher that always matches, regardless of the examined object, but describes + * itself with the specified {@link String}. * - * eg. assertThat(cheese, is(not(equalTo(smelly)))) - * vs assertThat(cheese, is(not(smelly))) + * @param description + * a meaningful {@link String} used when describing itself */ - public static org.hamcrest.Matcher not(T value) { - return org.hamcrest.core.IsNot.not(value); + public static org.hamcrest.Matcher anything(java.lang.String description) { + return org.hamcrest.core.IsAnything.anything(description); } /** - * Is the value equal to another value, as tested by the - * {@link java.lang.Object#equals} invokedMethod? + * Creates a matcher for {@link Iterable}s that only matches when a single pass over the + * examined {@link Iterable} yields at least one item that is matched by the specified + * itemMatcher. Whilst matching, the traversal of the examined {@link Iterable} + * will stop as soon as a matching item is found. + * For example: + *
assertThat(Arrays.asList("foo", "bar"), hasItem(startsWith("ba")))
+ * + * @param itemMatcher + * the matcher to apply to items provided by the examined {@link Iterable} */ - public static org.hamcrest.Matcher equalTo(T operand) { - return org.hamcrest.core.IsEqual.equalTo(operand); + public static org.hamcrest.Matcher> hasItem(org.hamcrest.Matcher itemMatcher) { + return org.hamcrest.core.IsCollectionContaining.hasItem(itemMatcher); } /** - * Is the value an instance of a particular type? + * Creates a matcher for {@link Iterable}s that only matches when a single pass over the + * examined {@link Iterable} yields at least one item that is equal to the specified + * item. Whilst matching, the traversal of the examined {@link Iterable} + * will stop as soon as a matching item is found. + * For example: + *
assertThat(Arrays.asList("foo", "bar"), hasItem("bar"))
+ * + * @param item + * the item to compare against the items provided by the examined {@link Iterable} */ - public static org.hamcrest.Matcher instanceOf(java.lang.Class type) { - return org.hamcrest.core.IsInstanceOf.instanceOf(type); + public static org.hamcrest.Matcher> hasItem(T item) { + return org.hamcrest.core.IsCollectionContaining.hasItem(item); } /** - * Evaluates to true only if ALL of the passed in matchers evaluate to true. + * Creates a matcher for {@link Iterable}s that matches when consecutive passes over the + * examined {@link Iterable} yield at least one item that is matched by the corresponding + * matcher from the specified itemMatchers. Whilst matching, each traversal of + * the examined {@link Iterable} will stop as soon as a matching item is found. + * For example: + *
assertThat(Arrays.asList("foo", "bar", "baz"), hasItems(endsWith("z"), endsWith("o")))
+ * + * @param itemMatchers + * the matchers to apply to items provided by the examined {@link Iterable} */ - public static org.hamcrest.Matcher allOf(org.hamcrest.Matcher... matchers) { - return org.hamcrest.core.AllOf.allOf(matchers); + @SafeVarargs + public static org.hamcrest.Matcher> hasItems(org.hamcrest.Matcher... itemMatchers) { + return org.hamcrest.core.IsCollectionContaining.hasItems(itemMatchers); } /** - * Evaluates to true only if ALL of the passed in matchers evaluate to true. + * Creates a matcher for {@link Iterable}s that matches when consecutive passes over the + * examined {@link Iterable} yield at least one item that is equal to the corresponding + * item from the specified items. Whilst matching, each traversal of the + * examined {@link Iterable} will stop as soon as a matching item is found. + * For example: + *
assertThat(Arrays.asList("foo", "bar", "baz"), hasItems("baz", "foo"))
+ * + * @param items + * the items to compare against the items provided by the examined {@link Iterable} */ - public static org.hamcrest.Matcher allOf(java.lang.Iterable> matchers) { - return org.hamcrest.core.AllOf.allOf(matchers); + @SafeVarargs + public static org.hamcrest.Matcher> hasItems(T... items) { + return org.hamcrest.core.IsCollectionContaining.hasItems(items); } /** - * Evaluates to true if ANY of the passed in matchers evaluate to true. + * Creates a matcher that matches when the examined object is logically equal to the specified + * operand, as determined by calling the {@link java.lang.Object#equals} method on + * the examined object. + * + *

If the specified operand is null then the created matcher will only match if + * the examined object's equals method returns true when passed a + * null (which would be a violation of the equals contract), unless the + * examined object itself is null, in which case the matcher will return a positive + * match.

+ * + *

The created matcher provides a special behaviour when examining Arrays, whereby + * it will match if both the operand and the examined object are arrays of the same length and + * contain items that are equal to each other (according to the above rules) in the same + * indexes.

+ * For example: + *
+   * assertThat("foo", equalTo("foo"));
+   * assertThat(new String[] {"foo", "bar"}, equalTo(new String[] {"foo", "bar"}));
+   * 
*/ - public static org.hamcrest.Matcher anyOf(org.hamcrest.Matcher... matchers) { - return org.hamcrest.core.AnyOf.anyOf(matchers); + public static org.hamcrest.Matcher equalTo(T operand) { + return org.hamcrest.core.IsEqual.equalTo(operand); } /** - * Evaluates to true if ANY of the passed in matchers evaluate to true. + * Creates an {@link org.hamcrest.core.IsEqual} matcher that does not enforce the values being + * compared to be of the same static type. */ - public static org.hamcrest.Matcher anyOf(java.lang.Iterable> matchers) { - return org.hamcrest.core.AnyOf.anyOf(matchers); + public static org.hamcrest.Matcher equalToObject(java.lang.Object operand) { + return org.hamcrest.core.IsEqual.equalToObject(operand); } /** - * Creates a new instance of IsSame + * Creates a matcher that matches when the examined object is an instance of the specified type, + * as determined by calling the {@link java.lang.Class#isInstance(Object)} method on that type, passing the + * the examined object. * - * @param object The predicate evaluates to true only when the argument is - * this object. + *

The created matcher forces a relationship between specified type and the examined object, and should be + * used when it is necessary to make generics conform, for example in the JMock clause + * with(any(Thing.class))

+ * For example: + *
assertThat(new Canoe(), instanceOf(Canoe.class));
*/ - public static org.hamcrest.Matcher sameInstance(T object) { - return org.hamcrest.core.IsSame.sameInstance(object); + public static org.hamcrest.Matcher any(java.lang.Class type) { + return org.hamcrest.core.IsInstanceOf.any(type); } /** - * This matcher always evaluates to true. + * Creates a matcher that matches when the examined object is an instance of the specified type, + * as determined by calling the {@link java.lang.Class#isInstance(Object)} method on that type, passing the + * the examined object. + * + *

The created matcher assumes no relationship between specified type and the examined object.

+ * For example: + *
assertThat(new Canoe(), instanceOf(Paddlable.class));
*/ - public static org.hamcrest.Matcher anything() { - return org.hamcrest.core.IsAnything.anything(); + public static org.hamcrest.Matcher instanceOf(java.lang.Class type) { + return org.hamcrest.core.IsInstanceOf.instanceOf(type); } /** - * This matcher always evaluates to true. + * Creates a matcher that wraps an existing matcher, but inverts the logic by which + * it will match. + * For example: + *
assertThat(cheese, is(not(equalTo(smelly))))
* - * @param description A meaningful string used when describing itself. + * @param matcher + * the matcher whose sense should be inverted */ - public static org.hamcrest.Matcher anything(java.lang.String description) { - return org.hamcrest.core.IsAnything.anything(description); + public static org.hamcrest.Matcher not(org.hamcrest.Matcher matcher) { + return org.hamcrest.core.IsNot.not(matcher); } /** - * This matcher always evaluates to true. With type inference. + * A shortcut to the frequently used not(equalTo(x)). + * For example: + *
assertThat(cheese, is(not(smelly)))
+ * instead of: + *
assertThat(cheese, is(not(equalTo(smelly))))
+ * + * @param value + * the value that any examined object should not equal */ - public static org.hamcrest.Matcher any(java.lang.Class type) { - return org.hamcrest.core.IsAnything.any(type); + public static org.hamcrest.Matcher not(T value) { + return org.hamcrest.core.IsNot.not(value); + } + + /** + * A shortcut to the frequently used not(nullValue()). + * For example: + *
assertThat(cheese, is(notNullValue()))
+ * instead of: + *
assertThat(cheese, is(not(nullValue())))
+ */ + public static org.hamcrest.Matcher notNullValue() { + return org.hamcrest.core.IsNull.notNullValue(); } /** - * Matches if value is null. + * A shortcut to the frequently used not(nullValue(X.class)). Accepts a + * single dummy argument to facilitate type inference.. + * For example: + *
assertThat(cheese, is(notNullValue(X.class)))
+ * instead of: + *
assertThat(cheese, is(not(nullValue(X.class))))
+ * + * @param type + * dummy parameter used to infer the generic type of the returned matcher */ - public static org.hamcrest.Matcher nullValue() { + public static org.hamcrest.Matcher notNullValue(java.lang.Class type) { + return org.hamcrest.core.IsNull.notNullValue(type); + } + + /** + * Creates a matcher that matches if examined object is null. + * For example: + *
assertThat(cheese, is(nullValue())
+ */ + public static org.hamcrest.Matcher nullValue() { return org.hamcrest.core.IsNull.nullValue(); } /** - * Matches if value is null. With type inference. + * Creates a matcher that matches if examined object is null. Accepts a + * single dummy argument to facilitate type inference. + * For example: + *
assertThat(cheese, is(nullValue(Cheese.class))
+ * + * @param type + * dummy parameter used to infer the generic type of the returned matcher */ public static org.hamcrest.Matcher nullValue(java.lang.Class type) { return org.hamcrest.core.IsNull.nullValue(type); } /** - * Matches if value is not null. + * Creates a matcher that matches only when the examined object is the same instance as + * the specified target object. + * + * @param target + * the target instance against which others should be assessed */ - public static org.hamcrest.Matcher notNullValue() { - return org.hamcrest.core.IsNull.notNullValue(); + public static org.hamcrest.Matcher sameInstance(T target) { + return org.hamcrest.core.IsSame.sameInstance(target); } /** - * Matches if value is not null. With type inference. + * Creates a matcher that matches only when the examined object is the same instance as + * the specified target object. + * + * @param target + * the target instance against which others should be assessed */ - public static org.hamcrest.Matcher notNullValue(java.lang.Class type) { - return org.hamcrest.core.IsNull.notNullValue(type); + public static org.hamcrest.Matcher theInstance(T target) { + return org.hamcrest.core.IsSame.theInstance(target); } /** - * Wraps an existing matcher and overrides the description when it fails. + * Creates a matcher that matches if the examined {@link String} contains the specified + * {@link String} anywhere. + * For example: + *
assertThat("myStringOfNote", containsString("ring"))
+ * + * @param substring + * the substring that the returned matcher will expect to find within any examined string */ - public static org.hamcrest.Matcher describedAs(java.lang.String description, org.hamcrest.Matcher matcher, java.lang.Object... values) { - return org.hamcrest.core.DescribedAs.describedAs(description, matcher, values); + public static org.hamcrest.Matcher containsString(java.lang.String substring) { + return org.hamcrest.core.StringContains.containsString(substring); + } + + /** + * Creates a matcher that matches if the examined {@link String} contains the specified + * {@link String} anywhere, ignoring case. + * For example: + *
assertThat("myStringOfNote", containsString("ring"))
+ * + * @param substring + * the substring that the returned matcher will expect to find within any examined string + */ + public static org.hamcrest.Matcher containsStringIgnoringCase(java.lang.String substring) { + return org.hamcrest.core.StringContains.containsStringIgnoringCase(substring); + } + + /** + *

+ * Creates a matcher that matches if the examined {@link String} starts with the specified + * {@link String}. + *

+ * For example: + *
assertThat("myStringOfNote", startsWith("my"))
+ * + * @param prefix + * the substring that the returned matcher will expect at the start of any examined string + */ + public static org.hamcrest.Matcher startsWith(java.lang.String prefix) { + return org.hamcrest.core.StringStartsWith.startsWith(prefix); + } + + /** + *

+ * Creates a matcher that matches if the examined {@link String} starts with the specified + * {@link String}, ignoring case + *

+ * For example: + *
assertThat("myStringOfNote", startsWith("my"))
+ * + * @param prefix + * the substring that the returned matcher will expect at the start of any examined string + */ + public static org.hamcrest.Matcher startsWithIgnoringCase(java.lang.String prefix) { + return org.hamcrest.core.StringStartsWith.startsWithIgnoringCase(prefix); + } + + /** + * Creates a matcher that matches if the examined {@link String} ends with the specified + * {@link String}. + * For example: + *
assertThat("myStringOfNote", endsWith("Note"))
+ * + * @param suffix + * the substring that the returned matcher will expect at the end of any examined string + */ + public static org.hamcrest.Matcher endsWith(java.lang.String suffix) { + return org.hamcrest.core.StringEndsWith.endsWith(suffix); + } + + /** + * Creates a matcher that matches if the examined {@link String} ends with the specified + * {@link String}, ignoring case. + * For example: + *
assertThat("myStringOfNote", endsWith("Note"))
+ * + * @param suffix + * the substring that the returned matcher will expect at the end of any examined string + */ + public static org.hamcrest.Matcher endsWithIgnoringCase(java.lang.String suffix) { + return org.hamcrest.core.StringEndsWith.endsWithIgnoringCase(suffix); } } diff --git a/hamcrest-core/src/main/java/org/hamcrest/CustomMatcher.java b/hamcrest-core/src/main/java/org/hamcrest/CustomMatcher.java new file mode 100644 index 0000000..036a764 --- /dev/null +++ b/hamcrest-core/src/main/java/org/hamcrest/CustomMatcher.java @@ -0,0 +1,37 @@ +package org.hamcrest; + +/** + * Utility class for writing one off matchers. + * For example: + *
+ * Matcher<String> aNonEmptyString = new CustomMatcher<String>("a non empty string") {
+ *   public boolean matches(Object object) {
+ *     return ((object instanceof String) && !((String) object).isEmpty();
+ *   }
+ * };
+ * 
+ *

+ * This class is designed for scenarios where an anonymous inner class + * matcher makes sense. It should not be used by API designers implementing + * matchers. + * + * @author Neil Dunn + * @see CustomTypeSafeMatcher for a type safe variant of this class that you probably + * want to use. + * @param The type of object being matched. + */ +public abstract class CustomMatcher extends BaseMatcher { + private final String fixedDescription; + + public CustomMatcher(String description) { + if (description == null) { + throw new IllegalArgumentException("Description should be non null!"); + } + this.fixedDescription = description; + } + + @Override + public final void describeTo(Description description) { + description.appendText(fixedDescription); + } +} diff --git a/hamcrest-core/src/main/java/org/hamcrest/CustomTypeSafeMatcher.java b/hamcrest-core/src/main/java/org/hamcrest/CustomTypeSafeMatcher.java new file mode 100644 index 0000000..7c5c46c --- /dev/null +++ b/hamcrest-core/src/main/java/org/hamcrest/CustomTypeSafeMatcher.java @@ -0,0 +1,39 @@ +package org.hamcrest; + + +/** + * Utility class for writing one off matchers. + * For example: + *

+ * Matcher<String> aNonEmptyString = new CustomTypeSafeMatcher<String>("a non empty string") {
+ *   public boolean matchesSafely(String string) {
+ *     return !string.isEmpty();
+ *   }
+ *   public void describeMismatchSafely(String string, Description mismatchDescription) {
+ *     mismatchDescription.appendText("was empty");
+ *   }
+ * };
+ * 
+ * This is a variant of {@link CustomMatcher} that first type checks + * the argument being matched. By the time {@link TypeSafeMatcher#matchesSafely} is + * is called the argument is guaranteed to be non-null and of the correct + * type. + * + * @author Neil Dunn + * @param The type of object being matched + */ +public abstract class CustomTypeSafeMatcher extends TypeSafeMatcher { + private final String fixedDescription; + + public CustomTypeSafeMatcher(String description) { + if (description == null) { + throw new IllegalArgumentException("Description must be non null!"); + } + this.fixedDescription = description; + } + + @Override + public final void describeTo(Description description) { + description.appendText(fixedDescription); + } +} diff --git a/hamcrest-core/src/main/java/org/hamcrest/Description.java b/hamcrest-core/src/main/java/org/hamcrest/Description.java index 36ddeda..73bfa38 100644 --- a/hamcrest-core/src/main/java/org/hamcrest/Description.java +++ b/hamcrest-core/src/main/java/org/hamcrest/Description.java @@ -1,44 +1,89 @@ -package org.hamcrest; - -/** - * A description of a Matcher. A Matcher will describe itself to a description - * which can later be used for reporting. - * - * @see Matcher#describeTo(Description) - */ -public interface Description { - - /** - * Appends some plain text to the description. - */ - Description appendText(String text); - - /** - * Appends the description of a {@link SelfDescribing} value to this description. - */ - Description appendDescriptionOf(SelfDescribing value); - - /** - * Appends an arbitary value to the description. - */ - Description appendValue(Object value); - - /** - * Appends a list of values to the description. - */ - Description appendValueList(String start, String separator, String end, - T... values); - - /** - * Appends a list of values to the description. - */ - Description appendValueList(String start, String separator, String end, - Iterable values); - - /** - * Appends a list of {@link org.hamcrest.SelfDescribing} objects - * to the description. - */ - Description appendList(String start, String separator, String end, - Iterable values); -} +package org.hamcrest; + +/** + * A description of a Matcher. A Matcher will describe itself to a description + * which can later be used for reporting. + * + * @see Matcher#describeTo(Description) + */ +public interface Description { + /** + * A description that consumes input but does nothing. + */ + static final Description NONE = new NullDescription(); + + /** + * Appends some plain text to the description. + */ + Description appendText(String text); + + /** + * Appends the description of a {@link SelfDescribing} value to this description. + */ + Description appendDescriptionOf(SelfDescribing value); + + /** + * Appends an arbitrary value to the description. + */ + Description appendValue(Object value); + + /** + * Appends a list of values to the description. + */ + Description appendValueList(String start, String separator, String end, + T... values); + + /** + * Appends a list of values to the description. + */ + Description appendValueList(String start, String separator, String end, + Iterable values); + + /** + * Appends a list of {@link org.hamcrest.SelfDescribing} objects + * to the description. + */ + Description appendList(String start, String separator, String end, + Iterable values); + + + public static final class NullDescription implements Description { + @Override + public Description appendDescriptionOf(SelfDescribing value) { + return this; + } + + @Override + public Description appendList(String start, String separator, + String end, Iterable values) { + return this; + } + + @Override + public Description appendText(String text) { + return this; + } + + @Override + public Description appendValue(Object value) { + return this; + } + + @Override + public Description appendValueList(String start, String separator, + String end, T... values) { + return this; + } + + @Override + public Description appendValueList(String start, String separator, + String end, Iterable values) { + return this; + } + + @Override + public String toString() { + return ""; + } + } +} diff --git a/hamcrest-core/src/main/java/org/hamcrest/DiagnosingMatcher.java b/hamcrest-core/src/main/java/org/hamcrest/DiagnosingMatcher.java new file mode 100644 index 0000000..f87de2d --- /dev/null +++ b/hamcrest-core/src/main/java/org/hamcrest/DiagnosingMatcher.java @@ -0,0 +1,21 @@ +package org.hamcrest; + +/** + * TODO(ngd): Document. + * + * @param + */ +public abstract class DiagnosingMatcher extends BaseMatcher { + + @Override + public final boolean matches(Object item) { + return matches(item, Description.NONE); + } + + @Override + public final void describeMismatch(Object item, Description mismatchDescription) { + matches(item, mismatchDescription); + } + + protected abstract boolean matches(Object item, Description mismatchDescription); +} diff --git a/hamcrest-core/src/main/java/org/hamcrest/Factory.java b/hamcrest-core/src/main/java/org/hamcrest/Factory.java deleted file mode 100644 index a8bf5f9..0000000 --- a/hamcrest-core/src/main/java/org/hamcrest/Factory.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.hamcrest; - -import static java.lang.annotation.ElementType.METHOD; -import java.lang.annotation.Retention; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import java.lang.annotation.Target; - -/** - * Marks a Hamcrest static factory method so tools recognise them. - * A factory method is an equivalent to a named constructor. - * - * @author Joe Walnes - */ -@Retention(RUNTIME) -@Target({METHOD}) -public @interface Factory { -} diff --git a/hamcrest-core/src/main/java/org/hamcrest/FeatureMatcher.java b/hamcrest-core/src/main/java/org/hamcrest/FeatureMatcher.java new file mode 100644 index 0000000..385cf99 --- /dev/null +++ b/hamcrest-core/src/main/java/org/hamcrest/FeatureMatcher.java @@ -0,0 +1,54 @@ +package org.hamcrest; + +import org.hamcrest.internal.ReflectiveTypeFinder; + +/** + * Supporting class for matching a feature of an object. Implement featureValueOf() + * in a subclass to pull out the feature to be matched against. + * + * @param The type of the object to be matched + * @param The type of the feature to be matched + */ +public abstract class FeatureMatcher extends TypeSafeDiagnosingMatcher { + private static final ReflectiveTypeFinder TYPE_FINDER = new ReflectiveTypeFinder("featureValueOf", 1, 0); + private final Matcher subMatcher; + private final String featureDescription; + private final String featureName; + + /** + * Constructor + * @param subMatcher The matcher to apply to the feature + * @param featureDescription Descriptive text to use in describeTo + * @param featureName Identifying text for mismatch message + */ + public FeatureMatcher(Matcher subMatcher, String featureDescription, String featureName) { + super(TYPE_FINDER); + this.subMatcher = subMatcher; + this.featureDescription = featureDescription; + this.featureName = featureName; + } + + /** + * Implement this to extract the interesting feature. + * @param actual the target object + * @return the feature to be matched + */ + protected abstract U featureValueOf(T actual); + + @Override + protected boolean matchesSafely(T actual, Description mismatch) { + final U featureValue = featureValueOf(actual); + if (!subMatcher.matches(featureValue)) { + mismatch.appendText(featureName).appendText(" "); + subMatcher.describeMismatch(featureValue, mismatch); + return false; + } + return true; + } + + @Override + public final void describeTo(Description description) { + description.appendText(featureDescription).appendText(" ") + .appendDescriptionOf(subMatcher); + } +} diff --git a/hamcrest-core/src/main/java/org/hamcrest/Matcher.java b/hamcrest-core/src/main/java/org/hamcrest/Matcher.java index fd10207..3ac1a53 100644 --- a/hamcrest-core/src/main/java/org/hamcrest/Matcher.java +++ b/hamcrest-core/src/main/java/org/hamcrest/Matcher.java @@ -1,32 +1,31 @@ -/* Copyright (c) 2000-2006 hamcrest.org - */ package org.hamcrest; /** + *

* A matcher over acceptable values. * A matcher is able to describe itself to give feedback when it fails. - *

+ *

+ *

* Matcher implementations should NOT directly implement this interface. * Instead, extend the {@link BaseMatcher} abstract class, * which will ensure that the Matcher API can grow to support * new features and remain compatible with all Matcher implementations. - *

- * For easy access to common Matcher implementations, use the static factory - * methods in {@link CoreMatchers}. + *

+ *

+ * N.B. Well designed matchers should be immutable. + *

* - * @see CoreMatchers * @see BaseMatcher */ -@SuppressWarnings({"unused", "UnusedDeclaration"}) public interface Matcher extends SelfDescribing { /** * Evaluates the matcher for argument item. - *

+ * * This method matches against Object, instead of the generic type T. This is * because the caller of the Matcher does not know at runtime what the type is * (because of type erasure with Java generics). It is down to the implementations - * to check the correct type. + * to check the correct type. * * @param item the object against which the matcher is evaluated. * @return true if item matches, otherwise false. @@ -34,6 +33,19 @@ public interface Matcher extends SelfDescribing { * @see BaseMatcher */ boolean matches(Object item); + + /** + * Generate a description of why the matcher has not accepted the item. + * The description will be part of a larger description of why a matching + * failed, so it should be concise. + * This method assumes that matches(item) is false, but + * will not check this. + * + * @param item The item that the Matcher has rejected. + * @param mismatchDescription + * The description to be built or appended to. + */ + void describeMismatch(Object item, Description mismatchDescription); /** * This method simply acts a friendly reminder not to implement Matcher directly and @@ -42,6 +54,8 @@ public interface Matcher extends SelfDescribing { * * @see Matcher for reasons why. * @see BaseMatcher + * @deprecated to make */ + @Deprecated void _dont_implement_Matcher___instead_extend_BaseMatcher_(); } diff --git a/hamcrest-core/src/main/java/org/hamcrest/MatcherAssert.java b/hamcrest-core/src/main/java/org/hamcrest/MatcherAssert.java index 3eb234a..049e1df 100644 --- a/hamcrest-core/src/main/java/org/hamcrest/MatcherAssert.java +++ b/hamcrest-core/src/main/java/org/hamcrest/MatcherAssert.java @@ -1,24 +1,27 @@ -/* Copyright (c) 2000-2006 hamcrest.org - */ -package org.hamcrest; - - -public class MatcherAssert { - public static void assertThat(T actual, Matcher matcher) { - assertThat("", actual, matcher); - } - - public static void assertThat(String reason, T actual, Matcher matcher) { - if (!matcher.matches(actual)) { - Description description = new StringDescription(); - description.appendText(reason) - .appendText("\nExpected: ") - .appendDescriptionOf(matcher) - .appendText("\n got: ") - .appendValue(actual) - .appendText("\n"); - - throw new java.lang.AssertionError(description.toString()); - } - } -} +package org.hamcrest; + + +public class MatcherAssert { + public static void assertThat(T actual, Matcher matcher) { + assertThat("", actual, matcher); + } + + public static void assertThat(String reason, T actual, Matcher matcher) { + if (!matcher.matches(actual)) { + Description description = new StringDescription(); + description.appendText(reason) + .appendText("\nExpected: ") + .appendDescriptionOf(matcher) + .appendText("\n but: "); + matcher.describeMismatch(actual, description); + + throw new AssertionError(description.toString()); + } + } + + public static void assertThat(String reason, boolean assertion) { + if (!assertion) { + throw new AssertionError(reason); + } + } +} diff --git a/hamcrest-core/src/main/java/org/hamcrest/SelfDescribing.java b/hamcrest-core/src/main/java/org/hamcrest/SelfDescribing.java index cd53070..06b361d 100644 --- a/hamcrest-core/src/main/java/org/hamcrest/SelfDescribing.java +++ b/hamcrest-core/src/main/java/org/hamcrest/SelfDescribing.java @@ -12,5 +12,5 @@ public interface SelfDescribing { * @param description * The description to be built or appended to. */ - void describeTo(Description description); + void describeTo(Description description); } \ No newline at end of file diff --git a/hamcrest-core/src/main/java/org/hamcrest/StringDescription.java b/hamcrest-core/src/main/java/org/hamcrest/StringDescription.java index 66709ee..813c178 100644 --- a/hamcrest-core/src/main/java/org/hamcrest/StringDescription.java +++ b/hamcrest-core/src/main/java/org/hamcrest/StringDescription.java @@ -1,60 +1,63 @@ -package org.hamcrest; - -import java.io.IOException; - -/** - * A {@link Description} that is stored as a string. - */ -public class StringDescription extends BaseDescription { - private final Appendable out; - - public StringDescription() { - this(new StringBuilder()); - } - - public StringDescription(Appendable out) { - this.out = out; - } - - /** - * Return the description of a {@link SelfDescribing} object as a String. - * - * @param selfDescribing - * The object to be described. - * @return - * The description of the object. - */ - public static String toString(SelfDescribing value) { - return new StringDescription().appendDescriptionOf(value).toString(); - } - - /** - * Alias for {@link #toString(SelfDescribing)}. - */ - public static String asString(SelfDescribing selfDescribing) { - return toString(selfDescribing); - } - - protected void append(String str) { - try { - out.append(str); - } catch (IOException e) { - throw new RuntimeException("Could not write description", e); - } - } - - protected void append(char c) { - try { - out.append(c); - } catch (IOException e) { - throw new RuntimeException("Could not write description", e); - } - } - - /** - * Returns the description as a string. - */ - public String toString() { - return out.toString(); - } -} +package org.hamcrest; + +import java.io.IOException; + +/** + * A {@link Description} that is stored as a string. + */ +public class StringDescription extends BaseDescription { + private final Appendable out; + + public StringDescription() { + this(new StringBuilder()); + } + + public StringDescription(Appendable out) { + this.out = out; + } + + /** + * Return the description of a {@link SelfDescribing} object as a String. + * + * @param selfDescribing + * The object to be described. + * @return + * The description of the object. + */ + public static String toString(SelfDescribing selfDescribing) { + return new StringDescription().appendDescriptionOf(selfDescribing).toString(); + } + + /** + * Alias for {@link #toString(SelfDescribing)}. + */ + public static String asString(SelfDescribing selfDescribing) { + return toString(selfDescribing); + } + + @Override + protected void append(String str) { + try { + out.append(str); + } catch (IOException e) { + throw new RuntimeException("Could not write description", e); + } + } + + @Override + protected void append(char c) { + try { + out.append(c); + } catch (IOException e) { + throw new RuntimeException("Could not write description", e); + } + } + + /** + * Returns the description as a string. + */ + @Override + public String toString() { + return out.toString(); + } +} diff --git a/hamcrest-core/src/main/java/org/hamcrest/TypeSafeDiagnosingMatcher.java b/hamcrest-core/src/main/java/org/hamcrest/TypeSafeDiagnosingMatcher.java new file mode 100644 index 0000000..c204120 --- /dev/null +++ b/hamcrest-core/src/main/java/org/hamcrest/TypeSafeDiagnosingMatcher.java @@ -0,0 +1,69 @@ +package org.hamcrest; + +import org.hamcrest.internal.ReflectiveTypeFinder; + + +/** + * Convenient base class for Matchers that require a non-null value of a specific type + * and that will report why the received value has been rejected. + * This implements the null check, checks the type and then casts. + * To use, implement

matchesSafely()
. + * + * @param + * @author Neil Dunn + * @author Nat Pryce + * @author Steve Freeman + */ +public abstract class TypeSafeDiagnosingMatcher extends BaseMatcher { + private static final ReflectiveTypeFinder TYPE_FINDER = new ReflectiveTypeFinder("matchesSafely", 2, 0); + private final Class expectedType; + + /** + * Subclasses should implement this. The item will already have been checked + * for the specific type and will never be null. + */ + protected abstract boolean matchesSafely(T item, Description mismatchDescription); + + /** + * Use this constructor if the subclass that implements matchesSafely + * is not the class that binds <T> to a type. + * @param expectedType The expectedType of the actual value. + */ + protected TypeSafeDiagnosingMatcher(Class expectedType) { + this.expectedType = expectedType; + } + + /** + * Use this constructor if the subclass that implements matchesSafely + * is not the class that binds <T> to a type. + * @param typeFinder A type finder to extract the type + */ + protected TypeSafeDiagnosingMatcher(ReflectiveTypeFinder typeFinder) { + this.expectedType = typeFinder.findExpectedType(getClass()); + } + + /** + * The default constructor for simple sub types + */ + protected TypeSafeDiagnosingMatcher() { + this(TYPE_FINDER); + } + + @Override + @SuppressWarnings("unchecked") + public final boolean matches(Object item) { + return item != null + && expectedType.isInstance(item) + && matchesSafely((T) item, new Description.NullDescription()); + } + + @SuppressWarnings("unchecked") + @Override + public final void describeMismatch(Object item, Description mismatchDescription) { + if (item == null || !expectedType.isInstance(item)) { + super.describeMismatch(item, mismatchDescription); + } else { + matchesSafely((T) item, mismatchDescription); + } + } +} diff --git a/hamcrest-core/src/main/java/org/hamcrest/TypeSafeMatcher.java b/hamcrest-core/src/main/java/org/hamcrest/TypeSafeMatcher.java index 7f18fd3..08dfce8 100644 --- a/hamcrest-core/src/main/java/org/hamcrest/TypeSafeMatcher.java +++ b/hamcrest-core/src/main/java/org/hamcrest/TypeSafeMatcher.java @@ -1,58 +1,85 @@ package org.hamcrest; -import java.lang.reflect.Method; +import org.hamcrest.internal.ReflectiveTypeFinder; /** * Convenient base class for Matchers that require a non-null value of a specific type. * This simply implements the null check, checks the type and then casts. * * @author Joe Walnes + * @author Steve Freeman + * @author Nat Pryce */ public abstract class TypeSafeMatcher extends BaseMatcher { - - private Class expectedType; + private static final ReflectiveTypeFinder TYPE_FINDER = new ReflectiveTypeFinder("matchesSafely", 1, 0); + + final private Class expectedType; /** - * Subclasses should implement this. The item will already have been checked for - * the specific type and will never be null. + * The default constructor for simple sub types */ - public abstract boolean matchesSafely(T item); - protected TypeSafeMatcher() { - expectedType = findExpectedType(getClass()); + this(TYPE_FINDER); } - - private static Class findExpectedType(Class fromClass) { - for (Class c = fromClass; c != Object.class; c = c.getSuperclass()) { - for (Method method : c.getDeclaredMethods()) { - if (isMatchesSafelyMethod(method)) { - return method.getParameterTypes()[0]; - } - } - } - - throw new Error("Cannot determine correct type for matchesSafely() method."); + + /** + * Use this constructor if the subclass that implements matchesSafely + * is not the class that binds <T> to a type. + * @param expectedType The expectedType of the actual value. + */ + protected TypeSafeMatcher(Class expectedType) { + this.expectedType = expectedType; } - private static boolean isMatchesSafelyMethod(Method method) { - return method.getName().equals("matchesSafely") - && method.getParameterTypes().length == 1 - && !method.isSynthetic(); + /** + * Use this constructor if the subclass that implements matchesSafely + * is not the class that binds <T> to a type. + * @param typeFinder A type finder to extract the type + */ + protected TypeSafeMatcher(ReflectiveTypeFinder typeFinder) { + this.expectedType = typeFinder.findExpectedType(getClass()); } + + /** + * Subclasses should implement this. The item will already have been checked for + * the specific type and will never be null. + */ + protected abstract boolean matchesSafely(T item); - protected TypeSafeMatcher(Class expectedType) { - this.expectedType = expectedType; + /** + * Subclasses should override this. The item will already have been checked for + * the specific type and will never be null. + */ + protected void describeMismatchSafely(T item, Description mismatchDescription) { + super.describeMismatch(item, mismatchDescription); } - + /** - * Method made final to prevent accidental override. + * Methods made final to prevent accidental override. * If you need to override this, there's no point on extending TypeSafeMatcher. * Instead, extend the {@link BaseMatcher}. */ + @Override @SuppressWarnings({"unchecked"}) public final boolean matches(Object item) { return item != null && expectedType.isInstance(item) && matchesSafely((T) item); } + + @SuppressWarnings("unchecked") + @Override + final public void describeMismatch(Object item, Description description) { + if (item == null) { + super.describeMismatch(null, description); + } else if (! expectedType.isInstance(item)) { + description.appendText("was a ") + .appendText(item.getClass().getName()) + .appendText(" (") + .appendValue(item) + .appendText(")"); + } else { + describeMismatchSafely((T)item, description); + } + } } diff --git a/hamcrest-core/src/main/java/org/hamcrest/core/AllOf.java b/hamcrest-core/src/main/java/org/hamcrest/core/AllOf.java index f619a7d..06e999a 100644 --- a/hamcrest-core/src/main/java/org/hamcrest/core/AllOf.java +++ b/hamcrest-core/src/main/java/org/hamcrest/core/AllOf.java @@ -1,51 +1,56 @@ package org.hamcrest.core; -import org.hamcrest.BaseMatcher; -import org.hamcrest.Matcher; import org.hamcrest.Description; -import org.hamcrest.Factory; +import org.hamcrest.DiagnosingMatcher; +import org.hamcrest.Matcher; import java.util.Arrays; /** - * Calculates the logical conjunction of two matchers. Evaluation is - * shortcut, so that the second matcher is not called if the first - * matcher returns false. + * Calculates the logical conjunction of multiple matchers. Evaluation is shortcut, so + * subsequent matchers are not called if an earlier matcher returns false. */ -public class AllOf extends BaseMatcher { - private final Iterable> matchers; +public class AllOf extends DiagnosingMatcher { + + private final Iterable> matchers; - public AllOf(Iterable> matchers) { + public AllOf(Iterable> matchers) { this.matchers = matchers; } - public boolean matches(Object o) { - for (Matcher matcher : matchers) { + @Override + public boolean matches(Object o, Description mismatch) { + for (Matcher matcher : matchers) { if (!matcher.matches(o)) { - return false; + mismatch.appendDescriptionOf(matcher).appendText(" "); + matcher.describeMismatch(o, mismatch); + return false; } } return true; } + @Override public void describeTo(Description description) { - description.appendList("(", " and ", ")", matchers); + description.appendList("(", " " + "and" + " ", ")", matchers); } /** - * Evaluates to true only if ALL of the passed in matchers evaluate to true. + * Creates a matcher that matches if the examined object matches ALL of the specified matchers. + * For example: + *
assertThat("myValue", allOf(startsWith("my"), containsString("Val")))
*/ - @Factory - public static Matcher allOf(Matcher... matchers) { - return allOf(Arrays.asList(matchers)); + public static Matcher allOf(Iterable> matchers) { + return new AllOf<>(matchers); } /** - * Evaluates to true only if ALL of the passed in matchers evaluate to true. + * Creates a matcher that matches if the examined object matches ALL of the specified matchers. + * For example: + *
assertThat("myValue", allOf(startsWith("my"), containsString("Val")))
*/ - @Factory - public static Matcher allOf(Iterable> matchers) { - return new AllOf(matchers); + @SafeVarargs + public static Matcher allOf(Matcher... matchers) { + return allOf(Arrays.asList(matchers)); } - } diff --git a/hamcrest-core/src/main/java/org/hamcrest/core/AnyOf.java b/hamcrest-core/src/main/java/org/hamcrest/core/AnyOf.java index e7e9181..03cc210 100644 --- a/hamcrest-core/src/main/java/org/hamcrest/core/AnyOf.java +++ b/hamcrest-core/src/main/java/org/hamcrest/core/AnyOf.java @@ -1,51 +1,46 @@ package org.hamcrest.core; -import org.hamcrest.BaseMatcher; -import org.hamcrest.Matcher; import org.hamcrest.Description; -import org.hamcrest.Factory; +import org.hamcrest.Matcher; import java.util.Arrays; /** - * Calculates the logical disjunction of two matchers. Evaluation is - * shortcut, so that the second matcher is not called if the first - * matcher returns true. + * Calculates the logical disjunction of multiple matchers. Evaluation is shortcut, so + * subsequent matchers are not called if an earlier matcher returns true. */ -public class AnyOf extends BaseMatcher { - - private final Iterable> matchers; +public class AnyOf extends ShortcutCombination { - public AnyOf(Iterable> matchers) { - this.matchers = matchers; + public AnyOf(Iterable> matchers) { + super(matchers); } + @Override public boolean matches(Object o) { - for (Matcher matcher : matchers) { - if (matcher.matches(o)) { - return true; - } - } - return false; + return matches(o, true); } + @Override public void describeTo(Description description) { - description.appendList("(", " or ", ")", matchers); + describeTo(description, "or"); } /** - * Evaluates to true if ANY of the passed in matchers evaluate to true. + * Creates a matcher that matches if the examined object matches ANY of the specified matchers. + * For example: + *
assertThat("myValue", anyOf(startsWith("foo"), containsString("Val")))
*/ - @Factory - public static Matcher anyOf(Matcher... matchers) { - return anyOf(Arrays.asList(matchers)); + public static AnyOf anyOf(Iterable> matchers) { + return new AnyOf<>(matchers); } - + /** - * Evaluates to true if ANY of the passed in matchers evaluate to true. + * Creates a matcher that matches if the examined object matches ANY of the specified matchers. + * For example: + *
assertThat("myValue", anyOf(startsWith("foo"), containsString("Val")))
*/ - @Factory - public static Matcher anyOf(Iterable> matchers) { - return new AnyOf(matchers); + @SafeVarargs + public static AnyOf anyOf(Matcher... matchers) { + return anyOf(Arrays.asList(matchers)); } } diff --git a/hamcrest-core/src/main/java/org/hamcrest/core/CombinableMatcher.java b/hamcrest-core/src/main/java/org/hamcrest/core/CombinableMatcher.java new file mode 100644 index 0000000..2414bbb --- /dev/null +++ b/hamcrest-core/src/main/java/org/hamcrest/core/CombinableMatcher.java @@ -0,0 +1,82 @@ +package org.hamcrest.core; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeDiagnosingMatcher; + +import java.util.ArrayList; + +public class CombinableMatcher extends TypeSafeDiagnosingMatcher { + private final Matcher matcher; + + public CombinableMatcher(Matcher matcher) { + this.matcher = matcher; + } + + @Override + protected boolean matchesSafely(T item, Description mismatch) { + if (!matcher.matches(item)) { + matcher.describeMismatch(item, mismatch); + return false; + } + return true; + } + + @Override + public void describeTo(Description description) { + description.appendDescriptionOf(matcher); + } + + public CombinableMatcher and(Matcher other) { + return new CombinableMatcher(new AllOf(templatedListWith(other))); + } + + public CombinableMatcher or(Matcher other) { + return new CombinableMatcher(new AnyOf(templatedListWith(other))); + } + + private ArrayList> templatedListWith(Matcher other) { + ArrayList> matchers = new ArrayList>(); + matchers.add(matcher); + matchers.add(other); + return matchers; + } + + /** + * Creates a matcher that matches when both of the specified matchers match the examined object. + * For example: + *
assertThat("fab", both(containsString("a")).and(containsString("b")))
+ */ + public static CombinableBothMatcher both(Matcher matcher) { + return new CombinableBothMatcher(matcher); + } + + public static final class CombinableBothMatcher { + private final Matcher first; + public CombinableBothMatcher(Matcher matcher) { + this.first = matcher; + } + public CombinableMatcher and(Matcher other) { + return new CombinableMatcher(first).and(other); + } + } + + /** + * Creates a matcher that matches when either of the specified matchers match the examined object. + * For example: + *
assertThat("fan", either(containsString("a")).or(containsString("b")))
+ */ + public static CombinableEitherMatcher either(Matcher matcher) { + return new CombinableEitherMatcher(matcher); + } + + public static final class CombinableEitherMatcher { + private final Matcher first; + public CombinableEitherMatcher(Matcher matcher) { + this.first = matcher; + } + public CombinableMatcher or(Matcher other) { + return new CombinableMatcher(first).or(other); + } + } +} diff --git a/hamcrest-core/src/main/java/org/hamcrest/core/DescribedAs.java b/hamcrest-core/src/main/java/org/hamcrest/core/DescribedAs.java index 7b8c151..2387609 100644 --- a/hamcrest-core/src/main/java/org/hamcrest/core/DescribedAs.java +++ b/hamcrest-core/src/main/java/org/hamcrest/core/DescribedAs.java @@ -1,55 +1,69 @@ -/* Copyright (c) 2000-2006 hamcrest.org - */ -package org.hamcrest.core; - -import java.util.regex.Pattern; - -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.Factory; -import org.hamcrest.BaseMatcher; - -/** - * Provides a custom description to another matcher. - */ -public class DescribedAs extends BaseMatcher { - private final String descriptionTemplate; - private final Matcher matcher; - private final Object[] values; - - private final static Pattern ARG_PATTERN = Pattern.compile("%([0-9]+)"); - - public DescribedAs(String descriptionTemplate, Matcher matcher, Object[] values) { - this.descriptionTemplate = descriptionTemplate; - this.matcher = matcher; - this.values = values.clone(); - } - - public boolean matches(Object o) { - return matcher.matches(o); - } - - public void describeTo(Description description) { - java.util.regex.Matcher arg = ARG_PATTERN.matcher(descriptionTemplate); - - int textStart = 0; - while (arg.find()) { - description.appendText(descriptionTemplate.substring(textStart, arg.start())); - int argIndex = Integer.parseInt(arg.group(1)); - description.appendValue(values[argIndex]); - textStart = arg.end(); - } - - if (textStart < descriptionTemplate.length()) { - description.appendText(descriptionTemplate.substring(textStart)); - } - } - - /** - * Wraps an existing matcher and overrides the description when it fails. - */ - @Factory - public static Matcher describedAs(String description, Matcher matcher, Object... values) { - return new DescribedAs(description, matcher, values); - } -} +package org.hamcrest.core; + +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.hamcrest.Matcher; + +import java.util.regex.Pattern; + +import static java.lang.Integer.parseInt; + +/** + * Provides a custom description to another matcher. + */ +public class DescribedAs extends BaseMatcher { + private final String descriptionTemplate; + private final Matcher matcher; + private final Object[] values; + + private final static Pattern ARG_PATTERN = Pattern.compile("%([0-9]+)"); + + public DescribedAs(String descriptionTemplate, Matcher matcher, Object[] values) { + this.descriptionTemplate = descriptionTemplate; + this.matcher = matcher; + this.values = values.clone(); + } + + @Override + public boolean matches(Object o) { + return matcher.matches(o); + } + + @Override + public void describeTo(Description description) { + java.util.regex.Matcher arg = ARG_PATTERN.matcher(descriptionTemplate); + + int textStart = 0; + while (arg.find()) { + description.appendText(descriptionTemplate.substring(textStart, arg.start())); + description.appendValue(values[parseInt(arg.group(1))]); + textStart = arg.end(); + } + + if (textStart < descriptionTemplate.length()) { + description.appendText(descriptionTemplate.substring(textStart)); + } + } + + @Override + public void describeMismatch(Object item, Description description) { + matcher.describeMismatch(item, description); + } + + /** + * Wraps an existing matcher, overriding its description with that specified. All other functions are + * delegated to the decorated matcher, including its mismatch description. + * For example: + *
describedAs("a big decimal equal to %0", equalTo(myBigDecimal), myBigDecimal.toPlainString())
+ * + * @param description + * the new description for the wrapped matcher + * @param matcher + * the matcher to wrap + * @param values + * optional values to insert into the tokenised description + */ + public static Matcher describedAs(String description, Matcher matcher, Object... values) { + return new DescribedAs(description, matcher, values); + } +} diff --git a/hamcrest-core/src/main/java/org/hamcrest/core/Every.java b/hamcrest-core/src/main/java/org/hamcrest/core/Every.java new file mode 100644 index 0000000..757b7b4 --- /dev/null +++ b/hamcrest-core/src/main/java/org/hamcrest/core/Every.java @@ -0,0 +1,44 @@ +package org.hamcrest.core; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeDiagnosingMatcher; + +public class Every extends TypeSafeDiagnosingMatcher> { + private final Matcher matcher; + + public Every(Matcher matcher) { + this.matcher= matcher; + } + + @Override + public boolean matchesSafely(Iterable collection, Description mismatchDescription) { + for (T t : collection) { + if (!matcher.matches(t)) { + mismatchDescription.appendText("an item "); + matcher.describeMismatch(t, mismatchDescription); + return false; + } + } + return true; + } + + @Override + public void describeTo(Description description) { + description.appendText("every item is ").appendDescriptionOf(matcher); + } + + /** + * Creates a matcher for {@link Iterable}s that only matches when a single pass over the + * examined {@link Iterable} yields items that are all matched by the specified + * itemMatcher. + * For example: + *
assertThat(Arrays.asList("bar", "baz"), everyItem(startsWith("ba")))
+ * + * @param itemMatcher + * the matcher to apply to every item provided by the examined {@link Iterable} + */ + public static Matcher> everyItem(final Matcher itemMatcher) { + return new Every(itemMatcher); + } +} diff --git a/hamcrest-core/src/main/java/org/hamcrest/core/Is.java b/hamcrest-core/src/main/java/org/hamcrest/core/Is.java index f9152e9..ec22238 100644 --- a/hamcrest-core/src/main/java/org/hamcrest/core/Is.java +++ b/hamcrest-core/src/main/java/org/hamcrest/core/Is.java @@ -1,68 +1,76 @@ package org.hamcrest.core; -import static org.hamcrest.core.IsInstanceOf.instanceOf; -import static org.hamcrest.core.IsEqual.equalTo; -import org.hamcrest.Factory; -import org.hamcrest.Matcher; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; +import org.hamcrest.Matcher; + +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.core.IsInstanceOf.instanceOf; /** - * Decorates another Matcher, retaining the behavior but allowing tests + * Decorates another Matcher, retaining the behaviour but allowing tests * to be slightly more expressive. * - * eg. assertThat(cheese, equalTo(smelly)) - * vs assertThat(cheese, is(equalTo(smelly))) + * For example: assertThat(cheese, equalTo(smelly)) + * vs. assertThat(cheese, is(equalTo(smelly))) */ public class Is extends BaseMatcher { - private final Matcher matcher; public Is(Matcher matcher) { this.matcher = matcher; } + @Override public boolean matches(Object arg) { return matcher.matches(arg); } + @Override public void describeTo(Description description) { description.appendText("is ").appendDescriptionOf(matcher); } - + + @Override + public void describeMismatch(Object item, Description mismatchDescription) { + matcher.describeMismatch(item, mismatchDescription); + } + /** - * Decorates another Matcher, retaining the behavior but allowing tests + * Decorates another Matcher, retaining its behaviour, but allowing tests * to be slightly more expressive. - * - * eg. assertThat(cheese, equalTo(smelly)) - * vs assertThat(cheese, is(equalTo(smelly))) + * For example: + *
assertThat(cheese, is(equalTo(smelly)))
+ * instead of: + *
assertThat(cheese, equalTo(smelly))
+ * */ - @Factory public static Matcher is(Matcher matcher) { return new Is(matcher); } /** - * This is a shortcut to the frequently used is(equalTo(x)). - * - * eg. assertThat(cheese, is(equalTo(smelly))) - * vs assertThat(cheese, is(smelly)) + * A shortcut to the frequently used is(equalTo(x)). + * For example: + *
assertThat(cheese, is(smelly))
+ * instead of: + *
assertThat(cheese, is(equalTo(smelly)))
+ * */ - @Factory public static Matcher is(T value) { return is(equalTo(value)); } /** - * This is a shortcut to the frequently used is(instanceOf(SomeClass.class)). - * - * eg. assertThat(cheese, is(instanceOf(Cheddar.class))) - * vs assertThat(cheese, is(Cheddar.class)) + * A shortcut to the frequently used is(instanceOf(SomeClass.class)). + * For example: + *
assertThat(cheese, isA(Cheddar.class))
+ * instead of: + *
assertThat(cheese, is(instanceOf(Cheddar.class)))
+ * */ - @Factory - public static Matcher is(Class type) { - return is(instanceOf(type)); + public static Matcher isA(Class type) { + final Matcher typeMatcher = instanceOf(type); + return is(typeMatcher); } - } - diff --git a/hamcrest-core/src/main/java/org/hamcrest/core/IsAnything.java b/hamcrest-core/src/main/java/org/hamcrest/core/IsAnything.java index c5ca49d..4c71a9b 100644 --- a/hamcrest-core/src/main/java/org/hamcrest/core/IsAnything.java +++ b/hamcrest-core/src/main/java/org/hamcrest/core/IsAnything.java @@ -1,11 +1,8 @@ -/* Copyright (c) 2000-2006 hamcrest.org - */ package org.hamcrest.core; +import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.hamcrest.Matcher; -import org.hamcrest.Factory; -import org.hamcrest.BaseMatcher; /** @@ -13,47 +10,41 @@ import org.hamcrest.BaseMatcher; */ public class IsAnything extends BaseMatcher { - private final String description; + private final String message; public IsAnything() { this("ANYTHING"); } - public IsAnything(String description) { - this.description = description; + public IsAnything(String message) { + this.message = message; } + @Override public boolean matches(Object o) { return true; } + @Override public void describeTo(Description description) { - description.appendText(this.description); + description.appendText(message); } /** - * This matcher always evaluates to true. + * Creates a matcher that always matches, regardless of the examined object. */ - @Factory - public static Matcher anything() { - return new IsAnything(); + public static Matcher anything() { + return new IsAnything(); } /** - * This matcher always evaluates to true. + * Creates a matcher that always matches, regardless of the examined object, but describes + * itself with the specified {@link String}. * - * @param description A meaningful string used when describing itself. - */ - @Factory - public static Matcher anything(String description) { - return new IsAnything(description); - } - - /** - * This matcher always evaluates to true. With type inference. + * @param description + * a meaningful {@link String} used when describing itself */ - @Factory - public static Matcher any(@SuppressWarnings("unused")Class type) { - return new IsAnything(); + public static Matcher anything(String description) { + return new IsAnything(description); } } diff --git a/hamcrest-core/src/main/java/org/hamcrest/core/IsCollectionContaining.java b/hamcrest-core/src/main/java/org/hamcrest/core/IsCollectionContaining.java new file mode 100644 index 0000000..c55853d --- /dev/null +++ b/hamcrest-core/src/main/java/org/hamcrest/core/IsCollectionContaining.java @@ -0,0 +1,133 @@ +package org.hamcrest.core; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeDiagnosingMatcher; + +import java.util.ArrayList; +import java.util.List; + +import static org.hamcrest.core.AllOf.allOf; +import static org.hamcrest.core.IsEqual.equalTo; + +public class IsCollectionContaining extends TypeSafeDiagnosingMatcher> { + private final Matcher elementMatcher; + + public IsCollectionContaining(Matcher elementMatcher) { + this.elementMatcher = elementMatcher; + } + + @Override + protected boolean matchesSafely(Iterable collection, Description mismatchDescription) { + if (isEmpty(collection)) { + mismatchDescription.appendText("was empty"); + return false; + } + + for (Object item : collection) { + if (elementMatcher.matches(item)) { + return true; + } + } + + mismatchDescription.appendText("mismatches were: ["); + boolean isPastFirst = false; + for (Object item : collection) { + if (isPastFirst) { + mismatchDescription.appendText(", "); + } + elementMatcher.describeMismatch(item, mismatchDescription); + isPastFirst = true; + } + mismatchDescription.appendText("]"); + return false; + } + + private boolean isEmpty(Iterable iterable) { + return ! iterable.iterator().hasNext(); + } + + @Override + public void describeTo(Description description) { + description + .appendText("a collection containing ") + .appendDescriptionOf(elementMatcher); + } + + + /** + * Creates a matcher for {@link Iterable}s that only matches when a single pass over the + * examined {@link Iterable} yields at least one item that is matched by the specified + * itemMatcher. Whilst matching, the traversal of the examined {@link Iterable} + * will stop as soon as a matching item is found. + * For example: + *
assertThat(Arrays.asList("foo", "bar"), hasItem(startsWith("ba")))
+ * + * @param itemMatcher + * the matcher to apply to items provided by the examined {@link Iterable} + */ + public static Matcher> hasItem(Matcher itemMatcher) { + return new IsCollectionContaining<>(itemMatcher); + } + + /** + * Creates a matcher for {@link Iterable}s that only matches when a single pass over the + * examined {@link Iterable} yields at least one item that is equal to the specified + * item. Whilst matching, the traversal of the examined {@link Iterable} + * will stop as soon as a matching item is found. + * For example: + *
assertThat(Arrays.asList("foo", "bar"), hasItem("bar"))
+ * + * @param item + * the item to compare against the items provided by the examined {@link Iterable} + */ + public static Matcher> hasItem(T item) { + // Doesn't forward to hasItem() method so compiler can sort out generics. + return new IsCollectionContaining<>(equalTo(item)); + } + + /** + * Creates a matcher for {@link Iterable}s that matches when consecutive passes over the + * examined {@link Iterable} yield at least one item that is matched by the corresponding + * matcher from the specified itemMatchers. Whilst matching, each traversal of + * the examined {@link Iterable} will stop as soon as a matching item is found. + * For example: + *
assertThat(Arrays.asList("foo", "bar", "baz"), hasItems(endsWith("z"), endsWith("o")))
+ * + * @param itemMatchers + * the matchers to apply to items provided by the examined {@link Iterable} + */ + @SafeVarargs + public static Matcher> hasItems(Matcher... itemMatchers) { + List>> all = new ArrayList<>(itemMatchers.length); + + for (Matcher elementMatcher : itemMatchers) { + // Doesn't forward to hasItem() method so compiler can sort out generics. + all.add(new IsCollectionContaining<>(elementMatcher)); + } + + return allOf(all); + } + + /** + * Creates a matcher for {@link Iterable}s that matches when consecutive passes over the + * examined {@link Iterable} yield at least one item that is equal to the corresponding + * item from the specified items. Whilst matching, each traversal of the + * examined {@link Iterable} will stop as soon as a matching item is found. + * For example: + *
assertThat(Arrays.asList("foo", "bar", "baz"), hasItems("baz", "foo"))
+ * + * @param items + * the items to compare against the items provided by the examined {@link Iterable} + */ + @SafeVarargs + public static Matcher> hasItems(T... items) { + List>> all = new ArrayList<>(items.length); + for (T item : items) { + all.add(hasItem(item)); + } + + return allOf(all); + } + +} diff --git a/hamcrest-core/src/main/java/org/hamcrest/core/IsEqual.java b/hamcrest-core/src/main/java/org/hamcrest/core/IsEqual.java index b9f17c5..860e85e 100644 --- a/hamcrest-core/src/main/java/org/hamcrest/core/IsEqual.java +++ b/hamcrest-core/src/main/java/org/hamcrest/core/IsEqual.java @@ -1,11 +1,8 @@ -/* Copyright (c) 2000-2006 hamcrest.org - */ package org.hamcrest.core; +import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.hamcrest.Matcher; -import org.hamcrest.Factory; -import org.hamcrest.BaseMatcher; import java.lang.reflect.Array; @@ -15,42 +12,47 @@ import java.lang.reflect.Array; * {@link java.lang.Object#equals} invokedMethod? */ public class IsEqual extends BaseMatcher { - private final Object object; + private final Object expectedValue; public IsEqual(T equalArg) { - object = equalArg; + expectedValue = equalArg; } - public boolean matches(Object arg) { - return areEqual(object, arg); + @Override + public boolean matches(Object actualValue) { + return areEqual(actualValue, expectedValue); } + @Override public void describeTo(Description description) { - description.appendValue(object); + description.appendValue(expectedValue); } - private static boolean areEqual(Object o1, Object o2) { - if (o1 == null || o2 == null) { - return o1 == null && o2 == null; - } else if (isArray(o1)) { - return isArray(o2) && areArraysEqual(o1, o2); - } else { - return o1.equals(o2); + private static boolean areEqual(Object actual, Object expected) { + if (actual == null) { + return expected == null; + } + + if (expected != null && isArray(actual)) { + return isArray(expected) && areArraysEqual(actual, expected); } + + return actual.equals(expected); } - private static boolean areArraysEqual(Object o1, Object o2) { - return areArrayLengthsEqual(o1, o2) - && areArrayElementsEqual(o1, o2); + private static boolean areArraysEqual(Object actualArray, Object expectedArray) { + return areArrayLengthsEqual(actualArray, expectedArray) && areArrayElementsEqual(actualArray, expectedArray); } - private static boolean areArrayLengthsEqual(Object o1, Object o2) { - return Array.getLength(o1) == Array.getLength(o2); + private static boolean areArrayLengthsEqual(Object actualArray, Object expectedArray) { + return Array.getLength(actualArray) == Array.getLength(expectedArray); } - private static boolean areArrayElementsEqual(Object o1, Object o2) { - for (int i = 0; i < Array.getLength(o1); i++) { - if (!areEqual(Array.get(o1, i), Array.get(o2, i))) return false; + private static boolean areArrayElementsEqual(Object actualArray, Object expectedArray) { + for (int i = 0; i < Array.getLength(actualArray); i++) { + if (!areEqual(Array.get(actualArray, i), Array.get(expectedArray, i))) { + return false; + } } return true; } @@ -60,12 +62,36 @@ public class IsEqual extends BaseMatcher { } /** - * Is the value equal to another value, as tested by the - * {@link java.lang.Object#equals} invokedMethod? + * Creates a matcher that matches when the examined object is logically equal to the specified + * operand, as determined by calling the {@link java.lang.Object#equals} method on + * the examined object. + * + *

If the specified operand is null then the created matcher will only match if + * the examined object's equals method returns true when passed a + * null (which would be a violation of the equals contract), unless the + * examined object itself is null, in which case the matcher will return a positive + * match.

+ * + *

The created matcher provides a special behaviour when examining Arrays, whereby + * it will match if both the operand and the examined object are arrays of the same length and + * contain items that are equal to each other (according to the above rules) in the same + * indexes.

+ * For example: + *
+     * assertThat("foo", equalTo("foo"));
+     * assertThat(new String[] {"foo", "bar"}, equalTo(new String[] {"foo", "bar"}));
+     * 
+ * */ - @Factory public static Matcher equalTo(T operand) { return new IsEqual(operand); } - + + /** + * Creates an {@link org.hamcrest.core.IsEqual} matcher that does not enforce the values being + * compared to be of the same static type. + */ + public static Matcher equalToObject(Object operand) { + return new IsEqual(operand); + } } diff --git a/hamcrest-core/src/main/java/org/hamcrest/core/IsInstanceOf.java b/hamcrest-core/src/main/java/org/hamcrest/core/IsInstanceOf.java index df20824..5a508c9 100644 --- a/hamcrest-core/src/main/java/org/hamcrest/core/IsInstanceOf.java +++ b/hamcrest-core/src/main/java/org/hamcrest/core/IsInstanceOf.java @@ -1,44 +1,91 @@ -/* Copyright (c) 2000-2006 hamcrest.org - */ package org.hamcrest.core; import org.hamcrest.Description; +import org.hamcrest.DiagnosingMatcher; import org.hamcrest.Matcher; -import org.hamcrest.Factory; -import org.hamcrest.BaseMatcher; /** * Tests whether the value is an instance of a class. + * Classes of basic types will be converted to the relevant "Object" classes */ -public class IsInstanceOf extends BaseMatcher { - private final Class theClass; +public class IsInstanceOf extends DiagnosingMatcher { + private final Class expectedClass; + private final Class matchableClass; /** * Creates a new instance of IsInstanceOf * - * @param theClass The predicate evaluates to true for instances of this class + * @param expectedClass The predicate evaluates to true for instances of this class * or one of its subclasses. */ - public IsInstanceOf(Class theClass) { - this.theClass = theClass; + public IsInstanceOf(Class expectedClass) { + this.expectedClass = expectedClass; + this.matchableClass = matchableClass(expectedClass); + } + + private static Class matchableClass(Class expectedClass) { + if (boolean.class.equals(expectedClass)) return Boolean.class; + if (byte.class.equals(expectedClass)) return Byte.class; + if (char.class.equals(expectedClass)) return Character.class; + if (double.class.equals(expectedClass)) return Double.class; + if (float.class.equals(expectedClass)) return Float.class; + if (int.class.equals(expectedClass)) return Integer.class; + if (long.class.equals(expectedClass)) return Long.class; + if (short.class.equals(expectedClass)) return Short.class; + return expectedClass; } - public boolean matches(Object item) { - return theClass.isInstance(item); + @Override + protected boolean matches(Object item, Description mismatch) { + if (null == item) { + mismatch.appendText("null"); + return false; + } + + if (!matchableClass.isInstance(item)) { + mismatch.appendValue(item).appendText(" is a " + item.getClass().getName()); + return false; + } + + return true; } + @Override public void describeTo(Description description) { - description.appendText("an instance of ") - .appendText(theClass.getName()); + description.appendText("an instance of ").appendText(expectedClass.getName()); } /** - * Is the value an instance of a particular type? + * Creates a matcher that matches when the examined object is an instance of the specified type, + * as determined by calling the {@link java.lang.Class#isInstance(Object)} method on that type, passing the + * the examined object. + * + *

The created matcher assumes no relationship between specified type and the examined object.

+ * For example: + *
assertThat(new Canoe(), instanceOf(Paddlable.class));
+ * + */ + @SuppressWarnings("unchecked") + public static Matcher instanceOf(Class type) { + return (Matcher) new IsInstanceOf(type); + } + + /** + * Creates a matcher that matches when the examined object is an instance of the specified type, + * as determined by calling the {@link java.lang.Class#isInstance(Object)} method on that type, passing the + * the examined object. + * + *

The created matcher forces a relationship between specified type and the examined object, and should be + * used when it is necessary to make generics conform, for example in the JMock clause + * with(any(Thing.class))

+ * For example: + *
assertThat(new Canoe(), instanceOf(Canoe.class));
+ * */ - @Factory - public static Matcher instanceOf(Class type) { - return new IsInstanceOf(type); + @SuppressWarnings("unchecked") + public static Matcher any(Class type) { + return (Matcher) new IsInstanceOf(type); } } diff --git a/hamcrest-core/src/main/java/org/hamcrest/core/IsNot.java b/hamcrest-core/src/main/java/org/hamcrest/core/IsNot.java index cb6946c..d5cf9c0 100644 --- a/hamcrest-core/src/main/java/org/hamcrest/core/IsNot.java +++ b/hamcrest-core/src/main/java/org/hamcrest/core/IsNot.java @@ -1,49 +1,57 @@ -/* Copyright (c) 2000-2006 hamcrest.org - */ package org.hamcrest.core; -import static org.hamcrest.core.IsEqual.equalTo; +import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.hamcrest.Matcher; -import org.hamcrest.Factory; -import org.hamcrest.BaseMatcher; + +import static org.hamcrest.core.IsEqual.equalTo; /** * Calculates the logical negation of a matcher. */ -public class IsNot extends BaseMatcher { +public class IsNot extends BaseMatcher { private final Matcher matcher; public IsNot(Matcher matcher) { this.matcher = matcher; } + @Override public boolean matches(Object arg) { return !matcher.matches(arg); } + @Override public void describeTo(Description description) { description.appendText("not ").appendDescriptionOf(matcher); } + /** - * Inverts the rule. + * Creates a matcher that wraps an existing matcher, but inverts the logic by which + * it will match. + * For example: + *
assertThat(cheese, is(not(equalTo(smelly))))
+ * + * @param matcher + * the matcher whose sense should be inverted */ - @Factory public static Matcher not(Matcher matcher) { return new IsNot(matcher); } /** - * This is a shortcut to the frequently used not(equalTo(x)). - * - * eg. assertThat(cheese, is(not(equalTo(smelly)))) - * vs assertThat(cheese, is(not(smelly))) + * A shortcut to the frequently used not(equalTo(x)). + * For example: + *
assertThat(cheese, is(not(smelly)))
+ * instead of: + *
assertThat(cheese, is(not(equalTo(smelly))))
+ * + * @param value + * the value that any examined object should not equal */ - @Factory public static Matcher not(T value) { return not(equalTo(value)); } - } diff --git a/hamcrest-core/src/main/java/org/hamcrest/core/IsNull.java b/hamcrest-core/src/main/java/org/hamcrest/core/IsNull.java index 737dcf2..9ebf080 100644 --- a/hamcrest-core/src/main/java/org/hamcrest/core/IsNull.java +++ b/hamcrest-core/src/main/java/org/hamcrest/core/IsNull.java @@ -1,55 +1,74 @@ -/* Copyright (c) 2000-2006 hamcrest.org - */ package org.hamcrest.core; -import static org.hamcrest.core.IsNot.not; +import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.hamcrest.Matcher; -import org.hamcrest.Factory; -import org.hamcrest.BaseMatcher; + +import static org.hamcrest.core.IsNot.not; /** * Is the value null? */ public class IsNull extends BaseMatcher { + @Override public boolean matches(Object o) { return o == null; } + @Override public void describeTo(Description description) { description.appendText("null"); } /** - * Matches if value is null. + * Creates a matcher that matches if examined object is null. + * For example: + *
assertThat(cheese, is(nullValue())
+ * */ - @Factory - public static Matcher nullValue() { - return new IsNull(); + public static Matcher nullValue() { + return new IsNull(); } /** - * Matches if value is not null. + * A shortcut to the frequently used not(nullValue()). + * For example: + *
assertThat(cheese, is(notNullValue()))
+ * instead of: + *
assertThat(cheese, is(not(nullValue())))
+ * */ - @Factory - public static Matcher notNullValue() { - return not(IsNull.nullValue()); + public static Matcher notNullValue() { + return not(nullValue()); } /** - * Matches if value is null. With type inference. + * Creates a matcher that matches if examined object is null. Accepts a + * single dummy argument to facilitate type inference. + * For example: + *
assertThat(cheese, is(nullValue(Cheese.class))
+ * + * @param type + * dummy parameter used to infer the generic type of the returned matcher */ - @Factory - public static Matcher nullValue(@SuppressWarnings("unused") Class type) { - return nullValue(); + public static Matcher nullValue(Class type) { + return new IsNull(); } /** - * Matches if value is not null. With type inference. + * A shortcut to the frequently used not(nullValue(X.class)). Accepts a + * single dummy argument to facilitate type inference.. + * For example: + *
assertThat(cheese, is(notNullValue(X.class)))
+ * instead of: + *
assertThat(cheese, is(not(nullValue(X.class))))
+ * + * @param type + * dummy parameter used to infer the generic type of the returned matcher + * */ - @Factory - public static Matcher notNullValue(@SuppressWarnings("unused") Class type) { - return notNullValue(); + public static Matcher notNullValue(Class type) { + return not(nullValue(type)); } } diff --git a/hamcrest-core/src/main/java/org/hamcrest/core/IsSame.java b/hamcrest-core/src/main/java/org/hamcrest/core/IsSame.java index b3ad77e..cbc3971 100644 --- a/hamcrest-core/src/main/java/org/hamcrest/core/IsSame.java +++ b/hamcrest-core/src/main/java/org/hamcrest/core/IsSame.java @@ -1,11 +1,8 @@ -/* Copyright (c) 2000-2006 hamcrest.org - */ package org.hamcrest.core; +import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.hamcrest.Matcher; -import org.hamcrest.Factory; -import org.hamcrest.BaseMatcher; /** @@ -13,28 +10,42 @@ import org.hamcrest.BaseMatcher; */ public class IsSame extends BaseMatcher { private final T object; - + public IsSame(T object) { this.object = object; } + @Override public boolean matches(Object arg) { return arg == object; } + @Override public void describeTo(Description description) { - description.appendText("same(") .appendValue(object) .appendText(")"); + description.appendText("sameInstance(") + .appendValue(object) + .appendText(")"); } - + /** - * Creates a new instance of IsSame + * Creates a matcher that matches only when the examined object is the same instance as + * the specified target object. * - * @param object The predicate evaluates to true only when the argument is - * this object. + * @param target + * the target instance against which others should be assessed */ - @Factory - public static Matcher sameInstance(T object) { - return new IsSame(object); + public static Matcher sameInstance(T target) { + return new IsSame(target); + } + + /** + * Creates a matcher that matches only when the examined object is the same instance as + * the specified target object. + * + * @param target + * the target instance against which others should be assessed + */ + public static Matcher theInstance(T target) { + return new IsSame(target); } - } diff --git a/hamcrest-core/src/main/java/org/hamcrest/core/ShortcutCombination.java b/hamcrest-core/src/main/java/org/hamcrest/core/ShortcutCombination.java new file mode 100644 index 0000000..30b33af --- /dev/null +++ b/hamcrest-core/src/main/java/org/hamcrest/core/ShortcutCombination.java @@ -0,0 +1,33 @@ +package org.hamcrest.core; + +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.hamcrest.Matcher; + +abstract class ShortcutCombination extends BaseMatcher { + + private final Iterable> matchers; + + public ShortcutCombination(Iterable> matchers) { + this.matchers = matchers; + } + + @Override + public abstract boolean matches(Object o); + + @Override + public abstract void describeTo(Description description); + + protected boolean matches(Object o, boolean shortcut) { + for (Matcher matcher : matchers) { + if (matcher.matches(o) == shortcut) { + return shortcut; + } + } + return !shortcut; + } + + public void describeTo(Description description, String operator) { + description.appendList("(", " " + operator + " ", ")", matchers); + } +} diff --git a/hamcrest-core/src/main/java/org/hamcrest/core/StringContains.java b/hamcrest-core/src/main/java/org/hamcrest/core/StringContains.java new file mode 100644 index 0000000..9e0a4ab --- /dev/null +++ b/hamcrest-core/src/main/java/org/hamcrest/core/StringContains.java @@ -0,0 +1,46 @@ +package org.hamcrest.core; + +import org.hamcrest.Matcher; + +/** + * Tests if the argument is a string that contains a substring. + */ +public class StringContains extends SubstringMatcher { + public StringContains(boolean ignoringCase, String substring) { + super("containing", ignoringCase, substring); + } + + @Override + protected boolean evalSubstringOf(String s) { + return converted(s).contains(converted(substring)); + } + + /** + * Creates a matcher that matches if the examined {@link String} contains the specified + * {@link String} anywhere. + * For example: + *
assertThat("myStringOfNote", containsString("ring"))
+ * + * @param substring + * the substring that the returned matcher will expect to find within any examined string + * + */ + public static Matcher containsString(String substring) { + return new StringContains(false, substring); + } + + /** + * Creates a matcher that matches if the examined {@link String} contains the specified + * {@link String} anywhere, ignoring case. + * For example: + *
assertThat("myStringOfNote", containsString("ring"))
+ * + * @param substring + * the substring that the returned matcher will expect to find within any examined string + * + */ + public static Matcher containsStringIgnoringCase(String substring) { + return new StringContains(true, substring); + } + +} diff --git a/hamcrest-core/src/main/java/org/hamcrest/core/StringEndsWith.java b/hamcrest-core/src/main/java/org/hamcrest/core/StringEndsWith.java new file mode 100644 index 0000000..6a6d1a0 --- /dev/null +++ b/hamcrest-core/src/main/java/org/hamcrest/core/StringEndsWith.java @@ -0,0 +1,42 @@ +package org.hamcrest.core; + +import org.hamcrest.Matcher; + +/** + * Tests if the argument is a string that contains a substring. + */ +public class StringEndsWith extends SubstringMatcher { + public StringEndsWith(boolean ignoringCase, String substring) { super("ending with", ignoringCase, substring); } + + @Override + protected boolean evalSubstringOf(String s) { + return converted(s).endsWith(converted(substring)); + } + + /** + * Creates a matcher that matches if the examined {@link String} ends with the specified + * {@link String}. + * For example: + *
assertThat("myStringOfNote", endsWith("Note"))
+ * + * @param suffix + * the substring that the returned matcher will expect at the end of any examined string + */ + public static Matcher endsWith(String suffix) { + return new StringEndsWith(false, suffix); + } + + /** + * Creates a matcher that matches if the examined {@link String} ends with the specified + * {@link String}, ignoring case. + * For example: + *
assertThat("myStringOfNote", endsWith("Note"))
+ * + * @param suffix + * the substring that the returned matcher will expect at the end of any examined string + */ + public static Matcher endsWithIgnoringCase(String suffix) { + return new StringEndsWith(true, suffix); + } + +} diff --git a/hamcrest-core/src/main/java/org/hamcrest/core/StringStartsWith.java b/hamcrest-core/src/main/java/org/hamcrest/core/StringStartsWith.java new file mode 100644 index 0000000..fe7b990 --- /dev/null +++ b/hamcrest-core/src/main/java/org/hamcrest/core/StringStartsWith.java @@ -0,0 +1,40 @@ +package org.hamcrest.core; + +import org.hamcrest.Matcher; + +/** + * Tests if the argument is a string that contains a substring. + */ +public class StringStartsWith extends SubstringMatcher { + public StringStartsWith(boolean ignoringCase, String substring) { super("starting with", ignoringCase, substring); } + + @Override + protected boolean evalSubstringOf(String s) { return converted(s).startsWith(converted(substring)); } + + /** + *

+ * Creates a matcher that matches if the examined {@link String} starts with the specified + * {@link String}. + *

+ * For example: + *
assertThat("myStringOfNote", startsWith("my"))
+ * + * @param prefix + * the substring that the returned matcher will expect at the start of any examined string + */ + public static Matcher startsWith(String prefix) { return new StringStartsWith(false, prefix); } + + /** + *

+ * Creates a matcher that matches if the examined {@link String} starts with the specified + * {@link String}, ignoring case + *

+ * For example: + *
assertThat("myStringOfNote", startsWith("my"))
+ * + * @param prefix + * the substring that the returned matcher will expect at the start of any examined string + */ + public static Matcher startsWithIgnoringCase(String prefix) { return new StringStartsWith(true, prefix); } + +} diff --git a/hamcrest-core/src/main/java/org/hamcrest/core/SubstringMatcher.java b/hamcrest-core/src/main/java/org/hamcrest/core/SubstringMatcher.java new file mode 100644 index 0000000..85c6657 --- /dev/null +++ b/hamcrest-core/src/main/java/org/hamcrest/core/SubstringMatcher.java @@ -0,0 +1,44 @@ +package org.hamcrest.core; + +import org.hamcrest.Description; +import org.hamcrest.TypeSafeMatcher; + +public abstract class SubstringMatcher extends TypeSafeMatcher { + + // TODO: Replace String with CharSequence to allow for easy interoperability between + // String, StringBuffer, StringBuilder, CharBuffer, etc (joe). + + private final String relationship; + private final boolean ignoringCase; + protected final String substring; + + protected SubstringMatcher(String relationship, boolean ignoringCase, String substring) { + this.relationship = relationship; + this.ignoringCase = ignoringCase; + this.substring = substring; + } + + @Override + public boolean matchesSafely(String item) { + return evalSubstringOf(ignoringCase ? item.toLowerCase() :item); + } + @Override + public void describeMismatchSafely(String item, Description mismatchDescription) { + mismatchDescription.appendText("was \"").appendText(item).appendText("\""); + } + + @Override + public void describeTo(Description description) { + description.appendText("a string ") + .appendText(relationship) + .appendText(" ") + .appendValue(substring); + if (ignoringCase) { + description.appendText(" ignoring case"); + } + } + + protected String converted(String arg) { return ignoringCase ? arg.toLowerCase() : arg; } + protected abstract boolean evalSubstringOf(String string); + +} diff --git a/hamcrest-core/src/main/java/org/hamcrest/internal/ArrayIterator.java b/hamcrest-core/src/main/java/org/hamcrest/internal/ArrayIterator.java index 093cdba..03e4c43 100644 --- a/hamcrest-core/src/main/java/org/hamcrest/internal/ArrayIterator.java +++ b/hamcrest-core/src/main/java/org/hamcrest/internal/ArrayIterator.java @@ -4,25 +4,28 @@ import java.lang.reflect.Array; import java.util.Iterator; public class ArrayIterator implements Iterator { - private final Object array; - private int currentIndex = 0; - - public ArrayIterator(Object array) { - if (!array.getClass().isArray()) { - throw new IllegalArgumentException("not an array"); - } - this.array = array; - } - - public boolean hasNext() { - return currentIndex < Array.getLength(array); - } + private final Object array; + private int currentIndex = 0; + + public ArrayIterator(Object array) { + if (!array.getClass().isArray()) { + throw new IllegalArgumentException("not an array"); + } + this.array = array; + } + + @Override + public boolean hasNext() { + return currentIndex < Array.getLength(array); + } - public Object next() { - return Array.get(array, currentIndex++); - } - - public void remove() { - throw new UnsupportedOperationException("cannot remove items from an array"); - } + @Override + public Object next() { + return Array.get(array, currentIndex++); + } + + @Override + public void remove() { + throw new UnsupportedOperationException("cannot remove items from an array"); + } } diff --git a/hamcrest-core/src/main/java/org/hamcrest/internal/NullSafety.java b/hamcrest-core/src/main/java/org/hamcrest/internal/NullSafety.java new file mode 100644 index 0000000..9310abf --- /dev/null +++ b/hamcrest-core/src/main/java/org/hamcrest/internal/NullSafety.java @@ -0,0 +1,18 @@ +package org.hamcrest.internal; + +import org.hamcrest.Matcher; +import org.hamcrest.core.IsNull; + +import java.util.ArrayList; +import java.util.List; + +public class NullSafety { + @SuppressWarnings("unchecked") + public static List> nullSafe(Matcher[] itemMatchers) { + final List> matchers = new ArrayList>(itemMatchers.length); + for (final Matcher itemMatcher : itemMatchers) { + matchers.add((Matcher) (itemMatcher == null ? IsNull.nullValue() : itemMatcher)); + } + return matchers; + } +} diff --git a/hamcrest-core/src/main/java/org/hamcrest/internal/ReflectiveTypeFinder.java b/hamcrest-core/src/main/java/org/hamcrest/internal/ReflectiveTypeFinder.java new file mode 100644 index 0000000..ada74d6 --- /dev/null +++ b/hamcrest-core/src/main/java/org/hamcrest/internal/ReflectiveTypeFinder.java @@ -0,0 +1,70 @@ +/** + * The TypeSafe classes, and their descendants, need a mechanism to find out what type has been used as a parameter + * for the concrete matcher. Unfortunately, this type is lost during type erasure so we need to use reflection + * to get it back, by picking out the type of a known parameter to a known method. + * The catch is that, with bridging methods, this type is only visible in the class that actually implements + * the expected method, so the ReflectiveTypeFinder needs to be applied to that class or a subtype. + * + * For example, the abstract TypeSafeDiagnosingMatcher<T> defines an abstract method + *
protected abstract boolean matchesSafely(T item, Description mismatchDescription);
+ * By default it uses new ReflectiveTypeFinder("matchesSafely", 2, 0); to find the + * parameterised type. If we create a TypeSafeDiagnosingMatcher<String>, the type + * finder will return String.class. + * + * A FeatureMatcher is an abstract subclass of TypeSafeDiagnosingMatcher. + * Although it has a templated implementation of matchesSafely(<T>, Description);, the + * actual run-time signature of this is matchesSafely(Object, Description);. Instead, + * we must find the type by reflecting on the concrete implementation of + *
protected abstract U featureValueOf(T actual);
+ * a method which is declared in FeatureMatcher. + * + * In short, use this to extract a type from a method in the leaf class of a templated class hierarchy. + * + * @author Steve Freeman + * @author Nat Pryce + */ +package org.hamcrest.internal; + +import java.lang.reflect.Method; + +public class ReflectiveTypeFinder { + private final String methodName; + private final int expectedNumberOfParameters; + private final int typedParameter; + + public ReflectiveTypeFinder(String methodName, int expectedNumberOfParameters, int typedParameter) { + this.methodName = methodName; + this.expectedNumberOfParameters = expectedNumberOfParameters; + this.typedParameter = typedParameter; + } + + public Class findExpectedType(Class fromClass) { + for (Class c = fromClass; c != Object.class; c = c.getSuperclass()) { + for (Method method : c.getDeclaredMethods()) { + if (canObtainExpectedTypeFrom(method)) { + return expectedTypeFrom(method); + } + } + } + throw new Error("Cannot determine correct type for " + methodName + "() method."); + } + + /** + * @param method The method to examine. + * @return true if this method references the relevant type + */ + protected boolean canObtainExpectedTypeFrom(Method method) { + return method.getName().equals(methodName) + && method.getParameterTypes().length == expectedNumberOfParameters + && !method.isSynthetic(); + } + + + /** + * @param method The method from which to extract + * @return The type we're looking for + */ + protected Class expectedTypeFrom(Method method) { + return method.getParameterTypes()[typedParameter]; + } +} diff --git a/hamcrest-core/src/main/java/org/hamcrest/internal/SelfDescribingValue.java b/hamcrest-core/src/main/java/org/hamcrest/internal/SelfDescribingValue.java index 0634527..6537018 100644 --- a/hamcrest-core/src/main/java/org/hamcrest/internal/SelfDescribingValue.java +++ b/hamcrest-core/src/main/java/org/hamcrest/internal/SelfDescribingValue.java @@ -10,6 +10,7 @@ public class SelfDescribingValue implements SelfDescribing { this.value = value; } + @Override public void describeTo(Description description) { description.appendValue(value); } diff --git a/hamcrest-core/src/main/java/org/hamcrest/internal/SelfDescribingValueIterator.java b/hamcrest-core/src/main/java/org/hamcrest/internal/SelfDescribingValueIterator.java index 58bedf6..bc8f8f4 100644 --- a/hamcrest-core/src/main/java/org/hamcrest/internal/SelfDescribingValueIterator.java +++ b/hamcrest-core/src/main/java/org/hamcrest/internal/SelfDescribingValueIterator.java @@ -1,9 +1,9 @@ package org.hamcrest.internal; -import java.util.Iterator; - import org.hamcrest.SelfDescribing; +import java.util.Iterator; + public class SelfDescribingValueIterator implements Iterator { private Iterator values; @@ -11,14 +11,17 @@ public class SelfDescribingValueIterator implements Iterator this.values = values; } + @Override public boolean hasNext() { return values.hasNext(); } + @Override public SelfDescribing next() { return new SelfDescribingValue(values.next()); } + @Override public void remove() { values.remove(); } diff --git a/hamcrest-core/src/main/java/org/hamcrest/internal/package.html b/hamcrest-core/src/main/java/org/hamcrest/internal/package.html deleted file mode 100644 index 1c9bf9d..0000000 --- a/hamcrest-core/src/main/java/org/hamcrest/internal/package.html +++ /dev/null @@ -1,5 +0,0 @@ - - - {@hide} - - diff --git a/hamcrest-core/src/main/java/org/hamcrest/package.html b/hamcrest-core/src/main/java/org/hamcrest/package.html deleted file mode 100644 index 143c704..0000000 --- a/hamcrest-core/src/main/java/org/hamcrest/package.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - -

The stable API defining Matcher and its associated interfaces and classes. - Hamcrest sub-projects define their convenience classes in the org.hamcrest package. -

- - -- cgit v1.2.3