I have written a program for a project that uses Pipes, which I love! I'm struggling to unit test my code however.
I have a series of functions of type Pipe In Out IO ()
(for example) that I wish to test with HSpec. How can I go about this?
For example, suppose I have this domain:
data Person = Person String Int | Unknown deriving (Show, Eq)
data Classification = Friend | Foe | Undecided deriving Show
and this Pipe:
classify :: Pipe Person (Person, Classification) IO ()
classify = do
p@(Person name _) <- await
case name of
"Alex" -> yield (p, Friend)
"Bob" -> yield (p, Foe)
_ -> yield (p, Undecided)
I would like to write a spec:
main = hspec $ do
describe "readFileP" $
it "yields all the lines of a file"
pendingWith "How can I test this Pipe? :("
The trick is to use toListM
from Pipes ListT
monad transformer.
import Pipes
import qualified Pipes.Prelude as P
import Test.Hspec
data Person = Person String Int | Unknown deriving (Show, Eq)
data Classification = Friend | Foe | Undecided deriving (Show, Eq)
classify :: Pipe Person (Person, Classification) IO ()
classify = do
p@(Person name _) <- await
case name of
"Alex" -> yield (p, Friend)
"Bob" -> yield (p, Foe)
_ -> yield (p, Undecided)
The test, using the ListT transformer to convert the pipe to a ListT and asserting using HSpec:
main = hspec $ do
describe "classify" $ do
it "correctly finds friends" $ do
[(p, cl)] <- P.toListM $ each [Person "Alex" 31] >-> classify
p `shouldBe` (Person "Alex" 31)
cl `shouldBe` Friend
Note, you don't have to use each
, this could be a simple producer with a call to yield
.