packages feed

stc-lang-1.0.0: test/SD/Correctness.hs

module SD.Correctness (testSuite) where

import Control.Monad.State

import Test.Framework
import Test.Framework.Providers.HUnit
import Test.HUnit hiding (State)

-- import Data.Monoid
-- import Utils
import Control.Monad.SD
import Data.StateElement

foo :: Int -> StateT Int IO Int
foo x = do
    s <- get
    put $ s + 2
    return $ x + 2

bar :: Int -> StateT Int IO Int
bar x = do
    s <- get
    put $ s + 3
    return $ x * 3

barFloat :: Int -> StateT Float IO Int
barFloat x = do
    s <- get
    put $ s + 3.34
    return $ x * 3

-- simpleAlgo :: Int -> OhuaM ([LocalStateBox Int], [LocalStateBox Int]) Int
simpleComposition v = do
    c <- return v
    r0 <- liftWithIndex 0 foo c
    r1 <- liftWithIndex 1 bar r0
    return r1

packagedSimpleComposition = do
    f0 <- liftWithState (return 0) foo
    f1 <- liftWithState (return 0) bar
    return $ f1 <=< f0

simpleCompositionHetState v = do
    c <- return v
    r0 <- liftWithIndex 0 foo c
    r1 <- liftWithIndex 1 barFloat r0
    return r1

simpleSMap = smap simpleComposition

smapWithContext v = do
    c <- return v
    r0 <- liftWithIndex 2 foo c
    r1 <- liftWithIndex 3 bar r0
    r2 <- smap simpleComposition [r0, r1]
    return r2

smapResultUsed v = do
    c <- return v
    r0 <- liftWithIndex 2 foo c
    r1 <- liftWithIndex 3 bar r0
    r2 <- smap simpleComposition [r0, r1]
    r3 <- liftWithIndex 4 foo $ r2 !! 0
    r4 <- liftWithIndex 5 bar $ r2 !! 1
    return (r3, r4)

packagedSmapResultUsed = do
    f0 <- liftWithState (return 0) foo
    f1 <- liftWithState (return 0) bar
    f2 <- smapSTC packagedSimpleComposition
    f3 <- liftWithState (return 0) foo
    f4 <- liftWithState (return 0) bar
    return $ \v -> do
        r0 <- f0 v
        r1 <- f1 r0
        r2 <- f2 [r0, r1]
        r3 <- f3 $ r2 !! 0
        r4 <- f4 $ r2 !! 1
        return (r3, r4)

smapOverEmptyList = do
    r1 <- smap simpleComposition []
    smap someComp [length r1]
  where
    someComp i = do
        r0 <- liftWithIndex 2 foo i
        liftWithIndex 3 bar r0

smapOverEmptyList2 = smap (smap simpleComposition) [[], [1 .. 3]]

simpleCompositionPackaged v = do
    c <- return v
    r0 <- liftWithIndex 0 foo c
    r1 <- liftWithIndex 1 bar r0
    return r1

caseComp idxFoo idxBranch1 idxBranch2 v = do
    c <- liftWithIndex idxFoo foo v
    o <- case_ c [(4, branch1 c), (8, branch2 c)]
    return o
  where
    branch1 = liftWithIndex idxBranch1 bar
    branch2 = liftWithIndex idxBranch2 bar

caseComposition = caseComp 0 1 2

smapWithCase = smap caseComposition

nestedCase v = do
    o <- case_ v [(2, caseComp 0 1 2 v), (6, caseComp 3 4 5 v)]
    return o

ret = return (10 :: Int)

returnTest :: Assertion
returnTest = do
    (result, s) <- runOhuaM ret []
    assertEqual "result was wrong." (10 :: Int) result
    assertEqual "state was wrong." [] (map fromS s :: [Int])

bindTest :: Assertion
bindTest = do
    (result, s) <- runOhuaM (simpleComposition 10) $ map toS [0 :: Int, 0]
    assertEqual "result was wrong." 36 result
    assertEqual "state was wrong." [2, 3] (map fromS s :: [Int])

hetStateTest :: Assertion
hetStateTest = do
    (result, s1:(s2:_)) <-
        runOhuaM
            (simpleCompositionHetState 10)
            [toS (0 :: Int), toS (2.5 :: Float)]
    assertEqual "result was wrong." 36 result
    assertEqual "state was wrong." 2 (fromS s1 :: Int)
    assertEqual "state was wrong." 5.84 (fromS s2 :: Float)
  -- assertEqual "state was wrong." 2 (toConcrete s1 :: Int)
  -- assertEqual "state was wrong." 5.84 (toConcrete s2 :: Float)

pipeSMapTest :: Assertion
pipeSMapTest = do
    (result, s) <- runOhuaM (simpleSMap [10, 10]) $ map toS [0 :: Int, 0]
    assertEqual "result was wrong." [36, 36] result
    assertEqual "state was wrong." [4, 6] (map fromS s :: [Int])

smapContextTest :: Assertion
smapContextTest = do
    (result, s) <- runOhuaM (smapWithContext 10) $ map toS [0 :: Int, 0, 0, 0]
    assertEqual "result was wrong." [42, 114] result
    assertEqual "state was wrong." [4, 6, 2, 3] (map fromS s :: [Int])

