content: {-# LANGUAGE FlexibleInstances #-}
  {-# LANGUAGE TypeFamilies #-}
  module Test.Hspec.Wai.QuickCheck (
    property
  , (==>)
  
  -- * Re-exports
  , Arbitrary (..)
  , module Test.QuickCheck.Gen
  
  -- * Internals
  , Testable (..)
  , WaiProperty (..)
  ) where
  
  import           Test.QuickCheck hiding (Testable, property, (==>))
  import qualified Test.QuickCheck as QuickCheck
  import           Test.QuickCheck.Gen
  import           Network.Wai (Application)
  
  import           Test.Hspec.Wai.Internal
  
  property :: Testable a => a -> (State a, Application) -> Property
  property = unWaiProperty . toProperty
  
  data WaiProperty st = WaiProperty {unWaiProperty :: (st, Application) -> Property}
  
  class Testable a where
    type State a
    toProperty :: a -> WaiProperty (State a)
  
  instance Testable (WaiProperty st) where
    type State (WaiProperty st) = st
    toProperty = id
  
  instance Testable (WaiExpectation st) where
    type State (WaiExpectation st) = st
    toProperty action = WaiProperty (QuickCheck.property . runWithState action)
  
  instance (Arbitrary a, Show a, Testable prop) => Testable (a -> prop) where
    type State (a -> prop) = State prop
    toProperty prop = WaiProperty $ QuickCheck.property . (flip $ unWaiProperty . toProperty . prop)
  
  infixr 0 ==>
  (==>) :: Testable prop => Bool -> prop -> WaiProperty (State prop)
  (==>) = lift (QuickCheck.==>)
  
  lift :: Testable prop => (a -> Property -> Property) -> a -> prop -> WaiProperty (State prop)
  lift f a prop = WaiProperty $ \app -> f a (unWaiProperty (toProperty prop) app)
  