2015-11-04 12:16:14 +01:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
2015-12-02 13:28:04 +01:00
|
|
|
{-# LANGUAGE TypeOperators #-}
|
|
|
|
{-# LANGUAGE DataKinds #-}
|
|
|
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
|
|
|
{-# LANGUAGE FlexibleContexts #-}
|
|
|
|
{-# LANGUAGE FlexibleInstances #-}
|
|
|
|
{-# LANGUAGE TypeSynonymInstances #-}
|
|
|
|
{-# LANGUAGE ScopedTypeVariables #-}
|
2015-12-02 14:02:05 +01:00
|
|
|
{-# LANGUAGE CPP #-}
|
|
|
|
#if __GLASGOW_HASKELL__ < 710
|
|
|
|
{-# LANGUAGE OverlappingInstances #-}
|
|
|
|
#endif
|
2015-11-04 12:16:14 +01:00
|
|
|
|
|
|
|
module Servant.ForeignSpec where
|
|
|
|
|
2015-12-02 13:28:04 +01:00
|
|
|
import Data.Monoid ((<>))
|
|
|
|
import Data.Proxy
|
|
|
|
import Servant.Foreign
|
|
|
|
import Servant.Foreign.Internal
|
2015-11-04 12:16:14 +01:00
|
|
|
|
|
|
|
import Test.Hspec
|
|
|
|
|
|
|
|
spec :: Spec
|
|
|
|
spec = describe "Servant.Foreign" $ do
|
|
|
|
camelCaseSpec
|
2015-12-02 13:28:04 +01:00
|
|
|
listFromAPISpec
|
2015-11-04 12:16:14 +01:00
|
|
|
|
|
|
|
camelCaseSpec :: Spec
|
2015-12-22 00:33:05 +01:00
|
|
|
camelCaseSpec = describe "camelCase" $
|
2015-11-04 12:16:14 +01:00
|
|
|
it "converts FunctionNames to camelCase" $ do
|
|
|
|
camelCase ["post", "counter", "inc"] `shouldBe` "postCounterInc"
|
|
|
|
camelCase ["get", "hyphen-ated", "counter"] `shouldBe` "getHyphenatedCounter"
|
2015-12-02 13:28:04 +01:00
|
|
|
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
|
|
|
|
data LangX
|
|
|
|
|
|
|
|
instance HasForeignType LangX () where
|
|
|
|
typeFor _ _ = "voidX"
|
|
|
|
instance HasForeignType LangX Int where
|
|
|
|
typeFor _ _ = "intX"
|
|
|
|
instance HasForeignType LangX Bool where
|
|
|
|
typeFor _ _ = "boolX"
|
|
|
|
instance {-# Overlapping #-} HasForeignType LangX String where
|
|
|
|
typeFor _ _ = "stringX"
|
2015-12-02 14:02:05 +01:00
|
|
|
instance {-# Overlappable #-} HasForeignType LangX a => HasForeignType LangX [a] where
|
2015-12-02 13:28:04 +01:00
|
|
|
typeFor lang _ = "listX of " <> typeFor lang (Proxy :: Proxy a)
|
|
|
|
|
|
|
|
type TestApi
|
|
|
|
= "test" :> Header "header" [String] :> QueryFlag "flag" :> Get '[JSON] Int
|
|
|
|
:<|> "test" :> QueryParam "param" Int :> ReqBody '[JSON] [String] :> Post '[JSON] ()
|
|
|
|
:<|> "test" :> QueryParams "params" Int :> ReqBody '[JSON] String :> Put '[JSON] ()
|
|
|
|
:<|> "test" :> Capture "id" Int :> Delete '[JSON] ()
|
|
|
|
|
|
|
|
testApi :: [Req]
|
|
|
|
testApi = listFromAPI (Proxy :: Proxy LangX) (Proxy :: Proxy TestApi)
|
|
|
|
|
|
|
|
listFromAPISpec :: Spec
|
|
|
|
listFromAPISpec = describe "listFromAPI" $ do
|
2015-12-22 00:33:05 +01:00
|
|
|
it "generates 4 endpoints for TestApi" $
|
2015-12-02 13:28:04 +01:00
|
|
|
length testApi `shouldBe` 4
|
|
|
|
|
|
|
|
let [getReq, postReq, putReq, deleteReq] = testApi
|
|
|
|
|
2015-12-22 00:33:05 +01:00
|
|
|
let reqEq req1 req2 = do
|
|
|
|
_reqUrl req1 `shouldBe` _reqUrl req2
|
|
|
|
_reqMethod req1 `shouldBe` _reqMethod req2
|
|
|
|
_reqBody req1 `shouldBe` _reqBody req2
|
|
|
|
_reqReturnType req1 `shouldBe` _reqReturnType req2
|
|
|
|
_funcName req1 `shouldBe` _funcName req2
|
|
|
|
|
|
|
|
let h = case (_reqHeaders req1, _reqHeaders req2) of
|
|
|
|
([], []) -> True
|
|
|
|
([HeaderArg a], [HeaderArg b]) -> a == b
|
|
|
|
_ -> False
|
|
|
|
|
|
|
|
h `shouldBe` True
|
|
|
|
|
2015-12-02 13:28:04 +01:00
|
|
|
it "collects all info for get request" $ do
|
2015-12-22 00:33:05 +01:00
|
|
|
let req1 = getReq
|
|
|
|
req2 = defReq
|
|
|
|
{ _reqUrl = Url
|
|
|
|
[ Segment $ Static "test" ]
|
|
|
|
[ QueryArg ("flag", "boolX") Flag ]
|
|
|
|
, _reqMethod = "GET"
|
|
|
|
, _reqHeaders = [HeaderArg ("header", "listX of stringX")]
|
|
|
|
, _reqBody = Nothing
|
|
|
|
, _reqReturnType = "intX"
|
|
|
|
, _funcName = ["get", "test"]
|
|
|
|
}
|
|
|
|
|
|
|
|
reqEq req1 req2
|
|
|
|
|
2015-12-02 13:28:04 +01:00
|
|
|
|
|
|
|
it "collects all info for post request" $ do
|
2015-12-22 00:33:05 +01:00
|
|
|
let req1 = getReq
|
|
|
|
req2 = defReq
|
|
|
|
{ _reqUrl = Url
|
|
|
|
[ Segment $ Static "test" ]
|
|
|
|
[ QueryArg ("param", "intX") Normal ]
|
|
|
|
, _reqMethod = "POST"
|
|
|
|
, _reqHeaders = []
|
|
|
|
, _reqBody = Just "listX of stringX"
|
|
|
|
, _reqReturnType = "voidX"
|
|
|
|
, _funcName = ["post", "test"]
|
|
|
|
}
|
|
|
|
|
|
|
|
reqEq req1 req2
|
2015-12-02 13:28:04 +01:00
|
|
|
|
|
|
|
it "collects all info for put request" $ do
|
2015-12-22 00:33:05 +01:00
|
|
|
let req1 = getReq
|
|
|
|
req2 = defReq
|
|
|
|
{ _reqUrl = Url
|
|
|
|
[ Segment $ Static "test" ]
|
|
|
|
-- Shoud this be |intX| or |listX of intX| ?
|
|
|
|
[ QueryArg ("params", "listX of intX") List ]
|
|
|
|
, _reqMethod = "PUT"
|
|
|
|
, _reqHeaders = []
|
|
|
|
, _reqBody = Just "stringX"
|
|
|
|
, _reqReturnType = "voidX"
|
|
|
|
, _funcName = ["put", "test"]
|
|
|
|
}
|
|
|
|
|
|
|
|
reqEq req1 req2
|
2015-12-02 13:28:04 +01:00
|
|
|
|
|
|
|
it "collects all info for delete request" $ do
|
2015-12-22 00:33:05 +01:00
|
|
|
let req1 = getReq
|
|
|
|
req2 = defReq
|
|
|
|
{ _reqUrl = Url
|
|
|
|
[ Segment $ Static "test"
|
|
|
|
, Segment $ Cap ("id", "intX") ]
|
|
|
|
[]
|
|
|
|
, _reqMethod = "DELETE"
|
|
|
|
, _reqHeaders = []
|
|
|
|
, _reqBody = Nothing
|
|
|
|
, _reqReturnType = "voidX"
|
|
|
|
, _funcName = ["delete", "test", "by", "id"]
|
|
|
|
}
|
|
|
|
|
|
|
|
reqEq req1 req2
|