lazyio-0.1: src/Test/Main.hs
module Main where
import qualified System.IO.Lazy as LazyIO
import qualified System.IO as IO
import System.Exit (exitFailure, )
import Control.Monad.Trans.Reader (ReaderT(ReaderT), runReaderT, )
import Control.Monad (liftM2, )
import Prelude hiding (getLine, )
inputName, outputName :: FilePath
inputName = "input"
outputName = "output"
assert :: Bool -> IO ()
assert b =
if b
then putStrLn "test ok"
else putStrLn "failure" >> exitFailure
class HasReadHandle h where
getReadHandle :: h -> IO.Handle
class HasWriteHandle h where
getWriteHandle :: h -> IO.Handle
newtype ReadHandle = ReadHandle IO.Handle
instance HasReadHandle ReadHandle where
getReadHandle (ReadHandle h) = h
data ReadWriteHandle = ReadWriteHandle IO.Handle IO.Handle
instance HasReadHandle ReadWriteHandle where
getReadHandle (ReadWriteHandle h _) = h
instance HasWriteHandle ReadWriteHandle where
getWriteHandle (ReadWriteHandle _ h) = h
getLine :: HasReadHandle h => ReaderT h LazyIO.T String
getLine =
ReaderT $ LazyIO.interleave . IO.hGetLine . getReadHandle
getLinePair :: HasReadHandle h => ReaderT h LazyIO.T (String, String)
getLinePair =
do x <- getLine
y <- getLine
return (x,y)
getLinePairOfPairs :: HasReadHandle h =>
ReaderT h LazyIO.T ((String, String), (String, String))
getLinePairOfPairs =
do x <- getLinePair
y <- getLinePair
return (x,y)
forever :: (Monad m) => m a -> m [a]
forever x = liftM2 (:) x (forever x)
runReadTest ::
String -> ReaderT ReadHandle LazyIO.T a -> (a -> IO ()) -> IO ()
runReadTest content action check =
do writeFile inputName content
IO.withFile inputName IO.ReadMode $ \h ->
do check =<< LazyIO.run (runReaderT action (ReadHandle h))
IO.hIsEOF h >>= assert
putLine :: HasWriteHandle h => String -> ReaderT h LazyIO.T ()
putLine str =
ReaderT $ \h -> LazyIO.interleave $ IO.hPutStrLn (getWriteHandle h) str
runReadWriteTest ::
String -> String -> ReaderT ReadWriteHandle LazyIO.T a -> (a -> IO ()) -> IO ()
runReadWriteTest inputContent outputContent action check =
do writeFile inputName inputContent
IO.withFile inputName IO.ReadMode $ \hr ->
IO.withFile outputName IO.WriteMode $ \hw ->
do check =<< LazyIO.run (runReaderT action (ReadWriteHandle hr hw))
IO.hIsEOF hr >>= assert
assert . (outputContent ==) =<< readFile outputName
{- |
This test works by observing things that should not be observable.
(Yes, in the IO monad it would also be possible to observe memory consumption
and thus whether laziness works or not.)
Be warned again, that you should not use LazyIO in that way,
but restrict its use to a set of IO actions,
that is safe when run lazily.
-}
main :: IO ()
main =
do runReadTest "bla\n"
(do a <- getLinePair
return (fst a))
(\str -> assert (str == "bla"))
runReadTest "bla\nblub\n"
(do a <- getLinePair
return (snd a))
(\str -> assert (str == "blub"))
runReadTest "1\n"
(do a <- getLinePairOfPairs
return (fst $ fst a))
(\str -> assert (str == "1"))
runReadTest "1\n2\n"
(do a <- getLinePairOfPairs
return (snd $ fst a))
(\str -> assert (str == "2"))
runReadTest "1\n2\n3\n"
(do a <- getLinePairOfPairs
return (fst $ snd a))
(\str -> assert (str == "3"))
runReadTest "1\n2\n3\n4\n"
(do a <- getLinePairOfPairs
return (snd $ snd a))
(\str -> assert (str == "4"))
runReadTest "1\n2\n3\n4\n"
getLinePairOfPairs
(\r -> assert (snd (snd r) == "4" && fst (fst r) == "1"))
runReadTest "1\n2\n3\n4\n"
getLinePairOfPairs
(\r ->
do assert (snd (snd r) == "4")
assert (snd (fst r) == "2")
assert (fst (fst r) == "1")
assert (fst (snd r) == "3"))
runReadTest "0\n1\n2\n3\n"
(forever getLine)
(\r ->
do assert (r!!2 == "2")
assert (r!!1 == "1")
assert (r!!3 == "3")
assert (r!!0 == "0"))
runReadWriteTest "0\n1\n2\n3\n"
(concat $ replicate 4 "bla\n")
(forever (putLine "bla" >> getLine))
(\r ->
do assert (r!!3 == "3"))
runReadWriteTest "0\n1\n2\n3\n"
"a\nb\nc\nd\n"
(mapM (\c -> putLine [c] >> getLine) ['a'..])
(\r ->
do assert (r!!3 == "3"))
runReadWriteTest "end\n"
"A\nB\nC\nD\n"
(mapM (\c -> putLine [c]) ['A'..'D'] >> getLine)
(\str -> assert (str == "end"))