packages feed

hurriyet-0.2.0.0: tests/Spec.hs

{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Main where
--------------------------------------------------------------------------------
import           Test.Hspec
import           Data.String
import           Data.Aeson
import           Data.Text.Lazy.Encoding (encodeUtf8)
import           Data.Text.Lazy          (Text, pack)
import           Data.Either             (isLeft)
import           Data.Monoid             ((<>))
import           Control.Monad           (when)
import           Data.Proxy              (Proxy(..))
import           Data.Foldable           (forM_)
--------------------------------------------------------------------------------
import qualified Hurriyet                as H
import qualified Hurriyet.Services       as HS
--------------------------------------------------------------------------------

testApiKey :: IsString s => s
testApiKey = "some_api_key"

testClient :: H.Client
testClient = H.getClient testApiKey

{- Beware: anyone using this function should annotate return
 - value, since we are doing json decoding.
 -}
testDecoding :: forall proxy a. (Show a, FromJSON a) => proxy a -> Text -> IO ()
testDecoding _ str = do
  let result = eitherDecode (encodeUtf8 str) :: Either String a
  when (isLeft result) $
    expectationFailure $ "Could not decode service: " <> fromLeft result
  return ()

fromLeft :: Show b => Either a b -> a
fromLeft (Right x) = error $ "Should not have got a right value: " ++ show x
fromLeft (Left x) = x

data Operation = List H.Resource
               | Show H.Resource

stubbedResponseFilename :: Operation -> String
stubbedResponseFilename (List resource) = show resource <> "_list_response"
stubbedResponseFilename (Show resource) = show resource <> "_show_response"

stubbedResponse :: Operation -> IO Text
stubbedResponse op =
  let
    filepath = "tests/static/" <> stubbedResponseFilename op <> ".json"
  in
    pack <$> readFile filepath 

serviceTestMapping ::
  [
    ( String                       -- Name of the resource test. Will be used as description
    , ( (H.Operation, String)      -- Endpoint check for list operation
      , (H.Operation, String)      -- Endpoint check for show operation
      , (Operation, Text -> IO ()) -- List operation and its response decoder
      , (Operation, Text -> IO ()) -- Show operation and its response decoder
      )
    )
  ]

serviceTestMapping =
  [ ("article", ( (H.List H.ArticleResource, "articles")
                , (H.Show H.ArticleResource "3", "articles/3")
                , (List H.ArticleResource, testDecoding (Proxy :: Proxy [HS.Article]))
                , (Show H.ArticleResource, testDecoding (Proxy :: Proxy HS.Article))
                )
    )
  , ("column", ( (H.List H.ColumnResource, "columns")
                , (H.Show H.ColumnResource "3", "columns/3")
                , (List H.ColumnResource, testDecoding (Proxy :: Proxy [HS.Column]))
                , (Show H.ColumnResource, testDecoding (Proxy :: Proxy HS.Column))
                )
    )
  , ("news_photo_gallery", ( (H.List H.NewsPhotoGalleryResource, "newsphotogalleries")
                           , (H.Show H.NewsPhotoGalleryResource "3", "newsphotogalleries/3")
                           , (List H.NewsPhotoGalleryResource, testDecoding (Proxy :: Proxy [HS.NewsPhotoGallery]))
                           , (Show H.NewsPhotoGalleryResource, testDecoding (Proxy :: Proxy HS.NewsPhotoGallery))
                           )
    )
  -- Pages endpoint is inaccessible at the moment of testing
  -- , ("page", ( (H.List H.PageResource, "pages")
  --            , (H.Show H.PageResource "3", "pages/3")
  --            , (List H.PageResource, testDecoding (Proxy :: Proxy [HS.Page]))
  --            , (Show H.PageResource, testDecoding (Proxy :: Proxy HS.Page))
  --            )
  --   )
  , ("path", ( (H.List H.PathResource, "paths")
             , (H.Show H.PathResource "3", "paths/3")
             , (List H.PathResource, testDecoding (Proxy :: Proxy [HS.Path]))
             , (Show H.PathResource, testDecoding (Proxy :: Proxy HS.Path))
             )
    )
  , ("writer", ( (H.List H.WriterResource, "writers")
             , (H.Show H.WriterResource "3", "writers/3")
             , (List H.WriterResource, testDecoding (Proxy :: Proxy [HS.Writer]))
             , (Show H.WriterResource, testDecoding (Proxy :: Proxy HS.Writer))
             )
    )
  ]

main :: IO ()
main = hspec $ do
  describe "client" $ do
    it "saves the api key" $
      H.apiKey testClient `shouldBe` testApiKey
    it "reads" $ do
      _ <- H.withClient testClient H.getArticles
      return ()  
  describe "resources" $
    forM_ serviceTestMapping $ \resource ->
      context (fst resource) $ do
        let (listUrl, showUrl, (listOperation, listDecodeTester), (showOperation, showDecodeTester)) = snd resource
        context "list" $
          it "has the right endpoint" $
            H.getUrl (fst listUrl) `shouldBe` H.baseUrl ++ snd listUrl 
        it "parses response" $
          listDecodeTester =<< stubbedResponse listOperation
        context "show" $
          it "has the right endpoint" $
            H.getUrl (fst showUrl) `shouldBe` H.baseUrl ++ snd showUrl 
        it "parses response" $
          showDecodeTester =<< stubbedResponse showOperation