Comments (7)
Looks like a bug I’ll check it.
from jqwik.
I did some research. The problem you're observing here is not related to the type paramater but to the fact that 'A' also fits type Object
(or List<Object>
). Instances of Object
are only equal if they are the exact same instance. So you can also observe this behaviour with:
@Property
void aInValuePos(
@ForAll Function<Integer, Object> f,
@ForAll Integer i
) {
Object first = f.apply(i);
Object second = f.apply(i);
Assertions.assertThat(first).isEqualTo(second);
}
A generated function, however, does not store all results, but generates a hash from the parameters which is than used as a random seed to generate the actual value. This will generate an equal (but not same) object when called with the same parameters.
You can mitigate the problem by making the type variable more specific, e.g.
<A extends Number>
Storing all generated values would use up additional memory. I could implemented this as an optional feature. Would that be an important improvement for you?
from jqwik.
Having had one more night to think it over, I'd even say that always returning the exact same object would be wrong, ie. would leave out behaviour that can definitely happen. In a language like Java where you can have objects with identity and changing state it's common behaviour that functions or functional interfaces create those kind of objects - and create them freshly whenever they are being invoked. Consider for example all those factory methods we use in the context of Spring et al.
If you want to constrain the type of objects to be created for A
you could use a provider method like this:
@Property
<A> void aInValuePos(
@ForAll Function<Integer, @From("valuesWithEquality") A> f,
@ForAll Integer i
) {
Assertions.assertThat(f.apply(i)).isEqualTo(f.apply(i));
}
@Provide
Arbitrary valuesWithEquality() {
return Arbitraries.oneOf(
Arbitraries.strings(),
(Arbitrary) Arbitraries.strings().list(),
(Arbitrary) Arbitraries.integers(),
... // Add whatever you think could be the target type
);
}
If you need those range of types regularly you might consider to register a default arbitrary provider.
So I close this issue as "works as designed". Feel free to reopen it if you still see a bug or want to make a feature request out of it.
from jqwik.
I understand that this is the way Java objects behave, but it would nice be nice to be able to restrict or filter which types A
may take in this circumstance, without requiring A
to be of a concrete subtype. equals
and hashcode
are part of the contract of Object
so they should be implemented correctly. This may not be possible or meaningful all the time. Unfortunately Java doesn't have something like Haskells Eq
or Ord
(or Hashable
) typeclasses. It would be nice to be able to annotate type parameters so that it's clear that only classes that implement equals
and hashcode
correctly should be chosen for A
. Something like:
@Property
<@Eq A, @Eq B> void aInValuePos(
@ForAll Function<A, B> f,
@ForAll A a
) {
Assertions.assertThat(f.apply(a)).isEqualTo(f.apply(a));
}
But I guess that would be essentially two different features. First the ability to register arbitrary providers on typeparameters and secondly the providers for @Eq
and @Hashable
. This would be pretty easy using Object.class.equals(targetClass.getMethod("equals", Object.class).getDeclaringClass())
.
Those are some pretty specific requirements though. I can understand if you don't think that this is something that you want to support. Although being able to annotate typeparameters would be nice regardless.
from jqwik.
The first required feature is rather simple since annotations are already being considered for the usage part of the type variable, thus @Eq
in
@Property
<A, B> void aInValuePos(
@ForAll Function<@Eq A, @Eq B> f,
@ForAll A a
)...
can be used for choosing an arbitrary.
The providers for @Eq
and @Hashable
are the bigger problem since with the current design of arbitrary provision the providers themselves would have to know about @Eq
and @Hashable
which they obviously should not. Let me think about it for a while...
from jqwik.
The advantage of declaring the Annotations at the variable declaration site would be that you could constrain all usages of that variable.
It would also be kind of inconsistent. In this example:
@Property
<A> void p(
@ForAll @Eq A a,
@ForAll A b
)...
would a
and b
resolve to different types essentially? a
resolves to only types that implement equals
correctly, but b
would resolve to any Object
?
Regarding the problem that the provider shouldn't know about @Eq
etc. Some kind of filter mechanism would be useful. You could register filters for annotations that would filter the arbitraries returned by the providers. It would also be nice if there was a way for an arbitrary provider to communicate that it can handle some of these filter annotations directly in a more efficient manner.
from jqwik.
I extracted part 1 into an issue of its own: #74
As for filtering arbitraries I haven't (yet) come up with an idea how to do that without breaking existing arbitrary providers or force them to know about a filter annotations. The problem is that neither ArbitraryProvider
instances nor Arbitrary
instances tell anything about themselves or the kind of objects they are going to create at runtime. So the question is: How would a filter function determine if it wants to let an arbitrary - or arbitrary provider - get through or not?
from jqwik.
Related Issues (20)
- Bug: PropertyExecutor.execute() does not handle AssertionErrors correctly HOT 1
- ClassCastException when using Combinators during shrinking HOT 21
- ListArbitrary<T> providers are not selected to resolve List<T> parameters HOT 1
- Support OpenJML for Arbitraries
- Jqwik Quarkus Support HOT 2
- Type arguments are missing in some situations HOT 8
- support for heterogeneous arbitrary configurators in base HOT 9
- Arbitrary.size as an option to tweak during arbitrary construction. HOT 22
- Feature Request: Report generator state when generation fails with exception
- Provide a way to suppress excessive output/stacktraces HOT 16
- Domains inject parameterized values incorrectly HOT 25
- Method to specify the order of execution for tests HOT 5
- Programmatic use of jqwik without JUnit HOT 3
- Repeatead chars not working as expected HOT 6
- Every X years in @YearRange HOT 1
- Allow parallel test runs with SBT HOT 15
- Infinite action chains biased towards small sizes HOT 5
- 1.8.0 contracts regression HOT 16
- IllegalArgumentException: "At least one shrinkable is required" during shrinking hides cause of test failure HOT 4
- Consider supporting @UseType for sealed interfaces HOT 8
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from jqwik.