packages feed

stateWriter-0.2.0: tests/rwscompare.hs

{-# LANGUAGE GADTs, FlexibleContexts, FlexibleInstances #-}
module Main where

import Control.Monad.Trans.RSS.Strict
import Control.Monad.RWS
import Test.Hspec
import Test.QuickCheck
import Control.Applicative
import Control.Monad.Free

data ActionF next = Tell        [Int]         next
                  | SetState    Int           next
                  | AskAndStore IModification next
                  | Modify      SModification next
                  | GetAndStore IModification next

type Action = Free ActionF

data SModification = SId
                   | Double
                   deriving (Enum, Show, Bounded)

data IModification = IReturn
                   | ReplicateThrice
                   deriving (Enum, Show, Bounded)

instance Arbitrary SModification where
    arbitrary = arbitraryBoundedEnum
instance Arbitrary IModification where
    arbitrary = arbitraryBoundedEnum

instance Arbitrary next => Arbitrary (ActionF next) where
    arbitrary = frequency [ (5,  Tell        <$> arbitrary <*> arbitrary)
                          , (5,  SetState    <$> arbitrary <*> arbitrary)
                          , (20, AskAndStore <$> arbitrary <*> arbitrary)
                          , (20, GetAndStore <$> arbitrary <*> arbitrary)
                          , (20, Modify      <$> arbitrary <*> arbitrary)
                          ]

instance Arbitrary (Action Int) where
    arbitrary = frequency [ (1, Pure <$> arbitrary)
                          , (9, Free <$> arbitrary) 
                          ]

evaluateIM :: IModification -> (Int -> [Int])
evaluateIM IReturn x = [x]
evaluateIM ReplicateThrice x = [x,x,x]

evaluateSM :: SModification -> (Int -> Int)
evaluateSM SId = id
evaluateSM Double = (*) 2

instance Show next => Show (ActionF next) where
    show (Tell x n) = "Tell " ++ show x ++ " / " ++ show n
    show (SetState s n) = "Set " ++ show s ++ " / " ++ show n
    show (AskAndStore i n) = "AskAndStore " ++ show i ++ " / " ++ show n
    show (GetAndStore i n) = "GetAndStore " ++ show i ++ " / " ++ show n
    show (Modify s n) = "Modify " ++ show s ++ " / " ++ show n

evaluateActions :: (MonadRWS Int [Int] Int m) => Action x -> m x
evaluateActions (Free (Tell x next))        = tell x >>  evaluateActions next
evaluateActions (Free (SetState s next))    = put s  >>  evaluateActions next
evaluateActions (Free (AskAndStore f next)) = ask >>= tell . evaluateIM f >> evaluateActions next
evaluateActions (Free (GetAndStore f next)) = get >>= tell . evaluateIM f >> evaluateActions next
evaluateActions (Free (Modify f next)) = modify (evaluateSM f) >> evaluateActions next
evaluateActions (Pure x) = return x

main :: IO ()
main = hspec $ do
    describe "Writer part" $ do
        it "logs stuff in the right order, with tell" $
            property $ \listOfLists -> runRSS (mapM_ tell (listOfLists :: [[Int]])) () () == runRWS (mapM_ tell listOfLists) () ()
        it "logs stuff in the right order, with tellElement" $
            property $ \list -> runRSS (mapM_ tellElement (list :: [Int])) () () == ((), (), list)
        it "interprets actions the same" $
            property $ \actions -> runRSS (evaluateActions (actions :: Action Int)) 42 12 == runRWS (evaluateActions actions) 42 12