|
| 1 | +import Foundation |
| 2 | +import Testing |
| 3 | + |
| 4 | +@testable import PackageToJS |
| 5 | + |
| 6 | +@Suite struct WasmOptTests { |
| 7 | + |
| 8 | + /// A mock system that simulates wasm-opt not being available |
| 9 | + class MockPackagingSystemWithoutWasmOpt: PackagingSystem { |
| 10 | + var warnings: [String] = [] |
| 11 | + var wasmOptCalls: [(arguments: [String], input: String, output: String)] = [] |
| 12 | + |
| 13 | + func npmInstall(packageDir: String) throws { |
| 14 | + // No-op for testing |
| 15 | + } |
| 16 | + |
| 17 | + func wasmOpt(_ arguments: [String], input: String, output: String) throws { |
| 18 | + wasmOptCalls.append((arguments, input, output)) |
| 19 | + |
| 20 | + // Simulate wasm-opt not found by using the same logic as DefaultPackagingSystem |
| 21 | + // but without the actual which() call succeeding |
| 22 | + warnings.append("Warning: wasm-opt is not installed, optimizations will not be applied") |
| 23 | + |
| 24 | + // Test the file copy logic that would happen when wasm-opt is not found |
| 25 | + // (This matches the fixed behavior that removes existing files first) |
| 26 | + if FileManager.default.fileExists(atPath: output) { |
| 27 | + try FileManager.default.removeItem(atPath: output) |
| 28 | + } |
| 29 | + try FileManager.default.copyItem(atPath: input, toPath: output) |
| 30 | + } |
| 31 | + } |
| 32 | + |
| 33 | + /// A mock system that fails when copying files (to test error handling) |
| 34 | + class MockPackagingSystemWithCopyFailure: PackagingSystem { |
| 35 | + var wasmOptCalls: [(arguments: [String], input: String, output: String)] = [] |
| 36 | + |
| 37 | + func npmInstall(packageDir: String) throws { |
| 38 | + // No-op for testing |
| 39 | + } |
| 40 | + |
| 41 | + func wasmOpt(_ arguments: [String], input: String, output: String) throws { |
| 42 | + wasmOptCalls.append((arguments, input, output)) |
| 43 | + |
| 44 | + // Simulate the case where wasm-opt is not found and file copy fails |
| 45 | + throw PackageToJSError("Permission denied when copying wasm file") |
| 46 | + } |
| 47 | + } |
| 48 | + |
| 49 | + @Test func wasmOptNotInstalledFallbackWorksCorrectly() throws { |
| 50 | + try withTemporaryDirectory { tempDir, _ in |
| 51 | + // Create a dummy input wasm file |
| 52 | + let inputFile = tempDir.appendingPathComponent("input.wasm") |
| 53 | + let outputFile = tempDir.appendingPathComponent("output.wasm") |
| 54 | + let dummyContent = Data("dummy wasm content".utf8) |
| 55 | + try dummyContent.write(to: inputFile) |
| 56 | + |
| 57 | + let mockSystem = MockPackagingSystemWithoutWasmOpt() |
| 58 | + |
| 59 | + // This should copy the file instead of optimizing |
| 60 | + try mockSystem.wasmOpt(["-Os"], input: inputFile.path, output: outputFile.path) |
| 61 | + |
| 62 | + // Verify the file was copied |
| 63 | + #expect(FileManager.default.fileExists(atPath: outputFile.path)) |
| 64 | + let copiedContent = try Data(contentsOf: outputFile) |
| 65 | + #expect(copiedContent == dummyContent) |
| 66 | + |
| 67 | + // Verify warning was recorded |
| 68 | + #expect(mockSystem.warnings.count == 1) |
| 69 | + #expect(mockSystem.warnings[0].contains("wasm-opt is not installed")) |
| 70 | + |
| 71 | + // Verify the call was made |
| 72 | + #expect(mockSystem.wasmOptCalls.count == 1) |
| 73 | + #expect(mockSystem.wasmOptCalls[0].arguments == ["-Os"]) |
| 74 | + } |
| 75 | + } |
| 76 | + |
| 77 | + @Test func wasmOptNotInstalledHandlesExistingOutputFile() throws { |
| 78 | + try withTemporaryDirectory { tempDir, _ in |
| 79 | + // Create a dummy input wasm file |
| 80 | + let inputFile = tempDir.appendingPathComponent("input.wasm") |
| 81 | + let outputFile = tempDir.appendingPathComponent("output.wasm") |
| 82 | + let inputContent = Data("input wasm content".utf8) |
| 83 | + let existingContent = Data("existing output content".utf8) |
| 84 | + |
| 85 | + try inputContent.write(to: inputFile) |
| 86 | + try existingContent.write(to: outputFile) |
| 87 | + |
| 88 | + let mockSystem = MockPackagingSystemWithoutWasmOpt() |
| 89 | + |
| 90 | + // This should overwrite the existing output file |
| 91 | + try mockSystem.wasmOpt(["-Os"], input: inputFile.path, output: outputFile.path) |
| 92 | + |
| 93 | + // Verify the output file has the input content (not the existing content) |
| 94 | + #expect(FileManager.default.fileExists(atPath: outputFile.path)) |
| 95 | + let finalContent = try Data(contentsOf: outputFile) |
| 96 | + #expect(finalContent == inputContent) |
| 97 | + #expect(finalContent != existingContent) |
| 98 | + } |
| 99 | + } |
| 100 | + |
| 101 | + @Test func wasmOptCopyFailureThrowsError() throws { |
| 102 | + try withTemporaryDirectory { tempDir, _ in |
| 103 | + let inputFile = tempDir.appendingPathComponent("input.wasm") |
| 104 | + let outputFile = tempDir.appendingPathComponent("output.wasm") |
| 105 | + |
| 106 | + let mockSystem = MockPackagingSystemWithCopyFailure() |
| 107 | + |
| 108 | + // This should throw an error |
| 109 | + #expect(throws: PackageToJSError.self) { |
| 110 | + try mockSystem.wasmOpt(["-Os"], input: inputFile.path, output: outputFile.path) |
| 111 | + } |
| 112 | + |
| 113 | + // Verify the call was made |
| 114 | + #expect(mockSystem.wasmOptCalls.count == 1) |
| 115 | + } |
| 116 | + } |
| 117 | + |
| 118 | + @Test func realDefaultPackagingSystemFallbackBehavior() throws { |
| 119 | + try withTemporaryDirectory { tempDir, _ in |
| 120 | + // Create a dummy input wasm file |
| 121 | + let inputFile = tempDir.appendingPathComponent("input.wasm") |
| 122 | + let outputFile = tempDir.appendingPathComponent("output.wasm") |
| 123 | + let dummyContent = Data("dummy wasm content".utf8) |
| 124 | + try dummyContent.write(to: inputFile) |
| 125 | + |
| 126 | + var capturedWarnings: [String] = [] |
| 127 | + let realSystem = DefaultPackagingSystem { warning in |
| 128 | + capturedWarnings.append(warning) |
| 129 | + } |
| 130 | + |
| 131 | + // Temporarily move wasm-opt out of the way to simulate it not being installed |
| 132 | + let wasmOptPath = "/opt/homebrew/bin/wasm-opt" |
| 133 | + let tempWasmOptPath = "/tmp/wasm-opt-backup-for-test" |
| 134 | + |
| 135 | + let wasmOptExists = FileManager.default.fileExists(atPath: wasmOptPath) |
| 136 | + if wasmOptExists { |
| 137 | + try? FileManager.default.moveItem(atPath: wasmOptPath, toPath: tempWasmOptPath) |
| 138 | + } |
| 139 | + |
| 140 | + defer { |
| 141 | + // Restore wasm-opt if it existed |
| 142 | + if wasmOptExists { |
| 143 | + try? FileManager.default.moveItem(atPath: tempWasmOptPath, toPath: wasmOptPath) |
| 144 | + } |
| 145 | + } |
| 146 | + |
| 147 | + // This should fall back to copying since wasm-opt is not available |
| 148 | + try realSystem.wasmOpt(["-Os"], input: inputFile.path, output: outputFile.path) |
| 149 | + |
| 150 | + // Verify the file was copied |
| 151 | + #expect(FileManager.default.fileExists(atPath: outputFile.path)) |
| 152 | + let copiedContent = try Data(contentsOf: outputFile) |
| 153 | + #expect(copiedContent == dummyContent) |
| 154 | + |
| 155 | + // Verify warning was issued |
| 156 | + #expect(capturedWarnings.count >= 1) |
| 157 | + #expect(capturedWarnings[0].contains("wasm-opt is not installed")) |
| 158 | + } |
| 159 | + } |
| 160 | +} |
0 commit comments