or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cross-platform.mdevent-reporting.mdframework.mdindex.mdtask-execution.md

cross-platform.mddocs/

0

# Cross-Platform Support

1

2

ZIO Test SBT provides cross-platform support for JVM, JavaScript, and Native environments with platform-specific optimizations and distributed testing capabilities.

3

4

## Platform Architecture

5

6

### JVM Platform

7

8

Simple single-process execution model:

9

10

```scala { .api }

11

class ZTestRunner(

12

args: Array[String],

13

remoteArgs: Array[String],

14

testClassLoader: ClassLoader

15

) extends Runner {

16

val summaries: AtomicReference[Vector[Summary]]

17

val sendSummary: SendSummary

18

def done(): String

19

def tasks(defs: Array[TaskDef]): Array[Task]

20

}

21

```

22

23

**Key Features:**

24

- Thread-safe summary collection using `AtomicReference`

25

- Direct task execution without continuation support

26

- Simple task policy system

27

28

### JavaScript/Native Platforms

29

30

Master-slave distributed execution model:

31

32

```scala { .api }

33

sealed abstract class ZTestRunner(

34

args: Array[String],

35

remoteArgs: Array[String],

36

testClassLoader: ClassLoader,

37

runnerType: String

38

) extends Runner {

39

val summaries: mutable.Buffer[Summary]

40

def sendSummary: SendSummary

41

def receiveMessage(summary: String): Option[String]

42

def serializeTask(task: Task, serializer: TaskDef => String): String

43

def deserializeTask(task: String, deserializer: String => TaskDef): Task

44

}

45

```

46

47

**Key Features:**

48

- Message-based communication between master and slave runners

49

- Task serialization/deserialization support

50

- Asynchronous task execution with continuations

51

52

## Runner Implementations

53

54

### ZMasterTestRunner (JS/Native)

55

56

Coordinates distributed test execution:

57

58

```scala { .api }

59

class ZMasterTestRunner(

60

args: Array[String],

61

remoteArgs: Array[String],

62

testClassLoader: ClassLoader

63

) extends ZTestRunner(args, remoteArgs, testClassLoader, "master") {

64

val sendSummary: SendSummary

65

}

66

```

67

68

**Responsibilities:**

69

- Collects summaries from slave runners

70

- Coordinates overall test execution

71

- Provides final test results

72

73

### ZSlaveTestRunner (JS/Native)

74

75

Executes tests and reports back to master:

76

77

```scala { .api }

78

class ZSlaveTestRunner(

79

args: Array[String],

80

remoteArgs: Array[String],

81

testClassLoader: ClassLoader,

82

sendSummary: SendSummary

83

) extends ZTestRunner(args, remoteArgs, testClassLoader, "slave")

84

```

85

86

**Responsibilities:**

87

- Executes individual test tasks

88

- Sends results to master via serialized summaries

89

- Handles task deserialization from master

90

91

## Framework Integration

92

93

### Platform-Specific Framework Creation

94

95

**JVM:**

96

```scala { .api }

97

class ZTestFramework extends Framework {

98

def runner(args: Array[String], remoteArgs: Array[String], testClassLoader: ClassLoader): ZTestRunner =

99

new ZTestRunner(args, remoteArgs, testClassLoader)

100

}

101

```

102

103

**JavaScript/Native:**

104

```scala { .api }

105

class ZTestFramework extends Framework {

106

def runner(args: Array[String], remoteArgs: Array[String], testClassLoader: ClassLoader): Runner =

107

new ZMasterTestRunner(args, remoteArgs, testClassLoader)

108

109

def slaveRunner(

110

args: Array[String],

111

remoteArgs: Array[String],

112

testClassLoader: ClassLoader,

113

send: String => Unit

114

): Runner =

115

new ZSlaveTestRunner(

116

args, remoteArgs, testClassLoader,

117

SendSummary.fromSend(summary => send(SummaryProtocol.serialize(summary)))

118

)

119

}

120

```

121

122

## Summary Serialization

123

124

### SummaryProtocol (JS/Native)

125

126

Handles serialization/deserialization of test summaries for cross-process communication:

