git.iko.soy/typeable/attoparsec
on master help sign in
Add a test for gh-75
commit9e2211782be94f21f4eb8b996b4897cbb97143a6 authorBryan O'Sullivan <bos@serpentine.com> dateTue 26 Aug 2014, 17:23 (12 years ago) parent1780eaf
4 files changed+100−1
attoparsec.cabal+4−1 tests/QC.hs+2 tests/QC/Rechunked.hs+54 tests/QC/Simple.hs+40
attoparsec.cabal+4−1
@@ -84,6 +84,8 @@ test-suite tests
8484 QC.ByteString
8585 QC.Combinator
8686 QC.Common
87+ QC.Rechunked
88+ QC.Simple
8789 QC.Text
8890
8991 ghc-options:
@@ -101,7 +103,8 @@ test-suite tests
101103 scientific,
102104 test-framework >= 0.8.0.2,
103105 test-framework-quickcheck2 >= 0.3.0.3,
104− text
106+ text,
107+ vector
105108
106109benchmark benchmarks
107110 type: exitcode-stdio-1.0
tests/QC.hs+2
@@ -4,6 +4,7 @@ module Main (main) where
44import qualified QC.Buffer as Buffer
55import qualified QC.ByteString as ByteString
66import qualified QC.Combinator as Combinator
7+import qualified QC.Simple as Simple
78import qualified QC.Text as Text
89import Test.Framework (defaultMain, testGroup)
910
@@ -13,5 +14,6 @@ tests = [
1314 testGroup "bs" ByteString.tests
1415 , testGroup "buf" Buffer.tests
1516 , testGroup "combinator" Combinator.tests
17+ , testGroup "simple" Simple.tests
1618 , testGroup "text" Text.tests
1719 ]
tests/QC/Rechunked.hsnew file+54
@@ -0,0 +1,54 @@
1+{-# LANGUAGE BangPatterns #-}
2+
3+module QC.Rechunked (
4+ rechunkBS
5+ , rechunkT
6+ ) where
7+
8+import Control.Monad (forM, forM_)
9+import Control.Monad.ST (runST)
10+import Data.List (unfoldr)
11+import Test.QuickCheck (Gen, choose)
12+import qualified Data.ByteString as B
13+import qualified Data.Text as T
14+import qualified Data.Vector as V
15+import qualified Data.Vector.Generic as G
16+import qualified Data.Vector.Generic.Mutable as M
17+
18+rechunkBS :: B.ByteString -> Gen [B.ByteString]
19+rechunkBS = fmap (map B.copy) . rechunk_ B.splitAt B.length
20+
21+rechunkT :: T.Text -> Gen [T.Text]
22+rechunkT = fmap (map T.copy) . rechunk_ T.splitAt T.length
23+
24+rechunk_ :: (Int -> a -> (a,a)) -> (a -> Int) -> a -> Gen [a]
25+rechunk_ split len xs = (unfoldr go . (,) xs) `fmap` rechunkSizes (len xs)
26+ where go (b,r:rs) = Just (h, (t,rs))
27+ where (h,t) = split r b
28+ go (_,_) = Nothing
29+
30+rechunkSizes :: Int -> Gen [Int]
31+rechunkSizes n0 = shuffle =<< loop [] (0:repeat 1) n0
32+ where loop acc (lb:lbs) n
33+ | n <= 0 = shuffle (reverse acc)
34+ | otherwise = do
35+ !i <- choose (lb,n)
36+ loop (i:acc) lbs (n-i)
37+
38+shuffle :: [Int] -> Gen [Int]
39+shuffle (0:xs) = (0:) `fmap` shuffle xs
40+shuffle xs = fisherYates xs
41+
42+fisherYates :: [a] -> Gen [a]
43+fisherYates xs = (V.toList . V.backpermute v) `fmap` swapIndices (G.length v)
44+ where
45+ v = V.fromList xs
46+ swapIndices n0 = do
47+ swaps <- forM [0..n] $ \i -> ((,) i) `fmap` choose (i,n)
48+ return (runST (swapAll swaps))
49+ where
50+ n = n0 - 1
51+ swapAll ijs = do
52+ mv <- G.unsafeThaw (G.enumFromTo 0 n :: V.Vector Int)
53+ forM_ ijs $ uncurry (M.swap mv)
54+ G.unsafeFreeze mv
tests/QC/Simple.hsnew file+40
@@ -0,0 +1,40 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
3+
4+module QC.Simple (
5+ tests
6+ ) where
7+
8+import Control.Applicative ((<|>))
9+import Data.ByteString (ByteString)
10+import Data.List
11+import Data.Maybe
12+import QC.Rechunked
13+import Test.Framework (Test)
14+import Test.Framework.Providers.QuickCheck2 (testProperty)
15+import Test.QuickCheck
16+import qualified Data.Attoparsec.ByteString.Char8 as A
17+
18+data Expect a b = Expect a b
19+ deriving (Show)
20+
21+t_issue75 = expect issue75 "ab" (A.Done "" "b")
22+
23+issue75 :: A.Parser ByteString
24+issue75 = "a" >> ("b" <|> "")
25+
26+expect :: (Show r, Eq r) => A.Parser r -> ByteString -> A.Result r -> Property
27+expect p input wanted =
28+ forAll (rechunkBS input) $ \in' ->
29+ let result = parse p in'
30+ in counterexample (show result ++ " /= " ++ show wanted) $
31+ fromMaybe False (A.compareResults result wanted)
32+
33+parse :: A.Parser r -> [ByteString] -> A.Result r
34+parse p (x:xs) = foldl' A.feed (A.parse p x) xs
35+parse p [] = A.parse p ""
36+
37+tests :: [Test]
38+tests = [
39+ testProperty "issue75" t_issue75
40+ ]