Reputation: 10584
I'm writing a chat server in Haskell. My executable has the following code:
data Client = Client {idx :: Int, hClient :: Handle} deriving (Show, Eq)
tellClient :: String -> Client -> IO ()
tellClient = flip $ hPutStrLn . hClient
askClient :: Client -> IO (String)
askClient = hGetLine . hClient
which I expect to be able to use to write and read from a file. I'm writing tests against this code with HSpec. I have the following function to build temporary Client
objects (which relies on the "temporary") library:
withTempClient :: Int -> (Client -> IO a) -> IO a
withTempClient cIdx f = withTempFile "tests/generated" "clientFile.tmp" axn
where axn _ handle = f $ Client cIdx handle
I'm using this to test the code above as follows:
main = hspec $ do
describe "client IO" $ do
it "can ask and tell" $ withTempClient 1 $ \c -> do
tellClient "hello" c
hFlush $ hClient c
askClient c `shouldReturn` "hello"
But the test fails with the following error:
uncaught exception: IOException of type EOF (test/generated
/clientFile11587.tmp: hGetLine: end of file)
I thought that maybe I was doing something wrong in withTempClient
, so I added the following test case:
it "opens a handle corectly" $ withTempClient 1 $ \(Client _ h) -> do
hIsOpen h `shouldReturn` True
hIsWritable h `shouldReturn` True
but that passed, so I'm not sure what the issue could be. What am I missing?
Upvotes: 3
Views: 155
Reputation: 12103
When you write to a file, the OS keeps track of the position at which you are in said file. You get an EOF
error because you're at the end of the file (it was empty to begin with and everything you have written is before the current position).
To fix that you need to use hSeek
to reposition yourself at the beginning of the file like so:
hSeek (hClient c) AbsoluteSeek 0
For more details about seeking, cf. this bit of real world haskell.
Upvotes: 4