parameterized-0.2.0.0: test/Parameterized/Control/Monad/Trans/Reader/ReaderSpec.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeApplications #-}
module Parameterized.Control.Monad.Trans.Reader.ReaderSpec (main, spec) where
import Control.Applicative
import Control.Monad.Trans.Reader
import Parameterized.Control.Monad.Trans.Reader
import Parameterized.Control.Monad
import Data.Diverse
import Data.Semigroup
import Test.Hspec
-- `main` is here so that this module can be run from GHCi on its own. It is
-- not needed for automatic spec dicovery.
main :: IO ()
main = hspec spec
whichIntMaybeReader :: ReaderT (Which '[Int]) Maybe String
whichIntMaybeReader = do
a <- ask
pure . show $ obvious a
whichBoolMaybeReader :: ReaderT (Which '[Bool]) Maybe String
whichBoolMaybeReader = do
a <- ask
pure . show $ obvious a
whichStringMaybeReader :: ReaderT (Which '[String]) Maybe String
whichStringMaybeReader = do
a <- ask
pure . show $ obvious a
whichIntBoolMaybeReader :: ReaderT (Which '[Int, Bool]) Maybe String
whichIntBoolMaybeReader = do
ay <- ask
pure $ switch ay (CaseFunc @Show show)
whichBoolStringMaybeReader :: ReaderT (Which '[Bool, String]) Maybe String
whichBoolStringMaybeReader = do
ay <- ask
pure $ switch ay (CaseFunc @Show show)
whichIntStringMaybeReader :: ReaderT (Which '[Int, String]) Maybe String
whichIntStringMaybeReader = do
ay <- ask
pure $ switch ay (CaseFunc @Show show)
whichIntBoolStringMaybeReader :: ReaderT (Which '[Int, Bool, String]) Maybe String
whichIntBoolStringMaybeReader = do
ay <- ask
pure $ switch ay (CaseFunc @Show show)
--------------------------------
whichIntReader :: Reader (Which '[Int]) String
whichIntReader = do
a <- ask
pure . show $ obvious a
whichBoolReader :: Reader (Which '[Bool]) String
whichBoolReader = do
a <- ask
pure . show $ obvious a
whichStringReader :: Reader (Which '[String]) String
whichStringReader = do
a <- ask
pure . show $ obvious a
whichIntBoolReader :: Reader (Which '[Int, Bool]) String
whichIntBoolReader = do
ay <- ask
pure $ switch ay (CaseFunc @Show show)
whichIntStringReader :: Reader (Which '[Int, String]) String
whichIntStringReader = do
ay <- ask
pure $ switch ay (CaseFunc @Show show)
whichIntBoolStringReader :: Reader (Which '[Int, Bool, String]) String
whichIntBoolStringReader = do
ay <- ask
pure $ switch ay (CaseFunc @Show show)
--------------------------------
manyIntMaybeReader :: ReaderT (Many '[Int]) Maybe String
manyIntMaybeReader = do
a <- ask
let r = fetch @Int a
case r of
0 -> empty
r' -> pure $ show r'
manyBoolMaybeReader :: ReaderT (Many '[Bool]) Maybe String
manyBoolMaybeReader = do
a <- ask
let r = fetch @Bool a
case r of
False -> empty
r' -> pure $ show r'
--------------------------------
spec :: Spec
spec = do
describe "Reader (Which a)" $ do
it "is can maybe read only the types it knows about" $ do
runReaderT whichIntMaybeReader (pick (5 :: Int)) `shouldBe` Just "5"
runReaderT whichIntBoolMaybeReader (pick (5 :: Int)) `shouldBe` Just "5"
runReaderT whichIntBoolStringMaybeReader (pick (5 :: Int)) `shouldBe` Just "5"
runReaderT whichBoolMaybeReader (pick False) `shouldBe` Just "False"
runReaderT whichIntBoolMaybeReader (pick False) `shouldBe` Just "False"
runReaderT whichIntBoolStringMaybeReader (pick False) `shouldBe` Just "False"
runReaderT whichStringMaybeReader (pick "foo") `shouldBe` Just "\"foo\""
runReaderT whichIntStringMaybeReader (pick "foo") `shouldBe` Just "\"foo\""
runReaderT whichIntBoolStringMaybeReader (pick "foo") `shouldBe` Just "\"foo\""
it "is can read only the types it knows about" $ do
runReader whichIntReader (pick (5 :: Int)) `shouldBe` "5"
runReader whichIntBoolReader (pick (5 :: Int)) `shouldBe` "5"
runReader whichIntBoolStringReader (pick (5 :: Int)) `shouldBe` "5"
runReader whichBoolReader (pick False) `shouldBe` "False"
runReader whichIntBoolReader (pick False) `shouldBe` "False"
runReader whichIntBoolStringReader (pick False) `shouldBe` "False"
runReader whichStringReader (pick "foo") `shouldBe` "\"foo\""
runReader whichIntStringReader (pick "foo") `shouldBe` "\"foo\""
runReader whichIntBoolStringReader (pick "foo") `shouldBe` "\"foo\""
describe "OverlappingWhichReader" $ do
it "pappend with empty doesn't change the type of the parameter" $ do
let r1 = OverlappingWhichReader whichIntMaybeReader `pappend` pempty
r2 = pempty `pappend` OverlappingWhichReader whichIntMaybeReader
-- the "parameter" doesn't change when `pappend` with empty
r1' = runOverlappingWhichReader r1 :: ReaderT (Which '[Int]) Maybe String
r2' = runOverlappingWhichReader r2 :: ReaderT (Which '[Int]) Maybe String
-- functionality unchanged
runReaderT r1' (pick (5 :: Int)) `shouldBe` Just "5"
runReaderT r2' (pick (5 :: Int)) `shouldBe` Just "5"
it "it can be pappended to combine distinct readers" $ do
let r = OverlappingWhichReader whichIntMaybeReader `pappend`
OverlappingWhichReader whichBoolMaybeReader
-- the "parameter" is combined
r' = runOverlappingWhichReader r :: ReaderT (Which '[Int, Bool]) Maybe String
-- functionality of both readers
runReaderT r' (pick (5 :: Int)) `shouldBe` Just "5"
runReaderT r' (pick False) `shouldBe` Just "False"
let r2 = r `pappend` OverlappingWhichReader whichStringMaybeReader
-- the "parameter" is combined
r2' = runOverlappingWhichReader r2 :: ReaderT (Which '[Int, Bool, String]) Maybe String
-- functionality of both readers
runReaderT r2' (pick (5 :: Int)) `shouldBe` Just "5"
runReaderT r2' (pick False) `shouldBe` Just "False"
runReaderT r2' (pick "foo") `shouldBe` Just "\"foo\""
it "it can be pappended to combine overlapping readers" $ do
let r = OverlappingWhichReader whichIntBoolMaybeReader `pappend`
OverlappingWhichReader whichBoolStringMaybeReader
-- the "parameter" is combined
r' = runOverlappingWhichReader r :: ReaderT (Which '[Int, Bool, String]) Maybe String
-- functionality of both readers
runReaderT r' (pick (5 :: Int)) `shouldBe` Just "5"
runReaderT r' (pick False) `shouldBe` Just "False"
runReaderT r' (pick "foo") `shouldBe` Just "\"foo\""
describe "DistinctWhichReader" $ do
it "pappend with empty doesn't change the type of the parameter" $ do
let r1 = DistinctWhichReader whichIntMaybeReader `pappend` pempty
r2 = pempty `pappend` DistinctWhichReader whichIntMaybeReader
-- the "parameter" doesn't change when `pappend` with empty
r1' = runDistinctWhichReader r1 :: ReaderT (Which '[Int]) Maybe String
r2' = runDistinctWhichReader r2 :: ReaderT (Which '[Int]) Maybe String
-- functionality unchanged
runReaderT r1' (pick (5 :: Int)) `shouldBe` Just "5"
runReaderT r2' (pick (5 :: Int)) `shouldBe` Just "5"
it "it can be pappended to combine distinct readers" $ do
let r = DistinctWhichReader whichIntReader `pappend` DistinctWhichReader whichBoolReader
-- the "parameter" is combined
r' = runDistinctWhichReader r :: Reader (Which '[Int, Bool]) String
-- functionality of both readers
runReader r' (pick (5 :: Int)) `shouldBe` "5"
runReader r' (pick False) `shouldBe` "False"
let r2 = r `pappend` DistinctWhichReader whichStringReader
-- the "parameter" is combined
r2' = runDistinctWhichReader r2 :: Reader (Which '[Int, Bool, String]) String
-- functionality of both readers
runReader r2' (pick (5 :: Int)) `shouldBe` "5"
runReader r2' (pick False) `shouldBe` "False"
runReader r2' (pick "foo") `shouldBe` "\"foo\""
describe "ManyReader" $ do
it "pappend with empty doesn't change the type of the parameter" $ do
let r1 = ManyReader manyIntMaybeReader `pappend` pempty
r2 = pempty `pappend` ManyReader manyIntMaybeReader
-- the "parameter" doesn't change when `pappend` with empty
r1' = runManyReader r1 :: ReaderT (Many '[Int]) Maybe String
r2' = runManyReader r2 :: ReaderT (Many '[Int]) Maybe String
-- functionality unchanged
runReaderT r1' (single (5 :: Int)) `shouldBe` Just "5"
runReaderT r2' (single (5 :: Int)) `shouldBe` Just "5"
it "it can 'pappend' to combine state runners 'Alternative'ly" $ do
let r = ManyReader manyIntMaybeReader `pappend`
ManyReader manyBoolMaybeReader
-- the "parameter" is combined
r' = runManyReader r :: ReaderT (Many '[Int, Bool]) Maybe String
-- functionality of both readers in an Alternative fashion
runReaderT r' ( (5 :: Int) ./ True ./ nil) `shouldBe` Just "5"
runReaderT r' ( (5 :: Int) ./ False ./ nil) `shouldBe` Just "5"
runReaderT r' ( (0 :: Int) ./ True ./ nil) `shouldBe` Just "True"
runReaderT r' ( (0 :: Int) ./ False ./ nil) `shouldBe` Nothing
it "it can 'papply' to combine state runners 'Applicative'ly" $ do
let r = (\a b -> a <> "." <> b) <$> ManyReader manyIntMaybeReader &<*>
ManyReader manyBoolMaybeReader
-- the "parameter" is combined
r' = runManyReader r :: ReaderT (Many '[Int, Bool]) Maybe String
-- functionality of both readers in an Alternative fashion
runReaderT r' ( (5 :: Int) ./ True ./ nil) `shouldBe` Just "5.True"
runReaderT r' ( (5 :: Int) ./ False ./ nil) `shouldBe` Nothing
runReaderT r' ( (0 :: Int) ./ True ./ nil) `shouldBe` Nothing
runReaderT r' ( (0 :: Int) ./ False ./ nil) `shouldBe` Nothing
it "it can 'pbind' to combine reader runners 'Monad'ically" $ do
let r = ManyReader manyIntMaybeReader &>>= \a ->
case a of
"1" -> ManyReader manyBoolMaybeReader
_ -> empty
-- the "parameter" is combined
r' = runManyReader r :: ReaderT (Many '[Int, Bool]) Maybe String
-- functionality of both readers in an Applicative fashion
runReaderT r' ( (1 :: Int) ./ True ./ nil) `shouldBe` Just "True"
runReaderT r' ( (1 :: Int) ./ False ./ nil) `shouldBe` Nothing
runReaderT r' ( (5 :: Int) ./ True ./ nil) `shouldBe` Nothing
runReaderT r' ( (5 :: Int) ./ False ./ nil) `shouldBe` Nothing
runReaderT r' ( (0 :: Int) ./ True ./ nil) `shouldBe` Nothing
runReaderT r' ( (0 :: Int) ./ False ./ nil) `shouldBe` Nothing