Skip to content

Commit

Permalink
Add uniqueElements() methods to StreamableArbitrary interface
Browse files Browse the repository at this point in the history
See #466
  • Loading branch information
jlink committed Mar 16, 2023
1 parent 239d28f commit 15f6067
Show file tree
Hide file tree
Showing 10 changed files with 60 additions and 34 deletions.
3 changes: 0 additions & 3 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
# 1.7.3

- Support UniqueElements annotation for extensions.
See: https://github.com/jqwik-team/jqwik/issues/466

- Add Arbitrary.ignoreException(maxMisses, ...)
See https://github.com/jqwik-team/jqwik/issues/462.

Expand Down
9 changes: 9 additions & 0 deletions api/src/main/java/net/jqwik/api/arbitraries/SetArbitrary.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,15 @@ default SetArbitrary<T> ofSize(int size) {
@API(status = MAINTAINED, since = "1.4.0")
<U> Arbitrary<Set<U>> flatMapEach(BiFunction<Set<T>, T, Arbitrary<U>> flatMapper);

/**
* Do not use. Sets have unique elements anyway.
* It only exists for purposes of symmetry.
*
* @return same instance of arbitrary
*/
@API(status = MAINTAINED, since = "1.7.3")
SetArbitrary<T> uniqueElements();

/**
* Add the constraint that elements of the generated set must be unique
* relating to an element's "feature" being extracted using the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,33 @@ default StreamableArbitrary<T, U> ofSize(int size) {
*/
@API(status = EXPERIMENTAL, since = "1.5.3")
StreamableArbitrary<T, U> withSizeDistribution(RandomDistribution distribution);

/**
* Add the constraint that elements of the generated streamable must be unique,
* i.e. no two elements must return true when being compared using {@linkplain Object#equals(Object)}.
*
* <p>
* The constraint can be combined with other {@linkplain #uniqueElements(Function)} constraints.
* </p>
*
* @return new arbitrary instance
*/
@API(status = MAINTAINED, since = "1.7.3")
StreamableArbitrary<T, U> uniqueElements();

/**
* Add the constraint that elements of the generated streamable must be unique
* relating to an element's "feature" being extracted using the
* {@code by} function.
* The extracted features are being compared using {@linkplain Object#equals(Object)}.
*
* <p>
* The constraint can be combined with other {@linkplain #uniqueElements(Function)} constraints.
* </p>
*
* @return new arbitrary instance
*/
@API(status = MAINTAINED, since = "1.7.3")
StreamableArbitrary<T, U> uniqueElements(Function<T, Object> by);

}
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ protected Iterable<T> toIterable(A array) {

@Override
public ArrayArbitrary<T, A> uniqueElements() {
return (ArrayArbitrary<T, A>) uniqueElements(FeatureExtractor.identity());
return (ArrayArbitrary<T, A>) super.uniqueElements();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public IteratorArbitrary<T> uniqueElements(Function<T, Object> by) {

@Override
public IteratorArbitrary<T> uniqueElements() {
return (IteratorArbitrary<T>) uniqueElements(FeatureExtractor.identity());
return (IteratorArbitrary<T>) super.uniqueElements();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,6 @@ public ListArbitrary<T> uniqueElements(Function<T, Object> by) {

@Override
public ListArbitrary<T> uniqueElements() {
return (ListArbitrary<T>) uniqueElements(FeatureExtractor.identity());
return (ListArbitrary<T>) super.uniqueElements();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ public <U> Arbitrary<Set<U>> flatMapEach(BiFunction<Set<T>, T, Arbitrary<U>> fla
});
}

@Override
public SetArbitrary<T> uniqueElements() {
return this;
}

@Override
public SetArbitrary<T> uniqueElements(Function<T, Object> by) {
FeatureExtractor<T> featureExtractor = by::apply;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public StreamArbitrary<T> uniqueElements(Function<T, Object> by) {

@Override
public StreamArbitrary<T> uniqueElements() {
return (StreamArbitrary<T>) uniqueElements(FeatureExtractor.identity());
return (StreamArbitrary<T>) super.uniqueElements();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ public <R> Arbitrary<R> reduce(R initial, BiFunction<R, T, R> accumulator) {
});
}

@Override
public StreamableArbitrary<T, U> uniqueElements() {
return uniqueElements(FeatureExtractor.identity());
}

protected abstract Iterable<T> toIterable(U streamable);

protected StreamableArbitrary<T, U> uniqueElements(FeatureExtractor<T> by) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,12 @@ public class UniqueElementsConfigurator implements ArbitraryConfigurator {
@Override
public <T> Arbitrary<T> configure(Arbitrary<T> arbitrary, TypeUsage targetType) {
return targetType.findAnnotation(UniqueElements.class).map(uniqueness -> {
if (arbitrary instanceof ListArbitrary) {
return (Arbitrary<T>) configureListArbitrary((ListArbitrary<?>) arbitrary, uniqueness);
}
if (arbitrary instanceof SetArbitrary) {
// Handle SetArbitrary explicitly for optimization
return (Arbitrary<T>) configureSetArbitrary((SetArbitrary<?>) arbitrary, uniqueness);
}
if (arbitrary instanceof ArrayArbitrary) {
return (Arbitrary<T>) configureArrayArbitrary((ArrayArbitrary<?, ?>) arbitrary, uniqueness);
}
if (arbitrary instanceof StreamArbitrary) {
return (Arbitrary<T>) configureStreamArbitrary((StreamArbitrary<?>) arbitrary, uniqueness);
}
if (arbitrary instanceof IteratorArbitrary) {
return (Arbitrary<T>) configureIteratorArbitrary((IteratorArbitrary<?>) arbitrary, uniqueness);
if (arbitrary instanceof StreamableArbitrary) {
return (Arbitrary<T>) configureStreamableArbitrary((StreamableArbitrary<?, ?>) arbitrary, uniqueness);
}
if (targetType.isAssignableFrom(List.class)) {
Arbitrary<List<?>> listArbitrary = (Arbitrary<List<?>>) arbitrary;
Expand Down Expand Up @@ -76,27 +68,16 @@ private boolean isUnique(Collection<?> list, Function<Object, Object> extractor)
return set.size() == list.size();
}

private <T> Arbitrary<?> configureListArbitrary(ListArbitrary<T> arbitrary, UniqueElements uniqueness) {
private <T> Arbitrary<?> configureStreamableArbitrary(StreamableArbitrary<T, ?> arbitrary, UniqueElements uniqueness) {
Function<T, Object> extractor = (Function<T, Object>) extractor(uniqueness);
return arbitrary.uniqueElements(extractor);
}

private <T> Arbitrary<?> configureSetArbitrary(SetArbitrary<T> arbitrary, UniqueElements uniqueness) {
Function<T, Object> extractor = (Function<T, Object>) extractor(uniqueness);
return arbitrary.uniqueElements(extractor);
}

private <T> Arbitrary<?> configureArrayArbitrary(ArrayArbitrary<T, ?> arbitrary, UniqueElements uniqueness) {
Function<T, Object> extractor = (Function<T, Object>) extractor(uniqueness);
return arbitrary.uniqueElements(extractor);
}

private <T> Arbitrary<?> configureStreamArbitrary(StreamArbitrary<T> arbitrary, UniqueElements uniqueness) {
Function<T, Object> extractor = (Function<T, Object>) extractor(uniqueness);
return arbitrary.uniqueElements(extractor);
}

private <T> Arbitrary<?> configureIteratorArbitrary(IteratorArbitrary<T> arbitrary, UniqueElements uniqueness) {
Class<? extends Function<?, Object>> extractorClass = uniqueness.by();
if (extractorClass.equals(UniqueElements.NOT_SET.class)) {
return arbitrary;
}
Function<T, Object> extractor = (Function<T, Object>) extractor(uniqueness);
return arbitrary.uniqueElements(extractor);
}
Expand Down

0 comments on commit 15f6067

Please sign in to comment.