packages feed

bitvec-0.2.0.0: test/Tests/MVector.hs

module Tests.MVector where

import Support

import Control.Monad
import Control.Monad.ST
import Data.Bit
import Data.Proxy
import Data.STRef
import qualified Data.Vector.Generic             as V
import qualified Data.Vector.Generic.Mutable     as M (basicInitialize, basicSet)
import qualified Data.Vector.Generic.New         as N
import qualified Data.Vector.Unboxed.Bit         as B hiding (reverse)
import qualified Data.Vector.Unboxed             as B
import qualified Data.Vector.Unboxed.Mutable.Bit as U
import qualified Data.Vector.Unboxed.Mutable     as M
import Test.Framework (Test, testGroup)
import Test.Framework.Providers.HUnit (testCase)
import Test.Framework.Providers.QuickCheck2 (testProperty)
import Test.HUnit (assertEqual)
import Test.QuickCheck
import Test.QuickCheck.Classes

mvectorTests :: Test
mvectorTests = testGroup "Data.Vector.Unboxed.Mutable.Bit"
    [ testGroup "Data.Vector.Unboxed.Mutable functions"
        [ testProperty "slice"          prop_slice_def
        , testProperty "grow"           prop_grow_def
        ]
    , testProperty "wordLength"     prop_wordLength_def
    , testGroup "Read/write Words"
        [ testProperty "readWord"       prop_readWord_def
        , testProperty "writeWord"      prop_writeWord_def
        , testProperty "cloneFromWords" (prop_cloneFromWords_def 10000)
        , testProperty "cloneToWords"   prop_cloneToWords_def
        ]
    , testGroup "mapMInPlaceWithIndex"
        [ testProperty "maps left to right" prop_mapMInPlaceWithIndex_leftToRight
        , testProperty "wordSize-aligned"   prop_mapMInPlaceWithIndex_aligned
        ]
    , testProperty "countBits"      prop_countBits_def
    , testProperty "listBits"       prop_listBits_def
    , testProperty "reverseInPlace" prop_reverseInPlace_def
    , testGroup "MVector laws" $ map (uncurry testProperty) $ lawsProperties $ muvectorLaws (Proxy :: Proxy Bit)
    , testCase "basicInitialize 1" case_write_init_read1
    , testCase "basicInitialize 2" case_write_init_read2
    , testCase "basicInitialize 3" case_write_init_read3
    , testCase "basicInitialize 4" case_write_init_read4
    , testCase "basicSet 1" case_write_set_read1
    , testCase "basicSet 2" case_write_set_read2
    , testCase "basicSet 3" case_write_set_read3
    , testCase "basicSet 4" case_write_set_read4
    , testCase "basicSet 5" case_set_read1
    , testCase "basicSet 6" case_set_read2
    , testCase "basicSet 7" case_set_read3
    , testCase "basicUnsafeCopy1" case_write_copy_read1
    , testCase "basicUnsafeCopy2" case_write_copy_read2
    , testCase "basicUnsafeCopy3" case_write_copy_read3
    , testCase "basicUnsafeCopy4" case_write_copy_read4
    , testCase "basicUnsafeCopy5" case_write_copy_read5
    ]

case_write_init_read1 :: IO ()
case_write_init_read1 = assertEqual "should be equal" (Bit True) $ runST $ do
    arr <- M.new 2
    M.write arr 0 (Bit True)
    M.basicInitialize (M.slice 1 1 arr)
    M.read arr 0

case_write_init_read2 :: IO ()
case_write_init_read2 = assertEqual "should be equal" (Bit True) $ runST $ do
    arr <- M.new 2
    M.write arr 1 (Bit True)
    M.basicInitialize (M.slice 0 1 arr)
    M.read arr 1

case_write_init_read3 :: IO ()
case_write_init_read3 = assertEqual "should be equal" (Bit True, Bit True) $ runST $ do
    arr <- M.new 2
    M.write arr 0 (Bit True)
    M.write arr 1 (Bit True)
    M.basicInitialize (M.slice 1 0 arr)
    (,) <$> M.read arr 0 <*> M.read arr 1

