or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

tessl/maven-org-scoverage--scalac-scoverage-runtime-2-11

Runtime support library for scoverage code coverage tool that collects coverage data during program execution when code has been instrumented by the scalac compiler plugin.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
mavenpkg:maven/org.scoverage/scalac-scoverage-runtime_2.11@1.4.x

To install, run

npx @tessl/cli install tessl/maven-org-scoverage--scalac-scoverage-runtime-2-11@1.4.0

0

# Scalac Scoverage Runtime

1

2

Scalac Scoverage Runtime is the runtime support library for scoverage, a code coverage tool for Scala. This library provides the essential instrumentation infrastructure that collects coverage data during program execution when code has been instrumented by the scalac-scoverage-plugin compiler plugin. It supports both JVM and JavaScript platforms through Scala.js.

3

4

## Package Information

5

6

- **Package Name**: scalac-scoverage-runtime_2.11

7

- **Package Type**: Maven

8

- **Language**: Scala

9

- **Platforms**: JVM, JavaScript (Scala.js)

10

- **Installation**:

11

- SBT: `libraryDependencies += "org.scoverage" %% "scalac-scoverage-runtime" % "1.4.11"`

12

- Maven: `<artifactId>scalac-scoverage-runtime_2.11</artifactId>`

13

14

## Core Imports

15

16

```scala

17

import scoverage.Invoker

18

import scoverage.Platform._

19

```

20

21

For JavaScript-specific functionality:

22

23

```scala

24

import scalajssupport.{File, FileWriter, Source}

25

```

26

27

## Basic Usage

28

29

The runtime library is typically used automatically by instrumented code, but can also be used directly for coverage analysis:

30

31

```scala

32

import scoverage.Invoker

33

import scoverage.Platform._

34

35

// Record statement execution (called by instrumented code)

36

Invoker.invoked(statementId = 42, dataDir = "/path/to/coverage/data")

37

38

// Find measurement files for analysis

39

val dataDir = "/path/to/coverage/data"

40

val measurementFiles = Invoker.findMeasurementFiles(dataDir)

41

42

// Load invoked statement IDs from files

43

val invokedIds = Invoker.invoked(measurementFiles)

44

println(s"Covered statements: ${invokedIds.size}")

45

```

46

47

## Architecture

48

49

The runtime library uses a cross-platform architecture with several key components:

50

51

- **Platform Abstraction**: `scoverage.Platform` provides unified interfaces across JVM and JavaScript with compile-time type resolution

52

- **Coverage Collection**: `scoverage.Invoker` handles thread-safe recording of statement executions with per-thread measurement files

53

- **UUID-based File Naming**: Uses runtime UUID (`runtimeUUID`) combined with thread ID to create unique measurement files

54

- **File System Abstraction**: JavaScript support includes comprehensive file system abstractions that auto-detect and adapt to different JS runtimes (Node.js, Rhino, PhantomJS)

55

- **Thread Safety**: Uses ThreadLocal storage and concurrent TrieMap data structures on JVM, simplified HashMap collections on JavaScript

56

- **Deduplication**: In-memory tracking of recorded statement IDs prevents duplicate writes within the same JVM execution

57

58

## Capabilities

59

60

### Coverage Data Collection

61

62

Core instrumentation runtime that records which statements have been executed during program execution.

63

64

```scala { .api }

65

object Invoker {

66

/**

67

* Records that a statement has been executed

68

* @param id the ID of the statement that was invoked

69

* @param dataDir the directory where measurement data is stored

70

* @param reportTestName whether to include test name information

71

*/

72

def invoked(id: Int, dataDir: String, reportTestName: Boolean = false): Unit

73

74

/**

75

* Gets the measurement file path for a given data directory

76

* @param dataDir the data directory as File

77

* @return measurement file for current thread

78

*/

79

def measurementFile(dataDir: File): File

80

81

/**

82

* Gets the measurement file path for a given data directory

83

* @param dataDir the data directory path as String

84

* @return measurement file for current thread

85

*/

86

def measurementFile(dataDir: String): File

87

88

/**

89

* Finds all measurement files in the given directory

90

* @param dataDir the directory to search as String

91

* @return array of measurement files

92

*/

93

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

94

95

/**

96

* Finds all measurement files in the given directory

97

* @param dataDir the directory to search as File

98

* @return array of measurement files

99

*/

100

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

101

102

/**

103

* Loads all invoked statement IDs from measurement files

104

* @param files sequence of measurement files to read

105

* @return set of statement IDs that were executed

106

* @note Each line may contain just the ID, or ID followed by test name (space-separated)

107

*/

108

def invoked(files: Seq[File]): Set[Int]

109

110

/**

111

* Utility method to identify calling ScalaTest suite

112

* @return name of calling test suite or empty string

113

*/

114

def getCallingScalaTest: String

115

}

116

```

