diff --git a/Plugins/PackageToJS/Sources/PackageToJS.swift b/Plugins/PackageToJS/Sources/PackageToJS.swift index a3083089..9a3f4c54 100644 --- a/Plugins/PackageToJS/Sources/PackageToJS.swift +++ b/Plugins/PackageToJS/Sources/PackageToJS.swift @@ -293,9 +293,11 @@ extension PackagingSystem { final class DefaultPackagingSystem: PackagingSystem { private let printWarning: (String) -> Void + private let which: (String) throws -> URL - init(printWarning: @escaping (String) -> Void) { + init(printWarning: @escaping (String) -> Void, which: @escaping (String) throws -> URL = which(_:)) { self.printWarning = printWarning + self.which = which } func npmInstall(packageDir: String) throws { @@ -309,6 +311,10 @@ final class DefaultPackagingSystem: PackagingSystem { func wasmOpt(_ arguments: [String], input: String, output: String) throws { guard let wasmOpt = try? which("wasm-opt") else { _ = warnMissingWasmOpt + // Remove existing output file if it exists (to match wasm-opt behavior) + if FileManager.default.fileExists(atPath: output) { + try FileManager.default.removeItem(atPath: output) + } try FileManager.default.copyItem(atPath: input, toPath: output) return } diff --git a/Plugins/PackageToJS/Tests/DefaultPackagingSystemTests.swift b/Plugins/PackageToJS/Tests/DefaultPackagingSystemTests.swift new file mode 100644 index 00000000..7de9c48d --- /dev/null +++ b/Plugins/PackageToJS/Tests/DefaultPackagingSystemTests.swift @@ -0,0 +1,60 @@ +import Foundation +import Testing + +@testable import PackageToJS + +@Suite struct DefaultPackagingSystemTests { + + @Test func wasmOptFallbackHandlesNewOutputFile() throws { + try withTemporaryDirectory { tempDir, _ in + let inputFile = tempDir.appendingPathComponent("input.wasm") + let outputFile = tempDir.appendingPathComponent("output.wasm") + let inputContent = Data("input wasm content".utf8) + try inputContent.write(to: inputFile) + + var warnings: [String] = [] + // Create system with mock which function that always fails to find wasm-opt + let system = DefaultPackagingSystem( + printWarning: { warnings.append($0) }, + which: { _ in throw PackageToJSError("wasm-opt not found") } + ) + + // This should work - fallback should copy file + try system.wasmOpt(["-Os"], input: inputFile.path, output: outputFile.path) + + // Verify the output file was created with input content + let finalContent = try Data(contentsOf: outputFile) + #expect(finalContent == inputContent) + #expect(warnings.contains { $0.contains("wasm-opt is not installed") }) + } + } + + @Test func wasmOptFallbackHandlesExistingOutputFile() throws { + try withTemporaryDirectory { tempDir, _ in + let inputFile = tempDir.appendingPathComponent("input.wasm") + let outputFile = tempDir.appendingPathComponent("output.wasm") + let inputContent = Data("input wasm content".utf8) + let existingContent = Data("existing output content".utf8) + + // Create input file and existing output file + try inputContent.write(to: inputFile) + try existingContent.write(to: outputFile) + + var warnings: [String] = [] + // Create system with mock which function that always fails to find wasm-opt + let system = DefaultPackagingSystem( + printWarning: { warnings.append($0) }, + which: { _ in throw PackageToJSError("wasm-opt not found") } + ) + + // This should work - fallback should overwrite existing file + try system.wasmOpt(["-Os"], input: inputFile.path, output: outputFile.path) + + // Verify the output file was overwritten with input content + let finalContent = try Data(contentsOf: outputFile) + #expect(finalContent == inputContent) + #expect(finalContent != existingContent) + #expect(warnings.contains { $0.contains("wasm-opt is not installed") }) + } + } +}