All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scoverage.domain.CodeGrid.scala Maven / Gradle / Ivy

The newest version!
package scoverage.domain

import scala.io.Codec
import scala.io.Source

/** @author Stephen Samuel */
class CodeGrid(mFile: MeasuredFile, sourceEncoding: Option[String]) {

  // for backward compatibility only
  def this(mFile: MeasuredFile) = {
    this(mFile, None);
  }

  case class Cell(char: Char, var status: StatementStatus)

  private val lineBreak = "\n"

  // Array of lines, each line is an array of cells, where a cell is a character + coverage info for that position
  // All cells default to NoData until the highlighted information is applied
  // note: we must re-include the line sep to keep source positions correct.
  private val lines = source(mFile)
    .split(lineBreak)
    .map(line => (line.toCharArray ++ lineBreak).map(Cell(_, NoData)))

  // useful to have a single array to write into the cells
  private val cells = lines.flatten

  // apply the instrumentation data to the cells updating their coverage info
  mFile.statements.foreach(stmt => {
    for (k <- stmt.start until stmt.end) {
      if (k < cells.size) {
        // if the cell is set to Invoked, then it be changed to NotInvoked, as an inner statement will override
        // outer containing statements. If a cell is NotInvoked then it can not be changed further.
        // in that block were executed
        cells(k).status match {
          case Invoked => if (!stmt.isInvoked) cells(k).status = NotInvoked
          case NoData =>
            if (!stmt.isInvoked) cells(k).status = NotInvoked
            else if (stmt.isInvoked) cells(k).status = Invoked
          case NotInvoked =>
        }
      }
    }
  })

  val highlighted: String = {
    var lineNumber = 1
    val code = lines map (line => {
      var style = cellStyle(NoData)
      val sb = new StringBuilder
      sb append lineNumber append " "
      lineNumber = lineNumber + 1
      sb append spanStart(NoData)
      line.map(cell => {
        val style2 = cellStyle(cell.status)
        if (style != style2) {
          sb append ""
          sb append spanStart(cell.status)
          style = style2
        }
        // escape xml characters
        cell.char match {
          case '<' => sb.append("<")
          case '>' => sb.append(">")
          case '&' => sb.append("&")
          case '"' => sb.append(""")
          case c   => sb.append(c)
        }
      })
      sb append ""
      sb.toString
    }) mkString ""
    s"
$code
" } private def source(mfile: MeasuredFile): String = { val src = sourceEncoding match { case Some(enc) => Source.fromFile(mfile.source, enc) case None => Source.fromFile(mfile.source, Codec.UTF8.name) } try src.mkString finally src.close() } private def spanStart(status: StatementStatus): String = s"" private def cellStyle(status: StatementStatus): String = { val GREEN = "#AEF1AE" val RED = "#F0ADAD" status match { case Invoked => s"background: $GREEN" case NotInvoked => s"background: $RED" case NoData => "" } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy