packages feed

basics-0.2.0.0: test/Main.hs

{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE UnboxedTuples #-}

module Main
  ( main
  ) where


import Basics.BitBool
import Prelude hiding (read)

import Control.Applicative (liftA2)
import Control.Monad (forM)
import Control.Monad.ST (runST)
import Data.Monoid (All(..))
import Data.Primitive.ByteArray (ByteArray(..),MutableByteArray(..))
import Data.Proxy (Proxy(Proxy))
import Data.Word (Word32)
import GHC.Exts (Int(I#),MutableByteArray#)
import GHC.ST (ST(ST))
import GHC.TypeNats (KnownNat)
import Test.QuickCheck.Instances.Text ()
import Test.Tasty (TestTree,defaultMain,testGroup,adjustOption)
import Test.Tasty.HUnit (testCase,(@=?),assertFailure)
import Test.Tasty.QuickCheck ((===),(=/=),(==>))
import Test.Tasty.QuickCheck (Gen,testProperty)
import Unsafe.Coerce (unsafeCoerce)

import qualified Control.Monad.Trans.State.Strict as State
import qualified Data.Foldable as F
import qualified Data.List as L
import qualified Data.List as List
import qualified Data.Primitive.ByteArray as Prim
import qualified GHC.Exts as Exts
import qualified GHC.TypeNats as GHC
import qualified Test.Tasty.QuickCheck as QC



main :: IO ()
main = defaultMain
  $ adjustOption (\_ -> QC.QuickCheckTests 4000)
  $ tests

tests :: TestTree
tests = testGroup "basics"
  [ testGroup "BitBool"
    [ testProperty "lift/unlift are inverse" $ \b ->
        lift (unlift b) == b
    , testCase "initialize with False" $
        let sz = 150
            actual = runST $ do
                marr <- initialized sz False
                forM [0..sz-1] $ \i -> read marr i
            expected = replicate sz False
         in actual @=? expected
    , testCase "initialize with True" $
        let sz = 150
            actual = runST $ do
                marr <- initialized sz True
                forM [0..sz-1] $ \i -> read marr i
            expected = replicate sz True
         in actual @=? expected
    , testProperty "read/write single bits" $ \xs ->
        let actual = runST $ do
              marr <- uninitialized (length xs)
              forM (zip [0..] xs) $ \(i, x) ->
                write marr i x
              forM [0..length xs - 1] $ \i -> read marr i
         in actual == xs
    , testProperty "index/write single bits" $ \xs ->
        let arr = Prim.runByteArray $ do
              marr <- uninitialized (length xs)
              forM (zip [0..] xs) $ \(i, x) ->
                write marr i x
              pure marr
            actual = index arr <$> [0..length xs - 1]
         in actual == xs
    , testProperty "shrink" $ \Shrink{xs,sz} ->
        let actual = runST $ do
              marr <- uninitialized (length xs)
              forM (zip [0..] xs) $ \(i, x) ->
                write marr i x
              marr' <- shrink marr sz
              forM [0..sz - 1] $ \i -> read marr' i
         in actual == take sz xs
    , testProperty "set#" $ \Set{xs,off,len,v} ->
        let actual = runST $ do
              marr <- uninitialized (length xs)
              forM (zip [0..] xs) $ \(i, x) ->
                write marr i x
              set marr off len v
              forM [0..length xs - 1] $ \i -> read marr i
            expected = take off xs ++ replicate len v ++ drop (off + len) xs
         in actual === expected
    , testProperty "copy" $ \Copy{xs,doff,ys,soff,len} ->
        let src = Prim.runByteArray $ do
              marr <- uninitialized (length ys)
              forM (zip [0..] ys) $ \(i, y) ->
                write marr i y
              pure marr
            actual = runST $ do
              dst <- uninitialized (length xs)
              forM (zip [0..] xs) $ \(i, x) ->
                write dst i x
              copy dst doff src soff len
              forM [0..length xs - 1] $ \i -> read dst i
            expected = take doff xs ++ take len (drop soff ys) ++ drop (doff + len) xs
         in actual === expected
    , testProperty "copyMutable" $ \Copy{xs,doff,ys,soff,len} ->
        let actual = runST $ do
              src <- uninitialized (length ys)
              forM (zip [0..] ys) $ \(i, y) ->
                write src i y
              dst <- uninitialized (length xs)
              forM (zip [0..] xs) $ \(i, x) ->
                write dst i x
              copyMutable dst doff src soff len
              forM [0..length xs - 1] $ \i -> read dst i
            expected = take doff xs ++ take len (drop soff ys) ++ drop (doff + len) xs
         in actual === expected
    ]
  ]

--- Lift the functions under test ---

index :: ByteArray -> Int -> Bool
index (ByteArray arr) (I# i) = lift (index# arr i)

read :: MutableByteArray s -> Int -> ST s Bool
read (MutableByteArray marr) (I# ix) = ST (\st ->
  let (# st', v #) = read# marr ix st
   in (# st', lift v #))

write :: MutableByteArray s -> Int -> Bool -> ST s ()
write (MutableByteArray marr) (I# i) v = ST (\st ->
  (# write# marr i (unlift v) st, () #))

uninitialized :: Int -> ST s (MutableByteArray s)
uninitialized (I# n) = ST (\st ->
  let (# st', marr #) = uninitialized# n st
   in (# st', MutableByteArray marr #))

initialized :: Int -> Bool -> ST s (MutableByteArray s)
initialized (I# n) v = ST (\st ->
  let (# st', marr #) = initialized# n (unlift v) st
   in (# st', MutableByteArray marr #))

shrink :: MutableByteArray s -> Int -> ST s (MutableByteArray s)
shrink (MutableByteArray marr) (I# i) = ST (\st ->
  let (# st', marr' #) = shrink# marr i st
   in (# st', MutableByteArray marr' #))

set :: MutableByteArray s -> Int -> Int -> Bool -> ST s ()
set (MutableByteArray marr) (I# off) (I# len) v = ST (\st ->
   (# set# marr off len (unlift v) st, () #))

copy :: MutableByteArray s -> Int -> ByteArray -> Int -> Int -> ST s ()
copy (MutableByteArray dst) (I# doff) (ByteArray src) (I# soff) (I# len) = ST (\st ->
  (# copy# dst doff src soff len st, () #))

copyMutable :: MutableByteArray s -> Int -> MutableByteArray s -> Int -> Int -> ST s ()
copyMutable (MutableByteArray dst) (I# doff) (MutableByteArray src) (I# soff) (I# len) = ST (\st ->
  (# copyMutable# dst doff src soff len st, () #))


data Shrink = Shrink { xs::[Bool], sz::Int} deriving (Show)
instance QC.Arbitrary Shrink where
  arbitrary = do
    x' <- QC.arbitrary
    xs' <- QC.arbitrary
    let xs = x':xs'
    sz <- QC.chooseInt (1, length xs)
    pure Shrink{xs,sz}

data Set = Set { xs::[Bool], off::Int, len::Int, v::Bool } deriving (Show)
instance QC.Arbitrary Set where
  arbitrary = do
    xs <- QC.arbitrary
    off <- QC.chooseInt (0,max 0 (length xs - 1))
    len <- QC.chooseInt (0,length xs - off)
    v <- QC.arbitrary
    pure Set{xs,off,len,v}

data Copy = Copy { xs::[Bool],doff::Int,ys::[Bool],soff::Int,len::Int } deriving (Show)
instance QC.Arbitrary Copy where
  arbitrary = do
    xs <- QC.arbitrary
    doff <- QC.chooseInt (0, max 0 (length xs - 1))
    ys <- QC.arbitrary
    soff <- QC.chooseInt (0, max 0 (length ys - 1))
    len <- QC.chooseInt (0, min (length xs - doff) (length ys - soff))
    pure Copy{xs,doff,ys,soff,len}