packages feed

hans-3.0.2: tests/Tests/IP4/Packet.hs

{-# LANGUAGE RecordWildCards #-}

module Tests.IP4.Packet where

import Tests.Ethernet (arbitraryMac)
import Tests.Network (arbitraryProtocol)
import Tests.Utils (encodeDecodeIdentity,showReadIdentity)

import Hans.IP4.Packet
import Hans.Lens

import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString.Short as Sh
import           Data.Word (Word8)
import           Test.QuickCheck
import           Test.Tasty (testGroup,TestTree)
import           Test.Tasty.QuickCheck (testProperty)


-- Packet Generator Support ----------------------------------------------------

arbitraryIP4 :: Gen IP4
arbitraryIP4  =
  do a <- arbitraryBoundedRandom
     b <- arbitraryBoundedRandom
     c <- arbitraryBoundedRandom
     d <- arbitraryBoundedRandom
     return $! packIP4 a b c d


arbitraryIP4Mask :: Gen IP4Mask
arbitraryIP4Mask  =
  do addr <- arbitraryIP4
     bits <- choose (0,32)
     return (IP4Mask addr bits)


arbitraryIdent :: Gen IP4Ident
arbitraryIdent  = arbitraryBoundedRandom


arbitraryPayload :: Int -> Gen L.ByteString
arbitraryPayload len =
  do bytes <- vectorOf len arbitraryBoundedRandom
     return (L.pack bytes)

arbitraryOptionPayload :: Word8 -> Gen Sh.ShortByteString
arbitraryOptionPayload len =
  do bytes <- vectorOf (fromIntegral len) arbitraryBoundedRandom
     return (Sh.pack bytes)


arbitraryIP4Header :: Gen IP4Header
arbitraryIP4Header  =
  do ip4TypeOfService <- arbitraryBoundedRandom
     ip4Ident         <- arbitraryIdent
     ip4TimeToLive    <- arbitraryBoundedRandom
     ip4Protocol      <- arbitraryProtocol
     ip4SourceAddr    <- arbitraryIP4
     ip4DestAddr      <- arbitraryIP4

     -- checksum processing is validated by a different property
     let ip4Checksum = 0

     -- XXX need to generate options that fit within the additional 40 bytes
     -- available
     let ip4Options = []

     -- set the members of the ip4Fragment_ field on the final header
     df  <- arbitraryBoundedRandom
     mf  <- arbitraryBoundedRandom
     off <- choose (0,0x1fff)
     let hdr = IP4Header { ip4Fragment_ = 0, .. }

     return $! set ip4DontFragment df
            $! set ip4MoreFragments mf
            $! set ip4FragmentOffset off hdr


arbitraryIP4Option :: Gen IP4Option
arbitraryIP4Option  =
  do ip4OptionCopied  <- arbitraryBoundedRandom
     ip4OptionClass   <- choose (0,0x3)
     ip4OptionNum     <- choose (0,0x1f)

     ip4OptionData <-
       if ip4OptionNum < 2
          then return Sh.empty
          else do len <- choose (0, 0xff - 2)
                  arbitraryOptionPayload len

     return IP4Option { .. }


arbitraryArpPacket :: Gen ArpPacket
arbitraryArpPacket  =
  do arpOper <- elements [ArpRequest,ArpReply]
     arpSHA  <- arbitraryMac
     arpSPA  <- arbitraryIP4
     arpTHA  <- arbitraryMac
     arpTPA  <- arbitraryIP4
     return ArpPacket { .. }


-- Packet Properties -----------------------------------------------------------

packetTests :: TestTree
packetTests  = testGroup "Packet"
  [ testProperty "IP4 Address encode/decode" $
    encodeDecodeIdentity putIP4 getIP4 arbitraryIP4

  , let get =
          do (hdr,20,0) <- getIP4Packet
             return hdr

        put hdr =
             putIP4Header hdr 0

     in testProperty "Header encode/decode" $
        encodeDecodeIdentity put get arbitraryIP4Header

  , testProperty "Option encode/decode" $
    encodeDecodeIdentity putIP4Option getIP4Option arbitraryIP4Option

  , testProperty "Arp Message encode/decode" $
    encodeDecodeIdentity putArpPacket getArpPacket arbitraryArpPacket

  , testProperty "IP4 Addr read/show" $
    showReadIdentity showIP4 readIP4 arbitraryIP4

  , testProperty "IP4 Mask read/show" $
    showReadIdentity showIP4Mask readIP4Mask arbitraryIP4Mask
  ]