OddWord-1.0.0.2: test/Main.hs
{-# LANGUAGE Haskell2010, ScopedTypeVariables #-}
module Main where
import System.Exit
import Test.QuickCheck hiding ((.&.))
import Test.QuickCheck.Gen
import Data.Bits
import Data.Word
import Data.Word.Odd
import Control.Monad
data UFunc =
Add Integer | Mul Integer | Sub Integer | SubR Integer |
Div Integer | Mod Integer | Quot Integer | Rem Integer |
DivR Integer | ModR Integer | QuotR Integer | RemR Integer |
Neg | Abs | Inv | AddDigit |
And Integer | Or Integer | Xor Integer |
ClrB Int | SetB Int | InvB Int |
Shift Int | Rot Int | PopCnt
deriving Show
instance Arbitrary (UFunc) where
arbitrary = oneof [
choose (0, 0xffff) >>= return . Add,
choose (0, 0xffff) >>= return . Mul,
choose (0, 0xffff) >>= return . Sub,
choose (0, 0xffff) >>= return . SubR,
choose (0, 0xffff) >>= return . Div,
choose (0, 0xffff) >>= return . Mod,
choose (0, 0xffff) >>= return . Quot,
choose (0, 0xffff) >>= return . Rem,
choose (0, 0xffff) >>= return . DivR,
choose (0, 0xffff) >>= return . ModR,
choose (0, 0xffff) >>= return . QuotR,
choose (0, 0xffff) >>= return . RemR,
return Neg,
return Abs,
return Inv,
return AddDigit,
choose (0, 0xffff) >>= return . And,
choose (0, 0xffff) >>= return . Or,
choose (0, 0xffff) >>= return . Xor,
choose (0, 32) >>= return . ClrB,
choose (0, 32) >>= return . SetB,
choose (0, 32) >>= return . InvB,
choose (-32, 32) >>= return . Shift,
choose (-32, 32) >>= return . Rot,
return PopCnt]
safeDiv :: (Integral a, Bounded a) => a -> a -> a
safeDiv d 0 = maxBound
safeDiv d n = div d n
safeMod :: (Integral a) => a -> a -> a
safeMod d 0 = 0
safeMod d n = mod d n
safeQuot :: (Integral a, Bounded a) => a -> a -> a
safeQuot d 0 = maxBound
safeQuot d n = quot d n
safeRem :: (Integral a) => a -> a -> a
safeRem d 0 = 0
safeRem d n = rem d n
fromUFunc :: (Integral a, Bounded a, Bits a, Read a, Show a) => UFunc -> a -> a
fromUFunc (Add i) x = x + (fromInteger i)
fromUFunc (Mul i) x = x * (fromInteger i)
fromUFunc (Sub i) x = x - (fromInteger i)
fromUFunc (SubR i) x = (fromInteger i) - x
fromUFunc (Div i) x = safeDiv x (fromInteger i)
fromUFunc (Mod i) x = safeMod x (fromInteger i)
fromUFunc (Quot i) x = safeQuot x (fromInteger i)
fromUFunc (Rem i) x = safeRem x (fromInteger i)
fromUFunc (DivR i) x = safeDiv (fromInteger i) x
fromUFunc (ModR i) x = safeMod (fromInteger i) x
fromUFunc (QuotR i) x = safeQuot (fromInteger i) x
fromUFunc (RemR i) x = safeRem (fromInteger i) x
fromUFunc Neg x = negate x
fromUFunc Abs x = abs x
fromUFunc Inv x = complement x
fromUFunc AddDigit x = read . ('1':) $ show x
fromUFunc (And i) x = x .&. (fromInteger i)
fromUFunc (Or i) x = x .|. (fromInteger i)
fromUFunc (Xor i) x = xor x (fromInteger i)
fromUFunc (ClrB n) x = clearBit x n
fromUFunc (SetB n) x = setBit x n
fromUFunc (InvB n) x = complementBit x n
fromUFunc (Shift n) x = shift x n
fromUFunc (Rot n) x = rotate x n
fromUFunc PopCnt x = fromIntegral $ popCount x
type TestWord16 = OddWord Word32 (One (Zero (Zero (Zero (Zero ())))))
verifyTestWord16 :: [UFunc] -> Bool
verifyTestWord16 us =
let refFn = foldr (.) id $ map fromUFunc us :: Word16 -> Word16
tstFn = foldr (.) id $ map fromUFunc us :: TestWord16 -> TestWord16
in toInteger (refFn 0) == toInteger (tstFn 0)
preDefWordLengths :: [Int]
preDefWordLengths = [
bitSize (0 :: Word1), bitSize (0 :: Word2), bitSize (0 :: Word3),
bitSize (0 :: Word4), bitSize (0 :: Word5), bitSize (0 :: Word6),
bitSize (0 :: Word7), bitSize (0 :: Word8), bitSize (0 :: Word9),
bitSize (0 :: Word10), bitSize (0 :: Word11), bitSize (0 :: Word12),
bitSize (0 :: Word13), bitSize (0 :: Word14), bitSize (0 :: Word15),
bitSize (0 :: Word16), bitSize (0 :: Word17), bitSize (0 :: Word18),
bitSize (0 :: Word19), bitSize (0 :: Word20), bitSize (0 :: Word21),
bitSize (0 :: Word22), bitSize (0 :: Word23), bitSize (0 :: Word24),
bitSize (0 :: Word25), bitSize (0 :: Word26), bitSize (0 :: Word27),
bitSize (0 :: Word28), bitSize (0 :: Word29), bitSize (0 :: Word30),
bitSize (0 :: Word31), bitSize (0 :: Word32), bitSize (0 :: Word33),
bitSize (0 :: Word34), bitSize (0 :: Word35), bitSize (0 :: Word36),
bitSize (0 :: Word37), bitSize (0 :: Word38), bitSize (0 :: Word39),
bitSize (0 :: Word40), bitSize (0 :: Word41), bitSize (0 :: Word42),
bitSize (0 :: Word43), bitSize (0 :: Word44), bitSize (0 :: Word45),
bitSize (0 :: Word46), bitSize (0 :: Word47), bitSize (0 :: Word48),
bitSize (0 :: Word49), bitSize (0 :: Word50), bitSize (0 :: Word51),
bitSize (0 :: Word52), bitSize (0 :: Word53), bitSize (0 :: Word54),
bitSize (0 :: Word55), bitSize (0 :: Word56), bitSize (0 :: Word57),
bitSize (0 :: Word58), bitSize (0 :: Word59), bitSize (0 :: Word60),
bitSize (0 :: Word61), bitSize (0 :: Word62), bitSize (0 :: Word63)]
main :: IO ()
main = do
-- Verify lengths of predefined odd word synonyms
mapM_ (\(u,v) -> putStrLn (
showString "Error: Word" . shows u . showString " has length " $
shows v ".") >> exitFailure) $
map fst $ filter snd $ map (\t -> (t,uncurry (/=) t)) $
zip [1..] preDefWordLengths
-- Verify correctness of operations on a test word type
r <- quickCheckWithResult stdArgs {maxSuccess = 1000} verifyTestWord16
case r of
Success _ _ _ -> exitSuccess
_ -> exitFailure