{-# 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 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