morley-1.4.0: src/Michelson/Test/Gen.hs
-- SPDX-FileCopyrightText: 2020 Tocqueville Group
--
-- SPDX-License-Identifier: LicenseRef-MIT-TQ
{-# OPTIONS_GHC -Wno-orphans #-}
-- | Utilities for arbitrary data generation in property tests.
--
-- == Deprecation Notice
--
-- At the moment, this module exposes both Hedgehog generators and QuickCheck `Arbitrary`
-- instances for convenience.
-- However, `Arbitrary` instances should be considered deprecated and will eventually be removed.
module Michelson.Test.Gen
( minTimestamp
, maxTimestamp
, midTimestamp
, genMutez
, genTimestamp
, genValueKeyHash
, genValueMutez
, genValueInt
, genValueList
, genValueUnit
, genValuePair
, genValueTimestamp
) where
import Data.Time.Calendar (Day, addDays, diffDays)
import Data.Time.Clock (UTCTime(..))
import Data.Time.Format (defaultTimeLocale, parseTimeM)
import Hedgehog (MonadGen)
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range
import Test.QuickCheck (Arbitrary(..), choose)
import Michelson.Typed (KnownT, T(..), Value'(..))
import Tezos.Core
(Mutez(..), Timestamp, timestampFromSeconds, timestampFromUTCTime, timestampToSeconds,
unsafeMkMutez)
import Tezos.Crypto (genKeyHash)
instance Arbitrary (Value' instr 'TKeyHash) where
arbitrary = VKeyHash <$> arbitrary
instance Arbitrary (Value' instr 'TMutez) where
arbitrary = VMutez <$> arbitrary
instance Arbitrary (Value' instr 'TInt) where
arbitrary = VInt <$> arbitrary
instance (KnownT a, Arbitrary (Value' instr a)) =>
Arbitrary (Value' instr ('TList a)) where
arbitrary = VList <$> arbitrary
instance Arbitrary (Value' instr 'TUnit) where
arbitrary = pure VUnit
instance (Arbitrary (Value' instr a), Arbitrary (Value' instr b))
=> Arbitrary (Value' instr ('TPair a b)) where
arbitrary = VPair ... (,) <$> arbitrary <*> arbitrary
genValueKeyHash :: MonadGen m => m (Value' instr 'TKeyHash)
genValueKeyHash = VKeyHash <$> genKeyHash
genValueMutez :: MonadGen m => m (Value' instr 'TMutez)
genValueMutez = VMutez <$> genMutez
genValueInt :: MonadGen m => m (Value' instr 'TInt)
genValueInt = VInt <$> Gen.integral (Range.linearFrom 0 -1000 1000)
genValueList :: (MonadGen m, KnownT a) => m (Value' instr a) -> m (Value' instr ('TList a))
genValueList genA = VList <$> Gen.list (Range.linear 0 100) genA
genValueUnit :: Applicative m => m (Value' instr 'TUnit)
genValueUnit = pure VUnit
genValuePair :: MonadGen m => m (Value' instr a) -> m (Value' instr b) -> m (Value' instr ('TPair a b))
genValuePair genA genB = VPair ... (,) <$> genA <*> genB
minDay :: Day
minDay = fromMaybe (error "failed to parse day 2008-11-01") $
parseTimeM True defaultTimeLocale "%Y-%-m-%-d" "2008-11-01"
maxDay :: Day
maxDay = fromMaybe (error "failed to parse day 2024-11-01") $
parseTimeM True defaultTimeLocale "%Y-%-m-%-d" "2024-11-01"
minSec :: Integer
minSec = 0
maxSec :: Integer
maxSec = 86399
-- | Minimal (earliest) timestamp used for @Arbitrary (CValue 'CTimestamp)@
minTimestamp :: Timestamp
minTimestamp = timestampFromUTCTime $ UTCTime minDay (fromInteger minSec)
-- | Maximal (latest) timestamp used for @Arbitrary (CValue 'CTimestamp)@
maxTimestamp :: Timestamp
maxTimestamp = timestampFromUTCTime $ UTCTime maxDay (fromInteger maxSec)
-- | Median of 'minTimestamp' and 'maxTimestamp'.
-- Useful for testing (exactly half of generated dates will be before and after
-- this date).
midTimestamp :: Timestamp
midTimestamp = timestampFromUTCTime $
UTCTime ( ((maxDay `diffDays` minDay) `div` 2) `addDays` minDay)
(fromInteger $ (maxSec - minSec) `div` 2)
instance Arbitrary (Value' instr 'TTimestamp) where
arbitrary = VTimestamp <$> arbitrary
instance Arbitrary Mutez where
arbitrary = unsafeMkMutez <$> choose (unMutez minBound, unMutez maxBound)
instance Arbitrary Timestamp where
arbitrary =
timestampFromSeconds <$>
choose (timestampToSeconds minTimestamp, timestampToSeconds maxTimestamp)
genValueTimestamp :: MonadGen m => m (Value' instr 'TTimestamp)
genValueTimestamp = VTimestamp <$> genTimestamp
genMutez :: MonadGen m => m Mutez
genMutez = unsafeMkMutez <$> Gen.word64 (Range.linear (unMutez minBound) (unMutez maxBound))
genTimestamp :: MonadGen m => m Timestamp
genTimestamp =
timestampFromSeconds <$> Gen.integral
(Range.linear (timestampToSeconds minTimestamp) (timestampToSeconds maxTimestamp))