packages feed

picoparsec-0.1.2: tests/QC/Combinator.hs

{-# LANGUAGE OverloadedStrings #-}

module QC.Combinator where

import Control.Applicative ((<$>), (<*>))
import Data.List (isPrefixOf)
import Data.Maybe (fromJust, isJust)
import Data.Monoid (mempty)
import Data.Word (Word8)
import QC.Common (Repack, parse, repackBS, toStrictBS)
import Test.Tasty (TestTree)
import Test.Tasty.QuickCheck (testProperty)
import Test.QuickCheck
import qualified Data.Picoparsec as P
import qualified Data.Picoparsec.Combinator as C
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Char8 as B8

choice :: NonEmptyList (NonEmptyList Word8) -> Gen Property
choice (NonEmpty xs) = do
  let ys = map (BL.pack . getNonEmpty) xs
  return . forAll (repackBS <$> arbitrary <*> (toStrictBS <$> elements ys)) $
    maybe False (`elem` ys) . P.maybeResult . flip P.feed mempty . P.parse (C.choice (map P.string ys))

count :: Positive (Small Int) -> Repack -> B8.ByteString -> Bool
count (Positive (Small n)) rs s =
    (length <$> parse (C.count n (P.string s)) (BL.toStrict input)) == Just n
  where input = repackBS rs (B8.concat (replicate (n+1) s))

lookAhead :: NonEmptyList Word8 -> Bool
lookAhead (NonEmpty xs) =
  let ys = B.pack xs
      withLookAheadThenConsume = (,) <$> C.lookAhead (P.string ys) <*> P.string ys
      mr = parse withLookAheadThenConsume ys
  in isJust mr && fst (fromJust mr) == snd (fromJust mr)

notFollowedBy :: NonEmptyList Word8 -> NonEmptyList Word8 -> Bool
notFollowedBy (NonEmpty xs) (NonEmpty ys) =
  let xs' = B.pack xs
      ys' = B.pack ys
      withNotFollowedByThenConsume = (,) <$> C.notFollowedBy (P.string xs') <*> P.string ys'
      mr = parse withNotFollowedByThenConsume ys'
  in mr == if xs `isPrefixOf` ys || ys `isPrefixOf` xs
           then Nothing
           else Just ((), ys')

{-
match :: Int -> NonNegative Int -> NonNegative Int -> Repack -> Bool
match n (NonNegative x) (NonNegative y) rs =
    parse (P.match parser) (repackBS rs input) == Just (input, n)
  where parser = P.skipWhile (=='x') *> P.signed P.decimal <*
                 P.skipWhile (=='y')
        input = B8.concat [
            B8.replicate x 'x', B8.pack (show n), B8.replicate y 'y'
          ]
-}

tests :: [TestTree]
tests = [
    testProperty "choice" choice
  , testProperty "count" count
--  , testProperty "match" match
  , testProperty "lookAhead" lookAhead
  , testProperty "notFollowedBy" notFollowedBy
  ]