Skip to content

Commit

Permalink
Revise RepeatableContainersTests
Browse files Browse the repository at this point in the history
  • Loading branch information
sbrannen committed Dec 13, 2022
1 parent 937ab5f commit b2ce54e
Showing 1 changed file with 127 additions and 145 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;

import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;
Expand All @@ -31,189 +33,162 @@
* Tests for {@link RepeatableContainers}.
*
* @author Phillip Webb
* @author Sam Brannen
*/
class RepeatableContainersTests {

@Test
void standardRepeatablesWhenNonRepeatableReturnsNull() {
Object[] values = findRepeatedAnnotationValues(
RepeatableContainers.standardRepeatables(), WithNonRepeatable.class,
NonRepeatable.class);
assertThat(values).isNull();
}
@Nested
class StandardRepeatableContainersTests {

@Test
void standardRepeatablesWhenSingleReturnsNull() {
Object[] values = findRepeatedAnnotationValues(
RepeatableContainers.standardRepeatables(),
WithSingleStandardRepeatable.class, StandardRepeatable.class);
assertThat(values).isNull();
}
@Test
void standardRepeatablesWhenNonRepeatableReturnsNull() {
Object[] values = findRepeatedAnnotationValues(RepeatableContainers.standardRepeatables(),
NonRepeatableTestCase.class, NonRepeatable.class);
assertThat(values).isNull();
}

@Test
void standardRepeatablesWhenContainerReturnsRepeats() {
Object[] values = findRepeatedAnnotationValues(
RepeatableContainers.standardRepeatables(), WithStandardRepeatables.class,
StandardContainer.class);
assertThat(values).containsExactly("a", "b");
}
@Test
void standardRepeatablesWhenSingleReturnsNull() {
Object[] values = findRepeatedAnnotationValues(RepeatableContainers.standardRepeatables(),
SingleStandardRepeatableTestCase.class, StandardRepeatable.class);
assertThat(values).isNull();
}

@Test
void standardRepeatablesWhenContainerButNotRepeatableReturnsNull() {
Object[] values = findRepeatedAnnotationValues(
RepeatableContainers.standardRepeatables(), WithExplicitRepeatables.class,
ExplicitContainer.class);
assertThat(values).isNull();
}
@Test
void standardRepeatablesWhenContainerButNotRepeatableReturnsNull() {
Object[] values = findRepeatedAnnotationValues(RepeatableContainers.standardRepeatables(),
ExplicitRepeatablesTestCase.class, ExplicitContainer.class);
assertThat(values).isNull();
}

@Test
void ofExplicitWhenNonRepeatableReturnsNull() {
Object[] values = findRepeatedAnnotationValues(
RepeatableContainers.of(ExplicitRepeatable.class,
ExplicitContainer.class),
WithNonRepeatable.class, NonRepeatable.class);
assertThat(values).isNull();
@Test
void standardRepeatablesWhenContainerReturnsRepeats() {
Object[] values = findRepeatedAnnotationValues(RepeatableContainers.standardRepeatables(),
StandardRepeatablesTestCase.class, StandardContainer.class);
assertThat(values).containsExactly("a", "b");
}
}

@Test
void ofExplicitWhenStandardRepeatableContainerReturnsNull() {
Object[] values = findRepeatedAnnotationValues(
RepeatableContainers.of(ExplicitRepeatable.class,
ExplicitContainer.class),
WithStandardRepeatables.class, StandardContainer.class);
assertThat(values).isNull();
}
@Nested
class ExplicitRepeatableContainerTests {

@Test
void ofExplicitWhenContainerReturnsRepeats() {
Object[] values = findRepeatedAnnotationValues(
RepeatableContainers.of(ExplicitRepeatable.class,
ExplicitContainer.class),
WithExplicitRepeatables.class, ExplicitContainer.class);
assertThat(values).containsExactly("a", "b");
}
@Test
void ofExplicitWhenNonRepeatableReturnsNull() {
Object[] values = findRepeatedAnnotationValues(
RepeatableContainers.of(ExplicitRepeatable.class, ExplicitContainer.class),
NonRepeatableTestCase.class, NonRepeatable.class);
assertThat(values).isNull();
}

@Test
void ofExplicitWhenHasNoValueThrowsException() {
assertThatExceptionOfType(AnnotationConfigurationException.class).isThrownBy(() ->
RepeatableContainers.of(ExplicitRepeatable.class, InvalidNoValue.class))
.withMessageContaining("Invalid declaration of container type ["
+ InvalidNoValue.class.getName()
+ "] for repeatable annotation ["
+ ExplicitRepeatable.class.getName() + "]");
}
@Test
void ofExplicitWhenStandardRepeatableContainerReturnsNull() {
Object[] values = findRepeatedAnnotationValues(
RepeatableContainers.of(ExplicitRepeatable.class, ExplicitContainer.class),
StandardRepeatablesTestCase.class, StandardContainer.class);
assertThat(values).isNull();
}

@Test
void ofExplicitWhenValueIsNotArrayThrowsException() {
assertThatExceptionOfType(AnnotationConfigurationException.class).isThrownBy(() ->
RepeatableContainers.of(ExplicitRepeatable.class, InvalidNotArray.class))
.withMessage("Container type ["
+ InvalidNotArray.class.getName()
+ "] must declare a 'value' attribute for an array of type ["
+ ExplicitRepeatable.class.getName() + "]");
}
@Test
void ofExplicitWhenContainerReturnsRepeats() {
Object[] values = findRepeatedAnnotationValues(
RepeatableContainers.of(ExplicitRepeatable.class, ExplicitContainer.class),
ExplicitRepeatablesTestCase.class, ExplicitContainer.class);
assertThat(values).containsExactly("a", "b");
}

@Test
void ofExplicitWhenValueIsArrayOfWrongTypeThrowsException() {
assertThatExceptionOfType(AnnotationConfigurationException.class).isThrownBy(() ->
RepeatableContainers.of(ExplicitRepeatable.class, InvalidWrongArrayType.class))
.withMessage("Container type ["
+ InvalidWrongArrayType.class.getName()
+ "] must declare a 'value' attribute for an array of type ["
+ ExplicitRepeatable.class.getName() + "]");
}
@Test
void ofExplicitWhenContainerIsNullDeducesContainer() {
Object[] values = findRepeatedAnnotationValues(RepeatableContainers.of(StandardRepeatable.class, null),
StandardRepeatablesTestCase.class, StandardContainer.class);
assertThat(values).containsExactly("a", "b");
}

@Test
void ofExplicitWhenAnnotationIsNullThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() ->
RepeatableContainers.of(null, null))
.withMessage("Repeatable must not be null");
}
@Test
void ofExplicitWhenHasNoValueThrowsException() {
assertThatExceptionOfType(AnnotationConfigurationException.class)
.isThrownBy(() -> RepeatableContainers.of(ExplicitRepeatable.class, InvalidNoValue.class))
.withMessageContaining("Invalid declaration of container type [%s] for repeatable annotation [%s]",
InvalidNoValue.class.getName(), ExplicitRepeatable.class.getName());
}

@Test
void ofExplicitWhenContainerIsNullDeducesContainer() {
Object[] values = findRepeatedAnnotationValues(
RepeatableContainers.of(StandardRepeatable.class, null),
WithStandardRepeatables.class, StandardContainer.class);
assertThat(values).containsExactly("a", "b");
}
@Test
void ofExplicitWhenValueIsNotArrayThrowsException() {
assertThatExceptionOfType(AnnotationConfigurationException.class)
.isThrownBy(() -> RepeatableContainers.of(ExplicitRepeatable.class, InvalidNotArray.class))
.withMessage("Container type [%s] must declare a 'value' attribute for an array of type [%s]",
InvalidNotArray.class.getName(), ExplicitRepeatable.class.getName());
}

@Test
void ofExplicitWhenValueIsArrayOfWrongTypeThrowsException() {
assertThatExceptionOfType(AnnotationConfigurationException.class)
.isThrownBy(() -> RepeatableContainers.of(ExplicitRepeatable.class, InvalidWrongArrayType.class))
.withMessage("Container type [%s] must declare a 'value' attribute for an array of type [%s]",
InvalidWrongArrayType.class.getName(), ExplicitRepeatable.class.getName());
}

@Test
void ofExplicitWhenAnnotationIsNullThrowsException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> RepeatableContainers.of(null, null))
.withMessage("Repeatable must not be null");
}

