Skip to content

Commit 9df17b4

Browse files
PackageToJS: Bring XCTest output formatter from carton
1 parent 5f1f224 commit 9df17b4

File tree

12 files changed

+543
-4
lines changed

12 files changed

+543
-4
lines changed

Examples/Testing/Package.swift

+5-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@ let package = Package(
1818
]),
1919
.testTarget(
2020
name: "CounterTests",
21-
dependencies: ["Counter"]
21+
dependencies: [
22+
"Counter",
23+
// This is needed to run the tests in the JavaScript event loop
24+
.product(name: "JavaScriptEventLoopTestSupport", package: "JavaScriptKit")
25+
]
2226
),
2327
]
2428
)

Examples/Testing/Tests/CounterTests/CounterTests.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ import Testing
2121
import XCTest
2222

2323
class CounterTests: XCTestCase {
24-
func testIncrement() async {
24+
func testIncrement() async throws {
2525
var counter = Counter()
26+
print("Incrementing")
2627
counter.increment()
2728
XCTAssertEqual(counter.count, 1)
2829
}

Plugins/PackageToJS/Sources/PackageToJS.swift

+65
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ struct PackageToJS {
4040
var inspect: Bool
4141
/// The extra arguments to pass to node
4242
var extraNodeArguments: [String]
43+
/// Whether to print verbose output
44+
var verbose: Bool
4345
/// The options for packaging
4446
var packageOptions: PackageOptions
4547
}
@@ -85,6 +87,7 @@ struct PackageToJS {
8587
try PackageToJS.runSingleTestingLibrary(
8688
testRunner: testRunner, currentDirectoryURL: currentDirectoryURL,
8789
extraArguments: extraArguments,
90+
testParser: testOptions.verbose ? nil : FancyTestsParser(),
8891
testOptions: testOptions
8992
)
9093
}
@@ -119,6 +122,7 @@ struct PackageToJS {
119122
testRunner: URL,
120123
currentDirectoryURL: URL,
121124
extraArguments: [String],
125+
testParser: (any TestsParser)? = nil,
122126
testOptions: TestOptions
123127
) throws {
124128
let node = try which("node")
@@ -129,11 +133,39 @@ struct PackageToJS {
129133
let task = Process()
130134
task.executableURL = node
131135
task.arguments = arguments
136+
137+
var finalize: () -> Void = {}
138+
if let testParser = testParser {
139+
class Writer: InteractiveWriter {
140+
func write(_ string: String) {
141+
print(string, terminator: "")
142+
}
143+
}
144+
145+
let writer = Writer()
146+
let stdoutBuffer = LineBuffer { line in
147+
testParser.onLine(line, writer)
148+
}
149+
let stdoutPipe = Pipe()
150+
stdoutPipe.fileHandleForReading.readabilityHandler = { handle in
151+
stdoutBuffer.append(handle.availableData)
152+
}
153+
task.standardOutput = stdoutPipe
154+
finalize = {
155+
if let data = try? stdoutPipe.fileHandleForReading.readToEnd() {
156+
stdoutBuffer.append(data)
157+
}
158+
stdoutBuffer.flush()
159+
testParser.finalize(writer)
160+
}
161+
}
162+
132163
task.currentDirectoryURL = currentDirectoryURL
133164
try task.forwardTerminationSignals {
134165
try task.run()
135166
task.waitUntilExit()
136167
}
168+
finalize()
137169
// swift-testing returns EX_UNAVAILABLE (which is 69 in wasi-libc) for "no tests found"
138170
guard task.terminationStatus == 0 || task.terminationStatus == 69 else {
139171
throw PackageToJSError("Test failed with status \(task.terminationStatus)")
@@ -151,6 +183,39 @@ struct PackageToJS {
151183
print("Saved profile data to \(mergedCoverageFile.path)")
152184
}
153185
}
186+
187+
class LineBuffer: @unchecked Sendable {
188+
let lock = NSLock()
189+
var buffer = ""
190+
let handler: (String) -> Void
191+
192+
init(handler: @escaping (String) -> Void) {
193+
self.handler = handler
194+
}
195+
196+
func append(_ data: Data) {
197+
let string = String(data: data, encoding: .utf8) ?? ""
198+
append(string)
199+
}
200+
201+
func append(_ data: String) {
202+
lock.lock()
203+
defer { lock.unlock() }
204+
buffer += data
205+
let lines = buffer.split(separator: "\n", omittingEmptySubsequences: false)
206+
for line in lines.dropLast() {
207+
handler(String(line))
208+
}
209+
buffer = String(lines.last ?? "")
210+
}
211+
212+
func flush() {
213+
lock.lock()
214+
defer { lock.unlock() }
215+
handler(buffer)
216+
buffer = ""
217+
}
218+
}
154219
}
155220

156221
struct PackageToJSError: Swift.Error, CustomStringConvertible {

Plugins/PackageToJS/Sources/PackageToJSPlugin.swift

+4
Original file line numberDiff line numberDiff line change
@@ -340,12 +340,14 @@ extension PackageToJS.TestOptions {
340340
let prelude = extractor.extractOption(named: "prelude").last
341341
let environment = extractor.extractOption(named: "environment").last
342342
let inspect = extractor.extractFlag(named: "inspect")
343+
let verbose = extractor.extractFlag(named: "verbose")
343344
let extraNodeArguments = extractor.extractSingleDashOption(named: "Xnode")
344345
let packageOptions = PackageToJS.PackageOptions.parse(from: &extractor)
345346
var options = PackageToJS.TestOptions(
346347
buildOnly: buildOnly != 0, listTests: listTests != 0,
347348
filter: filter, prelude: prelude, environment: environment, inspect: inspect != 0,
348349
extraNodeArguments: extraNodeArguments,
350+
verbose: verbose != 0,
349351
packageOptions: packageOptions
350352
)
351353

@@ -369,6 +371,8 @@ extension PackageToJS.TestOptions {
369371
--inspect Whether to run tests in the browser with inspector enabled
370372
--use-cdn Whether to use CDN for dependency packages (default: false)
371373
--enable-code-coverage Whether to enable code coverage collection (default: false)
374+
--verbose Whether to print verbose output (default: false)
375+
-Xnode <args> Extra arguments to pass to Node.js
372376
373377
EXAMPLES:
374378
$ swift package --swift-sdk wasm32-unknown-wasi plugin js test

0 commit comments

Comments
 (0)