1 package org.hamcrest.core; 2 3 import org.hamcrest.BaseMatcher; 4 import org.hamcrest.Description; 5 import org.hamcrest.Matcher; 6 7 import java.util.regex.Pattern; 8 9 import static java.lang.Integer.parseInt; 10 11 /** 12 * Provides a custom description to another matcher. 13 */ 14 public class DescribedAs<T> extends BaseMatcher<T> { 15 private final String descriptionTemplate; 16 private final Matcher<T> matcher; 17 private final Object[] values; 18 19 private final static Pattern ARG_PATTERN = Pattern.compile("%([0-9]+)"); 20 21 public DescribedAs(String descriptionTemplate, Matcher<T> matcher, Object[] values) { 22 this.descriptionTemplate = descriptionTemplate; 23 this.matcher = matcher; 24 this.values = values.clone(); 25 } 26 27 @Override 28 public boolean matches(Object o) { 29 return matcher.matches(o); 30 } 31 32 @Override 33 public void describeTo(Description description) { 34 java.util.regex.Matcher arg = ARG_PATTERN.matcher(descriptionTemplate); 35 36 int textStart = 0; 37 while (arg.find()) { 38 description.appendText(descriptionTemplate.substring(textStart, arg.start())); 39 description.appendValue(values[parseInt(arg.group(1))]); 40 textStart = arg.end(); 41 } 42 43 if (textStart < descriptionTemplate.length()) { 44 description.appendText(descriptionTemplate.substring(textStart)); 45 } 46 } 47 48 @Override 49 public void describeMismatch(Object item, Description description) { 50 matcher.describeMismatch(item, description); 51 } 52 53 /** 54 * Wraps an existing matcher, overriding its description with that specified. All other functions are 55 * delegated to the decorated matcher, including its mismatch description. 56 * For example: 57 * <pre>describedAs("a big decimal equal to %0", equalTo(myBigDecimal), myBigDecimal.toPlainString())</pre> 58 * 59 * @param description 60 * the new description for the wrapped matcher 61 * @param matcher 62 * the matcher to wrap 63 * @param values 64 * optional values to insert into the tokenised description 65 */ 66 public static <T> Matcher<T> describedAs(String description, Matcher<T> matcher, Object... values) { 67 return new DescribedAs<T>(description, matcher, values); 68 } 69 } 70