or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

aggregation.mdcobertura-reports.mdcoverage-model.mdhtml-reports.mdindex.mdio-utils.mdplugin.mdruntime.mdserialization.mdxml-reports.md

serialization.mddocs/

0

# Data Serialization

1

2

The Serializer provides functionality for persisting and loading coverage data to/from files, enabling report generation and analysis across different build phases. It handles the conversion between in-memory Coverage objects and the standardized scoverage file format.

3

4

## Core API

5

6

### Serializer Object

7

8

```scala { .api }

9

object Serializer {

10

// Serialization methods

11

def serialize(coverage: Coverage, dataDir: String, sourceRoot: String): Unit

12

def serialize(coverage: Coverage, file: File, sourceRoot: File): Unit

13

def serialize(coverage: Coverage, writer: Writer, sourceRoot: File): Unit

14

15

// Deserialization methods

16

def deserialize(file: File, sourceRoot: File): Coverage

17

def deserialize(lines: Iterator[String], sourceRoot: File): Coverage

18

19

// File utilities

20

def coverageFile(dataDir: File): File

21

def coverageFile(dataDir: String): File

22

def clean(dataDir: File): Unit

23

def clean(dataDir: String): Unit

24

def findMeasurementFiles(dataDir: File): Array[File]

25

}

26

```

27

28

**Serialization Methods:**

29

- `serialize(coverage, dataDir, sourceRoot)` - Write coverage to default file in directory

30

- `serialize(coverage, file, sourceRoot)` - Write coverage to specific file

31

- `serialize(coverage, writer, sourceRoot)` - Write coverage to Writer (for custom streams)

32

33

**Deserialization Methods:**

34

- `deserialize(file, sourceRoot)` - Load coverage from file

35

- `deserialize(lines, sourceRoot)` - Load coverage from line iterator

36

37

**Utility Methods:**

38

- `coverageFile(dataDir)` - Get standard coverage file path for directory

39

- `clean(dataDir)` - Remove measurement files from directory

40

- `findMeasurementFiles(dataDir)` - Find all measurement files in directory

41

42

## Usage Examples

43

44

### Basic Serialization and Deserialization

45

46

```scala

47

import java.io.File

48

import scoverage.serialize.Serializer

49

import scoverage.domain.Coverage

50

51

// Create or obtain coverage data

52

val coverage: Coverage = generateCoverageData()

53

54

// Serialize to default location

55

val dataDir = "target/scoverage-data"

56

val sourceRoot = "src/main/scala"

57

Serializer.serialize(coverage, dataDir, sourceRoot)

58

59

// Later, deserialize the coverage data

60

val sourceRootFile = new File(sourceRoot)

61

val coverageFile = Serializer.coverageFile(dataDir)

62

val loadedCoverage = Serializer.deserialize(coverageFile, sourceRootFile)

63

64

println(s"Loaded coverage with ${loadedCoverage.statementCount} statements")

65

```

66

67

### Working with Specific Files

68

69

```scala

70

import java.io.File

71

import scoverage.serialize.Serializer

72

73

val coverage: Coverage = getCoverageData()

74

val sourceRoot = new File("src/main/scala")

75

76

// Serialize to a specific file

77

val customFile = new File("reports/custom-coverage.data")

78

customFile.getParentFile.mkdirs()

79

Serializer.serialize(coverage, customFile, sourceRoot)

80

81

// Deserialize from the custom file

82

val loadedCoverage = Serializer.deserialize(customFile, sourceRoot)

83

```

84

85

### Streaming Serialization

86

87

```scala

88

import java.io.{StringWriter, StringReader, BufferedReader}

89

import scoverage.serialize.Serializer

90

91

val coverage: Coverage = getCoverageData()

92

val sourceRoot = new File("src/main/scala")

93

94

// Serialize to a string (in-memory)

95

val stringWriter = new StringWriter()

96

Serializer.serialize(coverage, stringWriter, sourceRoot)

97

val serializedData = stringWriter.toString()

98

99

// Deserialize from string data

100

val reader = new BufferedReader(new StringReader(serializedData))

101

val lines = Iterator.continually(reader.readLine()).takeWhile(_ != null)

102

val deserializedCoverage = Serializer.deserialize(lines, sourceRoot)

103

```

