claz) {
var ncons = 0;
ncons += testDefault(claz);
ncons += testString(claz);
ncons += testThrowable(claz);
ncons += testStringThrowable(claz);
ncons += testStringThrowableBooleanBoolean(claz);
return ncons;
}
/**
* Tests Throwable objects created via the default constructor. Verifies
* that:
*
* - toString() returns a non-null value
* - getMessage() returns null
* - getCause() returns null
*
*
* If the Throwable subclass does not support this type of
* constructor, then this method simply returns.
*
* @param claz subclass to be tested
* @param to be defined
* @return {@code 1}, if the subclass supports this type of constructor,
* {@code 0} otherwise
* @throws ConstructionError
* if the Throwable subclass cannot be constructed
* @throws AssertionError
* if the constructed objects fail to pass various tests
*/
public final int testDefault(
final Class claz) {
Constructor cons = getConstructor(claz, "default");
if (cons == null) {
return 0;
}
var ex = newInstance(cons);
assertNotNull(ex.toString());
assertNull(ex.getMessage());
assertNull(ex.getCause());
return 1;
}
/**
* Tests Throwable objects created via the constructor that takes just a
* String. Verifies that:
*
* - toString() returns a non-null value
* - getMessage() returns the original message passed to the
* constructor
* - getCause() returns null
*
*
* If the Throwable subclass does not support this type of constructor,
* then this method simply returns.
*
* @param claz
* subclass to be tested
* @param to be defined
* @return {@code 1}, if the subclass supports this type of constructor,
* {@code 0} otherwise
* @throws ConstructionError
* if the Throwable subclass cannot be constructed
* @throws AssertionError
* if the constructed objects fail to pass various tests
*/
public final int testString(final Class claz) {
Constructor cons = getConstructor(claz, "string",
String.class);
if (cons == null) {
return 0;
}
var ex = newInstance(cons, "hello");
assertNotNull(ex.toString());
assertEquals("hello", ex.getMessage());
assertNull(ex.getCause());
return 1;
}
/**
* Tests Throwable objects created via the constructor that takes just a
* Throwable. Verifies that:
*
* - toString() returns a non-null value
* - getMessage() returns the cause's message
* - getCause() returns the original cause passed to the
* constructor
*
*
* If the Throwable subclass does not support this type of constructor,
* then this method simply returns.
*
* @param claz
* subclass to be tested
* @param to be defined
* @return {@code 1}, if the subclass supports this type of constructor,
* {@code 0} otherwise
* @throws ConstructionError
* if the Throwable subclass cannot be constructed
* @throws AssertionError
* if the constructed objects fail to pass various tests
*/
public final int testThrowable(
final Class claz) {
Constructor cons = getConstructor(claz, "throwable",
Throwable.class);
if (cons == null) {
return 0;
}
var ex = newInstance(cons, CAUSE);
assertEquals(ex.getMessage(), ex.getMessage());
assertNotNull(ex.toString());
assertEquals(CAUSE, ex.getCause());
return 1;
}
/**
* Tests Throwable objects created via the constructor that takes
* a String and a Throwable. Verifies that:
*
* - toString() returns a non-null value
* - getMessage() returns the original message passed to the
* constructor
* - getCause() returns the original cause passed to the
* constructor
*
*
* If the Throwable subclass does not support this type of constructor,
* then this method simply returns.
*
* @param claz subclass to be tested
* @param to be defined
* @return {@code 1}, if the subclass supports this type of constructor,
* {@code 0} otherwise
* @throws ConstructionError
* if the Throwable subclass cannot be constructed
* @throws AssertionError
* if the constructed objects fail to pass various tests
*/
public final int testStringThrowable(
final Class claz) {
Constructor cons = getConstructor(claz, "string-throwable",
String.class, Throwable.class);
if (cons == null) {
return 0;
}
var ex = newInstance(cons, "world", CAUSE);
assertNotNull(ex.toString());
assertEquals("world", ex.getMessage());
assertEquals(CAUSE, ex.getCause());
return 1;
}
/**
* Tests Throwable objects created via the constructor that takes
* a String, a Throwable, and two booleans. Verifies that:
*
* - toString() returns a non-null value
* - getMessage() returns the original message passed to the
* constructor
* - getCause() returns the original cause passed to the
* constructor
* - suppressed exceptions can be added, if enabled
* - the stack trace can be added, if enabled
*
*
* If the Throwable subclass does not support this type of constructor,
* then this method simply returns.
*
* @param claz
* subclass to be tested
* @param to be defined
* @return {@code 1}, if the subclass supports this type of constructor,
* {@code 0} otherwise
* @throws ConstructionError
* if the Throwable subclass cannot be constructed
* @throws AssertionError
* if the constructed objects fail to pass various tests
*/
public final int
testStringThrowableBooleanBoolean(
final Class claz) {
Constructor cons = getConstructor(claz,
"string-throwable-flags",
String.class, Throwable.class,
Boolean.TYPE, Boolean.TYPE);
if (cons == null) {
return 0;
}
// test each combination of "message" and "cause"
testMessageCauseCombos(cons);
// test each combination of the boolean flags
testSuppressStack(cons);
testSuppressNoStack(cons);
testNoSuppressStack(cons);
testNoSuppressNoStack(cons);
return 1;
}
/**
* Tests each combination of values for the "message" and the "cause"
* when using the constructor that takes a String,
* a Throwable/Exception, and two booleans. Verifies that expected
* values are returned
*
* toString(),
* getMessage(), and getCause().
*
*
* @param cons
* constructor to be invoked
* @param to be defined
* @throws ConstructionError
* if the Throwable subclass cannot be constructed
* @throws AssertionError
* if the constructed objects fail to pass various tests
*/
public final void testMessageCauseCombos(
final Constructor cons) {
T ex;
ex = newInstance(cons, null, null, true, true);
assertNotNull(ex.toString());
assertNull(ex.getMessage());
assertNull(ex.getCause());
ex = newInstance(cons, "abc", null, true, true);
assertNotNull(ex.toString());
assertEquals("abc", ex.getMessage());
assertNull(ex.getCause());
ex = newInstance(cons, null, CAUSE, true, true);
assertNotNull(ex.toString());
assertNull(ex.getMessage());
assertEquals(CAUSE, ex.getCause());
ex = newInstance(cons, "xyz", CAUSE, true, true);
assertNotNull(ex.toString());
assertEquals("xyz", ex.getMessage());
assertEquals(CAUSE, ex.getCause());
}
/**
* Tests each combination of values for the "message" and the
* "cause" when using the constructor that takes a String,
* a Throwable/Exception, and two booleans. Verifies that
* expected values are returned by
*
* toString(),
* getMessage(), and getCause().
*
*
* @param cons
* constructor to be invoked
* @param to be defined
* @throws ConstructionError
* if the Throwable subclass cannot be constructed
* @throws AssertionError
* if the constructed objects fail to pass various tests
*/
public final void testFlagCombos(
final Constructor cons) {
testSuppressStack(cons);
testSuppressNoStack(cons);
testNoSuppressStack(cons);
testNoSuppressNoStack(cons);
}
/**
* Tests Throwable objects constructed with
* {@code enableSuppression=true} and
* {@code writableStackTrace=true}. Verifies that:
*
* - toString() returns a non-null value
* - getMessage() returns the original message passed to the
* constructor
* - getCause() returns the original cause passed to the
* constructor
* - suppressed exceptions are added
* - the stack trace is added
*
*
* @param cons
* the throwable's class constructor
* @param to be defined
* @throws ConstructionError
* if the Throwable subclass cannot be constructed
* @throws AssertionError
* if the constructed objects fail to pass various tests
*/
public final void testSuppressStack(
final Constructor cons) {
var ex = newInstance(cons, "yes,yes", CAUSE, true, true);
ex.addSuppressed(SUPPRESSED);
assertNotNull(ex.toString());
assertEquals("yes,yes", ex.getMessage());
assertEquals(CAUSE, ex.getCause());
assertEquals(1, ex.getSuppressed().length);
assertEquals(SUPPRESSED, ex.getSuppressed()[0]);
assertTrue(ex.getStackTrace().length > 0);
}
/**
* Tests Throwable objects constructed with
* {@code enableSuppression=true} and
* {@code writableStackTrace=false}. Verifies that:
*
* - toString() returns a non-null value
* - getMessage() returns the original message passed to the
* constructor
* - getCause() returns the original cause passed to the
* constructor
* - suppressed exceptions are added
* - the stack trace is not added
*
*
* @param cons
* the throwable's class constructor
* @param to be defined
* @throws ConstructionError
* if the Throwable subclass cannot be constructed
* @throws AssertionError
* if the constructed objects fail to pass various tests
*/
public final void testSuppressNoStack(
final Constructor cons) {
var ex = newInstance(cons, "yes,no", CAUSE, true, false);
ex.addSuppressed(SUPPRESSED);
assertNotNull(ex.toString());
assertEquals("yes,no", ex.getMessage());
assertEquals(CAUSE, ex.getCause());
assertEquals(1, ex.getSuppressed().length);
assertEquals(SUPPRESSED, ex.getSuppressed()[0]);
assertEquals(0, ex.getStackTrace().length);
}
/**
* Tests Throwable objects constructed with
* {@code enableSuppression=false} and
* {@code writableStackTrace=true}. Verifies that:
*
* - toString() returns a non-null value
* - getMessage() returns the original message passed to the
* constructor
* - getCause() returns the original cause passed to the
* constructor
* - suppressed exceptions are not added
* - the stack trace is added
*
*
* @param cons
* the throwable's class constructor
* @param to be defined
* @throws ConstructionError
* if the Throwable subclass cannot be constructed
* @throws AssertionError
* if the constructed objects fail to pass various tests
*/
public final void testNoSuppressStack(
final Constructor cons) {
var ex = newInstance(cons, "no,yes", CAUSE, false, true);
ex.addSuppressed(SUPPRESSED);
assertNotNull(ex.toString());
assertEquals("no,yes", ex.getMessage());
assertEquals(CAUSE, ex.getCause());
assertEquals(0, ex.getSuppressed().length);
assertTrue(ex.getStackTrace().length > 0);
}
/**
* Tests Throwable objects constructed with
* {@code enableSuppression=false} and
* {@code writableStackTrace=false}. Verifies that:
*
* - toString() returns a non-null value
* - getMessage() returns the original message passed to the
* constructor
* - getCause() returns the original cause passed to the
* constructor
* - suppressed exceptions are not added
* - the stack trace is not added
*
* @param cons
* the throwable's class constructor
* @param to be defined
* @throws ConstructionError
* if the Throwable subclass cannot be constructed
* @throws AssertionError
* if the constructed objects fail to pass various tests
*/
public final void testNoSuppressNoStack(
final Constructor cons) {
var ex = newInstance(cons, "no,no", CAUSE, false, false);
ex.addSuppressed(SUPPRESSED);
assertNotNull(ex.toString());
assertEquals("no,no", ex.getMessage());
assertEquals(CAUSE, ex.getCause());
assertEquals(0, ex.getSuppressed().length);
assertEquals(0, ex.getStackTrace().length);
}
/**
* Attempts to get a constructor for objects of a given type.
*
* @param claz
* class of objects whose constructor is to be gotten
* @param to be defined
* @param testType
* type of test being run
* @param argTypes
* argument types to be passed to the constructor
* @return the desired constructor, or {@code null} if the desired
* constructor is not available
*/
protected Constructor getConstructor(
final Class claz,
final String testType,
final Class>... argTypes) {
try {
return claz.getConstructor(argTypes);
} catch (NoSuchMethodException | SecurityException e) {
// this constructor is not defined so nothing to test
logger.debug("skipped test, no constructor for: {}", claz, e);
return null;
}
}
/**
* Creates a new instance of an Throwable subclass.
*
* @param cons
* subclass constructor
* @param to be defined
* @param args
* arguments to be passed to the constructor
* @return a new instance of the Throwable subclass
* @throws ConstructionError
* if the Throwable subclass cannot be constructed
*/
protected T newInstance(
final Constructor cons,
final Object... args) {
try {
return cons.newInstance(args);
} catch (InstantiationException | IllegalAccessException
| IllegalArgumentException
| InvocationTargetException e) {
throw new ConstructionError(e);
}
}
}