packages feed

ether-0.4.0.0: test/Regression/T6.hs

module Regression.T6 (test6) where

import Control.Monad
import Control.Ether.Abbr

import qualified Control.Monad.Ether.Implicit as I
import qualified Control.Ether.Implicit.Abbr as I

import Test.Tasty
import Test.Tasty.QuickCheck

data DivideByZero = DivideByZero
    deriving (Show)

data NegativeLog a = NegativeLog a
    deriving (Show)

testEther
  :: (Floating a, Ord a)
  => Ether '[I.E DivideByZero, I.E (NegativeLog a)] m
  => a -> a -> m a
testEther a b = do
  when (b == 0) (I.throw DivideByZero)
  let d = a / b
  when (d < 0) (I.throw (NegativeLog d))
  return (log d)

-- Copied verbatim from "Data.Function" to support @base < 4.8@.
(&) :: a -> (a -> b) -> b
x & f = f x

handleNegativeLog (NegativeLog (x :: Double)) = "nl: " ++ show x
handleDivideByZero DivideByZero = "dz"

runner1 :: Double -> Double -> String
runner1 a b = do
  (show `fmap` testEther a b)
    & I.handleT handleNegativeLog
    & I.handle  handleDivideByZero

runner2 :: Double -> Double -> String
runner2 a b = do
  (show `fmap` testEther a b)
    & I.handleT handleDivideByZero
    & I.handle  handleNegativeLog

logDiv :: Double -> Double -> String
logDiv a b
  | b == 0    = "dz"
  | d  < 0    = "nl: " ++ show d
  | otherwise = show (log d)
  where
    d = a / b

test6 :: TestTree
test6 = testGroup "T6: Checked exceptions"
  [ testProperty "runner₁ works"
    $ \a b -> property
    $ runner1 a b == logDiv a b
  , testProperty "runner₂ works"
    $ \a b -> property
    $ runner2 a b == logDiv a b
  , testProperty "runner₁ == runner₂"
    $ \a b -> property
    $ runner1 a b == runner2 a b
  ]