1module Main (main) where
3import Control.Exception (SomeException(..))
4import Data.Word (Word8, Word32, Word64)
5import Streamly.Test.Common (listEquals, checkListEqual, chooseInt)
6import Test.Hspec (Spec, hspec, describe)
7import Test.Hspec.QuickCheck
9 (arbitrary, forAll, elements, Property,
10 property, listOf, vectorOf, (.&&.), Gen)
11import Test.QuickCheck.Monadic (monadicIO, assert, run)
13import qualified Data.List as List
14import qualified Prelude
15import qualified Streamly.Internal.Data.Array.Foreign as A
16import qualified Streamly.Internal.Data.Fold as FL
17import qualified Streamly.Internal.Data.Parser.ParserD as P
18import qualified Streamly.Internal.Data.Producer.Source as Source
19import qualified Streamly.Internal.Data.Producer as Producer
20import qualified Streamly.Internal.Data.Stream.IsStream as S
21import qualified Streamly.Internal.Data.Unfold as Unfold
22import qualified Test.Hspec as H
24import Prelude hiding (sequence)
26#if MIN_VERSION_QuickCheck(2,14,0)
28import Test.QuickCheck (chooseAny)
32import System.Random (Random(random))
33import Test.QuickCheck.Gen (Gen(MkGen))
35-- | Generates a random element over the natural range of `a`.
36chooseAny :: Random a => Gen a
37chooseAny = MkGen (\r _ -> let (x,_) = random r in x)
60 forAll (listOf $ chooseInt (min_value, max_value))
62 case (==) <$> (S.parseD (P.fromFold FL.sum) (S.fromList ls))
63 <*> (S.fold FL.sum (S.fromList ls)) of
64 Right is_equal -> is_equal
69 forAll (chooseInt (min_value, max_value)) $ \x ->
70 case S.parseD (P.fromPure x) (S.fromList [1 :: Int]) of
76 forAll (chooseInt (min_value, max_value)) $ \x ->
77 case S.parseD (P.fromEffect $ return x) (S.fromList [1 :: Int]) of
84 case S.parseD (P.die "die test") (S.fromList [0 :: Int]) of
91 case S.parseD (P.dieM (Right "die test")) (S.fromList [0 :: Int]) of
95-- Element Parser Tests
99 forAll (chooseInt (1, max_length)) $ \list_length ->
100 forAll (vectorOf list_length (chooseInt (min_value, max_value))) $ \ls ->
101 case S.parseD P.peek (S.fromList ls) of
102 Right head_value -> case ls of
103 head_ls : _ -> head_value == head_ls
109 property (case S.parseD P.peek (S.fromList []) of
115 property (case S.parseD P.eof (S.fromList []) of
121 forAll (chooseInt (1, max_length)) $ \list_length ->
122 forAll (vectorOf list_length (chooseInt (min_value, max_value))) $ \ls ->
123 case S.parseD P.eof (S.fromList ls) of
127satisfyPass :: Property
129 forAll (chooseInt (mid_value, max_value)) $ \first_element ->
130 forAll (listOf (chooseInt (min_value, max_value))) $ \ls_tail ->
132 ls = first_element : ls_tail
133 predicate = (>= mid_value)
135 case S.parseD (P.satisfy predicate) (S.fromList ls) of
136 Right r -> r == first_element
141 forAll (listOf (chooseInt (min_value, max_value))) $ \ls ->
142 case S.parseD (P.satisfy predicate) (S.fromList ls) of
143 Right r -> case ls of
145 (x : _) -> predicate x && (r == x)
148 (x : _) -> not $ predicate x
150 predicate = (>= mid_value)
152-- Sequence Parsers Tests
153takeBetweenPass :: Property
155 forAll (chooseInt (min_value, max_value)) $ \m ->
156 forAll (chooseInt (m, max_value)) $ \n ->
157 forAll (chooseInt (m, max_value)) $ \list_length ->
158 forAll (vectorOf list_length (chooseInt (min_value, max_value))) $ \ls ->
159 case S.parseD (P.takeBetween m n FL.toList) (S.fromList ls) of
161 let lpl = Prelude.length parsed_list
162 in checkListEqual parsed_list (Prelude.take lpl ls)
163 Left _ -> property False
166takeBetween :: Property
168 forAll (chooseInt (min_value, max_value)) $ \m ->
169 forAll (chooseInt (min_value, max_value)) $ \n ->
170 forAll (listOf (chooseInt (min_value, max_value))) $ \ls ->
172 list_length = Prelude.length ls
174 case S.parseD (P.takeBetween m n FL.toList) (S.fromList ls) of
176 if m <= list_length && n >= list_length
178 let lpl = Prelude.length parsed_list
179 in checkListEqual parsed_list (Prelude.take
182 Left _ -> property (m > n || list_length < m)
186 forAll (chooseInt (min_value, max_value)) $ \n ->
187 forAll (listOf (chooseInt (min_value, max_value))) $ \ls ->
188 case S.parseD (P.fromFold $ FL.take n FL.toList) (S.fromList ls) of
189 Right parsed_list -> checkListEqual parsed_list (Prelude.take n ls)
190 Left _ -> property False
192takeEQPass :: Property
194 forAll (chooseInt (min_value, max_value)) $ \n ->
195 forAll (chooseInt (n, max_value)) $ \list_length ->
196 forAll (vectorOf list_length (chooseInt (min_value, max_value))) $ \ls ->
197 case S.parseD (P.takeEQ n FL.toList) (S.fromList ls) of
198 Right parsed_list -> checkListEqual parsed_list (Prelude.take n ls)
199 Left _ -> property False
203 forAll (chooseInt (min_value, max_value)) $ \n ->
204 forAll (listOf (chooseInt (min_value, max_value))) $ \ls ->
206 list_length = Prelude.length ls
208 case S.parseD (P.takeEQ n FL.toList) (S.fromList ls) of
210 if (n <= list_length) then
211 checkListEqual parsed_list (Prelude.take n ls)
214 Left _ -> property (n > list_length)
216takeGEPass :: Property
218 forAll (chooseInt (min_value, max_value)) $ \n ->
219 forAll (chooseInt (n, max_value)) $ \list_length ->
220 forAll (vectorOf list_length (chooseInt (min_value, max_value))) $ \ls ->
221 case S.parseD (P.takeGE n FL.toList) (S.fromList ls) of
222 Right parsed_list -> checkListEqual parsed_list ls
223 Left _ -> property False
227 forAll (chooseInt (min_value, max_value)) $ \n ->
228 forAll (listOf (chooseInt (min_value, max_value))) $ \ls ->
230 list_length = Prelude.length ls
232 case S.parseD (P.takeGE n FL.toList) (S.fromList ls) of
234 if (n <= list_length) then
235 checkListEqual parsed_list ls
238 Left _ -> property (n > list_length)
242 -> FL.Fold (Either SomeException) Int [Int]
243 -> P.Parser (Either SomeException) Int [Int]
245 -> (Int -> [Int] -> [Int])
247nLessThanEqual0 tk ltk =
248 forAll (elements [0, (-1)]) $ \n ->
249 forAll (listOf arbitrary) $ \ls ->
250 case S.parseD (tk n FL.toList) (S.fromList ls) of
251 Right parsed_list -> checkListEqual parsed_list (ltk n ls)
252 Left _ -> property False
254takeProperties :: Spec
256 describe "take combinators when n <= 0/" $ do
257 prop "takeEQ n FL.toList = []" $
258 nLessThanEqual0 P.takeEQ (\_ -> const [])
259 prop "takeGE n FL.toList xs = xs" $
260 nLessThanEqual0 P.takeGE (\_ -> id)
263-- XXX lookAhead can't deal with EOF which in this case means when
264-- n==list_length, this test will fail. So excluding that case for now.
265lookAheadPass :: Property
267 forAll (chooseInt (min_value, max_value)) $ \n ->
269 takeWithoutConsume = P.lookAhead $ P.fromFold $ FL.take n FL.toList
271 parsed_list_1 <- takeWithoutConsume
272 parsed_list_2 <- takeWithoutConsume
273 return (parsed_list_1, parsed_list_2)
275 forAll (chooseInt (n+1, max_value)) $ \list_length ->
276 forAll (vectorOf list_length (chooseInt (min_value, max_value))) $ \ls ->
277 case S.parseD parseTwice (S.fromList ls) of
278 Right (ls_1, ls_2) -> checkListEqual ls_1 ls_2 .&&. checkListEqual ls_1 (Prelude.take n ls)
279 Left _ -> property $ False
283 forAll (chooseInt (min_value, max_value)) $ \n ->
285 takeWithoutConsume = P.lookAhead $ P.fromFold $ FL.take n FL.toList
287 parsed_list_1 <- takeWithoutConsume
288 parsed_list_2 <- takeWithoutConsume
289 return (parsed_list_1, parsed_list_2)
291 forAll (listOf (chooseInt (min_value, max_value))) $ \ls ->
292 case S.parseD parseTwice (S.fromList ls) of
293 Right (ls_1, ls_2) -> checkListEqual ls_1 ls_2 .&&. checkListEqual ls_1 (Prelude.take n ls)
294 Left _ -> property ((list_length < n) || (list_length == n && n == 0))
296 list_length = Prelude.length ls
300 forAll (listOf (chooseInt (0, 1))) $ \ ls ->
301 case S.parseD (P.takeWhile predicate FL.toList) (S.fromList ls) of
302 Right parsed_list -> checkListEqual parsed_list (Prelude.takeWhile predicate ls)
303 Left _ -> property False
307takeWhile1 :: Property
309 forAll (listOf (chooseInt (0, 1))) $ \ ls ->
310 case S.parseD (P.takeWhile1 predicate FL.toList) (S.fromList ls) of
311 Right parsed_list -> case ls of
315 checkListEqual parsed_list (Prelude.takeWhile predicate ls)
320 (x : _) -> property (not $ predicate x)
326 forAll (listOf (chooseInt (0, 1)))
328 case S.parseD parser (S.fromList ls) of
329 Right parsed -> checkListEqual parsed (groupByLF ls)
330 Left _ -> property False
335 parser = P.groupBy cmp FL.toList
338 | otherwise = head $ List.groupBy cmp lst
340groupByRolling :: Property
342 forAll (listOf (chooseInt (0, 1)))
344 case S.parseD parser (S.fromList ls) of
345 Right parsed -> checkListEqual parsed (groupByLF Nothing ls)
346 Left _ -> property False
351 parser = P.groupBy cmp FL.toList
353 groupByLF Nothing (x:xs) = x : groupByLF (Just x) xs
354 groupByLF (Just y) (x:xs) =
356 then x : groupByLF (Just x) xs
359takeEndByOrMax :: Property
361 forAll (chooseInt (min_value, max_value)) $ \n ->
362 forAll (listOf (chooseInt (0, 1))) $ \ls ->
363 case S.parseD (P.fromFold $ FL.takeEndBy_ predicate (FL.take n FL.toList)) (S.fromList ls) of
364 Right parsed_list -> checkListEqual parsed_list (Prelude.take n (Prelude.takeWhile (not . predicate) ls))
365 Left _ -> property False
371 forAll (listOf (elements [' ', 's']))
373 case S.parseD parser (S.fromList ls) of
374 Right parsed -> checkListEqual parsed (words' ls)
375 Left _ -> property False
380 parser = P.many (P.wordBy predicate FL.toList) FL.toList
383 in if wrds == [] && length lst > 0 then [""] else wrds
386serialWith :: Property
388 forAll (listOf (chooseInt (0, 1))) $ \ls ->
389 case S.parseD (P.serialWith (,) (P.satisfy (== 0)) (P.satisfy (== 1))) (S.fromList ls) of
390 Right (result_first, result_second) -> case ls of
391 0 : 1 : _ -> (result_first == 0) && (result_second == 1)
397splitWithFailLeft :: Property
399 property (case S.parseD (P.serialWith (,) (P.die "die") (P.fromPure (1 :: Int))) (S.fromList [1 :: Int]) of
403splitWithFailRight :: Property
405 property (case S.parseD (P.serialWith (,) (P.fromPure (1 :: Int)) (P.die "die")) (S.fromList [1 :: Int]) of
409splitWithFailBoth :: Property
411 property (case S.parseD (P.serialWith (,) (P.die "die") (P.die "die")) (S.fromList [1 :: Int]) of
415teeWithPass :: Property
417 forAll (chooseInt (min_value, max_value)) $ \n ->
418 forAll (listOf (chooseInt (0, 1))) $ \ls ->
420 prsr = P.fromFold $ FL.take n FL.toList
422 case S.parseD (P.teeWith (,) prsr prsr) (S.fromList ls) of
423 Right (ls_1, ls_2) -> checkListEqual (Prelude.take n ls) ls_1 .&&. checkListEqual ls_1 ls_2
424 Left _ -> property False
426teeWithFailLeft :: Property
428 property (case S.parseD (P.teeWith (,) (P.die "die") (P.fromPure (1 :: Int))) (S.fromList [1 :: Int]) of
432teeWithFailRight :: Property
434 property (case S.parseD (P.teeWith (,) (P.fromPure (1 :: Int)) (P.die "die")) (S.fromList [1 :: Int]) of
438teeWithFailBoth :: Property
440 property (case S.parseD (P.teeWith (,) (P.die "die") (P.die "die")) (S.fromList [1 :: Int]) of
444shortestPass :: Property
446 forAll (listOf (chooseInt(min_value, max_value))) $ \ls ->
448 half_mid_value = mid_value `Prelude.div` 2
449 prsr_1 = P.takeWhile (<= half_mid_value) FL.toList
450 prsr_2 = P.takeWhile (<= mid_value) FL.toList
451 prsr_shortest = P.shortest prsr_1 prsr_2
453 case S.parseD prsr_shortest (S.fromList ls) of
454 Right short_list -> checkListEqual short_list (Prelude.takeWhile (<= half_mid_value) ls)
455 Left _ -> property False
457shortestPassLeft :: Property
459 property (case S.parseD (P.shortest (P.die "die") (P.fromPure (1 :: Int))) (S.fromList [1 :: Int]) of
463shortestPassRight :: Property
465 property (case S.parseD (P.shortest (P.fromPure (1 :: Int)) (P.die "die")) (S.fromList [1 :: Int]) of
469shortestFailBoth :: Property
473 (P.shortest (P.die "die") (P.die "die"))
474 (S.fromList [1 :: Int]) of
478longestPass :: Property
480 forAll (listOf (chooseInt(min_value, max_value))) $ \ls ->
482 half_mid_value = mid_value `Prelude.div` 2
483 prsr_1 = P.takeWhile (<= half_mid_value) FL.toList
484 prsr_2 = P.takeWhile (<= mid_value) FL.toList
485 prsr_longest = P.longest prsr_1 prsr_2
487 case S.parseD prsr_longest (S.fromList ls) of
488 Right long_list -> long_list == Prelude.takeWhile (<= mid_value) ls
491longestPassLeft :: Property
493 property (case S.parseD (P.shortest (P.die "die") (P.fromPure (1 :: Int))) (S.fromList [1 :: Int]) of
497longestPassRight :: Property
499 property (case S.parseD (P.shortest (P.fromPure (1 :: Int)) (P.die "die")) (S.fromList [1 :: Int]) of
503longestFailBoth :: Property
506 (case S.parseD (P.shortest (P.die "die") (P.die "die")) (S.fromList [1 :: Int]) of
512 forAll (listOf (chooseInt (0, 1)))
514 let fldstp conL currL = return $ FL.Partial (conL ++ currL)
516 FL.Fold fldstp (return (FL.Partial [])) return
518 flip P.many concatFold
519 $ P.fromFold $ FL.takeEndBy_ (== 1) FL.toList
520 in case S.parseD prsr (S.fromList ls) of
522 checkListEqual res_list (Prelude.filter (== 0) ls)
523 Left _ -> property False
525many_empty :: Property
527 property (case S.parseD (flip P.many FL.toList (P.die "die")) (S.fromList [1 :: Int]) of
528 Right res_list -> checkListEqual res_list ([] :: [Int])
529 Left _ -> property False)
533 forAll (listOf (chooseInt (0, 1)))
535 let fldstp conL currL = return $ FL.Partial $ conL ++ currL
536 concatFold = FL.Fold fldstp (return (FL.Partial [])) return
538 flip P.some concatFold
539 $ P.fromFold $ FL.takeEndBy_ (== 1) FL.toList
540 in case S.parseD prsr (S.fromList ls) of
541 Right res_list -> res_list == Prelude.filter (== 0) ls
546 property (case S.parseD (P.some (P.die "die") FL.toList) (S.fromList [1 :: Int]) of
550-------------------------------------------------------------------------------
552-------------------------------------------------------------------------------
554applicative :: Property
556 forAll (listOf (chooseAny :: Gen Int)) $ \ list1 ->
557 forAll (listOf (chooseAny :: Gen Int)) $ \ list2 ->
560 <$> P.fromFold (FL.take (length list1) FL.toList)
561 <*> P.fromFold (FL.take (length list2) FL.toList)
564 run $ S.parseD parser (S.fromList $ list1 ++ list2)
565 listEquals (==) olist1 list1
566 listEquals (==) olist2 list2
570 forAll (vectorOf 11 (listOf (chooseAny :: Gen Int))) $ \ ins ->
571 let parsers = fmap (\xs -> P.fromFold $ FL.take (length xs) FL.toList) ins
575 (Prelude.sequence parsers)
576 (S.fromList $ concat ins)
577 listEquals (==) outs ins
581 forAll (listOf (chooseAny :: Gen Int)) $ \ list1 ->
582 forAll (listOf (chooseAny :: Gen Int)) $ \ list2 ->
584 olist1 <- P.fromFold (FL.take (length list1) FL.toList)
585 olist2 <- P.fromFold (FL.take (length list2) FL.toList)
586 return (olist1, olist2)
589 run $ S.parseD parser (S.fromList $ list1 ++ list2)
590 listEquals (==) olist1 list1
591 listEquals (==) olist2 list2
593-------------------------------------------------------------------------------
595-------------------------------------------------------------------------------
599 forAll (chooseInt (1,100)) $ \len ->
600 forAll (listOf (vectorOf len (chooseAny :: Gen Int))) $ \ ins ->
606 (P.fromFold $ FL.take len FL.toList) (S.fromList $ concat ins)
608 listEquals (==) outs ins
610-- basic sanity test for parsing from arrays
611parseUnfold :: Property
614 -- ls = input list (stream)
616 -- tlen = parser take size
619 <$> vectorOf len (chooseAny :: Gen Int)
620 <*> chooseInt (1, len)
621 <*> chooseInt (1, len)) $ \(ls, clen, tlen) ->
623 arrays <- S.toList $ S.arraysOf clen (S.fromList ls)
624 let src = Source.source (Just (Producer.OuterLoop arrays))
625 let parser = P.fromFold (FL.take tlen FL.toList)
628 $ Producer.concat Producer.fromList A.producer
630 Producer.simplify (Source.parseManyD parser readSrc)
633 $ S.unfoldMany Unfold.fromList
634 $ S.unfold streamParser src
636 listEquals (==) xs ls
638-------------------------------------------------------------------------------
639-- Test for a particular case hit during fs events testing
640-------------------------------------------------------------------------------
643evId = [96,238,17,9,0,0,0,0]
646evFlags = [0,4,1,0,0,0,0,0]
649evPathLen = [71,0,0,0,0,0,0,0]
653 [47,85,115,101,114,115,47,118,111,108,47,118,101,109,98,97,47,99,111,109
654 ,112,111,115,101,119,101 ,108,108,45,116,101,99,104,47,69,110,103,47,112
655 ,114,111,106,101,99,116,115,47,115,116,114,101,97,109,108,121,47,115,116
656 ,114,101,97,109,108,121,47,116,109,112,47,122,122
660event = evId ++ evFlags ++ evPathLen ++ evPath
664 , eventFlags :: Word32
665 , eventAbsPath :: A.Array Word8
666 } deriving (Show, Ord, Eq)
668readOneEvent :: P.Parser IO Word8 Event
670 arr <- P.takeEQ 24 (A.writeN 24)
671 let arr1 = A.unsafeCast arr :: A.Array Word64
672 eid = A.unsafeIndex arr1 0
673 eflags = A.unsafeIndex arr1 1
674 pathLen = fromIntegral $ A.unsafeIndex arr1 2
675 path <- P.takeEQ pathLen (A.writeN pathLen)
678 , eventFlags = fromIntegral eflags
679 , eventAbsPath = path
682parseMany2Events :: Property
688 $ S.parseManyD readOneEvent
689 $ S.fromList (concat (replicate 2 event))
691 assert (length xs == 2)
692 -- XXX assuming little endian machine
694 { eventId = 152170080
696 , eventAbsPath = A.fromList evPath
698 in listEquals (==) xs (replicate 2 ev)
700-------------------------------------------------------------------------------
702-------------------------------------------------------------------------------
705moduleName = "Data.Parser.ParserD"
711 modifyMaxSuccess (const maxTestCount) $ do
712 describe moduleName $ do
714 describe "Instances" $ do
715 prop "applicative" applicative
717 prop "sequence" sequence
719 describe "Stream parsing" $ do
720 prop "parseMany" parseMany
721 prop "parseMany2Events" parseMany2Events
722 prop "parseUnfold" parseUnfold
724 describe "test for accumulator" $ do
725 prop "P.fromFold FL.sum = FL.sum" fromFold
726 prop "fromPure value provided" fromPure
727 prop "fromPure monadic value provided" fromEffect
728 prop "always fail" die
729 prop "always fail but monadic" dieM
731 describe "test for element parser" $ do
732 prop "peek = head with list length > 0" peekPass
733 prop "peek fail on []" peekFail
734 prop "eof pass on []" eofPass
735 prop "eof fail on non-empty list" eofFail
736 prop "first element exists and >= mid_value" satisfyPass
737 prop "check first element exists and satisfies predicate" satisfy
739 describe "test for sequence parser" $ do
740 prop "P.takeBetween m n = Prelude.take when len >= m and len <= n"
742 prop "P.takeBetween m n = Prelude.take when len >= m and len <= n and\
743 \fail otherwise" takeBetween
744 prop "P.take = Prelude.take" Main.take
745 prop "P.takeEQ = Prelude.take when len >= n" takeEQPass
746 prop "P.takeEQ = Prelude.take when len >= n and fail otherwise" Main.takeEQ
747 prop "P.takeGE n ls = ls when len >= n" takeGEPass
748 prop "P.takeGE n ls = ls when len >= n and fail otherwise" Main.takeGE
749 prop "lookAhead . take n >> lookAhead . take n = lookAhead . take n" lookAheadPass
750 prop "lookAhead . take n >> lookAhead . take n = lookAhead . take n, else fail" lookAhead
751 prop "P.takeWhile = Prelude.takeWhile" Main.takeWhile
752 prop "P.takeWhile1 = Prelude.takeWhile if taken something, else check why failed" takeWhile1
753 prop "P.groupBy = Prelude.head . Prelude.groupBy" groupBy
754 prop "groupByRolling" groupByRolling
755 prop "P.takeEndByOrMax = Prelude.take n (Prelude.takeWhile (not . predicate)" takeEndByOrMax
756 prop "many (P.wordBy ' ') = words'" wordBy
757 prop "parse 0, then 1, else fail" serialWith
758 prop "fail due to die as left parser" splitWithFailLeft
759 prop "fail due to die as right parser" splitWithFailRight
760 prop "fail due to die as both parsers" splitWithFailBoth
761 prop "parsed two lists should be equal" teeWithPass
762 prop "fail due to die as left parser" teeWithFailLeft
763 prop "fail due to die as right parser" teeWithFailRight
764 prop "fail due to die as both parsers" teeWithFailBoth
765 prop "P.takeWhile (<= half_mid_value) = Prelude.takeWhile half_mid_value" shortestPass
766 prop "pass even if die is left parser" shortestPassLeft
767 prop "pass even if die is right parser" shortestPassRight
768 prop "fail due to die as both parsers" shortestFailBoth
769 prop "P.takeWhile (<= mid_value) = Prelude.takeWhile (<= mid_value)" longestPass
770 prop "pass even if die is left parser" longestPassLeft
771 prop "pass even if die is right parser" longestPassRight
772 prop "fail due to die as both parsers" longestFailBoth
773 prop "P.many concatFold $ P.takeEndBy_ (== 1) FL.toList = Prelude.filter (== 0)" many
774 prop "[] due to parser being die" many_empty
775 prop "P.some concatFold $ P.takeEndBy_ (== 1) FL.toList = Prelude.filter (== 0)" some
776 prop "fail due to parser being die" someFail
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list