tasty-bdd-0.1.0.0: src/Test/BDD/Language.hs
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE TemplateHaskell #-}
-- |
--
-- Module : Test.BDD.Language
-- Copyright : (c) Paolo Veronelli, Pavlo Kerestey 2017
-- License : BSD3
-- Maintainer: paolo.veronelli@gmail.com
-- Stability : experimental
-- Portability: non-portable
--
--
-- The constrained language to define behaviors in BDD terminology
--
-- @
-- exampleL :: TestTree
-- exampleL = testBehavior "Test sequence"
-- $ Given (print "Some effect")
-- $ Given (print "Another effect")
-- $ GivenAndAfter (print "Aquiring resource" >> return "Resource 1")
-- (print . ("Release "++))
-- $ GivenAndAfter (print "Aquiring resource" >> return "Resource 2")
-- (print . ("Release "++))
-- $ When (print "Action returning" >> return ([1..10]++[100..106]) :: IO [Int])
-- $ Then (@?= ([1..10]++[700..706]))
-- $ End
-- @
module Test.BDD.Language
( Language (..)
, BDDPreparing
, BDDTesting
, BDDTest (..)
, TestContext (..)
, context
, when
, tests
, interpret
, Phase (..)
)
where
import Lens.Micro
import Lens.Micro.TH
-- | Separating the 2 phases by type
data Phase = Preparing | Testing
-- | Recording given actions and type related teardowns
data TestContext m = forall r. TestContext (m r) (r -> m ())
-- | Bare hoare language
data Language m t q a where
-- | action to prepare the test
Given
:: m ()
-> Language m t q 'Preparing
-> Language m t q 'Preparing
-- | action to prepare the test, and related teardown action
GivenAndAfter
:: m r
-> (r -> m ())
-> Language m t q 'Preparing
-> Language m t q 'Preparing
-- | core logic of the test (last preparing action)
When
:: m t
-> Language m t q 'Testing
-> Language m t q 'Preparing
-- | action producing a test
Then
:: (t -> m q)
-> Language m t q 'Testing
-> Language m t q 'Testing
-- | final placeholder
End :: Language m t q 'Testing
-- | Result of this module interpreter
data BDDTest m t q = BDDTest
{ -- | tests from 't'
_tests :: [t -> m q]
, -- | test context
_context :: [TestContext m]
, -- | when action to compute 't'
_when :: m t
}
makeLenses ''BDDTest
-- | Preparing language types
type BDDPreparing m t q = Language m t q 'Preparing
-- | Testing language types
type BDDTesting m t q = Language m t q 'Testing
-- | An interpreter collecting the actions
interpret :: Monad m => Language m t q a -> BDDTest m t q
interpret (Given given p) =
interpret $ GivenAndAfter given (const $ return ()) p
interpret (GivenAndAfter given after p) =
over context ((:) $ TestContext given after) $
interpret p
interpret (When fa p) =
set when fa $ interpret p
interpret (Then ca p) = over tests ((:) ca) $ interpret p
interpret End =
BDDTest [] [] $
error "End on its own does not make sense as a test"