fileplow-0.1.0.0: test/Spec.hs
module Main where
import Data.FilePlow
import Data.FilePlow.Ordered
import Control.Monad
import Control.Monad.Trans
import Data.List
import Data.Monoid
import System.IO (hClose)
import System.IO.Temp
import Test.Hspec
import Test.QuickCheck
import Test.QuickCheck.Monadic
import qualified Data.ByteString as BS
import qualified Data.ByteString.Builder as BSB
import qualified Data.ByteString.Char8 as BSC
import qualified Data.ByteString.Lazy as BSL
makeRangeBS :: ([Int] -> [Int]) -> Int -> Int -> BS.ByteString
makeRangeBS f lb ub =
BSL.toStrict . BSB.toLazyByteString $
foldl' (\bldr i -> bldr <> BSB.int64Dec (fromIntegral i) <> BSB.char8 '\n') mempty $ f [lb .. ub]
withDummyFileNum :: ([Int] -> [Int]) -> (Int, Int) -> (FilePath -> IO a) -> IO a
withDummyFileNum f (lb, ub) go =
withSystemTempFile "dummyFilePlowTest" $ \fp hdl ->
do BS.hPut hdl (makeRangeBS f lb ub)
hClose hdl
go fp
withDummyFile :: Char -> Int -> (FilePath -> IO a) -> IO a
withDummyFile c size go =
withSystemTempFile "dummyFilePlowTest" $ \fp hdl ->
do BS.hPut hdl (BSC.replicate size c)
hClose hdl
go fp
readRest :: MultiHandle Handle -> IO BS.ByteString
readRest hdl =
do let getLoop builder =
do eof <- pIsEOF hdl
if eof
then pure $ BSL.toStrict (BSB.toLazyByteString builder)
else do x <- pGetChar hdl
getLoop (builder <> BSB.char8 x)
getLoop mempty
main :: IO ()
main =
hspec $
do describe "multi handle" $
do it "simple get char works" $
withDummyFile 'a' 100 $ \f1 ->
withDummyFile 'b' 100 $ \f2 ->
withMultiHandle [f1, f2] $ \hdl ->
do bs <- readRest hdl
bs `shouldBe` (BSC.replicate 100 'a' <> BSC.replicate 100 'b')
it "two full reads with going to the begining work" $
withDummyFile 'a' 100 $ \f1 ->
withDummyFile 'b' 100 $ \f2 ->
withMultiHandle [f1, f2] $ \hdl ->
do _ <- readRest hdl
pSeek hdl AbsoluteSeek 0
bs <- readRest hdl
bs `shouldBe` (BSC.replicate 100 'a' <> BSC.replicate 100 'b')
it "seek tell works" $
forAll (choose (0, 199)) $ \p ->
monadicIO $
do r <-
liftIO $
withDummyFile 'a' 100 $ \f1 ->
withDummyFile 'b' 100 $ \f2 ->
withMultiHandle [f1, f2] $ \hdl ->
do pSeek hdl AbsoluteSeek p
x <- pTell hdl
pure x
assert (r == p)
it "seek until works" $
withDummyFile 'a' 100 $ \f1 ->
withDummyFile 'b' 100 $ \f2 ->
withMultiHandle [f1, f2] $ \hdl ->
do ok <- seekUntil hdl (== 'b')
ok `shouldBe` True
bs <- readRest hdl
bs `shouldBe` BSC.replicate 99 'b'
it "seek untilRev works" $
withDummyFile 'a' 100 $ \f1 ->
withDummyFile 'b' 100 $ \f2 ->
withMultiHandle [f1, f2] $ \hdl ->
do pSeek hdl AbsoluteSeek 199
ok <- seekUntilRev hdl (== 'a')
ok `shouldBe` True
bs <- readRest hdl
bs `shouldBe` BSC.replicate 100 'b'
it "seeked reads work" $
withDummyFile 'a' 100 $ \f1 ->
withDummyFile 'b' 100 $ \f2 ->
withMultiHandle [f1, f2] $ \hdl ->
do pSeek hdl AbsoluteSeek 100
bs <- readRest hdl
bs `shouldBe` BSC.replicate 100 'b'
pSeek hdl AbsoluteSeek 50
bs2 <- readRest hdl
bs2 `shouldBe` (BSC.replicate 50 'a' <> BSC.replicate 100 'b')
pSeek hdl SeekFromEnd (-50)
bs3 <- readRest hdl
bs3 `shouldBe` BSC.replicate 50 'b'
pSeek hdl SeekFromEnd (-150)
bs4 <- readRest hdl
bs4 `shouldBe` (BSC.replicate 50 'a' <> BSC.replicate 100 'b')
pSeek hdl AbsoluteSeek 0
pSeek hdl RelativeSeek 100
bs5 <- readRest hdl
bs5 `shouldBe` BSC.replicate 100 'b'
pSeek hdl AbsoluteSeek 50
pSeek hdl RelativeSeek 25
bs6 <- readRest hdl
bs6 `shouldBe` (BSC.replicate 25 'a' <> BSC.replicate 100 'b')
describe "ordered" $
do it "find a lower bound" $
withDummyFileNum id (100, 199) $ \f1 ->
withDummyFileNum id (200, 299) $ \f2 ->
withMultiHandle [f1, f2] $ \hdl ->
do ok <-
seekTo hdl (StLargerThan (150 :: Int)) $ \h ->
do void $ seekUntilRev hdl (== '\n')
eof <- pIsEOF hdl
if eof
then pure 999
else do ln <- pGetLine h
pure $ read (BSC.unpack ln)
ok `shouldBe` True
void $ seekUntilRev hdl (== '\n')
bs <- readRest hdl
bs `shouldBe` (makeRangeBS id 150 299)
it "finds upper bound" $
withDummyFileNum reverse (200, 299) $ \f1 ->
withDummyFileNum reverse (100, 199) $ \f2 ->
withMultiHandle [f1, f2] $ \hdl ->
do ok <-
seekTo hdl (StSmallerThan (150 :: Int)) $ \h ->
do void $ seekUntilRev hdl (== '\n')
eof <- pIsEOF hdl
if eof
then pure 0
else do ln <- pGetLine h
pure $ read (BSC.unpack ln)
ok `shouldBe` True
void $ seekUntilRev hdl (== '\n')
bs <- readRest hdl
bs `shouldBe` (makeRangeBS reverse 100 150)