add a property test for pupdate and updateMap

This commit is contained in:
fanghr 2022-05-20 03:15:21 +08:00
parent bce9b45c25
commit cdffbeffc9
No known key found for this signature in database
GPG key ID: 35CD9A71CD5D5870
3 changed files with 87 additions and 4 deletions

View file

@ -9,17 +9,33 @@ module Spec.Utils (tests) where
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
import Agora.Utils (phalve, pisUniq, pmergeBy, pmsort, pnubSort) import Agora.Utils (phalve, pisUniq, pmergeBy, pmsort, pnubSort, pupdate)
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
import Data.List (nub, sort) import Data.List (nub, sort)
import Data.Set as S import Data.Map qualified as M
import Data.Set qualified as S
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
import Control.Monad.Cont (cont, runCont)
import Test.Tasty (TestTree) import Test.Tasty (TestTree)
import Test.Tasty.QuickCheck (testProperty) import Test.Tasty.QuickCheck (
Arbitrary (arbitrary),
Property,
Testable (property),
elements,
forAll,
suchThat,
testProperty,
(.&&.),
)
import Test.Util (updateMap)
--------------------------------------------------------------------------------
import PlutusTx.AssocMap qualified as AssocMap
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@ -30,6 +46,7 @@ tests =
, testProperty "'phalve' splits a list in half as expected" prop_halveCorrect , testProperty "'phalve' splits a list in half as expected" prop_halveCorrect
, testProperty "'pnubSort' sorts a list and remove duplicate elements" prop_nubSortProperly , testProperty "'pnubSort' sorts a list and remove duplicate elements" prop_nubSortProperly
, testProperty "'pisUniq' can tell whether all elements in a list are unique" prop_uniqueList , testProperty "'pisUniq' can tell whether all elements in a list are unique" prop_uniqueList
, testProperty "'pupdate' updates assoc maps as 'updateMap' does" prop_updateAssocMapParity
] ]
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@ -142,3 +159,68 @@ prop_uniqueList l = isUnique == expected
-- --
isUnique = plift $ pisUniq # pconstant l isUnique = plift $ pisUniq # pconstant l
{- | Test the parity between 'updateMap' and 'pupdate',
also ensure they both work correctly.
-}
prop_updateAssocMapParity :: Property
prop_updateAssocMapParity =
runCont
( do
-- Generate a bunch unique keys.
keys <-
cont $
forAll $
arbitrary @(S.Set Integer) `suchThat` (not . S.null)
-- Generate key-value pairs.
kvPairs <- cont $ forAll $ mapM (\k -> (k,) <$> (arbitrary @Integer)) $ S.toList keys
let initialMap = AssocMap.fromList kvPairs
pinitialMap :: Term _ _
pinitialMap = phoistAcyclic $ pconstant initialMap
referenceMap = M.fromList kvPairs
let pupdatedValue :: Maybe Integer -> Term _ (PMaybe PInteger)
pupdatedValue updatedValue = phoistAcyclic $ case updatedValue of
Nothing -> pcon PNothing
Just v -> pcon $ PJust $ pconstant v
-- Given the key and the updated value, test the parity
parity key updatedValue =
let native = updateMap (const updatedValue) key initialMap
plutarch :: AssocMap.Map Integer Integer
plutarch =
plift $
pupdate
# plam (\_ -> pupdatedValue updatedValue)
# pconstant key
# pinitialMap
expected =
AssocMap.fromList $
M.toList $
M.update (const updatedValue) key referenceMap
in expected == native
&& expected == plutarch
-- Select a key, generate a maybe value.
-- The value at the key should be set to the new value or removed.
(targetKey, _) <- cont $ forAll $ elements kvPairs
updatedValue <- cont $ forAll $ arbitrary @(Maybe Integer)
-- Now what if the key doesn't exist in our map?
nonexistentKey <-
cont $
forAll $
arbitrary @Integer `suchThat` (\k -> not $ S.member k keys)
pure
( property (parity targetKey updatedValue)
.&&. property (parity nonexistentKey updatedValue)
)
)
id

View file

@ -246,7 +246,7 @@ closedBoundedInterval from to = PlutusTx.intersection (PlutusTx.from from) (Plut
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
{- | / O(n) /. The expression @'updateMap' f k v@ will update the value @x@ at key @k@. {- | / O(n) /. The expression @'updateMap' f k v@ will update the value @x@ at key @k@.
If @f x@ is Nothing, the key-value pair will be deleted from the map, otherwise the If @f x@ is Nothing, the key-value pair will be deleted from the map, otherwise the
value will be updated. value will be updated.
-} -}
updateMap :: Eq k => (v -> Maybe v) -> k -> AssocMap.Map k v -> AssocMap.Map k v updateMap :: Eq k => (v -> Maybe v) -> k -> AssocMap.Map k v -> AssocMap.Map k v

View file

@ -114,6 +114,7 @@ common test-deps
, agora , agora
, apropos , apropos
, apropos-tx , apropos-tx
, mtl
, QuickCheck , QuickCheck
, quickcheck-instances , quickcheck-instances
, tasty , tasty