packages feed

paseto-0.1.0.0: test/Test/Crypto/Paseto/Token/Claims.hs

{-# LANGUAGE TemplateHaskell #-}

module Test.Crypto.Paseto.Token.Claims
  ( tests
  ) where

import Crypto.Paseto.Token.Claim ( Claim (..), claimKey )
import qualified Crypto.Paseto.Token.Claims as Claims
import Data.Foldable ( foldl' )
import qualified Data.List as L
import qualified Data.Set as Set
import Hedgehog
  ( Property
  , assert
  , checkParallel
  , discover
  , forAll
  , property
  , tripping
  , withTests
  , (===)
  )
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range
import Prelude hiding ( exp )
import Test.Crypto.Paseto.Token.Claim.Gen
  ( genAesonString
  , genAudience
  , genClaim
  , genExpiration
  , genIssuedAt
  , genIssuer
  , genNotBefore
  , genSubject
  , genTokenIdentifier
  , genUnregisteredClaimKey
  )
import Test.Crypto.Paseto.Token.Claims.Gen ( genClaims, genNonEmptyClaims )

tests :: IO Bool
tests = checkParallel $$(discover)

------------------------------------------------------------------------------
-- Properties
------------------------------------------------------------------------------

-- | Test that 'Claims.toList' and 'Claims.fromList' round trip.
prop_roundTrip_toFromList :: Property
prop_roundTrip_toFromList = property $ do
  cs <- forAll genClaims
  tripping cs Claims.toList (Just . Claims.fromList)

-- | Test that the size of an empty collection of claims is zero.
prop_emptySizeIsZero :: Property
prop_emptySizeIsZero = withTests 1 . property $ do
  Claims.size (Claims.empty) === 0
  Claims.size (Claims.fromList []) === 0

-- | Test that the size of a 'Claims' value constructed with 'Claims.singleton'
-- is one.
prop_singletonSizeIsOne :: Property
prop_singletonSizeIsOne = property $ do
  c <- forAll genClaim
  Claims.size (Claims.singleton c) === 1

-- | Test that 'Claims.size' accurately reflects the size of the collection.
prop_size :: Property
prop_size = property $ do
  claimsList <- forAll $ Gen.list (Range.constant 0 32) genClaim
  let expectedSize = countUniqueClaims claimsList
      actualSize = Claims.size (Claims.fromList claimsList)
  expectedSize === actualSize
  where
    countUniqueClaims :: [Claim] -> Int
    countUniqueClaims = Set.size . foldl' (\acc c -> Set.insert (claimKey c) acc) Set.empty

-- | Test that 'Claims.null' appropriately reflects whether the collection is
-- empty.
prop_null :: Property
prop_null = property $ do
  claims <- forAll genClaims
  case Claims.size claims of
    0 -> assert (Claims.null claims)
    _ -> assert (not $ Claims.null claims)

-- | Test that 'Claims.delete' deletes a claim from the collection.
prop_delete :: Property
prop_delete = property $ do
  claims <- forAll genNonEmptyClaims
  let claimsList = Claims.toList claims
  randomClaim <- forAll $ Gen.element claimsList
  Claims.toList (Claims.delete (claimKey randomClaim) claims) === L.delete randomClaim claimsList

-- | Test that 'Claims.insert' inserts a claim into the collection.
prop_insert :: Property
prop_insert = property $ do
  claims <- forAll genClaims
  claim <- forAll genClaim
  assert (L.elem claim $ Claims.toList (Claims.insert claim claims))

prop_lookupIssuer :: Property
prop_lookupIssuer = property $ do
  iss <- forAll genIssuer
  claims <- forAll $ Claims.insert (IssuerClaim iss) <$> genClaims
  Just iss === Claims.lookupIssuer claims

prop_lookupSubject :: Property
prop_lookupSubject = property $ do
  sub <- forAll genSubject
  claims <- forAll $ Claims.insert (SubjectClaim sub) <$> genClaims
  Just sub === Claims.lookupSubject claims

prop_lookupAudience :: Property
prop_lookupAudience = property $ do
  aud <- forAll genAudience
  claims <- forAll $ Claims.insert (AudienceClaim aud) <$> genClaims
  Just aud === Claims.lookupAudience claims

prop_lookupExpiration :: Property
prop_lookupExpiration = property $ do
  exp <- forAll genExpiration
  claims <- forAll $ Claims.insert (ExpirationClaim exp) <$> genClaims
  Just exp === Claims.lookupExpiration claims

prop_lookupNotBefore :: Property
prop_lookupNotBefore = property $ do
  nbf <- forAll genNotBefore
  claims <- forAll $ Claims.insert (NotBeforeClaim nbf) <$> genClaims
  Just nbf === Claims.lookupNotBefore claims

prop_lookupIssuedAt :: Property
prop_lookupIssuedAt = property $ do
  iat <- forAll genIssuedAt
  claims <- forAll $ Claims.insert (IssuedAtClaim iat) <$> genClaims
  Just iat === Claims.lookupIssuedAt claims

prop_lookupTokenIdentifier :: Property
prop_lookupTokenIdentifier = property $ do
  jti <- forAll genTokenIdentifier
  claims <- forAll $ Claims.insert (TokenIdentifierClaim jti) <$> genClaims
  Just jti === Claims.lookupTokenIdentifier claims

prop_lookupCustom :: Property
prop_lookupCustom = property $ do
  k <- forAll genUnregisteredClaimKey
  v <- forAll genAesonString
  claims <- forAll $ Claims.insert (CustomClaim k v) <$> genClaims
  Just v === Claims.lookupCustom k claims