aboutsummaryrefslogtreecommitdiff
path: root/hamcrest-core/src/main/java/org/hamcrest/core
diff options
context:
space:
mode:
authorPaul Duffin <paulduffin@google.com>2017-01-20 15:04:28 +0000
committerPaul Duffin <paulduffin@google.com>2017-02-09 15:12:38 +0000
commitc1dbb44e71e47410ad5685aba3ef3fccb095a2b4 (patch)
tree08f6e90ece87cf59e3c7c645a7519eaaf63c716e /hamcrest-core/src/main/java/org/hamcrest/core
parent21a7b5b68f0bdc465bf6270db8917b881cf04157 (diff)
downloadhamcrest-c1dbb44e71e47410ad5685aba3ef3fccb095a2b4.tar.gz
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
Diffstat (limited to 'hamcrest-core/src/main/java/org/hamcrest/core')
-rw-r--r--hamcrest-core/src/main/java/org/hamcrest/core/AllOf.java49
-rw-r--r--hamcrest-core/src/main/java/org/hamcrest/core/AnyOf.java49
-rw-r--r--hamcrest-core/src/main/java/org/hamcrest/core/CombinableMatcher.java82
-rw-r--r--hamcrest-core/src/main/java/org/hamcrest/core/DescribedAs.java124
-rw-r--r--hamcrest-core/src/main/java/org/hamcrest/core/Every.java44
-rw-r--r--hamcrest-core/src/main/java/org/hamcrest/core/Is.java64
-rw-r--r--hamcrest-core/src/main/java/org/hamcrest/core/IsAnything.java41
-rw-r--r--hamcrest-core/src/main/java/org/hamcrest/core/IsCollectionContaining.java133
-rw-r--r--hamcrest-core/src/main/java/org/hamcrest/core/IsEqual.java82
-rw-r--r--hamcrest-core/src/main/java/org/hamcrest/core/IsInstanceOf.java81
-rw-r--r--hamcrest-core/src/main/java/org/hamcrest/core/IsNot.java36
-rw-r--r--hamcrest-core/src/main/java/org/hamcrest/core/IsNull.java61
-rw-r--r--hamcrest-core/src/main/java/org/hamcrest/core/IsSame.java39
-rw-r--r--hamcrest-core/src/main/java/org/hamcrest/core/ShortcutCombination.java33
-rw-r--r--hamcrest-core/src/main/java/org/hamcrest/core/StringContains.java46
-rw-r--r--hamcrest-core/src/main/java/org/hamcrest/core/StringEndsWith.java42
-rw-r--r--hamcrest-core/src/main/java/org/hamcrest/core/StringStartsWith.java40
-rw-r--r--hamcrest-core/src/main/java/org/hamcrest/core/SubstringMatcher.java44
18 files changed, 839 insertions, 251 deletions
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 <code>false</code>.
+ * Calculates the logical conjunction of multiple matchers. Evaluation is shortcut, so
+ * subsequent matchers are not called if an earlier matcher returns <code>false</code>.
*/
-public class AllOf<T> extends BaseMatcher<T> {
- private final Iterable<Matcher<? extends T>> matchers;
+public class AllOf<T> extends DiagnosingMatcher<T> {
+
+ private final Iterable<Matcher<? super T>> matchers;
- public AllOf(Iterable<Matcher<? extends T>> matchers) {
+ public AllOf(Iterable<Matcher<? super T>> matchers) {
this.matchers = matchers;
}
- public boolean matches(Object o) {
- for (Matcher<? extends T> matcher : matchers) {
+ @Override
+ public boolean matches(Object o, Description mismatch) {
+ for (Matcher<? super T> 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 <b>ALL</b> of the specified matchers.
+ * For example:
+ * <pre>assertThat("myValue", allOf(startsWith("my"), containsString("Val")))</pre>
*/
- @Factory
- public static <T> Matcher<T> allOf(Matcher<? extends T>... matchers) {
- return allOf(Arrays.asList(matchers));
+ public static <T> Matcher<T> allOf(Iterable<Matcher<? super T>> 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 <b>ALL</b> of the specified matchers.
+ * For example:
+ * <pre>assertThat("myValue", allOf(startsWith("my"), containsString("Val")))</pre>
*/
- @Factory
- public static <T> Matcher<T> allOf(Iterable<Matcher<? extends T>> matchers) {
- return new AllOf<T>(matchers);
+ @SafeVarargs
+ public static <T> Matcher<T> allOf(Matcher<? super T>... 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 <code>true</code>.
+ * Calculates the logical disjunction of multiple matchers. Evaluation is shortcut, so
+ * subsequent matchers are not called if an earlier matcher returns <code>true</code>.
*/
-public class AnyOf<T> extends BaseMatcher<T> {
-
- private final Iterable<Matcher<? extends T>> matchers;
+public class AnyOf<T> extends ShortcutCombination<T> {
- public AnyOf(Iterable<Matcher<? extends T>> matchers) {
- this.matchers = matchers;
+ public AnyOf(Iterable<Matcher<? super T>> matchers) {
+ super(matchers);
}
+ @Override
public boolean matches(Object o) {
- for (Matcher<? extends T> 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 <b>ANY</b> of the specified matchers.
+ * For example:
+ * <pre>assertThat("myValue", anyOf(startsWith("foo"), containsString("Val")))</pre>
*/
- @Factory
- public static <T> Matcher<T> anyOf(Matcher<? extends T>... matchers) {
- return anyOf(Arrays.asList(matchers));
+ public static <T> AnyOf<T> anyOf(Iterable<Matcher<? super T>> 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 <b>ANY</b> of the specified matchers.
+ * For example:
+ * <pre>assertThat("myValue", anyOf(startsWith("foo"), containsString("Val")))</pre>
*/
- @Factory
- public static <T> Matcher<T> anyOf(Iterable<Matcher<? extends T>> matchers) {
- return new AnyOf<T>(matchers);
+ @SafeVarargs
+ public static <T> AnyOf<T> anyOf(Matcher<? super T>... 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<T> extends TypeSafeDiagnosingMatcher<T> {
+ private final Matcher<? super T> matcher;
+
+ public CombinableMatcher(Matcher<? super T> 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<T> and(Matcher<? super T> other) {
+ return new CombinableMatcher<T>(new AllOf<T>(templatedListWith(other)));
+ }
+
+ public CombinableMatcher<T> or(Matcher<? super T> other) {
+ return new CombinableMatcher<T>(new AnyOf<T>(templatedListWith(other)));
+ }
+
+ private ArrayList<Matcher<? super T>> templatedListWith(Matcher<? super T> other) {
+ ArrayList<Matcher<? super T>> matchers = new ArrayList<Matcher<? super T>>();
+ 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:
+ * <pre>assertThat("fab", both(containsString("a")).and(containsString("b")))</pre>
+ */
+ public static <LHS> CombinableBothMatcher<LHS> both(Matcher<? super LHS> matcher) {
+ return new CombinableBothMatcher<LHS>(matcher);
+ }
+
+ public static final class CombinableBothMatcher<X> {
+ private final Matcher<? super X> first;
+ public CombinableBothMatcher(Matcher<? super X> matcher) {
+ this.first = matcher;
+ }
+ public CombinableMatcher<X> and(Matcher<? super X> other) {
+ return new CombinableMatcher<X>(first).and(other);
+ }
+ }
+
+ /**
+ * Creates a matcher that matches when either of the specified matchers match the examined object.
+ * For example:
+ * <pre>assertThat("fan", either(containsString("a")).or(containsString("b")))</pre>
+ */
+ public static <LHS> CombinableEitherMatcher<LHS> either(Matcher<? super LHS> matcher) {
+ return new CombinableEitherMatcher<LHS>(matcher);
+ }
+
+ public static final class CombinableEitherMatcher<X> {
+ private final Matcher<? super X> first;
+ public CombinableEitherMatcher(Matcher<? super X> matcher) {
+ this.first = matcher;
+ }
+ public CombinableMatcher<X> or(Matcher<? super X> other) {
+ return new CombinableMatcher<X>(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<T> extends BaseMatcher<T> {
- private final String descriptionTemplate;
- private final Matcher<T> matcher;
- private final Object[] values;
-
- private final static Pattern ARG_PATTERN = Pattern.compile("%([0-9]+)");
-
- public DescribedAs(String descriptionTemplate, Matcher<T> 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 <T> Matcher<T> describedAs(String description, Matcher<T> matcher, Object... values) {
- return new DescribedAs<T>(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<T> extends BaseMatcher<T> {
+ private final String descriptionTemplate;
+ private final Matcher<T> matcher;
+ private final Object[] values;
+
+ private final static Pattern ARG_PATTERN = Pattern.compile("%([0-9]+)");
+
+ public DescribedAs(String descriptionTemplate, Matcher<T> 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:
+ * <pre>describedAs("a big decimal equal to %0", equalTo(myBigDecimal), myBigDecimal.toPlainString())</pre>
+ *
+ * @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 <T> Matcher<T> describedAs(String description, Matcher<T> matcher, Object... values) {
+ return new DescribedAs<T>(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<T> extends TypeSafeDiagnosingMatcher<Iterable<? extends T>> {
+ private final Matcher<? super T> matcher;
+
+ public Every(Matcher<? super T> matcher) {
+ this.matcher= matcher;
+ }
+
+ @Override
+ public boolean matchesSafely(Iterable<? extends T> 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
+ * <code>itemMatcher</code>.
+ * For example:
+ * <pre>assertThat(Arrays.asList("bar", "baz"), everyItem(startsWith("ba")))</pre>
+ *
+ * @param itemMatcher
+ * the matcher to apply to every item provided by the examined {@link Iterable}
+ */
+ public static <U> Matcher<Iterable<? extends U>> everyItem(final Matcher<U> itemMatcher) {
+ return new Every<U>(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<T> extends BaseMatcher<T> {
-
private final Matcher<T> matcher;
public Is(Matcher<T> 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:
+ * <pre>assertThat(cheese, is(equalTo(smelly)))</pre>
+ * instead of:
+ * <pre>assertThat(cheese, equalTo(smelly))</pre>
+ *
*/
- @Factory
public static <T> Matcher<T> is(Matcher<T> matcher) {
return new Is<T>(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 <code>is(equalTo(x))</code>.
+ * For example:
+ * <pre>assertThat(cheese, is(smelly))</pre>
+ * instead of:
+ * <pre>assertThat(cheese, is(equalTo(smelly)))</pre>
+ *
*/
- @Factory
public static <T> Matcher<T> 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 <code>is(instanceOf(SomeClass.class))</code>.
+ * For example:
+ * <pre>assertThat(cheese, isA(Cheddar.class))</pre>
+ * instead of:
+ * <pre>assertThat(cheese, is(instanceOf(Cheddar.class)))</pre>
+ *
*/
- @Factory
- public static Matcher<Object> is(Class<?> type) {
- return is(instanceOf(type));
+ public static <T> Matcher<T> isA(Class<T> type) {
+ final Matcher<T> 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<T> extends BaseMatcher<T> {
- 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 <T> Matcher<T> anything() {
- return new IsAnything<T>();
+ public static Matcher<Object> anything() {
+ return new IsAnything<Object>();
}
/**
- * 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 <T> Matcher<T> anything(String description) {
- return new IsAnything<T>(description);
- }
-
- /**
- * This matcher always evaluates to true. With type inference.
+ * @param description
+ * a meaningful {@link String} used when describing itself
*/
- @Factory
- public static <T> Matcher<T> any(@SuppressWarnings("unused")Class<T> type) {
- return new IsAnything<T>();
+ public static Matcher<Object> anything(String description) {
+ return new IsAnything<Object>(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<T> extends TypeSafeDiagnosingMatcher<Iterable<? super T>> {
+ private final Matcher<? super T> elementMatcher;
+
+ public IsCollectionContaining(Matcher<? super T> elementMatcher) {
+ this.elementMatcher = elementMatcher;
+ }
+
+ @Override
+ protected boolean matchesSafely(Iterable<? super T> 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<? super T> 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
+ * <code>itemMatcher</code>. Whilst matching, the traversal of the examined {@link Iterable}
+ * will stop as soon as a matching item is found.
+ * For example:
+ * <pre>assertThat(Arrays.asList("foo", "bar"), hasItem(startsWith("ba")))</pre>
+ *
+ * @param itemMatcher
+ * the matcher to apply to items provided by the examined {@link Iterable}
+ */
+ public static <T> Matcher<Iterable<? super T>> hasItem(Matcher<? super T> 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
+ * <code>item</code>. Whilst matching, the traversal of the examined {@link Iterable}
+ * will stop as soon as a matching item is found.
+ * For example:
+ * <pre>assertThat(Arrays.asList("foo", "bar"), hasItem("bar"))</pre>
+ *
+ * @param item
+ * the item to compare against the items provided by the examined {@link Iterable}
+ */
+ public static <T> Matcher<Iterable<? super T>> 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 <code>itemMatchers</code>. Whilst matching, each traversal of
+ * the examined {@link Iterable} will stop as soon as a matching item is found.
+ * For example:
+ * <pre>assertThat(Arrays.asList("foo", "bar", "baz"), hasItems(endsWith("z"), endsWith("o")))</pre>
+ *
+ * @param itemMatchers
+ * the matchers to apply to items provided by the examined {@link Iterable}
+ */
+ @SafeVarargs
+ public static <T> Matcher<Iterable<T>> hasItems(Matcher<? super T>... itemMatchers) {
+ List<Matcher<? super Iterable<T>>> all = new ArrayList<>(itemMatchers.length);
+
+ for (Matcher<? super T> 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 <code>items</code>. Whilst matching, each traversal of the
+ * examined {@link Iterable} will stop as soon as a matching item is found.
+ * For example:
+ * <pre>assertThat(Arrays.asList("foo", "bar", "baz"), hasItems("baz", "foo"))</pre>
+ *
+ * @param items
+ * the items to compare against the items provided by the examined {@link Iterable}
+ */
+ @SafeVarargs
+ public static <T> Matcher<Iterable<T>> hasItems(T... items) {
+ List<Matcher<? super Iterable<T>>> 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<T> extends BaseMatcher<T> {
- 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<T> extends BaseMatcher<T> {
}
/**
- * 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
+ * <code>operand</code>, as determined by calling the {@link java.lang.Object#equals} method on
+ * the <b>examined</b> object.
+ *
+ * <p>If the specified operand is <code>null</code> then the created matcher will only match if
+ * the examined object's <code>equals</code> method returns <code>true</code> when passed a
+ * <code>null</code> (which would be a violation of the <code>equals</code> contract), unless the
+ * examined object itself is <code>null</code>, in which case the matcher will return a positive
+ * match.</p>
+ *
+ * <p>The created matcher provides a special behaviour when examining <code>Array</code>s, 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) <b>in the same
+ * indexes</b>.</p>
+ * For example:
+ * <pre>
+ * assertThat("foo", equalTo("foo"));
+ * assertThat(new String[] {"foo", "bar"}, equalTo(new String[] {"foo", "bar"}));
+ * </pre>
+ *
*/
- @Factory
public static <T> Matcher<T> equalTo(T operand) {
return new IsEqual<T>(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<Object> equalToObject(Object operand) {
+ return new IsEqual<Object>(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<Object> {
- private final Class<?> theClass;
+public class IsInstanceOf extends DiagnosingMatcher<Object> {
+ 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 <code>type</code>,
+ * as determined by calling the {@link java.lang.Class#isInstance(Object)} method on that type, passing the
+ * the examined object.
+ *
+ * <p>The created matcher assumes no relationship between specified type and the examined object.</p>
+ * For example:
+ * <pre>assertThat(new Canoe(), instanceOf(Paddlable.class));</pre>
+ *
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> Matcher<T> instanceOf(Class<?> type) {
+ return (Matcher<T>) new IsInstanceOf(type);
+ }
+
+ /**
+ * Creates a matcher that matches when the examined object is an instance of the specified <code>type</code>,
+ * as determined by calling the {@link java.lang.Class#isInstance(Object)} method on that type, passing the
+ * the examined object.
+ *
+ * <p>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
+ * <code>with(any(Thing.class))</code></p>
+ * For example:
+ * <pre>assertThat(new Canoe(), instanceOf(Canoe.class));</pre>
+ *
*/
- @Factory
- public static Matcher<Object> instanceOf(Class<?> type) {
- return new IsInstanceOf(type);
+ @SuppressWarnings("unchecked")
+ public static <T> Matcher<T> any(Class<T> type) {
+ return (Matcher<T>) 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<T> extends BaseMatcher<T> {
+public class IsNot<T> extends BaseMatcher<T> {
private final Matcher<T> matcher;
public IsNot(Matcher<T> 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:
+ * <pre>assertThat(cheese, is(not(equalTo(smelly))))</pre>
+ *
+ * @param matcher
+ * the matcher whose sense should be inverted
*/
- @Factory
public static <T> Matcher<T> not(Matcher<T> matcher) {
return new IsNot<T>(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 <code>not(equalTo(x))</code>.
+ * For example:
+ * <pre>assertThat(cheese, is(not(smelly)))</pre>
+ * instead of:
+ * <pre>assertThat(cheese, is(not(equalTo(smelly))))</pre>
+ *
+ * @param value
+ * the value that any examined object should <b>not</b> equal
*/
- @Factory
public static <T> Matcher<T> 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<T> extends BaseMatcher<T> {
+ @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 <code>null</code>.
+ * For example:
+ * <pre>assertThat(cheese, is(nullValue())</pre>
+ *
*/
- @Factory
- public static <T> Matcher<T> nullValue() {
- return new IsNull<T>();
+ public static Matcher<Object> nullValue() {
+ return new IsNull<Object>();
}
/**
- * Matches if value is not null.
+ * A shortcut to the frequently used <code>not(nullValue())</code>.
+ * For example:
+ * <pre>assertThat(cheese, is(notNullValue()))</pre>
+ * instead of:
+ * <pre>assertThat(cheese, is(not(nullValue())))</pre>
+ *
*/
- @Factory
- public static <T> Matcher<T> notNullValue() {
- return not(IsNull.<T>nullValue());
+ public static Matcher<Object> notNullValue() {
+ return not(nullValue());
}
/**
- * Matches if value is null. With type inference.
+ * Creates a matcher that matches if examined object is <code>null</code>. Accepts a
+ * single dummy argument to facilitate type inference.
+ * For example:
+ * <pre>assertThat(cheese, is(nullValue(Cheese.class))</pre>
+ *
+ * @param type
+ * dummy parameter used to infer the generic type of the returned matcher
*/
- @Factory
- public static <T> Matcher<T> nullValue(@SuppressWarnings("unused") Class<T> type) {
- return nullValue();
+ public static <T> Matcher<T> nullValue(Class<T> type) {
+ return new IsNull<T>();
}
/**
- * Matches if value is not null. With type inference.
+ * A shortcut to the frequently used <code>not(nullValue(X.class)). Accepts a
+ * single dummy argument to facilitate type inference.</code>.
+ * For example:
+ * <pre>assertThat(cheese, is(notNullValue(X.class)))</pre>
+ * instead of:
+ * <pre>assertThat(cheese, is(not(nullValue(X.class))))</pre>
+ *
+ * @param type
+ * dummy parameter used to infer the generic type of the returned matcher
+ *
*/
- @Factory
- public static <T> Matcher<T> notNullValue(@SuppressWarnings("unused") Class<T> type) {
- return notNullValue();
+ public static <T> Matcher<T> notNullValue(Class<T> 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<T> extends BaseMatcher<T> {
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 <T> Matcher<T> sameInstance(T object) {
- return new IsSame<T>(object);
+ public static <T> Matcher<T> sameInstance(T target) {
+ return new IsSame<T>(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 <T> Matcher<T> theInstance(T target) {
+ return new IsSame<T>(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<T> extends BaseMatcher<T> {
+
+ private final Iterable<Matcher<? super T>> matchers;
+
+ public ShortcutCombination(Iterable<Matcher<? super T>> 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<? super T> 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:
+ * <pre>assertThat("myStringOfNote", containsString("ring"))</pre>
+ *
+ * @param substring
+ * the substring that the returned matcher will expect to find within any examined string
+ *
+ */
+ public static Matcher<String> 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:
+ * <pre>assertThat("myStringOfNote", containsString("ring"))</pre>
+ *
+ * @param substring
+ * the substring that the returned matcher will expect to find within any examined string
+ *
+ */
+ public static Matcher<String> 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:
+ * <pre>assertThat("myStringOfNote", endsWith("Note"))</pre>
+ *
+ * @param suffix
+ * the substring that the returned matcher will expect at the end of any examined string
+ */
+ public static Matcher<String> 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:
+ * <pre>assertThat("myStringOfNote", endsWith("Note"))</pre>
+ *
+ * @param suffix
+ * the substring that the returned matcher will expect at the end of any examined string
+ */
+ public static Matcher<String> 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)); }
+
+ /**
+ * <p>
+ * Creates a matcher that matches if the examined {@link String} starts with the specified
+ * {@link String}.
+ * </p>
+ * For example:
+ * <pre>assertThat("myStringOfNote", startsWith("my"))</pre>
+ *
+ * @param prefix
+ * the substring that the returned matcher will expect at the start of any examined string
+ */
+ public static Matcher<String> startsWith(String prefix) { return new StringStartsWith(false, prefix); }
+
+ /**
+ * <p>
+ * Creates a matcher that matches if the examined {@link String} starts with the specified
+ * {@link String}, ignoring case
+ * </p>
+ * For example:
+ * <pre>assertThat("myStringOfNote", startsWith("my"))</pre>
+ *
+ * @param prefix
+ * the substring that the returned matcher will expect at the start of any examined string
+ */
+ public static Matcher<String> 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<String> {
+
+ // 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);
+
+}