From af7102a9b20790f02b817e8b4ea66ca3764fc079 Mon Sep 17 00:00:00 2001
From: Jean-Paul Calderone <exarkun@twistedmatrix.com>
Date: Fri, 6 Sep 2019 11:20:53 -0400
Subject: [PATCH] Broken attempt to get the tests working with Tasty

---
 test/SpecStuff.hs | 159 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 159 insertions(+)
 create mode 100644 test/SpecStuff.hs

diff --git a/test/SpecStuff.hs b/test/SpecStuff.hs
new file mode 100644
index 0000000..fe8f26e
--- /dev/null
+++ b/test/SpecStuff.hs
@@ -0,0 +1,159 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module SpecStuff where
+
+import Test.Tasty
+  ( TestTree
+  , testGroup
+  )
+import Test.Tasty.Wai
+  ( assertBody
+  , assertStatus
+  , assertStatus'
+  , get
+  , post
+  , testWai
+  )
+import Test.Tasty.QuickCheck
+  ( testProperty
+  )
+import PaymentServer.Persistence
+  ( Voucher
+  )
+import PaymentServer.Redemption
+  ( RedemptionAPI
+  , Result(Failed, Succeeded)
+  )
+import PaymentServer.Issuer
+  ( BlindedToken
+  )
+import Data.ByteString
+  ( ByteString
+  )
+import Text.Printf
+  ( printf
+  )
+import Data.Aeson
+ ( decode
+ , encode
+ )
+import Servant
+  ( Application
+  , Proxy(Proxy)
+  , serve
+  )
+import Test.Hspec
+  ( Spec
+  , parallel
+  , describe
+  , it
+  , runIO
+  )
+import Network.HTTP.Types
+  ( Header
+  )
+import Test.Hspec.Wai
+  ( ResponseMatcher(matchBody, matchHeaders)
+  , (<:>)
+  , WaiExpectation
+  , Body
+  , MatchBody(MatchBody)
+  , with
+  , shouldRespondWith
+  , liftIO
+  )
+import Test.QuickCheck
+  ( ioProperty
+  )
+import Test.Hspec.Wai.QuickCheck
+  ( Testable(toProperty)
+  , WaiProperty(unWaiProperty)
+  , property
+  )
+import Test.QuickCheck.Instances.Text ()
+import Util.Spec
+  ( wrongMethodNotAllowed
+  , nonJSONUnsupportedMediaType
+  , wrongJSONInvalidRequest
+  )
+import Util.WAI
+  ( postJSON
+  )
+import PaymentServer.Issuer
+  ( BlindedToken
+  , ChallengeBypass(ChallengeBypass)
+  , Issuer
+  , trivialIssue
+  )
+import PaymentServer.Redemption
+  ( RedemptionAPI
+  , Redeem(Redeem)
+  , Result(Failed, Succeeded)
+  , redemptionServer
+  )
+import PaymentServer.Persistence
+  ( RedeemError(NotPaid)
+  , Voucher
+  , VoucherDatabase(payForVoucher, redeemVoucher)
+  , memory
+  )
+
+redemptionAPI :: Proxy RedemptionAPI
+redemptionAPI = Proxy
+
+app :: VoucherDatabase d => Issuer -> d -> Application
+app issue = serve redemptionAPI . redemptionServer issue
+
+path = "/"
+
+propertyRedeem :: ByteString -> Voucher -> [BlindedToken] -> ResponseMatcher -> WaiExpectation
+propertyRedeem path voucher tokens matcher =
+  postJSON path (encode $ Redeem voucher tokens) `shouldRespondWith` matcher
+
+-- | A VoucherDatabaseTestDouble has a VoucherDatabase instance which provides
+-- a number of different behaviors which are useful to be able to directly
+-- test against.
+data VoucherDatabaseTestDouble
+  -- | A RefuseRedemption database always refuses redemption with a given error.
+  = RefuseRedemption RedeemError
+  -- | A PermitRedemption database always permits redemption.
+  | PermitRedemption
+  deriving (Show)
+
+instance VoucherDatabase VoucherDatabaseTestDouble where
+  payForVoucher _ voucher = return ()
+  redeemVoucher (RefuseRedemption err) _ _ = return $ Left err
+  redeemVoucher PermitRedemption _ _ = return $ Right ()
+
+test_foo :: TestTree
+test_foo = testGroup "Foo" redemption
+
+redemption :: [TestTree]
+redemption =
+  [ testProperty "fails when the voucher is not paid" $
+    \(voucher :: Voucher) (tokens :: [BlindedToken]) ->
+      propertyRedeem path voucher tokens 400
+      { matchBody = matchJSONBody Failed
+      -- major/minor, fine.  charset=utf-8... okay.  but really this is
+      -- overspecified by encoding the exact byte sequence.  I'd rather
+      -- assert semantic equality.
+      , matchHeaders = ["Content-Type" <:> "application/json;charset=utf-8"]
+      }
+  ]
+
+matchJSONBody :: Result -> MatchBody
+matchJSONBody expected =
+  let
+    bodyMatcher :: [Header] -> Body -> Maybe String
+    bodyMatcher headers actualBody =
+      case decode actualBody of
+        Nothing ->
+          Just $ "failed to decode body as value of expected type: " ++ show actualBody
+        Just actual ->
+          if actual == expected then
+            Nothing
+          else
+            Just $ "decoded body does not equal expected value: " ++ show actual ++ show expected
+  in
+    MatchBody bodyMatcher
-- 
GitLab