Verwendung der Reader-Monade mit QuickCheck / monadicIO
-
21-12-2019 - |
Frage
Ich möchte eine Ganzzahl als CLI-Argument an ein Haskell-Programm übergeben, das QuickCheck / verwendet. monadicIO
.Diese Ganzzahl wird innerhalb von verwendet assert
um die Tests anpassbar zu machen.Das Problem ist, dass ich den ganzzahligen Wert einmal analysiere main
, ich weiß nicht, wie ich es hineingeben soll monadicIO
Rufen Sie an, ohne etwas so Hässliches wie ein zu verwenden IORef
.Ich würde denken, dass eine elegante Lösung das sein könnte Reader
monad, aber ich konnte keine Lösung finden, damit es funktioniert, gesehen als quickCheck
ist in seinen Argumenten starr.Irgendwelche Ideen?
Spätere Bearbeitung 1: Wie gewünscht füge ich den eigentlichen Code bei, mit dem ich das versuche, aber es schlägt fehl.Die auskommentierten Zeilen stellen meinen gescheiterten Versuch dar.Hintergrund:Die Testsuite soll einen sehr einfachen Remote-Endpunkt testen, der den SHA512 der von QuickCheck generierten zufälligen Eingabe berechnet.Der Remote-Endpunkt basiert auf Python/Flask.
Später Edit 2 als Antwort an @user2407038: ich kann ... machen propHasExpectedLengthCeiling
Nehmen Sie ein zusätzliches Argument vom Typ Int, aber quickCheck
würde dafür zufällige Werte generieren, und das ist nicht das, was ich möchte.Mein Ziel ist es, das zu nutzen maxSegmentLengthCeiling
dass ich die Befehlszeilenargumente übernehme und darin verwende let testPassed = actualMaxSegmentLength <= maxSegmentLengthCeiling
innerhalb der monadicIO
Block.Im Augenblick maxSegmentLengthCeiling
wird als Wert der obersten Ebene angegeben, was bedeutet, dass ich den Code jedes Mal neu kompilieren muss, wenn ich den Wert ändere.Ich habe noch keinen entsprechenden Code IORef
denn das ist der letzte Ausweg und der Kern meiner Frage ist, wie ich das vermeiden kann 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
Lösung
Machen maxSegmentLengthCeiling
ein Parameter für propHasExpectedLengthCeiling
:
propHasExpectedLengthCeiling :: Int -> CustomInput -> Property
und rufe es auf als
main = do
[n] <- getArgs
quickCheckWith customArgs (propHasExpectedLengthCeiling (read n))