packages feed

mangrove-cli-0.4.0.0: test/Mangrove/StreamSpec.hs

{-# LANGUAGE OverloadedLists   #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications  #-}

module Mangrove.StreamSpec (spec) where

import           Data.Maybe
import           Data.Text                 (Text)
import           Test.Hspec
import           Test.Hspec.QuickCheck
import           Test.QuickCheck           hiding (Result (..))
import           Test.QuickCheck.Instances ()

import           Mangrove
import           Mangrove.Scheme.Unix
import           Mangrove.Stream
import           Mangrove.Test.Stream

--------------------------------------------------------------------------------
-- Functor Laws

prop_functorIdLaw
  :: SP_Unix Int
  -> StreamState (Token UnixScheme)
  -> Bool
prop_functorIdLaw (SP_Unix m) state =
  runSPU (fmap id m) state == runSPU m state

prop_functorComLaw
  :: Fun Int Int
  -> Fun Int Int
  -> SP_Unix Int
  -> StreamState (Token UnixScheme)
  -> Bool
prop_functorComLaw (Fn f) (Fn g) (SP_Unix m) state =
  runSPU (fmap (f . g) m) state == runSPU ((fmap f . fmap g) m) state

--------------------------------------------------------------------------------
-- Applicative Laws

prop_applicativeIdLaw
  :: SP_Unix Int
  -> StreamState (Token UnixScheme)
  -> Bool
prop_applicativeIdLaw (SP_Unix m) state =
  runSPU (pure id <*> m) state == runSPU m state

prop_applicativeHomLaw
  :: Fun Int Int
  -> Int
  -> StreamState (Token UnixScheme)
  -> Bool
prop_applicativeHomLaw (Fn f) x state =
  runSPU (pure f <*> pure x) state == runSPU (pure (f x)) state

prop_applicativeIntLaw
  :: SP_Unix (Int -> Int)
  -> Int
  -> StreamState (Token UnixScheme)
  -> Bool
prop_applicativeIntLaw (SP_Unix u) y state =
  runSPU (u <*> pure y) state == runSPU (pure ($ y) <*> u) state

prop_applicativeComLaw
  :: SP_Unix (Int -> Int)
  -> SP_Unix (Int -> Int)
  -> SP_Unix Int
  -> StreamState (Token UnixScheme)
  -> Bool
prop_applicativeComLaw (SP_Unix u) (SP_Unix v) (SP_Unix w) state =
  runSPU (pure (.) <*> u <*> v <*> w) state
  == runSPU (u <*> (v <*> w)) state

--------------------------------------------------------------------------------
-- Monad Laws

prop_monadLeftId
  :: Int
  -> Fun Int (SP_Unix Int)
  -> StreamState (Token UnixScheme)
  -> Bool
prop_monadLeftId a fn state =
  runSPU (f a) state == runSPU (return a >>= f) state
  where
    f = getSPU . applyFun fn

prop_monadRightId
  :: SP_Unix Int
  -> StreamState (Token UnixScheme)
  -> Bool
prop_monadRightId (SP_Unix m) state =
  runSPU m state == runSPU (m >>= return) state

prop_monadAssoc
  :: SP_Unix Int
  -> Fun Int (SP_Unix Int)
  -> Fun Int (SP_Unix Int)
  -> StreamState (Token UnixScheme)
  -> Bool
prop_monadAssoc (SP_Unix m) fn1 fn2 state =
  runSPU ((m >>= f) >>= g) state == runSPU (m >>= (\x -> f x >>= g)) state
  where
    f = getSPU . applyFun fn1
    g = getSPU . applyFun fn2

--------------------------------------------------------------------------------

prop_peek_preservesState
  :: StreamState (Token UnixScheme)
  -> Bool
prop_peek_preservesState state =
  case runSPU peek state of
    (_, state') -> state == state'

prop_pop_preservesContext
  :: StreamState (Token UnixScheme)
  -> Bool
prop_pop_preservesContext state =
  case runSPU pop state of
    (_, state') -> streamContext state == streamContext state'

prop_pop_preservesEscaped
  :: StreamState (Token UnixScheme)
  -> Bool
prop_pop_preservesEscaped state =
  case runSPU pop state of
    (_, state') -> streamEscaped state == streamEscaped state'

prop_yieldsValueOrEmpty
  :: SP_Unix_T Text
  -> StreamState (Token UnixScheme)
  -> Bool
prop_yieldsValueOrEmpty action state =
  case runSPU action state of
    (SPSuccess a, _) -> listToMaybe (streamContent state) == Just a
    (SPEmpty, _)     -> null $ streamContent state
    _                -> False

prop_consumesValue
  :: SP_Unix_T a
  -> StreamState (Token UnixScheme)
  -> Bool
prop_consumesValue action state =
  case runSPU action state of
    (_, state') -> streamContent state' == drop 1 (streamContent state)

spec :: Spec
spec = do
  describe "Functor instance" $ do
    prop "satisfies identity law"
      prop_functorIdLaw
    prop "satisfies composition law"
      prop_functorComLaw

  describe "Applicative instance" $ do
    prop "satisfies identity law"
      prop_applicativeIdLaw
    prop "satisfies homomorphism law"
      prop_applicativeHomLaw
    prop "satisfies interchange law"
      prop_applicativeIntLaw
    prop "satisfies composition law"
      prop_applicativeComLaw

  describe "Monad instance" $ do
    prop "satisfies left identity law"
      prop_monadLeftId
    prop "satisfies right identity law"
      prop_monadRightId
    prop "satisfies associativity law"
      prop_monadAssoc

  describe "peek" $ do
    prop "preserves the stream state"
      prop_peek_preservesState
    prop "yields first value or empty" $
      prop_yieldsValueOrEmpty peek

  describe "pop" $ do
    prop "consumes values" $
      prop_consumesValue pop
    prop "yields first value or empty" $
      prop_yieldsValueOrEmpty pop
    prop "preserves escaped setting" $
      prop_pop_preservesEscaped
    prop "preserves the stream state"
      prop_pop_preservesContext