case_write_init_read4 :: IO ()
case_write_init_read4 = assertEqual "should be equal" (Bit True, Bit True) $ runST $ do
    arr <- M.new 3
    M.write arr 0 (Bit True)
    M.write arr 2 (Bit True)
    M.basicInitialize (M.slice 1 1 arr)
    (,) <$> M.read arr 0 <*> M.read arr 2

case_write_set_read1 :: IO ()
case_write_set_read1 = assertEqual "should be equal" (Bit True) $ runST $ do
    arr <- M.new 2
    M.write arr 0 (Bit True)
    M.basicSet (M.slice 1 1 arr) (Bit False)
    M.read arr 0

case_write_set_read2 :: IO ()
case_write_set_read2 = assertEqual "should be equal" (Bit True) $ runST $ do
    arr <- M.new 2
    M.write arr 1 (Bit True)
    M.basicSet (M.slice 0 1 arr) (Bit False)
    M.read arr 1

case_write_set_read3 :: IO ()
case_write_set_read3 = assertEqual "should be equal" (Bit True, Bit True) $ runST $ do
    arr <- M.new 2
    M.write arr 0 (Bit True)
    M.write arr 1 (Bit True)
    M.basicSet (M.slice 1 0 arr) (Bit False)
    (,) <$> M.read arr 0 <*> M.read arr 1

case_write_set_read4 :: IO ()
case_write_set_read4 = assertEqual "should be equal" (Bit True, Bit True) $ runST $ do
    arr <- M.new 3
    M.write arr 0 (Bit True)
    M.write arr 2 (Bit True)
    M.basicSet (M.slice 1 1 arr) (Bit False)
    (,) <$> M.read arr 0 <*> M.read arr 2

case_set_read1 :: IO ()
case_set_read1 = assertEqual "should be equal" (Bit True) $ runST $ do
    arr <- M.new 1
    M.basicSet arr (Bit True)
    M.read arr 0

case_set_read2 :: IO ()
case_set_read2 = assertEqual "should be equal" (Bit True) $ runST $ do
    arr <- M.new 2
    M.basicSet (M.slice 1 1 arr) (Bit True)
    M.read arr 1

case_set_read3 :: IO ()
case_set_read3 = assertEqual "should be equal" (Bit True) $ runST $ do
    arr <- M.new 192
    M.basicSet (M.slice 71 121 arr) (Bit True)
    M.read arr 145

case_write_copy_read1 :: IO ()
case_write_copy_read1 = assertEqual "should be equal" (Bit True) $ runST $ do
    src <- M.slice 37 28 <$> M.new 65
    M.write src 27 (Bit True)
    dst <- M.slice 37 28 <$> M.new 65
    M.copy dst src
    M.read dst 27

case_write_copy_read2 :: IO ()
case_write_copy_read2 = assertEqual "should be equal" (Bit True) $ runST $ do
    src <- M.slice 32 33 <$> M.new 65
    M.write src 0 (Bit True)
    dst <- M.slice 32 33 <$> M.new 65
    M.copy dst src
    M.read dst 0

case_write_copy_read3 :: IO ()
case_write_copy_read3 = assertEqual "should be equal" (Bit True) $ runST $ do
    src <- M.slice 1 1 <$> M.new 2
    M.write src 0 (Bit True)
    dst <- M.slice 1 1 <$> M.new 2
    M.copy dst src
    M.read dst 0

case_write_copy_read4 :: IO ()
case_write_copy_read4 = assertEqual "should be equal" (Bit True) $ runST $ do
    src <- M.slice 12 52 <$> M.new 64
    M.write src 22 (Bit True)
    dst <- M.slice 12 52 <$> M.new 64
    M.copy dst src
    M.read dst 22

