mcp-server-0.1.0.17: test/Spec/BasicDerivation.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
module Spec.BasicDerivation (spec) where
import Control.Monad (forM_)
import Data.Text (Text)
import qualified Data.Text as T
import MCP.Server
import MCP.Server.Derive
import Test.Hspec
import TestTypes
import TestData
-- Generate handlers using Template Haskell
testPromptHandlers :: (PromptListHandler IO, PromptGetHandler IO)
testPromptHandlers = $(derivePromptHandler ''TestPrompt 'handleTestPrompt)
testResourceHandlers :: (ResourceListHandler IO, ResourceReadHandler IO)
testResourceHandlers = $(deriveResourceHandler ''TestResource 'handleTestResource)
testToolHandlers :: (ToolListHandler IO, ToolCallHandler IO)
testToolHandlers = $(deriveToolHandler ''TestTool 'handleTestTool)
-- Helper functions for common test patterns
shouldReturnContentText :: IO (Either Error Content) -> Text -> IO ()
shouldReturnContentText action expected = do
result <- action
case result of
Right (ContentText content) -> content `shouldBe` expected
other -> expectationFailure $ "Expected ContentText '" ++ T.unpack expected ++ "' but got: " ++ show other
shouldContainText :: IO (Either Error Content) -> Text -> IO ()
shouldContainText action expectedSubstring = do
result <- action
case result of
Right (ContentText content) ->
T.isInfixOf expectedSubstring content `shouldBe` True
other -> expectationFailure $ "Expected ContentText containing '" ++ T.unpack expectedSubstring ++ "' but got: " ++ show other
testPromptCall :: PromptGetHandler IO -> Text -> [(Text, Text)] -> Text -> IO ()
testPromptCall handler name args expected =
shouldReturnContentText (handler name args) expected
testResourceCall :: ResourceReadHandler IO -> String -> Text -> IO ()
testResourceCall handler uriString expected = do
case parseURI uriString of
Just uri -> do
result <- handler uri
case result of
Right (ResourceText _ _ content) -> content `shouldBe` expected
Right (ResourceBlob _ _ _) -> expectationFailure "Expected ResourceText but got ResourceBlob"
Left err -> expectationFailure $ "Expected success but got error: " ++ show err
Nothing -> expectationFailure $ "Failed to parse URI: " ++ uriString
testToolCall :: ToolCallHandler IO -> Text -> [(Text, Text)] -> Text -> IO ()
testToolCall handler name args expected =
shouldReturnContentText (handler name args) expected
spec :: Spec
spec = describe "Basic Template Haskell Derivation" $ do
describe "Prompt derivation" $ do
let (_, getHandler) = testPromptHandlers
forM_ promptTestCases $ \testCase ->
it (T.unpack $ testDescription testCase) $
testPromptCall getHandler (promptName testCase) (promptArgs testCase) (expectedResult testCase)
describe "Resource derivation" $ do
let (_, readHandler) = testResourceHandlers
forM_ resourceTestCases $ \testCase ->
it (T.unpack $ resourceTestDescription testCase) $ do
case parseURI (T.unpack $ TestData.resourceUri testCase) of
Just uri ->
if useSubstringMatch testCase
then do
result <- readHandler uri
case result of
Right (ResourceText _ _ content) ->
T.isInfixOf (resourceExpectedContent testCase) content `shouldBe` True
Right (ResourceBlob _ _ _) -> expectationFailure "Expected ResourceText but got ResourceBlob"
Left err -> expectationFailure $ "Expected success but got error: " ++ show err
else testResourceCall readHandler (T.unpack $ TestData.resourceUri testCase) (resourceExpectedContent testCase)
Nothing -> expectationFailure $ "Failed to parse URI: " ++ T.unpack (TestData.resourceUri testCase)
describe "Tool derivation" $ do
let (_, callHandler) = testToolHandlers
forM_ toolTestCases $ \testCase ->
it (T.unpack $ toolTestDescription testCase) $
testToolCall callHandler (toolName testCase) (toolArgs testCase) (toolExpectedResult testCase)