I'd like to pass an integer as a CLI argument to a Haskell program that makes use of QuickCheck / monadicIO
. That integer is going to be used inside the assert
to make the tests customizable.
The problem is that once I parse the integer value in main
, I don't know how to pass it inside of the monadicIO
call without using something as ugly as an IORef
. I would think that an elegant solution might be the Reader
monad, but I couldn't find a solution to make it work, seen as quickCheck
is rigid in its arguments.
Any ideas?
Later Edit 1: As requested, I'm attaching the actual code I'm trying this on, and failing. The commented-out lines represent my failed attempt. Background: the test suite is intended to exercise a very simple remote endpoint that computes the SHA512 of the randomized input generated by QuickCheck. The remote endpoint is Python/Flask based.
Later Edit 2 in response to @user2407038: I could make propHasExpectedLengthCeiling
take an additional argument of type Int, but quickCheck
would generate random values for it, and that's not what I want happening. My goal is to use the maxSegmentLengthCeiling
that I'm taking in from the command-line arguments and use it in let testPassed = actualMaxSegmentLength <= maxSegmentLengthCeiling
inside of the monadicIO
block. Right now maxSegmentLengthCeiling
is specified as a top-level value, which means I have to recompile the code every time I change the value. I don't yet have any code that involves IORef
because that's a last resort and the essence of my question is how to avoid going the IORef
route.
import qualified Data.ByteString.Lazy.Char8 as LC
import Control.Applicative ( (<$>) )
import Data.Function ( on )
import Data.List ( groupBy )
import Data.Char ( isDigit )
--import Safe ( headMay
-- , readMay
-- )
--import System.Environment ( getArgs )
import Network.HTTP.Conduit ( simpleHttp )
import Test.QuickCheck ( Arbitrary
, Property
, arbitrary
, choose
, frequency
, quickCheckWith
, stdArgs
, vectorOf
)
import Test.QuickCheck.Test ( Args
, maxSuccess
)
import Test.QuickCheck.Monadic ( assert
, monadicIO
, run
)
newtype CustomInput = MkCustomInput String deriving Show
instance Arbitrary CustomInput where
arbitrary =
let
genCustomInput = vectorOf 20
$ frequency [ (26, choose ('0','9'))
, (10, choose ('a','z'))
]
in
MkCustomInput <$> genCustomInput
maxSegmentLengthCeiling :: Int
maxSegmentLengthCeiling = 22
urlPrefix :: String
urlPrefix = "http://192.168.2.3:5000/sha512sum/"
propHasExpectedLengthCeiling :: CustomInput -> Property
propHasExpectedLengthCeiling (MkCustomInput input) = monadicIO $ do
testPassed <- run $ do
response <- simpleHttp $ urlPrefix ++ input
let stringResponse = LC.unpack response
let brokenDownStringResponse = groupBy ( (==) `on` isDigit ) stringResponse
let actualMaxSegmentLength = maximum $ map length brokenDownStringResponse
let testPassed = actualMaxSegmentLength <= maxSegmentLengthCeiling
putStrLn ""
putStrLn ""
putStrLn $ "Input: " ++ input
putStrLn $ "Control sum: " ++ stringResponse
putStrLn $ "Breakdown: " ++ show brokenDownStringResponse
putStrLn $ "Max. length: " ++ show actualMaxSegmentLength
putStrLn $ "Ceiling: " ++ show maxSegmentLengthCeiling
putStrLn $ "Test result: " ++ if testPassed then "Pass" else "Fail"
putStrLn ""
putStrLn ""
return testPassed
assert $ testPassed
customArgs :: Args
customArgs = stdArgs { maxSuccess = 1000000 }
--readMayAsInt :: String -> Maybe Int
--readMayAsInt = readMay
main :: IO ()
main =
--main = do
-- cliArgs <- getArgs
-- let ceilingInputMay = headMay cliArgs >>= readMayAsInt
-- maxSegmentLengthCeiling <- case ceilingInputMay of
-- (Just lengthCeiling) -> return lengthCeiling
-- Nothing -> error "No valid number given"
quickCheckWith
customArgs
propHasExpectedLengthCeiling
cliArgs
or any other input? Could you makepropHasExpectedLengthCeiling
take an additional argument (` :: Int -> CustomInput -> Property)? I don't know how
IORef` factors into this at all. Could you clarify that, or include the code that usesIORef
, or code that doesn't compile, but looks something like what you would want to have? – user2407038Int
a parameter topropHasExpectedLengthCeiling
and invoke it asmain = do [n] <- getArgs; quickCheckWith customArgs (propHasExpectedLengthCeiling (read n))
. What am I missing here? – user2407038