content: {-# OPTIONS_GHC -fno-warn-incomplete-uni-patterns #-}
  
  module Fission.Test.Web.Auth.Token.Bearer (spec) where
  
  import qualified Data.Aeson                          as JSON
  import qualified Data.ByteString.Lazy.Char8          as Lazy.Char8
  import qualified RIO.ByteString.Lazy                 as Lazy
  
  import qualified Fission.Web.Auth.Token.Bearer.Types as Bearer
  import qualified Fission.Web.Auth.Token.UCAN.Types   as Fission
  
  -- import qualified Fission.Internal.Fixture.Bearer     as Bearer
  import qualified Fission.Internal.UTF8               as UTF8
  
  import           Fission.Test.Prelude
  
  spec :: Spec
  spec =
    describe "Bearer Token" do
      -- FIXME waiting on new real world example
      -- describe "real world fixture" do
        -- it "deserializes" do
        --   ("\"" <> Bearer.jsonRSA2048 <> "\"")
        --     |> encodeUtf8
        --     |> Lazy.fromStrict
        --     |> JSON.decode
        --     |> shouldBe (Just Bearer.tokenRSA2048)
  
      describe "serialization" do
        itsProp' "serialized is isomorphic to ADT" \(bearer :: Bearer.Token) ->
          JSON.eitherDecode (JSON.encode bearer) `shouldBe` Right bearer
  
        describe "outgoing" do
          itsProp' "has no internal quotes" \(bearer :: Bearer.Token) ->
            bearer
              |> JSON.encode
              |> Lazy.count (fromIntegral $ ord '"')
              |> shouldBe 2
  
          itsProp' "starts with 'Bearer'" \(bearer :: Bearer.Token) ->
            Lazy.isPrefixOf "\"Bearer " (JSON.encode bearer) `shouldBe` True
  
          itsProp' "contains only valid base64 URL characters" \(bearer :: Bearer.Token) ->
            let
              encoded :: Text
              String encoded = JSON.toJSON bearer
            in
              encoded
                |> encodeUtf8
                |> Lazy.fromStrict
                |> Lazy.filter (not . isValidChar)
                |> shouldBe mempty
  
        describe "incoming" do
          describe "Postel's Law" do
            itsProp' "lowercase 'bearer'" \(jwt :: Fission.UCAN) -> do
              let
                jwt' :: Lazy.ByteString
                jwt' = UTF8.stripQuotesLazyBS (JSON.encode jwt)
  
                encoded :: Lazy.ByteString
                encoded = "\"bearer " <> jwt' <> "\""
  
                Right Bearer.Token {jwt = result} = eitherDecode encoded
  
              result `shouldBe` jwt
  
  isValidChar :: Word8 -> Bool
  isValidChar w8 = Lazy.elem w8 (" " <> validEncodedJWTChars)
  
  validEncodedJWTChars :: Lazy.ByteString
  validEncodedJWTChars = Lazy.Char8.pack (base64URLChars <> ['.']) -- dot is used as a separator in JWTs
    where
      base64URLChars :: [Char]
      base64URLChars =
           ['a'..'z']
        <> ['A'..'Z']
        <> ['0'..'9']
        <> ['_', '-']
  