diff --git a/matchers/HEADER.txt b/matchers/HEADER.txt
new file mode 100644
index 0000000..bd5cf4f
--- /dev/null
+++ b/matchers/HEADER.txt
@@ -0,0 +1,14 @@
+/*
+ * The copyright holders of this work license this file to You under
+ * the Apache License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
diff --git a/matchers/LICENSE b/matchers/LICENSE
new file mode 100644
index 0000000..883ab09
--- /dev/null
+++ b/matchers/LICENSE
@@ -0,0 +1,264 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+APACHE JACKRABBIT SUBCOMPONENTS
+
+Apache Jackrabbit includes parts with separate copyright notices and license
+terms. Your use of these subcomponents is subject to the terms and conditions
+of the following licenses:
+
+ XPath 2.0/XQuery 1.0 Parser:
+ http://www.w3.org/2002/11/xquery-xpath-applets/xgrammar.zip
+
+ Copyright (C) 2002 World Wide Web Consortium, (Massachusetts Institute of
+ Technology, European Research Consortium for Informatics and Mathematics,
+ Keio University). All Rights Reserved.
+
+ This work is distributed under the W3C(R) Software License in the hope
+ that it will be useful, but WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ W3C(R) SOFTWARE NOTICE AND LICENSE
+ http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
+
+ This work (and included software, documentation such as READMEs, or
+ other related items) is being provided by the copyright holders under
+ the following license. By obtaining, using and/or copying this work,
+ you (the licensee) agree that you have read, understood, and will comply
+ with the following terms and conditions.
+
+ Permission to copy, modify, and distribute this software and its
+ documentation, with or without modification, for any purpose and
+ without fee or royalty is hereby granted, provided that you include
+ the following on ALL copies of the software and documentation or
+ portions thereof, including modifications:
+
+ 1. The full text of this NOTICE in a location viewable to users
+ of the redistributed or derivative work.
+
+ 2. Any pre-existing intellectual property disclaimers, notices,
+ or terms and conditions. If none exist, the W3C Software Short
+ Notice should be included (hypertext is preferred, text is
+ permitted) within the body of any redistributed or derivative code.
+
+ 3. Notice of any changes or modifications to the files, including
+ the date changes were made. (We recommend you provide URIs to the
+ location from which the code is derived.)
+
+ THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT
+ HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED,
+ INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS
+ FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR
+ DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS,
+ TRADEMARKS OR OTHER RIGHTS.
+
+ COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL
+ OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR
+ DOCUMENTATION.
+
+ The name and trademarks of copyright holders may NOT be used in
+ advertising or publicity pertaining to the software without specific,
+ written prior permission. Title to copyright in this software and
+ any associated documentation will at all times remain with
+ copyright holders.
diff --git a/matchers/pom.xml b/matchers/pom.xml
new file mode 100644
index 0000000..420d940
--- /dev/null
+++ b/matchers/pom.xml
@@ -0,0 +1,101 @@
+
+
+
+
+
+ * If a failure appears after calling {@link #end(java.util.regex.Matcher)}, then the
+ * method {@link #hasFailure()} returns {@code true} and the failure description is
+ * retrieved by the return from {@link #getFailureDescription()}.
+ */
+final class EndPosition extends Position {
+ private int end = -1;
+ private boolean matches, isEvaluated;
+
+ @Override
+ protected boolean isEvaluated() {
+ return isEvaluated;
+ }
+
+ EndPosition(int group, Matcher
+ * The integer matcher represents expected range of position. The first method parameter
+ * specifies a group of given regular expression to search matching end position. If given
+ * group is negative, then the {@link AssertionError} is thrown.
+ * @param group a group in regular expression
+ * @param index expected range of end position (exclusive)
+ * @throws AssertionError
+ * if given group is negative,
+ * index is null
+ * ; or if not applicable when result matcher already specified
+ * @return opposite matcher
+ */
+ IStartMatcher
+ * The integer matcher represents expected range of end position with zero group.
+ * @param index expected range of end position (exclusive)
+ * @return opposite matcher
+ * @throws AssertionError
+ * index is null
+ * or; if not applicable when result matcher already specified
+ */
+ IStartMatcher
+ * The first method parameter specifies a group of given regular expression to search
+ * matching end position. If given group is negative, then the
+ * {@link AssertionError} is thrown.
+ * @param group a group in regular expression
+ * @param index expected range of end position (exclusive)
+ * @throws AssertionError
+ * if given group is negative
+ * ; or if not applicable when result matcher already specified
+ * @return opposite matcher
+ */
+ IStartMatcher
+ * The integer matcher represents expected range of end position with zero group.
+ * @param index expected range of end position (exclusive)
+ * @return opposite matcher
+ * @throws AssertionError
+ * if not applicable when result matcher already specified
+ */
+ IStartMatcher
+ * The integer matcher represents expected range of position. The first method parameter
+ * specifies a group of given regular expression to search matching start position. If given
+ * group is negative, then the {@link AssertionError} is thrown.
+ * @param group a group in regular expression
+ * @param index expected range of start position (inclusive)
+ * @throws AssertionError
+ * if given group is negative,
+ * index is null
+ * ; or if not applicable when result matcher already specified
+ * @return opposite matcher
+ * @see java.util.regex.Matcher#start(int)
+ */
+ IEndMatcher
+ * The integer matcher represents expected range of start position with zero group.
+ * @param index expected range of start position (inclusive)
+ * @return opposite matcher
+ * @throws AssertionError
+ * index is null
+ * ; or if not applicable when result matcher already specified
+ */
+ IEndMatcher
+ * The first method parameter specifies a group of given regular expression to search matching
+ * start position. If given group is negative, then the {@link AssertionError} is thrown.
+ * @param group a group in regular expression
+ * @param index expected range of start position (inclusive)
+ * @throws AssertionError
+ * if given group is negative
+ * ; or if not applicable when result matcher already specified
+ * @return opposite matcher
+ * @see java.util.regex.Matcher#start(int)
+ */
+ IEndMatcher
+ * The integer matcher represents expected range of start position with zero group.
+ * @param index expected range of start position (inclusive)
+ * @return opposite matcher
+ * @throws AssertionError
+ * if not applicable when result matcher already specified
+ */
+ IEndMatcher
+ */
+final class InternalDescription extends BaseDescription {
+ private final StringBuilder msg;
+
+ public InternalDescription() {
+ msg = new StringBuilder(128);
+ }
+
+ public InternalDescription(String description) {
+ msg = new StringBuilder(description);
+ }
+
+ @Override protected void append(char c) {
+ msg.append(c);
+ }
+
+ @Override public String toString() {
+ return msg.toString();
+ }
+}
\ No newline at end of file
diff --git a/matchers/src/main/java/org/junit/contrib/matchers/IsAssignableTo.java b/matchers/src/main/java/org/junit/contrib/matchers/IsAssignableTo.java
new file mode 100644
index 0000000..556220c
--- /dev/null
+++ b/matchers/src/main/java/org/junit/contrib/matchers/IsAssignableTo.java
@@ -0,0 +1,61 @@
+package org.junit.contrib.matchers;
+
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.junit.internal.matchers.TypeSafeMatcher;
+
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Matches the actual reference type with the given type.
+ *
+ * If the actual type is same with or a subtype, in other words assignable, to the given expected type in the
+ * methods {@link #assignableTo(Class)}, {@link #assignableToAny(Class)}, {@link #assignableToThrowable(Class)}.
+ *
+ * The method {@link #assignableTo(Class)} uses same generic type on the returned value and method parameter.
+ *
+ * The method {@link #assignableToAny(Class)} allows to use wildcards Class>.
+ *
+ * The last method {@link #assignableToThrowable(Class)}
+ * is suitable in use of exceptions, like it is in the {@linkplain IsThrowing IsThrowing matcher}.
+ *
+ * @param an actual type
+ * @param
+ * The matcher can be extended by specifying start and the end position found first by a
+ * positive result of the matcher. As for instance
+ *
+ * Both operations {@code startsAt} and {@code endsAt} have two alternatives. The integer
+ * matcher in last method parameter represents expected range of position. In other alternative
+ * {@link #startsAt(int, org.hamcrest.Matcher)} and {@link #endsAt(int, org.hamcrest.Matcher)}
+ * specifies a group of given regular expression. If this group is negative (i.e. not recognized within
+ * regular expression's group counter), then the the methods fail by throwing {@link AssertionError}.
+ * If the group, start, or end position is negative in
+ * {@link #startsAt(int)}, {@link #startsAt(int, int)}, {@link #startsAt(int, org.hamcrest.Matcher)},
+ * {@link #endsAt(int)}, {@link #endsAt(int, int)}, {@link #endsAt(int, org.hamcrest.Matcher)}.
+ * If the methods {@link #startsAt(org.hamcrest.Matcher)}, {@link #startsAt(int, org.hamcrest.Matcher)},
+ * {@link #endsAt(org.hamcrest.Matcher)}, {@link #endsAt(int, org.hamcrest.Matcher)} are used with
+ * null in reference parameter, the method call fails by throwing {@link AssertionError}.
+ * @param
+ * The pattern is specified by the first method parameter.
+ *
+ * If the match succeeds, then more information can be obtained via the
+ * startsAt, endsAt.
+ *
+ * The pattern is specified by the first method parameter, and the matched result is expected
+ * to match with the another matcher Matcher
+ * The pattern is specified by the first method parameter, and the matcher properties are given
+ * in the last parameter regexProperties.
+ *
+ * The pattern is specified by the first method parameter. The properties are given in the
+ * second parameter, and the matched result is expected to match with the another matcher
+ * Matcher
+ * The pattern is specified by the first method parameter.
+ *
+ * If the match succeeds, then more information can be obtained via the
+ * startsAt, endsAt.
+ *
+ * The pattern is specified by the first method parameter, and the matched result is expected
+ * to match with the another matcher Matcher
+ * The pattern is specified by the first method parameter, and the matcher properties are given
+ * in the last parameter regexProperties.
+ *
+ * The pattern is specified by the first method parameter. The properties are given in the
+ * second parameter, and the matched result is expected to match with the another matcher
+ * Matcher
+ *
+ *
+ * As an use case, this assert will succeed because the type of actual instance of
+ * exception of {@link ArrayIndexOutOfBoundsException} is a subtype of the expected type
+ * {@link IndexOutOfBoundsException} declared by the combination of matchers
+ * type(assignableTo(IndexOutOfBoundsException.class)):
+ *
+ * The purpose of them is to encapsulate a code into a block, see wrapping blocks {@link Block} and {@link Callable}, and
+ * impose exceptional conditions on how the block returns (normally or abruptly). This is especially useful in
+ * situations, when a surrounding code in test case should not throw at all, or throws other expected exceptions.
+ * The names of matchers which are finished by 'Deeply' report Java stack trace, cause and localized message, when
+ * the running block of code has returned unexpectedly.
+ * This matcher comes from practical experiences when trying to solve the following test scenario. The test case is
+ * testing code statements, where their calls would not split to other methods and call a sequence the statements
+ * matters a lot. Thus suppose this formal test case:
+ * In this particular scenario the developer dos not want to encapsulate the middle part into an ugly and dangerous
+ * try-catch block. Here the test behaviour wants to say that all statements are supposed to throw exceptions, except for
+ * the middle part. This means that we want to keep Hamcrest in use with assertThat() and keep the tests as much verbose
+ * as possible. When you read the expression using The matchers in
+ * The form of Finally the expression may continue with {@link #andMessage(org.hamcrest.Matcher)} or {@link #andMessage(IsRegex)}
+ * which additionally filters the expected exceptions against certainly localized message
+ * (via
+ * The following table describes a behavior and possible examples of the
+ * Note: Assignable exceptions means all specified and their sub-types.
+ * Concrete use cases:
+ * A lot of use cases are covered in the tests, see This is the most simple use case:
+ *
+ * A description can be placed on the exceptional conditions using {@link org.hamcrest.core.DescribedAs}, in a form
+ * as follows:
+ * This matcher can be also used in multiple times running block within one call of
+ * {@link org.junit.Assert#assertThat(Object, org.hamcrest.Matcher)} if these matchers are encapsulated by
+ * {@link org.junit.matchers.JUnitMatchers#both(org.hamcrest.Matcher)} and
+ * Other alternative of
+ * The order in which the block is launched by every matcher by
+ *
+ * Other two examples would describe situations when you want to assert against exceptions and expected messages. The
+ * first example shows the use of regular expression:
+ * The second example uses
+ *
+ * Known limitations:
+ * The
+ * @author Tibor17
+ * @version 0.1
+ * @since 0.1, Sep 15, 2011, 10:33:33 AM
+ */
+public class IsThrowing If no exceptions are specified and this parameter is {@code true}, then any exception is expected to be
+ * thrown when running the block of code.
+ * If {@code false}, then a complementary exception is expected to throw when running the block.
+ * If {@code false} and no exceptions are specified at all, then no exception is expected to be thrown
+ * (complement of all is nothing).
+ * @param showStack If {@code true} and an unexpected exception (other than exceptions) is thrown in
+ * running block, then Java Stack Trace is passed in the description on method's parameter of
+ * {@link #describeTo(org.hamcrest.Description)}.
+ * @param throwableClassesMatcher Expected exceptions which belong to the particular operation. An empty array of exceptions, or
+ * the {@link Throwable Throwable.class} in array represents all exceptions.
+ */
+ public IsThrowing(final Operation operation, final boolean isThrowing, final boolean showStack,
+ final Class extends Throwable>... throwableClassesMatcher) {
+ assertNotNull("an array of exceptions must not be null", throwableClassesMatcher);
+ this.throwableClassesMatcher = anyOfThrowable(operation, throwableClassesMatcher.length == 0 ? ALL_THROWABLE : throwableClassesMatcher);
+ throwableInstancesMatcher = null;
+ this.showStack = showStack;
+ this.isThrowing = isThrowing;
+ isThrownMessageMatcherEnabled = true;
+ if (throwableClassesMatcher.length != 0) additionalErrMsg.append(toString(throwableClassesMatcher));
+ matcherType = IsThrowing.MatcherType.THROWABLE_CLASSES;
+ }
+
+ /**
+ * Specifies expected behaviour when running the block of code.
+ * See Equivalent Embedded Flag Expression in {@link java.util.regex.Pattern}.
+ * @author Tibor17
+ * @version 0.1
+ * @see Pattern
+ * @since 0.1, Oct 2, 2011, 7:38:45 PM
+ */
+public enum MatchFlag {
+ UNIX_LINES("(?d)", Pattern.UNIX_LINES),
+ CASE_INSENSITIVE("(?i)", Pattern.CASE_INSENSITIVE),
+ COMMENTS("(?x)", Pattern.COMMENTS),
+ MULTILINE("(?m)", Pattern.MULTILINE),
+ LITERAL(null, Pattern.LITERAL),
+ DOTALL("(?s)", Pattern.DOTALL),
+ UNICODE_CASE("(?u)", Pattern.UNICODE_CASE),
+ CANON_EQ(null, Pattern.CANON_EQ);
+
+ private final int flag;
+ private final String expression;
+
+ private MatchFlag(String expression, int flag) {
+ this.flag = flag;
+ this.expression = expression;
+ }
+
+ /**
+ * Returns embedded flag expressions for this constant; or null if undefined.
+ * The embedded flag expressions that correspond to these constants are the following:
+ *
+ * @return embedded flag expressions for this constant; or null if undefined
+ */
+ public String getEmbeddedFlagExpression() {
+ return expression;
+ }
+
+ int getJavaFlag() {
+ return flag;
+ }
+
+ @Override
+ public String toString() {
+ return expression == null ? name() : expression;
+ }
+}
\ No newline at end of file
diff --git a/matchers/src/main/java/org/junit/contrib/matchers/Position.java b/matchers/src/main/java/org/junit/contrib/matchers/Position.java
new file mode 100644
index 0000000..e39692c
--- /dev/null
+++ b/matchers/src/main/java/org/junit/contrib/matchers/Position.java
@@ -0,0 +1,78 @@
+package org.junit.contrib.matchers;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Skeleton class for {@link StartPosition} and {@link EndPosition}.
+ * Determines a position index
+ * (as a result of {@link java.util.regex.Matcher#start(int)} or {@link java.util.regex.Matcher#end(int)})
+ * been matched with the given hamcrest's matcher expectedIndex as expected one.
+ *
+ * This is performed by {@link #matchExpectedIndex(int)}. The mismatched result enables the caller
+ * to retrieve failure description via {@link #getFailureDescription()} after method the
+ * {@link #matchExpectedIndex(int)} returned {@code false}.
+ *
+ * The method {@link #isEvaluated()} can be called after {@link #matchExpectedIndex(int)}. Thus the method
+ * {@link #isEvaluated()} always returns {@code true} if, and only if, {@link #matchExpectedIndex(int)} was
+ * called before with whatever value it returned.
+ */
+abstract class Position {
+ protected final ExpectedMatcher
+ *
+ * @author tibor17
+ * @version 0.1
+ * @see org.junit.contrib.matchers.IsRegex
+ * @since 0.1, 27.12.2011, 17:57
+ */
+public final class RegexProperties {
+ private int startRegion, endRegion = -1;
+ private MatchFlag[] flags = new MatchFlag[0];
+ private boolean useAnchoringBounds = true, useTransparentBounds;
+
+ /**
+ * Default properties.
+ */
+ public RegexProperties() {}
+
+ /**
+ * Properties with arbitrary mach flags.
+ * @param matchFlags mach flags array
+ * @throws AssertionError
+ * if the array is null or contains null element(s)
+ * @see java.util.regex.Pattern#compile(String, int)
+ */
+ public RegexProperties(MatchFlag... matchFlags) {
+ setMatchFlags(matchFlags);
+ }
+
+ /**
+ * Specifies the start index on the input sequence been applicable to {@link IsRegex}.
+ * @param startRegion start index on the input sequence
+ * @return this
+ * @throws AssertionError
+ * if negative number startRegion
+ * @see java.util.regex.Matcher#region(int, int)
+ */
+ public RegexProperties setStartRegion(int startRegion) {
+ if (startRegion < 0)
+ fail("startRegion is negative");
+ this.startRegion = startRegion;
+ return this;
+ }
+
+ /**
+ * Specifies the end index on the input sequence been applicable to {@link IsRegex}.
+ * @param endRegion end index on the input sequence
+ * @return this
+ * @throws AssertionError
+ * if negative number endRegion
+ * @see java.util.regex.Matcher#region(int, int)
+ */
+ public RegexProperties setEndRegion(int endRegion) {
+ if (endRegion < 0)
+ fail("endRegion is negative");
+ this.endRegion = endRegion;
+ return this;
+ }
+
+ /**
+ * Properties with arbitrary mach flags.
+ * @param matchFlags mach flags array
+ * @return this
+ * @throws AssertionError
+ * if the array is null or contains null element(s)
+ * @see java.util.regex.Pattern#compile(String, int)
+ */
+ public RegexProperties setMatchFlags(MatchFlag... matchFlags) {
+ if (matchFlags == null)
+ fail("null flags on given array");
+ MatchFlag[] flags = new MatchFlag[matchFlags.length];
+ int i = 0;
+ for (MatchFlag flag : matchFlags) {
+ if (flag == null)
+ fail("null element at " + i
+ + " in given flags array "
+ + Arrays.toString(matchFlags));
+ if (!hasSameInstance(0, i, flag, flags)) flags[i++] = flag;
+ }
+ this.flags = i == flags.length ? flags : Arrays.copyOf(flags, i);
+ return this;
+ }
+
+ /**
+ * Sets the anchoring of region bounds for this matcher.
+ * @param enable a boolean indicating whether or not to use anchoring bounds
+ * @return this
+ * @see java.util.regex.Matcher#useAnchoringBounds(boolean)
+ */
+ public RegexProperties setAnchoringBounds(boolean enable) {
+ useAnchoringBounds = enable;
+ return this;
+ }
+
+ /**
+ * Sets the transparency of region bounds for this matcher.
+ * @param enable a boolean indicating whether to use opaque or transparent regions
+ * @return this
+ * @see java.util.regex.Matcher#useTransparentBounds(boolean)
+ */
+ public RegexProperties setTransparentBounds(boolean enable) {
+ useTransparentBounds = enable;
+ return this;
+ }
+
+ /**
+ * A value provided by {@link #setStartRegion(int)}; or zero otherwise (by default).
+ * @return {@link #setStartRegion(int)}; or zero otherwise (by default)
+ * @see java.util.regex.Matcher#region(int, int)
+ */
+ public int getStartRegion() {
+ return startRegion;
+ }
+
+ /**
+ * A value provided by {@link #setEndRegion(int)}; or -1 otherwise (unlimited by default).
+ * @return {@link #setEndRegion(int)}; or -1 otherwise (unlimited by default)
+ * @see java.util.regex.Matcher#region(int, int)
+ */
+ public int getEndRegion() {
+ return endRegion;
+ }
+
+ /**
+ * Properties with arbitrary mach flags.
+ * @return mach flags
+ * @see java.util.regex.Pattern#compile(String, int)
+ */
+ public MatchFlag[] getFlags() {
+ return flags.clone();
+ }
+
+ /**
+ * Returns a boolean indicating whether or not to use anchoring bounds ({@code true} by default).
+ * @return a boolean indicating whether or not to use anchoring bounds ({@code true} by default)
+ * @see java.util.regex.Matcher#useAnchoringBounds(boolean)
+ */
+ public boolean hasAnchoringBounds() {
+ return useAnchoringBounds;
+ }
+
+ /**
+ * Returns a boolean indicating whether to use opaque or transparent regions ({@code false} by default).
+ * @return a boolean indicating whether to use opaque or transparent regions ({@code false} by default)
+ * @see java.util.regex.Matcher#useTransparentBounds(boolean)
+ */
+ public boolean hasTransparentBounds() {
+ return useTransparentBounds;
+ }
+
+ /**
+ * Returns {@code true} if, and only if, the array references
+ * has the given reference within given range of the array indexes.
+ * @param references content
+ * @param from inclusive
+ * @param to exclusive
+ * @param reference a reference to find
+ * @param
+ * If the group is -1, then any group of group's range is possibly used for comparison in
+ * {@link IsRegexResult} Hamcrest matcher.
+ * @param group group for start or end operation (must be non-negative or -1)
+ * @param start
+ * start index (must be non-negative) of the subsequence captured by the given group on a match operation
+ * @param end
+ * end index (must be non-negative) of the subsequence captured by the given group on a match operation
+ * @throws IllegalArgumentException
+ * if group is less than -1;
+ * or if stat or end is negative
+ */
+ RegexResult(int group, int start, int end) {
+ if (group < ANY_GROUP) throw new IllegalArgumentException("group is " + group);
+ if (start < 0) throw new IllegalArgumentException("start is " + start);
+ if (end < 0) throw new IllegalArgumentException("end is " + end);
+ this.group = group;
+ this.start = start;
+ this.end = end;
+ }
+
+ /**
+ * Returns the value passed in by the constructor.
+ * @return group. Must be non-negative number when passed in by {@link #RegexResult(int, int, int)} constructor}
+ * ; otherwise -1 which appears any group when passed in by
+ * {@link #RegexResult(int, int, int)}.
+ */
+ public int getGroup() {
+ return group;
+ }
+
+ /**
+ * Returns the value passed in by the constructor.
+ * @return (a non-negative number of) start operation
+ */
+ public int getStart() {
+ return start;
+ }
+
+ /**
+ * Returns the value passed in by the constructor.
+ * @return (a non-negative number of) end operation
+ */
+ public int getEnd() {
+ return end;
+ }
+
+ @Override
+ public int hashCode() {
+ return start ^ end ^ group;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || !(o instanceof RegexResult)) return false;
+ final RegexResult rr = (RegexResult) o;
+ return rr.start == start && rr.end == end && rr.group == group;
+ }
+}
diff --git a/matchers/src/main/java/org/junit/contrib/matchers/ResultType.java b/matchers/src/main/java/org/junit/contrib/matchers/ResultType.java
new file mode 100644
index 0000000..ef24cd6
--- /dev/null
+++ b/matchers/src/main/java/org/junit/contrib/matchers/ResultType.java
@@ -0,0 +1,27 @@
+/*
+ * The copyright holders of this work license this file to You under
+ * the Apache License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.junit.contrib.matchers;
+
+/**
+ * The purpose of this private package enum is to specify
+ * four post operations callable after successful regular
+ * expression match in {@link IsRegex}.
+ *
+ * If a failure appears after calling {@link #start(java.util.regex.Matcher)}, then the
+ * method {@link #hasFailure()} returns {@code true} and the failure description is
+ * retrieved by the return from {@link #getFailureDescription()}.
+ */
+final class StartPosition extends Position {
+ private int start = -1;
+ private boolean matches, isEvaluated;
+
+ @Override
+ protected boolean isEvaluated() {
+ return isEvaluated;
+ }
+
+ StartPosition(int group, Matcher
+ *
+ * org.hamcrest.Matcher m = ...;
+ * InternalDescription d = new InternalDescription();
+ * m.describeTo(d);
+ * String failureDescription = d.toString();
+ * // use of failureDescription
+ *
+ *
+ * assertThat("Hi There!", is(like("hi|hello", new RegexProperties(CASE_INSENSITIVE)).startsAt(equalTo(0))));
+ * assertThat("Hi There!", is(like("Hi|Hello", region(0, 2))));
+ *
+ *
+ *
+ *
+ *
+ * assertThat(new ArrayIndexOutOfBoundsException(),
+ is(type(assignableTo(IndexOutOfBoundsException.class))));
+ *
+ *
+ *
+ *
+ * @Test(expected = SomeException.class)
+ * public void myTest() {
+ * (statement)
+ * (statement)
+ *
+ * This block should not throw any exception
+ * {
+ * (statement)
+ * (statement)
+ * (statement)
+ * }
+ *
+ * (statement)
+ * (statement)
+ * }
+ *
+ * assertThat()
, you can understand what it does.
+ * IsThrowing
have eight variants, where the second half deals with stack trace from the
+ * failing block to a description (output stream):
+ *
+ *
+ * throwing(Class<? extends Throwable>... ): IThrownMessage<Void, ? extends Block>
+ * throwing(Matcher<Class<? extends Throwable>): IThrownMessage<V, ? extends Callable>
+ * throwing(Matcher<? extends Throwable>): Matcher<? extends Callable>
+ * notThrowing(Class<? extends Throwable>... ): IThrownMessage<V, ? extends Callable>
+ * throwingDeeply(Class<? extends Throwable>... ): IThrownMessage<Void, ? extends Block>
+ * throwingDeeply(Matcher<Class<? extends Throwable>): IThrownMessage<V, ? extends Callable>
+ * throwingDeeply(Matcher<? extends Throwable>): Matcher<? extends Callable>
+ * notThrowingDeeply(Class<? extends Throwable>... ): IThrownMessage<V, ? extends Callable>
+ *
+ * is(not(throwing()))
is equivalent to the form is(notThrowing())
. Similar with
+ * the form of is(not(throwingDeeply()))
which is again equivalent to is(notThrowingDeeply())
.
+ * Once you use the 'Deeply', the stack trace of failed block is observed. The allOf
and
+ * anyOf
, and/or combination forms of multiple matchers would not be much readable, however still correct.
+ * Matcher<String>
or the regular expression) of thrown exception in the block.
+ * Thus, the entire expression appears in a form of assertThat(block, is(throwing().andMessage()))
.IsThrowing
matcher.
+ *
+ *
+ *
+ *
+ *
+ * Use Case of IsThrowing Explanation
+ *
+ * assertThat(block, is(throwing()))
+ * the 'block' is expected to throw any exception
+ *
+ *
+ * assertThat(block, is(throwingDeeply()))
+ * the 'block' is expected to throw any exception with block's stack trace (not an error in 'block')
+ *
+ *
+ * assertThat(block, is(notThrowing())) or assertThat(block, is(not(throwing())))
+ * the 'block' is expected not to throw exceptions at all
+ *
+ *
+ * assertThat(block, is(notThrowingDeeply())) or assertThat(block, is(not(throwingDeeply())))
+ * the 'block' is expected not to throw exceptions at all (including block's stack trace if failure in it)
+ *
+ *
+ * assertThat(block, is(throwing(ArrayIndexOutOfBoundsException.class, IndexOutOfBoundsException.class)))
+ * the 'block' is expected to throw all assignable exceptions to java.lang.ArrayIndexOutOfBoundsException and java.lang.IndexOutOfBoundsException
+ *
+ *
+ * assertThat(block, is(throwingDeeply(ArrayIndexOutOfBoundsException.class, IndexOutOfBoundsException.class)))
+ * the 'block' is expected to throw all assignable exceptions to java.lang.ArrayIndexOutOfBoundsException and java.lang.IndexOutOfBoundsException (including block's stack trace if other failure in it). If other exception is thrown, the deep stack trace appears an error in the 'block'.
+ *
+ *
+ * assertThat(block, is(notThrowing(ArrayIndexOutOfBoundsException.class, IndexOutOfBoundsException.class))) or assertThat(block, is(not(throwing(ArrayIndexOutOfBoundsException.class, IndexOutOfBoundsException.class))))
+ * the 'block' is expected to throw all exceptions except for those which are assignable to java.lang.ArrayIndexOutOfBoundsException or java.lang.IndexOutOfBoundsException
+ *
+ *
+ *
+ * assertThat(block, is(notThrowingDeeply(ArrayIndexOutOfBoundsException.class, IndexOutOfBoundsException.class))) or assertThat(block, is(not(throwingDeeply(ArrayIndexOutOfBoundsException.class, IndexOutOfBoundsException.class))))
+ * the 'block' is expected to throw all exceptions except for those which are assignable to java.lang.ArrayIndexOutOfBoundsException or java.lang.IndexOutOfBoundsException; Otherwise a stack trace appears from the 'block'
+ * TestIsThrowing
.
+ *
+ * final Integer[] array = new Integer[2];
+ * IBlock block = new IBlock() {
+ * public void run() {
+ * int i = 0;
+ * array[i++] = i;
+ * array[i++] = i;
+ * array[i++] = i;
+ * }
+ * };
+ * assertThat(block, is(throwing(ArrayIndexOutOfBoundsException.class)));
+ * array[1] = array[0];
+ *
+ * expected = {IndexOutOfBoundsException.class, ArrayStoreException.class};
+ * assertThat(block, describedAs("\n%0 <why should 0>,\n%1 <why should 1>", is(throwingDeeply(expected)), expected))
+ *
and()
, or()
matchers.
+ *
+ * List list = Collections.checkedList(Arrays.asList("b", "c"), String.class);
+ * final ListIterator it = list.listIterator();
+ * IBlock block = new IBlock() {
+ * public void run() {
+ * it.next();
+ * it.next();
+ * it.set("a");
+ * }
+ * };
+ * assertThat(block, both(is(throwingDeeply(NoSuchElementException.class))).and(is(notThrowing())));
+ *
both()
matcher would be Hamcrest's allOf()
matcher:
+ *
+ *
+ * List list = Collections.checkedList(Arrays.asList("b", "c"), String.class);
+ * final ListIterator it = list.listIterator();
+ * IBlock block = new IBlock() {
+ * public void run() {
+ * it.next();
+ * it.next();
+ * it.set("a");
+ * }
+ * };
+ * assertThat(block, allOf(is(notThrowing()), is(throwingDeeply(NoSuchElementException.class))));
+ *
allOf()
is not same as if used in
+ * both()
matcher. The both().or()
and anyOf()
can be used as an alternative in
+ * other cases as well, when the block is expected to be reused in a test case in an order within one call of
+ * assertThat()
.
+ *
+ *
+ * List list = Collections.checkedList(Arrays.asList("b", "c"), String.class);
+ * final ListIterator it = list.listIterator();
+ * IBlock block = new IBlock() {
+ * public void run() {
+ * throw new Exception(" a ny thin g ");
+ * }
+ * };
+ * assertThat(block, is(throwingDeeply().andMessage("a ny|thing")));
+ *
Matcher
combinations on a thrown message:
+ *
+ * List list = Collections.checkedList(Arrays.asList("b", "c"), String.class);
+ * final ListIterator it = list.listIterator();
+ * IBlock block = new IBlock() {
+ * public void run() {
+ * throw new Exception(" a ny thin g ");
+ * }
+ * };
+ * assertThat(block, is(throwingDeeply().andMessage(anyOf(containsString("any"), containsString("thin"), containsString("thing")))));
+ *
assertThat()
fails as soon as identifying that no exceptions are required to throw
+ * (i.e. using {@link #notThrowing(Class[])}, {@link #notThrowingDeeply(Class[])} with empty parameter list)
+ * and an expected thrown message is specified (even if null) via {@link #andMessage(org.hamcrest.Matcher)}, and
+ * {@link #andMessage(IsRegex)}.
+ *
+ *
+ *
+ *
+ * RegexProperties regexProperties = new RegexProperties(CASE_INSENSITIVE).setStartRegion(1).setEndRegion(6);
+ * assertThat("aAaBbcD", is(like("a*b", regexProperties)));
+ *