-
Philippe Suter authoredPhilippe Suter authored
TestGeneration.scala 4.56 KiB
package leon.testgen
import leon.verification.Analyser
import leon.purescala.Common._
import leon.purescala.Definitions._
import leon.purescala.Trees._
import leon.purescala.TreeOps._
import leon.purescala.TypeTrees._
import leon.purescala.ScalaPrinter
import leon.Extensions._
import leon.solvers.z3.FairZ3Solver
import leon.Reporter
import scala.collection.mutable.{Set => MutableSet}
class TestGeneration(reporter: Reporter) extends Analyser(reporter) {
def description: String = "Generate random testcases"
override def shortDescription: String = "test"
private val z3Solver = new FairZ3Solver(reporter)
def analyse(program: Program) {
z3Solver.setProgram(program)
reporter.info("Running test generation")
val testcases = generateTestCases(program)
val topFunDef = program.definedFunctions.find(fd => isMain(fd)).get
//fd.body.exists(body => body match {
// case Waypoint(1, _) => true
// case _ => false
// })
val testFun = new FunDef(FreshIdentifier("test"), UnitType, Seq())
val funInvocs = testcases.map(testcase => {
val params = topFunDef.args
val args = topFunDef.args.map{
case VarDecl(id, tpe) => testcase.get(id) match {
case Some(v) => v
case None => simplestValue(tpe)
}
}
FunctionInvocation(topFunDef, args)
}).toSeq
testFun.body = Some(Block(funInvocs, UnitLiteral))
val Program(id, ObjectDef(objId, defs, invariants)) = program
val testProgram = Program(id, ObjectDef(objId, testFun +: defs , invariants))
testProgram.writeScalaFile("TestGen.scalax")
reporter.info("Running from waypoint with the following testcases:\n")
reporter.info(testcases.mkString("\n"))
}
private def isMain(fd: FunDef): Boolean = {
fd.annotations.exists(_ == "main")
}
def generatePathConditions(program: Program): Set[Expr] = {
val callGraph = new CallGraph(program)
callGraph.writeDotFile("testgen.dot")
val constraints = callGraph.findAllPaths(z3Solver).map(path => {
println("Path is: " + path)
val cnstr = callGraph.pathConstraint(path)
println("constraint is: " + cnstr)
cnstr
})
constraints
}
private def generateTestCases(program: Program): Set[Map[Identifier, Expr]] = {
val allPaths = generatePathConditions(program)
allPaths.flatMap(pathCond => {
reporter.info("Now considering path condition: " + pathCond)
var testcase: Option[Map[Identifier, Expr]] = None
//val z3Solver: FairZ3Solver = loadedSolverExtensions.find(se => se.isInstanceOf[FairZ3Solver]).get.asInstanceOf[FairZ3Solver]
z3Solver.init()
z3Solver.restartZ3
val (solverResult, model) = z3Solver.decideWithModel(pathCond, false)
solverResult match {
case None => Seq()
case Some(true) => {
reporter.info("The path is unreachable")
Seq()
}
case Some(false) => {
reporter.info("The model should be used as the testcase")
Seq(model)
}
}
})
}
//private def generatePathConditions(funDef: FunDef): Seq[Expr] = if(!funDef.hasImplementation) Seq() else {
// val body = funDef.body.get
// val cleanBody = hoistIte(expandLets(matchToIfThenElse(body)))
// collectWithPathCondition(cleanBody)
//}
//private def generateTestCases(funDef: FunDef): Seq[Map[Identifier, Expr]] = {
// val allPaths = generatePathConditions(funDef)
// allPaths.flatMap(pathCond => {
// reporter.info("Now considering path condition: " + pathCond)
// var testcase: Option[Map[Identifier, Expr]] = None
// //val z3Solver: FairZ3Solver = loadedSolverExtensions.find(se => se.isInstanceOf[FairZ3Solver]).get.asInstanceOf[FairZ3Solver]
//
// z3Solver.init()
// z3Solver.restartZ3
// val (solverResult, model) = z3Solver.decideWithModel(pathCond, false)
// solverResult match {
// case None => Seq()
// case Some(true) => {
// reporter.info("The path is unreachable")
// Seq()
// }
// case Some(false) => {
// reporter.info("The model should be used as the testcase")
// Seq(model)
// }
// }
// })
//}
//prec: ite are hoisted and no lets nor match occurs
//private def collectWithPathCondition(expression: Expr): Seq[Expr] = {
// var allPaths: Seq[Expr] = Seq()
// def rec(expr: Expr, path: List[Expr]): Seq[Expr] = expr match {
// case IfExpr(cond, then, elze) => rec(then, cond :: path) ++ rec(elze, Not(cond) :: path)
// case _ => Seq(And(path.toSeq))
// }
// rec(expression, List())
//}
}