packages feed

haskoin-store-data-0.53.0: test/Haskoin/Store/DataSpec.hs

{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleContexts          #-}
{-# LANGUAGE FlexibleInstances         #-}
{-# LANGUAGE OverloadedStrings         #-}
{-# LANGUAGE RecordWildCards           #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Haskoin.Store.DataSpec
    ( spec
    ) where

import           Control.Monad           (forM_)
import           Data.Aeson              (FromJSON (..))
import qualified Data.ByteString         as B
import           Data.String.Conversions (cs)
import           Haskoin
import           Haskoin.Store.Data
import           Haskoin.Util.Arbitrary
import           Test.Hspec              (Spec, describe)
import           Test.QuickCheck

serialVals :: [SerialBox]
serialVals =
    [ SerialBox (arbitrary :: Gen DeriveType)
    , SerialBox (arbitrary :: Gen XPubSpec)
    , SerialBox (arbitrary :: Gen BlockRef)
    , SerialBox (arbitrary :: Gen TxRef)
    , SerialBox (arbitrary :: Gen Balance)
    , SerialBox (arbitrary :: Gen Unspent)
    , SerialBox (arbitrary :: Gen BlockData)
    , SerialBox (arbitrary :: Gen StoreInput)
    , SerialBox (arbitrary :: Gen Spender)
    , SerialBox (arbitrary :: Gen StoreOutput)
    , SerialBox (arbitrary :: Gen Prev)
    , SerialBox (arbitrary :: Gen TxData)
    , SerialBox (arbitrary :: Gen Transaction)
    , SerialBox (arbitrary :: Gen XPubBal)
    , SerialBox (arbitrary :: Gen XPubUnspent)
    , SerialBox (arbitrary :: Gen XPubSummary)
    , SerialBox (arbitrary :: Gen HealthCheck)
    , SerialBox (arbitrary :: Gen Event)
    , SerialBox (arbitrary :: Gen TxId)
    , SerialBox (arbitrary :: Gen PeerInformation)
    , SerialBox (arbitrary :: Gen (GenericResult BlockData))
    , SerialBox (arbitrary :: Gen (RawResult BlockData))
    , SerialBox (arbitrary :: Gen (RawResultList BlockData))
    ]

jsonVals :: [JsonBox]
jsonVals =
    [ JsonBox (arbitrary :: Gen TxRef)
    , JsonBox (arbitrary :: Gen BlockRef)
    , JsonBox (arbitrary :: Gen Spender)
    , JsonBox (arbitrary :: Gen XPubSummary)
    , JsonBox (arbitrary :: Gen HealthCheck)
    , JsonBox (arbitrary :: Gen Event)
    , JsonBox (arbitrary :: Gen TxId)
    , JsonBox (arbitrary :: Gen PeerInformation)
    , JsonBox (arbitrary :: Gen (GenericResult XPubSummary))
    , JsonBox (arbitrary :: Gen (RawResult BlockData))
    , JsonBox (arbitrary :: Gen (RawResultList BlockData))
    , JsonBox (arbitrary :: Gen Except)
    , JsonBox (arbitrary :: Gen BinfoWallet)
    , JsonBox (arbitrary :: Gen BinfoSymbol)
    , JsonBox (arbitrary :: Gen BinfoBlockInfo)
    , JsonBox (arbitrary :: Gen BinfoInfo)
    , JsonBox (arbitrary :: Gen BinfoSpender)
    , JsonBox (arbitrary :: Gen BinfoRate)
    , JsonBox (arbitrary :: Gen BinfoTicker)
    , JsonBox (arbitrary :: Gen BinfoTxId)
    , JsonBox (arbitrary :: Gen BinfoShortBal)
    , JsonBox (arbitrary :: Gen BinfoHistory)
    , JsonBox (arbitrary :: Gen BinfoHeader)
    , JsonBox (arbitrary :: Gen BinfoBlocks)
    ]

netVals :: [NetBox]
netVals =
    [ NetBox ( balanceToJSON
             , balanceToEncoding
             , balanceParseJSON
             , arbitraryNetData)
    , NetBox ( storeOutputToJSON
             , storeOutputToEncoding
             , storeOutputParseJSON
             , arbitraryNetData)
    , NetBox ( unspentToJSON
             , unspentToEncoding
             , unspentParseJSON
             , arbitraryNetData)
    , NetBox ( xPubBalToJSON
             , xPubBalToEncoding
             , xPubBalParseJSON
             , arbitraryNetData)
    , NetBox ( xPubUnspentToJSON
             , xPubUnspentToEncoding
             , xPubUnspentParseJSON
             , arbitraryNetData)
    , NetBox ( storeInputToJSON
             , storeInputToEncoding
             , storeInputParseJSON
             , arbitraryStoreInputNet)
    , NetBox ( blockDataToJSON
             , blockDataToEncoding
             , const parseJSON
             , arbitraryBlockDataNet)
    , NetBox ( transactionToJSON
             , transactionToEncoding
             , transactionParseJSON
             , arbitraryNetData)
    , NetBox ( binfoMultiAddrToJSON
             , binfoMultiAddrToEncoding
             , binfoMultiAddrParseJSON
             , arbitraryNetData)
    , NetBox ( binfoBalanceToJSON
             , binfoBalanceToEncoding
             , binfoBalanceParseJSON
             , arbitraryNetData)
    , NetBox ( binfoBlockToJSON
             , binfoBlockToEncoding
             , binfoBlockParseJSON
             , arbitraryNetData)
    , NetBox ( binfoTxToJSON
             , binfoTxToEncoding
             , binfoTxParseJSON
             , arbitraryNetData)
    , NetBox ( binfoTxInputToJSON
             , binfoTxInputToEncoding
             , binfoTxInputParseJSON
             , arbitraryNetData)
    , NetBox ( binfoTxOutputToJSON
             , binfoTxOutputToEncoding
             , binfoTxOutputParseJSON
             , arbitraryNetData)
    , NetBox ( binfoXPubPathToJSON
             , binfoXPubPathToEncoding
             , binfoXPubPathParseJSON
             , arbitraryNetData)
    , NetBox ( binfoUnspentToJSON
             , binfoUnspentToEncoding
             , binfoUnspentParseJSON
             , arbitraryNetData)
    , NetBox ( binfoBlocksToJSON
             , binfoBlocksToEncoding
             , binfoBlocksParseJSON
             , arbitraryNetData)
    , NetBox ( binfoRawAddrToJSON
             , binfoRawAddrToEncoding
             , binfoRawAddrParseJSON
             , arbitraryNetData)
    , NetBox ( binfoMempoolToJSON
             , binfoMempoolToEncoding
             , binfoMempoolParseJSON
             , arbitraryNetData)
    ]

spec :: Spec
spec = do
    describe "Binary Encoding" $
        forM_ serialVals $ \(SerialBox g) -> testSerial g
    describe "JSON Encoding" $
        forM_ jsonVals $ \(JsonBox g) -> testJson g
    describe "JSON Encoding with Network" $
        forM_ netVals $ \(NetBox (j,e,p,g)) -> testNetJson j e p g

instance Arbitrary BlockRef where
    arbitrary =
        oneof [BlockRef <$> arbitrary <*> arbitrary, MemRef <$> arbitrary]

instance Arbitrary Prev where
    arbitrary = Prev <$> arbitraryBS1 <*> arbitrary

instance Arbitrary TxData where
    arbitrary =
        TxData
            <$> arbitrary
            <*> arbitraryTx btc
            <*> arbitrary
            <*> arbitrary
            <*> arbitrary
            <*> arbitrary

instance Arbitrary StoreInput where
    arbitrary =
        oneof
            [ StoreCoinbase
                <$> arbitraryOutPoint
                <*> arbitrary
                <*> arbitraryBS1
                <*> listOf arbitraryBS1
            , StoreInput
                <$> arbitraryOutPoint
                <*> arbitrary
                <*> arbitraryBS1
                <*> arbitraryBS1
                <*> arbitrary
                <*> listOf arbitraryBS1
                <*> arbitraryMaybe arbitraryAddress
            ]

arbitraryStoreInputNet :: Gen (Network, StoreInput)
arbitraryStoreInputNet = do
    net <- arbitraryNetwork
    store <- arbitrary
    let res | getSegWit net = store
            | otherwise = store{ inputWitness = [] }
    return (net, res)

instance Arbitrary Spender where
    arbitrary = Spender <$> arbitraryTxHash <*> arbitrary

instance Arbitrary StoreOutput where
    arbitrary =
        StoreOutput
          <$> arbitrary
          <*> arbitraryBS1
          <*> arbitrary
          <*> arbitraryMaybe arbitraryAddress

instance Arbitrary Transaction where
    arbitrary =
        Transaction
            <$> arbitrary
            <*> arbitrary
            <*> arbitrary
            <*> arbitrary
            <*> arbitrary
            <*> arbitrary
            <*> arbitrary
            <*> arbitrary
            <*> arbitraryTxHash
            <*> arbitrary
            <*> arbitrary
            <*> arbitrary

instance Arbitrary PeerInformation where
    arbitrary =
        PeerInformation
            <$> (cs <$> listOf arbitraryUnicodeChar)
            <*> listOf arbitraryPrintableChar
            <*> arbitrary
            <*> arbitrary
            <*> arbitrary

instance Arbitrary BlockHealth where
    arbitrary =
        BlockHealth
            <$> arbitrary
            <*> arbitrary
            <*> arbitrary

instance Arbitrary TimeHealth where
    arbitrary =
        TimeHealth
            <$> arbitrary
            <*> arbitrary

instance Arbitrary CountHealth where
    arbitrary =
        CountHealth
            <$> arbitrary
            <*> arbitrary

instance Arbitrary MaxHealth where
    arbitrary =
        MaxHealth
            <$> arbitrary
            <*> arbitrary

instance Arbitrary HealthCheck where
    arbitrary =
        HealthCheck
            <$> arbitrary
            <*> arbitrary
            <*> arbitrary
            <*> arbitrary
            <*> arbitrary
            <*> arbitrary
            <*> arbitrary

instance Arbitrary RejectCode where
    arbitrary =
        elements
            [ RejectMalformed
            , RejectInvalid
            , RejectObsolete
            , RejectDuplicate
            , RejectNonStandard
            , RejectDust
            , RejectInsufficientFee
            , RejectCheckpoint
            ]

instance Arbitrary XPubSpec where
    arbitrary = XPubSpec <$> (snd <$> arbitraryXPubKey) <*> arbitrary

instance Arbitrary DeriveType where
    arbitrary = elements [DeriveNormal, DeriveP2SH, DeriveP2WPKH]

instance Arbitrary TxId where
    arbitrary = TxId <$> arbitraryTxHash

instance Arbitrary TxRef where
    arbitrary = TxRef <$> arbitrary <*> arbitraryTxHash

instance Arbitrary Balance where
    arbitrary =
        Balance
            <$> arbitraryAddress
            <*> arbitrary
            <*> arbitrary
            <*> arbitrary
            <*> arbitrary
            <*> arbitrary

instance Arbitrary Unspent where
    arbitrary =
        Unspent
            <$> arbitrary
            <*> arbitraryOutPoint
            <*> arbitrary
            <*> arbitraryBS1
            <*> arbitraryMaybe arbitraryAddress

instance Arbitrary BlockData where
    arbitrary =
        BlockData
        <$> arbitrary
        <*> arbitrary
        <*> (fromInteger <$> suchThat arbitrary (0<=))
        <*> arbitraryBlockHeader
        <*> arbitrary
        <*> arbitrary
        <*> listOf1 arbitraryTxHash
        <*> arbitrary
        <*> arbitrary
        <*> arbitrary

arbitraryBlockDataNet :: Gen (Network, BlockData)
arbitraryBlockDataNet = do
    net <- arbitraryNetwork
    dat <- arbitrary
    let res | getSegWit net = dat
            | otherwise = dat{ blockDataWeight = 0}
    return (net, res)

instance Arbitrary a => Arbitrary (GenericResult a) where
    arbitrary = GenericResult <$> arbitrary

instance Arbitrary a => Arbitrary (RawResult a) where
    arbitrary = RawResult <$> arbitrary

instance Arbitrary a => Arbitrary (RawResultList a) where
    arbitrary = RawResultList <$> arbitrary

instance Arbitrary XPubBal where
    arbitrary = XPubBal <$> arbitrary <*> arbitrary

instance Arbitrary XPubUnspent where
    arbitrary = XPubUnspent <$> arbitrary <*> arbitrary

instance Arbitrary XPubSummary where
    arbitrary =
        XPubSummary
        <$> arbitrary
        <*> arbitrary
        <*> arbitrary
        <*> arbitrary
        <*> arbitrary
        <*> arbitrary

instance Arbitrary Event where
    arbitrary =
        oneof
        [ EventBlock <$> arbitraryBlockHash
        , EventTx <$> arbitraryTxHash
        ]

instance Arbitrary Except where
    arbitrary =
        oneof
        [ return ThingNotFound
        , return ServerError
        , return BadRequest
        , UserError <$> arbitrary
        , StringError <$> arbitrary
        , TxIndexConflict <$> listOf1 arbitraryTxHash
        , return ServerTimeout
        ]

---------------------------------------
-- Blockchain.info API Compatibility --
---------------------------------------

instance Arbitrary BinfoTxId where
    arbitrary = oneof
        [ BinfoTxIdHash <$> arbitraryTxHash
        , BinfoTxIdIndex <$> arbitrary
        ]

instance Arbitrary BinfoMultiAddr where
    arbitrary = do
        getBinfoMultiAddrAddresses <- arbitrary
        getBinfoMultiAddrWallet <- arbitrary
        getBinfoMultiAddrTxs <- resize 10 arbitrary
        getBinfoMultiAddrInfo <- arbitrary
        getBinfoMultiAddrRecommendFee <- arbitrary
        getBinfoMultiAddrCashAddr <- arbitrary
        return BinfoMultiAddr {..}

instance Arbitrary BinfoRawAddr where
    arbitrary = do
        binfoRawAddr <-
            oneof
            [ BinfoAddr <$> arbitraryAddress
            , BinfoXpub . snd <$> arbitraryXPubKey
            ]
        binfoRawBalance <- arbitrary
        binfoRawTxCount <- arbitrary
        binfoRawUnredeemed <- arbitrary
        binfoRawReceived <- arbitrary
        binfoRawSent <- arbitrary
        binfoRawTxs <- arbitrary
        return $ BinfoRawAddr {..}

instance Arbitrary BinfoShortBal where
    arbitrary = BinfoShortBal <$> arbitrary <*> arbitrary <*> arbitrary

instance Arbitrary BinfoBalance where
    arbitrary = do
        getBinfoAddress <- arbitraryAddress
        getBinfoAddrTxCount <- arbitrary
        getBinfoAddrReceived <- arbitrary
        getBinfoAddrSent <- arbitrary
        getBinfoAddrBalance <- arbitrary
        getBinfoXPubKey <- snd <$> arbitraryXPubKey
        getBinfoXPubAccountIndex <- arbitrary
        getBinfoXPubChangeIndex <- arbitrary
        elements [BinfoAddrBalance {..}, BinfoXPubBalance {..}]

instance Arbitrary BinfoWallet where
    arbitrary = do
        getBinfoWalletBalance <- arbitrary
        getBinfoWalletTxCount <- arbitrary
        getBinfoWalletFilteredCount <- arbitrary
        getBinfoWalletTotalReceived <- arbitrary
        getBinfoWalletTotalSent <- arbitrary
        return BinfoWallet {..}

instance Arbitrary BinfoBlock where
    arbitrary = do
        getBinfoBlockHash <- arbitraryBlockHash
        getBinfoBlockVer <- arbitrary
        getBinfoPrevBlock <- arbitraryBlockHash
        getBinfoMerkleRoot <- getTxHash <$> arbitraryTxHash
        getBinfoBlockTime <- arbitrary
        getBinfoBlockBits <- arbitrary
        getBinfoNextBlock <- listOf arbitraryBlockHash
        getBinfoBlockTxCount <- arbitrary
        getBinfoBlockFee <- arbitrary
        getBinfoBlockNonce <- arbitrary
        getBinfoBlockSize <- arbitrary
        getBinfoBlockIndex <- arbitrary
        getBinfoBlockMain <- arbitrary
        getBinfoBlockHeight <- arbitrary
        getBinfoBlockWeight <- arbitrary
        getBinfoBlockTx <- resize 5 arbitrary
        return BinfoBlock{..}

instance Arbitrary BinfoTx where
    arbitrary = do
        getBinfoTxHash <- arbitraryTxHash
        getBinfoTxVer <- arbitrary
        getBinfoTxInputs <- resize 5 $ listOf1 arbitrary
        getBinfoTxOutputs <- resize 5 $ listOf1 arbitrary
        let getBinfoTxVinSz = fromIntegral (length getBinfoTxInputs)
            getBinfoTxVoutSz = fromIntegral (length getBinfoTxOutputs)
        getBinfoTxSize <- arbitrary
        getBinfoTxWeight <- arbitrary
        getBinfoTxFee <- arbitrary
        getBinfoTxRelayedBy <- cs <$> listOf arbitraryUnicodeChar
        getBinfoTxLockTime <- arbitrary
        getBinfoTxIndex <- arbitrary
        getBinfoTxDoubleSpend <- arbitrary
        getBinfoTxRBF <- arbitrary
        getBinfoTxTime <- arbitrary
        getBinfoTxBlockIndex <- arbitrary
        getBinfoTxBlockHeight <- arbitrary
        getBinfoTxResultBal <- arbitrary
        return BinfoTx {..}

instance Arbitrary BinfoTxInput where
    arbitrary = do
        getBinfoTxInputSeq <- arbitrary
        getBinfoTxInputWitness <- B.pack <$> listOf arbitrary
        getBinfoTxInputScript <- B.pack <$> listOf arbitrary
        getBinfoTxInputIndex <- arbitrary
        getBinfoTxInputPrevOut <- arbitrary
        return BinfoTxInput {..}

instance Arbitrary BinfoTxOutput where
    arbitrary = do
        getBinfoTxOutputType <- arbitrary
        getBinfoTxOutputSpent <- arbitrary
        getBinfoTxOutputValue <- arbitrary
        getBinfoTxOutputIndex <- arbitrary
        getBinfoTxOutputTxIndex <- arbitrary
        getBinfoTxOutputScript <- B.pack <$> listOf arbitrary
        getBinfoTxOutputSpenders <- arbitrary
        getBinfoTxOutputAddress <-
            oneof [return Nothing, Just <$> arbitraryAddress]
        getBinfoTxOutputXPub <- arbitrary
        return BinfoTxOutput {..}

instance Arbitrary BinfoSpender where
    arbitrary = do
        getBinfoSpenderTxIndex <- arbitrary
        getBinfoSpenderIndex <- arbitrary
        return BinfoSpender {..}

instance Arbitrary BinfoXPubPath where
    arbitrary = do
        getBinfoXPubPathKey <- snd <$> arbitraryXPubKey
        getBinfoXPubPathDeriv <- arbitrarySoftPath
        return BinfoXPubPath {..}

instance Arbitrary BinfoInfo where
    arbitrary = do
        getBinfoConnected <- arbitrary
        getBinfoConversion <- arbitrary
        getBinfoLocal <- arbitrary
        getBinfoBTC <- arbitrary
        getBinfoLatestBlock <- arbitrary
        return BinfoInfo {..}

instance Arbitrary BinfoBlockInfo where
    arbitrary = do
        getBinfoBlockInfoHash <- arbitraryBlockHash
        getBinfoBlockInfoHeight <- arbitrary
        getBinfoBlockInfoTime <- arbitrary
        getBinfoBlockInfoIndex <- arbitrary
        return BinfoBlockInfo {..}

instance Arbitrary BinfoSymbol where
    arbitrary = do
        getBinfoSymbolCode <- cs <$> listOf1 arbitraryUnicodeChar
        getBinfoSymbolString <- cs <$> listOf1 arbitraryUnicodeChar
        getBinfoSymbolName <- cs <$> listOf1 arbitraryUnicodeChar
        getBinfoSymbolConversion <- arbitrary
        getBinfoSymbolAfter <- arbitrary
        getBinfoSymbolLocal <- arbitrary
        return BinfoSymbol {..}

instance Arbitrary BinfoRate where
    arbitrary = BinfoRate <$> arbitrary <*> arbitrary <*> arbitrary

instance Arbitrary BinfoTicker where
    arbitrary = do
        binfoTicker15m <- arbitrary
        binfoTickerSell <- arbitrary
        binfoTickerBuy <- arbitrary
        binfoTickerLast <- arbitrary
        binfoTickerSymbol <- cs <$> listOf1 arbitraryUnicodeChar
        return BinfoTicker{..}

instance Arbitrary BinfoHistory where
    arbitrary = do
        binfoHistoryDate <- cs <$> listOf1 arbitraryUnicodeChar
        binfoHistoryTime <- cs <$> listOf1 arbitraryUnicodeChar
        binfoHistoryType <- cs <$> listOf1 arbitraryUnicodeChar
        binfoHistoryAmount <- arbitrary
        binfoHistoryValueThen <- arbitrary
        binfoHistoryValueNow <- arbitrary
        binfoHistoryExchangeRateThen <- arbitrary
        binfoHistoryTx <- arbitraryTxHash
        return BinfoHistory{..}

instance Arbitrary BinfoUnspent where
    arbitrary = do
        getBinfoUnspentHash <- arbitraryTxHash
        getBinfoUnspentOutputIndex <- arbitrary
        getBinfoUnspentScript <- B.pack <$> listOf arbitrary
        getBinfoUnspentValue <- arbitrary
        getBinfoUnspentConfirmations <- arbitrary
        getBinfoUnspentTxIndex <- arbitrary
        getBinfoUnspentXPub <- arbitrary
        return BinfoUnspent{..}

instance Arbitrary BinfoUnspents where
    arbitrary = BinfoUnspents <$> arbitrary

instance Arbitrary BinfoHeader where
    arbitrary =
        BinfoHeader
        <$> arbitraryBlockHash
        <*> arbitrary
        <*> arbitrary
        <*> arbitrary
        <*> arbitrary

instance Arbitrary BinfoMempool where
    arbitrary = BinfoMempool <$> arbitrary

instance Arbitrary BinfoBlocks where
    arbitrary = BinfoBlocks <$> arbitrary