Add property test for auction algorithm.
[?]
Mar 5, 2016, 8:20 PM
LHJ2HFXVUQ4VG25I7DADWU73G5K5WNZBDQ3SVNKFYLZ5BEYM4XCQCDependencies
- [2]
HBULCDN6Add tests for auction winner determination algorithm. - [3]
KNSI575VCleanup of EventLog types. - [4]
2XQD6KKKAdd invitation logic and clean up DBProg error handling. - [5]
KEP5WUFJConvert project to stack-based build. - [6]
SCXG6TJWMake log reduction safer in presence of overlapping events. - [7]
UUR6SMCAAdd start of specs for auctions. - [8]
2KZPOGRBOnce you get Haskell to compile, the tests pass! - [9]
Y35QCWYWMinor improvement in WorkIndex type to eliminate duplicated information. - [10]
TLQ72DSJLenses, sqlite-simple - [11]
M4KM76DGMerge branch 'stackify' - [12]
IZEVQF62Work in progress replacing sqlite with postgres. - [13]
7KZP4RHZSwitch from Data.Time to Data.Thyme - [14]
WO2MINIFAuctions now compile! - [15]
QMRKFEPGRefactor QDB to use a free monad algebra instead. - [16]
F2XLL7XWRemove Ord Bid & sort in favor of sortBy - [17]
NMWWP4ZNTrying out Hspec - [18]
4SCFOJGNSpecs for recovering intervals from the log now pass. - [19]
5DRIWGLUImproving TimeLog specs - [20]
NEDDHXUKReformat via stylish-haskell - [21]
75N3UJ4JMore progression toward lenses. - [22]
GLFF5ZDKFactor winningBids for easier testing. - [23]
ZP62WC47Begin conversion to build with stack. - [24]
EQXRXRZDChanged to use tasty instead of test-framework - [25]
LAROLAYUWIP - [26]
WJO37T74Restored the single test to functionality. - [27]
7HPY3QPFFix linting errors. (yay hlint!) - [*]
64C6AWH6Rename Ananke -> Quixotic, project reboot. - [*]
NVOCQVASInitial failing tests.
Change contents
- edit in aftok.cabal at line 53
--, network-bitcoin >= 1.8 && < 1.9 - edit in aftok.cabal at line 84
, HUnit - edit in aftok.cabal at line 88
, network-bitcoin - replacement in lib/Aftok/Auction.hs at line 8
import Data.Thyme.Clock as Cimport Data.Thyme.Clock as C - edit in lib/Aftok/Auction.hs at line 35
data AuctionResult= WinningBids [Bid]| InsufficientBids Satoshideriving (Show, Eq)bidsTotal :: [Bid] -> SatoshibidsTotal bids =foldl' (\s b -> s + (b^.bidAmount)) (Satoshi 0) bids - replacement in lib/Aftok/Auction.hs at line 53
winningBids :: Auction -> [Bid] -> [Bid]winningBids auction = winningBids' (auction ^. raiseAmount)runAuction :: Auction -> [Bid] -> AuctionResultrunAuction auction = runAuction' (auction ^. raiseAmount) - replacement in lib/Aftok/Auction.hs at line 56
winningBids' :: Satoshi -> [Bid] -> [Bid]winningBids' raiseAmount' bids =runAuction' :: Satoshi -> [Bid] -> AuctionResultrunAuction' raiseAmount' bids = - replacement in lib/Aftok/Auction.hs at line 75
in takeWinningBids 0 $ sortBy bidOrder bids[3.1147]submittedTotal = bidsTotal bidsin if submittedTotal >= raiseAmount'then WinningBids $ takeWinningBids 0 $ sortBy bidOrder bidselse InsufficientBids (raiseAmount' - submittedTotal) - replacement in test/Aftok/AuctionSpec.hs at line 1
{-# OPTIONS_GHC -Wwarn #-}{-# OPTIONS_GHC -Wwarn -fno-warn-orphans #-} - replacement in test/Aftok/AuctionSpec.hs at line 13
--import Data.Thyme.Clock as Cimport Data.Thyme.Clock () - replacement in test/Aftok/AuctionSpec.hs at line 15
import Text.Read (read)import Text.Read (read) - replacement in test/Aftok/AuctionSpec.hs at line 18
--import Test.QuickCheckimport 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 - replacement in test/Aftok/AuctionSpec.hs at line 34
spec =spec = - replacement in test/Aftok/AuctionSpec.hs at line 40
in doin do - replacement in test/Aftok/AuctionSpec.hs at line 52
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." - edit in test/Aftok/AuctionSpec.hs at line 62
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) - replacement in test/Aftok/TimeLogSpec.hs at line 24
instance Arbitrary BtcAddr wherearbitrary = BtcAddr . pack <$> vectorOf 34 arbitrarygenBtcAddr :: Gen BtcAddrgenBtcAddr =BtcAddr . pack <$> vectorOf 34 arbitrary - replacement in test/Aftok/TimeLogSpec.hs at line 28
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) - replacement in test/Aftok/TimeLogSpec.hs at line 34
newtype Intervals = Intervals (L.NonEmpty Interval)genIntervals :: Gen (L.NonEmpty I.Interval)genIntervals =let deltas = fmap T.fromSeconds <$> ((listOf $ choose (0, 72 * 60 * 60)) :: Gen[Int]) - replacement in test/Aftok/TimeLogSpec.hs at line 38[3.3533]→[3.3533:3596](∅→∅),[3.3596]→[3.12561:12637](∅→∅),[3.12637]→[3.94:145](∅→∅),[3.3666]→[3.94:145](∅→∅),[3.145]→[3.3723:3800](∅→∅),[3.3723]→[3.3723:3800](∅→∅)
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 = dobuildIntervals :: 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 - edit in test/Aftok/TimeLogSpec.hs at line 45
let deltas = fmap T.fromSeconds <$> ((listOf $ choose (0, 72 * 60 * 60)) :: Gen[Int]) - replacement in test/Aftok/TimeLogSpec.hs at line 46
pure . Intervals $ L.fromList intervalspure $ L.fromList intervals - replacement in test/Aftok/TimeLogSpec.hs at line 48[3.2046]→[3.2046:2081](∅→∅),[3.2081]→[3.12666:12718](∅→∅),[3.12718]→[3.4038:4126](∅→∅),[3.4038]→[3.4038:4126](∅→∅),[3.4126]→[3.2170:2219](∅→∅),[3.2170]→[3.2170:2219](∅→∅)
instance Arbitrary WorkIndex wherearbitrary =let record = do addr <- arbitraryIntervals ivals <- arbitrarypure (addr, ivals)in WorkIndex . M.fromList <$> listOf recordgenWorkIndex :: Gen WorkIndexgenWorkIndex =let record = do addr <- genBtcAddrivals <- genIntervalspure (addr, ivals)in WorkIndex . M.fromList <$> listOf record - replacement in test/Aftok/TimeLogSpec.hs at line 88[3.494]→[3.3388:3444](∅→∅),[3.3444]→[3.12877:12904](∅→∅),[3.12904]→[3.237:351](∅→∅),[3.1964]→[3.237:351](∅→∅)
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' : xsit "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