packages feed

gamgee-1.0.0: test/Gamgee/Test/Operation.hs

{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE RankNTypes        #-}

module Gamgee.Test.Operation
  ( OutputMessage
  , runTest
  , addToken
  , deleteToken
  , listTokens
  , getOTP
  ) where

import           Control.Monad.ST      (ST, runST)
import qualified Crypto.Random         as CR
import           Data.STRef            (STRef)
import qualified Data.STRef            as STRef
import qualified Data.Time.Clock.POSIX as Clock
import qualified Gamgee.Effects        as Eff
import qualified Gamgee.Operation      as Operation
import qualified Gamgee.Test.Effects   as Eff
import qualified Gamgee.Token          as Token
import qualified Polysemy              as P
import qualified Polysemy.Error        as P
import           Relude


----------------------------------------------------------------------------------------------------
-- All operations supported by gamgee run using STRefs
----------------------------------------------------------------------------------------------------

type TestStore s = STRef s (Maybe LByteString)
type OutputMessage = Text

runTest :: Maybe LByteString -> (forall s. TestStore s -> ST s a) -> a
runTest store action = runST $ STRef.newSTRef store >>= action

addToken :: CR.DRG gen
         => gen
         -> TestStore s
         -> [Text]
         -> Token.TokenSpec
         -> ST s (Either Eff.EffError ())
addToken drg store input spec = P.runM
                                $ P.runError
                                $ Eff.runCryptoRandom drg
                                $ Eff.runCrypto
                                $ Eff.runListSecretInput input
                                $ Eff.runByteStoreST store
                                $ Eff.runGamgeeJSONStore
                                $ Eff.runStateJSON
                                $ Operation.addToken spec

deleteToken :: TestStore s -> Token.TokenIdentifier -> ST s (Either Eff.EffError ())
deleteToken store t = P.runM
                      $ P.runError
                      $ Eff.runByteStoreST store
                      $ Eff.runGamgeeJSONStore
                      $ Eff.runStateJSON
                      $ Operation.deleteToken t

listTokens :: TestStore s -> ST s (Either Eff.EffError [OutputMessage])
listTokens store = fmap fst
                   <$> P.runM
                       (P.runError
                        $ Eff.runOutputPure
                        $ Eff.runByteStoreST store
                        $ Eff.runGamgeeJSONStore
                        $ Eff.runStateJSON Operation.listTokens)

getOTP :: CR.DRG gen
       => gen
       -> TestStore s
       -> [Text]
       -> Token.TokenIdentifier
       -> Clock.POSIXTime
       -> ST s (Either Eff.EffError [OutputMessage])
getOTP drg store input tok time =
  fmap fst
  <$> P.runM
      (P.runError
       $ Eff.runOutputPure
       $ Eff.runCryptoRandom drg
       $ Eff.runCrypto
       $ Eff.runListSecretInput input
       $ Eff.runByteStoreST store
       $ Eff.runGamgeeJSONStore
       $ Eff.runStateJSON
       $ Eff.runTOTP
       $ Operation.getOTP tok time)