smapResultUsedTest :: Assertion
smapResultUsedTest = do
    (result, s) <-
        runOhuaM (smapResultUsed 10) $ map toS [0 :: Int, 0, 0, 0, 0, 0]
    assertEqual "result was wrong." (44, 342) result
    assertEqual "state was wrong." [4, 6, 2, 3, 2, 3] (map fromS s :: [Int])

-- | Basically the same as 'smapResultUsed' but order of elements in the state
-- is different, because of the order in which the state monad collects the
-- indices.
packagedSmapResultUsedTest :: Assertion
packagedSmapResultUsedTest = do
    (result, s) <- runSTCLang packagedSmapResultUsed 10
    assertEqual "result was wrong." (44, 342) result
    assertEqual "state was wrong." [2, 3, 4, 6, 2, 3] (map fromS s :: [Int])

packagedBindTest :: Assertion
packagedBindTest = do
    (result, s) <-
        runOhuaM (simpleCompositionPackaged 10) $ map toS [0 :: Int, 0]
    assertEqual "result was wrong." 36 result
    assertEqual "state was wrong." [2, 3] (map fromS s :: [Int])

caseTest :: Assertion
caseTest
  -- "true" branch
 = do
    (result, s) <- runOhuaM (caseComposition 2) $ map toS [0 :: Int, 0, 0]
    assertEqual "result was wrong." 12 result
    assertEqual "state was wrong." [2, 3, 0] (map fromS s :: [Int])
  -- "false" branch
    (result', s') <- runOhuaM (caseComposition 6) $ map toS [0 :: Int, 0, 0]
    assertEqual "result was wrong." 24 result'
    assertEqual "state was wrong." [2, 0, 3] (map fromS s' :: [Int])

caseSmapTest :: Assertion
caseSmapTest
  -- "true" branch
 = do
    (result, s) <- runOhuaM (smapWithCase [2, 6]) $ map toS [0 :: Int, 0, 0]
    assertEqual "result was wrong." [12, 24] result
    assertEqual "state was wrong." [4, 3, 3] (map fromS s :: [Int])
  -- execute only once
    (result, s) <- runOhuaM (smapWithCase [2]) $ map toS [0 :: Int, 0, 0]
    assertEqual "result was wrong." [12] result
  --assertEqual "state was wrong." [4,3,3] (map fromS s :: [Int])

nestedCaseTest :: Assertion
nestedCaseTest
  -- "true" branch
 = do
    (result, s) <- runOhuaM (nestedCase 2) $ map toS [0 :: Int, 0, 0, 0, 0, 0]
    assertEqual "result was wrong." 12 result
    assertEqual "state was wrong." [2, 3, 0, 0, 0, 0] (map fromS s :: [Int])
  -- "false" branch
    (result', s') <- runOhuaM (nestedCase 6) $ map toS [0 :: Int, 0, 0, 0, 0, 0]
    assertEqual "result was wrong." 24 result'
    assertEqual "state was wrong." [0, 0, 0, 2, 0, 3] (map fromS s' :: [Int])

tooMuchStateTest :: Assertion
tooMuchStateTest = do
    (result, s) <- runOhuaM ret $ map toS [0 :: Int]
    assertEqual "result was wrong." (10 :: Int) result
    assertEqual "state was wrong." [0] (map fromS s :: [Int])

notEnoughStateTest :: Assertion
notEnoughStateTest = do
    (result, s) <- runOhuaM (simpleComposition 10) $ map toS [0 :: Int]
    assertEqual "result was wrong." 36 result
    assertEqual "state was wrong." [2, 3] (map fromS s :: [Int])

smapHandlesEmptyList :: Assertion
smapHandlesEmptyList =
    void (runOhuaM smapOverEmptyList (map toS [0 .. 3 :: Int]))

smapHandlesEmptyList2 :: Assertion
smapHandlesEmptyList2 = do
    (res, _) <- runOhuaM smapOverEmptyList2 (map toS [0 .. 1 :: Int])
    assertEqual "lengths differ" [0, 3] (map length res)

testSuite :: Test.Framework.Test
testSuite =
    testGroup
        "Futures"
        [ testCase "checking monadic return" returnTest
        , testCase "checking monadic bind" bindTest
        , testCase "checking simple pipe smap" pipeSMapTest
        , testCase "checking smap with context" smapContextTest
        , testCase "checking smap result used" smapResultUsedTest
        , testCase "smap over empty list" smapHandlesEmptyList
        , testCase "nested smap over empty list" smapHandlesEmptyList2
        , testCase "checking packaged version" packagedBindTest
        , testCase "checking case statement" caseTest
        , testCase "checking smap-case composition" caseSmapTest
        , testCase "simple nested case composition" nestedCaseTest
        , testCase "heterogeneous state" hetStateTest
        , testCase "test packaged state" packagedSmapResultUsedTest
            -- , testCase "Futures: too much state" tooMuchStateTest --> this turns into an Error in monad-par that says: "no result"
            -- , testCase "Futures: not enough state" notEnoughStateTest --> turns into the error: Prelude.!!: index too large
        ]