From a0860371b4bff5082b698793689a01400c3b3c54 Mon Sep 17 00:00:00 2001 From: Joris ten Tusscher <joristt@gmail.com> Date: Tue, 16 Jan 2018 01:00:52 +0100 Subject: [PATCH] Slight overall improvements to the QuickCheck module: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fixed bug that caused some QuickCheck tests to throw an exception because not a complete substitution was taking place. - Uncommented the legendary 16th bug that causes an endless loop when Z3 is used. It doesn’t cause an endless loop with QuickCheck, but QuickCheck does give the wrong answer :’(. All in all, the very naive testing module correctly tests 13/16 tests at the moment (most of the time at least; it’s random). --- src/LogicIR/Backend/QuickCheck.hs | 27 ++++++++++++++++++++------- src/SimpleFormulaChecker.hs | 10 ++++++---- test/TIRQuickCheck.hs | 4 ++-- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/LogicIR/Backend/QuickCheck.hs b/src/LogicIR/Backend/QuickCheck.hs index 67f0b7f..ffe475b 100644 --- a/src/LogicIR/Backend/QuickCheck.hs +++ b/src/LogicIR/Backend/QuickCheck.hs @@ -48,8 +48,13 @@ checkRepeatedly n e1 e2 = do check :: LExpr -> LExpr -> IO (Bool, Model) check e1 e2 = do (result1, model) <- checkLExpr e1 - let result2 = eval $ applyModel model $ replaceQuantifiers e2 - return (result1 == result2, model) + let primFreeE = applyModel model $ replaceQuantifiers e2 + let finalE = repeatedApplyModel (primFreeE, model) + if evalPossible finalE then do + let result2 = eval finalE + return (result1 == result2, model) + else + return (False, model) -- Given an LExpr, generates a substitution model for all variables in it, -- and returns whether the formula evaluates to true or to false when that model @@ -59,7 +64,7 @@ checkLExpr :: LExpr -> IO (LConst, Model) checkLExpr e = do primitivesModel <- generateModel $ primitives let primFreeE = applyModel primitivesModel quantFreeE - (finalE, arrayModel) <- repeatedApplyModel (primFreeE, empty) + (finalE, arrayModel) <- repeatedApplyAndExpandModel (primFreeE, empty) let model = arrayModel ++ primitivesModel let result = eval finalE return $ (result, model) @@ -71,14 +76,15 @@ checkLExpr e = do -- applies substitution of arrays until a "pure" LExpr is the result, or no -- more substitutions can be applied. If the latter is the case, an error --- will be thrown. -repeatedApplyModel :: (LExpr, Model) -> IO (LExpr, Model) -repeatedApplyModel (e, m) = do +-- will be thrown. ***NOTE***: this function actually expands the model if +-- necessary. If you don't want this, use repeatedApplyModel +repeatedApplyAndExpandModel :: (LExpr, Model) -> IO (LExpr, Model) +repeatedApplyAndExpandModel (e, m) = do if length arrays > 0 then if length substitutableArrays > 0 then do model <- generateModel substitutableArrays let newE = applyModel model e - repeatedApplyModel (newE, m ++ model) + repeatedApplyAndExpandModel (newE, m ++ model) else error $ "There are unsubstitutable array accesses: " ++ (show arrays) else @@ -89,6 +95,13 @@ repeatedApplyModel (e, m) = do -- i doesn't contain variables. sSubstitutable (LArray var e) = evalPossible e +repeatedApplyModel :: (LExpr, Model) -> LExpr +repeatedApplyModel (e, m) = if newE /= e then + repeatedApplyModel (newE, m) + else + e + where newE = applyModel m e + -- Applies substitution given a Model and an LExpr. applyModel :: Model -> LExpr -> LExpr applyModel model = foldLExpr algebra diff --git a/src/SimpleFormulaChecker.hs b/src/SimpleFormulaChecker.hs index ec442ec..bc2cbfd 100644 --- a/src/SimpleFormulaChecker.hs +++ b/src/SimpleFormulaChecker.hs @@ -235,13 +235,15 @@ methodDefToLExpr m1@(decls1, _, env1) m2@(decls2, _, env2) name = do (lExpr1, lExpr2) where extractCond m n = extractExpr $ getMethodCalls m n -testSpec :: (FilePath, String) -> (FilePath, String) -> IO Bool -testSpec method1@(_, name1) method2@(_, name2) = do +testSpec :: (FilePath, String) -> (FilePath, String) -> Int -> IO Bool +testSpec method1@(_, name1) method2@(_, name2) n = do (m1, m2) <- parse method1 method2 putStrLn $ "----PRE---- (" ++ name1 ++ " vs " ++ name2 ++ ")" let (lExpr1, lExpr2) = methodDefToLExpr m1 m2 "pre" - preAns <- testEquality 10000 lExpr1 lExpr2 + preAns <- testEquality n lExpr1 lExpr2 putStrLn "\n----POST---" let (lExpr1, lExpr2) = methodDefToLExpr m1 m2 "post" - postAns <- testEquality 10000 lExpr1 lExpr2 + postAns <- testEquality n lExpr1 lExpr2 return $ preAns && postAns + +res = testSpec ("examples/javawlp_edsl/src/nl/uu/javawlp_edsl/Main.java", "swap_spec1") ("examples/javawlp_edsl/src/nl/uu/javawlp_edsl/Main.java", "swap_spec2") diff --git a/test/TIRQuickCheck.hs b/test/TIRQuickCheck.hs index 7c34c90..5336c43 100644 --- a/test/TIRQuickCheck.hs +++ b/test/TIRQuickCheck.hs @@ -10,7 +10,7 @@ edslSrc = "examples/javawlp_edsl/src/nl/uu/javawlp_edsl/Main.java" testEquiv :: Bool -> String -> String -> Assertion testEquiv b s s' = - unsafePerformIO (silence $ testSpec (edslSrc, s) (edslSrc, s')) @?= b + unsafePerformIO (silence $ testSpec (edslSrc, s) (edslSrc, s') 100000) @?= b (.==) = testEquiv True (.!=) = testEquiv False @@ -30,5 +30,5 @@ quickCheckTests = , "sorted1".!= "sorted3" , "test2" .!= "sorted3" , "sorted3" .!= "sorted4" - -- , equivalent "sorted1" "sorted4" -- does not terminate (TODO: should time out, but this does not work) + , "sorted1" .== "sorted4" ] -- GitLab