Bid
<$> (UserId <$> genUUID)
<*> (Seconds <$> arbitrary `suchThat` (>= 0))
<*> arbitrarySatoshi btc
`suchThat` (> Satoshi 0)
<*> arbitrary
Satoshi (a - b)
do
users <- runIO $ fmap UserId <$> replicateM 5 U.nextRandom
let testB0 =
Bid
(users !! 0)
(Seconds 3)
(Satoshi 100)
(read "2016-03-05 15:59:20.000000 UTC")
testB1 =
Bid
(users !! 1)
(Seconds 60)
(Satoshi 1000)
(read "2016-03-05 15:59:21.000000 UTC")
testB2 =
Bid
(users !! 2)
(Seconds 60)
(Satoshi 100)
(read "2016-03-05 15:59:22.000000 UTC")
testB3 =
Bid
(users !! 3)
(Seconds 90)
(Satoshi 100)
(read "2016-03-05 15:59:23.000000 UTC")
testB4 =
Bid
(users !! 4)
(Seconds 60)
(Satoshi 100)
(read "2016-03-05 15:59:24.000000 UTC")
describe "bid ordering" $ do
it "ensures that bids with lowest seconds/btc ratio are first" $ do
bidOrder testB0 testB1 `shouldBe` LT
bidOrder testB1 testB2 `shouldBe` LT
bidOrder testB2 testB3 `shouldBe` LT
it "ensures breaks ties in bid ordering by timestamp" $ do
bidOrder testB2 testB4 `shouldBe` LT
describe "winning bids" $ do
it "determines a sufficient number of winners to fulfill the raise amount" $
let result =
runAuction' (Satoshi 1250) [testB0, testB1, testB2, testB3, testB4]
split =
Bid (users !! 4) (Seconds 31) (Satoshi 50) (testB4 ^. bidTime)
expected = sortBy bidOrder [testB0, testB1, testB2, split]
in case result of
WinningBids winners -> sortBy bidOrder winners `shouldBe` expected
InsufficientBids _ ->
assertFailure
"Sufficinent bids were presented, but auction algorithm asserted otherwise."
it "ensures that the raise amount is fully consumed by the winning bids"
$ forAll ((,) <$> arbitrarySatoshi btc <*> listOf genBid)
$ \(raiseAmount', bids) -> case runAuction' raiseAmount' bids of
WinningBids xs -> bidsTotal xs == raiseAmount'
InsufficientBids t -> t == (raiseAmount' `subs` bidsTotal bids)
hspec spec