servant-pagination-2.1.0: test/Servant/PaginationSpec.hs
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Servant.PaginationSpec
( spec
) where
import Data.Either (isLeft)
import Data.Proxy (Proxy (..))
import Data.Text (Text)
import Servant (FromHttpApiData (..), ToHttpApiData (..))
import Test.Hspec (Spec, describe, it, shouldBe)
import Test.QuickCheck (Arbitrary (..), property, withMaxSuccess)
import Test.QuickCheck.Gen (Gen, choose, oneof, scale, sized, vectorOf)
import Test.QuickCheck.Modifiers (Positive (..))
import Servant.Pagination
spec :: Spec
spec = do
describe "round-up properties" $ do
it "parseUrlPiece . toUrlPiece = pure" $ withMaxSuccess 10000 $ property $
\x -> (fmap extractA . parseUrlPiece . toUrlPiece) x == (pure . extractA) x
it "parseUrlPiece . toUrlPiece = pure" $ withMaxSuccess 10000 $ property $
\x -> (fmap extractB . parseUrlPiece . toUrlPiece) x == (pure . extractB) x
describe "try-out ranges" $ do
let r0 = getDefaultRange (Proxy @Resource) :: Range "fieldA" Int
it "Range: fieldA" $
let
Right r = parseUrlPiece "fieldA"
r' = r0
in
extractA r `shouldBe` pure r'
it "Range: fieldA 14; limit 42" $
let
Right r = parseUrlPiece "fieldA 14; limit 42"
r' = r0 { rangeValue = Just 14, rangeLimit = 42 }
in
extractA r `shouldBe` pure r'
it "Range: fieldA; order asc; offset 2" $
let
Right r = parseUrlPiece "fieldA; order asc; offset 42"
r' = r0 { rangeOffset = 42, rangeOrder = RangeAsc }
in
extractA r `shouldBe` pure r'
it "Range: fieldA xxx" $
isLeft (parseUrlPiece "fieldA xxx" :: Either Text (Ranges '["fieldA", "fieldB"] Resource))
it "Range: fieldC" $
isLeft (parseUrlPiece "fieldC" :: Either Text (Ranges '["fieldA", "fieldB"] Resource))
it "Range: fieldB" $
isLeft (parseUrlPiece "fieldB" :: Either Text (Ranges '["fieldA"] Resource))
where
extractA :: Ranges '["fieldA", "fieldB"] Resource -> Maybe (Range "fieldA" Int)
extractA = extractRange
extractB :: Ranges '["fieldA", "fieldB"] Resource -> Maybe (Range "fieldB" SimpleString)
extractB = extractRange
data Resource = Resource
{ fieldA :: Int
, fieldB :: SimpleString
} deriving (Show, Eq)
newtype SimpleString = SimpleString
{ getSimpleString :: String
} deriving (Show, Eq, Ord)
instance Arbitrary SimpleString where
arbitrary =
SimpleString <$> scale (+1) (sized $ flip vectorOf $ choose ('a', 'z'))
instance FromHttpApiData SimpleString where
parseUrlPiece =
fmap SimpleString . parseUrlPiece
instance ToHttpApiData SimpleString where
toUrlPiece =
toUrlPiece . getSimpleString
instance HasPagination Resource "fieldA" where
type RangeType Resource "fieldA" = Int
getFieldValue _ = fieldA
instance HasPagination Resource "fieldB" where
type RangeType Resource "fieldB" = SimpleString
getFieldValue _ = fieldB
instance Arbitrary (Ranges '["fieldA", "fieldB"] Resource) where
arbitrary = oneof
[ putRange <$> (arbitrary :: Gen (Range "fieldA" Int))
, putRange <$> (arbitrary :: Gen (Range "fieldB" SimpleString))
]
instance (IsRangeType a, Arbitrary a) => Arbitrary (Range "fieldA" a) where
arbitrary = Range
<$> arbitrary
<*> fmap getPositive arbitrary
<*> fmap getPositive arbitrary
<*> oneof [pure RangeAsc, pure RangeDesc]
<*> pure Proxy
instance (IsRangeType a, Arbitrary a) => Arbitrary (Range "fieldB" a) where
arbitrary = Range
<$> arbitrary
<*> fmap getPositive arbitrary
<*> fmap getPositive arbitrary
<*> oneof [pure RangeAsc, pure RangeDesc]
<*> pure Proxy