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

name.didier.david.test4j.assertions.CodingStandardClassAssert Maven / Gradle / Ivy

The newest version!
package name.didier.david.test4j.assertions;

import static java.lang.reflect.Modifier.isPrivate;
import static java.lang.reflect.Modifier.isProtected;
import static java.lang.reflect.Modifier.isPublic;
import static java.lang.reflect.Modifier.isStatic;

import static com.google.common.base.Throwables.throwIfUnchecked;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

import org.assertj.core.api.AbstractClassAssert;

/**
 * {@link Class} assertions enforcing coding standard, using AssertJ.
 *
 * @author ddidier
 */
public class CodingStandardClassAssert
        extends AbstractClassAssert {

    /**
     * Creates a new assertion for the given class.
     *
     * @param actual the class under test.
     */
    protected CodingStandardClassAssert(final Class actual) {
        super(actual, CodingStandardClassAssert.class);
    }

    /**
     * Verifies that the actual {@code Class} is a well formed abstract class. This method checks that the class is not
     * final, has no public constructor and at least one protected constructor.
     *
     * @return this assertion object.
     * @throws AssertionError if {@code actual} is {@code null}.
     * @throws AssertionError if the actual {@code Class} is final.
     * @throws AssertionError if the actual {@code Class} has a public constructor.
     * @throws AssertionError if the actual {@code Class} has not a protected constructor.
     */
    public CodingStandardClassAssert isAbstract() {
        isNotNull();
        isNotFinal();

        checkHasNoPublicConstructor();
        checkHasProtectedConstructor();

        return this;
    }

    /**
     * Verifies that the actual {@code Class} is a well formed utility class. This method checks that the class is
     * final, has a single private constructor and has only static methods. From
     * http://stackoverflow.com/questions/4520216/how-to-add-test-coverage-to-a-private-constructor.
     *
     * @return this assertion object.
     * @throws AssertionError if {@code actual} is {@code null}.
     * @throws AssertionError if the actual {@code Class} is not final.
     * @throws AssertionError if the actual {@code Class} has more than a single constructor.
     * @throws AssertionError if the actual {@code Class} has not a private constructor.
     * @throws AssertionError if the actual {@code Class} has not only static methods.
     */
    public CodingStandardClassAssert isUtility() {
        isNotNull();
        isFinal();

        try {
            checkHasSingleConstructor();
            checkIsPrivate(actual.getDeclaredConstructor());
            checkInstanciation(actual.getDeclaredConstructor());
            checkHasOnlyStaticMethods();
        } catch (Exception e) {
            // OK to catch Exception here
            throwIfUnchecked(e);
            throw new RuntimeException(e);
        }

        return this;
    }

    // -----------------------------------------------------------------------------------------------------------------

    /**
     * Asserts that the actual class has a single constructor.
     *
     * @throws AssertionError if {@code actual} has more than one constructor.
     */
    private void checkHasSingleConstructor() {
        int constructorCount = actual.getDeclaredConstructors().length;

        if (constructorCount > 1) {
            failWithMessage("Expected %s to have only one constructor but had %s", actual, constructorCount);
        }
    }

    /**
     * Asserts that the given constructor is private.
     *
     * @param constructor the constructor under test.
     * @throws AssertionError if the given constructor is not private.
     */
    private void checkIsPrivate(final Constructor constructor) {
        if (constructor.isAccessible() || !isPrivate(constructor.getModifiers())) {
            failWithMessage("Expected %s to have a single private constructor", actual);
        }
    }

    /**
     * Asserts that the given constructor can be used.
     *
     * @param constructor the constructor under test.
     * @throws AssertionError if the given constructor cannot be used.
     */
    private void checkInstanciation(final Constructor constructor) {
        try {
            constructor.setAccessible(true);
            constructor.newInstance();
        } catch (Exception e) {
            // OK to catch Exception here
            String exceptionName = e.getClass().getName();
            failWithMessage("Expected %s to have a usable constructor but it raised %s", actual, exceptionName);
        } finally {
            constructor.setAccessible(false);
        }
    }

    /**
     * Asserts that the actual class has only static methods.
     *
     * @throws AssertionError if the actual class has an instance method.
     */
    private void checkHasOnlyStaticMethods() {
        for (Method method : actual.getMethods()) {
            if (!isStatic(method.getModifiers()) && method.getDeclaringClass().equals(actual)) {
                failWithMessage("Expected %s to have only static methods but has '%s'", actual, method.getName());
            }
        }
    }

    /**
     * Asserts that the actual class has a protected constructor.
     *
     * @throws AssertionError if {@code actual} has no protected constructor.
     */
    private void checkHasProtectedConstructor() {
        for (Constructor constructor : actual.getDeclaredConstructors()) {
            if (isProtected(constructor.getModifiers())) {
                return;
            }
        }
        failWithMessage("Expected %s to have a protected constructor", actual);
    }

    /**
     * Asserts that the actual class has no public constructor.
     *
     * @throws AssertionError if {@code actual} has a public constructor.
     */
    private void checkHasNoPublicConstructor() {
        for (Constructor constructor : actual.getDeclaredConstructors()) {
            if (isPublic(constructor.getModifiers())) {
                failWithMessage("Expected %s to not have a public constructor", actual);
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy