elocrypt-0.3.2: test/Test/ElocryptTest.hs
{-# LANGUAGE TemplateHaskell #-}
module Test.ElocryptTest where
import Control.Monad
import Control.Monad.Random hiding (next)
import Data.Maybe
import System.Random hiding (next)
import Test.QuickCheck
import Test.Tasty.QuickCheck (testProperty)
import Test.Tasty.TH
import Data.Elocrypt
import Data.Elocrypt.Trigraph
import Test.Elocrypt.Instances
tests = $(testGroupGenerator)
prop_genPasswordShouldBeUnique :: GreaterThan2 Int -> StdGen -> Bool
prop_genPasswordShouldBeUnique (GT2 len) gen
= p /= fst (genPassword len gen')
where (p, gen') = genPassword len gen
prop_genPasswordsShouldBeUnique :: GreaterThan2 Int -> StdGen -> Bool
prop_genPasswordsShouldBeUnique (GT2 len) gen
= p /= ps
where (p:ps:_) = fst (genPasswords len gen)
prop_newPasswordShouldBeLength :: GreaterThan2 Int -> StdGen -> Bool
prop_newPasswordShouldBeLength (GT2 len) gen = length (newPassword len gen) == len
prop_newPasswordShouldConsistOfAlphabet :: GreaterThan2 Int -> StdGen -> Bool
prop_newPasswordShouldConsistOfAlphabet (GT2 len) gen
= all ((flip elem) alphabet) (newPassword len gen)
prop_newPasswordsShouldBeUnique :: GreaterThan2 Int -> StdGen -> Bool
prop_newPasswordsShouldBeUnique (GT2 len) gen
= p /= ps
where (p:ps:_) = newPasswords len gen
prop_first2ShouldHaveLength2 :: StdGen -> Bool
prop_first2ShouldHaveLength2 g = length (evalRand first2 g) == 2
prop_nextShouldSkip0Weights :: AlphaChar -> AlphaChar -> StdGen -> Property
prop_nextShouldSkip0Weights (Alpha c1) (Alpha c2) gen = isCandidate next' [c1, c2]
where next' = evalRand (next . reverse $ [c1, c2]) gen
prop_lastNShouldSkip0Weights :: AlphaChar -> AlphaChar -> Int -> StdGen -> Property
prop_lastNShouldSkip0Weights (Alpha c1) (Alpha c2) len gen
= len > 0 ==> lastNShouldSkip0Weights' lastN'
where f2 = [c1, c2]
lastN' = evalRand (lastN (reverse [c1, c2]) len) gen
lastNShouldSkip0Weights' :: String -> Property
lastNShouldSkip0Weights' (p:ps:pss:psss) = isCandidate p [pss, ps] .&&.
lastNShouldSkip0Weights' (ps:pss:psss)
lastNShouldSkip0Weights' _ = property True
-- Utility functions
isCandidate :: Char -> String -> Property
isCandidate c (s:ss:sss) = hasCandidates f2 ==>
isJust $ elem c `liftM` findNextCandidates f2
where f2 = [s, ss]
isCandidate _ _ = undefined -- This really shouldn't ever happen
hasCandidates :: String -> Bool
hasCandidates s = (not . null) `liftM` findNextCandidates s == Just True
findNextCandidates :: String -> Maybe [Char]
findNextCandidates (c1:c2:_) = map fst `liftM` frequency
where f2 = [c1, c2]
frequency = (filter ((/=0) . snd) . zip ['a'..'z']) `liftM` findFrequency f2
findNextCandidates _ = Nothing -- This really shouldn't ever happen