Skip to content

Commit 73349f8

Browse files
committed
Added branch coverage
1 parent 81bdf82 commit 73349f8

File tree

3 files changed

+34
-18
lines changed

3 files changed

+34
-18
lines changed

src/main/scala/scales/InstrumentationRuntime.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ object InstrumentationRuntime {
1919
location: Location,
2020
start: Int,
2121
line: Int,
22-
desc: String) = {
22+
desc: String,
23+
branch: Boolean) = {
2324
val id = ids.incrementAndGet()
24-
val stmt = MeasuredStatement(location, id, start, line, desc)
25+
val stmt = MeasuredStatement(location, id, start, line, desc, branch)
2526
coverage.add(stmt)
2627
stmt
2728
}

src/main/scala/scales/coverage.scala

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import scala.reflect.internal.util.SourceFile
66
/**
77
* @author Stephen Samuel */
88
class Coverage
9-
extends StatementCoverage with
9+
extends CoverageMetrics with
1010
MethodBuilders with
1111
java.io.Serializable with
1212
ClassBuilders with
@@ -49,18 +49,18 @@ trait ClassBuilders {
4949
def classCount: Int = classes.size
5050
}
5151

52-
case class MeasuredMethod(name: String, statements: Iterable[MeasuredStatement]) extends StatementCoverage
52+
case class MeasuredMethod(name: String, statements: Iterable[MeasuredStatement]) extends CoverageMetrics
5353

5454
case class MeasuredClass(name: String, statements: Iterable[MeasuredStatement])
55-
extends StatementCoverage with MethodBuilders with Numerics
55+
extends CoverageMetrics with MethodBuilders with Numerics
5656

5757
case class MeasuredPackage(name: String, statements: Iterable[MeasuredStatement])
58-
extends StatementCoverage with ClassCoverage with ClassBuilders {
58+
extends CoverageMetrics with ClassCoverage with ClassBuilders {
5959
def files = Nil //statements.groupBy(_.source).map(arg => MeasuredFile(arg._1, arg._2))
6060
}
6161

6262
case class MeasuredFile(source: SourceFile, statements: Iterable[MeasuredStatement])
63-
extends StatementCoverage with ClassCoverage with ClassBuilders {
63+
extends CoverageMetrics with ClassCoverage with ClassBuilders {
6464
def lineStatus(lineNumber: Int): LineStatus = {
6565
statements.filter(_.line == lineNumber) match {
6666
case i if i.isEmpty => NotInstrumented
@@ -78,6 +78,7 @@ case class MeasuredStatement(location: Location,
7878
start: Int,
7979
line: Int,
8080
desc: String,
81+
branch: Boolean,
8182
var count: Int = 0) extends java.io.Serializable {
8283
def invoked(): Unit = count = count + 1
8384
}
@@ -87,17 +88,24 @@ trait Numerics {
8788
def loc = statements.map(stmt => stmt.location.fqn + ":" + stmt.line).toSet.size
8889
}
8990

90-
case class Location(_package: String, _class: String, classType: ClassType, method: Option[String])
91+
case class Location(_package: String, _class: String, classType: ClassType, method: String)
9192
extends java.io.Serializable {
9293
val fqn = (_package + ".").replace("<empty>.", "") + _class
9394
}
9495

95-
trait StatementCoverage {
96+
trait CoverageMetrics {
9697
val statements: Iterable[MeasuredStatement]
97-
def statementCoverage: Double = invokedStatements / statements.size.toDouble
98+
def statementCount: Int = statements.count(!_.branch)
99+
def invokedStatements: Iterable[MeasuredStatement] = statements.filter(_.count > 0)
100+
def invokedStatementCount = invokedStatements.size
101+
def statementCoverage: Double = invokedStatements / statementCount.toDouble
98102
def statementCoverageFormatted: String = "%.2f".format(statementCoverage * 100)
99-
def statementCount: Int = statements.size
100-
def invokedStatements: Int = statements.count(_.count > 0)
103+
def branches: Iterable[MeasuredStatement] = statements.filter(_.branch)
104+
def branchCount: Int = branches.size
105+
def invokedBranches: Iterable[MeasuredStatement] = branches.filter(_.count > 0)
106+
def invokedBranchesCount = invokedBranches.size
107+
def branchCoverage: Double = invokedBranchesCount / branchCount.toDouble
108+
def branchCoverageFormatted: String = "%.2f".format(branchCoverage * 100)
101109
}
102110

103111
trait ClassCoverage {

src/main/scala/scales/plugin.scala

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,11 @@ class ScalesComponent(val global: Global)
5252

5353
// instrument the given case defintions not changing the patterns or guards
5454
def transformCases(cases: List[CaseDef]): List[CaseDef] = {
55-
cases.map(c => treeCopy.CaseDef(c, c.pat, c.guard, instrument(c.body)))
55+
cases.map(c => treeCopy.CaseDef(c, c.pat, c.guard, instrument(instrument(c.body), true)))
56+
}
57+
58+
def transformIf(tree: Tree) = {
59+
instrument(process(tree), true)
5660
}
5761

5862
// Creates a call to the invoker
@@ -76,12 +80,12 @@ class ScalesComponent(val global: Global)
7680
def safeSource(tree: Tree): Option[SourceFile] = if (tree.pos.isDefined) Some(tree.pos.source) else None
7781

7882
// wraps the given tree with an Instrumentation call
79-
def instrument(tree: Tree) = {
83+
def instrument(tree: Tree, branch: Boolean = false) = {
8084
safeSource(tree) match {
8185
case None => tree
8286
case Some(source) =>
8387
val instruction =
84-
InstrumentationRuntime.add(source, location, safeStart(tree), safeLine(tree), tree.toString())
88+
InstrumentationRuntime.add(source, location, safeStart(tree), safeLine(tree), tree.toString(), branch)
8589
val apply = invokeCall(instruction.id)
8690
val block = Block(apply, tree)
8791
localTyper.typed(atPos(tree.pos)(block))
@@ -125,10 +129,10 @@ class ScalesComponent(val global: Global)
125129
//registerClass(c)
126130
super.transform(tree)
127131

128-
case t: Template => treeCopy.Template(tree, t.parents, t.self, transformStatements(t.body))
132+
case t: Template =>
133+
treeCopy.Template(tree, t.parents, t.self, transformStatements(t.body))
129134

130135
case _: TypeTree => super.transform(tree)
131-
case _: If => super.transform(tree)
132136
case _: Ident => super.transform(tree)
133137
case _: Block => super.transform(tree)
134138

@@ -171,7 +175,7 @@ class ScalesComponent(val global: Global)
171175
super.transform(tree)
172176

173177
case d: DefDef if d.symbol.isCaseApplyOrUnapply =>
174-
println("Case apply/unapply")
178+
println("Case apply/unapply " + d)
175179
updateLocation(d.symbol)
176180
super.transform(tree)
177181

@@ -180,6 +184,9 @@ class ScalesComponent(val global: Global)
180184
updateLocation(d.symbol)
181185
super.transform(tree)
182186

187+
case i: If =>
188+
treeCopy.If(i, i.cond, transformIf(i.thenp), transformIf(i.elsep))
189+
183190
// should only occur inside something we are instrumenting.
184191
case s: Select =>
185192
super.transform(tree)

0 commit comments

Comments
 (0)