001    /*
002     * Created on Feb 7, 2008
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005     * in compliance with the License. You may obtain a copy of the License at
006     *
007     * http://www.apache.org/licenses/LICENSE-2.0
008     *
009     * Unless required by applicable law or agreed to in writing, software distributed under the License
010     * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011     * or implied. See the License for the specific language governing permissions and limitations under
012     * the License.
013     *
014     * Copyright @2008-2009 the original author or authors.
015     */
016    package org.fest.test;
017    
018    import static org.fest.util.Objects.areEqual;
019    import static org.fest.util.Strings.concat;
020    import static org.fest.util.Strings.quote;
021    
022    /**
023     * Understands executing test code that is expected to fail.
024     *
025     * @author Alex Ruiz
026     * @author Yvonne Wang
027     */
028    public final class ExpectedFailure {
029    
030      private final Class<? extends Throwable> errorType;
031    
032      /**
033       * Specifies the expected failure message type.
034       * @param errorType the expected failure message type.
035       * @return a holder for the expected failure message type.
036       */
037      public static ExpectedFailure expect(Class<? extends Throwable> errorType) {
038        return new ExpectedFailure(errorType);
039      }
040    
041      /**
042       * Specifies the expected message of an expected <code>{@link AssertionError}</code>.
043       * @param message the expected failure message.
044       * @return a holder of the expected failure message.
045       */
046      public static Message expectAssertionError(String message) {
047        return new ExpectedFailure(AssertionError.class).withMessage(message);
048      }
049    
050      /**
051       * Specifies the expected failure message.
052       * @param message the expected failure message.
053       * @return a holder of the expected failure message.
054       */
055      public Message withMessage(String message) {
056        return new Message(errorType, message);
057      }
058    
059      /**
060       * Understands executing test code that is expected to fail.
061       *
062       * @author Alex Ruiz
063       * @author Yvonne Wang
064       */
065      public static class Message {
066        private final Class<? extends Throwable> errorType;
067        private final String message;
068    
069        Message(Class<? extends Throwable> errorType, String message) {
070          this.errorType = errorType;
071          this.message = message;
072        }
073    
074        /**
075         * Executes the given code to test.
076         * @param codeToTest the code to test.
077         * @throws AssertionError if an exception of the expected type is never thrown by the code to test.
078         * @throws AssertionError if the type of the thrown exception is different than the expected type.
079         * @throws AssertionError if the message of the thrown exception is different than the expected message.
080         */
081        public void on(CodeToTest codeToTest) {
082          try {
083            codeToTest.run();
084            fail(concat("Expecting a thrown exception of type:<", errorTypeName(), ">"));
085          } catch (Throwable t) {
086            if (!errorType.isInstance(t))
087              fail(concat("Expecting exception of type:<", errorTypeName(), "> but was:<", t.getClass().getName(), ">"));
088            if (!areEqual(message, t.getMessage()))
089              fail(concat("Expecting message:<", quote(message), "> but was:<", quote(t.getMessage()), ">"));
090          }
091        }
092    
093        private String errorTypeName() {
094          return errorType.getName();
095        }
096    
097        private void fail(String failureMessage) {
098          throw new AssertionError(failureMessage);
099        }
100      }
101    
102      private ExpectedFailure(Class<? extends Throwable> error) {
103        this.errorType = error;
104      }
105    }