@@ -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 }
@@ -59,44 +61,54 @@ struct PackageToJS {
5961 var testJsArguments : [ String ] = [ ]
6062 var testLibraryArguments : [ String ] = [ ]
6163 if testOptions. listTests {
62- testLibraryArguments += [ " --list-tests " ]
64+ testLibraryArguments. append ( " --list-tests " )
6365 }
6466 if let prelude = testOptions. prelude {
6567 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)
6770 }
6871 if let environment = testOptions. environment {
69- testJsArguments += [ " --environment " , environment]
72+ testJsArguments. append ( " --environment " )
73+ testJsArguments. append ( environment)
7074 }
7175 if testOptions. inspect {
72- testJsArguments += [ " --inspect " ]
76+ testJsArguments. append ( " --inspect " )
7377 }
7478
7579 let xctestCoverageFile = outputDir. appending ( path: " XCTest.profraw " )
7680 do {
7781 var extraArguments = testJsArguments
7882 if testOptions. packageOptions. enableCodeCoverage {
79- extraArguments += [ " --coverage-file " , xctestCoverageFile. path]
83+ extraArguments. append ( " --coverage-file " )
84+ extraArguments. append ( xctestCoverageFile. path)
8085 }
81- extraArguments += [ " -- " ]
82- extraArguments += testLibraryArguments
83- extraArguments += testOptions. filter
86+ extraArguments. append ( " -- " )
87+ extraArguments. append ( contentsOf : testLibraryArguments)
88+ extraArguments. append ( contentsOf : testOptions. filter)
8489
8590 try PackageToJS . runSingleTestingLibrary (
8691 testRunner: testRunner, currentDirectoryURL: currentDirectoryURL,
8792 extraArguments: extraArguments,
93+ testParser: testOptions. verbose ? nil : FancyTestsParser ( write: { print ( $0, terminator: " " ) } ) ,
8894 testOptions: testOptions
8995 )
9096 }
9197 let swiftTestingCoverageFile = outputDir. appending ( path: " SwiftTesting.profraw " )
9298 do {
9399 var extraArguments = testJsArguments
94100 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)
96111 }
97- extraArguments += [ " -- " , " --testing-library " , " swift-testing " ]
98- extraArguments += testLibraryArguments
99- extraArguments += testOptions. filter. flatMap { [ " --filter " , $0] }
100112
101113 try PackageToJS . runSingleTestingLibrary (
102114 testRunner: testRunner, currentDirectoryURL: currentDirectoryURL,
@@ -106,7 +118,7 @@ struct PackageToJS {
106118 }
107119
108120 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) }
110122 do {
111123 try PackageToJS . postProcessCoverageFiles ( outputDir: outputDir, profrawFiles: profrawFiles)
112124 } catch {
@@ -119,38 +131,97 @@ struct PackageToJS {
119131 testRunner: URL ,
120132 currentDirectoryURL: URL ,
121133 extraArguments: [ String ] ,
134+ testParser: FancyTestsParser ? = nil ,
122135 testOptions: TestOptions
123136 ) throws {
124137 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+
126143 print ( " Running test... " )
127144 logCommandExecution ( node. path, arguments)
128145
129146 let task = Process ( )
130147 task. executableURL = node
131148 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+
132169 task. currentDirectoryURL = currentDirectoryURL
133170 try task. forwardTerminationSignals {
134171 try task. run ( )
135172 task. waitUntilExit ( )
136173 }
174+ finalize ( )
137175 // 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 {
139177 throw PackageToJSError ( " Test failed with status \( task. terminationStatus) " )
140178 }
141179 }
142180
143- static func postProcessCoverageFiles( outputDir: URL , profrawFiles: [ URL ] ) throws {
181+ static func postProcessCoverageFiles( outputDir: URL , profrawFiles: [ String ] ) throws {
144182 let mergedCoverageFile = outputDir. appending ( path: " default.profdata " )
145183 do {
146184 // 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
148186 let llvmProfdata = try which ( " llvm-profdata " )
149187 logCommandExecution ( llvmProfdata. path, arguments)
150188 try runCommand ( llvmProfdata, arguments)
151189 print ( " Saved profile data to \( mergedCoverageFile. path) " )
152190 }
153191 }
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+ }
154225}
155226
156227struct PackageToJSError : Swift . Error , CustomStringConvertible {
@@ -509,12 +580,12 @@ struct PackagingPlanner {
509580 }
510581
511582 let inputPath = selfPackageDir. appending ( path: file)
512- let conditions = [
583+ let conditions : [ String : Bool ] = [
513584 " USE_SHARED_MEMORY " : triple == " wasm32-unknown-wasip1-threads " ,
514585 " IS_WASI " : triple. hasPrefix ( " wasm32-unknown-wasi " ) ,
515586 " USE_WASI_CDN " : options. useCDN,
516587 ]
517- let constantSubstitutions = [
588+ let constantSubstitutions : [ String : String ] = [
518589 " PACKAGE_TO_JS_MODULE_PATH " : wasmFilename,
519590 " PACKAGE_TO_JS_PACKAGE_NAME " : options. packageName ?? packageId. lowercased ( ) ,
520591 ]
@@ -529,11 +600,13 @@ struct PackagingPlanner {
529600 if let wasmImportsPath = wasmImportsPath {
530601 let wasmImportsPath = $1. resolve ( path: wasmImportsPath)
531602 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+ }
533606 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
537610 }
538611 }
539612
0 commit comments