packages feed

servant-matrix-param-0.2: test/Servant/MatrixParam/ServerSpec.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeOperators #-}

module Servant.MatrixParam.ServerSpec where

import           Control.Monad.IO.Class
import           Control.Monad.Trans.Except
import           Data.ByteString.Lazy
import           Data.Map.Strict
import           Data.Proxy
import           Data.Text
import           Network.HTTP.Types (ok200)
import           Network.Wai
import           Network.Wai.Test
import           Servant.API
import           Servant.Server
import           Test.Hspec

import           Servant.MatrixParam
import           Servant.MatrixParam.Server ()
import           Servant.MatrixParam.Server.Internal

type Api =
       WithMatrixParams "a" '[MatrixParam "name" String] :> Get '[PlainText] String
  :<|> WithMatrixParams "b" '[MatrixParam "foo" Int, MatrixParam "bar" Int]
         :> Get '[PlainText] String

api :: Proxy Api
api = Proxy

type Handler = ExceptT ServantErr IO

server :: Server Api
server = a :<|> b
  where
    a :: Maybe String -> Handler String
    a p = return $ show p

    b :: Maybe Int -> Maybe Int -> Handler String
    b foo bar = return $ show (foo, bar)

testWithPath :: [Text] -> ByteString -> IO ()
testWithPath segments expected = do
  (flip runSession) (serve api server) $ do
    response <- Network.Wai.Test.request defaultRequest{
      pathInfo = segments
    }
    liftIO $ do
      simpleStatus response `shouldBe` ok200
      simpleBody response `shouldBe` expected

spec :: Spec
spec = do
  describe "Servant.API.MatrixParam" $ do
    it "allows to retrieve simple matrix parameters" $ do
      testWithPath ["a;name=bob"] "Just \"bob\""

    it "allows to omit matrix parameters" $ do
      testWithPath ["a"] "Nothing"

    it "allows multiple keys per segment" $ do
      testWithPath ["b;foo=23;bar=42"] "(Just 23,Just 42)"

    it "allows to overwrite matrix params" $ do
      testWithPath ["a;name=alice;name=bob"] "Just \"bob\""

  describe "parsePathSegment" $ do
    it "parses a path segment with a matrix param" $ do
      parsePathSegment "foo;bar=baz" `shouldBe`
        Just (MatrixSegment "foo" (Just (fromList [("bar", "baz")])))

    it "parses a bare segment" $ do
      parsePathSegment "foo" `shouldBe`
        Just (MatrixSegment "foo" mempty)

    it "parses a segment with multiple matrix params" $ do
      parsePathSegment "foo;bar=baz;huhu=baba" `shouldBe`
        Just (MatrixSegment "foo" (Just (fromList [("bar", "baz"), ("huhu", "baba")])))

    it "parses a segment with multiple values for the same matrix param" $ do
      parsePathSegment "foo;bar=baz;bar=huhu" `shouldBe`
        Just (MatrixSegment "foo" (Just (fromList [("bar", "huhu")])))

    it "parses a segment with semicolon but without params" $ do
      parsePathSegment "foo;" `shouldBe`
        Just (MatrixSegment "foo" mempty)

    it "succeeds for invalid matrix parameters strings" $ do
      parsePathSegment "foo;bar==" `shouldBe`
        Just (MatrixSegment "foo" mempty)

    it "can parse the empty string as value" $ do
      parsePathSegment "foo;bar=" `shouldBe`
        Just (MatrixSegment "foo" (Just (fromList [("bar", "")])))