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.QuickCheckuuidGen :: Gen UUIDuuidGen = fromWords <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrarygenSatoshi :: Gen SatoshigenSatoshi = Satoshi <$> arbitrarygenBid :: Gen BidgenBid = 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 ofWinningBids winners ->sortBy bidOrder winners `shouldBe` expectedInsufficientBids 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 ofWinningBids xs -> bidsTotal xs == raiseAmount'InsufficientBids t -> t == (raiseAmount' - bidsTotal bids)
instance Arbitrary Interval wherearbitrary = dostartTime <- arbitrarydelta <- arbitrary :: Gen (Positive T.NominalDiffTime)pure $ I.interval startTime (startTime .+^ getPositive delta)
genInterval :: Gen I.IntervalgenInterval = dostartTime <- arbitrarydelta <- 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) dxbuildIntervals _ _ = []instance Arbitrary Intervals wherearbitrary = 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) dxbuildIntervals _ _ = []in do
instance Arbitrary WorkIndex wherearbitrary =let record = do addr <- arbitraryIntervals ivals <- arbitrarypure (addr, ivals)in WorkIndex . M.fromList <$> listOf record
genWorkIndex :: Gen WorkIndexgenWorkIndex =let record = do addr <- genBtcAddrivals <- genIntervalspure (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