104

105

### Build Tool Integration

106

107

```scala

108

// SBT integration example

109

import java.io.File

110

import scoverage.serialize.Serializer

111

112

val coverage: Coverage = collectCoverageFromTests()

113

val dataDir = crossTarget.value / "scoverage-data"

114

val sourceRoot = (Compile / scalaSource).value

115

116

// Ensure directory exists

117

dataDir.mkdirs()

118

119

// Serialize coverage data

120

Serializer.serialize(coverage, dataDir.getAbsolutePath, sourceRoot.getAbsolutePath)

121

122

// The coverage file can now be used by report generators

123

val coverageFile = Serializer.coverageFile(dataDir)

124

println(s"Coverage data written to: ${coverageFile.getAbsolutePath}")

125

```

126

127

## File Format Details

128

129

### Coverage File Format

130

131

The serialized coverage file uses a structured text format with version information:

132

133

```

134

# Coverage data, format version: 3.0

135

# Statement data:

136

# - id

137

# - source path

138

# - package name

139

# - class name

140

# - class type (Class, Object or Trait)

141

# - full class name

142

# - method name

143

# - start offset

144

# - end offset

145

# - line number

146

# - symbol name

147

# - tree name

148

# - is branch

149

# - invocations count

150

# - is ignored

151

# - description (can be multi-line)

152

# '\f' sign

153

# ------------------------------------------

154

1

155

src/main/scala/com/example/MyClass.scala

156

com.example

157

MyClass

158

Class

159

com.example.MyClass

160

myMethod

161

100

162

125

163

10

164

scala.Predef.println

165

Apply

166

false

167

0

168

false

169

println("Hello World")

170

```

171

172

### File Structure

173

174

Each statement is represented as a block of fields separated by newlines, with blocks separated by form feed characters (`\f`).

175

176

**Field Order:**

177

1. Statement ID (integer)

178

2. Relative source path (string)

179

3. Package name (string)

180

4. Class name (string)

181

5. Class type (Class/Object/Trait)

182

6. Full class name (string)

183

7. Method name (string)

184

8. Start character offset (integer)

185

9. End character offset (integer)

186

10. Line number (integer)

187

11. Symbol name (string)

188

12. Tree name (string)

189

13. Is branch (boolean)

190

14. Invocation count (integer)

191

15. Is ignored (boolean)

192

16. Description (multi-line string)

193

194

## File Management

195

196

### Standard File Names

197

198

```scala

199

// Default coverage file name

200

val coverageFile = Serializer.coverageFile(new File("target/scoverage-data"))

201

// Returns: target/scoverage-data/scoverage.coverage

202

203

// Get measurement files

204

val measurementFiles = Serializer.findMeasurementFiles(new File("target/scoverage-data"))

205

// Returns files matching: scoverage.measurements.*

206

```

207

208

### Cleaning Data Directories

209

210

```scala

211

import java.io.File

212

import scoverage.serialize.Serializer

213

214

// Clean measurement files but keep coverage file

215

val dataDir = new File("target/scoverage-data")

216

Serializer.clean(dataDir)

217

218

// Or using string path

219

Serializer.clean("target/scoverage-data")

220

```

221

222

### Directory Structure

223

224

A typical scoverage data directory contains:

225

226

```

227

target/scoverage-data/

228

├── scoverage.coverage # Main coverage data file

229

├── scoverage.measurements.1 # Measurement file for thread 1

230

├── scoverage.measurements.2 # Measurement file for thread 2

231

└── scoverage.measurements.N # Additional measurement files

232

```

233

234

## Path Handling

235

236

### Relative Path Conversion

237

238

During serialization, absolute source paths are converted to relative paths based on the source root:

239

240

```scala

241

// Absolute path: /project/src/main/scala/com/example/MyClass.scala

242

// Source root: /project/src/main/scala

243

// Stored as: com/example/MyClass.scala

244

```

245

246

### Path Resolution During Deserialization

247

248

During deserialization, relative paths are converted back to absolute paths:

249

250

```scala

251

// Stored path: com/example/MyClass.scala

252

// Source root: /project/src/main/scala

253

// Resolved to: /project/src/main/scala/com/example/MyClass.scala

254

```

255

256

## Advanced Usage

257

258

