0
# Native Platform Support
1
2
Scala Native test runner optimized for native compilation with efficient memory usage and native-specific execution patterns. Provides cross-platform compatibility for native executables.
3
4
## Capabilities
5
6
### ZTestRunnerNative Base Class
7
8
Abstract base class for Scala Native test runners that provides common functionality optimized for native compilation and execution.
9
10
```scala { .api }
11
/**
12
* Base Scala Native test runner with master/slave architecture support
13
* Optimized for native compilation with efficient memory usage
14
*/
15
sealed abstract class ZTestRunnerNative(
16
val args: Array[String],
17
remoteArgs0: Array[String],
18
testClassLoader: ClassLoader,
19
runnerType: String
20
) extends Runner {
21
/** Get remote execution arguments */
22
def remoteArgs(): Array[String]
23
24
/** Abstract method for summary handling strategy */
25
def sendSummary: SendSummary
26
27
/** Thread-safe queue for collecting test summaries */
28
val summaries: ConcurrentLinkedQueue[Summary]
29
30
/**
31
* Create test tasks from discovered test definitions
32
* @param defs Array of SBT task definitions
33
* @return Array of executable native test tasks
34
*/
35
def tasks(defs: Array[TaskDef]): Array[Task]
36
37
/**
38
* Complete test execution and return formatted results
39
* Efficiently processes summaries with minimal memory allocation
40
* @return Formatted test results or "No tests executed" message
41
*/
42
def done(): String
43
44
/**
45
* Receive serialized summaries from distributed execution
46
* @param summary Serialized summary string from SummaryProtocol
47
* @return Optional response message (always None for Native)
48
*/
49
override def receiveMessage(summary: String): Option[String]
50
51
/**
52
* Serialize task for distributed execution
53
* @param task Task to serialize
54
* @param serializer SBT-provided serialization function
55
* @return Serialized task string
56
*/
57
override def serializeTask(task: Task, serializer: TaskDef => String): String
58
59
/**
60
* Deserialize task from distributed execution
61
* @param task Serialized task string
62
* @param deserializer SBT-provided deserialization function
63
* @return Reconstructed test task
64
*/
65
override def deserializeTask(task: String, deserializer: String => TaskDef): Task
66
}
67
```
68
69
### ZMasterTestRunner
70
71
Master runner for single-process Scala Native execution, optimized for native executable environments.
72
73
```scala { .api }
74
/**
75
* Master Scala Native test runner for single-process execution
76
* Provides efficient local summary collection for native executables
77
*/
78
final class ZMasterTestRunner(
79
args: Array[String],
80
remoteArgs: Array[String],
81
testClassLoader: ClassLoader
82
) extends ZTestRunnerNative(args, remoteArgs, testClassLoader, "master") {
83
/**
84
* Summary sender that collects results locally using thread-safe queue
85
* Optimized for native execution with minimal overhead
86
*/
87
override val sendSummary: SendSummary
88
}
89
```
90
91
### ZSlaveTestRunner
92
93
Slave runner for distributed Scala Native execution, used when tests are executed across multiple native processes.
94
95
```scala { .api }
96
/**
97
* Slave Scala Native test runner for distributed execution
98
* Sends summaries to master process via serialization protocol
99
*/
100
final class ZSlaveTestRunner(
101
args: Array[String],
102
remoteArgs: Array[String],
103
testClassLoader: ClassLoader,
104
val sendSummary: SendSummary
105
) extends ZTestRunnerNative(args, remoteArgs, testClassLoader, "slave")
106
```
107
108
### ZTestTask (Native)
109
110
Scala Native-specific test task implementation with blocking execution optimized for native environments.
111
112
```scala { .api }
113
/**
114
* Scala Native-specific test task with blocking execution
115
* Optimized for native compilation and minimal memory usage
116
*/
117
sealed class ZTestTask(
118
taskDef: TaskDef,
119
testClassLoader: ClassLoader,
120
runnerType: String,
121
sendSummary: SendSummary,
122
testArgs: TestArgs,
123
spec: ZIOSpecAbstract
124
) extends BaseTestTask(
125
taskDef, testClassLoader, sendSummary, testArgs, spec,
126
zio.Runtime.default, zio.Console.ConsoleLive
127
) {
128
/**
129
* Execute test with blocking semantics suitable for native execution
130
* Uses Await.result for synchronous execution model
131
* @param eventHandler SBT event handler for reporting
132
* @param loggers Array of SBT loggers
133
* @return Empty array (no sub-tasks created)
134
*/
135
override def execute(eventHandler: EventHandler, loggers: Array[Logger]): Array[sbt.testing.Task]
136
}
137
```
138
139
### ZTestTask Companion Object (Native)
140
141
Factory methods for creating Scala Native test tasks.
142
143
```scala { .api }
144
object ZTestTask {
145
/**
146
* Create a Scala Native test task instance
147
* @param taskDef SBT task definition
148
* @param testClassLoader ClassLoader for loading test classes
149
* @param runnerType Runner type identifier ("master" or "slave")
150
* @param sendSummary Summary collection effect
151
* @param args Parsed test arguments
152
* @return Configured native ZTestTask instance
153
*/
154
def apply(
155
taskDef: TaskDef,
156
testClassLoader: ClassLoader,
157
runnerType: String,
158
sendSummary: SendSummary,
159
args: TestArgs
160
): ZTestTask
161
}
162
```
163
164
### Efficient Summary Processing
165
166
The native platform uses optimized summary processing for minimal memory allocation:
167
168
```scala { .api }
169
def done(): String = {
170
val log = new StringBuilder
171
var summary = summaries.poll()
172
var total = 0
173
var ignore = 0
174
val isEmpty = summary eq null
175
176
// Process summaries without creating intermediate collections
177
while (summary ne null) {
178
total += summary.total
179
ignore += summary.ignore
180
val details = summary.failureDetails
181
if (!details.isBlank) {
182
log append colored(details)
183
log append '\n'
184
}
185
summary = summaries.poll()
186
}
187
188
if (isEmpty || total == ignore)
189
s"${Console.YELLOW}No tests were executed${Console.RESET}"
190
else
191
log.append("Done").result()
192
}
193
```
194
195
### Blocking Execution Model
196
197
Native test tasks use blocking execution for simplicity and efficiency:
198
199
```scala { .api }
200
override def execute(eventHandler: EventHandler, loggers: Array[Logger]): Array[sbt.testing.Task] = {
201
var resOutter: CancelableFuture[Unit] = null
202
try {
203
resOutter = Runtime.default.unsafe.runToFuture {
204
ZIO.consoleWith { console =>
205
(for {
206
summary <- spec.runSpecAsApp(FilteredSpec(spec.spec, args), args, console)
207
_ <- sendSummary.provideSomeEnvironment[Any](_.add(summary))
208
_ <- ZIO.when(summary.status == Summary.Failure) {
209
ZIO.attempt(eventHandler.handle(ZTestEvent(/* failure event */)))
210
}
211
} yield ()).provideLayer(
212
sharedFilledTestLayer +!+ (Scope.default >>> spec.bootstrap)
213
)
214
}.mapError {
215
case t: Throwable => t
216
case other => new RuntimeException(s"Unknown error during tests: $other")
217
}
218
}
219
220
// Block until completion for native execution model
221
Await.result(resOutter, SDuration.Inf)
222
Array()
223
} catch {
224
case t: Throwable =>
225
if (resOutter != null) resOutter.cancel()
226
throw t
227
}
228
}
229
```
230
231
### SummaryProtocol (Native)
232
233
The native platform uses the same serialization protocol as JavaScript for inter-process communication:
234
235
```scala { .api }
236
/**
237
* Serialization protocol for test summaries in native environments
238
* Identical to JavaScript implementation for consistency
239
*/
240
object SummaryProtocol {
241
/**
242
* Serialize test summary to string for transmission
243
* @param summary Test execution summary to serialize
244
* @return Tab-separated string representation
245
*/
246
def serialize(summary: Summary): String
247
248
/**
249
* Deserialize string back to test summary
250
* @param s Serialized summary string
251
* @return Optional Summary if deserialization succeeds
252
*/
253
def deserialize(s: String): Option[Summary]
254
255
/**
256
* Escape tab characters for serialization
257
* @param token String token to escape
258
* @return Escaped string
259
*/
260
def escape(token: String): String
261
262
/**
263
* Unescape tab characters from serialized tokens
264
* @param token Escaped string token
265
* @return Unescaped original string
266
*/
267
def unescape(token: String): String
268
}
269
```
270
271
### Native Platform Optimizations
272
273
Scala Native provides several optimizations:
274
275
- **Memory Efficiency**: Uses `ConcurrentLinkedQueue` and `StringBuilder` for minimal allocations
276
- **Blocking Execution**: Simplifies execution model with `Await.result` for native environments
277
- **Native Compilation**: Optimized for ahead-of-time compilation to native executables
278
- **Cross-Platform**: Works on Linux, macOS, and Windows native targets
279
- **Fast Startup**: Native executables have faster startup compared to JVM
280
- **Small Binary Size**: Compiled to compact native executables
281
282
### Error Handling
283
284
Native execution includes comprehensive error handling:
285
286
```scala { .api }
287
// Explicit error mapping for native environments
288
.mapError {
289
case t: Throwable => t
290
case other => new RuntimeException(s"Unknown error during tests: $other")
291
}
292
293
// Proper resource cleanup on cancellation
294
catch {
295
case t: Throwable =>
296
if (resOutter != null) resOutter.cancel()
297
throw t
298
}
299
```
300
301
### Platform Considerations
302
303
The native platform has specific considerations:
304
305
- **Reflection Limitations**: Uses portable reflection for class loading
306
- **Threading Model**: Compatible with native threading constraints
307
- **Memory Management**: Optimized for native garbage collection
308
- **IO Operations**: Works with native file system and console access
309
- **Signal Handling**: Limited compared to JVM but functional for basic needs
310
311
### Usage Example
312
313
```scala
314
// Native framework usage is identical to other platforms
315
val framework = new ZTestFramework()
316
val runner = framework.runner(args, remoteArgs, classLoader)
317
318
// Native compilation produces fast-starting executable
319
// $ scala-native:nativeLink
320
// $ ./target/scala-native/my-tests
321
```