packages feed

haskoin-store-data-0.65.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
      <*> 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