@@ -40,6 +40,8 @@ struct PackageToJS {
40
40
var inspect : Bool
41
41
/// The extra arguments to pass to node
42
42
var extraNodeArguments : [ String ]
43
+ /// Whether to print verbose output
44
+ var verbose : Bool
43
45
/// The options for packaging
44
46
var packageOptions : PackageOptions
45
47
}
@@ -59,44 +61,54 @@ struct PackageToJS {
59
61
var testJsArguments : [ String ] = [ ]
60
62
var testLibraryArguments : [ String ] = [ ]
61
63
if testOptions. listTests {
62
- testLibraryArguments += [ " --list-tests " ]
64
+ testLibraryArguments. append ( " --list-tests " )
63
65
}
64
66
if let prelude = testOptions. prelude {
65
67
let preludeURL = URL ( fileURLWithPath: prelude, relativeTo: URL ( fileURLWithPath: FileManager . default. currentDirectoryPath) )
66
- testJsArguments += [ " --prelude " , preludeURL. path]
68
+ testJsArguments. append ( " --prelude " )
69
+ testJsArguments. append ( preludeURL. path)
67
70
}
68
71
if let environment = testOptions. environment {
69
- testJsArguments += [ " --environment " , environment]
72
+ testJsArguments. append ( " --environment " )
73
+ testJsArguments. append ( environment)
70
74
}
71
75
if testOptions. inspect {
72
- testJsArguments += [ " --inspect " ]
76
+ testJsArguments. append ( " --inspect " )
73
77
}
74
78
75
79
let xctestCoverageFile = outputDir. appending ( path: " XCTest.profraw " )
76
80
do {
77
81
var extraArguments = testJsArguments
78
82
if testOptions. packageOptions. enableCodeCoverage {
79
- extraArguments += [ " --coverage-file " , xctestCoverageFile. path]
83
+ extraArguments. append ( " --coverage-file " )
84
+ extraArguments. append ( xctestCoverageFile. path)
80
85
}
81
- extraArguments += [ " -- " ]
82
- extraArguments += testLibraryArguments
83
- extraArguments += testOptions. filter
86
+ extraArguments. append ( " -- " )
87
+ extraArguments. append ( contentsOf : testLibraryArguments)
88
+ extraArguments. append ( contentsOf : testOptions. filter)
84
89
85
90
try PackageToJS . runSingleTestingLibrary (
86
91
testRunner: testRunner, currentDirectoryURL: currentDirectoryURL,
87
92
extraArguments: extraArguments,
93
+ testParser: testOptions. verbose ? nil : FancyTestsParser ( write: { print ( $0, terminator: " " ) } ) ,
88
94
testOptions: testOptions
89
95
)
90
96
}
91
97
let swiftTestingCoverageFile = outputDir. appending ( path: " SwiftTesting.profraw " )
92
98
do {
93
99
var extraArguments = testJsArguments
94
100
if testOptions. packageOptions. enableCodeCoverage {
95
- extraArguments += [ " --coverage-file " , swiftTestingCoverageFile. path]
101
+ extraArguments. append ( " --coverage-file " )
102
+ extraArguments. append ( swiftTestingCoverageFile. path)
103
+ }
104
+ extraArguments. append ( " -- " )
105
+ extraArguments. append ( " --testing-library " )
106
+ extraArguments. append ( " swift-testing " )
107
+ extraArguments. append ( contentsOf: testLibraryArguments)
108
+ for filter in testOptions. filter {
109
+ extraArguments. append ( " --filter " )
110
+ extraArguments. append ( filter)
96
111
}
97
- extraArguments += [ " -- " , " --testing-library " , " swift-testing " ]
98
- extraArguments += testLibraryArguments
99
- extraArguments += testOptions. filter. flatMap { [ " --filter " , $0] }
100
112
101
113
try PackageToJS . runSingleTestingLibrary (
102
114
testRunner: testRunner, currentDirectoryURL: currentDirectoryURL,
@@ -106,7 +118,7 @@ struct PackageToJS {
106
118
}
107
119
108
120
if testOptions. packageOptions. enableCodeCoverage {
109
- let profrawFiles = [ xctestCoverageFile, swiftTestingCoverageFile] . filter { FileManager . default. fileExists ( atPath: $0. path ) }
121
+ let profrawFiles = [ xctestCoverageFile. path , swiftTestingCoverageFile. path ] . filter { FileManager . default. fileExists ( atPath: $0) }
110
122
do {
111
123
try PackageToJS . postProcessCoverageFiles ( outputDir: outputDir, profrawFiles: profrawFiles)
112
124
} catch {
@@ -119,38 +131,97 @@ struct PackageToJS {
119
131
testRunner: URL ,
120
132
currentDirectoryURL: URL ,
121
133
extraArguments: [ String ] ,
134
+ testParser: FancyTestsParser ? = nil ,
122
135
testOptions: TestOptions
123
136
) throws {
124
137
let node = try which ( " node " )
125
- let arguments = [ " --experimental-wasi-unstable-preview1 " ] + testOptions. extraNodeArguments + [ testRunner. path] + extraArguments
138
+ var arguments = [ " --experimental-wasi-unstable-preview1 " ]
139
+ arguments. append ( contentsOf: testOptions. extraNodeArguments)
140
+ arguments. append ( testRunner. path)
141
+ arguments. append ( contentsOf: extraArguments)
142
+
126
143
print ( " Running test... " )
127
144
logCommandExecution ( node. path, arguments)
128
145
129
146
let task = Process ( )
130
147
task. executableURL = node
131
148
task. arguments = arguments
149
+
150
+ var finalize : ( ) -> Void = { }
151
+ if let testParser = testParser {
152
+ let stdoutBuffer = LineBuffer { line in
153
+ testParser. onLine ( line)
154
+ }
155
+ let stdoutPipe = Pipe ( )
156
+ stdoutPipe. fileHandleForReading. readabilityHandler = { handle in
157
+ stdoutBuffer. append ( handle. availableData)
158
+ }
159
+ task. standardOutput = stdoutPipe
160
+ finalize = {
161
+ if let data = try ? stdoutPipe. fileHandleForReading. readToEnd ( ) {
162
+ stdoutBuffer. append ( data)
163
+ }
164
+ stdoutBuffer. flush ( )
165
+ testParser. finalize ( )
166
+ }
167
+ }
168
+
132
169
task. currentDirectoryURL = currentDirectoryURL
133
170
try task. forwardTerminationSignals {
134
171
try task. run ( )
135
172
task. waitUntilExit ( )
136
173
}
174
+ finalize ( )
137
175
// swift-testing returns EX_UNAVAILABLE (which is 69 in wasi-libc) for "no tests found"
138
- guard task . terminationStatus == 0 || task. terminationStatus == 69 else {
176
+ guard [ 0 , 69 ] . contains ( task. terminationStatus) else {
139
177
throw PackageToJSError ( " Test failed with status \( task. terminationStatus) " )
140
178
}
141
179
}
142
180
143
- static func postProcessCoverageFiles( outputDir: URL , profrawFiles: [ URL ] ) throws {
181
+ static func postProcessCoverageFiles( outputDir: URL , profrawFiles: [ String ] ) throws {
144
182
let mergedCoverageFile = outputDir. appending ( path: " default.profdata " )
145
183
do {
146
184
// Merge the coverage files by llvm-profdata
147
- let arguments = [ " merge " , " -sparse " , " -output " , mergedCoverageFile. path] + profrawFiles. map { $0 . path }
185
+ let arguments = [ " merge " , " -sparse " , " -output " , mergedCoverageFile. path] + profrawFiles
148
186
let llvmProfdata = try which ( " llvm-profdata " )
149
187
logCommandExecution ( llvmProfdata. path, arguments)
150
188
try runCommand ( llvmProfdata, arguments)
151
189
print ( " Saved profile data to \( mergedCoverageFile. path) " )
152
190
}
153
191
}
192
+
193
+ class LineBuffer : @unchecked Sendable {
194
+ let lock = NSLock ( )
195
+ var buffer = " "
196
+ let handler : ( String ) -> Void
197
+
198
+ init ( handler: @escaping ( String ) -> Void ) {
199
+ self . handler = handler
200
+ }
201
+
202
+ func append( _ data: Data ) {
203
+ let string = String ( data: data, encoding: . utf8) ?? " "
204
+ append ( string)
205
+ }
206
+
207
+ func append( _ data: String ) {
208
+ lock. lock ( )
209
+ defer { lock. unlock ( ) }
210
+ buffer. append ( data)
211
+ let lines = buffer. split ( separator: " \n " , omittingEmptySubsequences: false )
212
+ for line in lines. dropLast ( ) {
213
+ handler ( String ( line) )
214
+ }
215
+ buffer = String ( lines. last ?? " " )
216
+ }
217
+
218
+ func flush( ) {
219
+ lock. lock ( )
220
+ defer { lock. unlock ( ) }
221
+ handler ( buffer)
222
+ buffer = " "
223
+ }
224
+ }
154
225
}
155
226
156
227
struct PackageToJSError : Swift . Error , CustomStringConvertible {
@@ -509,12 +580,12 @@ struct PackagingPlanner {
509
580
}
510
581
511
582
let inputPath = selfPackageDir. appending ( path: file)
512
- let conditions = [
583
+ let conditions : [ String : Bool ] = [
513
584
" USE_SHARED_MEMORY " : triple == " wasm32-unknown-wasip1-threads " ,
514
585
" IS_WASI " : triple. hasPrefix ( " wasm32-unknown-wasi " ) ,
515
586
" USE_WASI_CDN " : options. useCDN,
516
587
]
517
- let constantSubstitutions = [
588
+ let constantSubstitutions : [ String : String ] = [
518
589
" PACKAGE_TO_JS_MODULE_PATH " : wasmFilename,
519
590
" PACKAGE_TO_JS_PACKAGE_NAME " : options. packageName ?? packageId. lowercased ( ) ,
520
591
]
@@ -529,11 +600,13 @@ struct PackagingPlanner {
529
600
if let wasmImportsPath = wasmImportsPath {
530
601
let wasmImportsPath = $1. resolve ( path: wasmImportsPath)
531
602
let importEntries = try JSONDecoder ( ) . decode ( [ ImportEntry ] . self, from: Data ( contentsOf: wasmImportsPath) )
532
- let memoryImport = importEntries. first { $0. module == " env " && $0. name == " memory " }
603
+ let memoryImport = importEntries. first {
604
+ $0. module == " env " && $0. name == " memory "
605
+ }
533
606
if case . memory( let type) = memoryImport? . kind {
534
- substitutions [ " PACKAGE_TO_JS_MEMORY_INITIAL " ] = " \( type. minimum) "
535
- substitutions [ " PACKAGE_TO_JS_MEMORY_MAXIMUM " ] = " \ ( type. maximum ?? type. minimum) "
536
- substitutions [ " PACKAGE_TO_JS_MEMORY_SHARED " ] = " \( type. shared) "
607
+ substitutions [ " PACKAGE_TO_JS_MEMORY_INITIAL " ] = type. minimum. description
608
+ substitutions [ " PACKAGE_TO_JS_MEMORY_MAXIMUM " ] = ( type. maximum ?? type. minimum) . description
609
+ substitutions [ " PACKAGE_TO_JS_MEMORY_SHARED " ] = type. shared. description
537
610
}
538
611
}
539
612
0 commit comments