packages feed

freer-simple-1.0.0.0: tests/Tests/State.hs

module Tests.State (tests) where

import Test.Tasty (TestTree, testGroup)
import Test.Tasty.QuickCheck (testProperty)

import Control.Monad.Freer (run)
import Control.Monad.Freer.State (evalState, execState, get, put, runState)

tests :: TestTree
tests = testGroup "State tests"
  [ testProperty "get after put n yields (n, n)"
      $ \n -> testPutGet n 0 == (n, n)
  , testProperty "Final put determines stored state"
      $ \p1 p2 start -> testPutGetPutGetPlus p1 p2 start == (p1 + p2, p2)
  , testProperty "If only getting, start state determines outcome"
      $ \start -> testGetStart start == (start, start)
  , testProperty "testEvalState: evalState discards final state"
      $ \n -> testEvalState n == n
  , testProperty "testExecState: execState returns final state"
      $ \n -> testExecState n == n
  ]

testPutGet :: Int -> Int -> (Int, Int)
testPutGet n start = run $ runState start go
  where
    go = put n >> get

testPutGetPutGetPlus :: Int -> Int -> Int -> (Int, Int)
testPutGetPutGetPlus p1 p2 start = run $ runState start go
  where
    go = do
      put p1
      x <- get
      put p2
      y <- get
      pure (x + y)

testGetStart :: Int -> (Int, Int)
testGetStart = run . flip runState get

testEvalState :: Int -> Int
testEvalState = run . flip evalState go
  where
    go = do
      x <- get
      -- Destroy the previous state.
      put (0 :: Int)
      pure x

testExecState :: Int -> Int
testExecState n = run $ execState 0 (put n)