1 | module Main where |
---|
2 | |
---|
3 | import qualified Data.ByteString as B |
---|
4 | import qualified Codec.FEC as FEC |
---|
5 | import System.IO (withFile, IOMode(..)) |
---|
6 | import System.Random |
---|
7 | import Data.List (sortBy) |
---|
8 | |
---|
9 | import Test.QuickCheck |
---|
10 | |
---|
11 | -- | Return true if the given @k@ and @n@ values are valid |
---|
12 | isValidConfig :: Int -> Int -> Bool |
---|
13 | isValidConfig k n |
---|
14 | | k >= n = False |
---|
15 | | k < 1 = False |
---|
16 | | n < 1 = False |
---|
17 | | otherwise = True |
---|
18 | |
---|
19 | randomTake :: Int -> Int -> [a] -> [a] |
---|
20 | randomTake seed n values = map snd $ take n sortedValues where |
---|
21 | sortedValues = sortBy (\a b -> compare (fst a) (fst b)) taggedValues |
---|
22 | taggedValues = zip rnds values |
---|
23 | rnds :: [Float] |
---|
24 | rnds = randoms gen |
---|
25 | gen = mkStdGen seed |
---|
26 | |
---|
27 | testFEC k n len seed = FEC.decode fec someTaggedBlocks == origBlocks where |
---|
28 | origBlocks = map (\i -> B.replicate len $ fromIntegral i) [0..(k - 1)] |
---|
29 | fec = FEC.fec k n |
---|
30 | secondaryBlocks = FEC.encode fec origBlocks |
---|
31 | taggedBlocks = zip [0..] (origBlocks ++ secondaryBlocks) |
---|
32 | someTaggedBlocks = randomTake seed k taggedBlocks |
---|
33 | |
---|
34 | prop_FEC :: Int -> Int -> Int -> Int -> Property |
---|
35 | prop_FEC k n len seed = |
---|
36 | isValidConfig k n && n < 256 && len < 1024 ==> testFEC k n len seed |
---|
37 | |
---|
38 | checkDivide :: Int -> IO () |
---|
39 | checkDivide n = do |
---|
40 | let input = B.replicate 1024 65 |
---|
41 | parts <- FEC.secureDivide n input |
---|
42 | if FEC.secureCombine parts == input |
---|
43 | then return () |
---|
44 | else fail "checkDivide failed" |
---|
45 | |
---|
46 | checkEnFEC :: Int -> IO () |
---|
47 | checkEnFEC len = do |
---|
48 | testdata <- withFile "/dev/urandom" ReadMode (\handle -> B.hGet handle len) |
---|
49 | let [a, b, c, d, e] = FEC.enFEC 3 5 testdata |
---|
50 | if FEC.deFEC 3 5 [b, e, d] == testdata |
---|
51 | then return () |
---|
52 | else fail "deFEC failure" |
---|
53 | |
---|
54 | main = do |
---|
55 | mapM_ (check (defaultConfig { configMaxTest = 1000, configMaxFail = 10000 })) [prop_FEC] |
---|
56 | mapM_ checkDivide [1, 2, 3, 4, 10] |
---|
57 | mapM_ checkEnFEC [1, 2, 3, 4, 5, 1024 * 1024] |
---|