hedgehogqa / haskell-hedgehog-classes

Hedgehog will eat your typeclass bugs
BSD 3-Clause "New" or "Revised" License
57 stars 17 forks source link

hedgehog-1.0 support #16

Closed dhess closed 5 years ago

dhess commented 5 years ago

Hi, any plans to support hedgehog-1.0? The current release (0.1.2) doesn't build with it:

  src/Hedgehog/Classes/Common/PP.hs:28:5: error:
      Module
      ‘Hedgehog.Internal.Report’
      does not export
      ‘DiscardCount(..)’
     |
  28 |   ( DiscardCount(..), TestCount(..), ShrinkCount(..), Markup(..), Report(..)
     |     ^^^^^^^^^^^^^^^^

  src/Hedgehog/Classes/Common/PP.hs:28:23: error:
      Module ‘Hedgehog.Internal.Report’ does not export ‘TestCount(..)’
     |
  28 |   ( DiscardCount(..), TestCount(..), ShrinkCount(..), Markup(..), Report(..)
     |                       ^^^^^^^^^^^^^

  src/Hedgehog/Classes/Common/PP.hs:28:38: error:
      Module ‘Hedgehog.Internal.Report’ does not export ‘ShrinkCount(..)’
     |
  28 |   ( DiscardCount(..), TestCount(..), ShrinkCount(..), Markup(..), Report(..)
     |                                      ^^^^^^^^^^^^^^^
chessai commented 5 years ago

Ah. I'll need to investigate the changes to hedgehog's internals.

chessai commented 5 years ago

I'm working on this.

when designing hedgehog-classes, i realised that hedgehog would display source code from hedgehog-classes, since that is where the test actually exists - however, i didn't want to expose that to source to end users in error messages.

What I ended up doing was re-implementing a ton of hedgehog's pretty-printing internals, which was kind of painful.

I'm currently discussing with the hedgehog team what the best course of action is, since what I'm currently doing breaks hard, and often, especially because internals are not bound by PVP.

As an example, if i have the following:

newtype BadList a = BadList [a]
  deriving (Eq,Show)

instance Foldable BadList where
  foldMap f (BadList xs) = foldMap f xs
  foldl' = foldl

hedgehog-classes will correctly identify that one's implementation of foldl' is not strict. But, with just hedgehog's errors, one gets the following:

           ┏━━ src/Hedgehog/Classes/Foldable.hs ━━━
    203 ┃ foldableFoldl' ::
    204 ┃   ( Foldable f
    205 ┃   , forall x. Eq x => Eq (f x), forall x. Show x => Show (f x)
    206 ┃   ) => (forall x. Gen x -> Gen (f x)) -> Property
    207 ┃ foldableFoldl' fgen = property $ do
    208 ┃   xs <- forAll $ fgen (genBottom genSmallInteger)
        ┃   │ BadList [ undefined , 3 ]
    209 ┃   let f :: Integer -> Bottom Integer -> Integer
    210 ┃       f a b = case b of
    211 ┃         BottomUndefined -> error "foldableFoldl': your foldl' is not strict!"
    212 ┃         BottomValue v -> if even v then a else v
    213 ┃   let z0 = 0
    214 ┃   (rhs,ctx1) <- liftIO $ do
    215 ┃     let f' x k z = k $! f z x
    216 ┃     e <- try (evaluate (Foldable.foldr f' id xs z0))
    217 ┃     case e of
    218 ┃       Left (_ :: ErrorCall) -> pure (Nothing, ctxNotStrict "foldl'")
    219 ┃       Right i -> pure (Just i, NoContext)
    220 ┃   (lhs,ctx2) <- liftIO $ do
    221 ┃     e <- try (evaluate (Foldable.foldl' f z0 xs))
    222 ┃     case e of
    223 ┃       Left (_ :: ErrorCall) -> pure (Nothing, ctxNotStrict "foldl'")
    224 ┃       Right i -> pure (Just i, NoContext)
    225 ┃   let ctx = case ctx1 of
    226 ┃         NoContext -> case ctx2 of
    227 ┃           NoContext -> contextualise $ LawContext
    228 ┃             { lawContextLawName = "Foldl'"
    229 ┃             , lawContextLawBody = "foldl' f z0 xs" `congruency` "foldr f' id xs z0, where f' x k z = k $! f z x"
    230 ┃             , lawContextTcName = "Foldable"
    231 ┃             , lawContextTcProp =
    232 ┃                 let showT = show xs
    233 ┃                     showF = "\\a b -> case a of\n  BottomUndefined -> error \"foldableFoldr': not strict\"\n  BottomValue v -> if even v then v else b"
    234 ┃                     showZ = show z0
    235 ┃                 in lawWhere
    236 ┃                   [ "foldl' f z0 xs" `congruency` "foldr f' id xs z0, where f' x k z = k $! f z x"
    237 ┃                   , "f = " ++ showF
    238 ┃                   , "z0 = " ++ showZ
    239 ┃                   , "t = " ++ showT
    240 ┃                   ]
    241 ┃             , lawContextReduced = reduced lhs rhs
    242 ┃             }
    243 ┃           c2 -> c2
    244 ┃         c1 -> c1
    245 ┃   heqCtx lhs rhs ctx

    ━━━ Context ━━━
    Your implementation of foldl' is not strict.
    ━━━━━━━━━━━━━━━

    This failure can be reproduced by running:
    > recheck (Size 15) (Seed 1777688920227310001 1361721854730653423) <property>

Foldable: foldl1   ✓ <interactive> passed 100 tests.
Foldable: foldr1   ✓ <interactive> passed 100 tests.
Foldable: toList   ✓ <interactive> passed 100 tests.
Foldable: null   ✓ <interactive> passed 100 tests.
Foldable: length   ✓ <interactive> passed 100 tests.
dhess commented 5 years ago

Thank you! This is a wonderful library.

chessai commented 5 years ago

the hack i came up with involves using the silently package and filtering out hedgehog's own output. hedgehog-classes-0.2 is now released.

chessai commented 5 years ago

http://hackage.haskell.org/package/hedgehog-classes-0.2/docs/Hedgehog-Classes.html

chessai commented 5 years ago

also, thank you for your support of the package, and taking the time to open the issue. being reminded that there are users of my code really helps motivate me. so thanks.

dhess commented 5 years ago

Awesome, I will test this out in the next few days. Thank you!