content: module Tests.IP4.Fragmentation where
  
  import Tests.IP4.Packet
  import Tests.Network
  
  import Hans.Config
  import Hans.IP4.Fragments
  import Hans.IP4.Packet
  import Hans.Monad (runHansOnce)
  
  import qualified Data.ByteString.Lazy as L
  import           Data.Maybe (catMaybes)
  import           Test.Tasty
  import           Test.Tasty.QuickCheck (testProperty)
  import           Test.QuickCheck
  import           Test.QuickCheck.Monadic
  
  
  fragTests :: TestTree
  fragTests  = testGroup "Fragmentation"
    [ testProperty "Reassembly" propReassemble
    ]
  
  
  propReassemble :: Property
  propReassemble  = monadicIO $
    do src   <- pick arbitraryIP4
       dst   <- pick arbitraryIP4
       prot  <- pick arbitraryProtocol
       ident <- pick arbitraryIdent
  
       len   <- pick (choose (100,1500))
  
       -- path mtu must be at least 68 (28 for header, and 40 for options)
       mtu   <- pick (choose (68,len))
       bytes <- pick (arbitraryPayload len)
  
       let hdr = emptyIP4Header { ip4DestAddr   = dst
                                , ip4SourceAddr = src
                                , ip4Protocol   = prot
                                , ip4Ident      = ident
                                }
  
           chunks = [(h,L.toStrict body) | (h,body) <- splitPacket mtu hdr bytes]
  
       incoming <- pick (shuffle chunks)
       table    <- run (newFragTable defaultConfig)
  
       results <- run $ sequence [ runHansOnce (processFragment table fhdr body)
                                 | (fhdr,body) <- incoming ]
  
       run (cleanupFragTable table)
  
       -- we should only get a single successful result here, otherwise something
       -- is wrong with the way that fragments are being collected
       case catMaybes results of
         [(_,result)] -> return (L.fromStrict result == bytes)
         _            -> return False
  