packages feed

http-proxy-0.1.0.6: test/Test/Gen.hs

{-# LANGUAGE OverloadedStrings    #-}
------------------------------------------------------------
-- Copyright : Ambiata Pty Ltd
-- Author : Sharif Olorin <sio@tesser.org>
-- License : BSD3
------------------------------------------------------------

module Test.Gen
    ( genWaiRequest
    ) where

import Data.ByteString.Char8 (ByteString)
import Data.CaseInsensitive (CI)
import Data.List (intersperse)
import Data.Monoid ((<>))
import Network.HTTP.Types
import Network.Socket (SockAddr (..), PortNumber)
import Test.QuickCheck

import qualified Data.ByteString.Char8 as BS
import qualified Data.CaseInsensitive as CI
import qualified Data.Text.Encoding as T
import qualified Data.Vault.Lazy as Vault
import qualified Network.Wai.Internal as Wai

genWaiRequest :: Gen Wai.Request
genWaiRequest = do
    method <- genHttpMethod
    version <- genHttpVersion
    pathList <- listOf genAscii
    secure <- elements [ False, True ]
    query <- genQuery
    port <- genPort
    sockAddr <- SockAddrInet port <$> arbitrary
    host <- genHostname
    headers <- genHeaderList
    (bodylen, body) <- genRequestBody
    return $ Wai.Request method version
                (BS.concat $ "/" : intersperse "/" pathList)
                (renderQueryBS query)
                headers secure sockAddr
                (map T.decodeUtf8 pathList)
                query
                (return body)   -- requestBody
                Vault.empty
                bodylen         -- requestBodyLength
                (Just host)     -- requestHeaderHost
                Nothing         -- requestHeaderRange
                Nothing         -- requestHeaderReferer
                Nothing         -- requestHeaderUserAgent


genRequestBody :: Gen (Wai.RequestBodyLength, ByteString)
genRequestBody =
    let mkResult body = (Wai.KnownLength (fromIntegral $ BS.length body), body)
    in  mkResult <$> genAscii


genHttpMethod :: Gen ByteString
genHttpMethod = elements
                [ "GET", "POST", "HEAD", "PUT", "DELETE", "TRACE", "CONNECT"
                , "OPTIONS", "PATCH"
                ]

genHttpVersion :: Gen HttpVersion
genHttpVersion = elements [ http09, http10, http11 ]

genHostname :: Gen ByteString
genHostname = BS.intercalate "." <$> listOf1 genAscii

genPort :: Gen PortNumber
genPort = fromIntegral <$> arbitrary `suchThat` (\x -> x > 1024 && x < (65536 :: Int))

genHeaderList :: Gen [Header]
genHeaderList = listOf genHeader

genHeader :: Gen Header
genHeader = (,) <$> genHeaderName <*> genAscii

genHeaderName :: Gen (CI ByteString)
genHeaderName = CI.mk <$> genAscii

renderQueryBS :: Query -> ByteString
renderQueryBS [] = ""
renderQueryBS ql =
    let mkPair (name, value) = name <> maybe "" ("=" <>) value
    in "?" <> BS.intercalate "&" (map mkPair ql)

genQuery :: Gen Query
genQuery = listOf genQueryItem

genQueryItem :: Gen QueryItem
genQueryItem = (,) <$> genAscii <*> oneof [Just <$> genAscii, pure Nothing]

genAscii :: Gen ByteString
genAscii = BS.pack <$> do
    srange <- choose (3, 10)
    vectorOf srange $ oneof [choose ('a', 'z'), choose ('0', '9')]