{-# LANGUAGE CPP #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# OPTIONS_GHC -freduction-depth=100 #-}

module Servant.FailSpec (spec) where

import Data.Monoid ()
import qualified Network.HTTP.Types as HTTP
import Prelude.Compat
import Servant.API ((:<|>) ((:<|>)))
import Test.Hspec
import Prelude ()

import Servant.Client
import Servant.ClientTestUtils

spec :: Spec
spec = describe "Servant.FailSpec" $ do
  failSpec

failSpec :: Spec
failSpec = beforeAll (startWaiApp failServer) $ afterAll endWaiApp $ do
  context "client returns errors appropriately" $ do
    it "reports FailureResponse" $ \(_, baseUrl) -> do
      let (_ :<|> _ :<|> _ :<|> getDeleteEmpty :<|> _) = client api
      Left res <- runClient getDeleteEmpty baseUrl
      case res of
        FailureResponse _ r | responseStatusCode r == HTTP.status404 -> pure ()
        _ -> fail $ "expected 404 response, but got " <> show res

    it "reports DecodeFailure" $ \(_, baseUrl) -> do
      let (_ :<|> _ :<|> _ :<|> _ :<|> getCapture :<|> _) = client api
      Left res <- runClient (getCapture "foo") baseUrl
      case res of
        DecodeFailure _ _ -> pure ()
        _ -> fail $ "expected DecodeFailure, but got " <> show res

    it "reports ConnectionError" $ \_ -> do
      let (getGetWrongHost :<|> _) = client api
      Left res <- runClient getGetWrongHost (BaseUrl Http "127.0.0.1" 19872 "")
      case res of
        ConnectionError _ -> pure ()
        _ -> fail $ "expected ConnectionError, but got " <> show res

    it "reports UnsupportedContentType" $ \(_, baseUrl) -> do
      let (_ :<|> getGet :<|> _) = client api
      Left res <- runClient getGet baseUrl
      case res of
        UnsupportedContentType "application/octet-stream" _ -> pure ()
        _ -> fail $ "expected UnsupportedContentType, but got " <> show res

    it "reports UnsupportedContentType when there are response headers" $ \(_, baseUrl) -> do
      Left res <- runClient getRespHeaders baseUrl
      case res of
        UnsupportedContentType "application/x-www-form-urlencoded" _ -> pure ()
        _ -> fail $ "expected UnsupportedContentType, but got " <> show res

    it "reports InvalidContentTypeHeader" $ \(_, baseUrl) -> do
      let (_ :<|> _ :<|> _ :<|> _ :<|> _ :<|> _ :<|> getBody :<|> _) = client api
      Left res <- runClient (getBody alice) baseUrl
      case res of
        InvalidContentTypeHeader _ -> pure ()
        _ -> fail $ "expected InvalidContentTypeHeader, but got " <> show res
