|
1 | 1 | package dotty.tools.dotc |
2 | 2 | package coverage |
3 | 3 |
|
| 4 | +import java.nio.charset.StandardCharsets.UTF_8 |
4 | 5 | import java.nio.file.{Path, Paths, Files} |
5 | 6 | import java.io.Writer |
6 | 7 | import scala.collection.mutable.StringBuilder |
| 8 | +import scala.io.Source |
7 | 9 |
|
8 | 10 | /** |
9 | 11 | * Serializes scoverage data. |
10 | | - * @see https://github.com/scoverage/scalac-scoverage-plugin/blob/main/scalac-scoverage-plugin/src/main/scala/scoverage/Serializer.scala |
| 12 | + * @see https://github.com/scoverage/scalac-scoverage-plugin/blob/main/serializer/src/main/scala/scoverage/serialize/Serializer.scala |
11 | 13 | */ |
12 | 14 | object Serializer: |
13 | 15 |
|
14 | 16 | private val CoverageFileName = "scoverage.coverage" |
15 | 17 | private val CoverageDataFormatVersion = "3.0" |
16 | 18 |
|
| 19 | + def coverageFilePath(dataDir: String) = |
| 20 | + Paths.get(dataDir, CoverageFileName).toAbsolutePath |
| 21 | + |
17 | 22 | /** Write out coverage data to the given data directory, using the default coverage filename */ |
18 | 23 | def serialize(coverage: Coverage, dataDir: String, sourceRoot: String): Unit = |
19 | | - serialize(coverage, Paths.get(dataDir, CoverageFileName).toAbsolutePath, Paths.get(sourceRoot).toAbsolutePath) |
| 24 | + serialize(coverage, coverageFilePath(dataDir), Paths.get(sourceRoot).toAbsolutePath) |
20 | 25 |
|
21 | 26 | /** Write out coverage data to a file. */ |
22 | 27 | def serialize(coverage: Coverage, file: Path, sourceRoot: Path): Unit = |
@@ -85,6 +90,64 @@ object Serializer: |
85 | 90 | .sortBy(_.id) |
86 | 91 | .foreach(stmt => writeStatement(stmt, writer)) |
87 | 92 |
|
| 93 | + def deserialize(file: Path): Coverage = |
| 94 | + val source = Source.fromFile(file.toFile(), UTF_8.name()) |
| 95 | + try deserialize(source.getLines()) |
| 96 | + finally source.close() |
| 97 | + |
| 98 | + def deserialize(lines: Iterator[String]): Coverage = |
| 99 | + def toStatement(lines: Iterator[String]): Statement = |
| 100 | + val id: Int = lines.next().toInt |
| 101 | + val sourcePath = lines.next() |
| 102 | + val packageName = lines.next() |
| 103 | + val className = lines.next() |
| 104 | + val classType = lines.next() |
| 105 | + val fullClassName = lines.next() |
| 106 | + val method = lines.next() |
| 107 | + val loc = Location( |
| 108 | + packageName, |
| 109 | + className, |
| 110 | + fullClassName, |
| 111 | + classType, |
| 112 | + method, |
| 113 | + Paths.get(sourcePath) |
| 114 | + ) |
| 115 | + val start: Int = lines.next().toInt |
| 116 | + val end: Int = lines.next().toInt |
| 117 | + val lineNo: Int = lines.next().toInt |
| 118 | + val symbolName: String = lines.next() |
| 119 | + val treeName: String = lines.next() |
| 120 | + val branch: Boolean = lines.next().toBoolean |
| 121 | + val count: Int = lines.next().toInt |
| 122 | + val ignored: Boolean = lines.next().toBoolean |
| 123 | + val desc = lines.toList.mkString("\n") |
| 124 | + Statement( |
| 125 | + loc, |
| 126 | + id, |
| 127 | + start, |
| 128 | + end, |
| 129 | + lineNo, |
| 130 | + desc, |
| 131 | + symbolName, |
| 132 | + treeName, |
| 133 | + branch, |
| 134 | + ignored |
| 135 | + ) |
| 136 | + |
| 137 | + val headerFirstLine = lines.next() |
| 138 | + require( |
| 139 | + headerFirstLine == s"# Coverage data, format version: $CoverageDataFormatVersion", |
| 140 | + "Wrong file format" |
| 141 | + ) |
| 142 | + |
| 143 | + val linesWithoutHeader = lines.dropWhile(_.startsWith("#")) |
| 144 | + val coverage = Coverage() |
| 145 | + while !linesWithoutHeader.isEmpty do |
| 146 | + val oneStatementLines = linesWithoutHeader.takeWhile(_ != "\f") |
| 147 | + coverage.addStatement(toStatement(oneStatementLines)) |
| 148 | + end while |
| 149 | + coverage |
| 150 | + |
88 | 151 | /** Makes a String suitable for output in the coverage statement data as a single line. |
89 | 152 | * Escaped characters: '\\' (backslash), '\n', '\r', '\f' |
90 | 153 | */ |
|
0 commit comments