case_write_copy_read5 :: IO ()
case_write_copy_read5 = assertEqual "should be equal" (Bit True) $ runST $ do
    src <- M.slice 48 80 <$> M.new 128
    M.write src 46 (Bit True)
    dst <- M.slice 48 80 <$> M.new 128
    M.copy dst src
    M.read dst 46

prop_slice_def :: Int -> Int -> N.New B.Vector Bit -> Bool
prop_slice_def s n xs = runST $ do
    let xs' = V.new xs
        (s', n') = trimSlice s n (V.length xs')
    xs1 <- N.run xs
    xs2 <- V.unsafeFreeze (M.slice s' n' xs1)

    return (B.toList xs2 == sliceList s' n' (B.toList xs'))

prop_grow_def :: B.Vector Bit -> NonNegative Int -> Bool
prop_grow_def xs (NonNegative m) = runST $ do
    let n = B.length xs
    v0 <- B.thaw xs
    v1 <- M.grow v0 m
    fv0 <- B.freeze v0
    fv1 <- B.freeze v1
    return (fv0 == B.take n fv1)

prop_readWord_def :: Int -> Property
prop_readWord_def n = withNonEmptyMVec
    (\xs ->   readWordL (B.toList xs) (n `mod` V.length xs))
    (\xs -> U.readWord            xs  (n `mod` M.length xs))

prop_writeWord_def :: Int -> Word -> Property
prop_writeWord_def n w = withNonEmptyMVec
    (\xs -> B.fromList
               $ writeWordL (B.toList xs) (n `mod` V.length xs) w)
    (\xs -> do U.writeWord            xs  (n `mod` M.length xs) w
               V.unsafeFreeze xs)

prop_wordLength_def :: N.New B.Vector Bit -> Bool
prop_wordLength_def xs
    =  runST (fmap U.wordLength (N.run xs))
    == runST (fmap M.length (N.run xs >>= U.cloneToWords))

prop_cloneFromWords_def :: Int -> Int -> N.New B.Vector Word -> Bool
prop_cloneFromWords_def maxN n' ws
    =  runST (N.run ws >>= U.cloneFromWords n >>= V.unsafeFreeze)
    == B.fromWords n (V.new ws)
    where n = n' `mod` maxN

prop_cloneToWords_def :: N.New B.Vector Bit -> Bool
prop_cloneToWords_def xs
    =  runST (N.run xs >>= U.cloneToWords >>= V.unsafeFreeze)
    == B.toWords (V.new xs)

prop_mapMInPlaceWithIndex_leftToRight :: N.New B.Vector Bit -> Bool
prop_mapMInPlaceWithIndex_leftToRight xs
    = runST $ do
        x <- newSTRef (-1)
        xs1 <- N.run xs
        let f i _ = do
                j <- readSTRef x
                writeSTRef x i
                return (if i > j then maxBound else 0)
        U.mapMInPlaceWithIndex f xs1
        xs2 <- V.unsafeFreeze xs1
        return (all unBit (B.toList xs2))

prop_mapMInPlaceWithIndex_aligned :: N.New B.Vector Bit -> Bool
prop_mapMInPlaceWithIndex_aligned xs = runST $ do
    ok <- newSTRef True
    xs1 <- N.run xs
    let aligned i   = i `mod` U.wordSize == 0
        f i x = do
            when (not (aligned i)) (writeSTRef ok False)
            return x
    U.mapMInPlaceWithIndex f xs1
    readSTRef ok

prop_countBits_def :: N.New B.Vector Bit -> Bool
prop_countBits_def xs
    =  runST (N.run xs >>= U.countBits)
    == B.countBits (V.new xs)

prop_listBits_def :: N.New B.Vector Bit -> Bool
prop_listBits_def xs
    =  runST (N.run xs >>= U.listBits)
    == B.listBits (V.new xs)

prop_reverseInPlace_def :: N.New B.Vector Bit -> Bool
prop_reverseInPlace_def xs
    =  runST (N.run xs >>= \v -> U.reverseInPlace v >> V.unsafeFreeze v)
    == B.reverse (V.new xs)