From 7483bbf576c44d83801cedf460e43bdd37441f31 Mon Sep 17 00:00:00 2001
From: koen <koenwermer@gmail.com>
Date: Tue, 17 Jan 2017 22:37:33 +0100
Subject: [PATCH] the main function now performs a mutation test (mutants have
 to be generated beforehand)

---
 Main.hs       | 62 ++++++++++++++++++++++++++++++++++++---------------
 Substitute.hs |  8 +++----
 WLP.hs        |  2 +-
 3 files changed, 49 insertions(+), 23 deletions(-)

diff --git a/Main.hs b/Main.hs
index 5f45bdd..3e9f6be 100644
--- a/Main.hs
+++ b/Main.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE TupleSections #-}
+
 module Main where
 
 import Language.Java.Syntax
@@ -6,7 +8,7 @@ import Language.Java.Pretty
 import Data.List
 import Control.Monad
 import System.FilePath(joinPath)
-
+import System.Directory
 
 import WLP
 import Types
@@ -14,33 +16,57 @@ import Verifier
 import HelperFunctions
 import Settings
 
+sourcePath, mutantsDir :: FilePath
+sourcePath = joinPath ["Tests", testFile ++ ".java"]
+mutantsDir = joinPath ["..", testFile ++ " mutants"]
 
 main :: IO ()
 main = do
-    source <- readFile (joinPath ["Tests", testFile ++ ".java"])
+    -- Get the wlp per method of the original source code
+    (env, wlpOriginal) <- wlpMethods sourcePath
+    
+    -- Get the names of the folders containing the mutants (MAJOR creates a folder for every mutant)
+    mutationFolders <- listDirectory mutantsDir
+    
+    -- Map each folder name to the path containing the mutant (mutant name is the same as the original file name)
+    let mutationPaths = map (\n -> joinPath [mutantsDir, n, testFile ++ ".java"]) mutationFolders
+    
+    -- Calculate the wlp per method of all the mutants
+    wlpMutants <- mapM (\path -> wlpMethods path >>= return . (path, ) . snd) mutationPaths
     
-    let result = parser compilationUnit source
+    mapM_ (compareWlps env wlpOriginal) wlpMutants
     
-    case result of
-        Left error -> print error
+-- | Calculates the wlp for every method in the source file. Also returns the type environment             
+wlpMethods :: FilePath -> IO (TypeEnv, [(Ident, Exp)])
+wlpMethods s = do
+    -- Get the source code
+    source <- readFile s
+    
+    -- Parse the source code
+    case parser compilationUnit source of
+        Left parseError -> error (show parseError)
         Right compUnit -> do
                             let decls = getDecls compUnit
                             let methods = getMethodIds decls
                             let env = getTypeEnv compUnit decls methods
-                         --   putStrLn "\r\n-----Code-----"
-                         --   print compUnit
-                            mapM_ (testMethod compUnit env decls) methods
                             
--- | Calculates and prints the wlp for a given method
-testMethod :: CompilationUnit -> TypeEnv -> [TypeDecl] -> Ident -> IO ()
-testMethod compUnit env decls id = do
-    putStrLn "--------------"
-    putStrLn (prettyPrint id ++ "\r\n")
-    let pred = wlpWithEnv decls env (fromJust' "testMethod" $ getMethod decls id) postCond'
-    putStrLn . prettyPrint $ pred
-    putStrLn ""
-    if unsafeIsTrue env pred then putStrLn "WLP evaluates to true" else (if unsafeIsFalse env pred then putStrLn "WLP evaluates to false" else putStrLn "undecidable")
-    putStrLn "--------------"
+                            -- Calculate the wlp per method
+                            r <- mapM (\ident -> wlpMethod compUnit env decls ident >>= return . (ident, )) methods
+                            
+                            return (env, r)
+                            
+-- | Calculates the wlp for a given method
+wlpMethod :: CompilationUnit -> TypeEnv -> [TypeDecl] -> Ident -> IO Exp
+wlpMethod compUnit env decls ident = do
+    let pred = wlpWithEnv decls env (fromJust' "wlpMethod" $ getMethod decls ident) postCond'
+    return pred
+    
+-- | Compares the wlp per method of a program S and mutation S' by verifying that (wlp (S, m) q => wlp (S', m) q) holds for every method m
+compareWlps :: TypeEnv -> [(Ident, Exp)] -> (String, [(Ident, Exp)]) -> IO ()
+compareWlps env s (path, s') = mapM_ compareMethod s where
+    compareMethod (ident, e) = case lookup ident s' of
+                                Nothing -> putStrLn ("The method \'" ++ show ident ++ "\' is missing in one of the mutations.")
+                                Just e' -> if unsafeIsTrue env (e `imp` e') then return () else putStrLn ("error detected in mutation: " ++ path)
 
 -- The post-condition (for testing)
 postCond' :: Exp
