Skip to content

Instantly share code, notes, and snippets.

@piq9117
Forked from ijt/io_quickcheck_example.hs
Created March 28, 2021 04:04
Show Gist options
  • Save piq9117/68b96887f75b3dc6e3cce5d3a83b289a to your computer and use it in GitHub Desktop.
Save piq9117/68b96887f75b3dc6e3cce5d3a83b289a to your computer and use it in GitHub Desktop.
Simple example of monadic IO with QuickCheck in Haskell
#!/usr/bin/env runhaskell
-- Synopsis:
-- $ cabal install QuickCheck
-- $ runhaskell io_quickcheck_example.hs
--
-- Author: Issac Trotts <issac.trotts@gmail.com>
import Directory
import System.Environment
import System.Process
import System.Exit
import Test.QuickCheck (Property, quickCheck, (==>))
import Test.QuickCheck.Monadic (assert, monadicIO, run)
main = do
putStrLn "addThenClearMakesClear"
quickCheck addThenClearMakesClear
putStrLn "addNewIsIdempotent"
quickCheck addNewIsIdempotent
-- Add some strings to /tmp/foo
add :: [String] -> IO ()
add strings = do
-- Have to write then rename to work around lazy IO.
oldStrings <- get
writeFile "/tmp/foo2" $ unlines $ oldStrings ++ strings
renameFile "/tmp/foo2" "/tmp/foo"
-- Add some strings to /tmp/foo that were not already there
addNew :: [String] -> IO ()
addNew strings = do
oldStrings <- get
add [s | s <- strings, s `notElem` oldStrings && s /= ""]
-- Get all the strings in /tmp/foo
get :: IO [String]
get = readProcessOrDie "cat" ["/tmp/foo"] "" >>= return . lines
-- Clear /tmp/foo
clear :: IO ()
clear = writeFile "/tmp/foo" ""
readProcessOrDie :: String -> [String] -> String -> IO String
readProcessOrDie cmd args input = do
(code, stdout, _) <- readProcessWithExitCode cmd args input
case code of
ExitFailure i -> error $ ("Command failed with status " ++ show i ++
": " ++ cmd ++ show args)
ExitSuccess -> return stdout
addThenClearMakesClear :: [String] -> Property
addThenClearMakesClear strings = monadicIO $ do
run $ add strings
run $ clear
contents <- run $ get
assert $ contents == []
addNewIsIdempotent :: [String] -> Property
addNewIsIdempotent strings = (and $ map ('\n' `notElem`) strings) ==> monadicIO $ do
run $ clear
run $ addNew strings
contents1 <- run $ get
run $ addNew strings
contents2 <- run $ get
assert $ contents1 == contents2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment