unit :: Spec
unit = do
    describe "checkResponse" $ do
        describe "when the response has \"errors\" key" $ do
            let errorMessage = fromJust . decode $ "{\"errors\":[{\"message\":\"Sorry, that page does not exist\",\"code\":34}]}"
                response = Response HT.status404 [] errorMessage
                result = checkResponse response

            it "returns TwitterErrorResponse" $ do
                case result of
                    Left res@(TwitterErrorResponse _ _ msgs) -> do
                        res `shouldBe` TwitterErrorResponse HT.status404 [] [TwitterErrorMessage 34 ""]
                        twitterErrorMessage (head msgs) `shouldBe` "Sorry, that page does not exist"
                    _ -> expectationFailure $ "Unexpected " ++ show result
        describe "when the response does not has \"errors\" key but have error status code" $ do
            let errorMessage = fromJust . decode $ "{}"
                response = Response HT.status404 [] errorMessage
                result = checkResponse response
            it "returns TwitterStatusError" $ do
                case result of
                    Left (TwitterStatusError st hdr body) -> do
                        st `shouldBe` HT.status404
                        hdr `shouldBe` []
                        body `shouldBe` errorMessage
                    _ -> expectationFailure $ "Unexpected " ++ show result

    describe "sinkJSON" $ do
        describe "when valid JSON input" $ do
            let input = "{\"test\": \"input\", \"status\": 200 }"
            it "can consume the input from Source and returns JSON Value" $ do
                res <- yield input $$ sinkJSON
                res ^. key "test" . _String `shouldBe` "input"
                res ^? key "status" . _Integer `shouldBe` Just 200
        describe "when invalid JSON input" $ do
            let input = "{]"
            it "should raise Data.Conduit.Attoparsec.ParseError" $ do
                let parseErrorException (CA.ParseError {}) = True
                    parseErrorException _ = False
                    action = yield input $$ sinkJSON
                action `shouldThrow` parseErrorException

    describe "sinkFromJSON" $ do
        describe "when valid JSON input" $ do
            let input = "{\"test\": \"input\", \"status\": 200 }"
            it "can consume the input from Source and returns a value which type is the specified one" $ do
                res <- yield input $$ sinkFromJSON
                res `shouldBe` TestJSON "input" 200
        describe "when the JSON value does not have expected format" $ do
            let input = "{\"status\": 200}"
            it "should raise FromJSONError" $ do
                let fromJSONException (FromJSONError {}) = True
                    fromJSONException _ = False
                    action :: IO TestJSON
                    action = yield input $$ sinkFromJSON
                action `shouldThrow` fromJSONException
