packages feed

rset-1.0.0: test/Prop.hs

import Data.List
import Data.Word
import Safe
import System.Environment
import System.Exit
import Test.QuickCheck
import Test.QuickCheck.Test

import qualified Data.Set.Range as R


-- | Test the empty set checking.
nullTest
  :: [Word8] -- ^ points
  -> Bool    -- ^ result
nullTest xs = rset == set
  where
    rset = R.null (R.fromList xs)
    set  = null xs

-- | Test the number of stored points in a set.
sizeTest
  :: [Word8] -- ^ points
  -> Bool    -- ^ result
sizeTest xs = rset == set
  where
    rset = (R.size . R.fromList) xs :: Integer
    set  = (genericLength . nub) xs :: Integer

-- | Test the conversion from and to ascending lists.
ascListTest
  :: [Word8] -- ^ points
  -> Bool    -- ^ result
ascListTest xs = R.fromList xs == (R.fromAscList . sort) xs

-- | Test the conversion from and to descending lists.
descListTest
  :: [Word8] -- ^ points
  -> Bool    -- ^ result
descListTest xs = R.fromList xs == (R.fromDescList . sortBy (flip compare)) xs

-- | Test the conversion from and to lists.
listTest
  :: [Word8] -- ^ points
  -> Bool    -- ^ result
listTest xs = (sort . nub) xs == (R.toList . R.fromList) xs

-- | Test adding new points to the range set.
insertPointTest
  :: [Word8] -- ^ points
  -> Word8   -- ^ point
  -> Bool    -- ^ result
insertPointTest xs y = rset == set
  where
    rset = R.toList $ R.insertPoint y (R.fromList xs)
    set  = sort $ nub (y:xs)

-- | Test adding a new range into the range set.
insertRangeTest
  :: [Word8]       -- ^ points
  -> (Word8,Word8) -- ^ range
  -> Bool          -- ^ result
insertRangeTest xs (a,b) = rset == set
  where
    lo   = min a b
    hi   = max a b
    rset = R.toList $ R.insertRange (lo,hi) (R.fromList xs)
    set  = sort $ nub ([lo .. hi] ++ xs)

-- | Test removing a single point from the range set.
removePointTest
  :: [Word8] -- ^ points
  -> Word8   -- ^ point to remove
  -> Bool    -- ^ result
removePointTest xs y = rset == set
  where
    rset = R.toList $ R.removePoint y (R.fromList xs)
    set  = sort $ nub $ filter (/= y) xs

-- | Test removing a range from the range set.
removeRangeTest
  :: [Word8]       -- ^ points
  -> (Word8,Word8) -- ^ range
  -> Bool          -- ^ result
removeRangeTest xs (a,b) = rset == set
  where
    lo   = min a b
    hi   = max a b
    rset = R.toList $ R.removeRange (lo,hi) (R.fromList xs)
    set  = sort $ nub $ filter (not . flip elem [lo .. hi]) xs

-- | Test the range set membership.
queryPointTest
  :: [Word8] -- ^ points
  -> Word8   -- ^ point
  -> Bool    -- ^ result
queryPointTest xs y = rset == set
  where
    rset = R.queryPoint y (R.fromList xs)
    set  = elem y xs

-- | Test the range set membership.
queryRangeTest
  :: [Word8]       -- ^ points
  -> (Word8,Word8) -- ^ range
  -> Bool          -- ^ result
queryRangeTest xs (a,b) = rset == set
  where
    lo   = min a b
    hi   = max a b
    rset = R.queryRange (lo,hi) (R.fromList xs)
    set  = all (flip elem xs) [lo .. hi]

-- | Test the diffence of one set from another.
differenceTest
  :: [Word8] -- ^ points
  -> [Word8] -- ^ points
  -> Bool    -- ^ result
differenceTest xs ys = rset == set
  where
    rset = R.toList $ R.difference (R.fromList xs) (R.fromList ys)
    set  = sort $ nub $ filter (not . flip elem ys) xs

-- | Test the intersection of two sets.
intersectTest
  :: [Word8] -- ^ points
  -> [Word8] -- ^ points
  -> Bool    -- ^ result
intersectTest xs ys = rset == set
  where
    rset = R.toList $ R.intersect (R.fromList xs) (R.fromList ys)
    set  = sort $ nub $ intersect xs ys

-- | Test the union of two sets.
unionTest
  :: [Word8] -- ^ points
  -> [Word8] -- ^ points
  -> Bool    -- ^ result
unionTest xs ys = rset == set
  where
    rset = R.toList $ R.union (R.fromList xs) (R.fromList ys)
    set  = sort $ nub $ union xs ys

-- | Print a name of the property test and execute the QuickCheck
-- algorithm.
runTest
  :: Args               -- ^ property test settings
  -> (String, Property) -- ^ name & test
  -> IO Result          -- ^ result
runTest args (name, prop) = do
  result <- quickCheckWithResult args prop
  putStr $ unwords [name, output result]
  return result

-- | List of property tests to run.
tests
  :: [(String,Property)] -- ^ name & test function
tests = [
    ("null       ", property nullTest)
  , ("size       ", property sizeTest)
  , ("ascList    ", property ascListTest)
  , ("descList   ", property descListTest)
  , ("list       ", property listTest)
  , ("insertPoint", property insertPointTest)
  , ("insertRange", property insertRangeTest)
  , ("removePoint", property removePointTest)
  , ("removeRange", property removeRangeTest)
  , ("queryPoint ", property queryPointTest)
  , ("queryRange ", property queryRangeTest)
  , ("difference ", property differenceTest)
  , ("intersect  ", property intersectTest)
  , ("union      ", property unionTest) ]

-- | Parse command-line options into test arguments. In case invalid or
-- no arguments were provided, the test fallbacks into a default value.
parseArguments
  :: [String] -- ^ command-line arguments
  -> Args     -- ^ test settings
parseArguments []    = stdArgs { maxSuccess=20000,           chatty=False }
parseArguments (x:_) = stdArgs { maxSuccess=readDef 20000 x, chatty=False }

-- | Evaluate test results and set appropriate process exit code.
main
  :: IO ()
main = do
  putStrLn "\nRunning property tests:"
  args    <- getArgs
  results <- mapM (runTest $ parseArguments args) tests
  if all isSuccess results then exitSuccess else exitFailure