{- Copyright 2017-2018 Luis Pedro Coelho
- License: MIT
-}
{-# LANGUAGE TemplateHaskell, CPP, QuasiQuotes, FlexibleContexts, OverloadedStrings #-}
module Main where
import Test.Framework.TH
import Test.HUnit
import Test.Framework.Providers.HUnit
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as B8
import qualified Data.Conduit as C
import qualified Data.Conduit.Combinators as CC
import qualified Data.Conduit.Binary as CB
import qualified Data.Conduit.List as CL
import qualified Data.Functor.Identity as FID
import qualified Data.Vector.Storable as VS
import Data.Conduit ((.|))
import Data.List (sort)
import System.Directory (removeFile)
import Control.Exception (catch, ErrorCall)
import Control.Monad (forM_)
import Control.Monad.Trans.Resource.Internal (ResourceT)
import Control.Monad.Trans.Control (MonadBaseControl)
import qualified Data.Conduit.Algorithms as CAlg
import qualified Data.Conduit.Algorithms.Storable as CAlg
import qualified Data.Conduit.Algorithms.Utils as CAlg
import qualified Data.Conduit.Algorithms.Async as CAlg
import qualified Data.Conduit.Algorithms.Async.ByteString as CAlg
main :: IO ()
main = $(defaultMainGenerator)
testingFileNameGZ :: FilePath
testingFileNameGZ = "file_just_for_testing_delete_me_please.gz"
testingFileNameGZ2 :: FilePath
testingFileNameGZ2 = "file_just_for_testing_delete_me_please_2.gz"
testingFileNameBZ2 :: FilePath
testingFileNameBZ2 = "file_just_for_testing_delete_me_please.bz2"
testingFileNameBZ22 :: FilePath
testingFileNameBZ22 = "file_just_for_testing_delete_me_please_2.bz2"
testingFileNameXZ :: FilePath
testingFileNameXZ = "file_just_for_testing_delete_me_please.xz"
testingFileNameXZ2 :: FilePath
testingFileNameXZ2 = "file_just_for_testing_delete_me_please_2.xz"
extract :: C.ConduitM () b FID.Identity () -> [b]
extract c = C.runConduitPure (c .| CC.sinkList)
extractIO :: MonadBaseControl IO m => C.ConduitM () b (ResourceT m) () -> m [b]
extractIO c = C.runConduitRes (c .| CC.sinkList)
shouldProduce :: (Show b, Eq b) => [b] -> C.ConduitM () b FID.Identity () -> Assertion
shouldProduce values cond = extract cond @?= values
shouldProduceIO :: (Show b, Eq b) => [b] -> C.ConduitM () b (ResourceT IO) () -> IO ()
shouldProduceIO values cond = do
p <- extractIO cond
p @?= values
assertError :: IO f -> IO ()
assertError f = do
errored <- catch (f >> pure False) handler
if errored then
pure ()
else
assertFailure "Expected error but none was triggered"
where
handler :: ErrorCall -> IO Bool
handler _ = pure True
case_uniqueC :: Assertion
case_uniqueC = extract (CC.yieldMany [1,2,3,1,1,2,3] .| CAlg.uniqueC) @=? [1,2,3 :: Int]
case_mergeC :: Assertion
case_mergeC = shouldProduce expected $
CAlg.mergeC
[ CC.yieldMany i1
, CC.yieldMany i2
, CC.yieldMany i3
, CC.yieldMany i3
]
where
expected = sort (concat [i1, i2, i3, i3])
i1 = [ 1, 2, 4 :: Int]
i2 = [ 1, 4, 4, 5]
i3 = [-1, 0, 7]
case_mergeCmonad :: Assertion
case_mergeCmonad = shouldProduce expected $
CAlg.mergeC
[ mYield i1
, mYield i2
, mYield i3
]
where
expected = sort (concat [i1, i2, i3])
mYield lst = do
let lst' = map return lst
forM_ lst' $ \elemnt -> do
elemnt' <- elemnt
C.yield elemnt'
i1 = [ 0, 2, 4 :: Int]
i2 = [ 1, 3, 4, 5]
i3 = [-1, 0, 7]
case_mergeCempty :: Assertion
case_mergeCempty = shouldProduce ([] :: [Int]) $ CAlg.mergeC []
case_mergeC2 :: Assertion
case_mergeC2 = shouldProduce [0, 1, 1, 2, 3, 5 :: Int] $
CAlg.mergeC2
(CC.yieldMany [0, 1, 2])
(CC.yieldMany [1, 3, 5])
case_mergeC2same :: Assertion
case_mergeC2same = shouldProduce [0, 0, 1, 1, 2, 2 :: Int] $
CAlg.mergeC2
(CC.yieldMany [0, 1, 2])
(CC.yieldMany [0, 1, 2])
case_mergeC2monad :: Assertion
case_mergeC2monad = shouldProduce [0, 1, 2, 2, 3, 4 :: Int] $ do
CAlg.mergeC2
(CC.yieldMany [0, 2])
(CC.yieldMany [1, 2])
CC.yieldMany [3]
CC.yieldMany [4]
case_groupC :: Assertion
case_groupC = shouldProduce [[0,1,2], [3,4,5], [6,7,8], [9, 10 :: Int]] $
CC.yieldMany [0..10] .| CAlg.groupC 3
case_enumerateC :: Assertion
case_enumerateC = shouldProduce [(0,'z'), (1,'o'), (2,'t')] $
CC.yieldMany ("zot" :: String) .| CAlg.enumerateC
case_removeRepeatsC :: Assertion
case_removeRepeatsC = shouldProduce [0,1,2,3,4,5,6,7,8,9, 10 :: Int] $
CC.yieldMany [0,0,0,1,1,1,2,2,3,4,5,6,6,6,6,7,7,8,9,10,10] .| CAlg.removeRepeatsC
case_asyncMap :: IO ()
case_asyncMap = do
vals <- extractIO (CC.yieldMany [0..10] .| CAlg.asyncMapC 3 (+ (1:: Int)))
vals @?= [1..11]
case_unorderedAsyncMapC :: IO ()
case_unorderedAsyncMapC = do
vals <- extractIO (CC.yieldMany [0..10] .| CAlg.unorderedAsyncMapC 3 (+ (1:: Int)))
sort vals @?= [1..11]
case_asyncGzip :: IO ()
case_asyncGzip = do
C.runConduitRes (CC.yieldMany ["Hello", " ", "World"] .| CAlg.asyncGzipToFile testingFileNameGZ)
r <- B.concat <$> extractIO (CAlg.asyncGzipFromFile testingFileNameGZ)
r @?= "Hello World"
removeFile testingFileNameGZ
case_asyncBzip2 :: IO ()
case_asyncBzip2 = do
C.runConduitRes (CC.yieldMany ["Hello", " ", "World"] .| CAlg.asyncBzip2ToFile testingFileNameBZ2)
r <- B.concat <$> extractIO (CAlg.asyncBzip2FromFile testingFileNameBZ2)
r @?= "Hello World"
removeFile testingFileNameBZ2
case_asyncXz :: IO ()
#ifdef WINDOWS
case_asyncXz = assertError $ do
#else
case_asyncXz = do
#endif
C.runConduitRes (CC.yieldMany ["Hello", " ", "World"] .| CAlg.asyncXzToFile testingFileNameXZ)
r <- B.concat <$> extractIO (CAlg.asyncXzFromFile testingFileNameXZ)
r @?= "Hello World"
removeFile testingFileNameXZ
case_async_gzip_to_from :: IO ()
case_async_gzip_to_from = do
let testdata = [0 :: Int .. 12]
C.runConduitRes $
CC.yieldMany testdata
.| CL.map (B8.pack . (\n -> show n ++ "\n"))
.| CAlg.asyncGzipToFile testingFileNameGZ
C.runConduitRes $
CAlg.asyncGzipFromFile testingFileNameGZ
.| CAlg.asyncGzipToFile testingFileNameGZ2
shouldProduceIO testdata $
CAlg.asyncGzipFromFile testingFileNameGZ2
.| CB.lines
.| CL.map (read . B8.unpack)
removeFile testingFileNameGZ
removeFile testingFileNameGZ2
case_async_bzip2_to_from :: IO ()
case_async_bzip2_to_from = do
let testdata = [0 :: Int .. 12]
C.runConduitRes $
CC.yieldMany testdata
.| CL.map (B8.pack . (\n -> show n ++ "\n"))
.| CAlg.asyncBzip2ToFile testingFileNameBZ2
C.runConduitRes $
CAlg.asyncBzip2FromFile testingFileNameBZ2
.| CAlg.asyncBzip2ToFile testingFileNameBZ22
shouldProduceIO testdata $
CAlg.asyncBzip2FromFile testingFileNameBZ22
.| CB.lines
.| CL.map (read . B8.unpack)
removeFile testingFileNameBZ2
removeFile testingFileNameBZ22
case_async_xz_to_from :: IO ()
#ifdef WINDOWS
case_async_xz_to_from = assertError $ do
#else
case_async_xz_to_from = do
#endif
let testdata = [0 :: Int .. 12]
C.runConduitRes $
CC.yieldMany testdata
.| CL.map (B8.pack . (\n -> show n ++ "\n"))
.| CAlg.asyncXzToFile testingFileNameXZ
C.runConduitRes $
CAlg.asyncXzFromFile testingFileNameXZ
.| CAlg.asyncXzToFile testingFileNameXZ2
shouldProduceIO testdata $
CAlg.asyncXzFromFile testingFileNameXZ2
.| CB.lines
.| CL.map (read . B8.unpack)
removeFile testingFileNameXZ
removeFile testingFileNameXZ2
case_asyncFilterLines :: IO ()
case_asyncFilterLines = do
vals <- extractIO (CC.yieldMany ["This is\nMy data\nBut"," sometimes","\nit is split,\n","in weird ways."] .| CAlg.asyncFilterLinesC 2 (B8.notElem ','))
vals @?= ["This is", "My data", "But sometimes", "in weird ways."]
case_asyncFilterLinesAllTrue :: IO ()
case_asyncFilterLinesAllTrue = do
vals <- extractIO (CC.yieldMany ["This is\nMy data\nBut"," sometimes","\nit is split,\n","in weird ways."] .| CAlg.asyncFilterLinesC 2 (const True))
vals @?= ["This is", "My data", "But sometimes", "it is split,", "in weird ways."]
case_storableVector :: IO ()
case_storableVector = do
let v = VS.fromList [0:: Int, 1, 2, 4, 6, 12]
vals <- extractIO (CC.yieldMany [v,v,v] .| CAlg.writeStorableV .| CAlg.readStorableV 3)
VS.concat vals @=? VS.concat [v,v,v]