Skip to content

Commit

Permalink
Allow Uniqueness.by() to return more specific function type
Browse files Browse the repository at this point in the history
  • Loading branch information
jlink committed Jun 10, 2024
1 parent a3cea7d commit 485960d
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.function.*;

import org.apiguardian.api.*;
import org.jspecify.annotations.*;

import static org.apiguardian.api.API.Status.*;

Expand All @@ -30,5 +31,5 @@ public Object apply(Object o) {
throw new IllegalArgumentException("This class must not be used");
}
}
Class<? extends Function<?, Object>> by() default NOT_SET.class;
Class<? extends Function<? extends @Nullable Object, ?>> by() default NOT_SET.class;
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ void listOfStringsTheFirstCharacterOfWhichMustBeUnique(
Assertions.assertThat(firstCharacters).doesNotHaveDuplicates();
}

private class FirstChar implements Function<String, Object> {
private class FirstChar implements Function<String, Character> {
@Override
public Object apply(String aString) {
public Character apply(String aString) {
return aString.charAt(0);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
@SuppressWarnings("unchecked")
public class UniqueElementsConfigurator implements ArbitraryConfigurator {

@SuppressWarnings("OverlyComplexMethod")
@SuppressWarnings({"OverlyComplexMethod", "OverlyLongMethod"})
@Override
public <T extends @Nullable Object> Arbitrary<T> configure(Arbitrary<T> arbitrary, TypeUsage targetType) {
return targetType.findAnnotation(UniqueElements.class).map(uniqueness -> {
Expand Down Expand Up @@ -66,8 +66,9 @@ public class UniqueElementsConfigurator implements ArbitraryConfigurator {
return list;
}

@SuppressWarnings("OverlyLongMethod")
private static <C extends Collection<?>> Predicate<C> isUnique(UniqueElements uniqueness) {
Class<? extends Function<?, Object>> extractorClass = uniqueness.by();
Class<? extends Function<?, ?>> extractorClass = uniqueness.by();
if (extractorClass.equals(UniqueElements.NOT_SET.class)) {
return items -> {
// Intentionally uses `items.getClass().equals(HashSet.class)`
Expand Down Expand Up @@ -101,7 +102,7 @@ private static <C extends Collection<?>> Predicate<C> isUnique(UniqueElements un
}

private <T extends @Nullable Object> Arbitrary<?> configureStreamableArbitrary(StreamableArbitrary<T, ?> arbitrary, UniqueElements uniqueness) {
Class<? extends Function<?, Object>> extractorClass = uniqueness.by();
Class<? extends Function<?, ?>> extractorClass = uniqueness.by();
if (extractorClass.equals(UniqueElements.NOT_SET.class)) {
return arbitrary.uniqueElements();
}
Expand All @@ -110,15 +111,15 @@ private static <C extends Collection<?>> Predicate<C> isUnique(UniqueElements un
}

private <T extends @Nullable Object> Arbitrary<?> configureSetArbitrary(SetArbitrary<T> arbitrary, UniqueElements uniqueness) {
Class<? extends Function<?, Object>> extractorClass = uniqueness.by();
Class<? extends Function<?, ?>> extractorClass = uniqueness.by();
if (extractorClass.equals(UniqueElements.NOT_SET.class)) {
return arbitrary;
}
Function<T, Object> extractor = extractor(extractorClass);
return arbitrary.uniqueElements(extractor);
}

private static <T extends @Nullable Object> Function<T, Object> extractor(Class<? extends Function<?, Object>> extractorClass) {
private static <T extends @Nullable Object> Function<T, Object> extractor(Class<? extends Function<?, ?>> extractorClass) {
return (Function<T, Object>) (
extractorClass.equals(UniqueElements.NOT_SET.class)
? Function.identity()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ boolean listsOfModuloIntegers(@ForAll @UniqueElements(by = Modulo13.class) List<
return hasNoDuplicates(integerList, i -> i % 13);
}

private class Modulo13 implements Function<Integer, Object> {
private class Modulo13 implements Function<Integer, Integer> {
@Override
public Object apply(Integer integer) {
public Integer apply(Integer integer) {
return integer % 13;
}
}
Expand Down Expand Up @@ -102,9 +102,9 @@ private Set<String> asSet(String... strings) {
return new LinkedHashSet<>(asList(strings));
}

private class GetFirstTwoChars implements Function<String, Object> {
private class GetFirstTwoChars implements Function<String, String> {
@Override
public Object apply(String string) {
public String apply(String string) {
return string.substring(0, 2);
}
}
Expand Down Expand Up @@ -202,9 +202,9 @@ private List<String> toList(Iterator<String> iterator) {

}

private class GetStringLength implements Function<String, Object> {
private class GetStringLength implements Function<String, Integer> {
@Override
public Object apply(String string) {
public Integer apply(String string) {
return string.length();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ class KotlinUniqueElementsConfigurator : ArbitraryConfigurator {
return@map when {
arbitrary is SequenceArbitrary<*> -> configureSequenceArbitrary(arbitrary, uniqueness)
targetType.isAssignableFrom(Sequence::class) -> {
val sequenceArbitrary = arbitrary as Arbitrary<Sequence<*>>
val sequenceArbitrary = arbitrary as Arbitrary<Sequence<T>>
sequenceArbitrary.filter {
isUnique(
it.toList(),
extractor(uniqueness) as Function<Any?, Any>
extractor<T>(uniqueness) as Function<Any?, Any>
)
}
}
Expand All @@ -40,13 +40,13 @@ class KotlinUniqueElementsConfigurator : ArbitraryConfigurator {
arbitrary: SequenceArbitrary<T>,
uniqueness: UniqueElements
): SequenceArbitrary<T> {
val extractor = extractor(uniqueness) as Function<T, Any>
val extractor = extractor<T>(uniqueness) as Function<T?, *>
return arbitrary.uniqueElements(extractor)
}

private fun extractor(uniqueElements: UniqueElements): Function<*, Any> {
val extractorClass: Class<out Function<*, Any>> = uniqueElements.by.java
return if (extractorClass == NOT_SET::class.java) Function.identity()
private fun <T> extractor(uniqueElements: UniqueElements): Function<*, *> {
val extractorClass: Class<out Function<*, *>> = uniqueElements.by.java
return if (extractorClass == NOT_SET::class.java) Function.identity<Any>()
// TODO: Create instance in context of test instance.
// This requires an extension of ArbitraryConfiguration interface
// to provide access to PropertyLifecycleContext
Expand Down

0 comments on commit 485960d

Please sign in to comment.