packages feed

morloc-0.33.0: test-suite/PropertyTests.hs

module PropertyTests
  ( propertyTests
  ) where

import Morloc.Namespace

import qualified Control.Monad as CM
import qualified Data.Set as Set
import qualified Data.Text as T
import qualified Test.QuickCheck as QC
import Safe (headMay)
import Test.Tasty
import Test.Tasty.QuickCheck as TQC

propertyTests =
  testGroup
    "internal list function properties"
    [ TQC.testProperty "unique makes unique lists" prop_unique_unique
    , TQC.testProperty "unique preserves original order" prop_unique_preserves_order
    , TQC.testProperty "duplicates makes unique lists" prop_duplicates_unique
    , TQC.testProperty "duplicates preserves original order" prop_duplicates_preserves_order
    ]

-- for the uniq family of functions (unique, duplicates, isSorted), I will test
-- on the numbers 1 to 5. If the desired property holds over this set, they
-- will hold over any ordered set. 
one2five :: [Int] -> [Int]
one2five = map (\x -> mod (abs x) 5)

prop_unique_unique :: [Int] -> Bool
prop_unique_unique [] = True
prop_unique_unique xs =
  let xs' = one2five xs
  in length (unique xs') == Set.size (Set.fromList xs') 

-- This test asserts that the first element in the original and unique list is
-- the same. This guarantee alone does not entirely guantee that the original
-- order is preserved, but it is close.
prop_unique_preserves_order :: [Int] -> Bool
prop_unique_preserves_order xs = headMay xs == headMay (unique xs)

-- Each element in the duplicates return list is unique
prop_duplicates_unique :: [Int] -> Bool
prop_duplicates_unique [] = True
prop_duplicates_unique xs =
  let xs' = duplicates (one2five xs)
  in length xs' == Set.size (Set.fromList xs')

prop_duplicates_preserves_order :: [Int] -> Bool
prop_duplicates_preserves_order xs = f Set.empty xs (duplicates xs) where
  f _ _ [] = True
  f _ [] _ = False
  f skipped (y:rs) (y':rs')
    -- if the original and duplicated elements match:
    | y == y' =
      -- if the current element was previously skipped
      if Set.member y' skipped
      -- then the duplicates function failed to respect the initial order
      then False
      -- else continue checking on the next elements
      else f skipped rs rs'
    -- otherwise store record the skipped value and continue
    | otherwise = f (Set.insert y skipped) rs (y':rs')