packages feed

hal-0.4.8: test/AWS/Lambda/Events/ApiGateway/ProxyRequest/Gen/Resource.hs

{-# LANGUAGE LambdaCase #-}

module AWS.Lambda.Events.ApiGateway.ProxyRequest.Gen.Resource where

import           Control.Monad             (foldM)
import           Control.Monad.Trans.State (StateT, evalStateT, get, put)
import           Data.Foldable             (toList)
import           Data.HashMap.Strict       (HashMap)
import qualified Data.HashMap.Strict       as H
import           Data.List.NonEmpty        (NonEmpty)
import qualified Data.List.NonEmpty        as NE
import           Data.Semigroup            ((<>))
import qualified Data.Set                  as S
import           Data.Text                 (Text)
import qualified Data.Text                 as T
import           Hedgehog
import qualified Hedgehog.Gen              as Gen
import qualified Hedgehog.Range            as Range

data ResourceSegment = Literal Text | Variable Text deriving (Eq, Show)

segments :: Gen (NonEmpty ResourceSegment)
segments = flip evalStateT S.empty
    . fmap NE.fromList
    . Gen.list (Range.linear 1 10)
    $ Gen.choice
        [ Literal <$> Gen.text (Range.linear 1 10) Gen.alpha
        , Variable <$> var
        ]

-- | Generate a variable mapping for a resource path.
vars :: Foldable t => t ResourceSegment -> Gen (HashMap Text Text)
vars = foldM addVar H.empty
    where
        addVar m = \case
            Literal{} -> pure m
            Variable v -> do
                value <- Gen.text (Range.linear 1 20) Gen.unicode
                pure $ H.insert v value m

-- | Instantiate vars in a resource path.
path :: HashMap Text Text -> NonEmpty ResourceSegment -> Text
path vars = ("/" <>) . T.intercalate "/" . toList . fmap toText
    where
        toText = \case
            Literal t -> t
            Variable v -> vars H.! v

-- | Render a resource path with @{var}@ to indicate variables
resource :: NonEmpty ResourceSegment -> Text
resource = ("/" <>) . T.intercalate "/" . toList . fmap toText
    where
        toText = \case
            Literal t -> t
            Variable v -> "{" <> v <> "}"

-- | Generate one variable name for a resource path, and don't reuse
-- variable names.
var :: StateT (S.Set Text) Gen Text
var = do
    vars <- get
    newVar <- Gen.filterT (not . (`S.member` vars)) $
        Gen.text (Range.linear 1 10) Gen.alpha
    put $ S.insert newVar vars
    pure newVar