okapi/lib/test/Spec.hs

167 lines
5.3 KiB
Haskell
Raw Normal View History

{-# LANGUAGE ApplicativeDo #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE LinearTypes #-}
2022-07-03 09:46:12 +03:00
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE QualifiedDo #-}
2023-04-15 23:39:54 +03:00
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeApplications #-}
import Control.Exception (evaluate)
import Data.Aeson qualified as Aeson
import Data.OpenApi qualified as OAPI
import Data.Text qualified as Text
import Network.HTTP.Types qualified as HTTP
2023-04-20 09:33:20 +03:00
import Okapi.Endpoint
import Okapi.Script
import Okapi.Script.AddHeader (Response)
2023-04-21 11:21:39 +03:00
import Okapi.Script.AddHeader qualified as AddHeaders
2023-04-20 09:33:20 +03:00
import Okapi.Script.Body qualified as Body
import Okapi.Script.Headers qualified as Headers
import Okapi.Script.Path qualified as Path
import Okapi.Script.Query qualified as Query
import Okapi.Script.Responder qualified as Responder
import Prelude.Linear qualified as L
import Test.Hspec
import Web.HttpApiData qualified as Web
2022-08-04 03:22:25 +03:00
2022-03-30 03:07:37 +03:00
main :: IO ()
main = hspec $ do
2023-04-15 23:39:54 +03:00
describe "Path Operations" $ do
it "returns the first element of a list" $ do
2023-04-20 09:33:20 +03:00
Path.eval path1 ["index"] `shouldBe` (Ok (), [])
it "returns the first element of a list" $ do
2023-04-20 09:33:20 +03:00
Path.eval path1 ["index", "about"] `shouldBe` (Fail Path.NotEnoughOperations, ["index", "about"])
it "returns the first element of a list" $ do
2023-04-20 09:33:20 +03:00
Path.eval path2 ["item", "5"] `shouldBe` (Ok 5, [])
it "returns the first element of a list" $ do
2023-04-20 09:33:20 +03:00
Path.eval path2 ["item"] `shouldBe` (Fail Path.TooManyOperations, ["item"])
it "returns the first element of a list" $ do
2023-04-20 09:33:20 +03:00
Path.eval path3 ["product", "books", "56708"] `shouldBe` (Ok (Category "books", ProductID 56708), [])
it "returns the first element of a list" $ do
2023-04-20 09:33:20 +03:00
Path.eval path3 ["product", "books", "56708", "info"] `shouldBe` (Fail Path.NotEnoughOperations, ["product", "books", "56708", "info"])
it "returns the first element of a list" $ do
2023-04-20 09:33:20 +03:00
Path.eval path3 ["product", "books"] `shouldBe` (Fail Path.TooManyOperations, ["product", "books"])
2023-04-15 23:39:54 +03:00
describe "Query Operations" $ do
it "returns the first element of a list" $ do
2023-04-20 09:33:20 +03:00
Query.eval query1 [("score", Just "5"), ("user", Just "Joe")] `shouldBe` (Ok $ Filter 5 $ Username "Joe", [])
2023-04-15 23:39:54 +03:00
it "returns the first element of a list" $ do
2023-04-20 09:33:20 +03:00
Query.eval query2 [("user", Just "Bob"), ("active", Nothing)] `shouldBe` (Ok $ Username "Bob", [])
2023-04-15 23:39:54 +03:00
it "returns the first element of a list" $ do
2023-04-20 09:33:20 +03:00
Query.eval query3 [("username", Just "Bob")] `shouldBe` (Ok (Username "Anon", Nothing), [("username", Just "Bob")])
2023-04-21 11:21:39 +03:00
data AddHeaders = AddHeaders
2023-04-20 09:33:20 +03:00
{ addCookie :: Username -> Response -> Response,
addAnotherHeader :: Username -> Response -> Response,
cacheHeader :: Int -> Response -> Response
}
responder1 = do
itsOk <- Responder.json
@Aeson.Value
HTTP.status200
do
2023-04-21 11:21:39 +03:00
addCookie <- AddHeaders.using @Username "Cookie"
pure addCookie
itsNotFound <- Responder.json
@Aeson.Value
HTTP.status404
do
2023-04-21 11:21:39 +03:00
addCookie <- AddHeaders.using @Username "Blob"
addAnotherHeader <- AddHeaders.using @Username "X-Some-Header"
cacheHeader <- AddHeaders.using @Int "X-Cache-Time"
pure $ AddHeaders {..}
pure (itsOk, itsNotFound)
responder2 = undefined
2023-04-15 23:39:54 +03:00
newtype Username = Username {unwrap :: Text.Text}
deriving newtype (Eq, Show, Web.FromHttpApiData, Web.ToHttpApiData, OAPI.ToSchema, Aeson.ToJSON)
2023-04-15 23:39:54 +03:00
data Filter = Filter
{ score :: Int,
byUser :: Username
}
deriving (Eq, Show)
2023-04-20 09:33:20 +03:00
query1 :: Query.Script Filter
query1 = do
2023-04-15 23:39:54 +03:00
score <- Query.param @Int "score"
byUser <- Query.param @Username "user"
pure Filter {..}
2023-04-15 23:39:54 +03:00
2023-04-20 09:33:20 +03:00
query2 :: Query.Script Username
query2 = do
2023-04-15 23:39:54 +03:00
username <- Query.param @Username "user"
Query.flag "active"
pure username
2023-04-15 23:39:54 +03:00
2023-04-20 09:33:20 +03:00
query3 :: Query.Script (Username, Maybe ())
query3 = do
2023-04-15 23:39:54 +03:00
user <- Query.option (Username "Anon") $ Query.param "user"
active <- Query.optional $ Query.flag "active"
pure (user, active)
2023-04-15 23:39:54 +03:00
2023-04-20 09:33:20 +03:00
path1 :: Path.Script ()
path1 = Path.static "index"
2023-04-20 09:33:20 +03:00
path2 :: Path.Script Int
path2 = do
Path.static "item"
uuid <- Path.param @Int "uuid"
pure uuid
newtype Category = Category {unwrap :: Text.Text}
deriving newtype (Eq, Show, Web.FromHttpApiData, OAPI.ToSchema, Aeson.ToJSON)
newtype ProductID = ProductID {unwrap :: Int}
deriving newtype (Eq, Show, Web.FromHttpApiData, OAPI.ToSchema, Aeson.ToJSON)
2023-04-20 09:33:20 +03:00
path3 :: Path.Script (Category, ProductID)
path3 = do
Path.static "product"
category <- Path.param @Category "category"
productID <- Path.param @ProductID "productID"
pure (category, productID)
testPlan =
2023-04-20 09:33:20 +03:00
Plan
id
2023-04-20 09:33:20 +03:00
( Endpoint
HTTP.GET
do
Path.static "index"
magicNumber <- Path.param @Int "magicNumber"
pure magicNumber
do
x <- Query.param @Int "x"
y <- Query.option 10 $ Query.param @Int "y"
pure (x, y)
do pure ()
do pure ()
do
2023-04-19 04:53:13 +03:00
itsOk <- Responder.json @Int HTTP.status200 do
2023-04-21 11:21:39 +03:00
addSecretNumber <- AddHeaders.using @Int "X-SECRET"
2023-04-19 04:53:13 +03:00
pure addSecretNumber
pure itsOk
)
\magicNumber (x, y) () () responder ->
do
let newNumber = magicNumber + x * y
print newNumber
return $ responder (\addHeader response -> addHeader (newNumber * 100) response) newNumber