001    /*
002     * Created on Nov 18, 2010
003     * 
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
005     * 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 is distributed on
010     * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
011     * specific language governing permissions and limitations under the License.
012     * 
013     * Copyright @2010-2011 the original author or authors.
014     */
015    package org.fest.assertions.api;
016    
017    import java.util.Comparator;
018    
019    import org.fest.assertions.core.Assert;
020    import org.fest.assertions.core.Condition;
021    import org.fest.assertions.core.WritableAssertionInfo;
022    import org.fest.assertions.description.Description;
023    import org.fest.assertions.internal.Conditions;
024    import org.fest.assertions.internal.Objects;
025    import org.fest.util.ComparatorBasedComparisonStrategy;
026    import org.fest.util.VisibleForTesting;
027    
028    
029    /**
030     * Base class for all assertions.
031     * @param <S> the "self" type of this assertion class. Please read &quot;<a href="http://bit.ly/anMa4g"
032     *          target="_blank">Emulating 'self types' using Java Generics to simplify fluent API implementation</a>&quot;
033     *          for more details.
034     * @param <A> the type of the "actual" value.
035     * 
036     * @author Alex Ruiz
037     * @author Joel Costigliola
038     * @author Mikhail Mazursky
039     * @author Nicolas François
040     */
041    public abstract class AbstractAssert<S extends AbstractAssert<S, A>, A> implements Assert<S, A> {
042    
043      @VisibleForTesting
044      Objects objects = Objects.instance();
045      
046      @VisibleForTesting
047      Conditions conditions = Conditions.instance();
048    
049      @VisibleForTesting
050      final WritableAssertionInfo info;
051      
052      // visibility is protected to allow us write custom assertions that need access to actual
053      @VisibleForTesting
054      protected final A actual;
055      protected final S myself;
056    
057      // we prefer not to use Class<? extends S> selfType because it would force inherited 
058      // constructor to cast with a compiler warning 
059      // let's keep compiler warning internal to fest (when we can) and not expose them to our end users.
060      @SuppressWarnings("unchecked")
061      protected AbstractAssert(A actual, Class<?> selfType) {
062        myself = (S) selfType.cast(this);
063        this.actual = actual;
064        info = new WritableAssertionInfo();
065      }
066    
067      /** {@inheritDoc} */
068      public final S as(String description) {
069        return describedAs(description);
070      }
071    
072      /** {@inheritDoc} */
073      public final S as(Description description) {
074        return describedAs(description);
075      }
076    
077      /** {@inheritDoc} */
078      public final S describedAs(String description) {
079        info.description(description);
080        return myself;
081      }
082    
083      /** {@inheritDoc} */
084      public final S describedAs(Description description) {
085        info.description(description);
086        return myself;
087      }
088    
089      /** {@inheritDoc} */
090      public S isEqualTo(A expected) {
091        objects.assertEqual(info, actual, expected);
092        return myself;
093      }
094    
095      /** {@inheritDoc} */
096      public S isNotEqualTo(A other) {
097        objects.assertNotEqual(info, actual, other);
098        return myself;
099      }
100    
101      /** {@inheritDoc} */
102      public final void isNull() {
103        objects.assertNull(info, actual);
104      }
105    
106      /** {@inheritDoc} */
107      public final S isNotNull() {
108        objects.assertNotNull(info, actual);
109        return myself;
110      }
111    
112      /** {@inheritDoc} */
113      public final S isSameAs(A expected) {
114        objects.assertSame(info, actual, expected);
115        return myself;
116      }
117    
118      /** {@inheritDoc} */
119      public final S isNotSameAs(A other) {
120        objects.assertNotSame(info, actual, other);
121        return myself;
122      }
123    
124      /** {@inheritDoc} */
125      public final S isIn(A... values) {
126        objects.assertIsIn(info, actual, values);
127        return myself;
128      }
129    
130      /** {@inheritDoc} */
131      public final S isNotIn(A... values) {
132        objects.assertIsNotIn(info, actual, values);
133        return myself;
134      }
135    
136      /** {@inheritDoc} */
137      public final S isIn(Iterable<? extends A> values) {
138        objects.assertIsIn(info, actual, values);
139        return myself;
140      }
141    
142      /** {@inheritDoc} */
143      public final S isNotIn(Iterable<? extends A> values) {
144        objects.assertIsNotIn(info, actual, values);
145        return myself;
146      }
147    
148      /** {@inheritDoc} */
149      public final S is(Condition<A> condition) {
150        conditions.assertIs(info, actual, condition);
151        return myself;
152      }
153    
154      /** {@inheritDoc} */
155      public final S isNot(Condition<A> condition) {
156        conditions.assertIsNot(info, actual, condition);
157        return myself;
158      }
159    
160      /** {@inheritDoc} */
161      public final S has(Condition<A> condition) {
162        conditions.assertHas(info, actual, condition);
163        return myself;
164      }
165    
166      /** {@inheritDoc} */
167      public final S doesNotHave(Condition<A> condition) {
168        conditions.assertDoesNotHave(info, actual, condition);
169        return myself;
170      }
171    
172      /**
173       * The description of this assertion set with {@link #describedAs(String)} or {@link #describedAs(Description)}.
174       * @return the description String representation of this assertion. 
175       */
176      public final String descriptionText() {
177        return info.descriptionText();
178      }
179    
180      /** {@inheritDoc} */
181      public S usingComparator(Comparator<?> customComparator) {  
182        // using a specific strategy to compare actual with other objects.
183        this.objects = new Objects(new ComparatorBasedComparisonStrategy(customComparator));
184        return myself;
185      }
186    
187      /** {@inheritDoc} */
188      public S usingDefaultComparator() {  
189        // fall back to default strategy to compare actual with other objects.
190        this.objects = Objects.instance();
191        return myself;
192      }
193      
194      /** {@inheritDoc} */
195      @Override 
196      public final boolean equals(Object obj) {
197        throw new UnsupportedOperationException("'equals' is not supported...maybe you intended to call 'isEqualTo'");
198      }  
199      
200      /**
201       * Always returns 1.
202       * @return 1.
203       */
204      @Override 
205      public final int hashCode() { 
206              return 1;
207      }  
208      
209    }