Usando il lettore MONAD con QuickCheck / Monadicio
-
21-12-2019 - |
Domanda
Mi piacerebbe passare un numero intero come argomento CLI a un programma Haskell che fa uso di QuickCheck / monadicIO
. Quel numero intero verrà utilizzato all'interno del assert
per rendere i test personalizzabili.
Il problema è che una volta analizzato il valore intero in main
, non so come passarlo all'interno della chiamata monadicIO
senza usare qualcosa come brutto come IORef
. Penserei che una soluzione elegante potrebbe essere la monada Reader
, ma non riesco a trovare una soluzione per farlo funzionare, visto come quickCheck
è rigido nei suoi argomenti.
Qualche idea?
Modifica successiva 1: Come richiesto, sto collegando il codice attuale che sto provando questo, e fallendo. Le linee commentate rappresentano il mio tentativo fallito. Sfondo: la suite di prova ha lo scopo di esercitare un endpoint remoto molto semplice che calcola lo SHA512 dell'ingresso randomizzato generato da QuickCheck. L'endpoint remoto è basato su Python / Boccette.
in seguito Modifica 2 In risposta a @ user2407038: Potrei rendere propHasExpectedLengthCeiling
a prendere un argomento aggiuntivo di tipo int, ma quickCheck
genererebbe valori casuali per questo, e non è quello che voglio accadendo. Il mio obiettivo è usare il maxSegmentLengthCeiling
che sto intraprendendo dagli argomenti della riga di comando e lo usano in let testPassed = actualMaxSegmentLength <= maxSegmentLengthCeiling
all'interno del blocco monadicIO
. In questo momento maxSegmentLengthCeiling
è specificato come valore di alto livello, il che significa che devo ricompilare il codice ogni volta che modifico il valore. Non ho ancora alcun codice che coinvolga IORef
perché è un'ultima risorsa e l'essenza della mia domanda è come evitare di andare alla rotta IORef
.
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
. Soluzione
Rendere maxSegmentLengthCeiling
un parametro su propHasExpectedLengthCeiling
:
propHasExpectedLengthCeiling :: Int -> CustomInput -> Property
.
e invocalo come
main = do
[n] <- getArgs
quickCheckWith customArgs (propHasExpectedLengthCeiling (read n))
.