packages feed

kademlia-1.1.0.0: test/TestTypes.hs

{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}

{-|
Module      : TestTypes
Description : Types and Generators needed for general testing
-}

module TestTypes where

import Test.QuickCheck

import Control.Monad (liftM, liftM2, liftM3)
import Control.Arrow (first)
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as C
import Network.Socket (PortNumber)
import Data.Word(Word16)
import Data.List (nubBy)
import Data.Function (on)

import Network.Kademlia.Types

newtype IdType = IT { getBS :: B.ByteString } deriving (Eq, Ord)

-- Custom show instance
instance Show IdType where
    show = show . C.unpack . getBS

-- A simple 5-byte ByteString
instance Serialize IdType where
    toBS = getBS
    fromBS bs = if B.length bs >= 5
        then Right $ first IT . B.splitAt 5 $ bs
        else Left "ByteString to short."

instance Serialize String where
    toBS = C.pack . show
    fromBS s =
        case (reads :: ReadS String) . C.unpack $ s of
            []               -> Left "Failed to parse string."
            (result, rest):_ -> Right (result, C.pack rest)

instance Arbitrary IdType where
    arbitrary = do
        str <- vectorOf 5 arbitrary
        return $ IT $ C.pack str

instance Arbitrary PortNumber where
    arbitrary = liftM fromIntegral (arbitrary :: Gen Word16)

instance Arbitrary Peer where
    arbitrary = do
        host <- arbitrary `suchThat` \s -> ' ' `notElem` s && not (null s)
                                           && length s < 20
        port <- arbitrary
        return $ Peer host port

instance (Arbitrary i, Arbitrary v) => Arbitrary (Command i v) where
    arbitrary = oneof [
          return PING
        , return PONG
        , liftM2 STORE arbitrary arbitrary
        , liftM FIND_NODE arbitrary
        , liftM2 RETURN_NODES arbitrary $ vectorOf 15 arbitrary
        , liftM FIND_VALUE arbitrary
        , liftM2 RETURN_VALUE arbitrary arbitrary
        ]

instance (Arbitrary i, Arbitrary v) => Arbitrary (Signal i v) where
    arbitrary = liftM2 Signal arbitrary arbitrary

instance (Arbitrary i) => Arbitrary (Node i) where
    arbitrary = liftM2 Node arbitrary arbitrary

-- | This enables me to specifiy a new Arbitrary instance
newtype NodeBunch i = NB {
      nodes :: [Node i]
    } deriving (Show)

-- | Make sure all Ids are unique
instance (Arbitrary i, Eq i) => Arbitrary (NodeBunch i) where
    arbitrary = liftM NB $ vectorOf 20 arbitrary `suchThat` individualIds
        where individualIds = individual ((==) `on` nodeId)

individual :: (a -> a -> Bool) -> [a] -> Bool
individual eq s = length s == (length . clear $ s)
    where clear = nubBy eq

-- | This is needed for the Implementation tests
newtype IdBunch i = IB {
      getIds :: [i]
    } deriving (Show)

instance (Arbitrary i, Eq i) => Arbitrary (IdBunch i) where
    arbitrary = liftM IB $ vectorOf 20 arbitrary `suchThat` individual (==)