agora/agora-test/Spec/Utils.hs

144 lines
4.1 KiB
Haskell

{- |
Module : Spec.Utils
Maintainer : emi@haskell.fyi
Description: Tests for utility functions in 'Agora.Utils'.
Tests for utility functions in 'Agora.Utils'.
-}
module Spec.Utils (tests) where
--------------------------------------------------------------------------------
import Agora.Utils (phalve, pisUniq, pmergeBy, pmsort, pnubSort)
--------------------------------------------------------------------------------
import Data.List (nub, sort)
import Data.Set as S
--------------------------------------------------------------------------------
import Test.Tasty (TestTree)
import Test.Tasty.QuickCheck (testProperty)
--------------------------------------------------------------------------------
tests :: [TestTree]
tests =
[ testProperty "'pmsort' sorts a list properly" prop_msortCorrect
, testProperty "'pmerge' merges two sorted lists into one sorted list" prop_mergeCorrect
, testProperty "'phalve' splits a list in half as expected" prop_halveCorrect
, 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
]
--------------------------------------------------------------------------------
-- | Yield true if 'Agora.Utils.pmsort' sorts a given list correctly.
prop_msortCorrect :: [Integer] -> Bool
prop_msortCorrect l = sorted == expected
where
-- Expected sorted list, using 'Data.List.sort'.
expected :: [Integer]
expected = sort l
--
psorted :: Term _ (PBuiltinList PInteger)
psorted = pmsort # pconstant l
sorted :: [Integer]
sorted = plift psorted
-- | Yield true if 'Agora.Utils.pmerge' merges two list into a ordered list correctly.
prop_mergeCorrect :: [Integer] -> [Integer] -> Bool
prop_mergeCorrect a b = merged == expected
where
-- Sorted list a and b
sa = sort a
sb = sort b
-- Merge two lists which are assumed to be ordered.
merge :: [Integer] -> [Integer] -> [Integer]
merge xs [] = xs
merge [] ys = ys
merge sx@(x : xs) sy@(y : ys)
| x <= y = x : merge xs sy
| otherwise = y : merge sx ys
expected :: [Integer]
expected = merge sa sb
--
pmerged :: Term _ (PBuiltinList PInteger)
pmerged = pmergeBy # plam (#<) # pconstant sa # pconstant sb
merged :: [Integer]
merged = plift pmerged
{- | Yield true if Plutarch level 'Agora.Utils.phalve' splits a given list
as its Haskell level counterpart does.
-}
prop_halveCorrect :: [Integer] -> Bool
prop_halveCorrect l = halved == expected
where
-- Halve a list.
halve :: [Integer] -> ([Integer], [Integer])
halve xs = go xs xs
where
go xs [] = ([], xs)
go (x : xs) [_] = ([x], xs)
go (x : xs) (_ : _ : ys) =
let (first, last) =
go xs ys
in (x : first, last)
go [] _ = ([], [])
expected :: ([Integer], [Integer])
expected = halve l
--
phalved :: Term _ (PPair (PBuiltinList PInteger) (PBuiltinList PInteger))
phalved = phalve # pconstant l
halved :: ([Integer], [Integer])
halved =
let f = plift $ pmatch phalved $ \(PPair x _) -> x
s = plift $ pmatch phalved $ \(PPair _ x) -> x
in (f, s)
{- | Yield true if 'Agora.Utils.pnubSort' sorts and removes
duplicate elements from a given list.
-}
prop_nubSortProperly :: [Integer] -> Bool
prop_nubSortProperly l = nubbed == expected
where
-- Sort and list and then nub it.
expected :: [Integer]
expected = nub $ sort l
--
pnubbed :: Term _ (PBuiltinList PInteger)
pnubbed = pnubSort # pconstant l
nubbed :: [Integer]
nubbed = plift pnubbed
{- | Yield true if 'Agora.Utils.isUnique' can correctly determine
whether a given list only contains unique elements or not.
-}
prop_uniqueList :: [Integer] -> Bool
prop_uniqueList l = isUnique == expected
where
-- Convert input list to a set.
-- If the set's size equals to list's size,
-- the list only contains unique elements.
expected :: Bool
expected = S.size (S.fromList l) == length l
--
isUnique = plift $ pisUniq # pconstant l