All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.arpnetworking.commons.test.EqualityTestHelper Maven / Gradle / Ivy

/*
 * Copyright 2018 Inscope Metrics, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.arpnetworking.commons.test;

import com.arpnetworking.commons.builder.Builder;
import org.junit.Assert;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.Optional;

/**
 * Test utility for {@link Builder} creates instances to validate that all
 * fields set on the {@link Builder} are accessible by the corresponding getter
 * on the built instance. This is most suitable for testing POJOs where all
 * fields set on the {@link Builder} are typically copied and available on the
 * instance.
 *
 * Dependencies:
 * 
    *
  • junit:junit
  • *
* * @author Ville Koskela (ville dot koskela at inscopemetrics dot io) */ public final class EqualityTestHelper { /** * Test the equality of a pojo. The test method cannot use the default value * of each type as the alternate value for each field because the default * value may not be valid for that field. Therefore, the test method * requires two distinct and valid builder instances. * * @param builderA builder pre-populated with values all distinct from {@code builderB} * @param builderB builder pre-populated with values all distinct from {@code builderA} * @param targetClass The {@link Class} of the instance created by the builder. * @param The type built by the builder. * @throws InvocationTargetException if a setter or getter call throws an exception * @throws IllegalAccessException if a setter or getter is inaccessible */ public static void testEquality( final Builder builderB, final Builder builderA, final Class targetClass) throws InvocationTargetException, IllegalAccessException { // The type's of the two builders must be the same @SuppressWarnings("unchecked") final Class> builderAClass = (Class>) builderA.getClass(); @SuppressWarnings("unchecked") final Class> builderBClass = (Class>) builderB.getClass(); Assert.assertEquals(builderAClass, builderBClass); // Both builders must produce valid instances final Object objectA = builderA.build(); final Object objectB = builderB.build(); // Test the simple equality cases // NOTE: Do not use Objects.equals here to ensure that the actual equals method is exercised Assert.assertTrue("Self equality failed", objectA.equals(objectA)); Assert.assertTrue("Clone equality failed", objectA.equals(builderA.build())); Assert.assertFalse("Null inequality failed", objectA.equals(null)); Assert.assertFalse("Type inequality failed", objectA.equals(new Object())); // While we're here let's just check the hash codes of two separate but identical instances are the same Assert.assertEquals("Equal instance hashcodes differ", objectA.hashCode(), builderA.build().hashCode()); // Create permutations of objectA using each field value from objectB and test field by field inequality for (final Method method : builderAClass.getMethods()) { if (method.getName().startsWith(SETTER_PREFIX) && Builder.class.isAssignableFrom(method.getReturnType()) && method.getParameters().length == 1 && !method.isVarArgs()) { // Find the matching getter final Optional getter = getterForSetter(targetClass, method); Assert.assertTrue("Getter not found for setter: " + method, getter.isPresent()); // Set the value from B on builder for A getter.get().setAccessible(true); final Object originalValue = getter.get().invoke(objectA); final Object alternateValue = getter.get().invoke(objectB); method.invoke(builderA, unwrapOptional(alternateValue)); // Create a variation of objectA with a single field from objectB final Object alternatePojo = builderA.build(); // Assert that they are not equal Assert.assertFalse("Pojo inequality failed for: " + getter, Objects.equals(objectA, alternatePojo)); // Restore the value from objectA on builder for objectA method.invoke(builderA, unwrapOptional(originalValue)); } } } private static Object unwrapOptional(final Object object) { if (object instanceof Optional) { final Optional optional = (Optional) object; return optional.orElse(null); } return object; } private static Optional getterForSetter(final Class targetClass, final Method setter) { final String getterName = GETTER_PREFIX + setter.getName().substring(SETTER_PREFIX.length()); Class clazz = targetClass; while (clazz != null) { try { return Optional.of(clazz.getDeclaredMethod(getterName)); } catch (final NoSuchMethodException e) { clazz = clazz.getSuperclass(); } } return Optional.empty(); } private EqualityTestHelper() {} private static final String SETTER_PREFIX = "set"; private static final String GETTER_PREFIX = "get"; }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy