module Codec.GrayQC ( test ) where import Codec.Gray import Data.List (nub) import Data.Word (Word8) import Test.Framework as TF (Test, testGroup) import Test.Framework.Providers.QuickCheck2 (testProperty) import Test.QuickCheck ((==>), Property, Gen, Arbitrary, arbitrary, choose, property, sized) prop_successive_values_differ_in_one_place1 :: Int -> Property prop_successive_values_differ_in_one_place1 k = k > 0 ==> nub (diffCounts xs) == [1] where xs = grayCodes k' k' = min 10 k -- avoid long tests data TestParms = TestParms String Int deriving Show sizedTestParms :: Int -> Gen TestParms sizedTestParms n = do let n' = 2 + (min 8 n) -- keep number of digits and bits low to speed up tests let digits = take n' ['a' .. 'z'] k <- choose (1,min 4 (n+1)) return $ TestParms digits k instance Arbitrary TestParms where arbitrary = sized sizedTestParms prop_successive_values_differ_in_one_place2 :: TestParms -> Property prop_successive_values_differ_in_one_place2 (TestParms ds k) = property $ nub (diffCounts xs) == [1] where xs = naryGrayCodes ds k diffCounts :: Eq b => [[b]] -> [Int] diffCounts [] = [] diffCounts [_] = [] diffCounts (x1:x2:xs) = (diffCount x1 x2) : diffCounts (x2:xs) diffCount :: Eq b => [b] -> [b] -> Int diffCount as bs = length $ filter (\x -> x) $ zipWith (/=) as bs prop_encoding_round_trippable :: Int -> Property prop_encoding_round_trippable n = n >= 0 ==> (grayToIntegral . integralToGray $ n) == n prop_decoding_round_trippable :: Int -> Property prop_decoding_round_trippable n = n >= 0 ==> (integralToGray . grayToIntegral $ n) == n prop_integralToGray_same_as_encode :: Word8 -> Property prop_integralToGray_same_as_encode n = property $ integralToGray n == boolsToIntegral bits where bits = (grayCodes 8) !! (fromIntegral n) boolsToIntegral :: Num c => [Bool] -> c boolsToIntegral bs = f 0 1 . reverse $ bs where f total _ [] = total f total factor (b:bs') = f total' (factor*2) bs' where total' = if b then total + factor else total -- integralToBools :: (Integral a, Bits a) => a -> [Bool] -- integralToBools 0 = [] -- integralToBools n = integralToBools (n `shiftR` 1) ++ [f (n `mod` 2)] -- where f 0 = False -- f 1 = True test :: Test test = testGroup "Codec.GrayQC" [ testProperty "prop_successive_values_differ_in_one_place1" prop_successive_values_differ_in_one_place1, testProperty "prop_successive_values_differ_in_one_place2" prop_successive_values_differ_in_one_place2, testProperty "prop_encoding_round_trippable" prop_encoding_round_trippable, testProperty "prop_decoding_round_trippable" prop_decoding_round_trippable, testProperty "prop_integralToGray_same_as_encode" prop_integralToGray_same_as_encode ]