@Test
void ofExplicitWhenContainerIsNullAndNotRepeatableThrowsException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> RepeatableContainers.of(ExplicitRepeatable.class, null))
.withMessage("Annotation type must be a repeatable annotation: failed to resolve container type for %s",
ExplicitRepeatable.class.getName());
}

@Test
void ofExplicitWhenContainerIsNullAndNotRepeatableThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() ->
RepeatableContainers.of(ExplicitRepeatable.class, null))
.withMessage("Annotation type must be a repeatable annotation: " +
"failed to resolve container type for " +
ExplicitRepeatable.class.getName());
}

@Test
void standardAndExplicitReturnsRepeats() {
RepeatableContainers repeatableContainers = RepeatableContainers.standardRepeatables().and(
ExplicitContainer.class, ExplicitRepeatable.class);
assertThat(findRepeatedAnnotationValues(repeatableContainers,
WithStandardRepeatables.class, StandardContainer.class)).containsExactly(
"a", "b");
assertThat(findRepeatedAnnotationValues(repeatableContainers,
WithExplicitRepeatables.class, ExplicitContainer.class)).containsExactly(
"a", "b");
RepeatableContainers repeatableContainers = RepeatableContainers.standardRepeatables()
.and(ExplicitContainer.class, ExplicitRepeatable.class);
assertThat(findRepeatedAnnotationValues(repeatableContainers, StandardRepeatablesTestCase.class, StandardContainer.class))
.containsExactly("a", "b");
assertThat(findRepeatedAnnotationValues(repeatableContainers, ExplicitRepeatablesTestCase.class, ExplicitContainer.class))
.containsExactly("a", "b");
}

