foldl-transduce 0.4.5.0 → 0.4.6.0
raw patch · 8 files changed
+423/−84 lines, 8 filesdep +semigroupsdep +splitPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: semigroups, split
API changes (from Hackage documentation)
- Control.Foldl.Transduce.Internal: _1of3 :: (a, b, c) -> a
+ Control.Foldl.Transduce.ByteString: chunkSize :: Int -> ChunkSize
+ Control.Foldl.Transduce.ByteString: chunkSizeDefault :: ChunkSize
+ Control.Foldl.Transduce.ByteString: data ChunkSize
+ Control.Foldl.Transduce.ByteString: drainHandle :: (MonadIO m, ToFoldM m f) => f ByteString r -> ChunkSize -> Handle -> m r
+ Control.Foldl.Transduce.ByteString: instance GHC.Classes.Eq Control.Foldl.Transduce.ByteString.ChunkSize
+ Control.Foldl.Transduce.ByteString: instance GHC.Classes.Ord Control.Foldl.Transduce.ByteString.ChunkSize
+ Control.Foldl.Transduce.ByteString: instance GHC.Num.Num Control.Foldl.Transduce.ByteString.ChunkSize
+ Control.Foldl.Transduce.ByteString: instance GHC.Show.Show Control.Foldl.Transduce.ByteString.ChunkSize
+ Control.Foldl.Transduce.ByteString: toHandle :: (MonadIO m) => Handle -> FoldM m ByteString ()
+ Control.Foldl.Transduce.ByteString: toHandleBuilder :: (MonadIO m) => Handle -> FoldM m Builder ()
+ Control.Foldl.Transduce.Internal: fst3 :: (a, b, c) -> a
+ Control.Foldl.Transduce.Text: paragraphs :: Transducer Text Text ()
Files
- CHANGELOG +6/−0
- foldl-transduce.cabal +5/−1
- src/Control/Foldl/Transduce.hs +5/−5
- src/Control/Foldl/Transduce/ByteString.hs +88/−0
- src/Control/Foldl/Transduce/ByteString/IO.hs +1/−1
- src/Control/Foldl/Transduce/Internal.hs +3/−3
- src/Control/Foldl/Transduce/Text.hs +129/−9
- tests/tests.hs +186/−65
CHANGELOG view
@@ -1,3 +1,9 @@+# 0.4.6.0++- Deprecated Control.Foldl.Transduce.ByteString.IO +- Added Control.Foldl.Transduce.ByteString+- Added "paragraphs" splitter.+ # 0.4.5.0 - added split
foldl-transduce.cabal view
@@ -1,5 +1,5 @@ Name: foldl-transduce-Version: 0.4.5.0+Version: 0.4.6.0 Cabal-Version: >=1.8.0.2 Build-Type: Simple License: BSD3@@ -30,16 +30,19 @@ containers < 0.6 , bifunctors == 5.* , profunctors == 5.* ,+ semigroups >= 0.18 , semigroupoids >= 5.0 , foldl >= 1.1 && < 2 , comonad == 4.* , free == 4.* , void >= 0.6 ,+ split >= 0.2.2 , monoid-subclasses == 0.4.* Exposed-Modules: Control.Foldl.Transduce, Control.Foldl.Transduce.Text, Control.Foldl.Transduce.Textual,+ Control.Foldl.Transduce.ByteString, Control.Foldl.Transduce.ByteString.IO, Control.Foldl.Transduce.Internal GHC-Options: -O2 -Wall@@ -67,6 +70,7 @@ tasty-hunit >= 0.9.2, tasty-quickcheck >= 0.8.3.2, monoid-subclasses == 0.4.*,+ split >= 0.2.2, foldl , foldl-transduce
src/Control/Foldl/Transduce.hs view
@@ -121,7 +121,7 @@ import Control.Comonad.Cofree import Control.Foldl (Fold(..),FoldM(..)) import qualified Control.Foldl as L-import Control.Foldl.Transduce.Internal (Pair(..),Quartet(..),_1of3)+import Control.Foldl.Transduce.Internal (Pair(..),Quartet(..),fst3) {- $setup @@ -168,7 +168,7 @@ -} type Transduction' a b r = forall x. Fold b x -> Fold a (r,x) -{-| Helper for storing a 'ReifiedTransduction'' safely on a container. +{-| Helper for storing a 'Transduction'' safely on a container. -} newtype ReifiedTransduction' a b r = ReifiedTransduction' { getTransduction' :: Transduction' a b r }@@ -203,7 +203,7 @@ = forall x. Transducer (x -> i -> (x,[o],[[o]])) x (x -> (r,[o],[[o]])) instance Comonad (Transducer i o) where- extract (Transducer _ begin done) = _1of3 (done begin)+ extract (Transducer _ begin done) = fst3 (done begin) {-# INLINABLE extract #-} duplicate (Transducer step begin done) = Transducer step begin (\x -> (Transducer step x done,[],[]))@@ -486,14 +486,14 @@ -} foldify :: Transducer i o s -> Fold i s foldify (Transducer step begin done) =- Fold (\x i -> _1of3 (step x i)) begin (\x -> _1of3 (done x))+ Fold (\x i -> fst3 (step x i)) begin (\x -> fst3 (done x)) {-| Monadic version of 'foldify'. -} foldifyM :: Functor m => TransducerM m i o s -> FoldM m i s foldifyM (TransducerM step begin done) =- FoldM (\x i -> fmap _1of3 (step x i)) begin (\x -> fmap _1of3 (done x))+ FoldM (\x i -> fmap fst3 (step x i)) begin (\x -> fmap fst3 (done x)) {-| Transforms a 'Fold' into a 'Transducer' that sends the return value of the 'Fold' downstream when upstream closes.
+ src/Control/Foldl/Transduce/ByteString.hs view
@@ -0,0 +1,88 @@+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++-- |+--+-- Pour handles into folds,+-- write to handles using folds. +module Control.Foldl.Transduce.ByteString (+ -- * Reading from handles+ drainHandle+ , ChunkSize+ , chunkSize+ , chunkSizeDefault+ -- * Writing to handles+ , toHandle+ , toHandleBuilder + ) where++import qualified Control.Foldl as L+import Control.Foldl.Transduce +import qualified Data.ByteString as B+import qualified Data.ByteString.Builder as B+import Control.Monad.IO.Class+import System.IO+import Data.ByteString.Lazy.Internal (defaultChunkSize)++{-| Feed a fold with bytes read from a 'Handle'.++-}+drainHandle + :: (MonadIO m,ToFoldM m f) + => f B.ByteString r + -> ChunkSize + -> Handle + -> m r +drainHandle f (ChunkSize csize) h = driveHandle f csize h++{-| Maximum chunk size ++-}+newtype ChunkSize = ChunkSize Int deriving (Show,Eq,Ord,Num)++chunkSize :: Int -> ChunkSize+chunkSize = ChunkSize++chunkSizeDefault :: ChunkSize+chunkSizeDefault = chunkSize defaultChunkSize++driveHandle :: (MonadIO m,ToFoldM m f) + => f B.ByteString r + -> Int -- ^ max chunk size+ -> Handle + -> m r +driveHandle (toFoldM -> f) chunkSize handle = + L.impurely consumeFunc f (B.hGetSome handle chunkSize,hIsEOF handle)+ where+ -- adapted from foldM in Pipes.Prelude+ consumeFunc step begin done (readChunk,checkEOF) = do+ x0 <- begin+ loop x0+ where+ loop x = do+ atEOF <- liftIO checkEOF+ if atEOF + then done x + else do+ chunk <- liftIO readChunk+ x' <- step x chunk+ loop $! x'+++toHandle :: (MonadIO m) => Handle -> L.FoldM m B.ByteString ()+toHandle handle = + L.FoldM + (\_ b -> liftIO (B.hPut handle b)) + (return ()) + (\_ -> return ())+++toHandleBuilder :: (MonadIO m) => Handle -> L.FoldM m B.Builder ()+toHandleBuilder handle = + L.FoldM+ (\_ b -> liftIO (B.hPutBuilder handle b)) + (return ()) + (\_ -> return ())++
src/Control/Foldl/Transduce/ByteString/IO.hs view
@@ -5,7 +5,7 @@ -- -- Pour handles into folds, -- write to handles using folds. -module Control.Foldl.Transduce.ByteString.IO (+module Control.Foldl.Transduce.ByteString.IO {-# DEPRECATED "Use Control.Foldl.Transduce.ByteString instead." #-} ( driveHandle , toHandle , toHandleBuilder
src/Control/Foldl/Transduce/Internal.hs view
@@ -2,12 +2,12 @@ -- * Strict datatypes Pair(..) , Quartet(..)- , _1of3+ , fst3 ) where data Pair a b = Pair !a !b data Quartet a b c d = Quartet !a !b !c !d -_1of3 :: (a,b,c) -> a-_1of3 (x,_,_) = x+fst3 :: (a,b,c) -> a+fst3 (x,_,_) = x
src/Control/Foldl/Transduce/Text.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ViewPatterns #-} -- | --@@ -17,8 +18,9 @@ , stripStart , stripEnd -- * Splitters- , lines , words+ , lines+ , paragraphs -- * Re-exports -- $reexports , module Control.Foldl.Transduce.Textual@@ -27,7 +29,7 @@ import Prelude hiding (lines,words) import Data.Char import Data.Monoid (mempty)-import Data.Foldable (foldMap)+import Data.Foldable (foldMap,foldl') import qualified Data.ByteString as B import qualified Data.Text import qualified Data.Text as T@@ -40,6 +42,11 @@ import qualified Control.Foldl.Transduce as L import Control.Foldl.Transduce.Textual import Control.Foldl.Transduce.Internal (Pair(..))+import qualified Data.List+import Data.List.Split+import qualified Data.List.Split+import Data.List.NonEmpty (NonEmpty(..))+import qualified Data.List.NonEmpty as NonEmpty {- $setup @@ -55,7 +62,7 @@ {-| Builds a decoding 'Transducer' out of a stream-oriented decoding function from "Data.Text.Encoding" and an error handler from- "Data.Text.Encoding.Error". + "Data.Text.Encoding.Error". -} decoder :: (B.ByteString -> T.Decoding) -> T.OnDecodeError -> L.Transducer B.ByteString T.Text ()@@ -73,7 +80,7 @@ onLeftovers' = onLeftovers "leftovers" Nothing {-| Builds a UTF8-decoding 'Transducer'. Takes an error handler from- "Data.Text.Encoding.Error". + "Data.Text.Encoding.Error". -} utf8 :: T.OnDecodeError -> L.Transducer B.ByteString T.Text ()@@ -112,7 +119,7 @@ utf8strict = utf8 T.strictDecode {-| Similar to 'decoder', but catches 'UnicodeException' in 'IO' and uses- 'Control.Monad.Trans.Except' to communicate the error. + 'Control.Monad.Trans.Except' to communicate the error. -} decoderE :: MonadIO m@@ -141,7 +148,7 @@ onLeftovers' = T.strictDecode "leftovers" Nothing {-| Like 'utf8strict', but catches 'UnicodeException' in 'IO' and uses- 'Control.Monad.Trans.Except' to communicate the error. + 'Control.Monad.Trans.Except' to communicate the error. >>> runExceptT $ L.foldM (transduceM utf8E (L.generalize L.list)) (map fromString ["invalid \xc3\x28 sequence"]) Left Cannot decode byte '\x28': Data.Text.Internal.Encoding.streamDecodeUtf8With: Invalid UTF-8 stream@@ -152,7 +159,7 @@ utf8E :: MonadIO m => L.TransducerM (ExceptT T.UnicodeException m) B.ByteString T.Text () utf8E = decoderE T.streamDecodeUtf8With -{-| Appends a newline at the end of the stream. +{-| Appends a newline at the end of the stream. >>> L.fold (transduce newline L.list) (map T.pack ["without","newline"]) ["without","newline","\n"]@@ -163,7 +170,7 @@ blank :: T.Text -> Bool blank = Data.Text.all isSpace -{-| Remove leading white space from a stream of 'Text'. +{-| Remove leading white space from a stream of 'Text'. >>> L.fold (transduce stripStart L.list) (map T.pack [" ","", " text "]) ["text "]@@ -178,7 +185,7 @@ else (True, [T.stripStart i],[]) done _ = ((),[],[]) -{-| Remove trailing white space from a stream of 'Text'. +{-| Remove trailing white space from a stream of 'Text'. __/BEWARE!/__ This function naively accumulates in memory any arriving "blank blocks" of@@ -274,6 +281,119 @@ (_,[]) -> error "never happens, txt not blank" in (nextstate,oldgroup,newgroups) done _ = ((),[],[])+++data ParagraphsState = + SkippingAfterStreamStart+ | SkippingAfterNewline+ | SkippingAfterBlankLine+ | ContinuingNonemptyLine++{-| Splits a stream of text into paragraphs, removing empty lines and trimming+ newspace from the start of each line.++>>> map mconcat (L.fold (folds paragraphs L.list L.list) (map T.pack [" \n aaa","\naa ", " \n\nbb\n"]))+["aaa\naa \n","bb\n"]++ Used with 'L.transduce', it removes empty lines and trims newspace from the+ start of each line.+-}+paragraphs :: L.Transducer T.Text T.Text ()+paragraphs = L.Transducer step SkippingAfterStreamStart done + where+ step tstate txt+ | Data.Text.null txt = + (tstate,[],[])+ | otherwise = + let (initlines,lastline) = splittedLines txt+ (tstate', outputsreversed) =+ advanceLast+ (foldl' + advance+ (tstate,pure [])+ initlines)+ lastline + (xs :| xss) = fmap reverse (NonEmpty.reverse outputsreversed)+ in (tstate',xs,xss)+ done _ = + ((),[],[])+ splittedLines :: T.Text -> ([T.Text],T.Text)+ splittedLines nonEmptyChunk = + let splitted = + Data.Text.lines nonEmptyChunk + +++ if T.last nonEmptyChunk == '\n' then [mempty] else mempty+ in (init splitted, last splitted) -- unsafe with empty lists!!!+ advance + :: (ParagraphsState, NonEmpty [T.Text]) + -> T.Text + -> (ParagraphsState, NonEmpty [T.Text])+ advance (s,outputs) i = + case (s, blank i) of+ (SkippingAfterStreamStart, True) -> + (,) + SkippingAfterStreamStart + outputs+ (SkippingAfterStreamStart, False) -> + (,)+ SkippingAfterNewline+ (prepend ["\n",T.stripStart i] outputs) + (SkippingAfterNewline, True) -> + (,) + SkippingAfterBlankLine + outputs + (SkippingAfterNewline, False) -> + (,)+ SkippingAfterNewline+ (prepend ["\n",T.stripStart i] outputs)+ (SkippingAfterBlankLine, True) -> + (,) + SkippingAfterBlankLine + outputs + (SkippingAfterBlankLine, False) -> + (,)+ SkippingAfterNewline+ (prepend ["\n",T.stripStart i] (NonEmpty.cons [] outputs)) + (ContinuingNonemptyLine, _) -> + (,)+ SkippingAfterNewline+ (prepend ["\n",i] outputs)+ advanceLast + :: (ParagraphsState, NonEmpty [T.Text]) + -> T.Text + -> (ParagraphsState, NonEmpty [T.Text])+ advanceLast (s,outputs) i = + case (s, blank i) of+ (SkippingAfterStreamStart, True) -> + (,) + SkippingAfterStreamStart + outputs+ (SkippingAfterStreamStart, False) -> + (,)+ ContinuingNonemptyLine+ (prepend [T.stripStart i] outputs)+ (SkippingAfterNewline, True) -> + (,) + SkippingAfterNewline + outputs+ (SkippingAfterNewline, False) -> + (,)+ ContinuingNonemptyLine+ (prepend [T.stripStart i] outputs)+ (SkippingAfterBlankLine, True) -> + (,)+ SkippingAfterBlankLine+ outputs + (SkippingAfterBlankLine, False) -> + (,)+ ContinuingNonemptyLine+ (prepend [T.stripStart i] (NonEmpty.cons [] outputs))+ (ContinuingNonemptyLine, _) -> + (,)+ ContinuingNonemptyLine+ (prepend [i] outputs)+ prepend :: [a] -> NonEmpty [a] -> NonEmpty [a]+ prepend as (as':| rest) = (as ++ as') :| rest ------------------------------------------------------------------------------
tests/tests.hs view
@@ -1,9 +1,12 @@ module Main where import Prelude hiding (splitAt,lines,words)+import Data.Char import Data.String hiding (lines,words) import Data.Monoid import Data.Bifunctor+import qualified Data.List (intersperse,splitAt)+import qualified Data.List.Split as Split import qualified Data.Monoid.Factorial as SFM import Test.Tasty import Test.Tasty.HUnit@@ -17,104 +20,222 @@ import Control.Foldl.Transduce.Text import Control.Foldl.Transduce.Textual +{- $quickcheck++ Notes for quickchecking on the REPL:++cabal repl tests+:t sample+sample :: Show a => Gen a -> IO ()+sample (arbitrary :: Gen WordA)++-}+ main :: IO () main = defaultMain tests -newtype WordQC = WordQC { getWordQC :: T.Text } deriving (Show)+testCaseEq :: (Eq a, Show a) => TestName -> a -> a -> TestTree+testCaseEq name a1 a2 = testCase name (assertEqual "" a1 a2) -instance Arbitrary WordQC where+blank :: T.Text -> Bool+blank = T.all isSpace++nl :: T.Text+nl = T.pack "\n"++sp :: T.Text+sp = T.pack " "++c :: T.Text+c = T.pack "c"++{- $words++-}++newtype WordA = WordA { getWord :: T.Text } deriving (Show)++instance Arbitrary WordA where arbitrary = do firstChar <- oneof [pure ' ', pure '\n', arbitrary] lastChar <- oneof [pure ' ', pure '\n', arbitrary] middle <- listOf (frequency [(1,pure ' '),(4,arbitrary)])- return (WordQC (T.pack (firstChar : (middle ++ [lastChar]))))+ return (WordA (T.pack (firstChar : (middle ++ [lastChar])))) +{- $paragraphs++-}++newtype TextChunksA = TextChunksA { getChunks :: [T.Text] } deriving (Show)++instance Arbitrary TextChunksA where+ arbitrary = flip suchThat (not . blank . mconcat . getChunks) (do+ TextChunksA <$> partz)+ where+ chunkz = frequency [+ (20::Int, flip T.replicate sp <$> choose (1,40)) + , (20, flip T.replicate sp <$> choose (1,3)) + , (50, pure nl)+ , (20, flip T.replicate c <$> choose (1,30))+ , (20, flip T.replicate c <$> choose (1,3))+ ]+ combined = mconcat <$> vectorOf 40 chunkz + partitions = infiniteListOf (choose (1::Int,7))+ partz = partition [] <$> combined <*> partitions+ partition :: [T.Text] -> T.Text -> [Int] -> [T.Text]+ partition accum text (x:xs) =+ if x >= T.length text + then reverse (text:accum)+ else + let (point,rest) = T.splitAt x text + in + partition (point:accum) rest xs+ partition _ _ [] = error "never happens"+ shrink (TextChunksA texts) = + let removeIndex i xs = + let (xs',xs'') = Data.List.splitAt i xs+ in xs' ++ tail xs'' + l = length texts+ in + if l == 1 + then []+ else map (\i -> TextChunksA (removeIndex i texts)) [0..l-1] ++paragraphsBaseline + :: T.Text -> [T.Text] +paragraphsBaseline = + map (T.unlines . map T.stripStart . T.lines)+ . map mconcat + . map (`mappend` [nl])+ . map (Data.List.intersperse nl)+ . filter (not . null) + . Split.splitWhen blank + . T.lines++ignoreLastNewline :: [T.Text] -> [T.Text]+ignoreLastNewline ts = + let + lastt = last ts+ lastt' = if T.last lastt == '\n' then T.init lastt else lastt + in init ts ++ [lastt']++-- (paragraphs,chunks)+splittedParagraphs :: T.Text -> [Int] -> [([T.Text],[T.Text])]+splittedParagraphs txt splitsizes = + let + splitted = paragraphsBaseline txt+ in + zip (repeat splitted) (map (flip T.chunksOf txt) splitsizes)++paragraphsUnderTest+ :: [T.Text] -> [T.Text] +paragraphsUnderTest txt =+ map mconcat (L.fold (folds paragraphs L.list L.list) txt)++paragraph01 :: T.Text+paragraph01 = + T.pack + " \n \n\n \n \n \+ \a aa aaa \nb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb bb \n \+ \ ccccccccccccccccccccccc cccccccc \n\n \n \n\n ccc\ + \ \n \n \nd\n\n\ne \+ \\n" + +paragraph02 :: T.Text+paragraph02 = T.pack " cc "+ tests :: TestTree tests = testGroup "Tests" [ testGroup "surround" [- testCase "surroundempty" $ - assertEqual mempty- "prefixsuffix"- (L.fold (transduce (surround "prefix" "suffix") L.list) "")- ]- ,+ testCaseEq "surroundempty" + "prefixsuffix"+ (L.fold (transduce (surround "prefix" "suffix") L.list) "")+ ], testGroup "chunksOf" [- testCase "emptyList3" $ - assertEqual mempty- ([[]]::[[Int]])- (L.fold (folds (chunksOf 3) L.list L.list) [])+ testCaseEq "emptyList3"+ ([[]]::[[Int]])+ (L.fold (folds (chunksOf 3) L.list L.list) []) ,- testCase "size1" $ - assertEqual mempty- ([[1],[2],[3],[4],[5],[6],[7]]::[[Int]])- (L.fold (folds (chunksOf 1) L.list L.list) [1..7])+ testCaseEq "size1" + ([[1],[2],[3],[4],[5],[6],[7]]::[[Int]])+ (L.fold (folds (chunksOf 1) L.list L.list) [1..7]) ,- testCase "size3" $ - assertEqual mempty- ([[1,2,3],[4,5,6],[7]]::[[Int]])- (L.fold (folds (chunksOf 3) L.list L.list) [1..7])- ]- ,- testGroup "textualBreak" $ + testCaseEq "size3" + ([[1,2,3],[4,5,6],[7]]::[[Int]])+ (L.fold (folds (chunksOf 3) L.list L.list) [1..7])+ ],+ testGroup "textualBreak" [- testCase "beginwithdot" $- assertEqual mempty- ".bb"- (L.fold (bisect (textualBreak (=='.')) ignore (reify id) L.mconcat) ["aa",".bb"])+ testCaseEq "beginwithdot"+ ".bb"+ (L.fold (bisect (textualBreak (=='.')) ignore (reify id) L.mconcat) ["aa",".bb"]) ,- testCase "endwithdot" $- assertEqual mempty- "."- (L.fold (bisect (textualBreak (=='.')) ignore (reify id) L.mconcat) ["aa","bb."])- ] - ,- testGroup "newline" $ + testCaseEq "endwithdot"+ "."+ (L.fold (bisect (textualBreak (=='.')) ignore (reify id) L.mconcat) ["aa","bb."])+ ],+ testGroup "newline" [- testCase "newlineempty" $- assertEqual mempty+ testCaseEq "newlineempty" (T.pack "\n") (mconcat (L.fold (transduce newline L.list) (map T.pack []))) ,- testCase "newlinenull" $- assertEqual mempty+ testCaseEq "newlinenull" (T.pack "\n") (mconcat (L.fold (transduce newline L.list) (map T.pack [""])))- ]- ,+ ], testGroup "words" [ testGroup "quickcheck" [ - testProperty "quickcheck1" (\chunks -> - let tchunks = fmap getWordQC chunks - in- (case TL.words (TL.fromChunks tchunks) of- [] -> [mempty]- x -> x) ==- (fmap TL.fromChunks (L.fold (folds words L.list L.list) tchunks)))+ testProperty "quickcheck1" (\chunks -> -- list of words + let tchunks = fmap getWord chunks + in+ (case TL.words (TL.fromChunks tchunks) of+ [] -> [mempty]+ x -> x) ==+ (fmap TL.fromChunks (L.fold (folds words L.list L.list) tchunks))) ]- ]- ,- testGroup "quiesceWith" $ + ],+ testGroup "paragraphs" [- testCase "collectAfterFailure" $- let foldthatfails = - transduceM utf8E (L.generalize L.list)- inputs = - map fromString ["invalid \xc3\x28 sequence","xxx","zzz","___"]- fallbackfold =- bisectM (chunkedSplitAt 4) (reifyM id) ignore (L.generalize L.list)- in- do- r <- L.foldM (quiesceWith fallbackfold foldthatfails) inputs - assertEqual - mempty - (Left ('C',4))- (first (bimap (head . show) (SFM.length . mconcat)) r)+ testCase "paragraphs01"+ (mapM_+ (\(x,y) -> assertEqual "" (ignoreLastNewline x) (ignoreLastNewline (paragraphsUnderTest y))) + (splittedParagraphs paragraph01 [1..7])),+ testCaseEq "newlineAtEnd"+ (map T.pack ["aa\n"]) + (paragraphsUnderTest (map T.pack ["a","a","\n"])),+ testCaseEq "noNewlineAtEnd"+ (map T.pack ["aa"]) + (paragraphsUnderTest (map T.pack ["a","a"])),+ testGroup "quickcheck" + [ + testProperty "quickcheck1" (\(TextChunksA chunks) ->+ ignoreLastNewline (paragraphsUnderTest chunks)+ ==+ ignoreLastNewline (paragraphsBaseline (mconcat chunks)))+ ]+ ],+ testGroup "quiesceWith" + [+ testCase "collectAfterFailure" (do+ let+ foldthatfails = + transduceM utf8E (L.generalize L.list)+ inputs = + map fromString ["invalid \xc3\x28 sequence","xxx","zzz","___"]+ fallbackfold =+ bisectM (chunkedSplitAt 4) (reifyM id) ignore (L.generalize L.list)+ r <- L.foldM (quiesceWith fallbackfold foldthatfails) inputs + assertEqual + mempty + (Left ('C',4))+ (first (bimap (head . show) (SFM.length . mconcat)) r)) ] ]