enumerator 0.4.14 → 0.4.15
raw patch · 69 files changed
+5251/−1563 lines, 69 filesdep −extensible-exceptionsdep ~basedep ~containersPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies removed: extensible-exceptions
Dependency ranges changed: base, containers
API changes (from Hackage documentation)
- Data.Enumerator: Chunks :: [a] -> Stream a
- Data.Enumerator: Continue :: (Stream a -> Iteratee a m b) -> Step a m b
- Data.Enumerator: EOF :: Stream a
- Data.Enumerator: Error :: SomeException -> Step a m b
- Data.Enumerator: Yield :: b -> (Stream a) -> Step a m b
- Data.Enumerator: checkContinue0 :: Monad m => (Enumerator a m b -> (Stream a -> Iteratee a m b) -> Iteratee a m b) -> Enumerator a m b
- Data.Enumerator: checkContinue1 :: Monad m => ((s1 -> Enumerator a m b) -> s1 -> (Stream a -> Iteratee a m b) -> Iteratee a m b) -> s1 -> Enumerator a m b
- Data.Enumerator: checkDone :: Monad m => ((Stream a -> Iteratee a m b) -> Iteratee a' m (Step a m b)) -> Enumeratee a' a m b
- Data.Enumerator: checkDoneEx :: Monad m => Stream a' -> ((Stream a -> Iteratee a m b) -> Iteratee a' m (Step a m b)) -> Enumeratee a' a m b
- Data.Enumerator: continue :: Monad m => (Stream a -> Iteratee a m b) -> Iteratee a m b
- Data.Enumerator: data Step a m b
- Data.Enumerator: data Stream a
- Data.Enumerator: enumEOF :: Monad m => Enumerator a m b
- Data.Enumerator: instance (Typeable a, Typeable1 m) => Typeable1 (Iteratee a m)
- Data.Enumerator: instance (Typeable a, Typeable1 m) => Typeable1 (Step a m)
- Data.Enumerator: instance Applicative Stream
- Data.Enumerator: instance Eq a => Eq (Stream a)
- Data.Enumerator: instance Functor Stream
- Data.Enumerator: instance Monad Stream
- Data.Enumerator: instance Monad m => Applicative (Iteratee a m)
- Data.Enumerator: instance Monad m => Functor (Iteratee a m)
- Data.Enumerator: instance Monad m => Monad (Iteratee a m)
- Data.Enumerator: instance MonadIO m => MonadIO (Iteratee a m)
- Data.Enumerator: instance MonadTrans (Iteratee a)
- Data.Enumerator: instance Monoid (Stream a)
- Data.Enumerator: instance Show a => Show (Stream a)
- Data.Enumerator: instance Typeable1 Stream
- Data.Enumerator: returnI :: Monad m => Step a m b -> Iteratee a m b
- Data.Enumerator: yield :: Monad m => b -> Stream a -> Iteratee a m b
- Data.Enumerator.IO: enumFile :: FilePath -> Enumerator ByteString IO b
- Data.Enumerator.IO: enumHandle :: MonadIO m => Integer -> Handle -> Enumerator ByteString m b
- Data.Enumerator.IO: iterHandle :: MonadIO m => Handle -> Iteratee ByteString m ()
+ Data.Enumerator: enumLists :: Monad m => [[a]] -> Enumerator a m b
+ Data.Enumerator: runLists :: [[a]] -> Iteratee a Identity b -> Either SomeException b
+ Data.Enumerator: runLists_ :: [[a]] -> Iteratee a Identity b -> b
+ Data.Enumerator.Internal: ($$) :: Monad m => (Step a m b -> Iteratee a' m b') -> Iteratee a m b -> Iteratee a' m b'
+ Data.Enumerator.Internal: (<==<) :: Monad m => (Step a m b -> Iteratee a' m b') -> Enumerator a m b -> Step a m b -> Iteratee a' m b'
+ Data.Enumerator.Internal: (==<<) :: Monad m => (Step a m b -> Iteratee a' m b') -> Iteratee a m b -> Iteratee a' m b'
+ Data.Enumerator.Internal: (>==>) :: Monad m => Enumerator a m b -> (Step a m b -> Iteratee a' m b') -> Step a m b -> Iteratee a' m b'
+ Data.Enumerator.Internal: (>>==) :: Monad m => Iteratee a m b -> (Step a m b -> Iteratee a' m b') -> Iteratee a' m b'
+ Data.Enumerator.Internal: Chunks :: [a] -> Stream a
+ Data.Enumerator.Internal: Continue :: (Stream a -> Iteratee a m b) -> Step a m b
+ Data.Enumerator.Internal: EOF :: Stream a
+ Data.Enumerator.Internal: Error :: SomeException -> Step a m b
+ Data.Enumerator.Internal: Iteratee :: m (Step a m b) -> Iteratee a m b
+ Data.Enumerator.Internal: Yield :: b -> (Stream a) -> Step a m b
+ Data.Enumerator.Internal: checkContinue0 :: Monad m => (Enumerator a m b -> (Stream a -> Iteratee a m b) -> Iteratee a m b) -> Enumerator a m b
+ Data.Enumerator.Internal: checkContinue1 :: Monad m => ((s1 -> Enumerator a m b) -> s1 -> (Stream a -> Iteratee a m b) -> Iteratee a m b) -> s1 -> Enumerator a m b
+ Data.Enumerator.Internal: checkDone :: Monad m => ((Stream a -> Iteratee a m b) -> Iteratee a' m (Step a m b)) -> Enumeratee a' a m b
+ Data.Enumerator.Internal: checkDoneEx :: Monad m => Stream a' -> ((Stream a -> Iteratee a m b) -> Iteratee a' m (Step a m b)) -> Enumeratee a' a m b
+ Data.Enumerator.Internal: continue :: Monad m => (Stream a -> Iteratee a m b) -> Iteratee a m b
+ Data.Enumerator.Internal: data Step a m b
+ Data.Enumerator.Internal: data Stream a
+ Data.Enumerator.Internal: enumEOF :: Monad m => Enumerator a m b
+ Data.Enumerator.Internal: instance (Typeable a, Typeable1 m) => Typeable1 (Iteratee a m)
+ Data.Enumerator.Internal: instance (Typeable a, Typeable1 m) => Typeable1 (Step a m)
+ Data.Enumerator.Internal: instance Applicative Stream
+ Data.Enumerator.Internal: instance Eq a => Eq (Stream a)
+ Data.Enumerator.Internal: instance Functor Stream
+ Data.Enumerator.Internal: instance Monad Stream
+ Data.Enumerator.Internal: instance Monad m => Applicative (Iteratee a m)
+ Data.Enumerator.Internal: instance Monad m => Functor (Iteratee a m)
+ Data.Enumerator.Internal: instance Monad m => Monad (Iteratee a m)
+ Data.Enumerator.Internal: instance MonadIO m => MonadIO (Iteratee a m)
+ Data.Enumerator.Internal: instance MonadTrans (Iteratee a)
+ Data.Enumerator.Internal: instance Monoid (Stream a)
+ Data.Enumerator.Internal: instance Show a => Show (Stream a)
+ Data.Enumerator.Internal: instance Typeable1 Stream
+ Data.Enumerator.Internal: newtype Iteratee a m b
+ Data.Enumerator.Internal: returnI :: Monad m => Step a m b -> Iteratee a m b
+ Data.Enumerator.Internal: runIteratee :: Iteratee a m b -> m (Step a m b)
+ Data.Enumerator.Internal: type Enumeratee ao ai m b = Step ai m b -> Iteratee ao m (Step ai m b)
+ Data.Enumerator.Internal: type Enumerator a m b = Step a m b -> Iteratee a m b
+ Data.Enumerator.Internal: yield :: Monad m => b -> Stream a -> Iteratee a m b
Files
- enumerator.cabal +70/−15
- examples/wc.hs +20/−22
- lib/Data/Enumerator.hs +107/−548
- lib/Data/Enumerator/Binary.hs +10/−11
- lib/Data/Enumerator/Compatibility.hs +219/−0
- lib/Data/Enumerator/IO.hs +2/−0
- lib/Data/Enumerator/Internal.hs +342/−0
- lib/Data/Enumerator/List.hs +5/−6
- lib/Data/Enumerator/List.hs-boot +1/−1
- lib/Data/Enumerator/Text.hs +20/−16
- lib/Data/Enumerator/Util.hs +2/−2
- scripts/run-coverage +78/−0
- tests/EnumeratorTests.hs +48/−0
- tests/EnumeratorTests/Binary.hs +64/−0
- tests/EnumeratorTests/Binary/Consume.hs +104/−0
- tests/EnumeratorTests/Binary/Drop.hs +64/−0
- tests/EnumeratorTests/Binary/Fold.hs +42/−0
- tests/EnumeratorTests/Binary/Handle.hs +88/−0
- tests/EnumeratorTests/Binary/Isolate.hs +74/−0
- tests/EnumeratorTests/Binary/Iterate.hs +31/−0
- tests/EnumeratorTests/Binary/Map.hs +140/−0
- tests/EnumeratorTests/Binary/Repeat.hs +49/−0
- tests/EnumeratorTests/Binary/Replicate.hs +38/−0
- tests/EnumeratorTests/Binary/Require.hs +67/−0
- tests/EnumeratorTests/Binary/Split.hs +49/−0
- tests/EnumeratorTests/Binary/Unfold.hs +37/−0
- tests/EnumeratorTests/Binary/Util.hs +44/−0
- tests/EnumeratorTests/Binary/Zip.hs +165/−0
- tests/EnumeratorTests/CatchError.hs +107/−0
- tests/EnumeratorTests/Compatibility.hs +204/−0
- tests/EnumeratorTests/Instances.hs +66/−0
- tests/EnumeratorTests/Join.hs +90/−0
- tests/EnumeratorTests/List.hs +62/−0
- tests/EnumeratorTests/List/Consume.hs +102/−0
- tests/EnumeratorTests/List/Drop.hs +63/−0
- tests/EnumeratorTests/List/Fold.hs +74/−0
- tests/EnumeratorTests/List/Isolate.hs +70/−0
- tests/EnumeratorTests/List/Iterate.hs +30/−0
- tests/EnumeratorTests/List/Map.hs +142/−0
- tests/EnumeratorTests/List/Repeat.hs +48/−0
- tests/EnumeratorTests/List/Replicate.hs +40/−0
- tests/EnumeratorTests/List/Require.hs +65/−0
- tests/EnumeratorTests/List/Split.hs +28/−0
- tests/EnumeratorTests/List/Unfold.hs +35/−0
- tests/EnumeratorTests/List/Unique.hs +22/−0
- tests/EnumeratorTests/List/Util.hs +81/−0
- tests/EnumeratorTests/List/Zip.hs +172/−0
- tests/EnumeratorTests/Misc.hs +143/−0
- tests/EnumeratorTests/Sequence.hs +28/−0
- tests/EnumeratorTests/Stream.hs +82/−0
- tests/EnumeratorTests/Text.hs +66/−0
- tests/EnumeratorTests/Text/Codecs.hs +322/−0
- tests/EnumeratorTests/Text/Consume.hs +103/−0
- tests/EnumeratorTests/Text/Drop.hs +64/−0
- tests/EnumeratorTests/Text/Fold.hs +41/−0
- tests/EnumeratorTests/Text/Handle.hs +50/−0
- tests/EnumeratorTests/Text/Isolate.hs +73/−0
- tests/EnumeratorTests/Text/Iterate.hs +31/−0
- tests/EnumeratorTests/Text/Map.hs +138/−0
- tests/EnumeratorTests/Text/Repeat.hs +49/−0
- tests/EnumeratorTests/Text/Replicate.hs +38/−0
- tests/EnumeratorTests/Text/Require.hs +67/−0
- tests/EnumeratorTests/Text/Split.hs +61/−0
- tests/EnumeratorTests/Text/Unfold.hs +36/−0
- tests/EnumeratorTests/Text/Util.hs +44/−0
- tests/EnumeratorTests/Text/Zip.hs +164/−0
- tests/EnumeratorTests/Util.hs +142/−0
- tests/Tests.hs +0/−936
- tests/enumerator-tests.cabal +28/−6
enumerator.cabal view
@@ -1,5 +1,5 @@ name: enumerator-version: 0.4.14+version: 0.4.15 synopsis: Reliable, high-performance processing with left-fold enumerators license: MIT license-file: license.txt@@ -63,39 +63,94 @@ scripts/common.bash scripts/dist scripts/run-benchmarks+ scripts/run-coverage scripts/run-tests -- tests/enumerator-tests.cabal- tests/Tests.hs+ tests/EnumeratorTests.hs+ tests/EnumeratorTests/Binary.hs+ tests/EnumeratorTests/Binary/Consume.hs+ tests/EnumeratorTests/Binary/Drop.hs+ tests/EnumeratorTests/Binary/Fold.hs+ tests/EnumeratorTests/Binary/Handle.hs+ tests/EnumeratorTests/Binary/Isolate.hs+ tests/EnumeratorTests/Binary/Iterate.hs+ tests/EnumeratorTests/Binary/Map.hs+ tests/EnumeratorTests/Binary/Repeat.hs+ tests/EnumeratorTests/Binary/Replicate.hs+ tests/EnumeratorTests/Binary/Require.hs+ tests/EnumeratorTests/Binary/Split.hs+ tests/EnumeratorTests/Binary/Unfold.hs+ tests/EnumeratorTests/Binary/Util.hs+ tests/EnumeratorTests/Binary/Zip.hs+ tests/EnumeratorTests/CatchError.hs+ tests/EnumeratorTests/Compatibility.hs+ tests/EnumeratorTests/Instances.hs+ tests/EnumeratorTests/Join.hs+ tests/EnumeratorTests/List.hs+ tests/EnumeratorTests/List/Consume.hs+ tests/EnumeratorTests/List/Drop.hs+ tests/EnumeratorTests/List/Fold.hs+ tests/EnumeratorTests/List/Isolate.hs+ tests/EnumeratorTests/List/Iterate.hs+ tests/EnumeratorTests/List/Map.hs+ tests/EnumeratorTests/List/Repeat.hs+ tests/EnumeratorTests/List/Replicate.hs+ tests/EnumeratorTests/List/Require.hs+ tests/EnumeratorTests/List/Split.hs+ tests/EnumeratorTests/List/Unfold.hs+ tests/EnumeratorTests/List/Unique.hs+ tests/EnumeratorTests/List/Util.hs+ tests/EnumeratorTests/List/Zip.hs+ tests/EnumeratorTests/Misc.hs+ tests/EnumeratorTests/Sequence.hs+ tests/EnumeratorTests/Stream.hs+ tests/EnumeratorTests/Text.hs+ tests/EnumeratorTests/Text/Codecs.hs+ tests/EnumeratorTests/Text/Consume.hs+ tests/EnumeratorTests/Text/Drop.hs+ tests/EnumeratorTests/Text/Fold.hs+ tests/EnumeratorTests/Text/Handle.hs+ tests/EnumeratorTests/Text/Isolate.hs+ tests/EnumeratorTests/Text/Iterate.hs+ tests/EnumeratorTests/Text/Map.hs+ tests/EnumeratorTests/Text/Repeat.hs+ tests/EnumeratorTests/Text/Replicate.hs+ tests/EnumeratorTests/Text/Require.hs+ tests/EnumeratorTests/Text/Split.hs+ tests/EnumeratorTests/Text/Unfold.hs+ tests/EnumeratorTests/Text/Util.hs+ tests/EnumeratorTests/Text/Zip.hs+ tests/EnumeratorTests/Util.hs source-repository head type: bazaar- location: http://john-millikin.com/software/enumerator/+ location: https://john-millikin.com/software/enumerator/ +source-repository this+ type: bazaar+ location: https://john-millikin.com/branches/enumerator/0.4/+ tag: enumerator_0.4.15+ library ghc-options: -Wall -O2 hs-source-dirs: lib build-depends:- transformers >= 0.2 && < 0.3+ base >= 4.0 && < 5.0+ , transformers >= 0.2 && < 0.3 , bytestring >= 0.9 && < 0.10- , containers+ , containers >= 0.1 && < 0.5 , text >= 0.7 && < 0.12 - if impl(ghc >= 6.10)- build-depends:- base >= 4 && < 5- else- build-depends:- base >= 3 && < 4- , extensible-exceptions >= 0.1 && < 0.2- exposed-modules: Data.Enumerator Data.Enumerator.Binary- Data.Enumerator.Text- Data.Enumerator.List+ Data.Enumerator.Internal Data.Enumerator.IO+ Data.Enumerator.List+ Data.Enumerator.Text other-modules:+ Data.Enumerator.Compatibility Data.Enumerator.Util
examples/wc.hs view
@@ -8,30 +8,30 @@ -- ----------------------------------------------------------------------------- module Main (main) where-import Data.Enumerator as E-import qualified Data.Enumerator.Binary as EB-import qualified Data.Enumerator.Text as ET-import qualified Data.ByteString as B --- support imports-import Control.Monad (unless, forM_)-import System.IO-import System.Console.GetOpt-import System.Environment-import System.Exit+import Control.Monad (unless, forM_)+import Data.ByteString (ByteString)+import System.Console.GetOpt+import System.IO+import System.Environment+import System.Exit +import Data.Enumerator as E+import qualified Data.Enumerator.Binary as Binary+import qualified Data.Enumerator.Text as Text+ -- support wc modes -c (bytes), -m (characters), and -l (lines) -- iterBytes simply counts how many bytes are in each chunk, accumulates this -- count, and returns it when EOF is received. -iterBytes :: Monad m => Iteratee B.ByteString m Integer-iterBytes = EB.fold (\acc _ -> acc + 1) 0+iterBytes :: Monad m => Iteratee ByteString m Integer+iterBytes = Binary.fold (\acc _ -> acc + 1) 0 -- iterLines is similar, except it only counts newlines ('\n') -iterLines :: Monad m => Iteratee B.ByteString m Integer-iterLines = EB.fold step 0 where+iterLines :: Monad m => Iteratee ByteString m Integer+iterLines = Binary.fold step 0 where step acc 0xA = acc + 1 step acc _ = acc @@ -39,13 +39,11 @@ -- assuming UTF-8) before performing any counting. Leftover bytes, not part -- of a valid UTF-8 character, are yielded as surplus ----- Note the use of joinI. 'ET.decode' is an enumeratee, which means it returns--- an iteratee yielding an inner step. 'joinI' "collapses" an enumeratee's--- return value, much as 'join' does to monadic values.+-- Note the use of (=$). This lets an enumeratee send data directly to an+-- iteratee, without worrying about leftover input. -iterChars :: Monad m => Iteratee B.ByteString m Integer-iterChars = joinI (ET.decode ET.utf8 $$ count) where- count = ET.fold (\acc _ -> acc + 1) 0+iterChars :: Monad m => Iteratee ByteString m Integer+iterChars = Text.decode Text.utf8 =$ Text.fold (\acc _ -> acc + 1) 0 main :: IO () main = do@@ -60,9 +58,9 @@ OptionChars -> iterChars forM_ files $ \filename -> do- putStr $ filename ++ ": "+ putStr (filename ++ ": ") - eitherStat <- run (EB.enumFile filename $$ iter)+ eitherStat <- run (Binary.enumFile filename $$ iter) putStrLn $ case eitherStat of Left err -> "ERROR: " ++ show err Right stat -> show stat
lib/Data/Enumerator.hs view
@@ -6,9 +6,7 @@ -- Maintainer: jmillikin@gmail.com -- Portability: portable ----- Core enumerator types, and some useful primitives.------ This module is intended to be imported qualified:+-- For compatibility reasons, this module should imported qualified: -- -- @ -- import qualified Data.Enumerator as E@@ -17,18 +15,18 @@ ( -- * Types- Stream (..)- , Iteratee (..)- , Step (..)+ Iteratee , Enumerator , Enumeratee - -- * Primitives- , returnI- , continue- , yield+ -- * Running iteratees+ , run+ , run_ - -- ** Operators+ -- * Operators+ -- | Compatibility note: Most of these will be obsoleted by+ -- version 0.5. Please make sure your @.cabal@ files have a+ -- @<0.5@ limit on the @enumerator@ dependency. , (>>==) , (==<<) , ($$)@@ -37,11 +35,7 @@ , (=$) , ($=) - -- ** Running iteratees- , run- , run_- - -- ** Error handling+ -- * Error handling , throwError , catchError @@ -50,222 +44,55 @@ , joinI , joinE , Data.Enumerator.sequence- , enumEOF- , checkContinue0- , checkContinue1- , checkDoneEx- , checkDone , isEOF , tryIO+ , liftTrans - -- ** Testing and debugging+ -- * Testing and debugging , printChunks , enumList+ , enumLists+ , runLists+ , runLists_ - -- * Legacy compatibility+ -- * Internal interfaces+ -- | This module export will be removed in version 0.5. If you+ -- depend on internal implementation details, please import+ -- @"Data.Enumerator.Internal"@ directly.+ , module Data.Enumerator.Internal - -- ** Obsolete- , liftTrans- , liftI+ -- Obsolete and pointless , peek , Data.Enumerator.last , Data.Enumerator.length - -- ** Aliases- , Data.Enumerator.head- , Data.Enumerator.drop- , Data.Enumerator.dropWhile- , Data.Enumerator.span- , Data.Enumerator.break- , consume- , Data.Enumerator.foldl- , Data.Enumerator.foldl'- , foldM- , Data.Enumerator.iterate- , iterateM- , Data.Enumerator.repeat- , repeatM- , Data.Enumerator.replicate- , replicateM- , generateM- , Data.Enumerator.map- , Data.Enumerator.mapM- , Data.Enumerator.concatMap- , concatMapM- , Data.Enumerator.filter- , filterM- , liftFoldL- , liftFoldL'- , liftFoldM- + -- Legacy compatibility+ -- These legacy compatibility functions will be removed in+ -- version 0.5.+ , module Data.Enumerator.Compatibility ) where -import Control.Applicative as A import qualified Control.Exception as Exc import qualified Control.Monad as CM import Control.Monad.IO.Class (MonadIO, liftIO) import Control.Monad.Trans.Class (MonadTrans, lift)-import Data.Function (fix)+import Data.Functor.Identity (Identity, runIdentity) import Data.List (genericLength, genericSplitAt)-import Data.Monoid (Monoid, mempty, mappend, mconcat)-import Data.Typeable ( Typeable, typeOf- , Typeable1, typeOf1- , mkTyConApp, mkTyCon) -import {-# SOURCE #-} qualified Data.Enumerator.List as EL---- | A 'Stream' is a sequence of chunks generated by an 'Enumerator'.------ @('Chunks' [])@ is used to indicate that a stream is still active, but--- currently has no available data. Iteratees should ignore empty chunks.-data Stream a- = Chunks [a]- | EOF- deriving (Show, Eq)--instance Monad Stream where- return = Chunks . return- Chunks xs >>= f = mconcat (fmap f xs)- EOF >>= _ = EOF--instance Monoid (Stream a) where- mempty = Chunks mempty- mappend (Chunks xs) (Chunks ys) = Chunks (xs ++ ys)- mappend _ _ = EOF--data Step a m b- -- | The 'Iteratee' is capable of accepting more input. Note that more input- -- is not necessarily required; the 'Iteratee' might be able to generate a- -- value immediately if it receives 'EOF'.- = Continue (Stream a -> Iteratee a m b)- - -- | The 'Iteratee' cannot receive any more input, and has generated a- -- result. Included in this value is left-over input, which can be passed to- -- composed 'Iteratee's.- | Yield b (Stream a)- - -- | The 'Iteratee' encountered an error which prevents it from proceeding- -- further.- | Error Exc.SomeException---- | The primary data type for this library, which consumes--- input from a 'Stream' until it either generates a value or encounters--- an error. Rather than requiring all input at once, an iteratee will--- return 'Continue' when it is capable of processing more data.------ In general, iteratees begin in the 'Continue' state. As each chunk is--- passed to the continuation, the iteratee returns the next step:--- 'Continue' for more data, 'Yield' when it's finished, or 'Error' to--- abort processing.-newtype Iteratee a m b = Iteratee- { runIteratee :: m (Step a m b)- }--instance Monad m => Monad (Iteratee a m) where- return x = yield x (Chunks [])-- m0 >>= f = ($ m0) $ fix $- \bind m -> Iteratee $ runIteratee m >>= \r1 ->- case r1 of- Continue k -> return (Continue (bind . k))- Error err -> return (Error err)- Yield x (Chunks []) -> runIteratee (f x)- Yield x extra -> runIteratee (f x) >>= \r2 ->- case r2 of- Continue k -> runIteratee (k extra)- Error err -> return (Error err)- Yield x' _ -> return (Yield x' extra)--instance MonadTrans (Iteratee a) where- lift m = Iteratee (m >>= runIteratee . return)--instance MonadIO m => MonadIO (Iteratee a m) where- liftIO = lift . liftIO---- | While 'Iteratee's consume data, enumerators generate it. Since--- @'Iteratee'@ is an alias for @m ('Step' a m b)@, 'Enumerator's can--- be considered step transformers of type--- @'Step' a m b -> m ('Step' a m b)@.------ 'Enumerator's typically read from an external source (parser, handle,--- random generator, etc). They feed chunks into an 'Iteratee' until the--- source runs out of data (triggering 'EOF') or the iteratee finishes--- processing ('Yield's a value).-type Enumerator a m b = Step a m b -> Iteratee a m b---- | In cases where an enumerator acts as both a source and sink, the resulting--- type is named an 'Enumeratee'. Enumeratees have two input types,--- “outer a” (@aOut@) and “inner a” (@aIn@).-type Enumeratee ao ai m b = Step ai m b -> Iteratee ao m (Step ai m b)---- | Since: 0.4.8-instance Typeable1 Stream where- typeOf1 _ = mkTyConApp tyCon [] where- tyCon = mkTyCon "Data.Enumerator.Stream"---- | Since: 0.4.6-instance (Typeable a, Typeable1 m) =>- Typeable1 (Iteratee a m) where- typeOf1 i = let- tyCon = mkTyCon "Data.Enumerator.Iteratee"- (a, m) = peel i- - peel :: Iteratee a m b -> (a, m ())- peel = undefined- - in mkTyConApp tyCon [typeOf a, typeOf1 m]---- | Since: 0.4.8-instance (Typeable a, Typeable1 m) =>- Typeable1 (Step a m) where- typeOf1 s = let- tyCon = mkTyCon "Data.Enumerator.Step"- (a, m) = peel s- - peel :: Step a m b -> (a, m ())- peel = undefined- - in mkTyConApp tyCon [typeOf a, typeOf1 m]--instance Monad m => Functor (Iteratee a m) where- fmap = CM.liftM--instance Monad m => A.Applicative (Iteratee a m) where- pure = return- (<*>) = CM.ap--instance Functor Stream where- fmap f (Chunks xs) = Chunks (fmap f xs)- fmap _ EOF = EOF---- | Since: 0.4.5-instance A.Applicative Stream where- pure = return- (<*>) = CM.ap---- | @'returnI' step = 'Iteratee' (return step)@-returnI :: Monad m => Step a m b -> Iteratee a m b-returnI step = Iteratee (return step)---- | @'yield' x extra = 'returnI' ('Yield' x extra)@------ WARNING: due to the current encoding of iteratees in this library,--- careless use of the 'yield' primitive may violate the monad laws.--- To prevent this, always make sure that an iteratee never yields--- extra data unless it has received at least one input element.------ More strictly, iteratees may not yield data that they did not--- receive as input. Don't use 'yield' to “inject” elements--- into the stream.-yield :: Monad m => b -> Stream a -> Iteratee a m b-yield x extra = returnI (Yield x extra)---- | @'continue' k = 'returnI' ('Continue' k)@-continue :: Monad m => (Stream a -> Iteratee a m b) -> Iteratee a m b-continue k = returnI (Continue k)+import Data.Enumerator.Compatibility+import Data.Enumerator.Internal -- | Run an iteratee until it finishes, and return either the final value -- (if it succeeded) or the error (if it failed).+--+-- > import Data.Enumerator+-- > import Data.Enumerator.List as EL+-- >+-- > main = do+-- > result <- run (EL.iterate succ 'A' $$ EL.take 5)+-- > case result of+-- > Left exc -> putStrLn ("Got an exception: " ++ show exc)+-- > Right chars -> putStrLn ("Got characters: " ++ show chars) run :: Monad m => Iteratee a m b -> m (Either Exc.SomeException b) run i = do@@ -278,11 +105,18 @@ -- | Like 'run', except errors are converted to exceptions and thrown. -- Primarily useful for small scripts or other simple cases. --+-- > import Data.Enumerator+-- > import Data.Enumerator.List as EL+-- >+-- > main = do+-- > chars <- run_ (EL.iterate succ 'A' $$ EL.take 5)+-- > putStrLn ("Got characters: " ++ show chars)+-- -- Since: 0.4.1 run_ :: Monad m => Iteratee a m b -> m b run_ i = run i >>= either Exc.throw return --- | @'throwError' exc = 'returnI' ('Error' ('Exc.toException' exc))@+-- | The moral equivalent of 'Exc.throwIO' for iteratees. throwError :: (Monad m, Exc.Exception e) => e -> Iteratee a m b throwError exc = returnI (Error (Exc.toException exc)) @@ -291,15 +125,12 @@ -- all errors to be represented by 'Exc.SomeException', libraries with -- varying error types can be easily composed. ----- WARNING: after a few rounds of "catchError doesn't work because X", this--- function has grown into a horrible monster. I have no concept of what--- unexpected behaviors lurk in its dark crevices. Users are strongly advised--- to wrap all uses of @catchError@ with an appropriate @isolate@, such as--- @Data.Enumerator.List.isolate@ or @Data.Enumerator.Binary.isolate@, which--- will handle input framing even in the face of unexpected errors.------ Within the error handler, it is difficult or impossible to know how much--- input the original iteratee has consumed.+-- WARNING: Within the error handler, it is difficult or impossible to know+-- how much input the original iteratee has consumed. Users are strongly+-- advised to wrap all uses of @catchError@ with an appropriate isolation+-- enumeratee, such as @Data.Enumerator.List.isolate@ or+-- @Data.Enumerator.Binary.isolate@, which will handle input framing even+-- in the face of unexpected errors. -- -- Since: 0.1.1 catchError :: Monad m@@ -331,61 +162,6 @@ _ -> return step' Continue k' -> return (Continue (wrap k')) -infixl 1 >>==-infixr 1 ==<<-infixr 0 $$-infixr 1 >==>-infixr 1 <==<---- | Equivalent to '(>>=)' for @m ('Step' a m b)@; allows 'Iteratee's with--- different input types to be composed.--(>>==) :: Monad m- => Iteratee a m b- -> (Step a m b -> Iteratee a' m b')- -> Iteratee a' m b'-i >>== f = Iteratee (runIteratee i >>= runIteratee . f)---- | @'(==\<\<)' = flip '(\>\>==)'@-(==<<) :: Monad m- => (Step a m b -> Iteratee a' m b')- -> Iteratee a m b- -> Iteratee a' m b'-(==<<) = flip (>>==)---- | @'($$)' = '(==\<\<)'@------ This might be easier to read when passing a chain of iteratees to an--- enumerator.------ Since: 0.1.1-($$) :: Monad m- => (Step a m b -> Iteratee a' m b')- -> Iteratee a m b- -> Iteratee a' m b'-($$) = (==<<)---- | @'(>==>)' e1 e2 s = e1 s '>>==' e2@------ Since: 0.1.1-(>==>) :: Monad m- => Enumerator a m b- -> (Step a m b -> Iteratee a' m b')- -> Step a m b- -> Iteratee a' m b'-(>==>) e1 e2 s = e1 s >>== e2---- | @'(\<==\<)' = flip '(>==>)'@------ Since: 0.1.1--(<==<) :: Monad m- => (Step a m b -> Iteratee a' m b')- -> Enumerator a m b- -> Step a m b- -> Iteratee a' m b'-(<==<) = flip (>==>)- -- | Print chunks as they're received from the enumerator, optionally -- printing empty chunks. printChunks :: (MonadIO m, Show a)@@ -402,9 +178,13 @@ yield () EOF -- | @'enumList' n xs@ enumerates /xs/ as a stream, passing /n/ inputs per--- chunk.+-- chunk. This is primarily useful for testing, debugging, and REPL+-- exploration. ----- Primarily useful for testing and debugging.+-- Compatibility note: In version 0.5, 'enumList' will be changed to the+-- type:+--+-- > enumList :: Monad m => [a] -> Enumerator a m b enumList :: Monad m => Integer -> [a] -> Enumerator a m b enumList n = loop where loop xs (Continue k) | not (null xs) = let@@ -412,14 +192,39 @@ in k (Chunks s1) >>== loop s2 loop _ step = returnI step +-- | @'enumLists' xs@ enumerates /xs/ as a stream, where each element is a+-- separate chunk. This is primarily useful for testing and debugging.+--+-- Since: 0.4.15+enumLists :: Monad m => [[a]] -> Enumerator a m b+enumLists (xs:xss) (Continue k) = k (Chunks xs) >>== enumLists xss+enumLists _ step = returnI step --- | Compose a list of 'Enumerator's using @'(>>==)'@+-- | Run an iteratee with the given input, and return either the final value+-- (if it succeeded) or the error (if it failed).+--+-- Since: 0.4.15+runLists :: [[a]] -> Iteratee a Identity b -> Either Exc.SomeException b+runLists lists iter = runIdentity (run (enumLists lists $$ iter))++-- | Like 'runLists', except errors are converted to exceptions and thrown.+--+-- Since: 0.4.15+runLists_ :: [[a]] -> Iteratee a Identity b -> b+runLists_ lists iter = runIdentity (run_ (enumLists lists $$ iter))++-- | Compose a list of 'Enumerator's using @('>==>').@ concatEnums :: Monad m => [Enumerator a m b] -> Enumerator a m b concatEnums = Prelude.foldl (>==>) returnI --- | 'joinI' is used to “flatten” 'Enumeratee's into an--- 'Iteratee'.+-- | “Wraps” an iteratee /inner/ in an enumeratee /wrapper/.+-- The resulting iteratee will consume /wrapper/’s input type and+-- yield /inner/’s output type.+--+-- See the documentation for ('=$').+--+-- @joinI (enum $$ iter) = enum =$ iter@ joinI :: Monad m => Iteratee a m (Step a' m b) -> Iteratee a m b joinI outer = outer >>= check where@@ -431,9 +236,7 @@ infixr 0 =$ --- | @enum =$ iter = 'joinI' (enum $$ iter)@------ “Wraps” an iteratee /inner/ in an enumeratee /wrapper/.+-- | “Wraps” an iteratee /inner/ in an enumeratee /wrapper/. -- The resulting iteratee will consume /wrapper/’s input type and -- yield /inner/’s output type. --@@ -441,11 +244,11 @@ -- that extra will be discarded. -- -- As an example, consider an iteratee that converts a stream of UTF8-encoded--- bytes into a single 'TL.Text':+-- bytes into a single @Text@: -- -- > consumeUTF8 :: Monad m => Iteratee ByteString m Text ----- It could be written with either 'joinI' or '(=$)':+-- It could be written with either 'joinI' or @(=$)@: -- -- > import Data.Enumerator.Text as ET -- >@@ -456,7 +259,14 @@ (=$) :: Monad m => Enumeratee ao ai m b -> Iteratee ai m b -> Iteratee ao m b enum =$ iter = joinI (enum $$ iter) --- | Flatten an enumerator/enumeratee pair into a single enumerator.+-- | “Wraps” an enumerator /inner/ in an enumeratee /wrapper/.+-- The resulting enumerator will generate /wrapper/’s output type.+--+-- See the documentation for ('$=').+--+-- @joinE enum enee = enum $= enee@+--+-- Since: 0.4.5 joinE :: Monad m => Enumerator ao m (Step ai m b) -> Enumeratee ao ai m b@@ -468,11 +278,9 @@ Yield x _ -> return x Continue _ -> error "joinE: divergent iteratee" -infixr 0 $=+infixl 1 $= --- | @enum $= enee = 'joinE' enum enee@------ “Wraps” an enumerator /inner/ in an enumeratee /wrapper/.+-- | “Wraps” an enumerator /inner/ in an enumeratee /wrapper/. -- The resulting enumerator will generate /wrapper/’s output type. -- -- As an example, consider an enumerator that yields line character counts@@ -480,7 +288,7 @@ -- -- > enumFileCounts :: FilePath -> Enumerator Int IO b ----- It could be written with either 'joinE' or '($=)':+-- It could be written with either 'joinE' or @($=)@: -- -- > import Data.Text as T -- > import Data.Enumerator.List as EL@@ -489,6 +297,9 @@ -- > enumFileCounts path = joinE (enumFile path) (EL.map T.length) -- > enumFileCounts path = enumFile path $= EL.map T.length --+-- Compatibility note: in version 0.4.15, the associativity of @($=)@ was+-- changed from @infixr 0@ to @infixl 1@.+-- -- Since: 0.4.9 ($=) :: Monad m => Enumerator ao m (Step ai m b)@@ -507,45 +318,15 @@ else step k step k = i >>= \v -> k (Chunks [v]) >>== loop --- | Sends 'EOF' to its iteratee. Most clients should use 'run' or 'run_'--- instead.-enumEOF :: Monad m => Enumerator a m b-enumEOF (Yield x _) = yield x EOF-enumEOF (Error err) = throwError err-enumEOF (Continue k) = k EOF >>== check where- check (Continue _) = error "enumEOF: divergent iteratee"- check s = enumEOF s---- | A common pattern in 'Enumeratee' implementations is to check whether--- the inner 'Iteratee' has finished, and if so, to return its output.--- 'checkDone' passes its parameter a continuation if the 'Iteratee'--- can still consume input, or yields otherwise.------ Since: 0.4.3-checkDoneEx :: Monad m =>- Stream a' ->- ((Stream a -> Iteratee a m b) -> Iteratee a' m (Step a m b)) ->- Enumeratee a' a m b-checkDoneEx _ f (Continue k) = f k-checkDoneEx extra _ step = yield step extra---- | @'checkDone' = 'checkDoneEx' ('Chunks' [])@------ Use this for enumeratees which do not have an input buffer.-checkDone :: Monad m =>- ((Stream a -> Iteratee a m b) -> Iteratee a' m (Step a m b)) ->- Enumeratee a' a m b-checkDone = checkDoneEx (Chunks [])---- | Check whether a stream has reached EOF. Most clients should use--- 'Data.Enumerator.List.head' instead.+-- | Check whether a stream has reached EOF. Note that if the stream is not+-- at EOF, @isEOF@ may cause data to be read from the enumerator. isEOF :: Monad m => Iteratee a m Bool isEOF = continue $ \s -> case s of EOF -> yield True s _ -> yield False s -- | Try to run an IO computation. If it throws an exception, the exception--- is caught and converted into an {\tt Error}.+-- is caught and passed to 'throwError'. -- -- Since: 0.4.9 tryIO :: MonadIO m => IO b -> Iteratee a m b@@ -555,54 +336,8 @@ Right b -> Yield b (Chunks []) Left err -> Error err --- | A common pattern in 'Enumerator' implementations is to check whether--- the inner 'Iteratee' has finished, and if so, to return its output.--- 'checkContinue0' passes its parameter a continuation if the 'Iteratee'--- can still consume input; if not, it returns the iteratee's step.------ The type signature here is a bit crazy, but it's actually very easy to--- use. Take this code:------ > repeat :: Monad m => a -> Enumerator a m b--- > repeat x = loop where--- > loop (Continue k) = k (Chunks [x]) >>== loop--- > loop step = returnI step------ And rewrite it without the boilerplate:------ > repeat :: Monad m => a -> Enumerator a m b--- > repeat x = checkContinue0 $ \loop k -> k (Chunks [x] >>== loop------ Since: 0.4.9-checkContinue0 :: Monad m- => (Enumerator a m b- -> (Stream a -> Iteratee a m b)- -> Iteratee a m b)- -> Enumerator a m b-checkContinue0 inner = loop where- loop (Continue k) = inner loop k- loop step = returnI step----- | Like 'checkContinue0', but allows each loop step to use a state value:------ > iterate :: Monad m => (a -> a) -> a -> Enumerator a m b--- > iterate f = checkContinue1 $ \loop a k -> k (Chunks [a]) >>== loop (f a)------ Since: 0.4.9-checkContinue1 :: Monad m- => ((s1 -> Enumerator a m b)- -> s1- -> (Stream a -> Iteratee a m b)- -> Iteratee a m b)- -> s1- -> Enumerator a m b-checkContinue1 inner = loop where- loop s (Continue k) = inner loop s k- loop _ step = returnI step---- | Lift an 'Iteratee' onto a monad transformer, re-wrapping the--- 'Iteratee'’s inner monadic values.+-- | Lift an 'Iteratee' onto a monad transformer, re-wrapping its+-- inner monadic values. -- -- Since: 0.1.1 liftTrans :: (Monad m, MonadTrans t, Monad (t m)) =>@@ -614,13 +349,6 @@ Error err -> Error err Continue k -> Continue (liftTrans . k) -{-# DEPRECATED liftI "Use 'Data.Enumerator.continue' instead" #-}---- | Deprecated in 0.4.5: use 'Data.Enumerator.continue' instead-liftI :: Monad m => (Stream a -> Step a m b)- -> Iteratee a m b-liftI k = continue (returnI . k)- -- | Peek at the next element in the stream, or 'Nothing' if the stream -- has ended. peek :: Monad m => Iteratee a m (Maybe a)@@ -648,172 +376,3 @@ len = genericLength loop n (Chunks xs) = continue (loop (n + len xs)) loop n EOF = yield n EOF--{-# DEPRECATED head "Use 'Data.Enumerator.List.head' instead" #-}--- | Deprecated in 0.4.5: use 'Data.Enumerator.List.head' instead-head :: Monad m => Iteratee a m (Maybe a)-head = EL.head--{-# DEPRECATED drop "Use 'Data.Enumerator.List.drop' instead" #-}--- | Deprecated in 0.4.5: use 'Data.Enumerator.List.drop' instead-drop :: Monad m => Integer -> Iteratee a m ()-drop = EL.drop--{-# DEPRECATED dropWhile "Use 'Data.Enumerator.List.dropWhile' instead" #-}--- | Deprecated in 0.4.5: use 'Data.Enumerator.List.dropWhile' instead-dropWhile :: Monad m => (a -> Bool) -> Iteratee a m ()-dropWhile = EL.dropWhile--{-# DEPRECATED span "Use 'Data.Enumerator.List.takeWhile' instead" #-}--- | Deprecated in 0.4.5: use 'Data.Enumerator.List.takeWhile' instead-span :: Monad m => (a -> Bool) -> Iteratee a m [a]-span = EL.takeWhile--{-# DEPRECATED break "Use 'Data.Enumerator.List.takeWhile' instead" #-}--- | Deprecated in 0.4.5: use 'Data.Enumerator.List.takeWhile' instead-break :: Monad m => (a -> Bool) -> Iteratee a m [a]-break p = EL.takeWhile (not . p)--{-# DEPRECATED consume "Use 'Data.Enumerator.List.consume' instead" #-}--- | Deprecated in 0.4.5: use 'Data.Enumerator.List.consume' instead-consume :: Monad m => Iteratee a m [a]-consume = EL.consume--{-# DEPRECATED foldl "Use Data.Enumerator.List.fold instead" #-}--- | Deprecated in 0.4.8: use 'Data.Enumerator.List.fold' instead------ Since: 0.4.5-foldl :: Monad m => (b -> a -> b) -> b -> Iteratee a m b-foldl step = continue . loop where- fold = Prelude.foldl step- loop acc stream = case stream of- Chunks [] -> continue (loop acc)- Chunks xs -> continue (loop (fold acc xs))- EOF -> yield acc EOF--{-# DEPRECATED foldl' "Use Data.Enumerator.List.fold instead" #-}--- | Deprecated in 0.4.8: use 'Data.Enumerator.List.fold' instead------ Since: 0.4.5-foldl' :: Monad m => (b -> a -> b) -> b -> Iteratee a m b-foldl' = EL.fold--{-# DEPRECATED foldM "Use Data.Enumerator.List.foldM instead" #-}--- | Deprecated in 0.4.8: use 'Data.Enumerator.List.foldM' instead------ Since: 0.4.5-foldM :: Monad m => (b -> a -> m b) -> b -> Iteratee a m b-foldM = EL.foldM--{-# DEPRECATED iterate "Use Data.Enumerator.List.iterate instead" #-}--- | Deprecated in 0.4.8: use 'Data.Enumerator.List.iterate' instead------ Since: 0.4.5-iterate :: Monad m => (a -> a) -> a -> Enumerator a m b-iterate = EL.iterate--{-# DEPRECATED iterateM "Use Data.Enumerator.List.iterateM instead" #-}--- | Deprecated in 0.4.8: use 'Data.Enumerator.List.iterateM' instead------ Since: 0.4.5-iterateM :: Monad m => (a -> m a) -> a -> Enumerator a m b-iterateM = EL.iterateM--{-# DEPRECATED repeat "Use Data.Enumerator.List.repeat instead" #-}--- | Deprecated in 0.4.8: use 'Data.Enumerator.List.repeat' instead------ Since: 0.4.5-repeat :: Monad m => a -> Enumerator a m b-repeat = EL.repeat--{-# DEPRECATED repeatM "Use Data.Enumerator.List.repeatM instead" #-}--- | Deprecated in 0.4.8: use 'Data.Enumerator.List.repeatM' instead------ Since: 0.4.5-repeatM :: Monad m => m a -> Enumerator a m b-repeatM = EL.repeatM--{-# DEPRECATED replicate "Use Data.Enumerator.List.replicate instead" #-}--- | Deprecated in 0.4.8: use 'Data.Enumerator.List.replicate' instead------ Since: 0.4.5-replicate :: Monad m => Integer -> a -> Enumerator a m b-replicate = EL.replicate--{-# DEPRECATED replicateM "Use Data.Enumerator.List.replicateM instead" #-}--- | Deprecated in 0.4.8: use 'Data.Enumerator.List.replicateM' instead------ Since: 0.4.5-replicateM :: Monad m => Integer -> m a -> Enumerator a m b-replicateM = EL.replicateM--{-# DEPRECATED generateM "Use Data.Enumerator.List.generateM instead" #-}--- | Deprecated in 0.4.8: use 'Data.Enumerator.List.generateM' instead------ Since: 0.4.5-generateM :: Monad m => m (Maybe a) -> Enumerator a m b-generateM = EL.generateM--{-# DEPRECATED map "Use Data.Enumerator.List.map instead" #-}--- | Deprecated in 0.4.8: use 'Data.Enumerator.List.map' instead-map :: Monad m => (ao -> ai) -> Enumeratee ao ai m b-map = EL.map--{-# DEPRECATED mapM "Use Data.Enumerator.List.mapM instead" #-}--- | Deprecated in 0.4.8: use 'Data.Enumerator.List.mapM' instead------ Since: 0.4.3-mapM :: Monad m => (ao -> m ai) -> Enumeratee ao ai m b-mapM = EL.mapM--{-# DEPRECATED concatMap "Use Data.Enumerator.List.concatMap instead" #-}--- | Deprecated in 0.4.8: use 'Data.Enumerator.List.concatMap' instead------ Since: 0.4.3-concatMap :: Monad m => (ao -> [ai]) -> Enumeratee ao ai m b-concatMap = EL.concatMap--{-# DEPRECATED concatMapM "Use Data.Enumerator.List.concatMapM instead" #-}--- | Deprecated in 0.4.8: use 'Data.Enumerator.List.concatMapM' instead------ Since: 0.4.5-concatMapM :: Monad m => (ao -> m [ai]) -> Enumeratee ao ai m b-concatMapM = EL.concatMapM--{-# DEPRECATED filter "Use Data.Enumerator.List.filter instead" #-}--- | Deprecated in 0.4.8: use 'Data.Enumerator.List.filter' instead------ Since: 0.4.5-filter :: Monad m => (a -> Bool) -> Enumeratee a a m b-filter = EL.filter--{-# DEPRECATED filterM "Use Data.Enumerator.List.filterM instead" #-}--- | Deprecated in 0.4.8: use 'Data.Enumerator.List.filterM' instead------ Since: 0.4.5-filterM :: Monad m => (a -> m Bool) -> Enumeratee a a m b-filterM = EL.filterM--{-# DEPRECATED liftFoldL "Use Data.Enumerator.List.fold instead" #-}--- | Deprecated in 0.4.5: use 'Data.Enumerator.List.fold' instead------ Since: 0.1.1-liftFoldL :: Monad m => (b -> a -> b) -> b- -> Iteratee a m b-liftFoldL = Data.Enumerator.foldl--{-# DEPRECATED liftFoldL' "Use Data.Enumerator.List.fold instead" #-}--- | Deprecated in 0.4.5: use 'Data.Enumerator.List.fold' instead------ Since: 0.1.1-liftFoldL' :: Monad m => (b -> a -> b) -> b- -> Iteratee a m b-liftFoldL' = EL.fold--{-# DEPRECATED liftFoldM "Use Data.Enumerator.List.foldM instead" #-}--- | Deprecated in 0.4.5: use 'Data.Enumerator.List.foldM' instead------ Since: 0.1.1-liftFoldM :: Monad m => (b -> a -> m b) -> b- -> Iteratee a m b-liftFoldM = EL.foldM
lib/Data/Enumerator/Binary.hs view
@@ -108,9 +108,8 @@ import qualified System.IO as IO import System.IO.Error (isEOFError) -import Data.Enumerator hiding ( head, drop, iterateM, repeatM, replicateM- , generateM, filterM, consume, foldM- , concatMapM)+import Data.Enumerator.Internal+import Data.Enumerator (isEOF, throwError, tryIO) import qualified Data.Enumerator.List as EL -- | Consume the entire input stream with a strict left fold, one byte@@ -194,7 +193,7 @@ loop k (x:xs) = do fx <- lift (f x) k (Chunks [fx]) >>==- checkDoneEx (Chunks [B.pack xs]) (\k' -> loop k' xs)+ checkDoneEx (Chunks [B.pack xs]) (`loop` xs) -- | Similar to 'Data.Enumerator.Binary.concatMap', but with a stateful step -- function.@@ -326,7 +325,7 @@ len = toInteger (BL.length lazy) iter = if len < n'- then continue (loop (acc . (BL.append lazy)) (n' - len))+ then continue (loop (acc . BL.append lazy) (n' - len)) else let (xs', extra) = BL.splitAt (fromInteger n') lazy in yield (acc xs') (toChunks extra)@@ -343,7 +342,7 @@ lazy = BL.fromChunks xs (xs', extra) = BL.span p lazy iter = if BL.null extra- then continue (loop (acc . (BL.append lazy)))+ then continue (loop (acc . BL.append lazy)) else yield (acc xs') (toChunks extra) loop acc EOF = yield (acc BL.empty) EOF @@ -355,7 +354,7 @@ loop acc (Chunks []) = continue (loop acc) loop acc (Chunks xs) = iter where lazy = BL.fromChunks xs- iter = continue (loop (acc . (BL.append lazy)))+ iter = continue (loop (acc . BL.append lazy)) loop acc EOF = yield (acc BL.empty) EOF -- | Pass input from a stream through two iteratees at once. Excess input is@@ -665,7 +664,7 @@ lazy = BL.fromChunks xs len = toInteger (BL.length lazy) iter = if len < n'- then continue (loop (acc . (BL.append lazy)) (n' - len))+ then continue (loop (acc . BL.append lazy) (n' - len)) else yield () (toChunks (acc lazy)) loop _ _ EOF = throwError (Exc.ErrorCall "require: Unexpected EOF") @@ -686,8 +685,8 @@ then k (Chunks xs) >>== isolate (n - len) else let (s1, s2) = BL.splitAt (fromInteger n) lazy- in k (toChunks s1) >>== (\step -> yield step (toChunks s2))- loop EOF = k EOF >>== (\step -> yield step EOF)+ in k (toChunks s1) >>== (`yield` toChunks s2)+ loop EOF = k EOF >>== (`yield` EOF) isolate n step = drop n >> return step -- | Split on bytes satisfying a given predicate.@@ -774,7 +773,7 @@ if B.null bytes then continue k else feed bytes- feed bs = k (Chunks [bs]) >>== loop (n - (toInteger (B.length bs)))+ feed bs = k (Chunks [bs]) >>== loop (n - toInteger (B.length bs)) in if rem <= 0 then continue k else keepGoing
+ lib/Data/Enumerator/Compatibility.hs view
@@ -0,0 +1,219 @@+-- |+-- Module: Data.Enumerator.Compatibility+-- Copyright: 2010-2011 John Millikin+-- License: MIT+--+-- Maintainer: jmillikin@gmail.com+-- Portability: portable+--+-- Shims for compatibility with earlier versions of the Enumerator library.+module Data.Enumerator.Compatibility+ ( liftI+ , head+ , drop+ , dropWhile+ , span+ , break+ , consume+ , foldl+ , foldl'+ , foldM+ , iterate+ , iterateM+ , repeat+ , repeatM+ , replicate+ , replicateM+ , generateM+ , map+ , mapM+ , concatMap+ , concatMapM+ , filter+ , filterM+ , liftFoldL+ , liftFoldL'+ , liftFoldM+ + ) where++import qualified Prelude+import Prelude (Bool, Integer, Maybe, Monad, not, (.))++import Data.Enumerator.Internal+import {-# SOURCE #-} qualified Data.Enumerator.List as EL++{-# DEPRECATED liftI "Use 'Data.Enumerator.continue' instead" #-}+-- | Deprecated in 0.4.5: use 'Data.Enumerator.continue' instead+liftI :: Monad m => (Stream a -> Step a m b)+ -> Iteratee a m b+liftI k = continue (returnI . k)++{-# DEPRECATED head "Use 'Data.Enumerator.List.head' instead" #-}+-- | Deprecated in 0.4.5: use 'Data.Enumerator.List.head' instead+head :: Monad m => Iteratee a m (Maybe a)+head = EL.head++{-# DEPRECATED drop "Use 'Data.Enumerator.List.drop' instead" #-}+-- | Deprecated in 0.4.5: use 'Data.Enumerator.List.drop' instead+drop :: Monad m => Integer -> Iteratee a m ()+drop = EL.drop++{-# DEPRECATED dropWhile "Use 'Data.Enumerator.List.dropWhile' instead" #-}+-- | Deprecated in 0.4.5: use 'Data.Enumerator.List.dropWhile' instead+dropWhile :: Monad m => (a -> Bool) -> Iteratee a m ()+dropWhile = EL.dropWhile++{-# DEPRECATED span "Use 'Data.Enumerator.List.takeWhile' instead" #-}+-- | Deprecated in 0.4.5: use 'Data.Enumerator.List.takeWhile' instead+span :: Monad m => (a -> Bool) -> Iteratee a m [a]+span = EL.takeWhile++{-# DEPRECATED break "Use 'Data.Enumerator.List.takeWhile' instead" #-}+-- | Deprecated in 0.4.5: use 'Data.Enumerator.List.takeWhile' instead+break :: Monad m => (a -> Bool) -> Iteratee a m [a]+break p = EL.takeWhile (not . p)++{-# DEPRECATED consume "Use 'Data.Enumerator.List.consume' instead" #-}+-- | Deprecated in 0.4.5: use 'Data.Enumerator.List.consume' instead+consume :: Monad m => Iteratee a m [a]+consume = EL.consume++{-# DEPRECATED foldl "Use Data.Enumerator.List.fold instead" #-}+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.fold' instead+--+-- Since: 0.4.5+foldl :: Monad m => (b -> a -> b) -> b -> Iteratee a m b+foldl step = continue . loop where+ fold = Prelude.foldl step+ loop acc stream = case stream of+ Chunks [] -> continue (loop acc)+ Chunks xs -> continue (loop (fold acc xs))+ EOF -> yield acc EOF++{-# DEPRECATED foldl' "Use Data.Enumerator.List.fold instead" #-}+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.fold' instead+--+-- Since: 0.4.5+foldl' :: Monad m => (b -> a -> b) -> b -> Iteratee a m b+foldl' = EL.fold++{-# DEPRECATED foldM "Use Data.Enumerator.List.foldM instead" #-}+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.foldM' instead+--+-- Since: 0.4.5+foldM :: Monad m => (b -> a -> m b) -> b -> Iteratee a m b+foldM = EL.foldM++{-# DEPRECATED iterate "Use Data.Enumerator.List.iterate instead" #-}+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.iterate' instead+--+-- Since: 0.4.5+iterate :: Monad m => (a -> a) -> a -> Enumerator a m b+iterate = EL.iterate++{-# DEPRECATED iterateM "Use Data.Enumerator.List.iterateM instead" #-}+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.iterateM' instead+--+-- Since: 0.4.5+iterateM :: Monad m => (a -> m a) -> a -> Enumerator a m b+iterateM = EL.iterateM++{-# DEPRECATED repeat "Use Data.Enumerator.List.repeat instead" #-}+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.repeat' instead+--+-- Since: 0.4.5+repeat :: Monad m => a -> Enumerator a m b+repeat = EL.repeat++{-# DEPRECATED repeatM "Use Data.Enumerator.List.repeatM instead" #-}+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.repeatM' instead+--+-- Since: 0.4.5+repeatM :: Monad m => m a -> Enumerator a m b+repeatM = EL.repeatM++{-# DEPRECATED replicate "Use Data.Enumerator.List.replicate instead" #-}+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.replicate' instead+--+-- Since: 0.4.5+replicate :: Monad m => Integer -> a -> Enumerator a m b+replicate = EL.replicate++{-# DEPRECATED replicateM "Use Data.Enumerator.List.replicateM instead" #-}+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.replicateM' instead+--+-- Since: 0.4.5+replicateM :: Monad m => Integer -> m a -> Enumerator a m b+replicateM = EL.replicateM++{-# DEPRECATED generateM "Use Data.Enumerator.List.generateM instead" #-}+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.generateM' instead+--+-- Since: 0.4.5+generateM :: Monad m => m (Maybe a) -> Enumerator a m b+generateM = EL.generateM++{-# DEPRECATED map "Use Data.Enumerator.List.map instead" #-}+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.map' instead+map :: Monad m => (ao -> ai) -> Enumeratee ao ai m b+map = EL.map++{-# DEPRECATED mapM "Use Data.Enumerator.List.mapM instead" #-}+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.mapM' instead+--+-- Since: 0.4.3+mapM :: Monad m => (ao -> m ai) -> Enumeratee ao ai m b+mapM = EL.mapM++{-# DEPRECATED concatMap "Use Data.Enumerator.List.concatMap instead" #-}+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.concatMap' instead+--+-- Since: 0.4.3+concatMap :: Monad m => (ao -> [ai]) -> Enumeratee ao ai m b+concatMap = EL.concatMap++{-# DEPRECATED concatMapM "Use Data.Enumerator.List.concatMapM instead" #-}+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.concatMapM' instead+--+-- Since: 0.4.5+concatMapM :: Monad m => (ao -> m [ai]) -> Enumeratee ao ai m b+concatMapM = EL.concatMapM++{-# DEPRECATED filter "Use Data.Enumerator.List.filter instead" #-}+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.filter' instead+--+-- Since: 0.4.5+filter :: Monad m => (a -> Bool) -> Enumeratee a a m b+filter = EL.filter++{-# DEPRECATED filterM "Use Data.Enumerator.List.filterM instead" #-}+-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.filterM' instead+--+-- Since: 0.4.5+filterM :: Monad m => (a -> m Bool) -> Enumeratee a a m b+filterM = EL.filterM++{-# DEPRECATED liftFoldL "Use Data.Enumerator.List.fold instead" #-}+-- | Deprecated in 0.4.5: use 'Data.Enumerator.List.fold' instead+--+-- Since: 0.1.1+liftFoldL :: Monad m => (b -> a -> b) -> b+ -> Iteratee a m b+liftFoldL = foldl++{-# DEPRECATED liftFoldL' "Use Data.Enumerator.List.fold instead" #-}+-- | Deprecated in 0.4.5: use 'Data.Enumerator.List.fold' instead+--+-- Since: 0.1.1+liftFoldL' :: Monad m => (b -> a -> b) -> b+ -> Iteratee a m b+liftFoldL' = EL.fold++{-# DEPRECATED liftFoldM "Use Data.Enumerator.List.foldM instead" #-}+-- | Deprecated in 0.4.5: use 'Data.Enumerator.List.foldM' instead+--+-- Since: 0.1.1+liftFoldM :: Monad m => (b -> a -> m b) -> b+ -> Iteratee a m b+liftFoldM = EL.foldM
lib/Data/Enumerator/IO.hs view
@@ -1,3 +1,5 @@+{-# OPTIONS_HADDOCK hide #-}+ -- | -- Module: Data.Enumerator.IO -- Copyright: 2010-2011 John Millikin
+ lib/Data/Enumerator/Internal.hs view
@@ -0,0 +1,342 @@+-- |+-- Module: Data.Enumerator.Internal+-- Copyright: 2010-2011 John Millikin+-- License: MIT+--+-- Maintainer: jmillikin@gmail.com+-- Portability: portable+--+-- Core enumerator types, and some useful primitives.+--+-- Be careful when using the functions defined in this module, as they will+-- allow you to create iteratees which violate the monad laws.+module Data.Enumerator.Internal+ ( Stream (..)+ , Iteratee (..)+ , Step (..)+ , Enumerator+ , Enumeratee+ + -- * Primitives+ , returnI+ , continue+ , yield+ + -- * Operators+ , (>>==)+ , (==<<)+ , ($$)+ , (>==>)+ , (<==<)+ + -- * Miscellaneous+ , enumEOF+ , checkContinue0+ , checkContinue1+ , checkDoneEx+ , checkDone+ + ) where++import Control.Applicative as A+import qualified Control.Exception as Exc+import qualified Control.Monad as CM+import Control.Monad.IO.Class (MonadIO, liftIO)+import Control.Monad.Trans.Class (MonadTrans, lift)+import Data.Function (fix)+import Data.Monoid (Monoid, mempty, mappend, mconcat)+import Data.Typeable ( Typeable, typeOf+ , Typeable1, typeOf1+ , mkTyConApp, mkTyCon)++-- | A 'Stream' is a sequence of chunks generated by an 'Enumerator'.+--+-- @('Chunks' [])@ is used to indicate that a stream is still active, but+-- currently has no available data. Iteratees should ignore empty chunks.+data Stream a+ = Chunks [a]+ | EOF+ deriving (Show, Eq)++instance Monad Stream where+ return = Chunks . return+ Chunks xs >>= f = mconcat (fmap f xs)+ EOF >>= _ = EOF++instance Monoid (Stream a) where+ mempty = Chunks mempty+ mappend (Chunks xs) (Chunks ys) = Chunks (xs ++ ys)+ mappend _ _ = EOF++data Step a m b+ -- | The 'Iteratee' is capable of accepting more input. Note that more input+ -- is not necessarily required; the 'Iteratee' might be able to generate a+ -- value immediately if it receives 'EOF'.+ = Continue (Stream a -> Iteratee a m b)+ + -- | The 'Iteratee' cannot receive any more input, and has generated a+ -- result. Included in this value is left-over input, which can be passed to+ -- composed 'Iteratee's.+ | Yield b (Stream a)+ + -- | The 'Iteratee' encountered an error which prevents it from proceeding+ -- further.+ | Error Exc.SomeException++-- | The primary data type for this library; an iteratee consumes+-- chunks of input from a stream until it either yields a value or+-- encounters an error.+--+-- Compatibility note: @Iteratee@ will become abstract in @enumerator_0.5@. If+-- you depend on internal implementation details, please import+-- @"Data.Enumerator.Internal"@.++-- In general, iteratees begin in the 'Continue' state. As each chunk is+-- passed to the continuation, the iteratee returns the next step:+-- 'Continue' for more data, 'Yield' when it's finished, or 'Error' to+-- abort processing.+newtype Iteratee a m b = Iteratee+ { runIteratee :: m (Step a m b)+ }++instance Monad m => Monad (Iteratee a m) where+ return x = yield x (Chunks [])++ m0 >>= f = ($ m0) $ fix $+ \bind m -> Iteratee $ runIteratee m >>= \r1 ->+ case r1 of+ Continue k -> return (Continue (bind . k))+ Error err -> return (Error err)+ Yield x (Chunks []) -> runIteratee (f x)+ Yield x extra -> runIteratee (f x) >>= \r2 ->+ case r2 of+ Continue k -> runIteratee (k extra)+ Error err -> return (Error err)+ Yield x' _ -> return (Yield x' extra)++instance MonadTrans (Iteratee a) where+ lift m = Iteratee (m >>= runIteratee . return)++instance MonadIO m => MonadIO (Iteratee a m) where+ liftIO = lift . liftIO++-- | Enumerators are sources of data, to be consumed by iteratees.+-- Enumerators typically read from an external source (parser, handle,+-- random generator, etc), then feed chunks into an tteratee until:+--+-- * The input source runs out of data.+--+-- * The iteratee yields a result value.+--+-- * The iteratee throws an exception.++-- Since @'Iteratee'@ is an alias for @m ('Step' a m b)@, 'Enumerator's can+-- be considered step transformers of type @'Step' a m b -> m ('Step' a m b)@.+type Enumerator a m b = Step a m b -> Iteratee a m b++-- | An enumeratee acts as a stream adapter; place one between an enumerator+-- and an iteratee, and it changes the type or contents of the input stream.+--+-- Most users will want to combine enumerators, enumeratees, and iteratees+-- using the stream combinators @joinI@ and @joinE@, or their operator aliases+-- @(=$)@ and @($=)@. These combinators are used to manage how left-over input+-- is passed between elements of the data processing pipeline.+type Enumeratee ao ai m b = Step ai m b -> Iteratee ao m (Step ai m b)++-- | Since: 0.4.8+instance Typeable1 Stream where+ typeOf1 _ = mkTyConApp tyCon [] where+ tyCon = mkTyCon "Data.Enumerator.Stream"++-- | Since: 0.4.6+instance (Typeable a, Typeable1 m) =>+ Typeable1 (Iteratee a m) where+ typeOf1 i = let+ tyCon = mkTyCon "Data.Enumerator.Iteratee"+ (a, m) = peel i+ + peel :: Iteratee a m b -> (a, m ())+ peel = undefined+ + in mkTyConApp tyCon [typeOf a, typeOf1 m]++-- | Since: 0.4.8+instance (Typeable a, Typeable1 m) =>+ Typeable1 (Step a m) where+ typeOf1 s = let+ tyCon = mkTyCon "Data.Enumerator.Step"+ (a, m) = peel s+ + peel :: Step a m b -> (a, m ())+ peel = undefined+ + in mkTyConApp tyCon [typeOf a, typeOf1 m]++instance Monad m => Functor (Iteratee a m) where+ fmap = CM.liftM++instance Monad m => A.Applicative (Iteratee a m) where+ pure = return+ (<*>) = CM.ap++instance Functor Stream where+ fmap f (Chunks xs) = Chunks (fmap f xs)+ fmap _ EOF = EOF++-- | Since: 0.4.5+instance A.Applicative Stream where+ pure = return+ (<*>) = CM.ap++-- | @'returnI' step = 'Iteratee' (return step)@+returnI :: Monad m => Step a m b -> Iteratee a m b+returnI step = Iteratee (return step)++-- | @'yield' x extra = 'returnI' ('Yield' x extra)@+--+-- WARNING: due to the current encoding of iteratees in this library,+-- careless use of the 'yield' primitive may violate the monad laws.+-- To prevent this, always make sure that an iteratee never yields+-- extra data unless it has received at least one input element.+--+-- More strictly, iteratees may not yield data that they did not+-- receive as input. Don't use 'yield' to “inject” elements+-- into the stream.+yield :: Monad m => b -> Stream a -> Iteratee a m b+yield x extra = returnI (Yield x extra)++-- | @'continue' k = 'returnI' ('Continue' k)@+continue :: Monad m => (Stream a -> Iteratee a m b) -> Iteratee a m b+continue k = returnI (Continue k)++infixl 1 >>==+infixr 1 ==<<+infixr 0 $$+infixr 1 >==>+infixr 1 <==<++-- | The most primitive stream operator. @iter >>== enum@ returns a new+-- iteratee which will read from @enum@ before continuing.+(>>==) :: Monad m+ => Iteratee a m b+ -> (Step a m b -> Iteratee a' m b')+ -> Iteratee a' m b'+i >>== f = Iteratee (runIteratee i >>= runIteratee . f)++-- | @('==<<') = flip ('>>==')@+(==<<) :: Monad m+ => (Step a m b -> Iteratee a' m b')+ -> Iteratee a m b+ -> Iteratee a' m b'+(==<<) = flip (>>==)++-- | @('$$') = ('==<<')@+--+-- This is somewhat easier to read when constructing an iteratee from many+-- processing stages. You can treat it like @('$')@, and read the data flow+-- from left to right.+--+-- Since: 0.1.1+($$) :: Monad m+ => (Step a m b -> Iteratee a' m b')+ -> Iteratee a m b+ -> Iteratee a' m b'+($$) = (==<<)++-- | @('>==>') enum1 enum2 step = enum1 step '>>==' enum2@+--+-- The moral equivalent of @('CM.>=>')@ for iteratees.+--+-- Since: 0.1.1+(>==>) :: Monad m+ => Enumerator a m b+ -> (Step a m b -> Iteratee a' m b')+ -> Step a m b+ -> Iteratee a' m b'+(>==>) e1 e2 s = e1 s >>== e2++-- | @('<==<') = flip ('>==>')@+--+-- Since: 0.1.1+(<==<) :: Monad m+ => (Step a m b -> Iteratee a' m b')+ -> Enumerator a m b+ -> Step a m b+ -> Iteratee a' m b'+(<==<) = flip (>==>)++-- | Sends 'EOF' to its iteratee. Most clients should use 'run' or 'run_'+-- instead.+enumEOF :: Monad m => Enumerator a m b+enumEOF (Yield x _) = yield x EOF+enumEOF (Error err) = returnI (Error err)+enumEOF (Continue k) = k EOF >>== check where+ check (Continue _) = error "enumEOF: divergent iteratee"+ check s = enumEOF s++-- | A common pattern in 'Enumeratee' implementations is to check whether+-- the inner 'Iteratee' has finished, and if so, to return its output.+-- 'checkDone' passes its parameter a continuation if the 'Iteratee'+-- can still consume input, or yields otherwise.+--+-- Since: 0.4.3+checkDoneEx :: Monad m =>+ Stream a' ->+ ((Stream a -> Iteratee a m b) -> Iteratee a' m (Step a m b)) ->+ Enumeratee a' a m b+checkDoneEx _ f (Continue k) = f k+checkDoneEx extra _ step = yield step extra++-- | @'checkDone' = 'checkDoneEx' ('Chunks' [])@+--+-- Use this for enumeratees which do not have an input buffer.+checkDone :: Monad m =>+ ((Stream a -> Iteratee a m b) -> Iteratee a' m (Step a m b)) ->+ Enumeratee a' a m b+checkDone = checkDoneEx (Chunks [])++-- | A common pattern in 'Enumerator' implementations is to check whether+-- the inner 'Iteratee' has finished, and if so, to return its output.+-- 'checkContinue0' passes its parameter a continuation if the 'Iteratee'+-- can still consume input; if not, it returns the iteratee's step.+--+-- The type signature here is a bit crazy, but it's actually very easy to+-- use. Take this code:+--+-- > repeat :: Monad m => a -> Enumerator a m b+-- > repeat x = loop where+-- > loop (Continue k) = k (Chunks [x]) >>== loop+-- > loop step = returnI step+--+-- And rewrite it without the boilerplate:+--+-- > repeat :: Monad m => a -> Enumerator a m b+-- > repeat x = checkContinue0 $ \loop k -> k (Chunks [x] >>== loop+--+-- Since: 0.4.9+checkContinue0 :: Monad m+ => (Enumerator a m b+ -> (Stream a -> Iteratee a m b)+ -> Iteratee a m b)+ -> Enumerator a m b+checkContinue0 inner = loop where+ loop (Continue k) = inner loop k+ loop step = returnI step+++-- | Like 'checkContinue0', but allows each loop step to use a state value:+--+-- > iterate :: Monad m => (a -> a) -> a -> Enumerator a m b+-- > iterate f = checkContinue1 $ \loop a k -> k (Chunks [a]) >>== loop (f a)+--+-- Since: 0.4.9+checkContinue1 :: Monad m+ => ((s1 -> Enumerator a m b)+ -> s1+ -> (Stream a -> Iteratee a m b)+ -> Iteratee a m b)+ -> s1+ -> Enumerator a m b+checkContinue1 inner = loop where+ loop s (Continue k) = inner loop s k+ loop _ step = returnI step
lib/Data/Enumerator/List.hs view
@@ -91,9 +91,8 @@ import Data.Monoid (mappend) import qualified Data.Set -import Data.Enumerator hiding ( concatMapM, iterateM, replicateM, head, drop- , foldM, repeatM, generateM, filterM, consume- , length)+import Data.Enumerator (sequence, throwError)+import Data.Enumerator.Internal -- | Consume the entire input stream with a strict left fold, one element -- at a time.@@ -160,7 +159,7 @@ loop k (x:xs) = do fx <- lift (f x) k (Chunks fx) >>==- checkDoneEx (Chunks xs) (\k' -> loop k' xs)+ checkDoneEx (Chunks xs) (`loop` xs) -- | @'Data.Enumerator.List.concatMap' f@ applies /f/ to each input element -- and feeds the resulting outputs to the inner iteratee.@@ -676,8 +675,8 @@ | len xs <= n = k (Chunks xs) >>== isolate (n - len xs) | otherwise = let (s1, s2) = L.genericSplitAt n xs- in k (Chunks s1) >>== (\step -> yield step (Chunks s2))- loop EOF = k EOF >>== (\step -> yield step EOF)+ in k (Chunks s1) >>== (`yield` Chunks s2)+ loop EOF = k EOF >>== (`yield` EOF) isolate n step = drop n >> return step -- | Split on elements satisfying a given predicate.
lib/Data/Enumerator/List.hs-boot view
@@ -1,5 +1,5 @@ module Data.Enumerator.List where-import {-# SOURCE #-} Data.Enumerator+import Data.Enumerator.Internal head :: Monad m => Iteratee a m (Maybe a) drop :: Monad m => Integer -> Iteratee a m () dropWhile :: Monad m => (a -> Bool) -> Iteratee a m ()
lib/Data/Enumerator/Text.hs view
@@ -129,9 +129,8 @@ import System.IO.Error (isEOFError) import System.IO.Unsafe (unsafePerformIO) -import Data.Enumerator hiding ( head, drop, generateM, filterM, consume- , concatMapM, iterateM, repeatM, replicateM- , foldM)+import Data.Enumerator.Internal+import Data.Enumerator (isEOF, tryIO, throwError) import qualified Data.Enumerator.List as EL import Data.Enumerator.Util (tSpanBy, tlSpanBy, reprWord, reprChar, textToStrict) @@ -216,7 +215,7 @@ loop k (x:xs) = do fx <- lift (f x) k (Chunks [fx]) >>==- checkDoneEx (Chunks [T.pack xs]) (\k' -> loop k' xs)+ checkDoneEx (Chunks [T.pack xs]) (`loop` xs) -- | Similar to 'Data.Enumerator.Text.concatMap', but with a stateful step -- function.@@ -347,7 +346,7 @@ len = toInteger (TL.length lazy) iter = if len < n'- then continue (loop (acc . (TL.append lazy)) (n' - len))+ then continue (loop (acc . TL.append lazy) (n' - len)) else let (xs', extra) = TL.splitAt (fromInteger n') lazy in yield (acc xs') (toChunks extra)@@ -364,7 +363,7 @@ lazy = TL.fromChunks xs (xs', extra) = tlSpanBy p lazy iter = if TL.null extra- then continue (loop (acc . (TL.append lazy)))+ then continue (loop (acc . TL.append lazy)) else yield (acc xs') (toChunks extra) loop acc EOF = yield (acc TL.empty) EOF @@ -376,7 +375,7 @@ loop acc (Chunks []) = continue (loop acc) loop acc (Chunks xs) = iter where lazy = TL.fromChunks xs- iter = continue (loop (acc . (TL.append lazy)))+ iter = continue (loop (acc . TL.append lazy)) loop acc EOF = yield (acc TL.empty) EOF -- | Pass input from a stream through two iteratees at once. Excess input is@@ -686,7 +685,7 @@ lazy = TL.fromChunks xs len = toInteger (TL.length lazy) iter = if len < n'- then continue (loop (acc . (TL.append lazy)) (n' - len))+ then continue (loop (acc . TL.append lazy) (n' - len)) else yield () (toChunks (acc lazy)) loop _ _ EOF = throwError (Exc.ErrorCall "require: Unexpected EOF") @@ -707,8 +706,8 @@ then k (Chunks xs) >>== isolate (n - len) else let (s1, s2) = TL.splitAt (fromInteger n) lazy- in k (toChunks s1) >>== (\step -> yield step (toChunks s2))- loop EOF = k EOF >>== (\step -> yield step EOF)+ in k (toChunks s1) >>== (`yield` toChunks s2)+ loop EOF = k EOF >>== (`yield` EOF) isolate n step = drop n >> return step -- | Split on characters satisfying a given predicate.@@ -838,13 +837,18 @@ decode :: Monad m => Codec -> Enumeratee B.ByteString T.Text m b decode codec = checkDone (continue . step B.empty) where- step _ k EOF = yield (Continue k) EOF+ step acc k EOF = if B.null acc+ then yield (Continue k) EOF+ else throwError (Exc.ErrorCall "Unexpected EOF while decoding") step acc k (Chunks xs) = loop acc k xs loop acc k [] = continue (step acc k) loop acc k (x:xs) = let (text, extra) = codecDecode codec (B.append acc x)- extraChunks = Chunks (either snd id extra : xs)+ extraChunks = Chunks $ case extra of+ Right bytes | B.null bytes -> xs+ Right bytes -> bytes:xs+ Left (_, bytes) -> bytes:xs checkError k' = case extra of Left (exc, _) -> throwError exc@@ -927,8 +931,8 @@ | (n + 1) == maxN = decodeTo n loop n = let req = utf16Required- (B.index bytes 0)- (B.index bytes 1)+ (B.index bytes n)+ (B.index bytes (n + 1)) decodeMore = loop $! n + req in if n + req > maxN then decodeTo n@@ -952,8 +956,8 @@ | (n + 1) == maxN = decodeTo n loop n = let req = utf16Required- (B.index bytes 1)- (B.index bytes 0)+ (B.index bytes (n + 1))+ (B.index bytes n) decodeMore = loop $! n + req in if n + req > maxN then decodeTo n
lib/Data/Enumerator/Util.hs view
@@ -15,10 +15,10 @@ else Prelude.replicate (size - len) '0' ++ str reprChar :: Char -> String-reprChar c = "U+" ++ (pad0 4 (showIntAtBase 16 (toUpper . intToDigit) (ord c) ""))+reprChar c = "U+" ++ pad0 4 (showIntAtBase 16 (toUpper . intToDigit) (ord c) "") reprWord :: Word8 -> String-reprWord w = "0x" ++ (pad0 2 (showIntAtBase 16 (toUpper . intToDigit) w ""))+reprWord w = "0x" ++ pad0 2 (showIntAtBase 16 (toUpper . intToDigit) w "") tSpanBy :: (Char -> Bool) -> T.Text -> (T.Text, T.Text) tlSpanBy :: (Char -> Bool) -> TL.Text -> (TL.Text, TL.Text)
+ scripts/run-coverage view
@@ -0,0 +1,78 @@+#!/bin/bash+if [ ! -f 'enumerator.cabal' ]; then+ echo -n "Can't find enumerator.cabal; please run this script as"+ echo -n " ./scripts/run-coverage from within the enumerator source"+ echo " directory"+ exit 1+fi++. scripts/common.bash++require_cabal_dev++pushd tests+$CABAL_DEV -s ../cabal-dev install --flags="coverage" || exit 1+popd++rm -f enumerator_tests.tix+cabal-dev/bin/enumerator_tests $@++EXCLUDES="\+--exclude=Main \+--exclude=EnumeratorTests.Binary \+--exclude=EnumeratorTests.Binary.Consume \+--exclude=EnumeratorTests.Binary.Drop \+--exclude=EnumeratorTests.Binary.Fold \+--exclude=EnumeratorTests.Binary.Handle \+--exclude=EnumeratorTests.Binary.Isolate \+--exclude=EnumeratorTests.Binary.Iterate \+--exclude=EnumeratorTests.Binary.Map \+--exclude=EnumeratorTests.Binary.Repeat \+--exclude=EnumeratorTests.Binary.Replicate \+--exclude=EnumeratorTests.Binary.Require \+--exclude=EnumeratorTests.Binary.Split \+--exclude=EnumeratorTests.Binary.Unfold \+--exclude=EnumeratorTests.Binary.Util \+--exclude=EnumeratorTests.Binary.Zip \+--exclude=EnumeratorTests.CatchError \+--exclude=EnumeratorTests.Compatibility \+--exclude=EnumeratorTests.Instances \+--exclude=EnumeratorTests.Join \+--exclude=EnumeratorTests.List \+--exclude=EnumeratorTests.List.Consume \+--exclude=EnumeratorTests.List.Drop \+--exclude=EnumeratorTests.List.Fold \+--exclude=EnumeratorTests.List.Isolate \+--exclude=EnumeratorTests.List.Iterate \+--exclude=EnumeratorTests.List.Map \+--exclude=EnumeratorTests.List.Repeat \+--exclude=EnumeratorTests.List.Replicate \+--exclude=EnumeratorTests.List.Require \+--exclude=EnumeratorTests.List.Split \+--exclude=EnumeratorTests.List.Unfold \+--exclude=EnumeratorTests.List.Unique \+--exclude=EnumeratorTests.List.Util \+--exclude=EnumeratorTests.List.Zip \+--exclude=EnumeratorTests.Misc \+--exclude=EnumeratorTests.Sequence \+--exclude=EnumeratorTests.Stream \+--exclude=EnumeratorTests.Text \+--exclude=EnumeratorTests.Text.Codecs \+--exclude=EnumeratorTests.Text.Consume \+--exclude=EnumeratorTests.Text.Drop \+--exclude=EnumeratorTests.Text.Fold \+--exclude=EnumeratorTests.Text.Handle \+--exclude=EnumeratorTests.Text.Isolate \+--exclude=EnumeratorTests.Text.Iterate \+--exclude=EnumeratorTests.Text.Map \+--exclude=EnumeratorTests.Text.Repeat \+--exclude=EnumeratorTests.Text.Replicate \+--exclude=EnumeratorTests.Text.Require \+--exclude=EnumeratorTests.Text.Split \+--exclude=EnumeratorTests.Text.Unfold \+--exclude=EnumeratorTests.Text.Util \+--exclude=EnumeratorTests.Text.Zip \+--exclude=EnumeratorTests.Util"++hpc markup --srcdir=src/ --srcdir=tests/ enumerator_tests.tix --destdir=hpc-markup $EXCLUDES > /dev/null+hpc report --srcdir=src/ --srcdir=tests/ enumerator_tests.tix $EXCLUDES
+ tests/EnumeratorTests.hs view
@@ -0,0 +1,48 @@+{-# LANGUAGE OverloadedStrings #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module Main+ ( tests+ , main+ ) where++import Test.Chell (Suite, defaultMain)++import EnumeratorTests.Binary (test_Binary)+import EnumeratorTests.CatchError (test_CatchError)+import EnumeratorTests.Compatibility (test_Compatibility)+import EnumeratorTests.Instances (test_Instances)+import EnumeratorTests.Join+import EnumeratorTests.List (test_List)+import EnumeratorTests.Misc+import EnumeratorTests.Sequence (test_Sequence)+import EnumeratorTests.Stream (test_Stream)+import EnumeratorTests.Text (test_Text)++tests :: [Suite]+tests =+ [ test_Binary+ , test_CatchError+ , test_Compatibility+ , test_ConcatEnums+ , test_EnumEOF+ , test_Instances+ , test_JoinE+ , test_JoinI+ , test_JoinOperatorAssociativity+ , test_Last+ , test_Length+ , test_LiftTrans+ , test_List+ , test_Peek+ , test_PrintChunks+ , test_Sequence+ , test_Stream+ , test_Text+ , test_TryIO+ ]++main :: IO ()+main = Test.Chell.defaultMain tests
+ tests/EnumeratorTests/Binary.hs view
@@ -0,0 +1,64 @@+{-# LANGUAGE OverloadedStrings #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Binary+ ( test_Binary+ ) where++import Test.Chell++import EnumeratorTests.Binary.Consume+import EnumeratorTests.Binary.Drop+import EnumeratorTests.Binary.Fold+import EnumeratorTests.Binary.Handle+import EnumeratorTests.Binary.Isolate+import EnumeratorTests.Binary.Iterate+import EnumeratorTests.Binary.Map+import EnumeratorTests.Binary.Repeat+import EnumeratorTests.Binary.Replicate+import EnumeratorTests.Binary.Require+import EnumeratorTests.Binary.Split+import EnumeratorTests.Binary.Unfold+import EnumeratorTests.Binary.Zip++test_Binary :: Suite+test_Binary = suite "binary"+ [ test_Consume+ , test_ConcatMap+ , test_ConcatMapM+ , test_ConcatMapAccum+ , test_ConcatMapAccumM+ , test_Drop+ , test_DropWhile+ , test_EnumHandle+ , test_EnumHandleRange+ , test_Filter+ , test_FilterM+ , test_Fold+ , test_FoldM+ , test_GenerateM+ , test_Head+ , test_Head_+ , test_Isolate+ , test_Iterate+ , test_IterateM+ , test_IterHandle+ , test_Map+ , test_MapM+ , test_MapM_+ , test_MapAccum+ , test_MapAccumM+ , test_Repeat+ , test_RepeatM+ , test_Replicate+ , test_ReplicateM+ , test_Require+ , test_SplitWhen+ , test_Take+ , test_TakeWhile+ , test_Unfold+ , test_UnfoldM+ , test_Zip+ ]
+ tests/EnumeratorTests/Binary/Consume.hs view
@@ -0,0 +1,104 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Binary.Consume+ ( test_Consume+ , test_Head+ , test_Head_+ , test_Take+ , test_TakeWhile+ ) where++import Control.Exception+import Data.Word (Word8)+import Test.Chell++import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL+import qualified Data.Enumerator.Binary as EB++import EnumeratorTests.Util (equalExc)++test_Consume :: Suite+test_Consume = assertions "consume" $ do+ $expect $ equal+ ("ABC", Nothing)+ (E.runLists_ [[], ["A", "B"], ["C"]] $ do+ xs <- EB.consume+ h <- EL.head+ return (xs, h))++test_Head :: Suite+test_Head = assertions "head" $ do+ $expect $ equal+ (Just 0x41, ["BC", "DE"])+ (E.runLists_ [[], ["ABC", "DE"]] $ do+ x <- EB.head+ extra <- EL.consume+ return (x, extra))+ $expect $ equal+ (Nothing :: Maybe Word8, [])+ (E.runLists_ [] $ do+ x <- EB.head+ extra <- EL.consume+ return (x, extra))++test_Head_ :: Suite+test_Head_ = assertions "head_" $ do+ $expect $ equal+ (0x41, ["BC", "DE"])+ (E.runLists_ [["ABC"], ["DE"]] $ do+ x <- EB.head_+ extra <- EL.consume+ return (x, extra))+ $expect $ equalExc+ (ErrorCall "head_: stream has ended")+ (E.runLists [] $ do+ x <- EB.head_+ extra <- EL.consume+ return (x, extra))++test_Take :: Suite+test_Take = assertions "take" $ do+ $expect $ equal+ ("ABC", ["D", "E"])+ (E.runLists_ [["A", "B"], ["C", "D"], ["E"]] $ do+ x <- EB.take 3+ extra <- EL.consume+ return (x, extra))+ $expect $ equal+ ("AB", [])+ (E.runLists_ [["A"], ["B"]] $ do+ x <- EB.take 3+ extra <- EL.consume+ return (x, extra))+ $expect $ equal+ ("", ["A", "B"])+ (E.runLists_ [["A"], ["B"]] $ do+ x <- EB.take 0+ extra <- EL.consume+ return (x, extra))++test_TakeWhile :: Suite+test_TakeWhile = assertions "takeWhile" $ do+ $expect $ equal+ ("ABC", ["D", "E"])+ (E.runLists_ [[], ["A", "B"], ["C", "D"], ["E"]] $ do+ x <- EB.takeWhile (< 0x44)+ extra <- EL.consume+ return (x, extra))+ $expect $ equal+ ("AB", [])+ (E.runLists_ [["A"], ["B"]] $ do+ x <- EB.takeWhile (< 0x44)+ extra <- EL.consume+ return (x, extra))+ $expect $ equal+ ("", ["A", "B"])+ (E.runLists_ [["A"], ["B"]] $ do+ x <- EB.takeWhile (< 0x41)+ extra <- EL.consume+ return (x, extra))
+ tests/EnumeratorTests/Binary/Drop.hs view
@@ -0,0 +1,64 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Binary.Drop+ ( test_Drop+ , test_DropWhile+ , test_Filter+ , test_FilterM+ ) where++import Test.Chell++import Data.Enumerator ((=$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.Binary as EB+import qualified Data.Enumerator.List as EL++test_Drop :: Suite+test_Drop = assertions "drop" $ do+ $expect $ equal+ ["ABCDE"]+ (E.runLists_ [["ABCDE"]] $ do+ EB.drop 0+ EL.consume)+ $expect $ equal+ ["CDE"]+ (E.runLists_ [["ABCDE"]] $ do+ EB.drop 2+ EL.consume)+ $expect $ equal+ ["CDE"]+ (E.runLists_ [["A"], ["BCDE"]] $ do+ EB.drop 2+ EL.consume)++test_DropWhile :: Suite+test_DropWhile = assertions "dropWhile" $ do+ $expect $ equal+ ["CDE"]+ (E.runLists_ [["ABCDE"]] $ do+ EB.dropWhile (< 0x43)+ EL.consume)+ $expect $ equal+ []+ (E.runLists_ [["ABCDE"]] $ do+ EB.dropWhile (\_ -> True)+ EL.consume)++test_Filter :: Suite+test_Filter = assertions "filter" $ do+ $expect $ equal+ ["A", "B", "", "D", "E"]+ (E.runLists_ [["ABCDE"]] $ do+ EB.filter (/= 0x43) =$ EL.consume)++test_FilterM :: Suite+test_FilterM = assertions "filterM" $ do+ $expect $ equal+ ["A", "B", "", "D", "E"]+ (E.runLists_ [["ABCDE"]] $ do+ EB.filterM (\x -> return (x /= 0x43)) =$ EL.consume)
+ tests/EnumeratorTests/Binary/Fold.hs view
@@ -0,0 +1,42 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2011 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Binary.Fold+ ( test_Fold+ , test_FoldM+ ) where++import Control.Monad (foldM)+import qualified Data.ByteString+import Data.ByteString (ByteString)+import Data.Functor.Identity (runIdentity)+import Data.Word (Word8)+import Test.Chell+import Test.Chell.QuickCheck+import Test.QuickCheck.Poly+import Test.QuickCheck.Modifiers++import qualified Data.Enumerator as E+import qualified Data.Enumerator.Binary as EB++import EnumeratorTests.Util ()++test_Fold :: Suite+test_Fold = property "fold" prop_Fold++prop_Fold :: Blind (B -> Word8 -> B) -> B -> ByteString -> Bool+prop_Fold (Blind f) z text = result == expected where+ result = E.runLists_ [[text]] (EB.fold f z)+ expected = Data.ByteString.foldl' f z text++test_FoldM :: Suite+test_FoldM = property "foldM" prop_FoldM++prop_FoldM :: Blind (B -> Word8 -> B) -> B -> ByteString -> Bool+prop_FoldM (Blind f) z text = result == expected where+ result = E.runLists_ [[text]] (EB.foldM f' z)+ expected = runIdentity (foldM f' z (Data.ByteString.unpack text))+ f' b a = return (f b a)
+ tests/EnumeratorTests/Binary/Handle.hs view
@@ -0,0 +1,88 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2011 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Binary.Handle+ ( test_EnumHandle+ , test_EnumHandleRange+ , test_IterHandle+ ) where++import Test.Chell++#ifdef MIN_VERSION_knob++import Data.Knob+import qualified System.IO as IO++import qualified Data.Enumerator as E+import Data.Enumerator (($$))+import qualified Data.Enumerator.Binary as EB+import qualified Data.Enumerator.List as EL++test_EnumHandle :: Suite+test_EnumHandle = assertions "enumHandle" $ do+ knob <- newKnob "01234567"+ chunks <- withFileHandle knob "" IO.ReadMode $ \h -> do+ E.run_ (EB.enumHandle 3 h $$ EL.consume)+ $expect (equal chunks ["012", "345", "67"])++test_EnumHandleRange :: Suite+test_EnumHandleRange = assertions "enumHandleRange" $ do+ knob <- newKnob "01234567"+ + -- no offset or count+ do+ chunks <- withFileHandle knob "" IO.ReadMode $ \h -> do+ E.run_ (EB.enumHandleRange 3 Nothing Nothing h $$ EL.consume)+ $expect (equal chunks ["012", "345", "67"])+ + -- offset+ do+ chunks <- withFileHandle knob "" IO.ReadMode $ \h -> do+ E.run_ (EB.enumHandleRange 3 (Just 1) Nothing h $$ EL.consume)+ $expect (equal chunks ["123", "456", "7"])+ + -- count+ do+ chunks <- withFileHandle knob "" IO.ReadMode $ \h -> do+ E.run_ (EB.enumHandleRange 3 Nothing (Just 7) h $$ EL.consume)+ $expect (equal chunks ["012", "345", "6"])+ + -- count beyond EOF+ do+ chunks <- withFileHandle knob "" IO.ReadMode $ \h -> do+ E.run_ (EB.enumHandleRange 3 Nothing (Just 10) h $$ EL.consume)+ $expect (equal chunks ["012", "345", "67"])+ + -- offset + count+ do+ chunks <- withFileHandle knob "" IO.ReadMode $ \h -> do+ E.run_ (EB.enumHandleRange 3 (Just 1) (Just 6) h $$ EL.consume)+ $expect (equal chunks ["123", "456"])++test_IterHandle :: Suite+test_IterHandle = assertions "iterHandle" $ do+ knob <- newKnob ""+ withFileHandle knob "" IO.WriteMode $ \h -> do+ E.run_ (E.enumLists [[], ["A", "B"], ["C"]] $$ EB.iterHandle h)+ bytes <- Data.Knob.getContents knob+ $expect (equal bytes "ABC")++#else++import EnumeratorTests.Util (todo)++test_EnumHandle :: Suite+test_EnumHandle = todo "enumHandle"++test_EnumHandleRange :: Suite+test_EnumHandleRange = todo "enumHandleRange"++test_IterHandle :: Suite+test_IterHandle = todo "iterHandle"++#endif
+ tests/EnumeratorTests/Binary/Isolate.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Binary.Isolate+ ( test_Isolate+ ) where++import qualified Data.ByteString.Lazy as BL+import Data.Word (Word8)++import Test.Chell+import Test.Chell.QuickCheck++import Data.Enumerator (($$), (=$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.Binary as EB+import qualified Data.Enumerator.List as EL++import EnumeratorTests.Binary.Util (prop_Bytes)++test_Isolate :: Suite+test_Isolate = suite "isolate"+ [ prop_Isolate+ , test_DropExtra+ , test_HandleEOF+ , test_BadParameter+ ]++prop_Isolate :: Suite+prop_Isolate = property "model" $ prop_Bytes+ (do+ x <- E.joinI (EB.isolate 2 $$ EB.head)+ extra <- EB.consume+ return (x, extra))+ (\bytes -> Right $ case BL.unpack bytes of+ [] -> (Nothing, BL.empty)+ (x:[]) -> (Just x, BL.empty)+ (x:_:xs) -> (Just x, BL.pack xs))++test_DropExtra :: Suite+test_DropExtra = assertions "drop-extra" $ do+ $expect $ equal+ (Just 0x41, ["C"])+ (E.runLists_ [[], ["A"], ["B"], ["C"]] $ do+ x <- EB.isolate 2 =$ EB.head+ extra <- EL.consume+ return (x, extra))+ $expect $ equal+ (Just 0x41, ["C"])+ (E.runLists_ [["A", "B", "C"]] $ do+ x <- EB.isolate 2 =$ EB.head+ extra <- EL.consume+ return (x, extra))++test_HandleEOF :: Suite+test_HandleEOF = assertions "handle-eof" $ do+ $expect $ equal+ (Nothing :: Maybe Word8, [])+ (E.runLists_ [] $ do+ x <- EB.isolate 2 =$ EB.head+ extra <- EL.consume+ return (x, extra))++test_BadParameter :: Suite+test_BadParameter = assertions "bad-parameter" $ do+ $expect $ equal+ (Nothing, ["A", "B", "C"])+ (E.runLists_ [["A"], ["B"], ["C"]] $ do+ x <- EB.isolate 0 =$ EB.head+ extra <- EL.consume+ return (x, extra))
+ tests/EnumeratorTests/Binary/Iterate.hs view
@@ -0,0 +1,31 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2011 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Binary.Iterate+ ( test_Iterate+ , test_IterateM+ ) where++import Data.Functor.Identity (runIdentity)+import Test.Chell++import Data.Enumerator (($$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.Binary as EB+import qualified Data.Enumerator.List as EL++test_Iterate :: Suite+test_Iterate = assertions "iterate" $ do+ $expect $ equal+ ["A", "B", "C"]+ (runIdentity (E.run_ (EB.iterate succ 0x41 $$ EL.take 3)))++test_IterateM :: Suite+test_IterateM = assertions "iterateM" $ do+ let succM = return . succ+ $expect $ equal+ ["A", "B", "C"]+ (runIdentity (E.run_ (EB.iterateM succM 0x41 $$ EL.take 3)))
+ tests/EnumeratorTests/Binary/Map.hs view
@@ -0,0 +1,140 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Binary.Map+ ( test_Map+ , test_MapM+ , test_MapM_+ , test_ConcatMap+ , test_ConcatMapM+ , test_ConcatMapAccum+ , test_ConcatMapAccumM+ , test_MapAccum+ , test_MapAccumM+ ) where++import Control.Monad.Trans.Writer (execWriter, tell)+import qualified Data.ByteString as B+import Test.Chell++import Data.Enumerator (($$), (=$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.Binary as EB+import qualified Data.Enumerator.List as EL++test_Map :: Suite+test_Map = assertions "map" $ do+ $expect $ equal+ ["a", "b"]+ (E.runLists_ [["AB"]] $ do+ EB.map (+ 0x20) =$ EL.consume)+ $expect $ equal+ (["a", "b"], ["CDEF", "GH"])+ (E.runLists_ [["ABCD", "EF"], ["GH"]] $ do+ xs <- EB.map (+ 0x20) =$ EL.take 2+ extra <- EL.consume+ return (xs, extra))++test_MapM :: Suite+test_MapM = assertions "mapM" $ do+ $expect $ equal+ ["a", "b"]+ (E.runLists_ [["AB"]] $ do+ EB.mapM (\x -> return (x + 0x20)) =$ EL.consume)+ $expect $ equal+ (["a", "b"], ["CDEF", "GH"])+ (E.runLists_ [["ABCD", "EF"], ["GH"]] $ do+ xs <- EB.mapM (\x -> return (x + 0x20)) =$ EL.take 2+ extra <- EL.consume+ return (xs, extra))++test_MapM_ :: Suite+test_MapM_ = assertions "mapM_" $ do+ $expect $ equal+ [0x41, 0x42]+ (execWriter (E.run_ (E.enumLists [["AB"]] $$ EB.mapM_ (\x -> tell [x]))))++test_ConcatMap :: Suite+test_ConcatMap = assertions "concatMap" $ do+ $expect $ equal+ ["Aa", "Bb"]+ (E.runLists_ [["AB"]] $ do+ EB.concatMap (\x -> B.pack [x, x + 0x20]) =$ EL.consume)+ $expect $ equal+ (["Aa", "Bb"], ["CDEF", "GH"])+ (E.runLists_ [["ABCD", "EF"], ["GH"]] $ do+ xs <- EB.concatMap (\x -> B.pack [x, x + 0x20]) =$ EL.take 2+ extra <- EL.consume+ return (xs, extra))++test_ConcatMapM :: Suite+test_ConcatMapM = assertions "concatMapM" $ do+ $expect $ equal+ ["Aa", "Bb"]+ (E.runLists_ [["AB"]] $ do+ EB.concatMapM (\x -> return (B.pack [x, x + 0x20])) =$ EL.consume)+ $expect $ equal+ (["Aa", "Bb"], ["CDEF", "GH"])+ (E.runLists_ [["ABCD", "EF"], ["GH"]] $ do+ xs <- EB.concatMapM (\x -> return (B.pack [x, x + 0x20])) =$ EL.take 2+ extra <- EL.consume+ return (xs, extra))++test_MapAccum :: Suite+test_MapAccum = assertions "mapAccum" $ do+ let step s ao = (s + 1, ao + s)+ $expect $ equal+ ["B", "D", "F"]+ (E.runLists_ [["A", "B"], ["C"]] $ do+ EB.mapAccum step 1 =$ EL.consume)+ $expect $ equal+ ("B", ["", "B", "C"])+ (E.runLists_ [["A", "B"], ["C"]] $ do+ xs <- EB.mapAccum step 1 =$ EB.take 1+ extra <- EL.consume+ return (xs, extra))++test_MapAccumM :: Suite+test_MapAccumM = assertions "mapAccumM" $ do+ let step s ao = return (s + 1, ao + s)+ $expect $ equal+ ["B", "D", "F"]+ (E.runLists_ [["A", "B"], ["C"]] $ do+ EB.mapAccumM step 1 =$ EL.consume)+ $expect $ equal+ ("B", ["", "B", "C"])+ (E.runLists_ [["A", "B"], ["C"]] $ do+ xs <- EB.mapAccumM step 1 =$ EB.take 1+ extra <- EL.consume+ return (xs, extra))++test_ConcatMapAccum :: Suite+test_ConcatMapAccum = assertions "concatMapAccum" $ do+ let step s ao = (s + 1, B.replicate s ao)+ $expect $ equal+ ["A", "BB", "CCC"]+ (E.runLists_ [["A", "B"], ["C"]] $ do+ EB.concatMapAccum step 1 =$ EL.consume)+ $expect $ equal+ ("AB", ["", "C"])+ (E.runLists_ [["A", "B"], ["C"]] $ do+ xs <- EB.concatMapAccum step 1 =$ EB.take 2+ extra <- EL.consume+ return (xs, extra))++test_ConcatMapAccumM :: Suite+test_ConcatMapAccumM = assertions "concatMapAccumM" $ do+ let step s ao = return (s + 1, B.replicate s ao)+ $expect $ equal+ ["A", "BB", "CCC"]+ (E.runLists_ [["A", "B"], ["C"]] $ do+ EB.concatMapAccumM step 1 =$ EL.consume)+ $expect $ equal+ ("AB", ["", "C"])+ (E.runLists_ [["A", "B"], ["C"]] $ do+ xs <- EB.concatMapAccumM step 1 =$ EB.take 2+ extra <- EL.consume+ return (xs, extra))
+ tests/EnumeratorTests/Binary/Repeat.hs view
@@ -0,0 +1,49 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2011 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Binary.Repeat+ ( test_Repeat+ , test_RepeatM+ , test_GenerateM+ ) where++import Control.Monad.Trans.State+import Data.Functor.Identity (runIdentity)+import Test.Chell++import Data.Enumerator (($$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.Binary as EB+import qualified Data.Enumerator.List as EL++test_Repeat :: Suite+test_Repeat = assertions "repeat" $ do+ $expect $ equal+ ["A", "A", "A"]+ (runIdentity (E.run_ (EB.repeat 0x41 $$ EL.take 3)))++test_RepeatM :: Suite+test_RepeatM = assertions "repeatM" $ do+ let step = do+ c <- get+ put (succ c)+ return c+ $expect $ equal+ ["A", "B", "C"]+ (evalState (E.run_ (EB.repeatM step $$ EL.take 3)) 0x41)++test_GenerateM :: Suite+test_GenerateM = assertions "generateM" $ do+ let step = do+ c <- get+ if c > 0x43+ then return Nothing+ else do+ put (succ c)+ return (Just c)+ $expect $ equal+ ["A", "B", "C"]+ (evalState (E.run_ (EB.generateM step $$ EL.consume)) 0x41)
+ tests/EnumeratorTests/Binary/Replicate.hs view
@@ -0,0 +1,38 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2011 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Binary.Replicate+ ( test_Replicate+ , test_ReplicateM+ ) where++import Control.Monad.Trans.State+import Data.Functor.Identity (runIdentity)+import Test.Chell++import Data.Enumerator (($$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.Binary as EB+import qualified Data.Enumerator.List as EL++test_Replicate :: Suite+test_Replicate = assertions "replicate" $ do+ $expect $ equal+ ["A", "A", "A"]+ (runIdentity (E.run_ (EB.replicate 3 0x41 $$ EL.consume)))++test_ReplicateM :: Suite+test_ReplicateM = assertions "replicateM" $ do+ let step = do+ c <- get+ put (succ c)+ return c+ $expect $ equal+ ["A", "B", "C"]+ (evalState (E.run_ (EB.replicateM 3 step $$ EL.consume)) 0x41)+ $expect $ equal+ ["A", "B"]+ (evalState (E.run_ (EB.replicateM 3 step $$ EL.take 2)) 0x41)
+ tests/EnumeratorTests/Binary/Require.hs view
@@ -0,0 +1,67 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Binary.Require+ ( test_Require+ ) where++import qualified Control.Exception as Exc+import qualified Data.ByteString.Lazy as BL+import Test.Chell+import Test.Chell.QuickCheck++import Data.Enumerator (($$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.Binary as EB+import qualified Data.Enumerator.List as EL++import EnumeratorTests.Binary.Util++test_Require :: Suite+test_Require = suite "require"+ [ prop_Require+ , test_YieldsInput+ , test_HandleEOF+ , test_BadParameter+ ]++prop_Require :: Suite+prop_Require = property "model" $ prop_BytesN+ (\n -> do+ EB.require n+ EB.consume)+ (\n xs -> if n > toInteger (BL.length xs)+ then Left (Exc.ErrorCall "require: Unexpected EOF")+ else Right xs)++test_YieldsInput :: Suite+test_YieldsInput = assertions "yields-input" $ do+ $expect $ equal+ ["A", "B", "C"]+ (E.runLists_ [["A"], ["B"], ["C"]] $ do+ EB.require 2+ EL.consume)+ $expect $ equal+ ["A", "B", "C"]+ (E.runLists_ [["A", "B", "C"]] $ do+ EB.require 2+ EL.consume)++test_HandleEOF :: Suite+test_HandleEOF = assertions "handle-eof" $ do+ $expect $ throwsEq+ (Exc.ErrorCall "require: Unexpected EOF")+ (E.run_ (E.enumLists [] $$ do+ EB.require 2+ EL.consume))++test_BadParameter :: Suite+test_BadParameter = assertions "bad-parameter" $ do+ $expect $ equal+ []+ (E.runLists_ [] $ do+ EB.require 0+ EL.consume)
+ tests/EnumeratorTests/Binary/Split.hs view
@@ -0,0 +1,49 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Binary.Split+ ( test_SplitWhen+ ) where++import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as BL++import qualified Data.List.Split as LS+import Test.Chell+import Test.Chell.QuickCheck++import Data.Enumerator (($$), (=$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL+import qualified Data.Enumerator.Binary as EB++import EnumeratorTests.Binary.Util++test_SplitWhen :: Suite+test_SplitWhen = suite "splitWhen"+ [ prop_SplitWhen+ , test_HandleEmpty+ ]++prop_SplitWhen :: Suite+prop_SplitWhen = property "model" $ prop_BytesX+ (\c -> do+ xs <- E.joinI (EB.splitWhen (== c) $$ EL.consume)+ extra <- EL.consume+ return (xs, extra))+ (\c text -> let+ split = LS.split . LS.dropFinalBlank . LS.dropDelims . LS.whenElt+ chars = BL.unpack text+ in Right (map B.pack (split (== c) chars), []))++test_HandleEmpty :: Suite+test_HandleEmpty = assertions "empty" $ do+ $expect $ equal+ ([], Nothing)+ (E.runLists_ [[""]] $ do+ xs <- EB.splitWhen (== 0x2C) =$ EL.consume+ extra <- EL.head+ return (xs, extra))
+ tests/EnumeratorTests/Binary/Unfold.hs view
@@ -0,0 +1,37 @@++{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2011 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Binary.Unfold+ ( test_Unfold+ , test_UnfoldM+ ) where++import Data.Functor.Identity (runIdentity)+import Test.Chell++import Data.Enumerator (($$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.Binary as EB+import qualified Data.Enumerator.List as EL++test_Unfold :: Suite+test_Unfold = assertions "unfold" $ do+ let step x = if x > 0x43+ then Nothing+ else Just (x, succ x)+ $expect $ equal+ ["A", "B", "C"]+ (runIdentity (E.run_ (EB.unfold step 0x41 $$ EL.consume)))++test_UnfoldM :: Suite+test_UnfoldM = assertions "unfoldM" $ do+ let step x = return $ if x > 0x43+ then Nothing+ else Just (x, succ x)+ $expect $ equal+ ["A", "B", "C"]+ (runIdentity (E.run_ (EB.unfoldM step 0x41 $$ EL.consume)))
+ tests/EnumeratorTests/Binary/Util.hs view
@@ -0,0 +1,44 @@+{-# LANGUAGE OverloadedStrings #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Binary.Util+ ( prop_Bytes+ , prop_BytesN+ , prop_BytesX+ ) where++import Control.Exception (ErrorCall)+import Data.ByteString (ByteString)+import qualified Data.ByteString.Lazy as BL+import Data.Functor.Identity (Identity)++import Test.QuickCheck hiding (property)++import Data.Enumerator (Iteratee)++import EnumeratorTests.Util (check)++prop_Bytes :: Eq b+ => Iteratee ByteString Identity b+ -> (BL.ByteString -> Either ErrorCall b)+ -> [ByteString]+ -> Bool+prop_Bytes iter plain = check iter (plain . BL.fromChunks)++prop_BytesN :: Eq b+ => (t -> Iteratee ByteString Identity b)+ -> (t -> BL.ByteString -> Either ErrorCall b)+ -> Positive t+ -> [ByteString]+ -> Bool+prop_BytesN iter plain (Positive n) = check (iter n) (plain n . BL.fromChunks)++prop_BytesX :: Eq b+ => (t -> Iteratee ByteString Identity b)+ -> (t -> BL.ByteString -> Either ErrorCall b)+ -> t+ -> [ByteString]+ -> Bool+prop_BytesX iter plain x = check (iter x) (plain x . BL.fromChunks)
+ tests/EnumeratorTests/Binary/Zip.hs view
@@ -0,0 +1,165 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Binary.Zip+ ( test_Zip+ ) where++import qualified Control.Exception as Exc+import Data.ByteString (ByteString)+import Data.Functor.Identity (Identity)+import Data.Text (Text)+import Test.Chell++import qualified Data.Enumerator as E+import qualified Data.Enumerator.Binary as EB+import qualified Data.Enumerator.List as EL++import EnumeratorTests.Util (equalExc)++test_ZipN :: (Eq b, Show b) => Text -> E.Iteratee ByteString Identity b -> b -> Suite+test_ZipN name iter expected = assertions name $ do+ $expect $ equal+ expected+ (E.runLists_ [[], ["A"], ["B"]] iter)++$([d||])++test_Zip :: Suite+test_Zip = suite "zip"+ [ test_ContinueContinue+ , test_YieldContinue+ , test_ContinueYield+ , test_YieldYield+ , test_ErrorFirst+ , test_ErrorSecond+ , test_HandleEOF+ , test_Zip3+ , test_Zip4+ , test_Zip5+ , test_Zip6+ , test_Zip7+ , test_ZipWith+ , test_ZipWith3+ , test_ZipWith4+ , test_ZipWith5+ , test_ZipWith6+ , test_ZipWith7+ ]++test_ContinueContinue :: Suite+test_ContinueContinue = assertions "continue-continue" $ do+ $expect $ equal+ ("AB", "AB", ["C"])+ (E.runLists_ [["A"], ["B"], ["C"]] $ do+ (x, y) <- EB.zip (EB.take 2) (EB.take 2)+ extra <- EL.consume+ return (x, y, extra))++test_YieldContinue :: Suite+test_YieldContinue = assertions "yield-continue" $ do+ $expect $ equal+ ("A", "AB", ["C"])+ (E.runLists_ [["A"], ["B"], ["C"]] $ do+ (x, y) <- EB.zip (EB.take 1) (EB.take 2)+ extra <- EL.consume+ return (x, y, extra))++test_ContinueYield :: Suite+test_ContinueYield = assertions "continue-yield" $ do+ $expect $ equal+ ("AB", "A", ["C"])+ (E.runLists_ [["A"], ["B"], ["C"]] $ do+ (x, y) <- EB.zip (EB.take 2) (EB.take 1)+ extra <- EL.consume+ return (x, y, extra))++test_YieldYield :: Suite+test_YieldYield = assertions "yield-yield" $ do+ $expect $ equal+ ("A", "A", ["B", "C"])+ (E.runLists_ [["A"], ["B"], ["C"]] $ do+ (x, y) <- EB.zip (EB.take 1) (EB.take 1)+ extra <- EL.consume+ return (x, y, extra))++test_ErrorFirst :: Suite+test_ErrorFirst = assertions "error-first" $ do+ $expect $ equalExc+ (Exc.ErrorCall "error")+ (E.runLists [["A"], ["B"], ["C"]] $ do+ EB.zip (E.throwError (Exc.ErrorCall "error")) (EB.take 1))++test_ErrorSecond :: Suite+test_ErrorSecond = assertions "error-second" $ do+ $expect $ equalExc+ (Exc.ErrorCall "error")+ (E.runLists [["A"], ["B"], ["C"]] $ do+ EB.zip (EB.take 1) (E.throwError (Exc.ErrorCall "error")))++test_HandleEOF :: Suite+test_HandleEOF = assertions "handle-eof" $ do+ $expect $ equal+ ("A", "AB", [])+ (E.runLists_ [["A"], ["B"]] $ do+ (x, y) <- EB.zip (EB.take 1) (EB.take 3)+ extra <- EL.consume+ return (x, y, extra))++test_Zip3 :: Suite+test_Zip3 = test_ZipN "zip3"+ (EB.zip3 EB.head EB.head EB.head)+ (Just 0x41, Just 0x41, Just 0x41)++test_Zip4 :: Suite+test_Zip4 = test_ZipN "zip4"+ (EB.zip4 EB.head EB.head EB.head EB.head)+ (Just 0x41, Just 0x41, Just 0x41, Just 0x41)++test_Zip5 :: Suite+test_Zip5 = test_ZipN "zip5"+ (EB.zip5 EB.head EB.head EB.head EB.head EB.head)+ (Just 0x41, Just 0x41, Just 0x41, Just 0x41, Just 0x41)++test_Zip6 :: Suite+test_Zip6 = test_ZipN "zip6"+ (EB.zip6 EB.head EB.head EB.head EB.head EB.head EB.head)+ (Just 0x41, Just 0x41, Just 0x41, Just 0x41, Just 0x41, Just 0x41)++test_Zip7 :: Suite+test_Zip7 = test_ZipN "zip7"+ (EB.zip7 EB.head EB.head EB.head EB.head EB.head EB.head EB.head)+ (Just 0x41, Just 0x41, Just 0x41, Just 0x41, Just 0x41, Just 0x41, Just 0x41)++test_ZipWith :: Suite+test_ZipWith = test_ZipN "zipWith"+ (EB.zipWith (,) EB.head EB.head)+ (Just 0x41, Just 0x41)++test_ZipWith3 :: Suite+test_ZipWith3 = test_ZipN "zipWith3"+ (EB.zipWith3 (,,) EB.head EB.head EB.head)+ (Just 0x41, Just 0x41, Just 0x41)++test_ZipWith4 :: Suite+test_ZipWith4 = test_ZipN "zipWith4"+ (EB.zipWith4 (,,,) EB.head EB.head EB.head EB.head)+ (Just 0x41, Just 0x41, Just 0x41, Just 0x41)++test_ZipWith5 :: Suite+test_ZipWith5 = test_ZipN "zipWith5"+ (EB.zipWith5 (,,,,) EB.head EB.head EB.head EB.head EB.head)+ (Just 0x41, Just 0x41, Just 0x41, Just 0x41, Just 0x41)++test_ZipWith6 :: Suite+test_ZipWith6 = test_ZipN "zipWith6"+ (EB.zipWith6 (,,,,,) EB.head EB.head EB.head EB.head EB.head EB.head)+ (Just 0x41, Just 0x41, Just 0x41, Just 0x41, Just 0x41, Just 0x41)++test_ZipWith7 :: Suite+test_ZipWith7 = test_ZipN "zipWith7"+ (EB.zipWith7 (,,,,,,) EB.head EB.head EB.head EB.head EB.head EB.head EB.head)+ (Just 0x41, Just 0x41, Just 0x41, Just 0x41, Just 0x41, Just 0x41, Just 0x41)
+ tests/EnumeratorTests/CatchError.hs view
@@ -0,0 +1,107 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.CatchError+ ( test_CatchError+ ) where++import Control.Concurrent+import qualified Control.Exception as Exc+import Control.Monad.IO.Class (liftIO)++import Test.Chell++import Data.Enumerator (($$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL++import EnumeratorTests.Util (equalExc, within)++test_CatchError :: Suite+test_CatchError = suite "catchError"+ [ test_WithoutContinue+ , test_NotDivergent+ , test_Interleaved+ , test_YieldImmediately+ , test_HandleError+ , test_HandleEOF+ , test_GotStream+ ]++test_WithoutContinue :: Suite+test_WithoutContinue = assertions "without-continue" $ do+ $expect $ equalExc+ (Exc.ErrorCall "require: Unexpected EOF")+ (E.runLists [] $ E.catchError+ (E.throwError (Exc.ErrorCall "error"))+ (\_ -> EL.require 1))++test_NotDivergent :: Suite+test_NotDivergent = assertions "not-divergent" $ do+ $expect $ equalExc+ (Exc.ErrorCall "require: Unexpected EOF")+ (E.runLists [] $ E.catchError+ (do+ _ <- EL.head+ E.throwError (Exc.ErrorCall "error"))+ (\_ -> EL.require 1))++test_Interleaved :: Suite+test_Interleaved = within 1000 $ assertions "interleaved" $ do+ let enumMVar mvar = EL.repeatM (liftIO (takeMVar mvar))+ let iter mvar = do+ liftIO (putMVar mvar ())+ _ <- EL.head+ return True+ let onError _ = return False+ + mvar <- liftIO newEmptyMVar+ E.run_ (enumMVar mvar $$ E.catchError (iter mvar) onError)++test_YieldImmediately :: Suite+test_YieldImmediately = assertions "yield-immediately" $ do+ $expect $ equal+ 'A'+ (E.runLists_ [['A']] $ do+ E.catchError (return 'A') (\_ -> return 'B'))++test_HandleError :: Suite+test_HandleError = assertions "handle-error" $ do+ $expect $ equal+ "error"+ (E.runLists_ [] $ E.catchError+ (EL.head >> E.throwError (Exc.ErrorCall "error"))+ (\err -> return (show err)))+ $expect $ equal+ "error"+ (E.runLists_ [['A']] $ E.catchError+ (E.throwError (Exc.ErrorCall "error"))+ (\err -> return (show err)))+ $expect $ equal+ "error"+ (E.runLists_ [['A'], ['B'], ['C']] $ E.catchError+ (EL.drop 1 >> E.throwError (Exc.ErrorCall "error"))+ (\err -> return (show err)))++test_HandleEOF :: Suite+test_HandleEOF = assertions "handle-eof" $ do+ $expect $ equal+ (Nothing, Nothing)+ (E.runLists_ [] $ do+ x <- E.catchError EL.head (\_ -> return (Just 'B'))+ y <- EL.head+ return (x, y))++test_GotStream :: Suite+test_GotStream = assertions "got-stream" $ do+ $expect $ equal+ (Just 'B')+ (E.runLists_ [['A'], ['B'], ['C']] $ E.catchError+ (do+ _ <- EL.head+ _ <- EL.head+ E.throwError (Exc.ErrorCall "error"))+ (\_ -> EL.head))
+ tests/EnumeratorTests/Compatibility.hs view
@@ -0,0 +1,204 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}+{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Compatibility+ ( test_Compatibility+ ) where++import Data.Functor.Identity (Identity, runIdentity)+import Data.Text (Text)+import Test.Chell++import qualified Data.Enumerator as E+import Data.Enumerator (($$), (=$))+import qualified Data.Enumerator.List as EL++compatIter :: (Eq a, Show a)+ => Text+ -> E.Iteratee Char Identity a+ -> E.Iteratee Char Identity a+ -> Suite+compatIter name i1 i2 = assertions name $ do+ let run i = E.runLists_ [[], ['A', 'B'], ['C', 'D'], ['E']] $ do+ x <- i+ y <- EL.consume+ return (x, y)+ $expect (equal (run i1) (run i2))++compatEnum :: (Eq a, Show a)+ => Text+ -> E.Enumerator a Identity [a]+ -> E.Enumerator a Identity [a]+ -> Suite+compatEnum name e1 e2 = assertions name $ do+ let run e = runIdentity (E.run_ (e $$ EL.take 10))+ $expect (equal (run e1) (run e2))++compatEnee :: (Eq ai, Show ai)+ => Text+ -> E.Enumeratee Char ai Identity [ai]+ -> E.Enumeratee Char ai Identity [ai]+ -> Suite+compatEnee name e1 e2 = assertions name $ do+ let run e = E.runLists_ [[], ['A', 'B'], ['C', 'D'], ['E']] (e =$ EL.consume)+ $expect (equal (run e1) (run e2))++$([d||])++test_Compatibility :: Suite+test_Compatibility = suite "compatibility"+ [ test_Head+ , test_Drop+ , test_DropWhile+ , test_Span+ , test_Break+ , test_Consume+ , test_Foldl+ , test_Foldl'+ , test_FoldM+ , test_Iterate+ , test_IterateM+ , test_Repeat+ , test_RepeatM+ , test_Replicate+ , test_ReplicateM+ , test_GenerateM+ , test_Map+ , test_MapM+ , test_ConcatMap+ , test_ConcatMapM+ , test_Filter+ , test_FilterM+ , test_LiftFoldL+ , test_LiftFoldL'+ , test_LiftFoldM+ , test_LiftI+ ]++test_Head :: Suite+test_Head = compatIter "head" E.head EL.head++test_Drop :: Suite+test_Drop = compatIter "drop" (E.drop 1) (EL.drop 1)++test_DropWhile :: Suite+test_DropWhile = compatIter "dropWhile"+ (E.dropWhile (< 'C'))+ (EL.dropWhile (< 'C'))++test_Span :: Suite+test_Span = compatIter "span"+ (E.span (< 'C'))+ (EL.takeWhile (< 'C'))++test_Break :: Suite+test_Break = compatIter "break"+ (E.break (> 'C'))+ (EL.takeWhile (<= 'C'))++test_Consume :: Suite+test_Consume = compatIter "consume" E.consume EL.consume++test_Foldl :: Suite+test_Foldl = compatIter "foldl"+ (E.foldl (flip (:)) [])+ (EL.fold (flip (:)) [])++test_LiftFoldL :: Suite+test_LiftFoldL = compatIter "liftFoldL"+ (E.liftFoldL (flip (:)) [])+ (EL.fold (flip (:)) [])++test_Foldl' :: Suite+test_Foldl' = compatIter "foldl'"+ (E.foldl' (flip (:)) [])+ (EL.fold (flip (:)) [])++test_LiftFoldL' :: Suite+test_LiftFoldL' = compatIter "liftFoldl'"+ (E.liftFoldL' (flip (:)) [])+ (EL.fold (flip (:)) [])++test_FoldM :: Suite+test_FoldM = compatIter "foldM"+ (E.foldM (\xs x -> return (x:xs)) [])+ (EL.foldM (\xs x -> return (x:xs)) [])++test_LiftFoldM :: Suite+test_LiftFoldM = compatIter "liftFoldM"+ (E.liftFoldM (\xs x -> return (x:xs)) [])+ (EL.foldM (\xs x -> return (x:xs)) [])++test_Iterate :: Suite+test_Iterate = compatEnum "iterate"+ (E.iterate succ 'A')+ (EL.iterate succ 'A')++test_IterateM :: Suite+test_IterateM = compatEnum "iterateM"+ (E.iterateM (return . succ) 'A')+ (EL.iterateM (return . succ) 'A')++test_Repeat :: Suite+test_Repeat = compatEnum "repeat"+ (E.repeat 'A')+ (EL.repeat 'A')++test_RepeatM :: Suite+test_RepeatM = compatEnum "repeatM"+ (E.repeatM (return 'A'))+ (EL.repeatM (return 'A'))++test_Replicate :: Suite+test_Replicate = compatEnum "replicate"+ (E.replicate 5 'A')+ (EL.replicate 5 'A')++test_ReplicateM :: Suite+test_ReplicateM = compatEnum "replicateM"+ (E.replicateM 5 (return 'A'))+ (EL.replicateM 5 (return 'A'))++test_GenerateM :: Suite+test_GenerateM = compatEnum "generateM"+ (E.generateM (return (Just 'A')))+ (EL.generateM (return (Just 'A')))++test_Map :: Suite+test_Map = compatEnee "map"+ (E.map succ)+ (EL.map succ)++test_MapM :: Suite+test_MapM = compatEnee "mapM"+ (E.mapM (return . succ))+ (EL.mapM (return . succ))++test_ConcatMap :: Suite+test_ConcatMap = compatEnee "concatMap"+ (E.concatMap (\x -> [succ x]))+ (EL.concatMap (\x -> [succ x]))++test_ConcatMapM :: Suite+test_ConcatMapM = compatEnee "concatMapM"+ (E.concatMapM (\x -> return [succ x]))+ (EL.concatMapM (\x -> return [succ x]))++test_Filter :: Suite+test_Filter = compatEnee "filter"+ (E.filter (< 'C'))+ (EL.filter (< 'C'))++test_FilterM :: Suite+test_FilterM = compatEnee "filterM"+ (E.filterM (return . (< 'C')))+ (EL.filterM (return . (< 'C')))++test_LiftI :: Suite+test_LiftI = compatIter "liftI"+ (E.liftI (\s -> E.Yield s (E.Chunks [])))+ (E.continue (\s -> E.yield s (E.Chunks [])))
+ tests/EnumeratorTests/Instances.hs view
@@ -0,0 +1,66 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Instances+ ( test_Instances+ ) where++import Control.Applicative (pure, (<*>))+import Data.Functor.Identity (runIdentity)+import Data.Typeable (typeOf)+import Test.Chell++import Data.Enumerator++test_Instances :: Suite+test_Instances = suite "instances"+ [ test_Typeable+ , test_Functor+ , test_Applicative+ ]++test_Typeable :: Suite+test_Typeable = suite "typeable"+ [ test_TypeableStream+ , test_TypeableIteratee+ , test_TypeableStep+ ]++test_TypeableStream :: Suite+test_TypeableStream = assertions "stream" $ do+ let x = undefined :: Stream Char+ $expect $ equal+ "Data.Enumerator.Stream Char"+ (show (typeOf x))++test_TypeableIteratee :: Suite+test_TypeableIteratee = assertions "iteratee" $ do+ let x = undefined :: Iteratee Char Maybe Int+ $expect $ equal+ "Data.Enumerator.Iteratee Char Maybe Int"+ (show (typeOf x))++test_TypeableStep :: Suite+test_TypeableStep = assertions "step" $ do+ let x = undefined :: Step Char Maybe Int+ $expect $ equal+ "Data.Enumerator.Step Char Maybe Int"+ (show (typeOf x))++test_Functor :: Suite+test_Functor = assertions "functor" $ do+ $expect $ equal+ 'B'+ (runIdentity (run_ (fmap succ (return 'A'))))++test_Applicative :: Suite+test_Applicative = assertions "applicative" $ do+ $expect $ equal+ 'A'+ (runIdentity (run_ (pure 'A')))+ $expect $ equal+ 'B'+ (runIdentity (run_ (pure succ <*> pure 'A')))
+ tests/EnumeratorTests/Join.hs view
@@ -0,0 +1,90 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Join+ ( test_JoinE+ , test_JoinI+ , test_JoinOperatorAssociativity+ ) where++import Control.Exception+import Data.Char (toLower)+import Data.Functor.Identity (Identity, runIdentity)++import Test.Chell++import Data.Enumerator (($$), ($=), (=$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL++import EnumeratorTests.Util (equalExc)++test_JoinE :: Suite+test_JoinE = suite "joinE"+ [ test_JoinE_Success+ , test_JoinE_Error+ , test_JoinE_Divergent+ ]++test_JoinE_Success :: Suite+test_JoinE_Success = assertions "success" $ do+ let enum :: Monad m => E.Enumerator Char m b+ enum = E.joinE (E.enumLists [['A', 'B', 'C']]) (EL.map toLower)+ $expect $ equal+ ['a', 'b', 'c']+ (runIdentity (E.run_ (enum $$ EL.consume)))++test_JoinE_Error :: Suite+test_JoinE_Error = assertions "error" $ do+ let enum :: Monad m => E.Enumerator Char m b+ enum = E.joinE (E.enumLists [['A', 'B', 'C']]) (E.sequence (E.throwError (ErrorCall "foo")))+ + $expect $ equalExc+ (ErrorCall "foo")+ (runIdentity (E.run (enum $$ EL.consume)))++test_JoinE_Divergent :: Suite+test_JoinE_Divergent = assertions "divergent" $ do+ let enum :: Monad m => E.Enumerator Char m b+ enum = E.joinE (E.enumLists [['A', 'B', 'C']]) (EL.map toLower)+ let diverg :: Monad m => E.Iteratee a m b+ diverg = E.continue (\_ -> diverg)+ + $expect $ throwsEq+ (ErrorCall "enumEOF: divergent iteratee")+ (E.run_ (enum $$ diverg))++test_JoinI :: Suite+test_JoinI = assertions "joinI" $ do+ let enum :: Monad m => E.Enumerator Char m b+ enum = E.enumLists [['A', 'B', 'C']]+ + let diverg :: Monad m => E.Iteratee a m b+ diverg = E.continue (\_ -> diverg)+ + $expect $ equal+ ['a', 'b', 'c']+ (runIdentity (E.run_ (enum $$ E.joinI (EL.map toLower $$ EL.consume))))+ $expect $ equalExc+ (ErrorCall "foo")+ (runIdentity (E.run (enum $$ E.joinI (EL.map toLower $$ E.throwError (ErrorCall "foo")))))+ $expect $ throwsEq+ (ErrorCall "joinI: divergent iteratee")+ (E.run_ (enum $$ E.joinI (EL.map toLower $$ diverg)))++test_JoinOperatorAssociativity :: Suite+test_JoinOperatorAssociativity = assertions "join-operator-associativity" $ do+ let xs = ['A', 'B', 'C']+ let enum = E.enumList 1 xs+ let enee = EL.map id+ let iter = EL.consume+ xs1 <- E.run_ $ enum $$ enee =$ enee =$ iter+ xs2 <- E.run_ $ enum $= enee $$ enee =$ iter+ xs3 <- E.run_ $ enum $= enee $= enee $$ iter+ $expect (equal xs xs1)+ $expect (equal xs xs2)+ $expect (equal xs xs3)+ return ()
+ tests/EnumeratorTests/List.hs view
@@ -0,0 +1,62 @@+{-# LANGUAGE OverloadedStrings #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.List+ ( test_List+ ) where++import Test.Chell++import EnumeratorTests.List.Consume+import EnumeratorTests.List.Drop+import EnumeratorTests.List.Fold+import EnumeratorTests.List.Isolate+import EnumeratorTests.List.Iterate+import EnumeratorTests.List.Map+import EnumeratorTests.List.Repeat+import EnumeratorTests.List.Replicate+import EnumeratorTests.List.Require+import EnumeratorTests.List.Split+import EnumeratorTests.List.Unfold+import EnumeratorTests.List.Unique+import EnumeratorTests.List.Zip++test_List :: Suite+test_List = suite "list"+ [ test_Consume+ , test_ConcatMap+ , test_ConcatMapM+ , test_ConcatMapAccum+ , test_ConcatMapAccumM+ , test_Drop+ , test_DropWhile+ , test_Fold+ , test_FoldM+ , test_Filter+ , test_FilterM+ , test_GenerateM+ , test_Head+ , test_Head_+ , test_Isolate+ , test_Iterate+ , test_IterateM+ , test_Map+ , test_MapM+ , test_MapM_+ , test_MapAccum+ , test_MapAccumM+ , test_Repeat+ , test_RepeatM+ , test_Replicate+ , test_ReplicateM+ , test_Require+ , test_SplitWhen+ , test_Take+ , test_TakeWhile+ , test_Unfold+ , test_UnfoldM+ , test_Unique+ , test_Zip+ ]
+ tests/EnumeratorTests/List/Consume.hs view
@@ -0,0 +1,102 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.List.Consume+ ( test_Consume+ , test_Head+ , test_Head_+ , test_Take+ , test_TakeWhile+ ) where++import Control.Exception+import Test.Chell++import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL++import EnumeratorTests.Util (equalExc)++test_Consume :: Suite+test_Consume = assertions "consume" $ do+ $expect $ equal+ (['A', 'B', 'C'], Nothing)+ (E.runLists_ [[], ['A', 'B'], ['C']] $ do+ xs <- EL.consume+ h <- EL.head+ return (xs, h))++test_Head :: Suite+test_Head = assertions "head" $ do+ $expect $ equal+ (Just 'A', ['B', 'C'])+ (E.runLists_ [[], ['A', 'B'], ['C']] $ do+ x <- EL.head+ extra <- EL.consume+ return (x, extra))+ $expect $ equal+ (Nothing :: Maybe Char, [])+ (E.runLists_ [] $ do+ x <- EL.head+ extra <- EL.consume+ return (x, extra))++test_Head_ :: Suite+test_Head_ = assertions "head_" $ do+ $expect $ equal+ ('A', ['B', 'C'])+ (E.runLists_ [[], ['A', 'B'], ['C']] $ do+ x <- EL.head_+ extra <- EL.consume+ return (x, extra))+ $expect $ equalExc+ (ErrorCall "head_: stream has ended")+ (E.runLists [] $ do+ x <- EL.head_+ extra <- EL.consume+ return (x, extra))++test_Take :: Suite+test_Take = assertions "take" $ do+ $expect $ equal+ (['A', 'B', 'C'], ['D', 'E'])+ (E.runLists_ [['A', 'B'], ['C', 'D'], ['E']] $ do+ x <- EL.take 3+ extra <- EL.consume+ return (x, extra))+ $expect $ equal+ (['A', 'B'], [])+ (E.runLists_ [['A'], ['B']] $ do+ x <- EL.take 3+ extra <- EL.consume+ return (x, extra))+ $expect $ equal+ ([], ['A', 'B'])+ (E.runLists_ [['A'], ['B']] $ do+ x <- EL.take 0+ extra <- EL.consume+ return (x, extra))++test_TakeWhile :: Suite+test_TakeWhile = assertions "takeWhile" $ do+ $expect $ equal+ (['A', 'B', 'C'], ['D', 'E'])+ (E.runLists_ [[], ['A', 'B'], ['C', 'D'], ['E']] $ do+ x <- EL.takeWhile (< 'D')+ extra <- EL.consume+ return (x, extra))+ $expect $ equal+ (['A', 'B'], [])+ (E.runLists_ [['A'], ['B']] $ do+ x <- EL.takeWhile (< 'D')+ extra <- EL.consume+ return (x, extra))+ $expect $ equal+ ([], ['A', 'B'])+ (E.runLists_ [['A'], ['B']] $ do+ x <- EL.takeWhile (< 'A')+ extra <- EL.consume+ return (x, extra))
+ tests/EnumeratorTests/List/Drop.hs view
@@ -0,0 +1,63 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.List.Drop+ ( test_Drop+ , test_DropWhile+ , test_Filter+ , test_FilterM+ ) where++import Test.Chell++import Data.Enumerator ((=$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL++test_Drop :: Suite+test_Drop = assertions "drop" $ do+ $expect $ equal+ ['A', 'B', 'C', 'D', 'E']+ (E.runLists_ [['A'], ['B'], ['C'], ['D'], ['E']] $ do+ EL.drop 0+ EL.consume)+ $expect $ equal+ ['C', 'D', 'E']+ (E.runLists_ [['A'], ['B'], ['C'], ['D'], ['E']] $ do+ EL.drop 2+ EL.consume)+ $expect $ equal+ []+ (E.runLists_ [['A']] $ do+ EL.drop 2+ EL.consume)++test_DropWhile :: Suite+test_DropWhile = assertions "dropWhile" $ do+ $expect $ equal+ ['C', 'D', 'E']+ (E.runLists_ [['A'], ['B'], ['C'], ['D'], ['E']] $ do+ EL.dropWhile (< 'C')+ EL.consume)+ $expect $ equal+ []+ (E.runLists_ [['A'], ['B'], ['C'], ['D'], ['E']] $ do+ EL.dropWhile (\_ -> True)+ EL.consume)++test_Filter :: Suite+test_Filter = assertions "filter" $ do+ $expect $ equal+ ['A', 'B', 'D', 'E']+ (E.runLists_ [['A'], ['B'], ['C'], ['D'], ['E']] $ do+ EL.filter (/= 'C') =$ EL.consume)++test_FilterM :: Suite+test_FilterM = assertions "filterM" $ do+ $expect $ equal+ ['A', 'B', 'D', 'E']+ (E.runLists_ [['A'], ['B'], ['C'], ['D'], ['E']] $ do+ EL.filterM (\x -> return (x /= 'C')) =$ EL.consume)
+ tests/EnumeratorTests/List/Fold.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2011 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.List.Fold+ ( test_Fold+ , test_FoldM+ ) where++import qualified Control.Exception as Exception+import Control.Monad (foldM)+import Data.Functor.Identity (runIdentity)+import Data.List (foldl')+import Test.Chell+import Test.Chell.QuickCheck+import Test.QuickCheck.Poly+import Test.QuickCheck.Modifiers++import qualified Data.Enumerator as E+import Data.Enumerator (($$))+import qualified Data.Enumerator.List as EL++import EnumeratorTests.List.Util ()++test_Fold :: Suite+test_Fold = suite "fold"+ [ property "model" prop_Fold+ , test_FoldStrict+ , test_Fold_EOF+ ]++prop_Fold :: Blind (B -> A -> B) -> B -> [A] -> Bool+prop_Fold (Blind f) z xs = result == expected where+ result = E.runLists_ [xs] (EL.fold f z)+ expected = foldl' f z xs++test_FoldStrict :: Suite+test_FoldStrict = assertions "strict" $ do+ let exc = Exception.ErrorCall "fail-step"+ let step _ x = case x of+ 'C' -> Exception.throw exc+ _ -> 'a'+ $expect $ throwsEq exc (E.run_ (E.enumList 1 ['A', 'B', 'C'] $$ EL.fold step 'a'))+ $expect $ throwsEq exc (E.run_ (E.enumList 3 ['A', 'B', 'C'] $$ EL.fold step 'a'))++test_Fold_EOF :: Suite+test_Fold_EOF = assertions "eof" $ do+ $expect $ equal+ Nothing+ (E.runLists_ [] $ do+ _ <- EL.fold (++) ['A']+ EL.head)++test_FoldM :: Suite+test_FoldM = suite "foldM"+ [ property "model" prop_FoldM+ , test_FoldM_EOF+ ]++prop_FoldM :: Blind (B -> A -> B) -> B -> [A] -> Bool+prop_FoldM (Blind f) z xs = result == expected where+ result = E.runLists_ [xs] (EL.foldM f' z)+ expected = runIdentity (foldM f' z xs)+ f' b a = return (f b a)++test_FoldM_EOF :: Suite+test_FoldM_EOF = assertions "eof" $ do+ $expect $ equal+ Nothing+ (E.runLists_ [] $ do+ _ <- EL.foldM (\x y -> return (x ++ y)) ['A']+ EL.head)
+ tests/EnumeratorTests/List/Isolate.hs view
@@ -0,0 +1,70 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.List.Isolate+ ( test_Isolate+ ) where++import Test.Chell+import Test.Chell.QuickCheck++import Data.Enumerator ((=$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL++import EnumeratorTests.List.Util++test_Isolate :: Suite+test_Isolate = suite "isolate"+ [ prop_Isolate+ , test_DropExtra+ , test_HandleEOF+ , test_BadParameter+ ]++prop_Isolate :: Suite+prop_Isolate = property "model" $ prop_List+ (do+ x <- EL.isolate 2 =$ EL.head+ extra <- EL.consume+ return (x, extra))+ (\xs -> Right $ case xs of+ [] -> (Nothing, [])+ (x:[]) -> (Just x, [])+ (x:_:xs') -> (Just x, xs'))++test_DropExtra :: Suite+test_DropExtra = assertions "drop-extra" $ do+ $expect $ equal+ (Just 'A', ['C'])+ (E.runLists_ [[], ['A'], ['B'], ['C']] $ do+ x <- EL.isolate 2 =$ EL.head+ extra <- EL.consume+ return (x, extra))+ $expect $ equal+ (Just 'A', ['C'])+ (E.runLists_ [['A', 'B', 'C']] $ do+ x <- EL.isolate 2 =$ EL.head+ extra <- EL.consume+ return (x, extra))++test_HandleEOF :: Suite+test_HandleEOF = assertions "handle-eof" $ do+ $expect $ equal+ (Nothing :: Maybe Char, [])+ (E.runLists_ [] $ do+ x <- EL.isolate 2 =$ EL.head+ extra <- EL.consume+ return (x, extra))++test_BadParameter :: Suite+test_BadParameter = assertions "bad-parameter" $ do+ $expect $ equal+ (Nothing, ['A', 'B', 'C'])+ (E.runLists_ [['A'], ['B'], ['C']] $ do+ x <- EL.isolate 0 =$ EL.head+ extra <- EL.consume+ return (x, extra))
+ tests/EnumeratorTests/List/Iterate.hs view
@@ -0,0 +1,30 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2011 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.List.Iterate+ ( test_Iterate+ , test_IterateM+ ) where++import Data.Functor.Identity (runIdentity)+import Test.Chell++import Data.Enumerator (($$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL++test_Iterate :: Suite+test_Iterate = assertions "iterate" $ do+ $expect $ equal+ ['A', 'B', 'C']+ (runIdentity (E.run_ (EL.iterate succ 'A' $$ EL.take 3)))++test_IterateM :: Suite+test_IterateM = assertions "iterateM" $ do+ let succM = return . succ+ $expect $ equal+ ['A', 'B', 'C']+ (runIdentity (E.run_ (EL.iterateM succM 'A' $$ EL.take 3)))
+ tests/EnumeratorTests/List/Map.hs view
@@ -0,0 +1,142 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.List.Map+ ( test_Map+ , test_MapM+ , test_MapM_+ , test_ConcatMap+ , test_ConcatMapM+ , test_ConcatMapAccum+ , test_ConcatMapAccumM+ , test_MapAccum+ , test_MapAccumM+ ) where++import Control.Monad.Trans.Writer (execWriter, tell)+import Data.Char (chr, ord, toLower)+import Test.Chell++import Data.Enumerator (($$), (=$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL++test_Map :: Suite+test_Map = assertions "map" $ do+ $expect $ equal+ ['a', 'b', 'c']+ (E.runLists_ [['A', 'B'], ['C']] $ do+ EL.map toLower =$ EL.consume)+ $expect $ equal+ (['a'], ['B', 'C'])+ (E.runLists_ [['A', 'B'], ['C']] $ do+ xs <- EL.map toLower =$ EL.take 1+ extra <- EL.consume+ return (xs, extra))++test_MapM :: Suite+test_MapM = assertions "mapM" $ do+ let step = return . toLower+ $expect $ equal+ ['a', 'b', 'c']+ (E.runLists_ [['A', 'B'], ['C']] $ do+ EL.mapM step =$ EL.consume)+ $expect $ equal+ (['a'], ['B', 'C'])+ (E.runLists_ [['A', 'B'], ['C']] $ do+ xs <- EL.mapM step =$ EL.take 1+ extra <- EL.consume+ return (xs, extra))++test_MapM_ :: Suite+test_MapM_ = assertions "mapM_" $ do+ $expect $ equal+ ['A', 'B', 'C']+ (execWriter (E.run_ (E.enumList 1 ['A', 'B', 'C'] $$ EL.mapM_ (\x -> tell [x]))))++test_ConcatMap :: Suite+test_ConcatMap = assertions "concatMap" $ do+ let step ao = [ao, toLower ao]+ $expect $ equal+ ['A', 'a', 'B', 'b', 'C', 'c']+ (E.runLists_ [['A', 'B'], ['C']] $ do+ EL.concatMap step =$ EL.consume)+ $expect $ equal+ (['A', 'a'], ['B', 'C'])+ (E.runLists_ [['A', 'B'], ['C']] $ do+ xs <- EL.concatMap step =$ EL.take 2+ extra <- EL.consume+ return (xs, extra))++test_ConcatMapM :: Suite+test_ConcatMapM = assertions "concatMapM" $ do+ let step ao = return [ao, toLower ao]+ $expect $ equal+ ['A', 'a', 'B', 'b', 'C', 'c']+ (E.runLists_ [['A', 'B'], ['C']] $ do+ EL.concatMapM step =$ EL.consume)+ $expect $ equal+ (['A', 'a'], ['B', 'C'])+ (E.runLists_ [['A', 'B'], ['C']] $ do+ xs <- EL.concatMapM step =$ EL.take 2+ extra <- EL.consume+ return (xs, extra))++test_MapAccum :: Suite+test_MapAccum = assertions "mapAccum" $ do+ let step s ao = (s + 1, chr (ord ao + s))+ $expect $ equal+ ['B', 'D', 'F']+ (E.runLists_ [['A', 'B'], ['C']] $ do+ EL.mapAccum step 1 =$ EL.consume)+ $expect $ equal+ (['B'], ['B', 'C'])+ (E.runLists_ [['A', 'B'], ['C']] $ do+ xs <- EL.mapAccum step 1 =$ EL.take 1+ extra <- EL.consume+ return (xs, extra))++test_MapAccumM :: Suite+test_MapAccumM = assertions "mapAccumM" $ do+ let step s ao = return (s + 1, chr (ord ao + s))+ $expect $ equal+ ['B', 'D', 'F']+ (E.runLists_ [['A', 'B'], ['C']] $ do+ EL.mapAccumM step 1 =$ EL.consume)+ $expect $ equal+ (['B'], ['B', 'C'])+ (E.runLists_ [['A', 'B'], ['C']] $ do+ xs <- EL.mapAccumM step 1 =$ EL.take 1+ extra <- EL.consume+ return (xs, extra))++test_ConcatMapAccum :: Suite+test_ConcatMapAccum = assertions "concatMapAccum" $ do+ let step s ao = (s + 1, replicate s ao)+ $expect $ equal+ ['A', 'B', 'B', 'C', 'C', 'C']+ (E.runLists_ [['A', 'B'], ['C']] $ do+ EL.concatMapAccum step 1 =$ EL.consume)+ $expect $ equal+ (['A', 'B'], ['C'])+ (E.runLists_ [['A', 'B'], ['C']] $ do+ xs <- EL.concatMapAccum step 1 =$ EL.take 2+ extra <- EL.consume+ return (xs, extra))++test_ConcatMapAccumM :: Suite+test_ConcatMapAccumM = assertions "concatMapAccumM" $ do+ let step s ao = return (s + 1, replicate s ao)+ $expect $ equal+ ['A', 'B', 'B', 'C', 'C', 'C']+ (E.runLists_ [['A', 'B'], ['C']] $ do+ EL.concatMapAccumM step 1 =$ EL.consume)+ $expect $ equal+ (['A', 'B'], ['C'])+ (E.runLists_ [['A', 'B'], ['C']] $ do+ xs <- EL.concatMapAccumM step 1 =$ EL.take 2+ extra <- EL.consume+ return (xs, extra))
+ tests/EnumeratorTests/List/Repeat.hs view
@@ -0,0 +1,48 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2011 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.List.Repeat+ ( test_Repeat+ , test_RepeatM+ , test_GenerateM+ ) where++import Control.Monad.Trans.State+import Data.Functor.Identity (runIdentity)+import Test.Chell++import Data.Enumerator (($$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL++test_Repeat :: Suite+test_Repeat = assertions "repeat" $ do+ $expect $ equal+ ['A', 'A', 'A']+ (runIdentity (E.run_ (EL.repeat 'A' $$ EL.take 3)))++test_RepeatM :: Suite+test_RepeatM = assertions "repeatM" $ do+ let step = do+ c <- get+ put (succ c)+ return c+ $expect $ equal+ ['A', 'B', 'C']+ (evalState (E.run_ (EL.repeatM step $$ EL.take 3)) 'A')++test_GenerateM :: Suite+test_GenerateM = assertions "generateM" $ do+ let step = do+ c <- get+ if c > 'C'+ then return Nothing+ else do+ put (succ c)+ return (Just c)+ $expect $ equal+ ['A', 'B', 'C']+ (evalState (E.run_ (EL.generateM step $$ EL.consume)) 'A')
+ tests/EnumeratorTests/List/Replicate.hs view
@@ -0,0 +1,40 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2011 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.List.Replicate+ ( test_Replicate+ , test_ReplicateM+ ) where++import Control.Monad.Trans.State+import Data.Functor.Identity (runIdentity)+import Test.Chell++import Data.Enumerator (($$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL++test_Replicate :: Suite+test_Replicate = assertions "replicate" $ do+ $expect $ equal+ ['A', 'A', 'A']+ (runIdentity (E.run_ (EL.replicate 3 'A' $$ EL.consume)))+ $expect $ equal+ ['A', 'A']+ (runIdentity (E.run_ (EL.replicate 3 'A' $$ EL.take 2)))++test_ReplicateM :: Suite+test_ReplicateM = assertions "replicateM" $ do+ let step = do+ c <- get+ put (succ c)+ return c+ $expect $ equal+ ['A', 'B', 'C']+ (evalState (E.run_ (EL.replicateM 3 step $$ EL.consume)) 'A')+ $expect $ equal+ ['A', 'B']+ (evalState (E.run_ (EL.replicateM 3 step $$ EL.take 2)) 'A')
+ tests/EnumeratorTests/List/Require.hs view
@@ -0,0 +1,65 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.List.Require+ ( test_Require+ ) where++import qualified Control.Exception as Exc+import Test.Chell+import Test.Chell.QuickCheck++import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL++import EnumeratorTests.List.Util (prop_ListN)+import EnumeratorTests.Util (equalExc)++test_Require :: Suite+test_Require = suite "require"+ [ prop_Require+ , test_YieldsInput+ , test_HandleEOF+ , test_BadParameter+ ]++prop_Require :: Suite+prop_Require = property "model" $ prop_ListN+ (\n -> do+ EL.require n+ EL.consume)+ (\n xs -> if n > toInteger (length xs)+ then Left (Exc.ErrorCall "require: Unexpected EOF")+ else Right xs)++test_YieldsInput :: Suite+test_YieldsInput = assertions "yields-input" $ do+ $expect $ equal+ ['A', 'B', 'C']+ (E.runLists_ [['A'], ['B'], ['C']] $ do+ EL.require 2+ EL.consume)+ $expect $ equal+ ['A', 'B', 'C']+ (E.runLists_ [['A', 'B', 'C']] $ do+ EL.require 2+ EL.consume)++test_HandleEOF :: Suite+test_HandleEOF = assertions "handle-eof" $ do+ $expect $ equalExc+ (Exc.ErrorCall "require: Unexpected EOF")+ (E.runLists [] $ do+ EL.require 2+ EL.consume)++test_BadParameter :: Suite+test_BadParameter = assertions "bad-parameter" $ do+ $expect $ equal+ ([] :: [Char])+ (E.runLists_ [] $ do+ EL.require 0+ EL.consume)
+ tests/EnumeratorTests/List/Split.hs view
@@ -0,0 +1,28 @@+{-# LANGUAGE OverloadedStrings #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.List.Split+ ( test_SplitWhen+ ) where+++import qualified Data.List.Split as LS+import Test.Chell+import Test.Chell.QuickCheck++import Data.Enumerator ((=$))+import qualified Data.Enumerator.List as EL++import EnumeratorTests.List.Util++test_SplitWhen :: Suite+test_SplitWhen = property "splitWhen" $ prop_ListX+ (\x -> do+ xs <- EL.splitWhen (== x) =$ EL.consume+ extra <- EL.consume+ return (xs, extra))+ (\x xs -> let+ split = LS.split . LS.dropFinalBlank . LS.dropDelims . LS.whenElt+ in Right (split (== x) xs, []))
+ tests/EnumeratorTests/List/Unfold.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2011 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.List.Unfold+ ( test_Unfold+ , test_UnfoldM+ ) where++import Data.Functor.Identity (runIdentity)+import Test.Chell++import Data.Enumerator (($$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL++test_Unfold :: Suite+test_Unfold = assertions "unfold" $ do+ let step x = if x > 'C'+ then Nothing+ else Just (x, succ x)+ $expect $ equal+ ['A', 'B', 'C']+ (runIdentity (E.run_ (EL.unfold step 'A' $$ EL.consume)))++test_UnfoldM :: Suite+test_UnfoldM = assertions "unfoldM" $ do+ let step x = return $ if x > 'C'+ then Nothing+ else Just (x, succ x)+ $expect $ equal+ ['A', 'B', 'C']+ (runIdentity (E.run_ (EL.unfoldM step 'A' $$ EL.consume)))
+ tests/EnumeratorTests/List/Unique.hs view
@@ -0,0 +1,22 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2011 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.List.Unique+ ( test_Unique+ ) where++import Test.Chell++import Data.Enumerator ((=$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL++test_Unique :: Suite+test_Unique = assertions "unique" $ do+ $expect $ equal+ ['B', 'A', 'C']+ (E.runLists_ [['B'], ['A'], ['B'], ['C'], ['A']] $ do+ EL.unique =$ EL.consume)
+ tests/EnumeratorTests/List/Util.hs view
@@ -0,0 +1,81 @@+{-# LANGUAGE OverloadedStrings #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.List.Util+ ( test_Enumeratee+ , prop_List+ , prop_ListN+ , prop_ListX+ ) where++import qualified Control.Exception as Exc+import Data.Functor.Identity (Identity, runIdentity)+import qualified Data.Text as T++import Test.Chell+import Test.Chell.QuickCheck+import Test.QuickCheck hiding (property)+import Test.QuickCheck.Poly (A)++import Data.Enumerator (($$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL++import EnumeratorTests.Util (check)++test_Enumeratee :: T.Text -> E.Enumeratee A A Identity (Maybe A) -> Suite+test_Enumeratee name enee = suite name props where+ props = [ property "incremental" prop_incremental+ , property "nest-errors" prop_nest_errors+ ]+ + prop_incremental (Positive n) (NonEmpty xs) = let+ result = runIdentity (E.run_ iter)+ expected = (Just (head xs), tail xs)+ + iter = E.enumList n xs $$ do+ a <- E.joinI (enee $$ EL.head)+ b <- EL.consume+ return (a, b)+ + in result == expected+ + prop_nest_errors (Positive n) (NonEmpty xs) = let+ result = runIdentity (E.run_ iter)+ + iter = E.enumList n xs $$ do+ _ <- enee $$ E.throwError (Exc.ErrorCall "")+ EL.consume+ + in result == xs++prop_List :: Eq b+ => E.Iteratee A Identity b+ -> ([A] -> Either Exc.ErrorCall b)+ -> [A]+ -> Bool+prop_List iter plain = prop where+ prop :: [A] -> Bool+ prop = check iter plain++prop_ListN :: Eq b+ => (Integer -> E.Iteratee A Identity b)+ -> (Integer -> [A] -> Either Exc.ErrorCall b)+ -> Positive Integer+ -> [A]+ -> Bool+prop_ListN iter plain = prop where+ prop :: Positive Integer -> [A] -> Bool+ prop (Positive n) = check (iter n) (plain n)++prop_ListX :: Eq b+ => (A -> E.Iteratee A Identity b)+ -> (A -> [A] -> Either Exc.ErrorCall b)+ -> A+ -> [A]+ -> Bool+prop_ListX iter plain = prop where+ prop :: A -> [A] -> Bool+ prop x = check (iter x) (plain x)
+ tests/EnumeratorTests/List/Zip.hs view
@@ -0,0 +1,172 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.List.Zip+ ( test_Zip+ ) where++import qualified Control.Exception as Exc+import Data.Functor.Identity (Identity)+import Data.Text (Text)+import Test.Chell++import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL++import EnumeratorTests.List.Util ()+import EnumeratorTests.Util (equalExc)++test_ZipN :: (Eq b, Show b) => Text -> E.Iteratee Char Identity b -> b -> Suite+test_ZipN name iter expected = assertions name $ do+ $expect $ equal+ expected+ (E.runLists_ [[], ['A'], ['B']] iter)++$([d||])++test_Zip :: Suite+test_Zip = suite "zip"+ [ test_ContinueContinue+ , test_YieldContinue+ , test_ContinueYield+ , test_YieldYield+ , test_ErrorFirst+ , test_ErrorSecond+ , test_HandleEOF+ , test_Zip3+ , test_Zip4+ , test_Zip5+ , test_Zip6+ , test_Zip7+ , test_ZipWith+ , test_ZipWith3+ , test_ZipWith4+ , test_ZipWith5+ , test_ZipWith6+ , test_ZipWith7+ ]++test_ContinueContinue :: Suite+test_ContinueContinue = assertions "continue-continue" $ do+ $expect $ equal+ (['A', 'B'], ['A', 'B'], ['C'])+ (E.runLists_ [['A'], ['B'], ['C']] $ do+ (x, y) <- EL.zip (EL.take 2) (EL.take 2)+ extra <- EL.consume+ return (x, y, extra))++test_YieldContinue :: Suite+test_YieldContinue = assertions "yield-continue" $ do+ $expect $ equal+ (['A'], ['A', 'B'], ['C'])+ (E.runLists_ [['A'], ['B'], ['C']] $ do+ (x, y) <- EL.zip (EL.take 1) (EL.take 2)+ extra <- EL.consume+ return (x, y, extra))++test_ContinueYield :: Suite+test_ContinueYield = assertions "continue-yield" $ do+ $expect $ equal+ (['A', 'B'], ['A'], ['C'])+ (E.runLists_ [['A'], ['B'], ['C']] $ do+ (x, y) <- EL.zip (EL.take 2) (EL.take 1)+ extra <- EL.consume+ return (x, y, extra))++test_YieldYield :: Suite+test_YieldYield = assertions "yield-yield" $ do+ $expect $ equal+ (['A'], ['A'], ['B', 'C'])+ (E.runLists_ [['A'], ['B'], ['C']] $ do+ (x, y) <- EL.zip (EL.take 1) (EL.take 1)+ extra <- EL.consume+ return (x, y, extra))++test_ErrorFirst :: Suite+test_ErrorFirst = assertions "error-first" $ do+ $expect $ equalExc+ (Exc.ErrorCall "error")+ (E.runLists [['A'], ['B'], ['C']] $ do+ EL.zip (E.throwError (Exc.ErrorCall "error")) (EL.take 1))++test_ErrorSecond :: Suite+test_ErrorSecond = assertions "error-second" $ do+ $expect $ equalExc+ (Exc.ErrorCall "error")+ (E.runLists [['A'], ['B'], ['C']] $ do+ EL.zip (EL.take 1) (E.throwError (Exc.ErrorCall "error")))++test_HandleEOF :: Suite+test_HandleEOF = assertions "handle-eof" $ do+ $expect $ equal+ (['A'], ['A', 'B'], [])+ (E.runLists_ [['A'], ['B']] $ do+ (x, y) <- EL.zip (EL.take 1) (EL.take 3)+ extra <- EL.consume+ return (x, y, extra))+ $expect $ equal+ (['a'], ['b'], [])+ (E.runLists_ [['A'], ['B']] $ do+ (x, y) <- EL.zip+ (E.yield ['a'] (E.Chunks []))+ (E.yield ['b'] E.EOF)+ extra <- EL.consume+ return (x, y, extra))++test_Zip3 :: Suite+test_Zip3 = test_ZipN "zip3"+ (EL.zip3 EL.head EL.head EL.head)+ (Just 'A', Just 'A', Just 'A')++test_Zip4 :: Suite+test_Zip4 = test_ZipN "zip4"+ (EL.zip4 EL.head EL.head EL.head EL.head)+ (Just 'A', Just 'A', Just 'A', Just 'A')++test_Zip5 :: Suite+test_Zip5 = test_ZipN "zip5"+ (EL.zip5 EL.head EL.head EL.head EL.head EL.head)+ (Just 'A', Just 'A', Just 'A', Just 'A', Just 'A')++test_Zip6 :: Suite+test_Zip6 = test_ZipN "zip6"+ (EL.zip6 EL.head EL.head EL.head EL.head EL.head EL.head)+ (Just 'A', Just 'A', Just 'A', Just 'A', Just 'A', Just 'A')++test_Zip7 :: Suite+test_Zip7 = test_ZipN "zip7"+ (EL.zip7 EL.head EL.head EL.head EL.head EL.head EL.head EL.head)+ (Just 'A', Just 'A', Just 'A', Just 'A', Just 'A', Just 'A', Just 'A')++test_ZipWith :: Suite+test_ZipWith = test_ZipN "zipWith"+ (EL.zipWith (,) EL.head EL.head)+ (Just 'A', Just 'A')++test_ZipWith3 :: Suite+test_ZipWith3 = test_ZipN "zipWith3"+ (EL.zipWith3 (,,) EL.head EL.head EL.head)+ (Just 'A', Just 'A', Just 'A')++test_ZipWith4 :: Suite+test_ZipWith4 = test_ZipN "zipWith4"+ (EL.zipWith4 (,,,) EL.head EL.head EL.head EL.head)+ (Just 'A', Just 'A', Just 'A', Just 'A')++test_ZipWith5 :: Suite+test_ZipWith5 = test_ZipN "zipWith5"+ (EL.zipWith5 (,,,,) EL.head EL.head EL.head EL.head EL.head)+ (Just 'A', Just 'A', Just 'A', Just 'A', Just 'A')++test_ZipWith6 :: Suite+test_ZipWith6 = test_ZipN "zipWith6"+ (EL.zipWith6 (,,,,,) EL.head EL.head EL.head EL.head EL.head EL.head)+ (Just 'A', Just 'A', Just 'A', Just 'A', Just 'A', Just 'A')++test_ZipWith7 :: Suite+test_ZipWith7 = test_ZipN "zipWith7"+ (EL.zipWith7 (,,,,,,) EL.head EL.head EL.head EL.head EL.head EL.head EL.head)+ (Just 'A', Just 'A', Just 'A', Just 'A', Just 'A', Just 'A', Just 'A')
+ tests/EnumeratorTests/Misc.hs view
@@ -0,0 +1,143 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Misc+ ( test_ConcatEnums+ , test_EnumEOF+ , test_Last+ , test_Length+ , test_LiftTrans+ , test_Peek+ , test_TryIO+ , test_PrintChunks+ ) where++import Control.Exception+import Control.Monad.Trans.Reader+import Control.Monad.IO.Class+import Data.Functor.Identity+import Test.Chell++#ifdef MIN_VERSION_silently++import System.IO.Silently (capture)++#endif++import Data.Enumerator (($$), (<==<))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL++import EnumeratorTests.Util (equalExc)++test_ConcatEnums :: Suite+test_ConcatEnums = assertions "concatEnums" $ do+ let enum = E.concatEnums+ [ E.enumLists [['A']]+ , E.enumLists [['B']]+ , E.enumLists [['C']]+ ]+ $expect $ equal+ ['A', 'B', 'C']+ (runIdentity (E.run_ (enum $$ EL.consume)))+ $expect $ equal+ ['A', 'B']+ (runIdentity (E.run_ (E.enumLists [['B']] <==< E.enumLists [['A']] $$ EL.consume)))++test_EnumEOF :: Suite+test_EnumEOF = assertions "enumEOF" $ do+ let iter = E.continue (\_ -> iter)+ + $expect $ throwsEq+ (ErrorCall "enumEOF: divergent iteratee")+ (E.runIteratee (E.enumEOF $$ iter))++test_Last :: Suite+test_Last = assertions "last" $ do+ $expect $ equal+ (Nothing :: Maybe Char, [])+ (E.runLists_ [[]] $ do+ x <- E.last+ extra <- EL.consume+ return (x, extra))+ $expect $ equal+ (Just 'E', [])+ (E.runLists_ [['A', 'B'], ['C', 'D'], ['E']] $ do+ x <- E.last+ extra <- EL.consume+ return (x, extra))++test_Length :: Suite+test_Length = assertions "length" $ do+ $expect $ equal+ 5+ (E.runLists_ [['A', 'B'], ['C', 'D'], ['E']] E.length)++test_LiftTrans :: Suite+test_LiftTrans = assertions "liftTrans" $ do+ let iter1 :: E.Iteratee Char Identity (Maybe Char)+ iter1 = EL.head+ + let iter2 :: Bool -> E.Iteratee Char (ReaderT Int Identity) (Maybe Char, [Char])+ iter2 bad = do+ x <- E.liftTrans (if bad then E.throwError (ErrorCall "failed") else iter1)+ xs <- EL.consume+ return (x, xs)+ + $expect $ equal+ (Just 'A', ['B', 'C', 'D', 'E'])+ (runIdentity (runReaderT (E.run_ (E.enumList 1 ['A'..'E'] $$ iter2 False)) 0))+ + $expect $ equalExc+ (ErrorCall "failed")+ (runIdentity (runReaderT (E.run (E.enumList 1 ['A'..'E'] $$ iter2 True)) 0))++test_Peek :: Suite+test_Peek = assertions "peek" $ do+ $expect $ equal+ (Nothing :: Maybe Char, [])+ (E.runLists_ [] $ do+ x <- E.peek+ extra <- EL.consume+ return (x, extra))+ $expect $ equal+ (Just 'A', ['A', 'B', 'C', 'D', 'E'])+ (E.runLists_ [[], ['A', 'B'], ['C', 'D'], ['E']] $ do+ x <- E.peek+ extra <- EL.consume+ return (x, extra))+ $expect $ equal+ (Just 'A', ['A'])+ (E.runLists_ [['A']] $ do+ x <- E.peek+ extra <- EL.consume+ return (x, extra))++test_TryIO :: Suite+test_TryIO = assertions "tryIO" $ do+ do+ res <- E.run (E.tryIO (return 'A'))+ $expect (right res)+ let Right res' = res+ $expect (equal 'A' res')+ + do+ res <- E.run (E.tryIO (throwIO (ErrorCall "failed")))+ $expect (equalExc (ErrorCall "failed") res)++test_PrintChunks :: Suite+#ifdef MIN_VERSION_silently+test_PrintChunks = assertions "printChunks" $ do+ do+ (stdout, _) <- liftIO (capture (E.run_ (E.enumLists [[], ['A', 'B'], ['C']] $$ E.printChunks False)))+ $expect (equal stdout "\"AB\"\n\"C\"\nEOF\n")+ do+ (stdout, _) <- liftIO (capture (E.run_ (E.enumLists [[], ['A', 'B'], ['C']] $$ E.printChunks True)))+ $expect (equal stdout "\"\"\n\"AB\"\n\"C\"\nEOF\n")+#else+test_PrintChunks = skipIf True (assertions "printChunks" (return ()))+#endif
+ tests/EnumeratorTests/Sequence.hs view
@@ -0,0 +1,28 @@+{-# LANGUAGE OverloadedStrings #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Sequence+ ( test_Sequence+ ) where++import Data.Functor.Identity (Identity, runIdentity)++import Test.Chell+import Test.Chell.QuickCheck+import Test.QuickCheck hiding (property)+import Test.QuickCheck.Poly (A)++import Data.Enumerator (($$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL++test_Sequence :: Suite+test_Sequence = property "sequence" prop where+ prop :: Positive Integer -> [A] -> Bool+ prop (Positive n) xs = result == expected where+ result = runIdentity (E.run_ iter)+ expected = map Just xs+ + iter = E.enumList n xs $$ E.joinI (E.sequence EL.head $$ EL.consume)
+ tests/EnumeratorTests/Stream.hs view
@@ -0,0 +1,82 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010-2011 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Stream+ ( test_Stream+ ) where++import Control.Applicative (pure, (<*>))+import Data.Monoid (mappend, mempty, mconcat)++import Test.Chell+import Test.Chell.QuickCheck+import Test.QuickCheck hiding (property)+import Test.QuickCheck.Poly (A, B, C)++import qualified Data.Enumerator as E++import EnumeratorTests.Util ()++test_Stream :: Suite+test_Stream = suite "stream"+ [ test_Monoid+ , test_Functor+ , test_Monad+ , test_Applicative+ ]++test_Monoid :: Suite+test_Monoid = suite "monoid"+ [ property "law-1" prop_MonoidLaw1+ , property "law-2" prop_MonoidLaw2+ , property "law-3" prop_MonoidLaw3+ , property "law-4" prop_MonoidLaw4+ ]++prop_MonoidLaw1 :: E.Stream A -> Bool+prop_MonoidLaw1 x = mappend mempty x == x++prop_MonoidLaw2 :: E.Stream A -> Bool+prop_MonoidLaw2 x = mappend x mempty == x++prop_MonoidLaw3 :: E.Stream A -> E.Stream A -> E.Stream A -> Bool+prop_MonoidLaw3 x y z = mappend x (mappend y z) == mappend (mappend x y) z++prop_MonoidLaw4 :: [E.Stream A] -> Bool+prop_MonoidLaw4 xs = mconcat xs == foldr mappend mempty xs++test_Functor :: Suite+test_Functor = suite "functor"+ [ property "law-1" prop_FunctorLaw1+ , property "law-2" prop_FunctorLaw2+ ]++prop_FunctorLaw1 :: E.Stream A -> Bool+prop_FunctorLaw1 x = fmap id x == id x++prop_FunctorLaw2 :: E.Stream A -> Blind (B -> C) -> Blind (A -> B) -> Bool+prop_FunctorLaw2 x (Blind f) (Blind g) = fmap (f . g) x == (fmap f . fmap g) x++test_Monad :: Suite+test_Monad = suite "monad"+ [ property "law-1" prop_MonadLaw1+ , property "law-2" prop_MonadLaw2+ , property "law-3" prop_MonadLaw3+ ]++prop_MonadLaw1 :: A -> Blind (A -> E.Stream B) -> Bool+prop_MonadLaw1 a (Blind f) = (return a >>= f) == f a++prop_MonadLaw2 :: E.Stream A -> Bool+prop_MonadLaw2 m = (m >>= return) == m++prop_MonadLaw3 :: E.Stream A -> Blind (A -> E.Stream B) -> Blind (B -> E.Stream C) -> Bool+prop_MonadLaw3 m (Blind f) (Blind g) = ((m >>= f) >>= g) == (m >>= (\x -> f x >>= g))++test_Applicative :: Suite+test_Applicative = assertions "applicative" $ do+ $expect (equal (E.Chunks ['A']) (pure 'A'))+ $expect (equal (E.Chunks ['B']) (pure succ <*> E.Chunks ['A']))
+ tests/EnumeratorTests/Text.hs view
@@ -0,0 +1,66 @@+{-# LANGUAGE OverloadedStrings #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Text+ ( test_Text+ ) where++import Test.Chell++import EnumeratorTests.Text.Codecs+import EnumeratorTests.Text.Consume+import EnumeratorTests.Text.Drop+import EnumeratorTests.Text.Fold+import EnumeratorTests.Text.Handle+import EnumeratorTests.Text.Isolate+import EnumeratorTests.Text.Iterate+import EnumeratorTests.Text.Map+import EnumeratorTests.Text.Repeat+import EnumeratorTests.Text.Replicate+import EnumeratorTests.Text.Require+import EnumeratorTests.Text.Split+import EnumeratorTests.Text.Unfold+import EnumeratorTests.Text.Zip++test_Text :: Suite+test_Text = suite "text"+ [ test_TextCodecs+ , test_Consume+ , test_ConcatMap+ , test_ConcatMapM+ , test_ConcatMapAccum+ , test_ConcatMapAccumM+ , test_Drop+ , test_DropWhile+ , test_EnumHandle+ , test_Filter+ , test_FilterM+ , test_Fold+ , test_FoldM+ , test_GenerateM+ , test_Head+ , test_Head_+ , test_Isolate+ , test_Iterate+ , test_IterateM+ , test_IterHandle+ , test_Lines+ , test_Map+ , test_MapM+ , test_MapM_+ , test_MapAccum+ , test_MapAccumM+ , test_Repeat+ , test_RepeatM+ , test_Replicate+ , test_ReplicateM+ , test_Require+ , test_SplitWhen+ , test_Take+ , test_TakeWhile+ , test_Unfold+ , test_UnfoldM+ , test_Zip+ ]
+ tests/EnumeratorTests/Text/Codecs.hs view
@@ -0,0 +1,322 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Text.Codecs+ ( test_TextCodecs+ ) where++import Prelude hiding (words)++import Control.Exception (ErrorCall(..))+import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as B8+import qualified Data.ByteString.Lazy as BL+import Data.Char (ord)+import qualified Data.Text as T+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Encoding as TE+import qualified Data.Text.Encoding.Error as TE++import Test.Chell+import Test.Chell.QuickCheck+import Test.QuickCheck hiding (property)++import Data.Enumerator ((=$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.Binary as EB+import qualified Data.Enumerator.Text as ET+import qualified Data.Enumerator.List as EL++import EnumeratorTests.Util++test_TextCodecs :: Suite+test_TextCodecs = suite "codecs"+ [ test_ASCII+ , test_ISO8859_1+ , test_UTF8+ , test_UTF16_BE+ , test_UTF16_LE+ , test_UTF32_BE+ , test_UTF32_LE+ ]++test_ASCII :: Suite+test_ASCII = suite "ascii"+ [ property "encode" (forAll genASCII (prop_Encode ET.ascii encodeASCII))+ , property "decode" (forAll genASCII (prop_Decode ET.ascii decodeASCII))+ + , assertions "show" $ do+ $expect $ equal+ "Codec \"ASCII\""+ (show ET.ascii)+ + , assertions "encode-invalid" $ do+ $expect $ equalExc+ (ErrorCall "Codec \"ASCII\" can't encode character U+00FF")+ (E.runLists [["\xFF"]] (ET.encode ET.ascii =$ EB.consume))+ + , assertions "decode-invalid" $ do+ $expect $ equalExc+ (ErrorCall "Codec \"ASCII\" can't decode byte 0xFF")+ (E.runLists [["\xFF"]] (ET.decode ET.ascii =$ ET.consume))+ + , skipIf True $ assertions "lazy.broken" $ do+ $expect $ equal+ (Just 0x61, ["b"])+ (E.runLists_ [["", "ab"]] (do+ x <- ET.encode ET.ascii =$ EB.head+ y <- EL.consume+ return (x, y)))+ + , assertions "lazy" $ do+ $expect $ equal+ (Just 0x61, ["b"])+ (E.runLists_ [[""], ["a"], ["b"]] $ do+ x <- ET.encode ET.ascii =$ EB.head+ y <- EL.consume+ return (x, y))+ $expect $ equal+ (Just 0x61, ["\xFF"])+ (E.runLists_ [[""], ["a\xFF"]] $ do+ x <- ET.encode ET.ascii =$ EB.head+ y <- EL.consume+ return (x, y))+ $expect $ equal+ (Just 'a', ["b"])+ (E.runLists_ [[""], ["a"], ["b"]] $ do+ x <- ET.decode ET.ascii =$ ET.head+ y <- EL.consume+ return (x, y))+ $expect $ equal+ (Just 'a', ["\xFF"])+ (E.runLists_ [[""], ["a\xFF"]] $ do+ x <- ET.decode ET.ascii =$ ET.head+ y <- EL.consume+ return (x, y))+ ]++encodeASCII :: T.Text -> B.ByteString+encodeASCII text = if T.any (\c -> ord c > 127) text+ then error "encodeASCII: input contains non-ASCII characters."+ else B8.pack (T.unpack text)++decodeASCII :: B.ByteString -> T.Text+decodeASCII bytes = if B.any (> 127) bytes+ then error "decodeASCII: input contains non-ASCII characters."+ else T.pack (B8.unpack bytes)++test_ISO8859_1 :: Suite+test_ISO8859_1 = suite "iso8859-1"+ [ property "encode" (forAll genISO8859_1 (prop_Encode ET.iso8859_1 encodeISO8859_1))+ , property "decode" (forAll genISO8859_1 (prop_Decode ET.iso8859_1 decodeISO8859_1))+ + , assertions "show" $ do+ $expect $ equal+ "Codec \"ISO-8859-1\""+ (show ET.iso8859_1)+ + , assertions "encode-invalid" $ do+ $expect $ equalExc+ (ErrorCall "Codec \"ISO-8859-1\" can't encode character U+01FF")+ (E.runLists [["\x1FF"]] (ET.encode ET.iso8859_1 =$ EB.consume))+ + , assertions "lazy" $ do+ $expect $ equal+ (Just 0x61, ["b"])+ (E.runLists_ [[""], ["a"], ["b"]] $ do+ x <- ET.encode ET.iso8859_1 =$ EB.head+ y <- EL.consume+ return (x, y))+ $expect $ equal+ (Just 0x61, ["\x1FF"])+ (E.runLists_ [[""], ["a\x1FF"]] $ do+ x <- ET.encode ET.iso8859_1 =$ EB.head+ y <- EL.consume+ return (x, y))+ $expect $ equal+ (Just 'a', ["b"])+ (E.runLists_ [[""], ["a"], ["b"]] $ do+ x <- ET.decode ET.iso8859_1 =$ ET.head+ y <- EL.consume+ return (x, y))+ ]++encodeISO8859_1 :: T.Text -> B.ByteString+encodeISO8859_1 text = if T.any (\c -> ord c > 255) text+ then error "encodeASCII: input contains non-ISO8859-1 characters."+ else B8.pack (T.unpack text)++decodeISO8859_1 :: B.ByteString -> T.Text+decodeISO8859_1 bytes = T.pack (B8.unpack bytes)++test_UTF8 :: Suite+test_UTF8 = suite "utf8"+ [ property "encode" (prop_Encode ET.utf8 TE.encodeUtf8)+ , property "decode" (prop_Decode ET.utf8 TE.decodeUtf8 . TE.encodeUtf8)+ + , assertions "show" $ do+ $expect $ equal+ "Codec \"UTF-8\""+ (show ET.utf8)+ + , assertions "decode-invalid" $ do+ $expect $ equalExc+ (TE.DecodeError "Data.Text.Encoding.decodeUtf8: Invalid UTF-8 stream" (Just 0xFF))+ (E.runLists [["\xFF"]] (ET.decode ET.utf8 =$ ET.consume))+ $expect $ equalExc+ (ErrorCall "Unexpected EOF while decoding")+ (E.runLists [["\xF0"]] (ET.decode ET.utf8 =$ ET.consume))+ + , assertions "lazy" $ do+ $expect $ equal+ (Just 'a', ["\xEF\xBD"])+ (E.runLists_ [["a\xEF\xBD"]] $ do+ x <- ET.decode ET.utf8 =$ ET.head+ y <- EL.consume+ return (x, y))+ ]++test_UTF16_BE :: Suite+test_UTF16_BE = suite "utf16-be"+ [ property "encode" (prop_Encode ET.utf16_be TE.encodeUtf16BE)+ , property "decode" (prop_Decode ET.utf16_be TE.decodeUtf16BE . TE.encodeUtf16BE)+ + , assertions "show" $ do+ $expect $ equal+ "Codec \"UTF-16-BE\""+ (show ET.utf16_be)+ + , assertions "decode-invalid" $ do+ $expect $ equalExc+ (TE.DecodeError "Data.Text.Encoding.Fusion.streamUtf16BE: Invalid UTF-16BE stream" Nothing)+ (E.runLists [["\xDD\x1E"]] (ET.decode ET.utf16_be =$ ET.consume))+ $expect $ equalExc+ (ErrorCall "Unexpected EOF while decoding")+ (E.runLists [["\xD8\x00"]] (ET.decode ET.utf16_be =$ ET.consume))+ + , assertions "lazy" $ do+ $expect $ equal+ (Just 'a', ["\x00"])+ (E.runLists_ [["\x00\x61\x00"]] $ do+ x <- ET.decode ET.utf16_be =$ ET.head+ y <- EL.consume+ return (x, y))+ $expect $ equal+ (Just 'a', ["\xDD\x1E"])+ (E.runLists_ [["\x00\x61\xDD\x1E"]] $ do+ x <- ET.decode ET.utf16_be =$ ET.head+ y <- EL.consume+ return (x, y))+ ]++test_UTF16_LE :: Suite+test_UTF16_LE = suite "utf16-le"+ [ property "encode" (prop_Encode ET.utf16_le TE.encodeUtf16LE)+ , property "decode" (prop_Decode ET.utf16_le TE.decodeUtf16LE . TE.encodeUtf16LE)+ + , assertions "show" $ do+ $expect $ equal+ "Codec \"UTF-16-LE\""+ (show ET.utf16_le)+ + , assertions "decode-invalid" $ do+ $expect $ equalExc+ (TE.DecodeError "Data.Text.Encoding.Fusion.streamUtf16LE: Invalid UTF-16LE stream" Nothing)+ (E.runLists [["\x1E\xDD"]] (ET.decode ET.utf16_le =$ ET.consume))+ $expect $ equalExc+ (ErrorCall "Unexpected EOF while decoding")+ (E.runLists [["\x00\xD8"]] (ET.decode ET.utf16_le =$ ET.consume))+ + , assertions "lazy" $ do+ $expect $ equal+ (Just 'a', ["\x00"])+ (E.runLists_ [["\x61\x00\x00"]] $ do+ x <- ET.decode ET.utf16_le =$ ET.head+ y <- EL.consume+ return (x, y))+ $expect $ equal+ (Just 'a', ["\x1E\xDD"])+ (E.runLists_ [["\x61\x00\x1E\xDD"]] $ do+ x <- ET.decode ET.utf16_le =$ ET.head+ y <- EL.consume+ return (x, y))+ ]++test_UTF32_BE :: Suite+test_UTF32_BE = suite "utf32-be"+ [ property "encode" (prop_Encode ET.utf32_be TE.encodeUtf32BE)+ , property "decode" (prop_Decode ET.utf32_be TE.decodeUtf32BE . TE.encodeUtf32BE)+ + , assertions "show" $ do+ $expect $ equal+ "Codec \"UTF-32-BE\""+ (show ET.utf32_be)+ + , assertions "decode-invalid" $ do+ $expect $ equalExc+ (TE.DecodeError "Data.Text.Encoding.Fusion.streamUtf32BE: Invalid UTF-32BE stream" Nothing)+ (E.runLists [["\xFF\xFF\xFF\xFF"]] (ET.decode ET.utf32_be =$ ET.consume))+ $expect $ equalExc+ (ErrorCall "Unexpected EOF while decoding")+ (E.runLists [["\x00\x00"]] (ET.decode ET.utf32_be =$ ET.consume))+ + , assertions "lazy" $ do+ $expect $ equal+ (Just 'a', ["\x00"])+ (E.runLists_ [["\x00\x00\x00\x61\x00"]] $ do+ x <- ET.decode ET.utf32_be =$ ET.head+ y <- EL.consume+ return (x, y))+ $expect $ equal+ (Just 'a', ["\xFF\xFF\xFF\xFF"])+ (E.runLists_ [["\x00\x00\x00\x61\xFF\xFF\xFF\xFF"]] $ do+ x <- ET.decode ET.utf32_be =$ ET.head+ y <- EL.consume+ return (x, y))+ ]++test_UTF32_LE :: Suite+test_UTF32_LE = suite "utf32-le"+ [ property "encode" (prop_Encode ET.utf32_le TE.encodeUtf32LE)+ , property "decode" (prop_Decode ET.utf32_le TE.decodeUtf32LE . TE.encodeUtf32LE)+ + , assertions "show" $ do+ $expect $ equal+ "Codec \"UTF-32-LE\""+ (show ET.utf32_le)+ + , assertions "decode-invalid" $ do+ $expect $ equalExc+ (TE.DecodeError "Data.Text.Encoding.Fusion.streamUtf32LE: Invalid UTF-32LE stream" Nothing)+ (E.runLists [["\xFF\xFF\xFF\xFF"]] (ET.decode ET.utf32_le =$ ET.consume))+ $expect $ equalExc+ (ErrorCall "Unexpected EOF while decoding")+ (E.runLists [["\x00\x00"]] (ET.decode ET.utf32_le =$ ET.consume))+ + , assertions "lazy" $ do+ $expect $ equal+ (Just 'a', ["\x00"])+ (E.runLists_ [["\x61\x00\x00\x00\x00"]] $ do+ x <- ET.decode ET.utf32_le =$ ET.head+ y <- EL.consume+ return (x, y))+ $expect $ equal+ (Just 'a', ["\xFF\xFF\xFF\xFF"])+ (E.runLists_ [["\x61\x00\x00\x00\xFF\xFF\xFF\xFF"]] $ do+ x <- ET.decode ET.utf32_le =$ ET.head+ y <- EL.consume+ return (x, y))+ ]++prop_Encode :: ET.Codec -> (T.Text -> B.ByteString) -> T.Text -> Bool+prop_Encode codec model text = encoded == model text where+ lazy = E.runLists_ [[text]] (ET.encode codec =$ EB.consume)+ encoded = B.concat (BL.toChunks lazy)++prop_Decode :: ET.Codec -> (B.ByteString -> T.Text) -> B.ByteString -> Bool+prop_Decode codec model bytes = decoded == model bytes where+ lazy = E.runLists_ [[bytes]] (ET.decode codec =$ ET.consume)+ decoded = TL.toStrict lazy
+ tests/EnumeratorTests/Text/Consume.hs view
@@ -0,0 +1,103 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Text.Consume+ ( test_Consume+ , test_Head+ , test_Head_+ , test_Take+ , test_TakeWhile+ ) where++import Control.Exception+import Test.Chell++import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL+import qualified Data.Enumerator.Text as ET++import EnumeratorTests.Util (equalExc)++test_Consume :: Suite+test_Consume = assertions "consume" $ do+ $expect $ equal+ ("ABC", Nothing)+ (E.runLists_ [[], ["A", "B"], ["C"]] $ do+ xs <- ET.consume+ h <- EL.head+ return (xs, h))++test_Head :: Suite+test_Head = assertions "head" $ do+ $expect $ equal+ (Just 'A', ["BC", "DE"])+ (E.runLists_ [[], ["ABC", "DE"]] $ do+ x <- ET.head+ extra <- EL.consume+ return (x, extra))+ $expect $ equal+ (Nothing :: Maybe Char, [])+ (E.runLists_ [] $ do+ x <- ET.head+ extra <- EL.consume+ return (x, extra))++test_Head_ :: Suite+test_Head_ = assertions "head_" $ do+ $expect $ equal+ ('A', ["BC", "DE"])+ (E.runLists_ [["ABC"], ["DE"]] $ do+ x <- ET.head_+ extra <- EL.consume+ return (x, extra))+ $expect $ equalExc+ (ErrorCall "head_: stream has ended")+ (E.runLists [] $ do+ x <- ET.head_+ extra <- EL.consume+ return (x, extra))++test_Take :: Suite+test_Take = assertions "take" $ do+ $expect $ equal+ ("ABC", ["D", "E"])+ (E.runLists_ [["A", "B"], ["C", "D"], ["E"]] $ do+ x <- ET.take 3+ extra <- EL.consume+ return (x, extra))+ $expect $ equal+ ("AB", [])+ (E.runLists_ [["A"], ["B"]] $ do+ x <- ET.take 3+ extra <- EL.consume+ return (x, extra))+ $expect $ equal+ ("", ["A", "B"])+ (E.runLists_ [["A"], ["B"]] $ do+ x <- ET.take 0+ extra <- EL.consume+ return (x, extra))++test_TakeWhile :: Suite+test_TakeWhile = assertions "takeWhile" $ do+ $expect $ equal+ ("ABC", ["D", "E"])+ (E.runLists_ [[], ["A", "B"], ["C", "D"], ["E"]] $ do+ x <- ET.takeWhile (< 'D')+ extra <- EL.consume+ return (x, extra))+ $expect $ equal+ ("AB", [])+ (E.runLists_ [["A"], ["B"]] $ do+ x <- ET.takeWhile (< 'D')+ extra <- EL.consume+ return (x, extra))+ $expect $ equal+ ("", ["A", "B"])+ (E.runLists_ [["A"], ["B"]] $ do+ x <- ET.takeWhile (< 'A')+ extra <- EL.consume+ return (x, extra))
+ tests/EnumeratorTests/Text/Drop.hs view
@@ -0,0 +1,64 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Text.Drop+ ( test_Drop+ , test_DropWhile+ , test_Filter+ , test_FilterM+ ) where++import Test.Chell++import Data.Enumerator ((=$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL+import qualified Data.Enumerator.Text as ET++test_Drop :: Suite+test_Drop = assertions "drop" $ do+ $expect $ equal+ ["ABCDE"]+ (E.runLists_ [["ABCDE"]] $ do+ ET.drop 0+ EL.consume)+ $expect $ equal+ ["CDE"]+ (E.runLists_ [["ABCDE"]] $ do+ ET.drop 2+ EL.consume)+ $expect $ equal+ ["CDE"]+ (E.runLists_ [["A"], ["BCDE"]] $ do+ ET.drop 2+ EL.consume)++test_DropWhile :: Suite+test_DropWhile = assertions "dropWhile" $ do+ $expect $ equal+ ["CDE"]+ (E.runLists_ [["ABCDE"]] $ do+ ET.dropWhile (< 'C')+ EL.consume)+ $expect $ equal+ []+ (E.runLists_ [["ABCDE"]] $ do+ ET.dropWhile (\_ -> True)+ EL.consume)++test_Filter :: Suite+test_Filter = assertions "filter" $ do+ $expect $ equal+ ["A", "B", "", "D", "E"]+ (E.runLists_ [["ABCDE"]] $ do+ ET.filter (/= 'C') =$ EL.consume)++test_FilterM :: Suite+test_FilterM = assertions "filterM" $ do+ $expect $ equal+ ["A", "B", "", "D", "E"]+ (E.runLists_ [["ABCDE"]] $ do+ ET.filterM (\x -> return (x /= 'C')) =$ EL.consume)
+ tests/EnumeratorTests/Text/Fold.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2011 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Text.Fold+ ( test_Fold+ , test_FoldM+ ) where++import Control.Monad (foldM)+import Data.Functor.Identity (runIdentity)+import qualified Data.Text+import Data.Text (Text)+import Test.Chell+import Test.Chell.QuickCheck+import Test.QuickCheck.Poly+import Test.QuickCheck.Modifiers++import qualified Data.Enumerator as E+import qualified Data.Enumerator.Text as ET++import EnumeratorTests.Util ()++test_Fold :: Suite+test_Fold = property "fold" prop_Fold++prop_Fold :: Blind (B -> Char -> B) -> B -> Text -> Bool+prop_Fold (Blind f) z text = result == expected where+ result = E.runLists_ [[text]] (ET.fold f z)+ expected = Data.Text.foldl' f z text++test_FoldM :: Suite+test_FoldM = property "foldM" prop_FoldM++prop_FoldM :: Blind (B -> Char -> B) -> B -> Text -> Bool+prop_FoldM (Blind f) z text = result == expected where+ result = E.runLists_ [[text]] (ET.foldM f' z)+ expected = runIdentity (foldM f' z (Data.Text.unpack text))+ f' b a = return (f b a)
+ tests/EnumeratorTests/Text/Handle.hs view
@@ -0,0 +1,50 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2011 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Text.Handle+ ( test_EnumHandle+ , test_IterHandle+ ) where++import Test.Chell++#ifdef MIN_VERSION_knob++import Data.Knob+import qualified System.IO as IO++import qualified Data.Enumerator as E+import Data.Enumerator (($$))+import qualified Data.Enumerator.List as EL+import qualified Data.Enumerator.Text as ET++test_EnumHandle :: Suite+test_EnumHandle = assertions "enumHandle" $ do+ knob <- newKnob "0123\n\n4567"+ chunks <- withFileHandle knob "" IO.ReadMode $ \h -> do+ E.run_ (ET.enumHandle h $$ EL.consume)+ $expect (equal chunks ["0123", "", "4567"])++test_IterHandle :: Suite+test_IterHandle = assertions "iterHandle" $ do+ knob <- newKnob ""+ withFileHandle knob "" IO.WriteMode $ \h -> do+ E.run_ (E.enumLists [[], ["A", "B"], ["C"]] $$ ET.iterHandle h)+ bytes <- Data.Knob.getContents knob+ $expect (equal bytes "ABC")++#else++import EnumeratorTests.Util (todo)++test_EnumHandle :: Suite+test_EnumHandle = todo "enumHandle"++test_IterHandle :: Suite+test_IterHandle = todo "iterHandle"++#endif
+ tests/EnumeratorTests/Text/Isolate.hs view
@@ -0,0 +1,73 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Text.Isolate+ ( test_Isolate+ ) where++import qualified Data.Text.Lazy as TL++import Test.Chell+import Test.Chell.QuickCheck++import Data.Enumerator (($$), (=$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL+import qualified Data.Enumerator.Text as ET++import EnumeratorTests.Text.Util (prop_Text)++test_Isolate :: Suite+test_Isolate = suite "isolate"+ [ prop_Isolate+ , test_DropExtra+ , test_HandleEOF+ , test_BadParameter+ ]++prop_Isolate :: Suite+prop_Isolate = property "model" $ prop_Text+ (do+ x <- E.joinI (ET.isolate 2 $$ ET.head)+ extra <- ET.consume+ return (x, extra))+ (\text -> Right $ case TL.unpack text of+ [] -> (Nothing, TL.empty)+ (x:[]) -> (Just x, TL.empty)+ (x:_:xs') -> (Just x, TL.pack xs'))++test_DropExtra :: Suite+test_DropExtra = assertions "drop-extra" $ do+ $expect $ equal+ (Just 'A', ["C"])+ (E.runLists_ [[], ["A"], ["B"], ["C"]] $ do+ x <- ET.isolate 2 =$ ET.head+ extra <- EL.consume+ return (x, extra))+ $expect $ equal+ (Just 'A', ["C"])+ (E.runLists_ [["A", "B", "C"]] $ do+ x <- ET.isolate 2 =$ ET.head+ extra <- EL.consume+ return (x, extra))++test_HandleEOF :: Suite+test_HandleEOF = assertions "handle-eof" $ do+ $expect $ equal+ (Nothing :: Maybe Char, [])+ (E.runLists_ [] $ do+ x <- ET.isolate 2 =$ ET.head+ extra <- EL.consume+ return (x, extra))++test_BadParameter :: Suite+test_BadParameter = assertions "bad-parameter" $ do+ $expect $ equal+ (Nothing, ["A", "B", "C"])+ (E.runLists_ [["A"], ["B"], ["C"]] $ do+ x <- ET.isolate 0 =$ ET.head+ extra <- EL.consume+ return (x, extra))
+ tests/EnumeratorTests/Text/Iterate.hs view
@@ -0,0 +1,31 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2011 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Text.Iterate+ ( test_Iterate+ , test_IterateM+ ) where++import Data.Functor.Identity (runIdentity)+import Test.Chell++import Data.Enumerator (($$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL+import qualified Data.Enumerator.Text as ET++test_Iterate :: Suite+test_Iterate = assertions "iterate" $ do+ $expect $ equal+ ["A", "B", "C"]+ (runIdentity (E.run_ (ET.iterate succ 'A' $$ EL.take 3)))++test_IterateM :: Suite+test_IterateM = assertions "iterateM" $ do+ let succM = return . succ+ $expect $ equal+ ["A", "B", "C"]+ (runIdentity (E.run_ (ET.iterateM succM 'A' $$ EL.take 3)))
+ tests/EnumeratorTests/Text/Map.hs view
@@ -0,0 +1,138 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Text.Map+ ( test_Map+ , test_MapM+ , test_MapM_+ , test_ConcatMap+ , test_ConcatMapM+ , test_ConcatMapAccum+ , test_ConcatMapAccumM+ , test_MapAccum+ , test_MapAccumM+ ) where++import Control.Monad.Trans.Writer (execWriter, tell)+import Data.Char (chr, ord, toLower)+import qualified Data.Text as T++import Test.Chell++import Data.Enumerator (($$), (=$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL+import qualified Data.Enumerator.Text as ET++test_Map :: Suite+test_Map = assertions "map" $ do+ $expect $ equal+ ["a", "b"]+ (E.runLists_ [["AB"]] (ET.map toLower =$ EL.consume))+ $expect $ equal+ (["a", "b"], ["CDEF", "GH"])+ (E.runLists_ [["ABCD", "EF"], ["GH"]] $ do+ xs <- ET.map toLower =$ EL.take 2+ extra <- EL.consume+ return (xs, extra))++test_MapM :: Suite+test_MapM = assertions "mapM" $ do+ $expect $ equal+ ["a", "b"]+ (E.runLists_ [["AB"]] (ET.mapM (return . toLower) =$ EL.consume))+ $expect $ equal+ (["a", "b"], ["CDEF", "GH"])+ (E.runLists_ [["ABCD", "EF"], ["GH"]] $ do+ xs <- ET.mapM (return . toLower) =$ EL.take 2+ extra <- EL.consume+ return (xs, extra))++test_MapM_ :: Suite+test_MapM_ = assertions "mapM_" $ do+ $expect $ equal+ ['A', 'B']+ (execWriter (E.run_ (E.enumLists [["AB"]] $$ ET.mapM_ (\x -> tell [x]))))++test_ConcatMap :: Suite+test_ConcatMap = assertions "concatMap" $ do+ $expect $ equal+ ["Aa", "Bb"]+ (E.runLists_ [["AB"]] (ET.concatMap (\x -> T.pack [x, toLower x]) =$ EL.consume))+ $expect $ equal+ (["Aa", "Bb"], ["CDEF", "GH"])+ (E.runLists_ [["ABCD", "EF"], ["GH"]] $ do+ xs <- ET.concatMap (\x -> T.pack [x, toLower x]) =$ EL.take 2+ extra <- EL.consume+ return (xs, extra))++test_ConcatMapM :: Suite+test_ConcatMapM = assertions "concatMapM" $ do+ $expect $ equal+ ["Aa", "Bb"]+ (E.runLists_ [["AB"]] (ET.concatMapM (\x -> return (T.pack [x, toLower x])) =$ EL.consume))+ $expect $ equal+ (["Aa", "Bb"], ["CDEF", "GH"])+ (E.runLists_ [["ABCD", "EF"], ["GH"]] $ do+ xs <- ET.concatMapM (\x -> return (T.pack [x, toLower x])) =$ EL.take 2+ extra <- EL.consume+ return (xs, extra))++test_MapAccum :: Suite+test_MapAccum = assertions "mapAccum" $ do+ let step s ao = (s + 1, chr (ord ao + s))+ $expect $ equal+ ["B", "D", "F"]+ (E.runLists_ [["A", "B"], ["C"]] $ do+ ET.mapAccum step 1 =$ EL.consume)+ $expect $ equal+ ("B", ["", "B", "C"])+ (E.runLists_ [["A", "B"], ["C"]] $ do+ xs <- ET.mapAccum step 1 =$ ET.take 1+ extra <- EL.consume+ return (xs, extra))++test_MapAccumM :: Suite+test_MapAccumM = assertions "mapAccumM" $ do+ let step s ao = return (s + 1, chr (ord ao + s))+ $expect $ equal+ ["B", "D", "F"]+ (E.runLists_ [["A", "B"], ["C"]] $ do+ ET.mapAccumM step 1 =$ EL.consume)+ $expect $ equal+ ("B", ["", "B", "C"])+ (E.runLists_ [["A", "B"], ["C"]] $ do+ xs <- ET.mapAccumM step 1 =$ ET.take 1+ extra <- EL.consume+ return (xs, extra))++test_ConcatMapAccum :: Suite+test_ConcatMapAccum = assertions "concatMapAccum" $ do+ let step s ao = (s + 1, T.replicate s (T.pack [ao]))+ $expect $ equal+ ["A", "BB", "CCC"]+ (E.runLists_ [["A", "B"], ["C"]] $ do+ ET.concatMapAccum step 1 =$ EL.consume)+ $expect $ equal+ ("AB", ["", "C"])+ (E.runLists_ [["A", "B"], ["C"]] $ do+ xs <- ET.concatMapAccum step 1 =$ ET.take 2+ extra <- EL.consume+ return (xs, extra))++test_ConcatMapAccumM :: Suite+test_ConcatMapAccumM = assertions "concatMapAccumM" $ do+ let step s ao = return (s + 1, T.replicate s (T.pack [ao]))+ $expect $ equal+ ["A", "BB", "CCC"]+ (E.runLists_ [["A", "B"], ["C"]] $ do+ ET.concatMapAccumM step 1 =$ EL.consume)+ $expect $ equal+ ("AB", ["", "C"])+ (E.runLists_ [["A", "B"], ["C"]] $ do+ xs <- ET.concatMapAccumM step 1 =$ ET.take 2+ extra <- EL.consume+ return (xs, extra))
+ tests/EnumeratorTests/Text/Repeat.hs view
@@ -0,0 +1,49 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2011 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Text.Repeat+ ( test_Repeat+ , test_RepeatM+ , test_GenerateM+ ) where++import Control.Monad.Trans.State+import Data.Functor.Identity (runIdentity)+import Test.Chell++import Data.Enumerator (($$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL+import qualified Data.Enumerator.Text as ET++test_Repeat :: Suite+test_Repeat = assertions "repeat" $ do+ $expect $ equal+ ["A", "A", "A"]+ (runIdentity (E.run_ (ET.repeat 'A' $$ EL.take 3)))++test_RepeatM :: Suite+test_RepeatM = assertions "repeatM" $ do+ let step = do+ c <- get+ put (succ c)+ return c+ $expect $ equal+ ["A", "B", "C"]+ (evalState (E.run_ (ET.repeatM step $$ EL.take 3)) 'A')++test_GenerateM :: Suite+test_GenerateM = assertions "generateM" $ do+ let step = do+ c <- get+ if c > 'C'+ then return Nothing+ else do+ put (succ c)+ return (Just c)+ $expect $ equal+ ["A", "B", "C"]+ (evalState (E.run_ (ET.generateM step $$ EL.consume)) 'A')
+ tests/EnumeratorTests/Text/Replicate.hs view
@@ -0,0 +1,38 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2011 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Text.Replicate+ ( test_Replicate+ , test_ReplicateM+ ) where++import Control.Monad.Trans.State+import Data.Functor.Identity (runIdentity)+import Test.Chell++import Data.Enumerator (($$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL+import qualified Data.Enumerator.Text as ET++test_Replicate :: Suite+test_Replicate = assertions "replicate" $ do+ $expect $ equal+ ["A", "A", "A"]+ (runIdentity (E.run_ (ET.replicate 3 'A' $$ EL.consume)))++test_ReplicateM :: Suite+test_ReplicateM = assertions "replicateM" $ do+ let step = do+ c <- get+ put (succ c)+ return c+ $expect $ equal+ ["A", "B", "C"]+ (evalState (E.run_ (ET.replicateM 3 step $$ EL.consume)) 'A')+ $expect $ equal+ ["A", "B"]+ (evalState (E.run_ (ET.replicateM 3 step $$ EL.take 2)) 'A')
+ tests/EnumeratorTests/Text/Require.hs view
@@ -0,0 +1,67 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Text.Require+ ( test_Require+ ) where++import qualified Control.Exception as Exc+import qualified Data.Text.Lazy as TL+import Test.Chell+import Test.Chell.QuickCheck++import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL+import qualified Data.Enumerator.Text as ET++import EnumeratorTests.Text.Util+import EnumeratorTests.Util (equalExc)++test_Require :: Suite+test_Require = suite "require"+ [ prop_Require+ , test_YieldsInput+ , test_HandleEOF+ , test_BadParameter+ ]++prop_Require :: Suite+prop_Require = property "model" $ prop_TextN+ (\n -> do+ ET.require n+ ET.consume)+ (\n xs -> if n > toInteger (TL.length xs)+ then Left (Exc.ErrorCall "require: Unexpected EOF")+ else Right xs)++test_YieldsInput :: Suite+test_YieldsInput = assertions "yields-input" $ do+ $expect $ equal+ ["A", "B", "C"]+ (E.runLists_ [["A"], ["B"], ["C"]] $ do+ ET.require 2+ EL.consume)+ $expect $ equal+ ["A", "B", "C"]+ (E.runLists_ [["A", "B", "C"]] $ do+ ET.require 2+ EL.consume)++test_HandleEOF :: Suite+test_HandleEOF = assertions "handle-eof" $ do+ $expect $ equalExc+ (Exc.ErrorCall "require: Unexpected EOF")+ (E.runLists [] $ do+ ET.require 2+ EL.consume)++test_BadParameter :: Suite+test_BadParameter = assertions "bad-parameter" $ do+ $expect $ equal+ []+ (E.runLists_ [] $ do+ ET.require 0+ EL.consume)
+ tests/EnumeratorTests/Text/Split.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Text.Split+ ( test_SplitWhen+ , test_Lines+ ) where++import qualified Data.List.Split as LS+import qualified Data.Text as T+import qualified Data.Text.Lazy as TL+import Test.Chell+import Test.Chell.QuickCheck++import Data.Enumerator ((=$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL+import qualified Data.Enumerator.Text as ET++import EnumeratorTests.Text.Util++test_SplitWhen :: Suite+test_SplitWhen = suite "splitWhen"+ [ prop_SplitWhen+ , test_HandleEmpty+ ]++prop_SplitWhen :: Suite+prop_SplitWhen = property "model" $ prop_TextX+ (\c -> do+ xs <- ET.splitWhen (== c) =$ EL.consume+ extra <- EL.consume+ return (xs, extra))+ (\c text -> let+ split = LS.split . LS.dropFinalBlank . LS.dropDelims . LS.whenElt+ chars = TL.unpack text+ in Right (map T.pack (split (== c) chars), []))++test_HandleEmpty :: Suite+test_HandleEmpty = assertions "empty" $ do+ $expect $ equal+ ([], Nothing)+ (E.runLists_ [[""]] $ do+ xs <- ET.splitWhen (== ',') =$ EL.consume+ extra <- EL.head+ return (xs, extra))++test_Lines :: Suite+test_Lines = assertions "lines" $ do+ $expect $ equal+ ["abc", "def"]+ (E.runLists_ [["abc\ndef"]] (ET.lines =$ EL.consume))+ $expect $ equal+ ["abc", "def"]+ (E.runLists_ [["abc\ndef\n"]] (ET.lines =$ EL.consume))+ $expect $ equal+ ["abc", "def", ""]+ (E.runLists_ [["abc\ndef\n\n"]] (ET.lines =$ EL.consume))
+ tests/EnumeratorTests/Text/Unfold.hs view
@@ -0,0 +1,36 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2011 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Text.Unfold+ ( test_Unfold+ , test_UnfoldM+ ) where++import Data.Functor.Identity (runIdentity)+import Test.Chell++import Data.Enumerator (($$))+import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL+import qualified Data.Enumerator.Text as ET++test_Unfold :: Suite+test_Unfold = assertions "unfold" $ do+ let step x = if x > 'C'+ then Nothing+ else Just (x, succ x)+ $expect $ equal+ ["A", "B", "C"]+ (runIdentity (E.run_ (ET.unfold step 'A' $$ EL.consume)))++test_UnfoldM :: Suite+test_UnfoldM = assertions "unfoldM" $ do+ let step x = return $ if x > 'C'+ then Nothing+ else Just (x, succ x)+ $expect $ equal+ ["A", "B", "C"]+ (runIdentity (E.run_ (ET.unfoldM step 'A' $$ EL.consume)))
+ tests/EnumeratorTests/Text/Util.hs view
@@ -0,0 +1,44 @@+{-# LANGUAGE OverloadedStrings #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Text.Util+ ( prop_Text+ , prop_TextN+ , prop_TextX+ ) where++import Control.Exception (ErrorCall)+import Data.Text (Text)+import qualified Data.Text.Lazy as TL+import Data.Functor.Identity (Identity)++import Test.QuickCheck hiding (property)++import Data.Enumerator (Iteratee)++import EnumeratorTests.Util (check)++prop_Text :: Eq b+ => Iteratee Text Identity b+ -> (TL.Text -> Either ErrorCall b)+ -> [Text]+ -> Bool+prop_Text iter plain = check iter (plain . TL.fromChunks)++prop_TextN :: Eq b+ => (Integer -> Iteratee Text Identity b)+ -> (Integer -> TL.Text -> Either ErrorCall b)+ -> Positive Integer+ -> [Text]+ -> Bool+prop_TextN iter plain (Positive n) = check (iter n) (plain n . TL.fromChunks)++prop_TextX :: Eq b+ => (Char -> Iteratee Text Identity b)+ -> (Char -> TL.Text -> Either ErrorCall b)+ -> Char+ -> [Text]+ -> Bool+prop_TextX iter plain x = check (iter x) (plain x . TL.fromChunks)
+ tests/EnumeratorTests/Text/Zip.hs view
@@ -0,0 +1,164 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Text.Zip+ ( test_Zip+ ) where++import qualified Control.Exception as Exc+import Data.Functor.Identity (Identity)+import Data.Text (Text)+import Test.Chell++import qualified Data.Enumerator as E+import qualified Data.Enumerator.List as EL+import qualified Data.Enumerator.Text as ET++import EnumeratorTests.Util (equalExc)++test_ZipN :: (Eq b, Show b) => Text -> E.Iteratee Text Identity b -> b -> Suite+test_ZipN name iter expected = assertions name $ do+ $expect $ equal+ expected+ (E.runLists_ [[], ["A"], ["B"]] iter)++$([d||])++test_Zip :: Suite+test_Zip = suite "zip"+ [ test_ContinueContinue+ , test_YieldContinue+ , test_ContinueYield+ , test_YieldYield+ , test_ErrorFirst+ , test_ErrorSecond+ , test_HandleEOF+ , test_Zip3+ , test_Zip4+ , test_Zip5+ , test_Zip6+ , test_Zip7+ , test_ZipWith+ , test_ZipWith3+ , test_ZipWith4+ , test_ZipWith5+ , test_ZipWith6+ , test_ZipWith7+ ]++test_ContinueContinue :: Suite+test_ContinueContinue = assertions "continue-continue" $ do+ $expect $ equal+ ("AB", "AB", ["C"])+ (E.runLists_ [["A"], ["B"], ["C"]] $ do+ (x, y) <- ET.zip (ET.take 2) (ET.take 2)+ extra <- EL.consume+ return (x, y, extra))++test_YieldContinue :: Suite+test_YieldContinue = assertions "yield-continue" $ do+ $expect $ equal+ ("A", "AB", ["C"])+ (E.runLists_ [["A"], ["B"], ["C"]] $ do+ (x, y) <- ET.zip (ET.take 1) (ET.take 2)+ extra <- EL.consume+ return (x, y, extra))++test_ContinueYield :: Suite+test_ContinueYield = assertions "continue-yield" $ do+ $expect $ equal+ ("AB", "A", ["C"])+ (E.runLists_ [["A"], ["B"], ["C"]] $ do+ (x, y) <- ET.zip (ET.take 2) (ET.take 1)+ extra <- EL.consume+ return (x, y, extra))++test_YieldYield :: Suite+test_YieldYield = assertions "yield-yield" $ do+ $expect $ equal+ ("A", "A", ["B", "C"])+ (E.runLists_ [["A"], ["B"], ["C"]] $ do+ (x, y) <- ET.zip (ET.take 1) (ET.take 1)+ extra <- EL.consume+ return (x, y, extra))++test_ErrorFirst :: Suite+test_ErrorFirst = assertions "error-first" $ do+ $expect $ equalExc+ (Exc.ErrorCall "error")+ (E.runLists [["A"], ["B"], ["C"]] $ do+ ET.zip (E.throwError (Exc.ErrorCall "error")) (ET.take 1))++test_ErrorSecond :: Suite+test_ErrorSecond = assertions "error-second" $ do+ $expect $ equalExc+ (Exc.ErrorCall "error")+ (E.runLists [["A"], ["B"], ["C"]] $ do+ ET.zip (ET.take 1) (E.throwError (Exc.ErrorCall "error")))++test_HandleEOF :: Suite+test_HandleEOF = assertions "handle-eof" $ do+ $expect $ equal+ ("A", "AB", [])+ (E.runLists_ [["A"], ["B"]] $ do+ (x, y) <- ET.zip (ET.take 1) (ET.take 3)+ extra <- EL.consume+ return (x, y, extra))++test_Zip3 :: Suite+test_Zip3 = test_ZipN "zip3"+ (ET.zip3 ET.head ET.head ET.head)+ (Just 'A', Just 'A', Just 'A')++test_Zip4 :: Suite+test_Zip4 = test_ZipN "zip4"+ (ET.zip4 ET.head ET.head ET.head ET.head)+ (Just 'A', Just 'A', Just 'A', Just 'A')++test_Zip5 :: Suite+test_Zip5 = test_ZipN "zip5"+ (ET.zip5 ET.head ET.head ET.head ET.head ET.head)+ (Just 'A', Just 'A', Just 'A', Just 'A', Just 'A')++test_Zip6 :: Suite+test_Zip6 = test_ZipN "zip6"+ (ET.zip6 ET.head ET.head ET.head ET.head ET.head ET.head)+ (Just 'A', Just 'A', Just 'A', Just 'A', Just 'A', Just 'A')++test_Zip7 :: Suite+test_Zip7 = test_ZipN "zip7"+ (ET.zip7 ET.head ET.head ET.head ET.head ET.head ET.head ET.head)+ (Just 'A', Just 'A', Just 'A', Just 'A', Just 'A', Just 'A', Just 'A')++test_ZipWith :: Suite+test_ZipWith = test_ZipN "zipWith"+ (ET.zipWith (,) ET.head ET.head)+ (Just 'A', Just 'A')++test_ZipWith3 :: Suite+test_ZipWith3 = test_ZipN "zipWith3"+ (ET.zipWith3 (,,) ET.head ET.head ET.head)+ (Just 'A', Just 'A', Just 'A')++test_ZipWith4 :: Suite+test_ZipWith4 = test_ZipN "zipWith4"+ (ET.zipWith4 (,,,) ET.head ET.head ET.head ET.head)+ (Just 'A', Just 'A', Just 'A', Just 'A')++test_ZipWith5 :: Suite+test_ZipWith5 = test_ZipN "zipWith5"+ (ET.zipWith5 (,,,,) ET.head ET.head ET.head ET.head ET.head)+ (Just 'A', Just 'A', Just 'A', Just 'A', Just 'A')++test_ZipWith6 :: Suite+test_ZipWith6 = test_ZipN "zipWith6"+ (ET.zipWith6 (,,,,,) ET.head ET.head ET.head ET.head ET.head ET.head)+ (Just 'A', Just 'A', Just 'A', Just 'A', Just 'A', Just 'A')++test_ZipWith7 :: Suite+test_ZipWith7 = test_ZipN "zipWith7"+ (ET.zipWith7 (,,,,,,) ET.head ET.head ET.head ET.head ET.head ET.head ET.head)+ (Just 'A', Just 'A', Just 'A', Just 'A', Just 'A', Just 'A', Just 'A')
+ tests/EnumeratorTests/Util.hs view
@@ -0,0 +1,142 @@+{-# LANGUAGE OverloadedStrings #-}++-- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>+--+-- See license.txt for details+module EnumeratorTests.Util+ ( check+ , equalExc+ , todo+ , within+ , genASCII+ , genISO8859_1+ , genUnicode+ ) where++import qualified Control.Exception as Exc+import Data.Bits ((.&.))+import qualified Data.ByteString as B+import Data.Char (chr)+import Data.Functor.Identity (Identity, runIdentity)+import Data.String (IsString, fromString)+import qualified Data.Text as T+import System.Timeout (timeout)++import Test.Chell+import Test.QuickCheck hiding ((.&.), within)++import Data.Enumerator (($$))+import qualified Data.Enumerator as E++check :: Eq b => E.Iteratee a Identity b -> ([a] -> Either Exc.ErrorCall b) -> [a] -> Bool+check iter plain xs = expected == run where+ expected = case plain xs of+ Left exc -> Left (Just exc)+ Right x -> Right x+ + run = case runIdentity (E.run (E.enumList 1 xs $$ iter)) of+ Left exc -> Left (Exc.fromException exc)+ Right x -> Right x++todo :: T.Text -> Suite+todo name = skipIf True (assertions name (return ()))++genASCII :: IsString a => Gen a+genASCII = fmap fromString string where+ string = sized $ \n -> do+ k <- choose (0,n)+ sequence [ char | _ <- [1..k] ]+ + char = chr `fmap` choose (0,0x7F)++genISO8859_1 :: IsString a => Gen a+genISO8859_1 = fmap fromString string where+ string = sized $ \n -> do+ k <- choose (0,n)+ sequence [ char | _ <- [1..k] ]+ + char = chr `fmap` choose (0,0xFF)++genUnicode :: IsString a => Gen a+genUnicode = fmap fromString string where+ string = sized $ \n -> do+ k <- choose (0,n)+ sequence [ char | _ <- [1..k] ]+ + excluding :: [a -> Bool] -> Gen a -> Gen a+ excluding bad gen = loop where+ loop = do+ x <- gen+ if or (map ($ x) bad)+ then loop+ else return x+ + reserved = [lowSurrogate, highSurrogate, noncharacter]+ lowSurrogate c = c >= 0xDC00 && c <= 0xDFFF+ highSurrogate c = c >= 0xD800 && c <= 0xDBFF+ noncharacter c = masked == 0xFFFE || masked == 0xFFFF where+ masked = c .&. 0xFFFF+ + ascii = choose (0,0x7F)+ plane0 = choose (0xF0, 0xFFFF)+ plane1 = oneof [ choose (0x10000, 0x10FFF)+ , choose (0x11000, 0x11FFF)+ , choose (0x12000, 0x12FFF)+ , choose (0x13000, 0x13FFF)+ , choose (0x1D000, 0x1DFFF)+ , choose (0x1F000, 0x1FFFF)+ ]+ plane2 = oneof [ choose (0x20000, 0x20FFF)+ , choose (0x21000, 0x21FFF)+ , choose (0x22000, 0x22FFF)+ , choose (0x23000, 0x23FFF)+ , choose (0x24000, 0x24FFF)+ , choose (0x25000, 0x25FFF)+ , choose (0x26000, 0x26FFF)+ , choose (0x27000, 0x27FFF)+ , choose (0x28000, 0x28FFF)+ , choose (0x29000, 0x29FFF)+ , choose (0x2A000, 0x2AFFF)+ , choose (0x2B000, 0x2BFFF)+ , choose (0x2F000, 0x2FFFF)+ ]+ plane14 = choose (0xE0000, 0xE0FFF)+ planes = [ascii, plane0, plane1, plane2, plane14]+ + char = chr `fmap` excluding reserved (oneof planes)++instance Arbitrary a => Arbitrary (E.Stream a) where+ arbitrary = frequency+ [ (10, return E.EOF)+ , (90, fmap E.Chunks arbitrary)+ ]++instance Arbitrary T.Text where+ arbitrary = genUnicode++instance Arbitrary B.ByteString where+ arbitrary = genUnicode++instance Eq Exc.ErrorCall where+ (Exc.ErrorCall s1) == (Exc.ErrorCall s2) = s1 == s2++-- | Require a test to complete within /n/ milliseconds.+within :: Int -> Suite -> Suite+within time s = suite (suiteName s) (map wrapTest (suiteTests s)) where+ wrapTest (Test name io) = test $ Test name $ \opts -> do+ res <- timeout (time * 1000) (io opts)+ case res of+ Just res' -> return res'+ Nothing -> return (TestAborted [] (T.pack ("Test timed out after " ++ show time ++ " milliseconds")))++equalExc :: (Eq exc, Exc.Exception exc) => exc -> Either Exc.SomeException a -> Assertion+equalExc expected funResult = Assertion (return result) where+ failed :: String -> AssertionResult+ failed str = AssertionFailed (T.pack ("equalExc: " ++ show str))+ result = case funResult of+ Right _ -> failed "received Right"+ Left exc -> case Exc.fromException exc of+ Nothing -> failed ("received unexpected exception: " ++ show exc)+ Just exc' -> if expected == exc'+ then AssertionPassed+ else failed (show expected ++ " /= " ++ show exc')
− tests/Tests.hs
@@ -1,936 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}---- Copyright (C) 2010 John Millikin <jmillikin@gmail.com>------ See license.txt for details-module Main (tests, main) where--import Control.Concurrent-import qualified Control.Exception as Exc-import Control.Monad.IO.Class (liftIO)-import Data.Bits ((.&.))-import qualified Data.ByteString as B-import qualified Data.ByteString.Char8 as B8-import qualified Data.ByteString.Lazy as BL-import Data.Char (chr)-import Data.Functor.Identity (Identity, runIdentity)-import qualified Data.List as L-import qualified Data.List.Split as LS-import Data.Monoid (mappend, mempty, mconcat)-import Data.String (IsString, fromString)-import qualified Data.Text as T-import qualified Data.Text.Encoding as TE-import qualified Data.Text.Lazy as TL-import Data.Word (Word8)-import System.Timeout (timeout)--import Test.Chell-import Test.Chell.QuickCheck-import Test.QuickCheck hiding ((.&.), property, within)-import Test.QuickCheck.Poly (A, B, C)--import Data.Enumerator (($$), (>>==))-import qualified Data.Enumerator as E-import qualified Data.Enumerator.Binary as EB-import qualified Data.Enumerator.Text as ET-import qualified Data.Enumerator.List as EL--tests :: [Suite]-tests =- [ suite_StreamInstances- , suite_Text- , suite_ListAnalogues- , suite_Other- ]--main :: IO ()-main = Test.Chell.defaultMain tests---- Stream instances {{{--suite_StreamInstances :: Suite-suite_StreamInstances = suite "stream-instances"- [ suite_StreamMonoid- , suite_StreamFunctor- , suite_StreamMonad- ]--suite_StreamMonoid :: Suite-suite_StreamMonoid = suite "monoid" props where- props = [ property "law-1" prop_law1- , property "law-2" prop_law2- , property "law-3" prop_law3- , property "law-4" prop_law4- ]- - prop_law1 :: E.Stream A -> Bool- prop_law1 x = mappend mempty x == x- - prop_law2 :: E.Stream A -> Bool- prop_law2 x = mappend x mempty == x- - prop_law3 :: E.Stream A -> E.Stream A -> E.Stream A -> Bool- prop_law3 x y z = mappend x (mappend y z) == mappend (mappend x y) z- - prop_law4 :: [E.Stream A] -> Bool- prop_law4 xs = mconcat xs == foldr mappend mempty xs--suite_StreamFunctor :: Suite-suite_StreamFunctor = suite "functor" props where- props = [ property "law-1" prop_law1- , property "law-2" prop_law2- ]- - prop_law1 :: E.Stream A -> Bool- prop_law1 x = fmap id x == id x- - prop_law2 :: E.Stream A -> Blind (B -> C) -> Blind (A -> B) -> Bool- prop_law2 x (Blind f) (Blind g) = fmap (f . g) x == (fmap f . fmap g) x--suite_StreamMonad :: Suite-suite_StreamMonad = suite "Monad Stream" props where- props = [ property "law-1" prop_law1- , property "law-2" prop_law2- , property "law-3" prop_law3- ]- - prop_law1 :: A -> Blind (A -> E.Stream B) -> Bool- prop_law1 a (Blind f) = (return a >>= f) == f a- - prop_law2 :: E.Stream A -> Bool- prop_law2 m = (m >>= return) == m- - prop_law3 :: E.Stream A -> Blind (A -> E.Stream B) -> Blind (B -> E.Stream C) -> Bool- prop_law3 m (Blind f) (Blind g) = ((m >>= f) >>= g) == (m >>= (\x -> f x >>= g))---- }}}---- Generic properties {{{--test_Enumeratee :: T.Text -> E.Enumeratee A A Identity (Maybe A) -> Suite-test_Enumeratee name enee = suite name props where- props = [ property "incremental" prop_incremental- , property "nest-errors" prop_nest_errors- ]- - prop_incremental (Positive n) (NonEmpty xs) = let- result = runIdentity (E.run_ iter)- expected = (Just (head xs), tail xs)- - iter = E.enumList n xs $$ do- a <- E.joinI (enee $$ EL.head)- b <- EL.consume- return (a, b)- - in result == expected- - prop_nest_errors (Positive n) (NonEmpty xs) = let- result = runIdentity (E.run_ iter)- - iter = E.enumList n xs $$ do- _ <- enee $$ E.throwError (Exc.ErrorCall "")- EL.consume- - in result == xs---- }}}---- Text encoding / decoding {{{--suite_Text :: Suite-suite_Text = suite "text"- [ suite_Encoding- , suite_Decoding- ]--suite_Encoding :: Suite-suite_Encoding = suite "encoding"- [ suite_Encode_ASCII- , suite_Encode_ISO8859- ]--suite_Encode_ASCII :: Suite-suite_Encode_ASCII = suite "ascii" props where- props = [ property "works" (forAll genASCII prop_works)- , property "error" prop_error- , property "lazy" prop_lazy- ]- - encode iter input =- runIdentity . E.run $- E.enumList 1 input $$- E.joinI (ET.encode ET.ascii $$ iter)- - prop_works bytes = result == map B.singleton words where- Right result = encode EL.consume (map T.singleton chars)- - chars = B8.unpack bytes- words = B.unpack bytes- - prop_error = isLeft (encode EL.consume input) where- isLeft = either (const True) (const False)- input = [T.pack "\x61\xFF"]- - prop_lazy = either (const False) (== expected) result where- result = encode EL.head input- input = [T.pack "\x61\xFF"]- expected = Just (B.singleton 0x61)--suite_Encode_ISO8859 :: Suite-suite_Encode_ISO8859 = suite "iso-8859-1" props where- props = [ property "works" (forAll genISO8859 prop_works)- , property "error" prop_error- , property "lazy" prop_lazy- ]- - encode iter input =- runIdentity . E.run $- E.enumList 1 input $$- E.joinI (ET.encode ET.iso8859_1 $$ iter)- - prop_works bytes = result == map B.singleton words where- Right result = encode EL.consume (map T.singleton chars)- - chars = B8.unpack bytes- words = B.unpack bytes- - prop_error = isLeft (encode EL.consume input) where- isLeft = either (const True) (const False)- input = [T.pack "\x61\xFF5E"]- - prop_lazy = either (const False) (== expected) result where- result = encode EL.head input- input = [T.pack "\x61\xFF5E"]- expected = Just (B.singleton 0x61)--suite_Decoding :: Suite-suite_Decoding = suite "decoding"- [ suite_Decode_ASCII- , suite_Decode_UTF8- , suite_Decode_UTF16_BE- , suite_Decode_UTF16_LE- , suite_Decode_UTF32_BE- , suite_Decode_UTF32_LE- ]--suite_Decode_ASCII :: Suite-suite_Decode_ASCII = suite "ascii" props where- props = [ property "works" (forAll genASCII prop_works)- , property "error" prop_error- , property "lazy" prop_lazy- ]- - decode iter input =- runIdentity . E.run $- E.enumList 1 input $$- E.joinI (ET.decode ET.ascii $$ iter)- - prop_works text = result == map T.singleton chars where- Right result = decode EL.consume (map B.singleton bytes)- - bytes = B.unpack (TE.encodeUtf8 text)- chars = T.unpack text- - prop_error = isLeft (decode EL.consume input) where- isLeft = either (const True) (const False)- input = [B.pack [0xFF]]- - prop_lazy = either (const False) (== expected) result where- result = decode EL.head input- input = [B.pack [0x61, 0xFF]]- expected = Just (T.pack "a")--suite_Decode_UTF8 :: Suite-suite_Decode_UTF8 = suite "utf-8" props where- props = [ property "works" prop_works- , property "error" prop_error- , property "lazy" prop_lazy- , property "incremental" prop_incremental- ]- - decode iter input =- runIdentity . E.run $- E.enumList 1 input $$- E.joinI (ET.decode ET.utf8 $$ iter)- - prop_works text = result == map T.singleton chars where- Right result = decode EL.consume (map B.singleton bytes)- - bytes = B.unpack (TE.encodeUtf8 text)- chars = T.unpack text- - prop_error = isLeft (decode EL.consume input) where- isLeft = either (const True) (const False)- input = [B.pack [0x61, 0x80]]- - prop_lazy = either (const False) (== expected) result where- result = decode EL.head input- input = [B.pack [0x61, 0x80]]- expected = Just (T.pack "a")- - prop_incremental = either (const False) (== expected) result where- result = decode EL.head input- input = [B.pack [0x61, 0xC2, 0xC2]]- expected = Just (T.pack "a")--suite_Decode_UTF16_BE :: Suite-suite_Decode_UTF16_BE = suite "utf-16-be" props where- props = [ property "works" prop_works- , property "lazy" prop_lazy- , property "error" prop_error- , property "incremental" prop_incremental- ]- - decode iter input =- runIdentity . E.run $- E.enumList 1 input $$- E.joinI (ET.decode ET.utf16_be $$ iter)- - prop_works text = result == map T.singleton chars where- Right result = decode EL.consume (map B.singleton bytes)- - bytes = B.unpack (TE.encodeUtf16BE text)- chars = T.unpack text- - prop_lazy = either (const False) (== expected) result where- result = decode EL.head input- input = [B.pack [0x00, 0x61, 0xDD, 0x1E]]- expected = Just (T.pack "a")- - prop_error = isLeft (decode EL.consume input) where- isLeft = either (const True) (const False)- input = [B.pack [0x00, 0x61, 0xDD, 0x1E]]- - prop_incremental = either (const False) (== expected) result where- result = decode EL.head input- input = [B.pack [0x00, 0x61, 0xD8, 0x34, 0xD8, 0xD8]]- expected = Just (T.pack "a")--suite_Decode_UTF16_LE :: Suite-suite_Decode_UTF16_LE = suite "utf-16-le" props where- props = [ property "works" prop_works- , property "lazy" prop_lazy- , property "error" prop_error- , property "incremental" prop_incremental- ]- - decode iter input =- runIdentity . E.run $- E.enumList 1 input $$- E.joinI (ET.decode ET.utf16_le $$ iter)- - prop_works text = result == map T.singleton chars where- Right result = decode EL.consume (map B.singleton bytes)- - bytes = B.unpack (TE.encodeUtf16LE text)- chars = T.unpack text- - prop_lazy = either (const False) (== expected) result where- result = decode EL.head input- input = [B.pack [0x61, 0x00, 0x1E, 0xDD]]- expected = Just (T.pack "a")- - prop_error = isLeft (decode EL.consume input) where- isLeft = either (const True) (const False)- input = [B.pack [0x61, 0x00, 0x1E, 0xDD]]- - prop_incremental = either (const False) (== expected) result where- result = decode EL.head input- input = [B.pack [0x61, 0x00, 0x34, 0xD8, 0xD8, 0xD8]]- expected = Just (T.pack "a")--suite_Decode_UTF32_BE :: Suite-suite_Decode_UTF32_BE = suite "utf-32-be" props where- props = [ property "works" prop_works- , property "lazy" prop_lazy- , property "error" prop_error- ]- - decode iter input =- runIdentity . E.run $- E.enumList 1 input $$- E.joinI (ET.decode ET.utf32_be $$ iter)- - prop_works text = result == map T.singleton chars where- Right result = decode EL.consume (map B.singleton bytes)- - bytes = B.unpack (TE.encodeUtf32BE text)- chars = T.unpack text- - prop_lazy = either (const False) (== expected) result where- result = decode EL.head input- input = [B.pack [0x00, 0x00, 0x00, 0x61, 0xFF, 0xFF]]- expected = Just (T.pack "a")- - prop_error = isLeft (decode EL.consume input) where- isLeft = either (const True) (const False)- input = [B.pack [0xFF, 0xFF, 0xFF, 0xFF]]--suite_Decode_UTF32_LE :: Suite-suite_Decode_UTF32_LE = suite "utf-32-le" props where- props = [ property "works" prop_works- , property "lazy" prop_lazy- , property "error" prop_error- ]- - decode iter input =- runIdentity . E.run $- E.enumList 1 input $$- E.joinI (ET.decode ET.utf32_le $$ iter)- - prop_works text = result == map T.singleton chars where- Right result = decode EL.consume (map B.singleton bytes)- - bytes = B.unpack (TE.encodeUtf32LE text)- chars = T.unpack text- - prop_lazy = either (const False) (== expected) result where- result = decode EL.head input- input = [B.pack [0x61, 0x00, 0x00, 0x00, 0xFF, 0xFF]]- expected = Just (T.pack "a")- - prop_error = isLeft (decode EL.consume input) where- isLeft = either (const True) (const False)- input = [B.pack [0xFF, 0xFF, 0xFF, 0xFF]]---- }}}---- List analogues {{{--suite_ListAnalogues :: Suite-suite_ListAnalogues = suite "list-analogues"- [ suite_Consume- , suite_Head- , suite_Drop- , suite_Take- , suite_Require- , suite_Isolate- , suite_SplitWhen- , suite_Map- , suite_ConcatMap- , suite_MapM- , suite_ConcatMapM- , suite_MapAccum- , suite_MapAccumM- , suite_Filter- , suite_FilterM- ]--check :: Eq b => E.Iteratee a Identity b -> ([a] -> Either Exc.ErrorCall b) -> [a] -> Bool-check iter plain xs = expected == run iter xs where- expected = case plain xs of- Left exc -> Left (Just exc)- Right x -> Right x- - run iter xs = case runIdentity (E.run (E.enumList 1 xs $$ iter)) of- Left exc -> Left (Exc.fromException exc)- Right x -> Right x--testListAnalogue name iterList plainList iterText plainText iterBytes plainBytes = suite name tests where- tests = [ property "list" prop_List- , property "text" prop_Text- , property "bytes" prop_Bytes- ]- - prop_List :: [A] -> Bool- prop_List xs = check iterList plainList xs- - prop_Text xs = check iterText (plainText . TL.fromChunks) xs- prop_Bytes xs = check iterBytes (plainBytes . BL.fromChunks) xs--testListAnalogueN name iterList plainList iterText plainText iterBytes plainBytes = suite name tests where- tests = [ property "list" prop_List- , property "text" prop_Text- , property "bytes" prop_Bytes- ]- - prop_List :: Positive Integer -> [A] -> Bool- prop_List (Positive n) xs = check (iterList n) (plainList n) xs- - prop_Text (Positive n) xs = check (iterText n) (plainText n . TL.fromChunks) xs- prop_Bytes (Positive n) xs = check (iterBytes n) (plainBytes n . BL.fromChunks) xs--testListAnalogueX name iterList plainList iterText plainText iterBytes plainBytes = suite name tests where- tests = [ property "list" prop_List- , property "text" prop_Text- , property "bytes" prop_Bytes- ]- - prop_List :: A -> [A] -> Bool- prop_List x xs = check (iterList x) (plainList x) xs- - prop_Text x xs = check (iterText x) (plainText x . TL.fromChunks) xs- prop_Bytes x xs = check (iterBytes x) (plainBytes x . BL.fromChunks) xs--suite_Consume :: Suite-suite_Consume = testListAnalogue "consume"- EL.consume Right- ET.consume Right- EB.consume Right--suite_Head :: Suite-suite_Head = testListAnalogue "head"- (do- x <- EL.head- extra <- EL.consume- return (x, extra)- )- (\xs -> Right $ case xs of- [] -> (Nothing, [])- (x:xs') -> (Just x, xs'))- (do- x <- ET.head- extra <- ET.consume- return (x, extra)- )- (\text -> Right $ case TL.uncons text of- Nothing -> (Nothing, TL.empty)- Just (x, extra) -> (Just x, extra))- (do- x <- EB.head- extra <- EB.consume- return (x, extra)- )- (\bytes -> Right $ case BL.uncons bytes of- Nothing -> (Nothing, BL.empty)- Just (x, extra) -> (Just x, extra))--suite_Drop :: Suite-suite_Drop = testListAnalogueN "drop"- (\n -> EL.drop n >> EL.consume)- (\n -> Right . L.genericDrop n)- (\n -> ET.drop n >> ET.consume)- (\n -> Right . TL.drop (fromInteger n))- (\n -> EB.drop n >> EB.consume)- (\n -> Right . BL.drop (fromInteger n))--suite_Take :: Suite-suite_Take = testListAnalogueN "take"- (\n -> do- xs <- EL.take n- extra <- EL.consume- return (xs, extra))- (\n -> Right . L.genericSplitAt n)- (\n -> do- xs <- ET.take n- extra <- ET.consume- return (xs, extra))- (\n -> Right . TL.splitAt (fromInteger n))- (\n -> do- xs <- EB.take n- extra <- EB.consume- return (xs, extra))- (\n -> Right . BL.splitAt (fromInteger n))--suite_Require :: Suite-suite_Require = testListAnalogueN "require"- (\n -> do- EL.require n- EL.consume)- (\n xs -> if n > toInteger (length xs)- then Left (Exc.ErrorCall "require: Unexpected EOF")- else Right xs)- (\n -> do- ET.require n- ET.consume)- (\n xs -> if n > toInteger (TL.length xs)- then Left (Exc.ErrorCall "require: Unexpected EOF")- else Right xs)- (\n -> do- EB.require n- EB.consume)- (\n xs -> if n > toInteger (BL.length xs)- then Left (Exc.ErrorCall "require: Unexpected EOF")- else Right xs)--suite_Isolate :: Suite-suite_Isolate = testListAnalogue "isolate"- (do- x <- E.joinI (EL.isolate 2 $$ EL.head)- extra <- EL.consume- return (x, extra))- (\xs -> Right $ case xs of- [] -> (Nothing, [])- (x:[]) -> (Just x, [])- (x:_:xs') -> (Just x, xs'))- (do- x <- E.joinI (ET.isolate 2 $$ ET.head)- extra <- ET.consume- return (x, extra))- (\text -> Right $ case TL.unpack text of- [] -> (Nothing, TL.empty)- (x:[]) -> (Just x, TL.empty)- (x:_:xs') -> (Just x, TL.pack xs'))- (do- x <- E.joinI (EB.isolate 2 $$ EB.head)- extra <- EB.consume- return (x, extra))- (\bytes -> Right $ case BL.unpack bytes of- [] -> (Nothing, BL.empty)- (x:[]) -> (Just x, BL.empty)- (x:_:xs) -> (Just x, BL.pack xs))--suite_SplitWhen :: Suite-suite_SplitWhen = testListAnalogueX "splitWhen"- (\x -> do- xs <- E.joinI (EL.splitWhen (== x) $$ EL.consume)- extra <- EL.consume- return (xs, extra))- (\x xs -> let- split = LS.split . LS.dropFinalBlank . LS.dropDelims . LS.whenElt- in Right (split (== x) xs, []))- (\c -> do- xs <- E.joinI (ET.splitWhen (== c) $$ EL.consume)- extra <- EL.consume- return (xs, extra))- (\c text -> let- split = LS.split . LS.dropFinalBlank . LS.dropDelims . LS.whenElt- chars = TL.unpack text- in Right (map T.pack (split (== c) chars), []))- (\x -> do- xs <- E.joinI (EB.splitWhen (== x) $$ EL.consume)- extra <- EL.consume- return (xs, extra))- (\x bytes -> let- split = LS.split . LS.dropFinalBlank . LS.dropDelims . LS.whenElt- words = BL.unpack bytes- in Right (map B.pack (split (== x) words), []))--suite_Map :: Suite-suite_Map = test_Enumeratee "map" (EL.map id)--suite_ConcatMap :: Suite-suite_ConcatMap = test_Enumeratee "concatMap" (EL.concatMap (:[]))--suite_MapM :: Suite-suite_MapM = test_Enumeratee "mapM" (EL.mapM return)--suite_ConcatMapM :: Suite-suite_ConcatMapM = test_Enumeratee "concatMapM" (EL.concatMapM (\x -> return [x]))--suite_MapAccum :: Suite-suite_MapAccum = testListAnalogue "mapAccum"- (do- let enee = EL.mapAccum (\s ao -> (s+1, (s, ao))) 10- a <- E.joinI (enee $$ EL.head)- b <- EL.consume- return (a, b))- (\xs -> Right $ case xs of- [] -> (Nothing, [])- (x:xs') -> (Just (10, x), xs'))- (do- let enee = ET.mapAccum (\s ao -> (s+1, succ ao)) 10- a <- E.joinI (enee $$ EL.head)- b <- ET.consume- return (a, b))- (\text -> Right $ case TL.uncons text of- Nothing -> (Nothing, TL.empty)- Just (c, text') -> (Just (T.singleton (succ c)), text'))- (do- let enee = EB.mapAccum (\s ao -> (s+1, ao + s)) 10- a <- E.joinI (enee $$ EL.head)- b <- EB.consume- return (a, b))- (\bytes -> Right $ case BL.uncons bytes of- Nothing -> (Nothing, BL.empty)- Just (b, bytes') -> (Just (B.singleton (b + 10)), bytes'))---suite_MapAccumM :: Suite-suite_MapAccumM = testListAnalogue "mapAccumM"- (do- let enee = EL.mapAccumM (\s ao -> return (s+1, (s, ao))) 10- a <- E.joinI (enee $$ EL.head)- b <- EL.consume- return (a, b))- (\xs -> Right $ case xs of- [] -> (Nothing, [])- (x:xs') -> (Just (10, x), xs'))- (do- let enee = ET.mapAccumM (\s ao -> return (s+1, succ ao)) 10- a <- E.joinI (enee $$ EL.head)- b <- ET.consume- return (a, b))- (\text -> Right $ case TL.uncons text of- Nothing -> (Nothing, TL.empty)- Just (c, text') -> (Just (T.singleton (succ c)), text'))- (do- let enee = EB.mapAccumM (\s ao -> return (s+1, ao + s)) 10- a <- E.joinI (enee $$ EL.head)- b <- EB.consume- return (a, b))- (\bytes -> Right $ case BL.uncons bytes of- Nothing -> (Nothing, BL.empty)- Just (b, bytes') -> (Just (B.singleton (b + 10)), bytes'))--suite_Filter :: Suite-suite_Filter = test_Enumeratee "filter" (EL.filter (\_ -> True))--suite_FilterM :: Suite-suite_FilterM = test_Enumeratee "filterM" (EL.filterM (\_ -> return True))---- }}}---- Specific functions--suite_Other :: Suite-suite_Other = suite "other"- [ test_Sequence- , test_joinE- , suite "catchError"- [ test test_CatchError_WithoutContinue- , test test_CatchError_NotDivergent- , test test_CatchError_Interleaved- ]- , test test_Zip- , test test_ZipBytes- , test test_ZipText- ]--test_Sequence :: Suite-test_Sequence = property "sequence" prop where- prop :: Positive Integer -> [A] -> Bool- prop (Positive n) xs = result == expected where- result = runIdentity (E.run_ iter)- expected = map Just xs- - iter = E.enumList n xs $$ E.joinI (E.sequence EL.head $$ EL.consume)--test_joinE :: Suite-test_joinE = property "joinE" prop where- prop :: [Integer] -> Bool- prop xs = result == expected where- result = runIdentity (E.run_ iter)- expected = map (* 10) xs- - iter = (E.joinE (E.enumList 1 xs) (EL.map (* 10))) $$ EL.consume--test_CatchError_WithoutContinue :: Test-test_CatchError_WithoutContinue = assertions "without-continue" $ do- let iter = E.catchError- (E.throwError (Exc.ErrorCall "error"))- (\_ -> EL.require 1)- - res <- E.run (E.enumList 1 [] $$ iter)- $assert (left res)- - let Left err = res- $assert $ equal (Exc.fromException err) (Just (Exc.ErrorCall "require: Unexpected EOF"))--test_CatchError_NotDivergent :: Test-test_CatchError_NotDivergent = assertions "not-divergent" $ do- let iter = E.catchError- (do- EL.head- E.throwError (Exc.ErrorCall "error"))- (\_ -> EL.require 1)- - res <- E.run (E.enumList 1 [] $$ iter)- $assert (left res)- - let Left err = res- $assert $ equal (Exc.fromException err) (Just (Exc.ErrorCall "require: Unexpected EOF"))--test_CatchError_Interleaved :: Test-test_CatchError_Interleaved = within 1000 $ assertions "interleaved" $ do- let enumMVar mvar = EL.repeatM (liftIO (takeMVar mvar))- let iter mvar = do- liftIO (putMVar mvar ())- EL.head- return True- let onError err = return False- - mvar <- liftIO newEmptyMVar- E.run_ (enumMVar mvar $$ E.catchError (iter mvar) onError)--test_Zip :: Test-test_Zip = assertions "zip" $ do- let iterTup = do- Just x <- EL.head- Just y <- EL.head- return (x, y)- let iterTupFlip = do- Just x <- EL.head- Just y <- EL.head- return (y, x)- - let check i1 i2 = E.run_ (E.enumList 4 [1, 2, 3, 4, 5] $$ do- (x, y) <- EL.zip i1 i2- extra <- EL.consume- return (x, y, extra))- - -- Both sides have same behavior- (tup, tup2, extra) <- check iterTup iterTupFlip- $expect (equal tup (1, 2))- $expect (equal tup2 (2, 1))- $expect (equal extra [3, 4, 5])- - -- First side has more extra data- (took, tup, extra) <- check (EL.take 1) iterTup- $expect (equal took [1])- $expect (equal tup (1, 2))- $expect (equal extra [3, 4, 5])- - -- Second side has more extra data- (tup, took, extra) <- check iterTup (EL.take 1)- $expect (equal tup (1, 2))- $expect (equal took [1])- $expect (equal extra [3, 4, 5])--test_ZipBytes :: Test-test_ZipBytes = assertions "zip-bytes" $ do- let iterTup = do- Just x <- EB.head- Just y <- EB.head- return (x, y)- let iterTupFlip = do- Just x <- EB.head- Just y <- EB.head- return (y, x)- - let check i1 i2 = E.run_ (E.enumList 2 ["abc", "def", "ghi"] $$ do- (x, y) <- EB.zip i1 i2- extra <- EL.consume- return (x, y, extra))- - -- Both sides have same behavior- (tup, tup2, extra) <- check iterTup iterTupFlip- $expect (equal tup (0x61, 0x62))- $expect (equal tup2 (0x62, 0x61))- $expect (equal extra ["c", "def", "ghi"])- - -- First side has more extra data- (took, tup, extra) <- check (EB.take 1) iterTup- $expect (equal took "a")- $expect (equal tup (0x61, 0x62))- $expect (equal extra ["c", "def", "ghi"])- - -- Second side has more extra data- (tup, took, extra) <- check iterTup (EB.take 1)- $expect (equal tup (0x61, 0x62))- $expect (equal took "a")- $expect (equal extra ["c", "def", "ghi"])--test_ZipText :: Test-test_ZipText = assertions "zip-text" $ do- let iterTup = do- Just x <- ET.head- Just y <- ET.head- return (x, y)- let iterTupFlip = do- Just x <- ET.head- Just y <- ET.head- return (y, x)- - let check i1 i2 = E.run_ (E.enumList 2 ["abc", "def", "ghi"] $$ do- (x, y) <- ET.zip i1 i2- extra <- EL.consume- return (x, y, extra))- - -- Both sides have same behavior- (tup, tup2, extra) <- check iterTup iterTupFlip- $expect (equal tup ('a', 'b'))- $expect (equal tup2 ('b', 'a'))- $expect (equal extra ["c", "def", "ghi"])- - -- First side has more extra data- (took, tup, extra) <- check (ET.take 1) iterTup- $expect (equal took "a")- $expect (equal tup ('a', 'b'))- $expect (equal extra ["c", "def", "ghi"])- - -- Second side has more extra data- (tup, took, extra) <- check iterTup (ET.take 1)- $expect (equal tup ('a', 'b'))- $expect (equal took "a")- $expect (equal extra ["c", "def", "ghi"])---- misc--genASCII :: IsString a => Gen a-genASCII = fmap fromString string where- string = sized $ \n -> do- k <- choose (0,n)- sequence [ char | _ <- [1..k] ]- - char = chr `fmap` choose (0,0x7F)--genISO8859 :: IsString a => Gen a-genISO8859 = fmap fromString string where- string = sized $ \n -> do- k <- choose (0,n)- sequence [ char | _ <- [1..k] ]- - char = chr `fmap` choose (0,0xFF)--genUnicode :: IsString a => Gen a-genUnicode = fmap fromString string where- string = sized $ \n -> do- k <- choose (0,n)- sequence [ char | _ <- [1..k] ]- - excluding :: [a -> Bool] -> Gen a -> Gen a- excluding bad gen = loop where- loop = do- x <- gen- if or (map ($ x) bad)- then loop- else return x- - reserved = [lowSurrogate, highSurrogate, noncharacter]- lowSurrogate c = c >= 0xDC00 && c <= 0xDFFF- highSurrogate c = c >= 0xD800 && c <= 0xDBFF- noncharacter c = masked == 0xFFFE || masked == 0xFFFF where- masked = c .&. 0xFFFF- - ascii = choose (0,0x7F)- plane0 = choose (0xF0, 0xFFFF)- plane1 = oneof [ choose (0x10000, 0x10FFF)- , choose (0x11000, 0x11FFF)- , choose (0x12000, 0x12FFF)- , choose (0x13000, 0x13FFF)- , choose (0x1D000, 0x1DFFF)- , choose (0x1F000, 0x1FFFF)- ]- plane2 = oneof [ choose (0x20000, 0x20FFF)- , choose (0x21000, 0x21FFF)- , choose (0x22000, 0x22FFF)- , choose (0x23000, 0x23FFF)- , choose (0x24000, 0x24FFF)- , choose (0x25000, 0x25FFF)- , choose (0x26000, 0x26FFF)- , choose (0x27000, 0x27FFF)- , choose (0x28000, 0x28FFF)- , choose (0x29000, 0x29FFF)- , choose (0x2A000, 0x2AFFF)- , choose (0x2B000, 0x2BFFF)- , choose (0x2F000, 0x2FFFF)- ]- plane14 = choose (0xE0000, 0xE0FFF)- planes = [ascii, plane0, plane1, plane2, plane14]- - char = chr `fmap` excluding reserved (oneof planes)--instance Arbitrary a => Arbitrary (E.Stream a) where- arbitrary = frequency- [ (10, return E.EOF)- , (90, fmap E.Chunks arbitrary)- ]--instance Arbitrary T.Text where- arbitrary = genUnicode--instance Arbitrary B.ByteString where- arbitrary = genUnicode--instance Eq Exc.ErrorCall where- (Exc.ErrorCall s1) == (Exc.ErrorCall s2) = s1 == s2---- | Require a test to complete within /n/ milliseconds.-within :: Int -> Test -> Test-within time (Test name io) = Test name $ \opts -> do- res <- timeout (time * 1000) (io opts)- case res of- Just res' -> return res'- Nothing -> return (TestAborted [] (T.pack ("Test timed out after " ++ show time ++ " milliseconds")))
tests/enumerator-tests.cabal view
@@ -3,16 +3,38 @@ build-type: Simple cabal-version: >= 1.6 +flag coverage+ default: False+ manual: True++flag test-io-functions+ default: True+ executable enumerator_tests- main-is: Tests.hs- ghc-options: -Wall -O2+ main-is: EnumeratorTests.hs+ ghc-options: -Wall+ hs-source-dirs: ../lib,. + if flag(coverage)+ ghc-options: -fhpc++ if flag(test-io-functions)+ build-depends:+ base >= 4.2 && < 5.0+ , knob >= 0.1 && < 0.2++ if !os(windows)+ build-depends:+ silently+ else+ build-depends:+ base >= 4.0 && < 5.0+ build-depends:- base > 3 && < 5- , bytestring- , chell >= 0.1 && < 0.2+ bytestring+ , chell >= 0.2 && < 0.3 , chell-quickcheck >= 0.1 && < 0.2- , enumerator+ , containers , QuickCheck , split , text