117

118

### Platform Abstraction

119

120

Provides unified cross-platform interfaces for file operations and concurrent data structures.

121

122

```scala { .api }

123

object Platform {

124

// JVM Platform (when compiling to JVM bytecode)

125

type ThreadSafeMap[A, B] = scala.collection.concurrent.TrieMap[A, B]

126

lazy val ThreadSafeMap: TrieMap.type = TrieMap

127

type File = java.io.File

128

type FileWriter = java.io.FileWriter

129

type FileFilter = java.io.FileFilter

130

lazy val Source: scala.io.Source.type = scala.io.Source

131

132

// JavaScript Platform (when compiling to JavaScript via Scala.js)

133

type ThreadSafeMap[A, B] = scala.collection.mutable.HashMap[A, B]

134

lazy val ThreadSafeMap: HashMap.type = HashMap

135

type File = scalajssupport.File

136

type FileWriter = scalajssupport.FileWriter

137

type FileFilter = scalajssupport.FileFilter

138

lazy val Source: scalajssupport.Source.type = scalajssupport.Source

139

}

140

```

141

142

### JavaScript File System Support

143

144

JavaScript-compatible file system abstractions that emulate Java I/O APIs for Scala.js environments.

145

146

```scala { .api }

147

// JavaScript File abstraction

148

class File(path: String) {

149

/**

150

* Creates a File with parent path and child name

151

* @param path parent directory path

152

* @param child child file/directory name

153

*/

154

def this(path: String, child: String)

155

156

/** Deletes the file or directory */

157

def delete(): Unit

158

159

/** Returns the absolute path */

160

def getAbsolutePath(): String

161

162

/** Returns the file name */

163

def getName(): String

164

165

/** Returns the file path */

166

def getPath(): String

167

168

/** Checks if this is a directory */

169

def isDirectory(): Boolean

170

171

/** Creates directory structure */

172

def mkdirs(): Unit

173

174

/** Lists all files in directory */

175

def listFiles(): Array[File]

176

177

/** Lists files matching filter */

178

def listFiles(filter: FileFilter): Array[File]

179

180

/** Reads entire file content as string */

181

def readFile(): String

182

}

183

184

object File {

185

/** Joins path components */

186

def pathJoin(path: String, child: String): String

187

188

/** Writes data to file */

189

def write(path: String, data: String, mode: String = "a"): Unit

190

}

191

192

// JavaScript FileWriter abstraction

193

class FileWriter(file: File, append: Boolean) {

194

/** Create FileWriter for file without append mode */

195

def this(file: File)

196

/** Create FileWriter for file path without append mode */

197

def this(file: String)

198

/** Create FileWriter for file path with append mode */

199

def this(file: String, append: Boolean)

200

201

/** Appends character sequence, returns this for chaining */

202

def append(csq: CharSequence): FileWriter

203

204

/** Closes the writer */

205

def close(): Unit

206

207

/** Flushes the writer */

208

def flush(): Unit

209

}

210

211

// JavaScript Source abstraction

212

object Source {

213

/** Creates source reader from file */

214

def fromFile(file: File): scala.io.Source

215

}

216

217

// File filtering interface

218

trait FileFilter {

219

/** Returns true if file should be included */

220

def accept(file: File): Boolean

221

}

222

223

// JavaScript File trait hierarchy

224

trait JsFile {

225

/** Deletes the file or directory */

226

def delete(): Unit

227

/** Returns the absolute path */

228

def getAbsolutePath(): String

229

/** Returns the file name */

230

def getName(): String

231

/** Returns the file path */

232

def getPath(): String

233

/** Checks if this is a directory */

234

def isDirectory(): Boolean

235

/** Creates directory structure */

236

def mkdirs(): Unit

237

/** Lists all files in directory */

238

def listFiles(): Array[File]

239

/** Lists files matching filter */

240

def listFiles(filter: FileFilter): Array[File]

241

/** Reads entire file content as string */

242

def readFile(): String

243

}

244

245

trait JsFileObject {

246

/** Writes data to file with mode (default append) */

247

def write(path: String, data: String, mode: String = "a"): Unit

248

/** Joins path components */

249

def pathJoin(path: String, child: String): String

250

/** Creates JsFile instance for path */

251

def apply(path: String): JsFile

252

}

253

```

