Skip to content
Snippets Groups Projects
Commit 25f24e4d authored by Jean-Paul Calderone's avatar Jean-Paul Calderone
Browse files

Make the typeclass test suite easily reusable

parent a48b46aa
No related branches found
No related tags found
1 merge request!2Stripe webhook
...@@ -50,6 +50,7 @@ test-suite PaymentServer-test ...@@ -50,6 +50,7 @@ test-suite PaymentServer-test
, hspec , hspec
, hspec-wai , hspec-wai
, hspec-wai-json , hspec-wai-json
, hspec-expectations
, aeson , aeson
, stripe-core , stripe-core
, time , time
......
...@@ -9,17 +9,31 @@ module SpecPersistence where ...@@ -9,17 +9,31 @@ module SpecPersistence where
import Test.QuickCheck import Test.QuickCheck
( Property ( Property
, (===) , (==>)
) )
import Control.Monad.IO.Class import Control.Monad.IO.Class
( liftIO ( liftIO
) )
import Test.Hspec
( Spec
, describe
, it
)
import Test.Hspec.Expectations
( shouldReturn
)
import Test.QuickCheck
( property
)
import Test.QuickCheck.Monadic import Test.QuickCheck.Monadic
( monadicIO ( monadicIO
, run , run
, assert , assert
, pre , pre
) )
import Test.QuickCheck.Instances.Text
(
)
import PaymentServer.Persistence import PaymentServer.Persistence
( RedeemError(NotPaid, AlreadyRedeemed) ( RedeemError(NotPaid, AlreadyRedeemed)
, Voucher , Voucher
...@@ -29,51 +43,45 @@ import PaymentServer.Persistence ...@@ -29,51 +43,45 @@ import PaymentServer.Persistence
) )
-- | A voucher which has not been paid for cannot be redeemed. -- | A voucher which has not been paid for cannot be redeemed.
unpaidVoucherNotRedeemable :: VoucherDatabase d => IO d -> Voucher -> Fingerprint -> Property unpaidVoucherNotRedeemable :: VoucherDatabase d => IO d -> Property
unpaidVoucherNotRedeemable getDB voucher fingerprint = monadicIO $ do unpaidVoucherNotRedeemable getDB = property $ \voucher fingerprint -> do
db <- liftIO getDB db <- liftIO getDB
result <- run $ redeemVoucher db voucher fingerprint redeemVoucher db voucher fingerprint `shouldReturn` Left NotPaid
assert (result == Left NotPaid)
-- | The in-memory implementation for unpaidVoucherNotRedeemable.
prop_memory_unpaidVoucherNotRedeemable = unpaidVoucherNotRedeemable memory
-- | A voucher which is paid for can be redeemed with any fingerprint. -- | A voucher which is paid for can be redeemed with any fingerprint.
paidVoucherRedeemable :: VoucherDatabase d => IO d -> Voucher -> Fingerprint -> Property paidVoucherRedeemable :: VoucherDatabase d => IO d -> Property
paidVoucherRedeemable getDB voucher fingerprint = monadicIO $ do paidVoucherRedeemable getDB = property $ \voucher fingerprint -> do
db <- liftIO getDB db <- liftIO getDB
() <- run $ payForVoucher db voucher () <- payForVoucher db voucher
result <- run $ redeemVoucher db voucher fingerprint redeemVoucher db voucher fingerprint `shouldReturn` Right ()
assert (result == Right ())
-- | The in-memory implementation for paidVoucherRedeemable.
prop_memory_paidVoucherRedeemable = paidVoucherRedeemable memory
-- | A voucher which is paid for can be redeemed more than once as long as the -- | A voucher which is paid for can be redeemed more than once as long as the
-- same fingerprint is used each time. -- same fingerprint is used each time.
paidVoucherMultiRedeemable :: VoucherDatabase d => IO d -> Voucher -> Fingerprint -> Property paidVoucherMultiRedeemable :: VoucherDatabase d => IO d -> Property
paidVoucherMultiRedeemable getDB voucher fingerprint = monadicIO $ do paidVoucherMultiRedeemable getDB = property $ \voucher fingerprint -> do
db <- liftIO getDB db <- liftIO getDB
() <- run $ payForVoucher db voucher () <- payForVoucher db voucher
let redeem = redeemVoucher db voucher fingerprint let redeem = redeemVoucher db voucher fingerprint
run redeem redeem
result <- run redeem redeem `shouldReturn` Right ()
assert (result == Right ())
-- | The in-memory implementation for paidVoucherMultiRedeemable.
prop_memory_paidVoucherMultiRedeemable = paidVoucherMultiRedeemable memory
-- | A voucher which is paid for can not be redeemed a second time with a -- | A voucher which is paid for can not be redeemed a second time with a
-- different fingerprint than was used on the first attempt. -- different fingerprint than was used on the first attempt.
paidVoucherMismatchFingerprint :: VoucherDatabase d => IO d -> Voucher -> Fingerprint -> Fingerprint -> Property paidVoucherMismatchFingerprint :: VoucherDatabase d => IO d -> Property
paidVoucherMismatchFingerprint getDB voucher fingerprint fingerprint' = monadicIO $ do paidVoucherMismatchFingerprint getDB = property $ \voucher fingerprint fingerprint' ->
pre (fingerprint /= fingerprint') fingerprint /= fingerprint' ==> do
db <- liftIO getDB db <- liftIO getDB
() <- run $ payForVoucher db voucher () <- payForVoucher db voucher
let redeem = redeemVoucher db voucher let redeem = redeemVoucher db voucher
run $ redeem fingerprint redeem fingerprint
result <- run $ redeem fingerprint' redeem fingerprint' `shouldReturn` Left AlreadyRedeemed
assert (result == Left AlreadyRedeemed)
makeSpec :: VoucherDatabase d => IO d -> Spec
makeSpec getDB = do
describe "voucher interactions" $ do
it "denies redemption of a not-paid-for voucher" $ unpaidVoucherNotRedeemable getDB
it "allows redemption of paid-for vouchers" $ paidVoucherRedeemable getDB
it "allows multiple redemption as long as the same fingerprint is used" $ paidVoucherMultiRedeemable getDB
it "denies a subsequent redemption with a different fingerprint" $ paidVoucherMismatchFingerprint getDB
-- | The in-memory implementation for paidVoucherMismatchFingerprint. spec_memory = makeSpec memory
prop_memory_paidVoucherMismatchFingerprint = paidVoucherMismatchFingerprint memory
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment