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

How to write Arbitrary instances that depend on current time? #176

Closed
saurabhnanda opened this issue Jun 21, 2017 · 5 comments
Closed

How to write Arbitrary instances that depend on current time? #176

saurabhnanda opened this issue Jun 21, 2017 · 5 comments

Comments

@saurabhnanda
Copy link

I need to write Arbitrary instances for fields of type UTCTime, where the values are something that make sense for the problem domain, for example:

  • Current time
  • Current time minus X hours, where X is a small integer
  • Current time plus X hours, where X is a small integer
  • Midnight OR midnight +/- 10 minutes, in UTC, of any date within (currentTime, currentTime + 1 year)
  • Midnight OR midnight +/- 10 minutes, in a random timezone, of any date within (currentTime, currentTime + 1 year)
  • Any start OR end of week boundary within (currentTime, currentTime + 1 year)
  • Any start OR end of month boundary within (currentTime, currentTime + 1 year)

Related questions:

  • How does one do IO inside an Arbitrary instance, i.e. inside the Gen monad?
  • How does one pass a "special value" (in this case the currentTime) to an Arbitrary instance?
@saurabhnanda saurabhnanda changed the title How to generate Arbitrary instances that depend on current time? How to write Arbitrary instances that depend on current time? Jun 21, 2017
@phadej
Copy link
Contributor

phadej commented Jun 21, 2017

IMHO this kind of questions are perfect fit for StackOverflow.

Very brief answer: Getting current time is a "side-effect", factor it out.

  • Parametrise the unit at test:
foo  :: MonadTime m => m Res
foo' :: Monad m => m UTCTime -> m Res
  • Generate intervals, or moments:
data Offset
    = Now
    | HoursInFuture (Small Int)
    | NextMidning
    ...

applyOffset :: Offset -> UTCTime -> UTCTime
  • You cannot have IO inside Arbitrary instance. You can have IO inside Property though. See Test.QuickCheck.Monadic
  • Don't try to pass special value to instance. Generate a change, and apply it in the Property.

@saurabhnanda
Copy link
Author

Okay, taking this to StackOverflow

@nick8325
Copy link
Owner

@phadej's suggestion of defining an Offset type is the approach I would try first.

Alternatively, you can avoid the Arbitrary class and define your generator as a function of type UTCTime -> Gen UTCTime, and then use forAll or forAllShrink in your property.

You can do I/O in a property by using the ioProperty combinator. For example:

prop_whatever x y z =
  ioProperty $ do
     time <- getCurrentTime
     return $ ... rest of property goes here ...

@brandon-leapyear
Copy link

brandon-leapyear commented Aug 12, 2021

This is an old work account. Please reference @brandonchinn178 for all future communication


I've also historically done

arbitraryMyType :: Foo -> Bar -> Gen MyType

forAll (arbitraryMyType foo bar) $ \myType -> ...

(I know I'm posting on a really old issue. Maybe this issue should be closed?)

@MaximilianAlgehed
Copy link
Collaborator

Closing this as the discussion has moved to Stack Overflow

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

5 participants