Reputation: 255
My impure functions are defined as follows:
module HangmanImpure (HangmanImpure.getLine, HangmanImpure.putStr, HangmanImpure.putStrLn, HangmanImpure.strlen) where
import qualified System.IO as Sys
getLine :: IO String
getLine = do x <- Sys.getChar
if x == '\n' then
return []
else
do xs <- HangmanImpure.getLine
return (x:xs)
putStr :: String -> IO ()
putStr [] = return ()
putStr (x:xs) = do Sys.putChar x
HangmanImpure.putStr xs
I want to test these functions using Tasty, like e.g. so:
module TestHangmanImpure (scProps) where
import qualified Test.Tasty as T
import qualified Test.Tasty.SmallCheck as SC
import qualified HangmanImpure as HI (getLine, putStr, putStrLn, strlen)
scProps :: T.TestTree
scProps = T.testGroup "checked by SmallCheck"
[
SC.testProperty "getLine should return what is written to stdin" $
"Placeholder to get the test to run" == "Placeholder to get the test to run" -- HI.getLine == IO "Hello" -- PLEASE, HELP ME WITH SOME CONTENT HERE
, SC.testProperty "putStr should write to stdout what it gets in as an argument" $
"Placeholder to get the test to run" == "Placeholder to get the test to run" -- HI.putStr "Nice day!" -- PLEASE, HELP ME WITH SOME CONTENT HERE
]
I would be very thankful if anybody could fill in the body in the two simple tests I have indicated.
EDIT:
I think [In haskell, how can I interact with stdin of an IO ()
?][1] could lead me to a solution. I can get that solution to work on my Win10 with HSpec. So this question is almost a duplicate. But I cannot get it to work using Tasty.HUnit. My tentative code runs as follows:
module TestUtilImpure (scProps, qcProps, uTests, properties) where
import qualified Test.Tasty as T
import qualified Test.Tasty.HUnit as HU
import StdInStdOutUtil as IOU (captureStdout, provideStdin)
import UtilImpure as UI (getLine)
properties :: T.TestTree
properties = T.testGroup "TestUtilImpure tests" [
uTests
]
uTests :: T.TestTree
uTests = T.testGroup "Checked by HUnit"
[
HU.testCase "UI.getLine reading from stdin should return what was provided" $ do
let line = "Hello, echo!\n"
let capturedIOString = IOU.captureStdout (provideStdin line echo)
capturedString <- capturedIOString
HU.assertBool "The String returned from UI.getLine differs from the one provided for StdIn" $ capturedString == line
]
echo :: IO ()
echo = UI.getLine >>= Prelude.putStrLn
(I have put the solution from [1]: In haskell, how can I interact with stdin of an `IO ()`? into its own file referred by
import StdInStdOutUtil as IOU (captureStdout, provideStdin)
My test fails:
The String returned from UI.getLine differs from the one provided for StdIn
I get the same error message whether I test Prelude.getLine or my own UI.getLine. So I guess that there's some syntax I have not understood using Tasty that fails.
Upvotes: 1
Views: 148
Reputation: 706
I am using Test.Tasty.HIOUnit to test IO functions.
At the moment, HIOUnit is only available as source code at https://github.com/JoergBrueggmann/tasty-hiounit.
A test spec with HIOUnit looks like this:
import qualified Test.Tasty as T
import qualified Test.Tasty.HIOUnit as HIOU
testGroup :: T.TestTree
testGroup =
T.testGroup
"module Test.Tasty.HIOUnit"
[
tgFib
]
tgFib :: T.TestTree
tgFib =
T.testGroup
"Fib.ioFib"
[
-- edge cases using values arround zero
HIOU.testCase "Fib.ioFib -2" (HIOU.IOTestParameter ( Just "-2" ) fdefFib ( Just "-1" ) ( Just "" ) ( Just 0 )),
HIOU.testCase "Fib.ioFib -1" (HIOU.IOTestParameter ( Just "-1" ) fdefFib ( Just "1" ) ( Just "" ) ( Just 0 )),
HIOU.testCase "Fib.ioFib 0" (HIOU.IOTestParameter ( Just "0" ) fdefFib ( Just "0" ) ( Just "" ) ( Just 0 )),
HIOU.testCase "Fib.ioFib 1" (HIOU.IOTestParameter ( Just "1" ) fdefFib ( Just "1" ) ( Just "" ) ( Just 0 )),
HIOU.testCase "Fib.ioFib 2" (HIOU.IOTestParameter ( Just "2" ) fdefFib ( Just "1" ) ( Just "" ) ( Just 0 )),
HIOU.testCase "Fib.ioFib 3" (HIOU.IOTestParameter ( Just "3" ) fdefFib ( Just "2" ) ( Just "" ) ( Just 0 ))
]
fdefFib :: HIOU.IOFunctionDefinition
fdefFib =
HIOU.IOFunctionDefinition
"Fib"
(Just "ioFib")
[HIOU.sMultiLine|
import qualified System.IO as Sys
ioFib :: IO ()
ioFib =
do
Sys.hSetBuffering Sys.stdout Sys.NoBuffering
sNumber <- getLine
let
niNumber = (read sNumber) :: Integer
putStr (show (fib niNumber))
fib :: (Integral n) => n -> n
fib n
| n >= 0 = fib' n (0,1)
| even n = 0 - fib (-n)
| otherwise = fib (-n)
where
fib' n' (a, b)
| n'==0 = a
| otherwise = fib' (n'-1) (b, a+b)
|]
Upvotes: 1