content: {-# LANGUAGE FlexibleContexts, NoMonomorphismRestriction #-}
  {-# LANGUAGE TypeOperators, DataKinds #-}
  {-# LANGUAGE ScopedTypeVariables #-}
  {-# LANGUAGE TemplateHaskell #-}
  {-# OPTIONS_GHC -fno-warn-unused-binds #-}
  
  module Control.Eff.Reader.Lazy.Test (testGroups) where
  
  import Test.HUnit hiding (State)
  import Control.Eff
  import Control.Eff.Reader.Lazy
  import Control.Monad
  import Utils
  
  import Test.Framework.TH
  import Test.Framework.Providers.HUnit
  
  testGroups = [ $(testGroupGenerator) ]
  
  t1 = ask `add` return (1::Int)
  
  case_Lazy1_Reader_t1 :: Assertion
  case_Lazy1_Reader_t1 = let
    t1' = do v <- ask; return (v + 1 :: Int)
    t1r = runReader (10::Int) t1
    in
      -- 'run t1' should result in type-error
      11 @=? (run t1r)
  
  t2 = do
    v1 <- ask
    v2 <- ask
    return $ fromIntegral (v1 + (1::Int)) + (v2 + (2::Float))
  
  
  case_Lazy1_Reader_t2 :: Assertion
  case_Lazy1_Reader_t2 = let
    t2r = runReader (10::Int) t2
    t2rr = runReader (20::Float) . runReader (10::Int) $ t2
    in
      33.0 @=? (run t2rr)
  
  -- 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'
  -}
  case_Lazy1_Reader_t2' :: Assertion
  case_Lazy1_Reader_t2' = 33.0 @=?
    (run $ runReader (10 :: Int) . runReader (20 :: Float) $ t2)
  
  
  case_Lazy1_Reader_t3 :: Assertion
  case_Lazy1_Reader_t3 = let
    t3 = t1 `add` local (+ (10::Int)) t1
    in
      212 @=? (run $ runReader (100::Int) t3)
  
  -- The following example demonstrates true interleaving of Reader Int
  -- and Reader Float layers
  {-
  t4
    :: (Member (Reader Int) r, Member (Reader Float) r) =>
       () -> Eff r Float
  -}
  t4 = liftM2 (+) (local (+ (10::Int)) t2)
                  (local (+ (30::Float)) t2)
  
  case_Lazy1_Reader_t4 :: Assertion
  case_Lazy1_Reader_t4 = 106.0 @=?
    (run $ runReader (10::Int) . runReader (20::Float) $ t4)
  
  -- The opposite order of layers gives the same result
  case_Lazy1_Reader_t4' :: Assertion
  case_Lazy1_Reader_t4' = 106.0 @=?
    (run $ runReader (10::Int) . runReader (20::Float) $ t4)
  
  -- Map an effectful function
  case_Lazy1_Reader_tmap :: Assertion
  case_Lazy1_Reader_tmap = let
    tmap = mapM f [1..5]
    in
      ([11,12,13,14,15] :: [Int]) @=?
      (run $ runReader (10::Int) tmap)
    where
      f x = ask `add` return x
  
  case_Lazy1_Reader_runReader :: Assertion
  case_Lazy1_Reader_runReader = let
    e = run $ runReader (undefined :: ()) voidReader
    in
     assertNoUndefined (e :: ())
    where
      voidReader = do
          _ <- (ask :: Eff '[Reader ()] ())
          return ()
  
  case_Lazy1_Reader_monadBaseControl :: Assertion
  case_Lazy1_Reader_monadBaseControl =
        runLift (runReader i act) @=? (Just i)
      where
          act = doThing ask
          i = 10 :: Int
  