elocrypt-2.1.0: test/Test/Elocrypt/UtilsTest.hs
{-# LANGUAGE TemplateHaskell #-}
module Test.Elocrypt.UtilsTest where
import Control.Monad.Random
import Data.Maybe (isNothing)
import Data.List (find, elem, sort)
import Data.Ratio ((%))
import qualified Data.Map as M
import Test.QuickCheck
import Test.QuickCheck.Monadic (monadicIO)
import Test.Tasty
import Test.Tasty.QuickCheck (testProperty)
import Test.Tasty.TH
import Data.Elocrypt.Utils
import Test.Elocrypt.QuickCheck
import Test.Elocrypt.Instances
tests :: TestTree
tests = $(testGroupGenerator)
-- |Maps letters to all digits 0-9
prop_numeralConversionsHasAllDigits :: Bool
prop_numeralConversionsHasAllDigits
= sort digits == ['0'..'9']
where digits = M.foldr (++) [] numeralConversions
-- |toDigit never returns a letter that looks like a number
prop_toDigitDoesntLookLikeNumber :: Char -> Bool
prop_toDigitDoesntLookLikeNumber c
= isNothing $ find (`elem` candidates) c'
where candidates = M.keys numeralConversions
c' = toDigit c
-- |toSymbol never returns a letter that looks like a symbol
prop_toSymbolDoesntLookLikeSymbol :: Char -> Bool
prop_toSymbolDoesntLookLikeSymbol c
= isNothing $ find (`elem` M.keys symbolConversions) c'
where c' = toSymbol c
prop_toSymbolReturnsSymbols :: Bool
prop_toSymbolReturnsSymbols = all isSymbol ss
where ks = M.keys symbolConversions
ss = concatMap toSymbol ks
-- |isSymbol returns false for letters and numbers
prop_isSymbolAlphaNumReturnsFalse :: Char -> Property
prop_isSymbolAlphaNumReturnsFalse c
= c `elem` (['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9']) ==> not (isSymbol c)
prop_isSymbolWhitespaceReturnsFalse :: Bool
prop_isSymbolWhitespaceReturnsFalse = all (not . isSymbol) " \n"
-- |updateR always updates when prob = 1/0
prop_updateRAlwaysUpdates :: String -> StdGen -> Bool
prop_updateRAlwaysUpdates s = evalRand $ do
let f _ = return '*'
prob = 99999 % 1 -- Make prob absurdly high since we can't use 0 denoms
s' <- updateR f prob s
-- Make sure almost all letters are '*'
return $ length (filter (=='*') s') >= length s - 1
-- |updateR never updates when prob = 0/1
prop_updateRNeverUpdates :: String -> StdGen -> Bool
prop_updateRNeverUpdates s = evalRand $ do
let f _ = return '*'
prob = 0 % 1
s' <- updateR f prob s
return $ s == s'
-- |update1 Always updates at least one character
prop_update1AlwaysUpdates1 :: String -> Property
prop_update1AlwaysUpdates1 s = not (null s) ==> do
let f = (const . return) '*'
pos <- choose (0, length s - 1)
s' <- update1 f s pos
return $ elem '*' s'
-- |update1 allows empty string
prop_update1DoesntCrashOnEmpty :: Property
prop_update1DoesntCrashOnEmpty = monadicIO $ do
let f _ = return '*'
s <- update1 f "" 0
return (s == "")