content: module Tests.Reader (tests) where
  
  import Test.Tasty (TestTree, testGroup)
  import Test.Tasty.QuickCheck (testProperty)
  
  import Control.Monad.Freer (run)
  import Control.Monad.Freer.Reader (ask, local, runReader)
  
  tests :: TestTree
  tests = testGroup "Reader tests"
    [ testProperty "Reader passes along environment: n + x"
        $ \n x -> testReader n x == n + x
    , testProperty "Multiple readers work"
        $ \i n -> testMultiReader i n == (i + 2) + fromIntegral (n + 1)
    , testProperty "Local injects into env"
        $ \env inc -> testLocal env inc == 2 * (env + 1) + inc
    ]
  
  --------------------------------------------------------------------------------
                              -- Examples --
  --------------------------------------------------------------------------------
  testReader :: Int -> Int -> Int
  testReader n x = run . runReader n $ (+) <$> ask <*> pure x
  
  {-
  t1rr' = run t1
      No instance for (Member (Reader Int) Void)
        arising from a use of `t1'
  -}
  
  testMultiReader :: Integer -> Int -> Integer
  testMultiReader i j = run . runReader i $ runReader j t2
    where
      t2 = do
        v1 <- ask
        v2 <- ask
        pure $ fromIntegral (v1 + (1 :: Int)) + (v2 + (2 :: Integer))
  
  -- The opposite order of layers
  {- If we mess up, we get an error
  t2rrr1' = run $ runReader (runReader t2 (20 :: Float)) (10 :: Float)
      No instance for (Member (Reader Int) [])
        arising from a use of `t2'
  -}
  
  testLocal :: Int -> Int -> Int
  testLocal env inc = run $ runReader env t3
    where
      t3 = (+) <$> t1 <*> local (+ inc) t1
      t1 = (+) <$> ask <*> pure (1 :: Int)
  