### Custom Source Root Handling

259

260

```scala

261

import java.io.File

262

import scoverage.serialize.Serializer

263

264

// Handle multiple source roots

265

val sourceRoots = Seq(

266

new File("module1/src/main/scala"),

267

new File("module2/src/main/scala")

268

)

269

270

// For serialization, use the common parent

271

val commonRoot = new File(".")

272

Serializer.serialize(coverage, dataDir, commonRoot.getAbsolutePath)

273

274

// For deserialization, the common root will resolve paths correctly

275

val loadedCoverage = Serializer.deserialize(coverageFile, commonRoot)

276

```

277

278

### Error Recovery

279

280

```scala

281

import java.io.File

282

import scoverage.serialize.Serializer

283

import scala.util.{Try, Success, Failure}

284

285

def loadCoverageWithRecovery(dataDir: File, sourceRoot: File): Option[Coverage] = {

286

val coverageFile = Serializer.coverageFile(dataDir)

287

288

Try(Serializer.deserialize(coverageFile, sourceRoot)) match {

289

case Success(coverage) =>

290

println(s"Successfully loaded ${coverage.statementCount} statements")

291

Some(coverage)

292

293

case Failure(exception) =>

294

println(s"Failed to load coverage data: ${exception.getMessage}")

295

None

296

}

297

}

298

```

299

300

### Batch Processing

301

302

```scala

303

// Process multiple data directories

304

val dataDirs = Seq(

305

new File("module1/target/scoverage-data"),

306

new File("module2/target/scoverage-data")

307

)

308

309

val sourceRoot = new File("src/main/scala")

310

311

val allCoverage: Seq[Coverage] = dataDirs.flatMap { dataDir =>

312

if (Serializer.coverageFile(dataDir).exists()) {

313

Try(Serializer.deserialize(Serializer.coverageFile(dataDir), sourceRoot)).toOption

314

} else {

315

None

316

}

317

}

318

319

println(s"Loaded coverage from ${allCoverage.size} modules")

320

```

321

322

## Format Version Compatibility

323

324

### Current Format Version

325

326

The current format version is 3.0, as defined in:

327

328

```

329

# Coverage data, format version: 3.0

330

```

331

332

### Version Checking

333

334

The deserializer validates the format version:

335

336

```scala

337

// Deserialization will fail with wrong format version

338

val lines = Iterator(

339

"# Coverage data, format version: 2.0", // Wrong version

340

"# Statement data:",

341

// ... rest of data

342

)

343

344

// This will throw an exception

345

val coverage = Serializer.deserialize(lines, sourceRoot)

346

```

347

348

## Error Handling

349

350

### Common Issues

351

352

**File Permission Errors:**

353

```scala

354

// Handle permission issues during serialization

355

try {

356

Serializer.serialize(coverage, dataDir, sourceRoot)

357

} catch {

358

case ex: java.io.IOException =>

359

println(s"Failed to write coverage file: ${ex.getMessage}")

360

// Handle error (create directory, check permissions, etc.)

361

}

362

```

363

364

**Malformed Coverage Files:**

365

```scala

366

// Handle corrupted or invalid coverage files

367

try {

368

val coverage = Serializer.deserialize(coverageFile, sourceRoot)

369

} catch {

370

case ex: IllegalArgumentException =>

371

println(s"Invalid coverage file format: ${ex.getMessage}")

372

case ex: NumberFormatException =>

373

println(s"Corrupted numeric data in coverage file: ${ex.getMessage}")

374

}

375

```

376

377

**Missing Source Files:**

378

```scala

379

// Handle cases where source files have moved

380

val sourceRoot = new File("src/main/scala")

381

if (!sourceRoot.exists()) {

382

println(s"Warning: Source root ${sourceRoot.getPath} does not exist")

383

// Use alternative source root or handle gracefully

384

}

385

```

386

387

### Best Practices

388

389

1. **Validate Input**: Always check that data directories and source roots exist

390

2. **Handle Exceptions**: Wrap serialization/deserialization in try-catch blocks

391

3. **Path Consistency**: Use consistent path handling across serialization and deserialization

392

4. **Format Validation**: Verify format version compatibility before processing

393

5. **Cleanup**: Use `clean()` method to remove stale measurement files when appropriate