254

255

## Types

256

257

```scala { .api }

258

// Core platform types (resolved at compile time based on target platform)

259

type ThreadSafeMap[A, B] // TrieMap on JVM, HashMap on JS

260

type File // java.io.File on JVM, scalajssupport.File on JS

261

type FileWriter // java.io.FileWriter on JVM, scalajssupport.FileWriter on JS

262

type FileFilter // java.io.FileFilter on JVM, scalajssupport.FileFilter on JS

263

```

264

265

## Error Handling

266

267

The library handles errors gracefully across both platforms:

268

269

- **File operations**: JavaScript implementations catch exceptions and return appropriate defaults (e.g., `false` for `isDirectory()` if file doesn't exist)

270

- **Thread safety**:

271

- JVM: Synchronized blocks prevent race conditions in concurrent ID tracking using `dataDirToIds.synchronized` to guard against SI-7943

272

- JavaScript: Single-threaded environment eliminates race conditions

273

- **Measurement files**: Each thread writes to separate files (using thread ID in filename) to avoid write conflicts, especially important on Windows

274

- **Empty lines**: The `invoked(files)` method skips empty lines in measurement files using `if (!line.isEmpty)`

275

- **ThreadLocal cleanup**: ThreadLocal storage for FileWriter instances is properly managed per thread

276

- **File parsing**: Measurement file lines are parsed as integers with proper error handling for malformed data

277

278

## Platform-Specific Behavior

279

280

### JVM Platform

281

- Uses `java.util.concurrent.TrieMap` for thread-safe collections

282

- Leverages standard Java I/O classes

283

- Supports true concurrent access across multiple threads

284

- Uses `ThreadLocal` storage for file writers

285

286

### JavaScript Platform

287

- Uses `scala.collection.mutable.HashMap` (JavaScript is single-threaded)

288

- Provides file system abstractions for different JS environments

289

- Automatically detects and adapts to Node.js, Rhino, or PhantomJS environments using global object detection

290

- File operations delegate to environment-specific implementations (`NodeFile`, `RhinoFile`, `PhantomFile`)

291

- Environment detection: checks for `Packages` (Rhino), `callPhantom` (PhantomJS), or defaults to Node.js

292

293

### Measurement File Format

294

- **File naming**: `scoverage.measurements.<UUID>.<threadId>`

295

- **Content format**: Each line contains either:

296

- Just the statement ID: `"123"`

297

- ID with test name: `"123 MySuite"` (when `reportTestName = true`)

298

- **Multiple files**: One file per thread to avoid write conflicts

299

- **Parsing**: Only the first part (before space) is used as the statement ID

300

301

## Usage Examples

302

303

**Recording coverage data (typically done by instrumented code):**

304

305

```scala

306

import scoverage.Invoker

307

308

// Record that statement 123 was executed

309

Invoker.invoked(123, "/tmp/scoverage-data")

310

311

// Record with test name information

312

Invoker.invoked(456, "/tmp/scoverage-data", reportTestName = true)

313

```

314

315

**Analyzing coverage data:**

316

317

```scala

318

import scoverage.Invoker

319

import scoverage.Platform._

320

321

val dataDir = "/tmp/scoverage-data"

322

323

// Find all measurement files

324

val files = Invoker.findMeasurementFiles(dataDir)

325

println(s"Found ${files.length} measurement files")

326

327

// Load executed statement IDs

328

val executedIds = Invoker.invoked(files.toSeq)

329

println(s"Total statements executed: ${executedIds.size}")

330

331

// Check if specific statement was executed

332

val statementId = 42

333

if (executedIds.contains(statementId)) {

334

println(s"Statement $statementId was executed")

335

}

336

```

337

338

**Cross-platform file operations:**

339

340

```scala

341

import scoverage.Platform._

342

343

// This works on both JVM and JavaScript

344

val file = new File("/path/to/data", "measurements.txt")

345

val writer = new FileWriter(file, append = true)

346

writer.append("42\n")

347

writer.close()

348

349

// Read measurement data

350

val source = Source.fromFile(file)

351

val lines = source.getLines().toList

352

source.close()

353

```