diff --git a/Substitute.hs b/Substitute.hs
index b8a4daa..337f9cc 100644
--- a/Substitute.hs
+++ b/Substitute.hs
@@ -28,9 +28,9 @@ substVarExpAlgebra = (fLit, fClassLit, fThis, fThisClass, fInstanceCreation, fQu
     fArrayCreateInit t dim arrayInit _ = ArrayCreateInit t dim arrayInit
     fFieldAccess fieldAccess inh                 = case lhs inh of
                                                         FieldLhs fieldAccess' -> case fieldAccess of
-                                                                                PrimaryFieldAccess e ident -> error "todo: fieldAccess substitution"
-                                                                                SuperFieldAccess ident -> error "todo: fieldAccess substitution"
-                                                                                ClassFieldAccess name ident -> error "todo: fieldAccess substitution"
+                                                                                PrimaryFieldAccess e ident -> error "fieldAccess substitution"
+                                                                                SuperFieldAccess ident -> error "fieldAccess substitution"
+                                                                                ClassFieldAccess name ident -> error "fieldAccess substitution"
                                                         _ -> FieldAccess fieldAccess
     fMethodInv invocation inh           = case invocation of 
                                             MethodCall name exps -> MethodInv (MethodCall name (map (flip (foldExp substVarExpAlgebra) (inh {arrayLookup = True})) exps))
@@ -87,7 +87,7 @@ substVarExpAlgebra = (fLit, fClassLit, fThis, fThisClass, fInstanceCreation, fQu
     fCast t e inh = Cast t (e inh)
     fBinOp e1 op e2 inh = BinOp (e1 inh) op (e2 inh)
     fInstanceOf e refType inh = InstanceOf (e inh) refType
-    fCond g e1 e2 inh = Cond (g inh) (e1 inh) (e2 inh)
+    fCond g e1 e2 inh = Cond (g inh {arrayLookup = False}) (e1 inh) (e2 inh)
     fAssign lhs assOp e inh = Assign lhs assOp (e inh)
     fLambda lParams lExp _ = Lambda lParams lExp
     fMethodRef className methodName _ = MethodRef className methodName
diff --git a/WLP.hs b/WLP.hs
index c84dd05..c9a796f 100644
--- a/WLP.hs
+++ b/WLP.hs
@@ -206,7 +206,7 @@ wlpExpAlgebra = (fLit, fClassLit, fThis, fThisClass, fInstanceCreation, fQualIns
     -- gets the transformer for array access (as array access may throw an error)
     arrayAccessWlp :: Exp -> [Exp] -> Inh -> Exp -> Exp
     arrayAccessWlp a i inh q =  case catch inh of
-                                    Nothing      -> Cond (foldr (\(i, l) e -> e &* (BinOp i LThan l) &* (BinOp i GThanE (Lit (Int 0)))) true (zip i (dimLengths a))) q false
+                                    Nothing      -> (foldr (\(i, l) e -> e &* (BinOp i LThan l) &* (BinOp i GThanE (Lit (Int 0)))) true (zip i (dimLengths a))) &* q
                                     Just (cs, f) -> let e = InstanceCreation [] (ClassType [(Ident "ArrayIndexOutOfBoundsException", [])]) [] Nothing
                                                     in Cond (foldr (\(i, l) e -> e &* (BinOp i LThan l) &* (BinOp i GThanE (Lit (Int 0)))) true (zip i (dimLengths a))) q ((maybe (if f then q else q &* throwException e)) (\b -> wlp' (inh {acc = id, catch = Nothing}) (StmtBlock b) q) (getCatch (decls inh) (env inh) e cs))
                                 
-- 
GitLab