001/**
002 * Copyright (C) 2011 rwoo@gmx.de
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *         http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package com.googlecode.catchexception.throwable.apis;
017
018import org.hamcrest.Matcher;
019import org.junit.matchers.JUnitMatchers;
020
021import com.googlecode.catchexception.throwable.apis.internal.hamcrest.ThrowableMessageMatcher;
022import com.googlecode.catchexception.throwable.apis.internal.hamcrest.ThrowableNoCauseMatcher;
023
024/**
025 * Provides some Hamcrest {@link Matcher matchers} to match some {@link Throwable throwable} properties.
026 * <p>
027 * EXAMPLE: <code><pre class="prettyprint lang-java">// given an empty list
028List myList = new ArrayList();
029
030// when we try to get the first element of the list
031catchThrowable(myList).get(1);
032
033// then we expect an IndexOutOfBoundsThrowable with message "Index: 1, Size: 0" 
034assertThat(caughtThrowable(),
035  allOf(
036    is(IndexOutOfBoundsThrowable.class), 
037    hasMessage("Index: 1, Size: 0"),
038    hasNoCause()
039  )
040);</pre></code>
041 * <p>
042 * To combine the standard Hamcrest matchers, your custom matchers, these matchers, and other matcher collections (as
043 * {@link JUnitMatchers}) in a single class follow the instructions outlined in <a
044 * href="http://code.google.com/p/hamcrest/wiki/Tutorial#Sugar_generation">Sugar generation</a>.
045 * <p>
046 * Hint: This class might use <a href="http://code.google.com/p/hamsandwich">hamsandwich</a> in the future but as long
047 * as hamsandwich is not in any public maven repository, this class will not use hamsandwich.
048 * 
049 * @author rwoo
050 * @since 1.2.0
051 */
052public class CatchThrowableHamcrestMatchers {
053
054    /**
055     * EXAMPLE:
056     * <code><pre class="prettyprint lang-java">assertThat(caughtThrowable(), hasMessage("Index: 9, Size: 9"));</pre></code>
057     * 
058     * @param <T>
059     *            the throwable subclass
060     * @param expectedMessage
061     *            the expected throwable message
062     * @return Returns a matcher that matches an throwable if it has the given message.
063     */
064    public static <T extends Throwable> org.hamcrest.Matcher<T> hasMessage(String expectedMessage) {
065        return new ThrowableMessageMatcher<T>(expectedMessage);
066    }
067
068    /**
069     * EXAMPLES:
070     * <code><pre class="prettyprint lang-java">assertThat(caughtThrowable(), hasMessageThat(is("Index: 9, Size: 9")));
071assertThat(caughtThrowable(), hasMessageThat(containsString("Index: 9"))); // using JUnitMatchers
072assertThat(caughtThrowable(), hasMessageThat(containsPattern("Index: \\d+"))); // using Mockito's Find</pre></code>
073     * 
074     * @param <T>
075     *            the throwable subclass
076     * @param stringMatcher
077     *            a string matcher
078     * @return Returns a matcher that matches an throwable if the given string matcher matches the throwable message.
079     */
080    public static <T extends Throwable> org.hamcrest.Matcher<T> hasMessageThat(Matcher<String> stringMatcher) {
081        return new ThrowableMessageMatcher<T>(stringMatcher);
082    }
083
084    /**
085     * EXAMPLE: <code><pre class="prettyprint lang-java">assertThat(caughtThrowable(), hasNoCause());</pre></code>
086     * 
087     * @param <T>
088     *            the throwable subclass
089     * @return Returns a matcher that matches the throwable if it does not have a {@link Throwable#getCause() cause}.
090     */
091    public static <T extends Throwable> org.hamcrest.Matcher<T> hasNoCause() {
092        return new ThrowableNoCauseMatcher<T>();
093    }
094
095}