    001    /*  Copyright (c) 2000-2006 hamcrest.org
    002     */
    003    package org.hamcrest.core;
    004
    005    import org.hamcrest.BaseMatcher;
    006    import org.hamcrest.Description;
    007    import org.hamcrest.Factory;
    008    import org.hamcrest.Matcher;
    009
    010    import java.util.regex.Pattern;
    011
    012    import static java.lang.Integer.parseInt;
    013
    014    /**
    015     * Provides a custom description to another matcher.
    016     */
    017    public class DescribedAs<T> extends BaseMatcher<T> {
    018        private final String descriptionTemplate;
    019        private final Matcher<T> matcher;
    020        private final Object[] values;
    021
    022        private final static Pattern ARG_PATTERN = Pattern.compile("%([0-9]+)");
    023
    024        public DescribedAs(String descriptionTemplate, Matcher<T> matcher, Object[] values) {
    025            this.descriptionTemplate = descriptionTemplate;
    026            this.matcher = matcher;
    027            this.values = values.clone();
    028        }
    029
    030        @Override
    031        public boolean matches(Object o) {
    032            return matcher.matches(o);
    033        }
    034
    035        @Override
    036        public void describeTo(Description description) {
    037            java.util.regex.Matcher arg = ARG_PATTERN.matcher(descriptionTemplate);
    038
    039            int textStart = 0;
    040            while (arg.find()) {
    041                description.appendText(descriptionTemplate.substring(textStart, arg.start()));
    042                description.appendValue(values[parseInt(arg.group(1))]);
    043                textStart = arg.end();
    044            }
    045
    046            if (textStart < descriptionTemplate.length()) {
    047                description.appendText(descriptionTemplate.substring(textStart));
    048            }
    049        }
    050
    051        @Override
    052        public void describeMismatch(Object item, Description description) {
    053            matcher.describeMismatch(item, description);
    054        }
    055
    056        /**
    057         * Wraps an existing matcher, overriding its description with that specified.  All other functions are
    058         * delegated to the decorated matcher, including its mismatch description.
    059         * <p/>
    060         * For example:
    061         * <pre>describedAs("a big decimal equal to %0", equalTo(myBigDecimal), myBigDecimal.toPlainString())</pre>
    062         *
    063         * @param description
    064         *     the new description for the wrapped matcher
    065         * @param matcher
    066         *     the matcher to wrap
    067         * @param values
    068         *     optional values to insert into the tokenised description
    069         */
    070        @Factory
    071        public static <T> Matcher<T> describedAs(String description, Matcher<T> matcher, Object... values) {
    072            return new DescribedAs<T>(description, matcher, values);
    073        }
    074    }