-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Automated Mutation Testing -- -- This package defines a mutation analysis library for haskell programs. -- It does this by parsing the haskell source, and replacing a few of the -- common haskell functions and operators with other, but similar -- operators and functions, and running the testsuite to check whether -- the difference has been detected. @package MuCheck @version 0.3.0.0 -- | Common print utilities module Test.MuCheck.Utils.Print -- | simple wrapper for adding a % at the end. (./.) :: (Show a, Integral a) => a -> a -> String -- | join lines together showAS :: [String] -> String -- | make lists into lines in text. showA :: Show a => [a] -> String -- | convenience function for debug tt :: Show a => a -> a -- | Capture output and err of an IO action catchOutputStr :: IO a -> IO (a, String) -- | Capture output and err of an IO action to a file catchOutput :: String -> IO a -> IO a -- | Redirect out and err to handle redirectToHandle :: IO b -> Handle -> IO b -- | Mutation operators module Test.MuCheck.MuOp -- | MuOp constructor used to specify mutation transformation data MuOp -- | Mutation operation representing translation from one fn to another fn. class Mutable a (==>) :: Mutable a => a -> a -> MuOp -- | The function ==>* pairs up the given element with all -- elements of the second list, and applies ==> on them. (==>*) :: Mutable a => a -> [a] -> [MuOp] -- | The function *==>* pairs up all elements of first list with -- all elements of second list and applies ==> between them. (*==>*) :: Mutable a => [a] -> [a] -> [MuOp] -- | The function ~~> accepts two values, and returns a function -- that if given a value equal to first, returns second we handle x -- ~~> x separately (~~>) :: (MonadPlus m, Eq a) => a -> a -> a -> m a -- | A wrapper over mkMp mkMpMuOp :: (MonadPlus m, Typeable a) => MuOp -> a -> m a -- | The function same applies on a MuOP determining if -- transformation is between same values. same :: MuOp -> Bool instance Eq MuOp instance Mutable GuardedRhs instance Mutable Literal instance Mutable Decl instance Mutable Exp instance Mutable QOp instance Mutable QName instance Mutable Name instance Show MuOp -- | SYB functions module Test.MuCheck.Utils.Syb -- | The function relevantOps does two filters. For the first, it -- removes spurious transformations like "Int 1 ~~> Int 1". Secondly, -- it tries to apply the transformation to the given program on some -- element if it does not succeed, then we discard that transformation. relevantOps :: (Data a, Eq a) => a -> [MuOp] -> [MuOp] -- | apply a mutating function on a piece of code one at a time like -- somewhere (from so) once :: MonadPlus m => GenericM m -> GenericM m module Test.MuCheck.AnalysisSummary -- | Datatype to hold results of the entire run data MAnalysisSummary MAnalysisSummary :: Int -> Int -> Int -> Int -> MAnalysisSummary maNumMutants :: MAnalysisSummary -> Int maAlive :: MAnalysisSummary -> Int maKilled :: MAnalysisSummary -> Int maErrors :: MAnalysisSummary -> Int instance Show MAnalysisSummary -- | Module for adapting test framekworks module Test.MuCheck.TestAdapter -- | Wrapper for interpreter output data Summarizable a => InterpreterOutput a Io :: Either InterpreterError a -> String -> InterpreterOutput a _io :: InterpreterOutput a -> Either InterpreterError a _ioLog :: InterpreterOutput a -> String -- | Holding mutant information type Mutant = String -- | Holding test information type TestStr = String -- | Summary of test run newtype Summary Summary :: String -> Summary -- | Interface to be implemented by a test framework class Typeable s => Summarizable s where isFailure = not . isSuccess isOther x = not (isSuccess x) && not (isFailure x) testSummary :: Summarizable s => Mutant -> TestStr -> InterpreterOutput s -> Summary isSuccess :: Summarizable s => s -> Bool isFailure :: Summarizable s => s -> Bool isOther :: Summarizable s => s -> Bool instance Typeable Summary instance Show Summary -- | Common functions used by MuCheck module Test.MuCheck.Utils.Common -- | The choose function generates subsets of a given size choose :: [a] -> Int -> [[a]] -- | The coupling function produces all possible pairings, and -- applies the given function to each coupling :: Eq a => (a -> a -> t) -> [a] -> [t] -- | The replaceFst function replaces first matching element in a -- list given old and new values as a pair replaceFst :: Eq a => (a, a) -> [a] -> [a] -- | The sample function takes a random generator and chooses a -- random sample subset of given size. sample :: RandomGen g => g -> Int -> [t] -> [t] -- | Wrapper around sample providing the random seed rSample :: Int -> [t] -> IO [t] -- | The sampleF function takes a random generator, and a fraction -- and returns subset of size given by fraction sampleF :: RandomGen g => g -> Rational -> [t] -> [t] -- | The remElt function removes element at index specified from a -- list remElt :: Int -> [a] -> [a] -- | The swapElts function swaps two elements in a list given their -- indices swapElts :: Int -> Int -> [t] -> [t] -- | The genSwapped generates a list of lists where each element has -- been swapped by another genSwapped :: [t] -> [[t]] -- | Generate a random seed from the time. genRandomSeed :: IO StdGen -- | take a function of two args producing a monadic result, and apply it -- to a pair curryM :: (t1 -> t2 -> m t) -> (t1, t2) -> m t -- | A simple hash hash :: String -> String -- | The entry point for mucheck module Test.MuCheck.Interpreter -- | Given the list of tests suites to check, run the test suite on -- mutants. evaluateMutants :: (Summarizable a, Show a) => (Mutant -> TestStr -> InterpreterOutput a -> Summary) -> [Mutant] -> [String] -> IO (MAnalysisSummary, [MutantSummary]) -- | Given the filename, modulename, test to evaluate, evaluate, and return -- result as a pair. -- --
--   t = I.runInterpreter (evalMethod
--          "Examples/QuickCheckTest.hs"
--          "quickCheckResult idEmp")
--   
evalMethod :: (MonadInterpreter m, Typeable t) => String -> String -> m t -- | Run all tests on a mutant evalMutant :: (Typeable t, Summarizable t) => [TestStr] -> Mutant -> IO [InterpreterOutput t] -- | Run one single test on a mutant evalTest :: (Typeable a, Summarizable a) => String -> String -> String -> IO (InterpreterOutput a) summarizeResults :: Summarizable a => (Mutant -> TestStr -> InterpreterOutput a -> Summary) -> [String] -> (Mutant, [InterpreterOutput a]) -> MutantSummary -- | Data type to hold results of a single test execution data MutantSummary MSumError :: Mutant -> String -> [Summary] -> MutantSummary MSumAlive :: Mutant -> [Summary] -> MutantSummary MSumKilled :: Mutant -> [Summary] -> MutantSummary MSumOther :: Mutant -> [Summary] -> MutantSummary instance Typeable MutantSummary instance Show MutantSummary -- | Available mutation operators module Test.MuCheck.Operators -- | comparison operators [""", ""=", "/=", "=="] -- -- all available operators comparators :: [MuOp] -- | predicates ["pred", "id", "succ"] -- -- all available operators predNums :: [MuOp] -- | binary arithmetic ["+", "-", "*", "/"] -- -- all available operators binAriths :: [MuOp] -- | functions on lists ["sum", "product", "maximum", "minimum", "head", -- "last"] -- -- all available operators arithLists :: [MuOp] -- | all available operators allOps :: [MuOp] -- | Configuration module module Test.MuCheck.Config -- | The knob controlling if we want first order mutation. data GenerationMode FirstOrderOnly :: GenerationMode FirstAndHigherOrder :: GenerationMode -- | The configuration options if 1 is provided, all mutants are selected -- for that kind, and 0 ensures that no mutants are picked for that kind. -- Any fraction in between causes that many mutants to be picked randomly -- from the available pool data Config Config :: [MuOp] -> Rational -> Rational -> Rational -> Rational -> Int -> GenerationMode -> Config -- | Mutation operators on operator or function replacement muOps :: Config -> [MuOp] -- | Mutate pattern matches for functions? for example -- --
--   first [] = Nothing
--   first (x:_) = Just x
--   
-- -- is mutated to -- --
--   first (x:_) = Just x
--   first [] = Nothing
--   
doMutatePatternMatches :: Config -> Rational -- | Mutates integer values by +1 or -1 or by replacing it with 0 or 1 doMutateValues :: Config -> Rational -- | negate if conditions, that is -- --
--   if True then 1 else 0
--   
-- -- becomes -- --
--   if (not True) then 1 else 0
--   
doNegateIfElse :: Config -> Rational -- | negate guarded booleans in case statements, that is -- --
--   case v of
--     True -> 1
--     otherwise -> 0
--   
-- -- becomes -- --
--   case v of
--    (not True) -> 1
--    otherwise -> 0
--   
doNegateGuards :: Config -> Rational -- | Maximum number of mutants to generate. maxNumMutants :: Config -> Int -- | Generation mode, can be traditional (firstOrder) and higher order -- (higher order is experimental) genMode :: Config -> GenerationMode -- | The default configuration defaultConfig :: Config -- | Enumeration of different kinds of mutations data MuVars MutatePatternMatch :: MuVars MutateValues :: MuVars MutateNegateIfElse :: MuVars MutateNegateGuards :: MuVars -- | getSample returns the fraction in config corresponding to the enum -- passed in getSample :: MuVars -> Config -> Rational instance Eq GenerationMode instance Show GenerationMode instance Show Config -- | Mutation happens here. module Test.MuCheck.Mutation -- | The genMutants function is a wrapper to genMutantsWith with -- standard configuraton genMutants :: String -> FilePath -> IO [Mutant] -- | The genMutantsWith function takes configuration function to -- mutate, filename the function is defined in, and produces mutants in -- the same directory as the filename, and returns the number of mutants -- produced. genMutantsWith :: Config -> String -> FilePath -> IO [Mutant] -- | Wrapper around sampleF that returns correct sampling ratios according -- to configuration passed. sampler :: RandomGen g => Config -> g -> MuVars -> [t] -> [t] -- | The genMutantsForSrc takes the function name to mutate, source -- where it is defined, and a sampling function, and returns the mutated -- sources selected using sampling function. genMutantsForSrc :: Config -> String -> String -> (MuVars -> [MuOp] -> [MuOp]) -> [Mutant] -- | Replace old function definition with a new one in the AST replaceDef :: Decl -> Decl -> Module -> [Decl] -- | Fetch the function definition from module getFunc :: String -> Module -> Decl -- | Higher order mutation of a function's code using a bunch of mutation -- operators (In all the three mutate functions, we assume working with -- functions declaration.) mutates :: [MuOp] -> Decl -> [Decl] -- | First and higher order mutation. The third argument specifies whether -- it's first order or higher order mutatesN :: [MuOp] -> Decl -> Int -> [Decl] -- | Given a function, generate all mutants after applying applying op once -- (op might be applied at different places). E.g.: if the operator is -- (op = "== ">") and there are two instances of "<" in the -- AST, then it will return two AST with each replaced. mutate :: MuOp -> Decl -> [Decl] -- | is the parsed expression the function we are looking for? isFunctionD :: String -> Decl -> Bool -- | Generate all operators for permutating pattern matches in a function. -- We don't deal with permutating guards and case for now. permMatches :: Decl -> [MuOp] -- | Generates transformations that removes one pattern match from a -- function definition. removeOnePMatch :: Decl -> [MuOp] -- | Generate sub-arrays with one less element removeOneElem :: Eq t => [t] -> [[t]] -- | Returns the AST from the file getASTFromStr :: String -> Module -- | Set the declaration in a module putDecls :: Module -> [Decl] -> Module -- | For valops, unlike functions, we specify how any given literal value -- might change. So we take a predicate specifying how to recognize the -- literal value, a list of mappings specifying how the literal can -- change, and the AST, and recurse over the AST looking for literals -- that match our predicate. When we find any, we apply the given list of -- mappings to them, and produce a MuOp mapping between the original -- value and transformed value. This list of MuOp mappings are then -- returned. selectValOps :: (Typeable b, Mutable b) => (b -> Bool) -> (b -> [b]) -> Decl -> [MuOp] -- | Look for literal values in AST, and return applicable MuOp transforms. -- Unfortunately booleans are not handled here. selectLitOps :: Decl -> [MuOp] -- | Convert Boolean Literals selectBLitOps :: Decl -> [MuOp] -- | Negating boolean in if/else statements selectIfElseBoolNegOps :: Decl -> [MuOp] -- | Negating boolean in Guards selectGuardedBoolNegOps :: Decl -> [MuOp] -- | MuCheck base module module Test.MuCheck -- | Perform mutation analysis mucheck :: (Summarizable a, Show a) => (Mutant -> TestStr -> InterpreterOutput a -> Summary) -> String -> String -> [TestStr] -> IO (MAnalysisSummary, [MutantSummary])