unit :: Spec
unit = do
    describe "checkResponse" $ do
        describe "when the response has \"errors\" key" $ do
            let errorMessage = fromJust . decode $ "{\"errors\":[{\"message\":\"Sorry, that page does not exist\",\"code\":34}]}"
                response = Response HT.status404 [] errorMessage
                result = checkResponse response

            it "returns TwitterErrorResponse" $ do
                case result of
                    Left res@(TwitterErrorResponse _ _ msgs) -> do
                        res `shouldBe` TwitterErrorResponse HT.status404 [] [TwitterErrorMessage 34 ""]
                        twitterErrorMessage (head msgs) `shouldBe` "Sorry, that page does not exist"
                    _ -> expectationFailure $ "Unexpected " ++ show result
        describe "when the response does not has \"errors\" key but have error status code" $ do
            let errorMessage = fromJust . decode $ "{}"
                response = Response HT.status404 [] errorMessage
                result = checkResponse response
            it "returns TwitterStatusError" $ do
                case result of
                    Left (TwitterStatusError st hdr body) -> do
                        st `shouldBe` HT.status404
                        hdr `shouldBe` []
                        body `shouldBe` errorMessage
                    _ -> expectationFailure $ "Unexpected " ++ show result

    describe "sinkJSON" $ do
        describe "when valid JSON input" $ do
            let input = "{\"test\": \"input\", \"status\": 200 }"
            it "can consume the input from Source and returns JSON Value" $ do
                res <- yield input $$ sinkJSON
                res ^. key "test" . _String `shouldBe` "input"
                res ^? key "status" . _Integer `shouldBe` Just 200
        describe "when invalid JSON input" $ do
            let input = "{]"
            it "should raise Data.Conduit.Attoparsec.ParseError" $ do
                let parseErrorException (CA.ParseError {}) = True
                    parseErrorException _ = False
                    action = yield input $$ sinkJSON
                action `shouldThrow` parseErrorException

    describe "sinkFromJSON" $ do
        describe "when valid JSON input" $ do
            let input = "{\"test\": \"input\", \"status\": 200 }"
            it "can consume the input from Source and returns a value which type is the specified one" $ do
                res <- yield input $$ sinkFromJSON
                res `shouldBe` TestJSON "input" 200
        describe "when the JSON value does not have expected format" $ do
            let input = "{\"status\": 200}"
            it "should raise FromJSONError" $ do
                let fromJSONException (FromJSONError {}) = True
                    fromJSONException _ = False
                    action :: IO TestJSON
                    action = yield input $$ sinkFromJSON
                action `shouldThrow` fromJSONException
unit = do
    describe "checkResponse" $ do
        describe "when the response has \"errors\" key" $ do
            let errorMessage = fromJust . decode $ "{\"errors\":[{\"message\":\"Sorry, that page does not exist\",\"code\":34}]}"
                response = Response HT.status404 [] errorMessage
                result = checkResponse response

            it "returns TwitterErrorResponse" $ do
                case result of
                    Left res@(TwitterErrorResponse _ _ msgs) -> do
                        res `shouldBe` TwitterErrorResponse HT.status404 [] [TwitterErrorMessage 34 ""]
                        twitterErrorMessage (head msgs) `shouldBe` "Sorry, that page does not exist"
                    _ -> expectationFailure $ "Unexpected " ++ show result
        describe "when the response does not has \"errors\" key but have error status code" $ do
            let errorMessage = fromJust . decode $ "{}"
                response = Response HT.status404 [] errorMessage
                result = checkResponse response
            it "returns TwitterStatusError" $ do
                case result of
                    Left (TwitterStatusError st hdr body) -> do
                        st `shouldBe` HT.status404
                        hdr `shouldBe` []
                        body `shouldBe` errorMessage
                    _ -> expectationFailure $ "Unexpected " ++ show result

    describe "sinkJSON" $ do
        describe "when valid JSON input" $ do
            let input = "{\"test\": \"input\", \"status\": 200 }"
            it "can consume the input from Source and returns JSON Value" $ do
                res <- yield input $$ sinkJSON
                res ^. key "test" . _String `shouldBe` "input"
                res ^? key "status" . _Integer `shouldBe` Just 200
        describe "when invalid JSON input" $ do
            let input = "{]"
            it "should raise Data.Conduit.Attoparsec.ParseError" $ do
                let parseErrorException (CA.ParseError {}) = True
                    parseErrorException _ = False
                    action = yield input $$ sinkJSON
                action `shouldThrow` parseErrorException

    describe "sinkFromJSON" $ do
        describe "when valid JSON input" $ do
            let input = "{\"test\": \"input\", \"status\": 200 }"
            it "can consume the input from Source and returns a value which type is the specified one" $ do
                res <- yield input $$ sinkFromJSON
                res `shouldBe` TestJSON "input" 200
        describe "when the JSON value does not have expected format" $ do
            let input = "{\"status\": 200}"
            it "should raise FromJSONError" $ do
                let fromJSONException (FromJSONError {}) = True
                    fromJSONException _ = False
                    action :: IO TestJSON
                    action = yield input $$ sinkFromJSON
                action `shouldThrow` fromJSONException