packages feed

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

-- This is necessary to work around a weird infinite loop bug in GHC 8.0.x. I
-- have no idea what causes it, but disabling these extensions in this module
-- avoids the problem.
{-# LANGUAGE NoGADTs #-}
{-# LANGUAGE NoMonoLocalBinds #-}

module Tests.Coroutine (tests) where

import Control.Monad (unless)

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

import Control.Monad.Freer (Eff, Members, run)
import Control.Monad.Freer.Coroutine
  ( Status(Continue, Done)
  , Yield
  , runC
  , yield
  )
import Control.Monad.Freer.State (State, modify, runState)

tests :: TestTree
tests = testGroup "Coroutine Eff tests"
    [ testProperty "Counting consecutive pairs of odds"
        $ \list -> runTestCoroutine list == countOddDuoPrefix list
    ]

-- | Counts number of consecutive pairs of odd elements at beginning of a list.
countOddDuoPrefix :: [Int] -> Int
countOddDuoPrefix list = count list 0
  where
    count (i1:i2:is) n = if even i1 && even i2 then n else count is (n + 1)
    count _          n = n

runTestCoroutine :: [Int] -> Int
runTestCoroutine list = snd . run $ runState 0 effTestCoroutine
  where
    testCoroutine :: Members '[Yield () Int, State Int] r => Eff r ()
    testCoroutine = do
      -- Yield for two elements and hope they're both odd.
      b <- (&&)
          <$> yield () (even :: Int -> Bool)
          <*> yield () (even :: Int -> Bool)
      unless b $ modify (+ (1 :: Int)) >> testCoroutine

    effTestCoroutine = runC testCoroutine >>= handleStatus list
      where
        handleStatus _      (Done ())       = pure ()
        handleStatus (i:is) (Continue () k) = k i >>= handleStatus is
        handleStatus []     _               = pure ()