blob: 0e5ccfcafd67bf125a6952fdc5ef1da06ca8315f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.onlab.junit;
import org.hamcrest.Description;
import org.hamcrest.StringDescription;
import org.onlab.junit.TestUtils.TestUtilsException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* Hamcrest style class for verifying that a class follows the
* accepted rules for utility classes.
*
* The rules that are enforced for utility classes:
* - the class must be declared final
* - the class must have only one constructor
* - the constructor must be private and inaccessible to callers
* - the class must have only static methods
*/
public class UtilityClassChecker {
private String failureReason = "";
/**
* Method to determine if a given class is a properly specified
* utility class. In addition to checking that the class meets the criteria
* for utility classes, an object of the class type is allocated to force
* test code coverage onto the class constructor.
*
* @param clazz the class to check
* @return true if the given class is a properly specified utility class.
*/
private boolean isProperlyDefinedUtilityClass(Class<?> clazz) {
// class must be declared final
if (!Modifier.isFinal(clazz.getModifiers())) {
failureReason = "a class that is not final";
return false;
}
// class must have only one constructor
final Constructor<?>[] constructors = clazz.getDeclaredConstructors();
if (constructors.length != 1) {
failureReason = "a class with more than one constructor";
return false;
}
// constructor must not be accessible outside of the class
final Constructor<?> constructor = constructors[0];
if (constructor.isAccessible()) {
failureReason = "a class with an accessible default constructor";
return false;
}
// constructor must be private
if (!Modifier.isPrivate(constructor.getModifiers())) {
failureReason = "a class with a default constructor that is not private";
return false;
}
// class must have only static methods
for (final Method method : clazz.getMethods()) {
if (method.getDeclaringClass().equals(clazz)) {
if (!Modifier.isStatic(method.getModifiers())) {
failureReason = "a class with one or more non-static methods";
return false;
}
}
}
try {
final Object newObject = TestUtils.callConstructor(constructor);
if (newObject == null) {
failureReason = "could not instantiate a new object";
return false;
}
} catch (TestUtilsException e) {
failureReason = "could not instantiate a new object";
return false;
}
return true;
}
/**
* Describe why an error was reported. Uses Hamcrest style Description
* interfaces.
*
* @param description the Description object to use for reporting the
* mismatch
*/
public void describeMismatch(Description description) {
description.appendText(failureReason);
}
/**
* Describe the source object that caused an error, using a Hamcrest
* Matcher style interface. In this case, it always returns
* that we are looking for a properly defined utility class.
*
* @param description the Description object to use to report the "to"
* object
*/
public void describeTo(Description description) {
description.appendText("a properly defined utility class");
}
/**
* Assert that the given class adheres to the utility class rules.
*
* @param clazz the class to check
*
* @throws java.lang.AssertionError if the class is not a valid
* utility class
*/
public static void assertThatClassIsUtility(Class<?> clazz) {
final UtilityClassChecker checker = new UtilityClassChecker();
if (!checker.isProperlyDefinedUtilityClass(clazz)) {
final Description toDescription = new StringDescription();
final Description mismatchDescription = new StringDescription();
checker.describeTo(toDescription);
checker.describeMismatch(mismatchDescription);
final String reason =
"\n" +
"Expected: is \"" + toDescription.toString() + "\"\n" +
" but : was \"" + mismatchDescription.toString() + "\"";
throw new AssertionError(reason);
}
}
}