Skip to content

Commit

Permalink
Write arbitrary instance for data that uses sized
Browse files Browse the repository at this point in the history
By using sized we can have an arbitrary instance that actually
terminates and is configurable via standard QuickCheck
methods (e.g. generate, resize). This will allow testing with Datums and
will prevent users unintentionally stalling their tests when generating
Datums, BuiltinData, and Data. Fixes #172.
  • Loading branch information
Yasuke committed Dec 8, 2021
1 parent a53bfca commit 1395654
Showing 1 changed file with 49 additions and 3 deletions.
52 changes: 49 additions & 3 deletions plutus-pab/src/Plutus/PAB/Arbitrary.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
-- across to the test suite.
module Plutus.PAB.Arbitrary where

import Control.Monad (replicateM)
import Data.Aeson (Value)
import Data.Aeson qualified as Aeson
import Data.ByteString (ByteString)
Expand All @@ -29,7 +30,7 @@ import Plutus.Contract.StateMachine (ThreadToken)
import PlutusTx qualified
import PlutusTx.AssocMap qualified as AssocMap
import PlutusTx.Prelude qualified as PlutusTx
import Test.QuickCheck (Gen, oneof)
import Test.QuickCheck (Gen, Positive (..), oneof, sized)
import Test.QuickCheck.Arbitrary.Generic (Arbitrary, arbitrary, genericArbitrary, genericShrink, shrink)
import Test.QuickCheck.Instances ()
import Wallet (WalletAPIError)
Expand Down Expand Up @@ -156,8 +157,53 @@ instance Arbitrary ThreadToken where
shrink = genericShrink

instance Arbitrary PlutusTx.Data where
arbitrary = genericArbitrary
shrink = genericShrink
arbitrary = sized arbitraryData
where
arbitraryData :: Int -> Gen PlutusTx.Data
arbitraryData n =
oneof [ arbitraryConstr n
, arbitraryMap n
, arbitraryList n
, arbitraryI
, arbitraryB
]

arbitraryConstr 0 = do
(Positive ix) <- arbitrary
pure $ PlutusTx.Constr ix []
arbitraryConstr n = do
(n', m) <- segmentRange n
(Positive ix) <- arbitrary
args <- replicateM m (arbitraryData n')
pure $ PlutusTx.Constr ix args

arbitraryMap 0 = pure $ PlutusTx.Map []
arbitraryMap n = do
(n', m) <- segmentRange n
kvs <- replicateM m (arbitraryPair n')
pure $ PlutusTx.Map kvs

arbitraryPair n = do
(n', _) <- segmentRange n
(,) <$> arbitraryData n' <*> arbitraryData n'

arbitraryList 0 = pure $ PlutusTx.List []
arbitraryList n = do
(n', m) <- segmentRange n
es <- replicateM m (arbitraryData n')
pure $ PlutusTx.List es

arbitraryI =
PlutusTx.I <$> arbitrary

arbitraryB =
PlutusTx.B <$> arbitrary

-- Used to break the sized generator up more or less evenly
segmentRange n = do
(Positive m) <- arbitrary
let n' = n `div` (m + 1) -- Prevent division by 0
pure (n', m)

instance Arbitrary PlutusTx.BuiltinData where
arbitrary = PlutusTx.dataToBuiltinData <$> arbitrary
Expand Down

0 comments on commit 1395654

Please sign in to comment.