{-# LANGUAGE TemplateHaskell #-} module Main where import Control.Concurrent (forkIO, killThread) import Control.Exception (bracket) import Control.Monad.IO.Class (liftIO) import Data.ByteString (ByteString) import Data.Text.Lazy (Text) import Network.HTTP.Client (Request) import qualified Network.HTTP.Client as HTTP import Test.Hspec import Test.HUnit import Web.Scotty import Web.Scotty.Binding.Play port :: Int port = 3000 host :: String host = "http://localhost:" ++ show port withScotty :: ScottyM () -> IO a -> IO () withScotty app f = bracket (forkIO $ scotty port app) killThread (const $ f >> return ()) type SMethod = RoutePattern -> ActionM () -> ScottyM () data Method = GET | POST toS :: Method -> ActionM () -> ScottyM () toS GET = get "/" toS POST = post "/" p :: Method -> [(ByteString, ByteString)] -> Request -> Request p GET = HTTP.setQueryString . map (\(k, v) -> (k, Just v)) p POST = HTTP.urlEncodedBody http :: (Request -> Request) -> IO () http f = HTTP.withManager HTTP.defaultManagerSettings $ \mgr -> do req <- HTTP.parseUrl $ host ++ "/" _ <- HTTP.httpNoBody (f req) mgr return () data Test1 = Test1 { field1 :: Int , field2 :: Text } deriving (Show, Eq) deriveBindable ''Test1 testServer :: (Eq a, Show a, Bindable a) => (ActionM () -> b) -> a -> b testServer m d = m $ do t1 <- parseParams "data" liftIO $ d @=? t1 test :: (Eq a, Show a, Bindable a) => Method -> a -> [(ByteString, ByteString)] -> IO () test m ex = withScotty (testServer (toS m) ex) . http . p m data Test2 = Test2 { field21 :: [Text] } deriving (Show, Eq) deriveBindable ''Test2 data Test3 = Test3 { field31 :: Test1 , field32 :: Test2 } deriving (Show, Eq) deriveBindable ''Test3 data Test4 = Test4 { field41 :: Maybe Int , field42 :: Maybe Test1 } deriving (Show, Eq) deriveBindable ''Test4 main :: IO () main = hspec $ do describe "Web.Scotty.Binding.Play" $ do let ex1 = Test1 1 "test" let ac1 = [ ("data.field1", "1") , ("data.field2", "test") ] it "bind data GET" $ test GET ex1 ac1 it "bind data POST" $ test POST ex1 ac1 let ex2 = 1 :: Int let ac2 = [("data", "1")] it "bind simple data GET" $ test GET ex2 ac2 it "bind simple data POST" $ test POST ex2 ac2 let ex3 = Test2 ["text1", "text2"] let ac3 = [ ("data.field21[0]", "text1") , ("data.field21[1]", "text2") ] it "bind array data GET" $ test GET ex3 ac3 it "bind array data POST" $ test POST ex3 ac3 let ex4 = Test3 ex1 ex3 let ac4 = [ ("data.field31.field1", "1") , ("data.field31.field2", "test") , ("data.field32.field21[0]", "text1") , ("data.field32.field21[1]", "text2") ] it "bind nested data GET" $ test GET ex4 ac4 it "bind nested data POST" $ test POST ex4 ac4 let ex5 = Just 1 :: Maybe Int let ac5 = [ ("data", "1") ] it "bind Maybe data GET" $ test GET ex5 ac5 it "bind Maybe data POST" $ test POST ex5 ac5 let ex6 = Nothing :: Maybe Int let ac6 = [] it "bind Maybe data GET" $ test GET ex6 ac6 it "bind Maybe data POST" $ test POST ex6 ac6 let ex7 = Test4 Nothing (Just ex1) let ac7 = [ ("data.field42.field1", "1") , ("data.field42.field2", "test") ] it "bind Maybe struct data GET" $ test GET ex7 ac7 it "bind Maybe struct data POST" $ test POST ex7 ac7