@Test
void noneAlwaysReturnsNull() {
Object[] values = findRepeatedAnnotationValues(
RepeatableContainers.none(), WithStandardRepeatables.class,
StandardContainer.class);
Object[] values = findRepeatedAnnotationValues(RepeatableContainers.none(), StandardRepeatablesTestCase.class,
StandardContainer.class);
assertThat(values).isNull();
}

@Test
void equalsAndHashcode() {
RepeatableContainers c1 = RepeatableContainers.of(ExplicitRepeatable.class,
ExplicitContainer.class);
RepeatableContainers c2 = RepeatableContainers.of(ExplicitRepeatable.class,
ExplicitContainer.class);
RepeatableContainers c1 = RepeatableContainers.of(ExplicitRepeatable.class, ExplicitContainer.class);
RepeatableContainers c2 = RepeatableContainers.of(ExplicitRepeatable.class, ExplicitContainer.class);
RepeatableContainers c3 = RepeatableContainers.standardRepeatables();
RepeatableContainers c4 = RepeatableContainers.standardRepeatables().and(
ExplicitContainer.class, ExplicitRepeatable.class);
assertThat(c1.hashCode()).isEqualTo(c2.hashCode());
RepeatableContainers c4 = RepeatableContainers.standardRepeatables().and(ExplicitContainer.class, ExplicitRepeatable.class);
assertThat(c1).hasSameHashCodeAs(c2);
assertThat(c1).isEqualTo(c1).isEqualTo(c2);
assertThat(c1).isNotEqualTo(c3).isNotEqualTo(c4);
}

private Object[] findRepeatedAnnotationValues(RepeatableContainers containers,

private static Object[] findRepeatedAnnotationValues(RepeatableContainers containers,
Class<?> element, Class<? extends Annotation> annotationType) {
Annotation[] annotations = containers.findRepeatedAnnotations(
element.getAnnotation(annotationType));
Annotation[] annotations = containers.findRepeatedAnnotations(element.getAnnotation(annotationType));
return extractValues(annotations);
}

private Object[] extractValues(Annotation[] annotations) {
try {
if (annotations == null) {
return null;
}
Object[] result = new String[annotations.length];
for (int i = 0; i < annotations.length; i++) {
result[i] = annotations[i].annotationType().getMethod("value").invoke(
annotations[i]);
}
return result;
}
catch (Exception ex) {
throw new RuntimeException(ex);
private static Object[] extractValues(Annotation[] annotations) {
if (annotations == null) {
return null;
}
return Arrays.stream(annotations).map(AnnotationUtils::getValue).toArray(Object[]::new);
}

@Retention(RetentionPolicy.RUNTIME)
@interface NonRepeatable {

String value() default "";
}

@Retention(RetentionPolicy.RUNTIME)
@Repeatable(StandardContainer.class)
@interface StandardRepeatable {
@interface NonRepeatable {

String value() default "";
}
Expand All @@ -225,7 +200,8 @@ private Object[] extractValues(Annotation[] annotations) {
}

@Retention(RetentionPolicy.RUNTIME)
@interface ExplicitRepeatable {
@Repeatable(StandardContainer.class)
@interface StandardRepeatable {

String value() default "";
}
Expand All @@ -236,6 +212,12 @@ private Object[] extractValues(Annotation[] annotations) {
ExplicitRepeatable[] value();
}

@Retention(RetentionPolicy.RUNTIME)
@interface ExplicitRepeatable {

String value() default "";
}

@Retention(RetentionPolicy.RUNTIME)
@interface InvalidNoValue {
}
Expand All @@ -253,20 +235,20 @@ private Object[] extractValues(Annotation[] annotations) {
}

@NonRepeatable("a")
static class WithNonRepeatable {
static class NonRepeatableTestCase {
}

@StandardRepeatable("a")
static class WithSingleStandardRepeatable {
static class SingleStandardRepeatableTestCase {
}

@StandardRepeatable("a")
@StandardRepeatable("b")
static class WithStandardRepeatables {
static class StandardRepeatablesTestCase {
}

@ExplicitContainer({ @ExplicitRepeatable("a"), @ExplicitRepeatable("b") })
static class WithExplicitRepeatables {
static class ExplicitRepeatablesTestCase {
}

}

0 comments on commit b2ce54e

Please sign in to comment.