001    /*
002     * Created on Mar 3, 2007
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 @2007-2011 the original author or authors.
014     */
015    package org.fest.assertions;
016    
017    import static org.fest.assertions.ErrorMessages.*;
018    import static org.fest.assertions.Formatting.format;
019    import static org.fest.util.Collections.*;
020    
021    import java.util.*;
022    
023    import org.fest.util.IntrospectionError;
024    
025    /**
026     * Assertions for {@code Object} arrays.
027     * <p>
028     * To create a new instance of this class invoke <code>{@link Assertions#assertThat(Object[])}</code>.
029     * </p>
030     *
031     * @author Yvonne Wang
032     * @author Alex Ruiz
033     */
034    public class ObjectArrayAssert extends ObjectGroupAssert<ObjectArrayAssert, Object[]> {
035    
036      /**
037       * Creates a new </code>{@link ObjectArrayAssert}</code>.
038       * @param actual the target to verify.
039       */
040      protected ObjectArrayAssert(Object... actual) {
041        super(ObjectArrayAssert.class, actual);
042      }
043    
044      /**
045       * Verifies that all the elements in the actual {@code Object} array belong to the specified type. Matching
046       * includes subclasses of the given type.
047       * <p>
048       * For example, consider the following code listing:
049       * <pre>
050       * Number[] numbers = { 2, 6 ,8 };
051       * assertThat(numbers).hasComponentType(Integer.class);
052       * </pre>
053       * The assertion <code>hasAllElementsOfType</code> will be successful.
054       * </p>
055       * @param type the expected type.
056       * @return this assertion object.
057       * @throws NullPointerException if the given type is {@code null}.
058       * @throws AssertionError if the component type of the actual {@code Object} array is not the same as the
059       * specified one.
060       */
061      public ObjectArrayAssert hasAllElementsOfType(Class<?> type) {
062        validateIsNotNull(type);
063        isNotNull();
064        for (Object o : actual) {
065          if (type.isInstance(o)) continue;
066          failIfCustomMessageIsSet();
067          fail(format("not all elements in array:<%s> belong to the type:<%s>", actual, type));
068        }
069        return this;
070      }
071    
072      /**
073       * Verifies that at least one element in the actual {@code Object} array belong to the specified type. Matching
074       * includes subclasses of the given type.
075       * @param type the expected type.
076       * @return this assertion object.
077       * @throws AssertionError if the actual {@code Object} does not have any elements of the given type.
078       */
079      public ObjectArrayAssert hasAtLeastOneElementOfType(Class<?> type) {
080        validateIsNotNull(type);
081        isNotNull();
082        boolean found = false;
083        for (Object o : actual) {
084          if (!type.isInstance(o)) continue;
085          found = true;
086          break;
087        }
088        if (found) return this;
089        failIfCustomMessageIsSet();
090        throw failure(format("array:<%s> does not have any elements of type:<%s>", actual, type));
091      }
092    
093      private void validateIsNotNull(Class<?> type) {
094        if (type == null) throw new NullPointerException(unexpectedNullType(rawDescription()));
095      }
096    
097      /**
098       * Verifies that the actual {@code Object} array is equal to the given array. Array equality is checked by
099       * <code>{@link Arrays#deepEquals(Object[], Object[])}</code>.
100       * @param expected the given array to compare the actual array to.
101       * @return this assertion object.
102       * @throws AssertionError if the actual {@code Object} array is not equal to the given one.
103       */
104      @Override public ObjectArrayAssert isEqualTo(Object[] expected) {
105        if (Arrays.deepEquals(actual, expected)) return this;
106        failIfCustomMessageIsSet();
107        throw failure(unexpectedNotEqual(actual, expected));
108      }
109    
110      /**
111       * Verifies that the actual {@code Object} array is not equal to the given array. Array equality is checked by
112       * <code>{@link Arrays#deepEquals(Object[], Object[])}</code>.
113       * @param array the given array to compare the actual array to.
114       * @return this assertion object.
115       * @throws AssertionError if the actual {@code Object} array is equal to the given one.
116       */
117      @Override public ObjectArrayAssert isNotEqualTo(Object[] array) {
118        if (!Arrays.deepEquals(actual, array)) return this;
119        failIfCustomMessageIsSet();
120        throw failure(unexpectedEqual(actual, array));
121      }
122    
123      /**
124       * Creates a new instance of <code>{@link ObjectArrayAssert}</code> whose target array contains the values of the
125       * given property name from the elements of this {@code ObjectArrayAssert}'s array. Property access works with both
126       * simple properties like {@code Person.age} and nested properties {@code Person.father.age}.
127       * </p>
128       * <p>
129       * For example, let's say we have a array of {@code Person} objects and you want to verify their age:
130       * <pre>
131       * assertThat(persons).onProperty("age").containsOnly(25, 16, 44, 37); // simple property
132       * assertThat(persons).onProperty("father.age").containsOnly(55, 46, 74, 62); // nested property
133       * </p>
134       * @param propertyName the name of the property to extract values from the actual array to build a new
135       * {@code ObjectArrayAssert}.
136       * @return a new {@code ObjectArrayAssert} containing the values of the given property name from the elements of this
137       * {@code ObjectArrayAssert}'s array.
138       * @throws AssertionError if the actual array is {@code null}.
139       * @throws IntrospectionError if an element in the given array does not have a matching property.
140       * @since 1.3
141       */
142      @Override public ObjectArrayAssert onProperty(String propertyName) {
143        isNotNull();
144        if (actual.length == 0) return new ObjectArrayAssert(new Object[0]);
145        List<Object> values = PropertySupport.instance().propertyValues(propertyName, list(actual));
146        return new ObjectArrayAssert(values.toArray());
147      }
148    
149      /** {@inheritDoc} */
150      @Override protected Set<Object> actualAsSet() {
151        return set(actual);
152      }
153    
154      /** {@inheritDoc} */
155      @Override protected List<Object> actualAsList() {
156        return list(actual);
157      }
158    
159      /** {@inheritDoc} */
160      @Override protected int actualGroupSize() {
161        return actual.length;
162      }
163    }