{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
module URI.ByteString.ExtensionSpec
    ( spec
    ) where

import Test.Hspec

import Control.Exception (ErrorCall, evaluate)
import Data.List (isInfixOf)
import URI.ByteString
import URI.ByteString.Extension
import URI.ByteString.QQ

spec :: Spec
spec = do
    describe "IsString Scheme" $ it "works" $ do
        "https" `shouldBe` Scheme "https"

    describe "IsString Host" $ it "works" $ do
        "example.com" `shouldBe` Host "example.com"

    describe "IsString URIRef Relative" $ it "works" $ do
        "example.com/foo?bar=baz"
            `shouldBe` [relativeRef|example.com/foo?bar=baz|]

    describe "IsString URIRef Absolute" $ it "works" $ do
        "https://example.com/foo?bar=baz"
            `shouldBe` [uri|https://example.com/foo?bar=baz|]

    describe "fromText" $ do
        it "returns Just a URI for valid values, as the quasi-quoter would" $ do
            fromText "http://example.com/foo?bar=baz"
                `shouldBe` Just [uri|http://example.com/foo?bar=baz|]

        it "returns Nothing for invalid values" $ do
            fromText "Oh my, what did I do?" `shouldBe` Nothing

    describe "unsafeFromText" $ do
        it "returns a URI for valid values, as the quasi-quoter would" $ do
            unsafeFromText "http://example.com/foo?bar=baz"
                `shouldBe` [uri|http://example.com/foo?bar=baz|]

        it "raises for invalid values" $ do
            evaluate (unsafeFromText "Oh my, what did I do?")
                `shouldThrow` errorContaining "MissingColon"

    describe "toText" $ do
        it "serializes the URI to text" $ do
            toText [uri|https://example.com/foo?bar=baz|]
                `shouldBe` "https://example.com/foo?bar=baz"

    describe "fromRelative" $ do
        it "makes a URI absolute with a given host" $ do
            fromRelative "ftp" "foo.com" [relativeRef|/bar?baz=bat|]
                `shouldBe` [uri|ftp://foo.com/bar?baz=bat|]

    describe "withQuery" $ do
        it "appends a query to a URI" $ do
            let uriWithQuery = [uri|http://example.com|] `withQuery` [("foo", "bar")]

            uriWithQuery `shouldBe` [uri|http://example.com?foo=bar|]

        it "handles a URI with an existing query" $ do
            let uriWithQuery = [uri|http://example.com?foo=bar|] `withQuery` [("baz", "bat")]

            uriWithQuery `shouldBe` [uri|http://example.com?foo=bar&baz=bat|]

        -- This is arguably testing the internals of another package, but IMO
        -- it's worthwhile to show that you don't (and can't) pre-sanitize when
        -- using this function.
        it "handles santization of the query" $ do
            let uriWithQuery = [uri|http://example.com|] `withQuery` [("foo", "bar baz")]

            toText uriWithQuery `shouldBe` "http://example.com?foo=bar%20baz"

errorContaining :: String -> Selector ErrorCall
errorContaining msg = (msg `isInfixOf`) . show
