Skip to content

Commit

Permalink
Add tests for the ReflectionTestUtils class
Browse files Browse the repository at this point in the history
  • Loading branch information
stijn-dejongh committed Sep 22, 2024
1 parent 3a8c391 commit 6fbc0de
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,27 +50,30 @@
*/
public final class ReflectionAssertionUtils {

public static final String PROHIBITED_CONSTRUCTOR_ACCESS =
"Utility classes should not have a public or default constructor";

private ReflectionAssertionUtils() {
throw new UnsupportedOperationException(
"Utility classes should not have a public or default constructor");
throw new UnsupportedOperationException("Utility classes should not have a public or default constructor");
}

public static void assertPrivateMemberReflectionProtection(
@SuppressWarnings("rawtypes") final Constructor constructor) {
constructor.setAccessible(true);
assertThatThrownBy(constructor::newInstance)

assertThatThrownBy(constructor::newInstance, unprotectedConstructorError(constructor))
.isInstanceOf(InvocationTargetException.class)
.hasCauseInstanceOf(UnsupportedOperationException.class)
.hasStackTraceContaining(
"This operation is not allowed for reason: [ Utility classes should not have a public or default constructor ]");
.hasStackTraceContaining(PROHIBITED_CONSTRUCTOR_ACCESS);
}

public static void assertPrivateMember(
@SuppressWarnings("rawtypes") final Constructor constructor) {
assertThatThrownBy(constructor::newInstance,
format("Constructor %s is expected to be protected from illegal access",
constructor
)
).isInstanceOfAny(InvocationTargetException.class, IllegalAccessException.class);
assertThatThrownBy(constructor::newInstance, unprotectedConstructorError(constructor))
.isInstanceOfAny(InvocationTargetException.class, IllegalAccessException.class);
}

private static String unprotectedConstructorError(final Constructor constructor) {
return format("Constructor %s is expected to be protected from illegal access", constructor);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*-
* #%L
* commons-testing
* %%
* Copyright (C) 2020 - 2024 SD Development
* %%
* Licensed under the EUPL, Version 1.1 or – as soon they will be
* approved by the European Commission - subsequent versions of the
* EUPL (the "Licence");
*
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://ec.europa.eu/idabc/eupl5
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the Licence is distributed on an "AS IS" basis,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Licence for the specific language governing permissions and
* limitations under the Licence.
* #L%
*/

package be.sddevelopment.commons.testing;

import static be.sddevelopment.commons.testing.ReflectionAssertionUtils.assertPrivateMember;
import static be.sddevelopment.commons.testing.ReflectionAssertionUtils.assertPrivateMemberReflectionProtection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
import org.assertj.core.api.WithAssertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

@DisplayNameGeneration(ReplaceUnderscoredCamelCasing.class)
class ReflectionAssertionUtilsTest implements WithAssertions {

@Test
void constructorIsPrivate() throws NoSuchMethodException {
assertPrivateMember(ReflectionAssertionUtils.class.getDeclaredConstructor());
}

@Test
void constructorIsReflectionSafe() throws NoSuchMethodException {
assertPrivateMemberReflectionProtection(ReflectionAssertionUtils.class.getDeclaredConstructor());
}

@Nested
@DisplayName("Method: assertPrivateMember")
class AssertPrivateMember {
@Test
void passesWhenConstructorIsPrivate() throws NoSuchMethodException {
var constructorToTest = ClassWithPrivateConstructor.class.getDeclaredConstructor();
assertThat(constructorToTest).isNotNull().extracting(Constructor::getModifiers).matches(Modifier::isPrivate);

ThrowingCallable assertion = () -> assertPrivateMember(constructorToTest);

assertThatCode(assertion).doesNotThrowAnyException();
}

@Test
void failsWhenConstructorIsPublic() throws NoSuchMethodException {
var constructorToTest = ClassWithPublicConstructor.class.getDeclaredConstructor();
assertThat(constructorToTest).isNotNull().extracting(Constructor::getModifiers).matches(Modifier::isPublic);

ThrowingCallable assertion = () -> assertPrivateMember(constructorToTest);

assertThatCode(assertion).isInstanceOf(AssertionError.class).hasMessageContaining("is expected to be protected from illegal access");
}
}

@Nested
@DisplayName("Method: assertPrivateMemberReflectionProtection")
class AssertPrivateMemberReflectionProtection {
@Test
void failsWhenConstructorIsPublic() throws NoSuchMethodException {
var constructorToTest = ClassWithPublicConstructor.class.getDeclaredConstructor();
assertThat(constructorToTest).isNotNull().extracting(Constructor::getModifiers).matches(Modifier::isPublic);

ThrowingCallable assertion = () -> assertPrivateMemberReflectionProtection(constructorToTest);

assertThatCode(assertion).isInstanceOf(AssertionError.class).hasMessageContaining("is expected to be protected from illegal access");
}

@Test
void failsWhenConstructorIsPrivateButNotReflectionSafe() throws NoSuchMethodException {
var constructorToTest = ClassWithPrivateConstructor.class.getDeclaredConstructor();
assertThat(constructorToTest).isNotNull().extracting(Constructor::getModifiers).matches(Modifier::isPrivate);

ThrowingCallable assertion = () -> assertPrivateMemberReflectionProtection(constructorToTest);

assertThatCode(assertion).isNotNull().isInstanceOf(AssertionError.class).hasMessageContaining("is expected to be protected from illegal access");
}

@Test
void passesWhenConstructorIsPrivateAndReflectionSafe() throws NoSuchMethodException {
var constructorToTest = ClassWithReflectionSafeConstructor.class.getDeclaredConstructor();
assertThat(constructorToTest).isNotNull().extracting(Constructor::getModifiers).matches(Modifier::isPrivate);

ThrowingCallable assertion = () -> assertPrivateMemberReflectionProtection(constructorToTest);

assertThatCode(assertion).doesNotThrowAnyException();
}
}

static final class ClassWithReflectionSafeConstructor {
private ClassWithReflectionSafeConstructor() {
throw new UnsupportedOperationException("Utility classes should not have a public or default constructor");
}
}

static final class ClassWithPrivateConstructor {
private ClassWithPrivateConstructor() {
}
}

static final class ClassWithPublicConstructor {
public ClassWithPublicConstructor() {
}
}

}

0 comments on commit 6fbc0de

Please sign in to comment.