packages feed

hstox-0.0.1: src/testsuite/Network/Tox/DHT/DhtStateSpec.hs

{-# LANGUAGE Trustworthy #-}
module Network.Tox.DHT.DhtStateSpec where

import           Test.Hspec
import           Test.QuickCheck

import           Control.Monad                 (unless)
import           Data.Proxy                    (Proxy (..))

import qualified Network.Tox.Crypto.KeyPair    as KeyPair
import           Network.Tox.DHT.DhtState      (DhtState)
import qualified Network.Tox.DHT.DhtState      as DhtState
import           Network.Tox.EncodingSpec
import qualified Network.Tox.NodeInfo.NodeInfo as NodeInfo


spec :: Spec
spec = do
  readShowSpec (Proxy :: Proxy DhtState)

  it "the state can never contain itself" $
    property $ \keyPair nodeInfo ->
      let
        dhtState = DhtState.empty keyPair
        afterAdd = DhtState.addNode
          nodeInfo { NodeInfo.publicKey = KeyPair.publicKey keyPair }
          dhtState
      in
      afterAdd `shouldBe` dhtState

  describe "adding a node that was not yet contained" $ do
    it "should result in a different state" $
      property $ \keyPair nodeInfo ->
        let
          dhtState = DhtState.empty keyPair
          afterAdd = DhtState.addNode nodeInfo dhtState
        in
        unless (DhtState.containsNode (NodeInfo.publicKey nodeInfo) dhtState) $
          afterAdd `shouldNotBe` dhtState

    it "and removing it yields the same state" $
      property $ \keyPair nodeInfo ->
        let
          dhtState    = DhtState.empty keyPair
          afterAdd    = DhtState.addNode nodeInfo dhtState
          afterRemove = DhtState.removeNode (NodeInfo.publicKey nodeInfo) afterAdd
        in
        unless (DhtState.containsNode (NodeInfo.publicKey nodeInfo) dhtState) $
          afterRemove `shouldBe` dhtState

  describe "adding a node" $
    it "and adding it again does not change the state twice" $
      property $ \keyPair nodeInfo ->
        let
          dhtState  = DhtState.empty keyPair
          afterAdd1 = DhtState.addNode nodeInfo dhtState
          afterAdd2 = DhtState.addNode nodeInfo afterAdd1
        in
        afterAdd1 `shouldBe` afterAdd2

  describe "adding a search node" $ do
    it "should result in a different state" $
      property $ \keyPair publicKey ->
        let
          dhtState = DhtState.empty keyPair
          afterAdd = DhtState.addSearchKey publicKey dhtState
        in
        afterAdd `shouldNotBe` dhtState

    it "and removing it yields the same state" $
      property $ \keyPair publicKey ->
        let
          dhtState    = DhtState.empty keyPair
          afterAdd    = DhtState.addSearchKey publicKey dhtState
          afterRemove = DhtState.removeSearchKey publicKey afterAdd
        in
        afterRemove `shouldBe` dhtState

    it "and adding it again does not change the state twice" $
      property $ \keyPair publicKey ->
        let
          dhtState  = DhtState.empty keyPair
          afterAdd1 = DhtState.addSearchKey publicKey dhtState
          afterAdd2 = DhtState.addSearchKey publicKey afterAdd1
        in
        afterAdd1 `shouldBe` afterAdd2

    it "and adding a node info for it will not add it to the search entry's k-buckets" $
      property $ \keyPair nodeInfo ->
        let
          dhtState = DhtState.empty keyPair
          afterAddSearchKey = DhtState.addSearchKey
            (NodeInfo.publicKey nodeInfo)
            dhtState
        in
        DhtState.size (DhtState.addNode nodeInfo afterAddSearchKey)
        `shouldBe`
        DhtState.size (DhtState.addNode nodeInfo dhtState)