LHJ2HFXVUQ4VG25I7DADWU73G5K5WNZBDQ3SVNKFYLZ5BEYM4XCQC
HBULCDN6E75FAPILFVLTQIKABDEWL3HZTBLICLCWOIKDRYM6UIBQC
KEP5WUFJXTMKRRNZLYTGYYWA4VLFCMHTKTJYF5EA5IWBYFMU6WYQC
64C6AWH66FDKU6UE6Z6JPX2J2GBM2JOPTH2GL6LHKAIUBGNGDZ5AC
2XQD6KKKD6QVHFHAEMVE3XXY7X2T7BLTLL7XIILZAXNJJH2YONUQC
UUR6SMCAJMA7O3ZFUCQMPZFDDIPUVQ5IHUAC5F252YVD6H3JIKPQC
5DRIWGLUKMQZU2ZPBXSTLAWJKAMOD5YXAHM5LEDQHDFGYYLHWCDQC
NEDDHXUK3GNFMOFO3KLU7NRIHCTYNWBT3D6HTKZAOXFDE6HMDZ6AC
LAROLAYUGJ4Q5AEFV5EJMIA2ZKBNCBWHHHPCJ3CKCNIUIYUKRFVQC
75N3UJ4JK56KXF56GASGPAWLFYGJDETVJNYTF4KXFCQM767JUU5AC
F2XLL7XWGUV4TJD4X2MJADYAQHCSB4HD2TPPEYVHEKHOQIOOFISAC
WO2MINIF4TXOHWSE7JWXRZYN64XRVLYIRFMF4SMPSOXKA2V77KMQC
GLFF5ZDKWI7WKPZSAEE3IUM27LL6DFOPIL4VPODXYXV3BCSCJ6GQC
ZP62WC472OTQETO2HTHIQIPO57XZIWVKPA4KL62GYU4OZDMB6NSAC
7KZP4RHZ3QSYTPPQ257A65Z5UPX44TF2LAI2U5EMULQCLDCEUK2AC
NVOCQVASZWTKQJG7GPH7KHKZZR7NUG4WLV5YY4KAIRPCJRWCZPIAC
EQXRXRZDYCM7BDAVBOXQYPG6C7IJT3OFGNIXCDAHJJBRKAXNGL7AC
SCXG6TJWYIPRUMT27KGKIIF6FYKTUTY74UNZ2FQTT63XZ6HIF3AAC
KNSI575VAW6HRCZYXOEPQ4DTSML4EORML5MV4DJBRKE7TXCPS4EAC
4SCFOJGNDAN4XZEAPWQQCBJ3CGZCJP3HUADRQLYZ2ITAKA7EJJTQC
2KZPOGRBY6KBMO76F55ZKIVOLSG3O63VP3RHRZVANXYT3OLZ3OWQC
--import Test.QuickCheck
import Test.HUnit.Base (assertFailure)
import Test.QuickCheck
uuidGen :: Gen UUID
uuidGen = fromWords <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
genSatoshi :: Gen Satoshi
genSatoshi = Satoshi <$> arbitrary
genBid :: Gen Bid
genBid = Bid <$> (UserId <$> uuidGen)
<*> (Seconds <$> arbitrary `suchThat` (>= 0))
<*> genSatoshi `suchThat` (> Satoshi 0)
<*> arbitrary
let winners = winningBids' (Satoshi 1250) [testB0, testB1, testB2, testB3, testB4]
split = Bid (UserId nil) (Seconds 30) (Satoshi 50) (testB4 ^. bidTime)
in sortBy bidOrder winners `shouldBe` sortBy bidOrder [testB0, testB1, testB2, split]
let result = runAuction' (Satoshi 1250) [testB0, testB1, testB2, testB3, testB4]
split = Bid (UserId nil) (Seconds 30) (Satoshi 50) (testB4 ^. bidTime)
expected = sortBy bidOrder [testB0, testB1, testB2, split]
in case result of
WinningBids winners ->
sortBy bidOrder winners `shouldBe` expected
InsufficientBids t ->
assertFailure "Sufficinent bids were presented, but auction algorithm asserted otherwise."
it "ensures that the raise amount is fully consumed by the winning bids" $
forAll ((,) <$> genSatoshi <*> listOf genBid) $
\(raiseAmount', bids) ->
case runAuction' raiseAmount' bids of
WinningBids xs -> bidsTotal xs == raiseAmount'
InsufficientBids t -> t == (raiseAmount' - bidsTotal bids)
instance Arbitrary Interval where
arbitrary = do
startTime <- arbitrary
delta <- arbitrary :: Gen (Positive T.NominalDiffTime)
pure $ I.interval startTime (startTime .+^ getPositive delta)
genInterval :: Gen I.Interval
genInterval = do
startTime <- arbitrary
delta <- arbitrary :: Gen (Positive T.NominalDiffTime)
pure $ I.interval startTime (startTime .+^ getPositive delta)
buildIntervals :: T.UTCTime -> [NominalDiffTime] -> [Interval]
buildIntervals t (d : s : dx) | d > 0 =
let ival = I.interval t (t .+^ d)
in ival : buildIntervals (ival ^. end .+^ s) dx
buildIntervals _ _ = []
instance Arbitrary Intervals where
arbitrary = do
buildIntervals :: T.UTCTime -> [NominalDiffTime] -> [I.Interval]
buildIntervals t (d : s : dx) | d > 0 =
let ival = I.interval t (t .+^ d)
in ival : buildIntervals (ival ^. I.end .+^ s) dx
buildIntervals _ _ = []
in do
instance Arbitrary WorkIndex where
arbitrary =
let record = do addr <- arbitrary
Intervals ivals <- arbitrary
pure (addr, ivals)
in WorkIndex . M.fromList <$> listOf record
genWorkIndex :: Gen WorkIndex
genWorkIndex =
let record = do addr <- genBtcAddr
ivals <- genIntervals
pure (addr, ivals)
in WorkIndex . M.fromList <$> listOf record
it "recovers a work index from events" $ property $
\(WorkIndex widx) ->
let mergeAdjacent ((Interval s e) : (Interval s' e') : xs) | e == s' = mergeAdjacent $ Interval s e' : xs
it "recovers a work index from events" $
forAll genWorkIndex $ \(WorkIndex widx) ->
let mergeAdjacent ((I.Interval s e) : (I.Interval s' e') : xs) | e == s' = mergeAdjacent $ I.Interval s e' : xs