massiv-test-0.1.3: tests/Test/Massiv/Array/MutableSpec.hs
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MonoLocalBinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
module Test.Massiv.Array.MutableSpec (spec) where
import Data.Massiv.Array as A
import Test.Massiv.Core
import Test.Massiv.Core.Mutable
import Test.Massiv.Array.Delayed
import Test.Massiv.Array.Mutable
import GHC.Exts
type MutableArraySpec r ix e
= ( Show e
, Eq e
, Arbitrary e
, Arbitrary ix
, CoArbitrary e
, Function e
, Eq (Array r ix e)
, Show (Array r ix e)
, Eq (Array (R r) Ix1 e)
, Show (Array (R r) Ix1 e)
, Load (R r) ix e
, Extract r ix e
, Resize r ix
, Arbitrary (Array r ix e)
, Mutable r ix e
, Stream r ix e
, Construct r ix e)
type MutableSpec r e
= ( Typeable e
, IsList (Array r Ix1 e)
, Item (Array r Ix1 e) ~ e
, MutableArraySpec r Ix1 e
, MutableArraySpec r Ix2 e
, MutableArraySpec r Ix3 e
, MutableArraySpec r Ix4 e
, MutableArraySpec r Ix5 e)
localMutableSpec :: forall r ix e. (MutableArraySpec r ix e) => Spec
localMutableSpec = do
describe "toStream/toList" $
it "toStream" $ property (prop_toStream @r @ix @e)
describe "Mutable operations" $ do
it "write" $ property (prop_Write @r @ix @e)
it "modify" $ property (prop_Modify @r @ix @e)
it "swap" $ property (prop_Swap @r @ix @e)
specMutableR :: forall r e. MutableSpec r e => Spec
specMutableR = do
unsafeMutableSpec @r @Ix1 @e
unsafeMutableSpec @r @Ix2 @e
unsafeMutableSpec @r @Ix3 @e
unsafeMutableSpec @r @Ix4 @e
unsafeMutableSpec @r @Ix5 @e
mutableSpec @r @Ix1 @e
mutableSpec @r @Ix2 @e
mutableSpec @r @Ix3 @e
mutableSpec @r @Ix4 @e
localMutableSpec @r @Ix1 @e
localMutableSpec @r @Ix2 @e
localMutableSpec @r @Ix3 @e
localMutableSpec @r @Ix4 @e
localMutableSpec @r @Ix5 @e
describe "toStream/toList" $
it "toStreamIsList" $ property (prop_toStreamIsList @r @e)
--mutableSpec @r @Ix5 @e -- slows down the test suite
specUnboxedMutableR :: forall r e. MutableSpec r e => Spec
specUnboxedMutableR = do
specMutableR @r @e
unsafeMutableUnboxedSpec @r @Ix1 @e
unsafeMutableUnboxedSpec @r @Ix2 @e
unsafeMutableUnboxedSpec @r @Ix3 @e
unsafeMutableUnboxedSpec @r @Ix4 @e
unsafeMutableUnboxedSpec @r @Ix5 @e
prop_Write :: (Mutable r ix e, Eq e, Show e) => Array r ix e -> ix -> e -> Property
prop_Write arr ix e =
monadicIO $
run $ do
marr <- thaw arr
A.read marr ix >>= \case
Nothing ->
let withExcept = assertExceptionIO (== IndexOutOfBoundsException (size arr) ix)
in pure
(withExcept (writeM marr ix e) .&&.
(write marr ix e `shouldReturn` False) .&&.
(write_ marr ix e `shouldReturn` ()))
Just olde ->
pure $
property $ do
indexM arr ix `shouldReturn` olde
A.write marr ix e `shouldReturn` True
A.read marr ix `shouldReturn` Just e
marr' <- thaw arr
writeM marr' ix e `shouldReturn` ()
arr' <- freeze (getComp arr) marr'
indexM arr' ix `shouldReturn` e
arr'' <- withMArray_ arr (\_ ma -> write_ ma ix e)
index' arr'' ix `shouldBe` e
prop_Modify :: (Mutable r ix e, Eq e, Show e) => Array r ix e -> Fun e e -> ix -> Property
prop_Modify arr f ix =
monadicIO $
run $ do
marr <- thaw arr
modify marr (pure . apply f) ix >>= \case
Nothing ->
let withExcept = assertExceptionIO (== IndexOutOfBoundsException (size arr) ix)
in pure
(withExcept (void $ indexM arr ix) .&&.
withExcept (void $ readM marr ix) .&&.
withExcept (void $ modifyM marr (pure . apply f) ix) .&&.
withExcept (modifyM_ marr (pure . apply f) ix) .&&.
(modify_ marr (pure . apply f) ix `shouldReturn` ()))
Just e ->
pure $
property $ do
let fM = pure . apply f
fe = apply f e
indexM arr ix `shouldReturn` e
A.read marr ix `shouldReturn` Just fe
marr' <- thawS arr
readM marr' ix `shouldReturn` e
modifyM marr' fM ix `shouldReturn` e
arr' <- freezeS marr'
indexM arr' ix `shouldReturn` fe
arr'' <- withMArrayS_ arr (\ma -> modify_ ma fM ix)
index' arr'' ix `shouldBe` fe
prop_Swap :: (Mutable r ix e, Eq e, Show e) => Array r ix e -> ix -> ix -> Property
prop_Swap arr ix1 ix2 =
monadicIO $
run $ do
marr <- thaw arr
swap marr ix1 ix2 >>= \case
Nothing ->
let withExcept =
assertExceptionIO
(\case
IndexOutOfBoundsException _ _ -> True
_ -> False)
in pure
(withExcept (void $ indexM arr ix1 >> indexM arr ix2) .&&.
withExcept (void $ readM marr ix1 >> readM marr ix2) .&&.
withExcept (void $ swapM marr ix1 ix2) .&&.
withExcept (void $ swapM marr ix2 ix1) .&&.
withExcept (swapM_ marr ix1 ix2) .&&.
withExcept (swapM_ marr ix2 ix1) .&&.
(swap_ marr ix1 ix2 `shouldReturn` ()) .&&.
(swap_ marr ix2 ix1 `shouldReturn` ()))
Just (e1, e2) ->
pure $
property $ do
indexM arr ix1 `shouldReturn` e1
indexM arr ix2 `shouldReturn` e2
readM marr ix1 `shouldReturn` e2
readM marr ix2 `shouldReturn` e1
marr' <- thawS arr
swapM marr' ix1 ix2 `shouldReturn` (e1, e2)
arr' <- freezeS marr'
indexM arr' ix1 `shouldReturn` e2
indexM arr' ix2 `shouldReturn` e1
let arr'' = withMArrayST_ arr (\ma -> swap_ ma ix1 ix2)
index' arr'' ix1 `shouldBe` e2
index' arr'' ix2 `shouldBe` e1
spec :: Spec
spec = do
specMutableR @B @Int
specMutableR @N @Int
specUnboxedMutableR @S @Int
specUnboxedMutableR @P @Int
specUnboxedMutableR @U @Int
atomicIntSpec @Ix1
atomicIntSpec @Ix2
atomicIntSpec @Ix3
atomicIntSpec @Ix4
atomicIntSpec @Ix5