Skip to content
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

Refined failed in the community build #530

Closed
non opened this issue Aug 31, 2019 · 10 comments
Closed

Refined failed in the community build #530

non opened this issue Aug 31, 2019 · 10 comments

Comments

@non
Copy link
Contributor

non commented Aug 31, 2019

Extracting the error from CI we get:

[refined] [info] ! NonNegShift.shift Byte: Gave up after only 0 passed tests. 501 tests were discarded.
[refined] [info] ! NonNegShift.shift Short: Gave up after only 0 passed tests. 501 tests were discarded.
[refined] [info] ! NonNegShift.shift Int: Gave up after only 0 passed tests. 501 tests were discarded.
[refined] [info] ! NonNegShift.shift Long: Gave up after only 0 passed tests. 501 tests were discarded.
...
[refined] [info] ! NegShift.shift Byte: Gave up after only 0 passed tests. 501 tests were discarded.
[refined] [info] ! NegShift.shift Short: Gave up after only 0 passed tests. 501 tests were discarded.
[refined] [info] ! NegShift.shift Int: Gave up after only 0 passed tests. 501 tests were discarded.
[refined] [info] ! NegShift.shift Long: Gave up after only 0 passed tests. 501 tests were discarded.

It sounds like @ashawley wasn't able to reproduce these. I'm going to read these specific tests tests to see if I can figure out what's going on. Given that the tests were discarded (not failed) it's possible a change to our generation logic may have caused problems.

@non
Copy link
Contributor Author

non commented Aug 31, 2019

Alright, I understand the problem. The failing property looks like this:

    def createProperty[A: Arbitrary: Min: NonNegShift](implicit num: Numeric[A]): Prop = {
      import num.{abs, gteq, lt, plus, zero}

      forAll { a: A =>
        gteq(a, zero) ==> (NonNegShift[A].shift(a) == a)
      } &&
      forAll { a: A =>
        lt(a, zero) ==> (NonNegShift[A].shift(a) == plus(a, abs(Min[A].min)))
      }
    }

The issue is that the two forAll statements are generating the same a values. Since the conditions are mutually exclusive, we cannot find any examples that pass both preconditions.

I think it's likely that changes around deterministic testing are causing this problem. Either that, or we are not updating seeds appropriately. I'll dig into this a bit and report back.

cc @ashawley

@non
Copy link
Contributor Author

non commented Aug 31, 2019

I figured it out. It's a bug with the interaction between viewSeed, &&, and mutually-incompatible properties that's manifesting because we're now using viewSeed everywhere.

@ashawley
Copy link
Contributor

Ok, glad you figured it out. I will quit bisecting then, which I didn't even get a chance to start. ^_^

I didn't think we had any changes to seeds or deterministic testing in this release, but I wasn't aware that it could be a side effect of using viewSeed everywhere.

Because the failing test in refined was about numbers, the only other thing I thought of were changes #380 and #451, but those deal with floating point.

@non
Copy link
Contributor Author

non commented Aug 31, 2019

I'm about to submit a PR to fix this with a test case. Definitely take a look and see what you think.

non added a commit to non/scalacheck that referenced this issue Aug 31, 2019
Here's the basic issue:

When using viewSeed, we need to put an initialSeed in the
Gen.Parameters used to evaluate the Prop, so we can recover
the seed later and display it. So far, so good.

In some cases, we need to "slide" the seed that's embedded
in the parameters, so we don't reuse it. Any time we need
to evaluate several properties and don't want identical
RNG state (which could lead to identical inputs) we need
to slide.

We were missing a "slide" in flatMap -- we were reusing
the same parameters in both cases. Since flatMap was used
to define && (via for-comprehension) that meant that when
you said p0 && p1, you'd use the same seed for both if
viewSeed was set.

Refined's property was unusual, but valid. Basically, one
property had (x >= 0) ==> and one had (x < 0) ==>. So no
single x value would satisfy both, but on average you'd
satisfy each 50% of the time, and together you'd get
a non-discarded case about 25% of the time.

Previously, this worked OK. But since 1.14.0 we started
always displaying seeds. This meant that the bug associated
with failing to slide manifested, and we always generated
the same x value for both sides of the property. This
meant we ended up discarding every x generated.

The fix was to slide correctly in this case. I also added
a toString to Gen.Parameters which was missing, since this
helped with debugging.
@non
Copy link
Contributor Author

non commented Aug 31, 2019

#531

@ashawley
Copy link
Contributor

Yes, I can confirm that your change in #531 fixed it. I'm still trying to follow the reasoning behind your fix and the refined test, so thanks for providing the long write-up in the commit message.

This entire thing reminds me of something I wrote about about && and || in #425 (comment)

Indeed, it seems the current implementation in ScalaCheck will combine two properties with && in to one, and then the generators are run for each of the separate properties simultaneously to produce a pair of values where both properties are true. I understand the confusion from properties becoming combined and then tested, rather than tested atomically and then, and only then, their results combined. This could be especially confusing if you assign your properties to variables, as you have done, which are later be combined in an actual property. [...]

It's a long discussion that is difficult to follow. A lot of the back and forth was trying to find idiomatic examples, minimize and generally clarify the issue(s). There's a good chance that your change in #531 addresses those problems somehow.

@non
Copy link
Contributor Author

non commented Aug 31, 2019

Alright, I'm going to merge #531 then. Thanks for confirming the fix.

non added a commit that referenced this issue Aug 31, 2019
@non
Copy link
Contributor Author

non commented Aug 31, 2019

I'm closing this -- I'll try to head over to #425 to chime in there, although it's unlikely I'll be able to do that today.

@non non closed this as completed Aug 31, 2019
@ashawley
Copy link
Contributor

Yeah, fine to merge. We need to keep the community build process going.

@ashawley
Copy link
Contributor

Any idea if viewSeed could have a different implementation to avoid this defect?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants