Utilisation de la monade Reader avec QuickCheck / monadicIO
-
21-12-2019 - |
Question
J'aimerais transmettre un entier comme argument CLI à un programme Haskell qui utilise QuickCheck / monadicIO
.Cet entier va être utilisé à l'intérieur du assert
pour rendre les tests personnalisables.Le problème est qu'une fois que j'analyse la valeur entière dans main
, je ne sais pas comment le passer à l'intérieur du monadicIO
appeler sans utiliser quelque chose d'aussi laid qu'un IORef
.Je pense qu'une solution élégante pourrait être la Reader
monade, mais je n'ai pas trouvé de solution pour que ça marche, vu comme quickCheck
est rigide dans ses arguments.Des idées?
Modification ultérieure 1 : Comme demandé, je joins le code sur lequel j'essaie cela et j'échoue.Les lignes commentées représentent ma tentative ratée.Arrière-plan:la suite de tests est destinée à exercer un point de terminaison distant très simple qui calcule le SHA512 de l'entrée aléatoire générée par QuickCheck.Le point de terminaison distant est basé sur Python/Flask.
Plus tard, modifiez 2 en réponse à @ user2407038 : je pourrais faire propHasExpectedLengthCeiling
prendre un argument supplémentaire de type Int, mais quickCheck
générerait des valeurs aléatoires pour cela, et ce n'est pas ce que je veux qu'il se produise.Mon objectif est d'utiliser le maxSegmentLengthCeiling
que je récupère des arguments de ligne de commande et que je l'utilise dans let testPassed = actualMaxSegmentLength <= maxSegmentLengthCeiling
à l'intérieur du monadicIO
bloc.Tout de suite maxSegmentLengthCeiling
est spécifié comme valeur de niveau supérieur, ce qui signifie que je dois recompiler le code chaque fois que je modifie la valeur.Je n'ai pas encore de code impliquant IORef
parce que c'est un dernier recours et l'essentiel de ma question est de savoir comment éviter d'aller dans ce sens. IORef
itinéraire.
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
La solution
Faire maxSegmentLengthCeiling
un paramètre à propHasExpectedLengthCeiling
:
propHasExpectedLengthCeiling :: Int -> CustomInput -> Property
et l'invoquer comme
main = do
[n] <- getArgs
quickCheckWith customArgs (propHasExpectedLengthCeiling (read n))