packages feed

rws-0.1.1.2: src/Ppp.hs

{-# LANGUAGE CPP #-}
module Ppp where

import Data.Binary.Put
import qualified Data.ByteString.Lazy as B
import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Perm

import Util
import Packet
import Lexer

#ifdef HRWS_TEST
import Debug.Trace
import Test.QuickCheck hiding ((.&.))
import Test.Framework (Test)
import Test.Framework.Providers.QuickCheck2 (testProperty)
import Text.Printf
#endif

parsePppPkt :: Parser Packet -> Parser PppPkt
parsePppPkt f = permute
  (tuple <$?> (0xff, parseIntAttribute "address")
         <|?> (0x03, parseIntAttribute "control")
         <|?> (0x0021, parseIntAttribute "protocol")
         <|?> ([PPayload defaultPayload], parsePayload f))
  where
    tuple a c prot = PppPkt (Ppp a c prot)


pppDecl :: Parser Packet -> Parser Packet
pppDecl f = do
  symbol "ppp"
  g <- parsePppPkt f
  return (PPpp g)

pppWriteHdr :: Ppp -> Put
pppWriteHdr p = do
    putWord8 (pppAddress p)
    putWord8 (pppControl p)
    putWord16be (pppProtocol p)

pppWrite :: Ppp -> Maybe Packet -> B.ByteString -> Put
pppWrite h _ bs = do
    pppWriteHdr h
    putLazyByteString bs

instance PacketWriteable PppPkt where packetWrite p = pppWrite (pppPktHeader p)


#ifdef HRWS_TEST
{- Unit Tests -}

instance Arbitrary Ppp where
  arbitrary = do
    a <- arbitrary
    c <- arbitrary
    p <- arbitrary
    return (Ppp a c p)

testValidParse :: String -> (Ppp -> Bool) -> Bool
testValidParse str fn =
  case parse (dummyParsePacket pppDecl) "packet parse" str of
       Left  err -> trace (show err) False
       Right val -> fn $ testPppPkt val

testPppDefault :: () -> Bool
testPppDefault _ = let cmp f = defaultPpp == f in
  testValidParse "(ppp)" cmp

testPppPkt :: Packet -> Ppp
testPppPkt (PPpp f) = pppPktHeader f
testPppPkt _ = error "Unexpected packet type"

testPppPacket :: Ppp -> Bool
testPppPacket pkt =
  let cmp p = pkt == p in
  testValidParse (printf "(ppp address=%d control=%d protocol=%d)" (pppAddress pkt)
                  (pppControl pkt) (pppProtocol pkt)) cmp

testPppWrite :: () -> Bool
testPppWrite _ =
  let expPkt = B.pack [0xff, 0x03, 0xca, 0xfe] in
  let cmp p = runPut (pppWrite p Nothing B.empty) == expPkt in
  testValidParse "(ppp address=0xff protocol=0xcafe)" cmp

pppTests :: [Test]
pppTests = [
  testProperty "PPP: Default Packet" testPppDefault,
  testProperty "PPP: Packet" testPppPacket,
  testProperty "PPP: Write" testPppWrite
  ]
#endif