-
-
Notifications
You must be signed in to change notification settings - Fork 64
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow a way to tell @Provide methods that we are unable to create an Arbitrary with the given arguments and we need a new set #405
Comments
In your case I‘d probably use a filter function to only return an arbitrary if some condition is fulfilled. Your code is missing some elements for me to see what this condition is. ( BTW, if you use a non wildcard return type for the provider function ( |
One more thing. If you ever need something like
the idiomatic way is
This will give jqwik a better chance to do the right thing during shrinking. And it looks cleaner IMO. |
I probably didn't explain it that well - but essentially what I'm looking for is a way to tell JQwik that; I am unable to create an object with the values (or value) you gave me - please give me new ones so I can try again Using in |
It's also just coincidental behaviour. You could as well use Arbitraries.just((PublishSpork) null) which would at least be type-safe. I suggest you go with something like: @Provide
public Arbitrary<?> providePublishSpork(@ForAll Type type, @ForAll short flags,
@ForAll @NotEmpty byte[] signature, @ForAll Instant time) {
return type
.filter(t -> !(t instanceof Type.UNDEFINED))
.map(t -> {
/* Code that creates a PublishSpork instance */
return Arbitraries.just(instance);
});
} |
Nah, that wont work. You are assuming that Type.UNDEFINED should always fail - the failure does not stem from the type, but from the incoming arguments. What if we had something like this?: @Provide
public Arbitrary<?> provideSomething(@ForAll Arg1 arg1, @ForAll Arg2 arg2) {
try {
/* Code creating instance */
return Arbitraries.of(instance);
} catch (Exception1 | Exception2 | Exception3 ex) {
/* NOP - The passed args makes instantiation fail with an exception */
/* Likely a failure we are expecting, so we still want to continue... */
}
return Arbitraries.nothing(); /* What else can we do here? */
} We are stuck here unless we rely on that coincidental behavior. From what I can tell, one way is obviously to not rely on |
I tried an alternative approach with a configurator, public class NotNullConfigurator extends ArbitraryConfiguratorBase {
@Override
public <T> Arbitrary<T> configure(Arbitrary<T> arbitrary, TypeUsage targetType) {
return arbitrary.filter(obj -> Objects.nonNull(obj));
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.ANNOTATION_TYPE, ElementType.PARAMETER, ElementType.TYPE_USE })
public @interface NotNull {
/* Empty on purpose */
} I changed my provider and added the annotation to my @Provide
public Arbitrary<PublishSpork> providePublishSpork(...) {
try {
....
return Arbitraries.of(instance);
} catch (IllegalArgumentException ex) {
assertThat(gridSporkType, is(Type.UNDEFINED));
}
return Arbitraries.just(null);
}
@Property
public void shouldMatch(@ForAll("providePublishSpork") @NotNull PublishSpork publishSpork,
@Mocked ChannelHandlerContext context) {
...
}
} I know its parsing the service file and loading the class. Still, the filtering does not seem to work. Am I misinterpreting the |
Thinking a bit more about your example, there probably should be a simpler way to shortcut the generation of values. Implementing the above-mentioned |
|
Yes. If JQwik also filtered it, we would also not get "unnecessary/empty" calls to the property like now. Plus looks a lot better and makes more sense than |
I did. I registered it in I also tried the |
For now my hacky solution with the manual check will have to do. I will see if I can whip up a unit test replicating the failing configurator. If so - I will make a pull request later to replicate it. |
Just noticed that your configurator should look different to make it react to public class NotNullConfigurator extends ArbitraryConfiguratorBase {
public <T> Arbitrary<T> configure(Arbitrary<T> arbitrary, NotNull ignore) {
return arbitrary.filter(obj -> Objects.nonNull(obj));
}
} This should invoke the configurator - at least it did in my experiments - but it won't solve your problem, because wrapping the arbitrary instance created by Your configurator example came with a surprising result, though. When debugging it, I stumbled upon a bug in the annotations processing code. :-) |
Nice. 👍 Every bug found is a win. I got the filtering to work by registering it under a Going to stick with this solution for now and will tweak it once there is something like |
Added #408 as follow up. |
Testing Problem
I have the following test class:
It works well most of the time. But whenever
Arbitraries.nothing()
is passed back by the provider it seems like publishSpork is coming in asnull
, causing aNullPointerException
. Right now, the solution to this problem is to do the following in the test method and skip the assertion (and logic) whenever null comes in;Is this is how it is supposed to work at the moment?
Suggested Solution
Arbitraries.nothing()
presents a perfect opportunity to filter calls to the property test whenever a provider returnsnothing()
. Rather than passing null (which seems wrong) it would be a lot better if Jqwik just moved on to the next try and made a new attempt to gather values from the providers. That, or just call that specific provider again until a value is returned.The text was updated successfully, but these errors were encountered: