{-# LANGUAGE CPP #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeApplications #-} module MockQuery (tests) where import Control.Applicative ((<|>)) import Control.Exception (SomeException, try) #if !MIN_VERSION_base(4,13,0) import Control.Monad.Fail (MonadFail) #endif import Control.Monad.State.Strict (StateT, evalStateT, get, put) import Data.Aeson (Result (..), Value (..), fromJSON) import Data.Either (isLeft) import Data.List (uncons) import Data.Maybe (fromMaybe, isJust, isNothing) import Data.Text (Text) import qualified Data.Text as Text import GHC.Exts (fromList) import Network.HTTP.Types (StdMethod (..)) import Test.Tasty (TestTree, testGroup) import Test.Tasty.HUnit import GitHub.REST.Endpoint (GHEndpoint (..)) import GitHub.REST.Monad.Class import GitHub.REST.PageLinks (PageLinks (..)) tests :: [TestTree] tests = [ testGroup "queryGitHubPage" [ testCase "success single" $ do (result, pageLinks) <- runMockREST (queryGitHubPage @_ @Text) [Right "a"] result @?= "a" isNothing (pageNext pageLinks) @? "PageLinks 'next' rel is not Nothing" , testCase "success multiple" $ do (result, pageLinks) <- runMockREST (queryGitHubPage @_ @Text) [Right "a", Right "b"] result @?= "a" isJust (pageNext pageLinks) @? "PageLinks 'next' rel is Nothing" , testCase "error single" $ do result <- try @SomeException $ runMockREST (queryGitHubPage @_ @Text) [Left "error message!"] isLeft result @? "query did not error" , testCase "success with error in second page" $ do (result, pageLinks) <- runMockREST (queryGitHubPage @_ @Text) [Right "a", Left "error message!"] result @?= "a" isJust (pageNext pageLinks) @? "PageLinks 'next' rel is Nothing" ] , testGroup "queryGitHub" [ testCase "success single" $ do result <- runMockREST (queryGitHub @_ @Text) [Right "a"] result @?= "a" , testCase "success multiple" $ do result <- runMockREST (queryGitHub @_ @Text) [Right "a", Right "b"] result @?= "a" , testCase "error single" $ do result <- try @SomeException $ runMockREST (queryGitHub @_ @Text) [Left "error message!"] isLeft result @? "query did not error" , testCase "success with error in second page" $ do result <- runMockREST (queryGitHub @_ @Text) [Right "a", Left "error message!"] result @?= "a" ] , testGroup "queryGitHubAll" [ testCase "success single" $ do result <- runMockREST (queryGitHubAll @_ @[Text]) [Right "a"] result @?= ["a"] , testCase "success multiple" $ do result <- runMockREST (queryGitHubAll @_ @[Text]) [Right "a", Right "b"] result @?= ["a", "b"] , testCase "error single" $ do result <- try @SomeException $ runMockREST (queryGitHubAll @_ @[Text]) [Left "error message!"] isLeft result @? "query did not error" , testCase "error in second page" $ do result <- try @SomeException $ runMockREST (queryGitHubAll @_ @[Text]) [Right "a", Left "error message!"] isLeft result @? "query did not error" ] , testGroup "queryGitHub_" [ testCase "success single" $ runMockREST queryGitHub_ [Right "a"] , testCase "success multiple" $ runMockREST queryGitHub_ [Right "a", Right "b"] , testCase "error single" $ do result <- try @SomeException $ runMockREST queryGitHub_ [Left "error message!"] isLeft result @? "query did not error" , testCase "success with error in second page" $ runMockREST queryGitHub_ [Right "a", Left "error message!"] ] ] {- Mock implementation -} newtype MockREST a = MockREST {unMockREST :: StateT [Either Text Text] IO a} deriving (Functor, Applicative, Monad, MonadFail) runMockREST :: (GHEndpoint -> MockREST a) -> [Either Text Text] -> IO a runMockREST f results = (`evalStateT` results) $ unMockREST $ f ghEndpoint where ghEndpoint = GHEndpoint { method = GET , endpoint = "/" , endpointVals = [] , ghData = [] } instance MonadGitHubREST MockREST where queryGitHubPage _ = do (curr, rest) <- fromMaybe (error "Did you forget to mock a query?") . uncons <$> MockREST get MockREST $ put rest case curr of Left e -> error $ "Mocked error: " ++ Text.unpack e Right v -> do result <- case fromJSON (String v) <|> fromJSON (Array $ fromList [String v]) of Success a -> return a Error _ -> error "MockREST only supports returning Text or [Text]" let pageLinks = case rest of [] -> mempty _ -> mempty{pageNext = Just "/"} return (result, pageLinks)