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 }