127

128

```scala { .api }

129

object SummaryProtocol {

130

def serialize(summary: Summary): String

131

def deserialize(s: String): Option[Summary]

132

def escape(token: String): String

133

def unescape(token: String): String

134

}

135

```

136

137

#### serialize()

138

139

Converts a `Summary` to a tab-separated string.

140

141

**Parameters:**

142

- `summary: Summary` - Test summary to serialize

143

144

**Returns:** `String` - Tab-separated string containing success count, fail count, ignore count, and summary text

145

146

**Format:** `"<success>\t<fail>\t<ignore>\t<summary>"`

147

148

#### deserialize()

149

150

Parses a serialized string back to a `Summary`.

151

152

**Parameters:**

153

- `s: String` - Serialized summary string

154

155

**Returns:** `Option[Summary]` - Parsed summary or `None` if parsing fails

156

157

#### escape() / unescape()

158

159

Utility methods for escaping tab characters in summary text:

160

161

**Parameters:**

162

- `token: String` - String to escape/unescape

163

164

**Returns:** `String` - Processed string with tabs escaped as `\\t` or vice versa

165

166

## Task Execution Differences

167

168

### JVM Task Execution

169

170

Synchronous execution with direct result handling:

171

172

```scala

173

def execute(eventHandler: EventHandler, loggers: Array[Logger]): Array[Task] = {

174

Runtime((), specInstance.platform).unsafeRun {

175

run(eventHandler).provideLayer(sbtTestLayer(loggers))

176

}

177

Array()

178

}

179

```

180

181

### JavaScript/Native Task Execution

182

183

Asynchronous execution with continuation support:

184

185

```scala

186

def execute(

187

eventHandler: EventHandler,

188

loggers: Array[Logger],

189

continuation: Array[Task] => Unit

190

): Unit = {

191

Runtime((), specInstance.platform)

192

.unsafeRunAsync(

193

(sbtTestLayer(loggers).build >>> run(eventHandler).toManaged_).use_(ZIO.unit)

194

) { exit =>

195

exit match {

196

case Exit.Failure(cause) => Console.err.println(s"$runnerType failed: " + cause.prettyPrint)

197

case _ =>

198

}

199

continuation(Array())

200

}

201

}

202

```

203

204

## Platform Detection

205

206

The appropriate implementation is selected at compile time based on the target platform:

207

208

- **JVM**: Uses `artifacts/original-repo/test-sbt/jvm/src/main/scala/`

209

- **JavaScript**: Uses `artifacts/original-repo/test-sbt/js/src/main/scala/`

210

- **Native**: Uses `artifacts/original-repo/test-sbt/native/src/main/scala/`

211

- **Shared**: Common code in `artifacts/original-repo/test-sbt/shared/src/main/scala/`

212

213

## Usage Considerations

214

215

### JVM Platform

216

- Suitable for traditional server-side and desktop applications

217

- Full ZIO and Scala standard library support

218

- Thread-safe concurrent execution

219

220

### JavaScript Platform

221

- Runs in browser or Node.js environments

222

- Limited to JavaScript-compatible libraries

223

- Single-threaded execution model with async support

224

225

### Native Platform

226

- Compiles to native executables

227

- Fast startup and low memory usage

228

- Limited library ecosystem

229

- Explicit method overrides required for some interfaces

230

231

## Message Flow Example

232

233

```scala

234

// 1. Master creates slave runner with send function

235

val slaveRunner = framework.slaveRunner(args, remoteArgs, classLoader, send)

236

237

// 2. Slave executes tests and sends results

238

val summary = Summary(1, 0, 0, "Test passed")

239

send(SummaryProtocol.serialize(summary)) // Sends: "1\t0\t0\tTest passed"

240

241

// 3. Master receives and deserializes

242

def receiveMessage(msg: String): Option[String] = {

243

SummaryProtocol.deserialize(msg).foreach(summaries += _)

244

None

245

}

246

247

// 4. Master provides final results

248

def done(): String = {

249

// Aggregate all received summaries

250

summaries.map(_.summary).mkString("\n") + "Done"

251

}

252

```