-- | Use QuickCheck generators and 'QuickCheck.Arbitrary' instances with Hedgehog.
--
module Hedgehog.Gen.QuickCheck (
    arbitrary
  , quickcheck
  ) where

import           Hedgehog
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range

import qualified Test.QuickCheck as QuickCheck
import qualified Test.QuickCheck.Gen as QuickCheck
import qualified Test.QuickCheck.Random as QuickCheck


seedQCGen :: MonadGen m => m QuickCheck.QCGen
seedQCGen :: forall (m :: * -> *). MonadGen m => m QCGen
seedQCGen =
  Int -> QCGen
QuickCheck.mkQCGen (Int -> QCGen) -> m Int -> m QCGen
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GenT (GenBase m) Int -> m Int
forall a. GenT (GenBase m) a -> m a
forall (m :: * -> *) a. MonadGen m => GenT (GenBase m) a -> m a
fromGenT (Range Int -> GenT (GenBase m) Int
forall (m :: * -> *) a. (MonadGen m, Integral a) => Range a -> m a
Gen.integral_ Range Int
forall a. (Bounded a, Num a) => Range a
Range.constantBounded)

-- | Create a Hedgehog 'Gen' from a QuickCheck 'QuickCheck.Gen'.
--
--   By default the 'Gen' created will not have any shrinking, you can use
--   @Gen.@'Gen.shrink' if you have a shrink function which you would like to
--   apply.
--
quickcheck :: MonadGen m => QuickCheck.Gen a -> m a
quickcheck :: forall (m :: * -> *) a. MonadGen m => Gen a -> m a
quickcheck (QuickCheck.MkGen QCGen -> Int -> a
gen) =
  (Size -> m a) -> m a
forall (m :: * -> *) a. MonadGen m => (Size -> m a) -> m a
Gen.sized ((Size -> m a) -> m a) -> (Size -> m a) -> m a
forall a b. (a -> b) -> a -> b
$ \Size
size -> do
    QCGen
qcg <- m QCGen
forall (m :: * -> *). MonadGen m => m QCGen
seedQCGen
    a -> m a
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a -> m a) -> a -> m a
forall a b. (a -> b) -> a -> b
$
      QCGen -> Int -> a
gen QCGen
qcg (Size -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Size
size)

-- | Create a Hedgehog 'Gen' from a QuickCheck 'QuickCheck.Arbitrary' instance.
--
--   The Arbitrary's 'QuickCheck.shrink' function is used to provide shrinking
--   for the Hedgehog 'Gen'.
--
arbitrary :: (QuickCheck.Arbitrary a, MonadGen m) => m a
arbitrary :: forall a (m :: * -> *). (Arbitrary a, MonadGen m) => m a
arbitrary =
  (a -> [a]) -> m a -> m a
forall (m :: * -> *) a. MonadGen m => (a -> [a]) -> m a -> m a
Gen.shrink a -> [a]
forall a. Arbitrary a => a -> [a]
QuickCheck.shrink (m a -> m a) -> m a -> m a
forall a b. (a -> b) -> a -> b
$
    Gen a -> m a
forall (m :: * -> *) a. MonadGen m => Gen a -> m a
quickcheck Gen a
forall a. Arbitrary a => Gen a
QuickCheck.arbitrary