From 4ffa3cc1bf9d8c01537199633976dd418e5b8ca2 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Wed, 22 Oct 2025 23:56:02 +0100 Subject: [PATCH 1/4] Remove `#if canImport(Testing)` as unnecessary in Swift 6.0+ --- Tests/WasmKitTests/ExecutionTests.swift | 255 ++++++++++++------------ 1 file changed, 126 insertions(+), 129 deletions(-) diff --git a/Tests/WasmKitTests/ExecutionTests.swift b/Tests/WasmKitTests/ExecutionTests.swift index e5b61c87..3d95b1c5 100644 --- a/Tests/WasmKitTests/ExecutionTests.swift +++ b/Tests/WasmKitTests/ExecutionTests.swift @@ -1,150 +1,147 @@ -#if canImport(Testing) - import WAT - import Testing +import WAT +import Testing - @testable import WasmKit +@testable import WasmKit - @Suite - struct ExecutionTests { +@Suite +struct ExecutionTests { - @Test - func dropWithRelinkingOptimization() throws { - let module = try parseWasm( - bytes: wat2wasm( - """ - (module - (func (export "_start") (result i32) (local $x i32) - (i32.const 42) - (i32.const 0) - (i32.eqz) - (drop) - (local.set $x) - (local.get $x) - ) + @Test + func dropWithRelinkingOptimization() throws { + let module = try parseWasm( + bytes: wat2wasm( + """ + (module + (func (export "_start") (result i32) (local $x i32) + (i32.const 42) + (i32.const 0) + (i32.eqz) + (drop) + (local.set $x) + (local.get $x) ) - """ ) + """ ) - let engine = Engine() - let store = Store(engine: engine) - let instance = try module.instantiate(store: store) - let _start = try #require(instance.exports[function: "_start"]) - let results = try _start() - #expect(results == [.i32(42)]) - } + ) + let engine = Engine() + let store = Store(engine: engine) + let instance = try module.instantiate(store: store) + let _start = try #require(instance.exports[function: "_start"]) + let results = try _start() + #expect(results == [.i32(42)]) + } - @Test - func updateCurrentMemoryCacheOnGrow() throws { - let module = try parseWasm( - bytes: wat2wasm( - """ - (module - (memory 0) - (func (export "_start") (result i32) - (drop (memory.grow (i32.const 1))) - (i32.store (i32.const 1) (i32.const 42)) - (i32.load (i32.const 1)) - ) + @Test + func updateCurrentMemoryCacheOnGrow() throws { + let module = try parseWasm( + bytes: wat2wasm( + """ + (module + (memory 0) + (func (export "_start") (result i32) + (drop (memory.grow (i32.const 1))) + (i32.store (i32.const 1) (i32.const 42)) + (i32.load (i32.const 1)) ) - """ ) + """ ) - let engine = Engine() - let store = Store(engine: engine) - let instance = try module.instantiate(store: store) - let _start = try #require(instance.exports[function: "_start"]) - let results = try _start() - #expect(results == [.i32(42)]) - } + ) + let engine = Engine() + let store = Store(engine: engine) + let instance = try module.instantiate(store: store) + let _start = try #require(instance.exports[function: "_start"]) + let results = try _start() + #expect(results == [.i32(42)]) + } - func expectTrap(_ wat: String, assertTrap: (Trap) throws -> Void) throws { - let module = try parseWasm( - bytes: wat2wasm(wat, options: EncodeOptions(nameSection: true)) - ) + func expectTrap(_ wat: String, assertTrap: (Trap) throws -> Void) throws { + let module = try parseWasm( + bytes: wat2wasm(wat, options: EncodeOptions(nameSection: true)) + ) - let engine = Engine() - let store = Store(engine: engine) - var imports = Imports() - for importEntry in module.imports { - guard case .function(let type) = importEntry.descriptor else { continue } - let function = try Function( - store: store, - type: module.resolveFunctionType(type), - body: { _, _ in - return [] - } - ) - imports.define(importEntry, .function(function)) - } - let instance = try module.instantiate(store: store, imports: imports) - let _start = try #require(instance.exports[function: "_start"]) + let engine = Engine() + let store = Store(engine: engine) + var imports = Imports() + for importEntry in module.imports { + guard case .function(let type) = importEntry.descriptor else { continue } + let function = try Function( + store: store, + type: module.resolveFunctionType(type), + body: { _, _ in + return [] + } + ) + imports.define(importEntry, .function(function)) + } + let instance = try module.instantiate(store: store, imports: imports) + let _start = try #require(instance.exports[function: "_start"]) - let trap: Trap - do { - let _ = try _start() - #expect((false), "Expected trap") - return - } catch let _trap as Trap { - trap = _trap - } catch { - #expect((false), "Expected trap: \(error)") - return - } - try assertTrap(trap) + let trap: Trap + do { + let _ = try _start() + #expect((false), "Expected trap") + return + } catch let _trap as Trap { + trap = _trap + } catch { + #expect((false), "Expected trap: \(error)") + return } + try assertTrap(trap) + } - @Test - func backtraceBasic() throws { - try expectTrap( - """ - (module - (func $foo - unreachable - ) - (func $bar - (call $foo) - ) - (func (export "_start") - (call $bar) - ) + @Test + func backtraceBasic() throws { + try expectTrap( + """ + (module + (func $foo + unreachable ) - """ - ) { trap in - #expect( - trap.backtrace?.symbols.compactMap(\.?.name) == [ - "foo", - "bar", - "_start", - ]) - } + (func $bar + (call $foo) + ) + (func (export "_start") + (call $bar) + ) + ) + """ + ) { trap in + #expect( + trap.backtrace?.symbols.compactMap(\.?.name) == [ + "foo", + "bar", + "_start", + ]) } + } - @Test - func backtraceWithImports() throws { - try expectTrap( - """ - (module - (func (import "env" "bar")) - (func - unreachable - ) - (func $bar - (call 1) - ) - (func (export "_start") - (call $bar) - ) + @Test + func backtraceWithImports() throws { + try expectTrap( + """ + (module + (func (import "env" "bar")) + (func + unreachable ) - """ - ) { trap in - #expect( - trap.backtrace?.symbols.compactMap(\.?.name) == [ - "wasm function[1]", - "bar", - "_start", - ]) - } + (func $bar + (call 1) + ) + (func (export "_start") + (call $bar) + ) + ) + """ + ) { trap in + #expect( + trap.backtrace?.symbols.compactMap(\.?.name) == [ + "wasm function[1]", + "bar", + "_start", + ]) } } - -#endif +} From a19936ffca403b84e9d7508d73877b767726f3b1 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Wed, 22 Oct 2025 23:58:23 +0100 Subject: [PATCH 2/4] Fix formatting in `ExecutionTests.swift` --- Tests/WasmKitTests/ExecutionTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/WasmKitTests/ExecutionTests.swift b/Tests/WasmKitTests/ExecutionTests.swift index 3d95b1c5..501789ed 100644 --- a/Tests/WasmKitTests/ExecutionTests.swift +++ b/Tests/WasmKitTests/ExecutionTests.swift @@ -1,5 +1,5 @@ -import WAT import Testing +import WAT @testable import WasmKit From 04a755ac8643d6120868f2fda5babb451a55c194 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Thu, 23 Oct 2025 00:17:19 +0100 Subject: [PATCH 3/4] Remove remaining uses of `canImport(Testing)` --- Tests/WASITests/IntegrationTests.swift | 383 +++++++++--------- .../SandboxPrimitives/OpenParentTests.swift | 66 ++- .../RandomBufferGeneratorTests.swift | 62 ++- Tests/WASITests/WASITests.swift | 230 ++++++----- Tests/WATTests/EncoderTests.swift | 290 +++++++------ Tests/WATTests/LexerTests.swift | 178 ++++---- Tests/WATTests/ParserTests.swift | 344 ++++++++-------- .../Execution/HostModuleTests.swift | 146 ++++--- .../Runtime/StoreAllocatorTests.swift | 86 ++-- .../FuzzTranslatorRegressionTests.swift | 66 ++- Tests/WasmKitTests/SpectestTests.swift | 84 ++-- Tests/WasmKitTests/Trait+Platform.swift | 44 +- 12 files changed, 977 insertions(+), 1002 deletions(-) diff --git a/Tests/WASITests/IntegrationTests.swift b/Tests/WASITests/IntegrationTests.swift index c4aba1ad..c8400147 100644 --- a/Tests/WASITests/IntegrationTests.swift +++ b/Tests/WASITests/IntegrationTests.swift @@ -1,215 +1,212 @@ -#if canImport(Testing) - - import Foundation - import SystemPackage - import WasmKit - import WasmKitWASI - import Testing - - @Suite - struct IntegrationTests { - - #if !os(Android) - @Test( - arguments: try IntegrationTests.discoverAllTests() - ) - func run(test: URL) throws { - try runTest(path: test) - } - #endif - - struct FailedTest { - let suite: String - let name: String - let path: URL - let reason: String - } - struct SuiteManifest: Codable { - let name: String +import Foundation +import SystemPackage +import WasmKit +import WasmKitWASI +import Testing + +@Suite +struct IntegrationTests { + + #if !os(Android) + @Test( + arguments: try IntegrationTests.discoverAllTests() + ) + func run(test: URL) throws { + try runTest(path: test) } + #endif - static var skipTests: [String: Set] { - #if os(Windows) - return [ - "WASI Assemblyscript tests": [], - "WASI C tests": [ - "fdopendir-with-access", - "fopen-with-access", - "lseek", - "pread-with-access", - "pwrite-with-access", - "pwrite-with-append", - "sock_shutdown-invalid_fd", - "sock_shutdown-not_sock", - "stat-dev-ino", - ], - "WASI Rust tests": [ - "close_preopen", - "dangling_fd", - "dangling_symlink", - "dir_fd_op_failures", - "directory_seek", - "fd_advise", - "fd_fdstat_set_rights", - "fd_filestat_set", - "fd_flags_set", - "fd_readdir", - "file_allocate", - "file_pread_pwrite", - "file_seek_tell", - "file_truncation", - "file_unbuffered_write", - "fstflags_validate", - "interesting_paths", - "isatty", - "nofollow_errors", - "overwrite_preopen", - "path_exists", - "path_filestat", - "path_link", - "path_open_create_existing", - "path_open_dirfd_not_dir", - "path_open_missing", - "path_open_nonblock", - "path_open_preopen", - "path_open_read_write", - "path_rename", - "path_rename_dir_trailing_slashes", - "path_symlink_trailing_slashes", - "poll_oneoff_stdio", - "readlink", - "remove_directory_trailing_slashes", - "remove_nonempty_directory", - "renumber", - "sched_yield", - "stdio", - "symlink_create", - "symlink_filestat", - "symlink_loop", - "truncation_rights", - "unlink_file_trailing_slashes", - ], - ] - #else - var tests: [String: Set] = [ - "WASI Rust tests": [ - "path_link", - "dir_fd_op_failures", - "pwrite-with-append", - "poll_oneoff_stdio", - "overwrite_preopen", - "path_filestat", - "renumber", - "symlink_filestat", - "path_open_read_write", - "path_open_preopen", - "fd_fdstat_set_rights", - "file_allocate", - "stdio", - "remove_directory_trailing_slashes", - "symlink_create", - "readlink", - "sched_yield", - ], - "WASI C tests": [ - "sock_shutdown-invalid_fd", - "sock_shutdown-not_sock", - ], - ] - #if os(Linux) - tests["WASI C tests"]?.insert("pwrite-with-append") - #endif - return tests - #endif - } + struct FailedTest { + let suite: String + let name: String + let path: URL + let reason: String + } + struct SuiteManifest: Codable { + let name: String + } - static func discoverAllTests() throws -> [URL] { - let testDir = URL(fileURLWithPath: #filePath) - .deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent() - .appendingPathComponent("Vendor/wasi-testsuite") - var tests = [URL]() - for testSuitePath in ["tests/assemblyscript/testsuite", "tests/c/testsuite", "tests/rust/testsuite"] { - let suitePath = testDir.appendingPathComponent(testSuitePath) - tests.append(contentsOf: try discoverTestsFromSuite(path: suitePath)) - } + static var skipTests: [String: Set] { + #if os(Windows) + return [ + "WASI Assemblyscript tests": [], + "WASI C tests": [ + "fdopendir-with-access", + "fopen-with-access", + "lseek", + "pread-with-access", + "pwrite-with-access", + "pwrite-with-append", + "sock_shutdown-invalid_fd", + "sock_shutdown-not_sock", + "stat-dev-ino", + ], + "WASI Rust tests": [ + "close_preopen", + "dangling_fd", + "dangling_symlink", + "dir_fd_op_failures", + "directory_seek", + "fd_advise", + "fd_fdstat_set_rights", + "fd_filestat_set", + "fd_flags_set", + "fd_readdir", + "file_allocate", + "file_pread_pwrite", + "file_seek_tell", + "file_truncation", + "file_unbuffered_write", + "fstflags_validate", + "interesting_paths", + "isatty", + "nofollow_errors", + "overwrite_preopen", + "path_exists", + "path_filestat", + "path_link", + "path_open_create_existing", + "path_open_dirfd_not_dir", + "path_open_missing", + "path_open_nonblock", + "path_open_preopen", + "path_open_read_write", + "path_rename", + "path_rename_dir_trailing_slashes", + "path_symlink_trailing_slashes", + "poll_oneoff_stdio", + "readlink", + "remove_directory_trailing_slashes", + "remove_nonempty_directory", + "renumber", + "sched_yield", + "stdio", + "symlink_create", + "symlink_filestat", + "symlink_loop", + "truncation_rights", + "unlink_file_trailing_slashes", + ], + ] + #else + var tests: [String: Set] = [ + "WASI Rust tests": [ + "path_link", + "dir_fd_op_failures", + "pwrite-with-append", + "poll_oneoff_stdio", + "overwrite_preopen", + "path_filestat", + "renumber", + "symlink_filestat", + "path_open_read_write", + "path_open_preopen", + "fd_fdstat_set_rights", + "file_allocate", + "stdio", + "remove_directory_trailing_slashes", + "symlink_create", + "readlink", + "sched_yield", + ], + "WASI C tests": [ + "sock_shutdown-invalid_fd", + "sock_shutdown-not_sock", + ], + ] + #if os(Linux) + tests["WASI C tests"]?.insert("pwrite-with-append") + #endif return tests + #endif + } + + static func discoverAllTests() throws -> [URL] { + let testDir = URL(fileURLWithPath: #filePath) + .deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent() + .appendingPathComponent("Vendor/wasi-testsuite") + var tests = [URL]() + for testSuitePath in ["tests/assemblyscript/testsuite", "tests/c/testsuite", "tests/rust/testsuite"] { + let suitePath = testDir.appendingPathComponent(testSuitePath) + tests.append(contentsOf: try discoverTestsFromSuite(path: suitePath)) } + return tests + } - static func discoverTestsFromSuite(path: URL) throws -> [URL] { - let manifestPath = path.appendingPathComponent("manifest.json") - let manifest = try JSONDecoder().decode(SuiteManifest.self, from: Data(contentsOf: manifestPath)) - - // Clean up **/*.cleanup - do { - let enumerator = FileManager.default.enumerator(at: path, includingPropertiesForKeys: nil, options: [.skipsHiddenFiles])! - for case let url as URL in enumerator { - if url.pathExtension == "cleanup" { - try FileManager.default.removeItem(at: url) - } + static func discoverTestsFromSuite(path: URL) throws -> [URL] { + let manifestPath = path.appendingPathComponent("manifest.json") + let manifest = try JSONDecoder().decode(SuiteManifest.self, from: Data(contentsOf: manifestPath)) + + // Clean up **/*.cleanup + do { + let enumerator = FileManager.default.enumerator(at: path, includingPropertiesForKeys: nil, options: [.skipsHiddenFiles])! + for case let url as URL in enumerator { + if url.pathExtension == "cleanup" { + try FileManager.default.removeItem(at: url) } } + } - let tests = try FileManager.default.contentsOfDirectory(at: path, includingPropertiesForKeys: nil, options: []) + let tests = try FileManager.default.contentsOfDirectory(at: path, includingPropertiesForKeys: nil, options: []) - let skipTests = Self.skipTests[manifest.name] ?? [] + let skipTests = Self.skipTests[manifest.name] ?? [] - var testCases = [URL]() - for test in tests { - guard test.pathExtension == "wasm" else { continue } - let testName = test.deletingPathExtension().lastPathComponent - if skipTests.contains(testName) { - continue - } - testCases.append(test) + var testCases = [URL]() + for test in tests { + guard test.pathExtension == "wasm" else { continue } + let testName = test.deletingPathExtension().lastPathComponent + if skipTests.contains(testName) { + continue } - return testCases + testCases.append(test) } + return testCases + } - struct CaseManifest: Codable { - var dirs: [String]? - var args: [String]? - var env: [String: String]? - var exitCode: UInt32? + struct CaseManifest: Codable { + var dirs: [String]? + var args: [String]? + var env: [String: String]? + var exitCode: UInt32? - static var empty: CaseManifest { - CaseManifest(dirs: nil, args: nil, env: nil, exitCode: nil) - } + static var empty: CaseManifest { + CaseManifest(dirs: nil, args: nil, env: nil, exitCode: nil) } + } - func runTest(path: URL) throws { - let manifestPath = path.deletingPathExtension().appendingPathExtension("json") - var manifest: CaseManifest - if FileManager.default.fileExists(atPath: manifestPath.path) { - let decoder = JSONDecoder() - decoder.keyDecodingStrategy = .convertFromSnakeCase - manifest = try decoder.decode(CaseManifest.self, from: Data(contentsOf: manifestPath)) - } else { - manifest = .empty - } + func runTest(path: URL) throws { + let manifestPath = path.deletingPathExtension().appendingPathExtension("json") + var manifest: CaseManifest + if FileManager.default.fileExists(atPath: manifestPath.path) { + let decoder = JSONDecoder() + decoder.keyDecodingStrategy = .convertFromSnakeCase + manifest = try decoder.decode(CaseManifest.self, from: Data(contentsOf: manifestPath)) + } else { + manifest = .empty + } - // HACK: WasmKit intentionally does not support fd_allocate - if path.lastPathComponent == "fd_advise.wasm" { - manifest.env = (manifest.env ?? [:]).merging(["NO_FD_ALLOCATE": "1"]) { _, new in new } - } + // HACK: WasmKit intentionally does not support fd_allocate + if path.lastPathComponent == "fd_advise.wasm" { + manifest.env = (manifest.env ?? [:]).merging(["NO_FD_ALLOCATE": "1"]) { _, new in new } + } - let suitePath = path.deletingLastPathComponent() + let suitePath = path.deletingLastPathComponent() - let wasi = try WASIBridgeToHost( - args: [path.path] + (manifest.args ?? []), - environment: manifest.env ?? [:], - preopens: (manifest.dirs ?? []).reduce(into: [String: String]()) { - $0[$1] = suitePath.appendingPathComponent($1).path - } - ) - let engine = Engine() - let store = Store(engine: engine) - var imports = Imports() - wasi.link(to: &imports, store: store) - let module = try parseWasm(filePath: FilePath(path.path)) - let instance = try module.instantiate(store: store, imports: imports) - let exitCode = try wasi.start(instance) - #expect(exitCode == manifest.exitCode ?? 0, "\(path.path)") - } + let wasi = try WASIBridgeToHost( + args: [path.path] + (manifest.args ?? []), + environment: manifest.env ?? [:], + preopens: (manifest.dirs ?? []).reduce(into: [String: String]()) { + $0[$1] = suitePath.appendingPathComponent($1).path + } + ) + let engine = Engine() + let store = Store(engine: engine) + var imports = Imports() + wasi.link(to: &imports, store: store) + let module = try parseWasm(filePath: FilePath(path.path)) + let instance = try module.instantiate(store: store, imports: imports) + let exitCode = try wasi.start(instance) + #expect(exitCode == manifest.exitCode ?? 0, "\(path.path)") } +} -#endif diff --git a/Tests/WASITests/Platform/SandboxPrimitives/OpenParentTests.swift b/Tests/WASITests/Platform/SandboxPrimitives/OpenParentTests.swift index 2b68cc01..acd67288 100644 --- a/Tests/WASITests/Platform/SandboxPrimitives/OpenParentTests.swift +++ b/Tests/WASITests/Platform/SandboxPrimitives/OpenParentTests.swift @@ -1,42 +1,40 @@ -#if canImport(Testing) - import Testing - import SystemPackage +import Testing +import SystemPackage - @testable import WASI +@testable import WASI - @Suite - struct OpenParentTests { - @Test - func testSplitParent() { - func check( - _ lhs: (FilePath, FilePath.Component)?, - _ rhs: (FilePath, FilePath.Component)?, - sourceLocation: SourceLocation = #_sourceLocation - ) { - switch (lhs, rhs) { - case (.none, .none): return - case (.some(let lhs), .some(let rhs)): - #expect(lhs.0 == rhs.0, sourceLocation: sourceLocation) - #expect(lhs.1 == rhs.1, sourceLocation: sourceLocation) - default: - #expect((false), "\(String(describing: lhs)) and \(String(describing: rhs)) are not equal", sourceLocation: sourceLocation) - } +@Suite +struct OpenParentTests { + @Test + func testSplitParent() { + func check( + _ lhs: (FilePath, FilePath.Component)?, + _ rhs: (FilePath, FilePath.Component)?, + sourceLocation: SourceLocation = #_sourceLocation + ) { + switch (lhs, rhs) { + case (.none, .none): return + case (.some(let lhs), .some(let rhs)): + #expect(lhs.0 == rhs.0, sourceLocation: sourceLocation) + #expect(lhs.1 == rhs.1, sourceLocation: sourceLocation) + default: + #expect((false), "\(String(describing: lhs)) and \(String(describing: rhs)) are not equal", sourceLocation: sourceLocation) } + } - check(splitParent(path: ""), nil) + check(splitParent(path: ""), nil) - check(splitParent(path: "/"), (FilePath("/"), FilePath.Component("."))) - check(splitParent(path: "/."), (FilePath("/."), FilePath.Component("."))) - check(splitParent(path: "/a"), (FilePath("/"), FilePath.Component("a"))) - check(splitParent(path: "/a/"), (FilePath("/a"), FilePath.Component("."))) - check(splitParent(path: "/a/."), (FilePath("/a/."), FilePath.Component("."))) - check(splitParent(path: "/a/.."), (FilePath("/a/.."), FilePath.Component("."))) + check(splitParent(path: "/"), (FilePath("/"), FilePath.Component("."))) + check(splitParent(path: "/."), (FilePath("/."), FilePath.Component("."))) + check(splitParent(path: "/a"), (FilePath("/"), FilePath.Component("a"))) + check(splitParent(path: "/a/"), (FilePath("/a"), FilePath.Component("."))) + check(splitParent(path: "/a/."), (FilePath("/a/."), FilePath.Component("."))) + check(splitParent(path: "/a/.."), (FilePath("/a/.."), FilePath.Component("."))) - check(splitParent(path: "b"), (FilePath(""), FilePath.Component("b"))) - check(splitParent(path: "b/."), (FilePath("b/."), FilePath.Component("."))) - check(splitParent(path: "b/.."), (FilePath("b/.."), FilePath.Component("."))) + check(splitParent(path: "b"), (FilePath(""), FilePath.Component("b"))) + check(splitParent(path: "b/."), (FilePath("b/."), FilePath.Component("."))) + check(splitParent(path: "b/.."), (FilePath("b/.."), FilePath.Component("."))) - check(splitParent(path: "../c"), (FilePath(".."), FilePath.Component("c"))) - } + check(splitParent(path: "../c"), (FilePath(".."), FilePath.Component("c"))) } -#endif +} diff --git a/Tests/WASITests/RandomBufferGeneratorTests.swift b/Tests/WASITests/RandomBufferGeneratorTests.swift index 680ea267..8ab48f05 100644 --- a/Tests/WASITests/RandomBufferGeneratorTests.swift +++ b/Tests/WASITests/RandomBufferGeneratorTests.swift @@ -1,40 +1,38 @@ -#if canImport(Testing) - import Testing +import Testing - @testable import WASI +@testable import WASI - @Suite - struct RandomBufferGeneratorTests { - struct DeterministicGenerator: RandomNumberGenerator, RandomBufferGenerator { - var items: [UInt64] +@Suite +struct RandomBufferGeneratorTests { + struct DeterministicGenerator: RandomNumberGenerator, RandomBufferGenerator { + var items: [UInt64] - mutating func next() -> UInt64 { - items.removeFirst() - } + mutating func next() -> UInt64 { + items.removeFirst() } - @Test - func defaultFill() { - var generator = DeterministicGenerator(items: [ - 0x0123_4567_89ab_cdef, 0xfedc_ba98_7654_3210, 0xdead_beef_badd_cafe, - ]) - for (bufferSize, expectedBytes): (Int, [UInt8]) in [ - (10, [0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01, 0x10, 0x32]), - (2, [0xfe, 0xca]), - (0, []), - ] { - var buffer: [UInt8] = Array(repeating: 0, count: bufferSize) - buffer.withUnsafeMutableBufferPointer { - generator.fill(buffer: $0) - } - let expected: [UInt8] - #if _endian(little) - expected = expectedBytes - #else - expected = Array(expectedBytes.reversed()) - #endif - #expect(buffer == expected) + } + @Test + func defaultFill() { + var generator = DeterministicGenerator(items: [ + 0x0123_4567_89ab_cdef, 0xfedc_ba98_7654_3210, 0xdead_beef_badd_cafe, + ]) + for (bufferSize, expectedBytes): (Int, [UInt8]) in [ + (10, [0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01, 0x10, 0x32]), + (2, [0xfe, 0xca]), + (0, []), + ] { + var buffer: [UInt8] = Array(repeating: 0, count: bufferSize) + buffer.withUnsafeMutableBufferPointer { + generator.fill(buffer: $0) } + let expected: [UInt8] + #if _endian(little) + expected = expectedBytes + #else + expected = Array(expectedBytes.reversed()) + #endif + #expect(buffer == expected) } } +} -#endif diff --git a/Tests/WASITests/WASITests.swift b/Tests/WASITests/WASITests.swift index bcbc7490..2cd5ef94 100644 --- a/Tests/WASITests/WASITests.swift +++ b/Tests/WASITests/WASITests.swift @@ -1,38 +1,57 @@ -#if canImport(Testing) - import Testing - - @testable import WASI - - @Suite - struct WASITests { - #if !os(Windows) - @Test - func pathOpen() throws { - let t = try TestSupport.TemporaryDirectory() - - try t.createDir(at: "External") - try t.createDir(at: "External/secret-dir-b") - try t.createFile(at: "External/secret-a.txt", contents: "Secret A") - try t.createFile(at: "External/secret-dir-b/secret-c.txt", contents: "Secret C") - try t.createDir(at: "Sandbox") - try t.createFile(at: "Sandbox/hello.txt", contents: "Hello") - try t.createSymlink(at: "Sandbox/link-hello.txt", to: "hello.txt") - try t.createDir(at: "Sandbox/world.dir") - try t.createSymlink(at: "Sandbox/link-world.dir", to: "world.dir") - try t.createSymlink(at: "Sandbox/link-external-secret-a.txt", to: "../External/secret-a.txt") - try t.createSymlink(at: "Sandbox/link-secret-dir-b", to: "../External/secret-dir-b") - try t.createSymlink(at: "Sandbox/link-updown-hello.txt", to: "../Sandbox/link-updown-hello.txt") - try t.createSymlink(at: "Sandbox/link-external-non-existent.txt", to: "../External/non-existent.txt") - try t.createSymlink(at: "Sandbox/link-root", to: "/") - try t.createSymlink(at: "Sandbox/link-loop.txt", to: "link-loop.txt") - - let wasi = try WASIBridgeToHost( - preopens: ["/Sandbox": t.url.appendingPathComponent("Sandbox").path] +import Testing + +@testable import WASI + +@Suite +struct WASITests { + #if !os(Windows) + @Test + func pathOpen() throws { + let t = try TestSupport.TemporaryDirectory() + + try t.createDir(at: "External") + try t.createDir(at: "External/secret-dir-b") + try t.createFile(at: "External/secret-a.txt", contents: "Secret A") + try t.createFile(at: "External/secret-dir-b/secret-c.txt", contents: "Secret C") + try t.createDir(at: "Sandbox") + try t.createFile(at: "Sandbox/hello.txt", contents: "Hello") + try t.createSymlink(at: "Sandbox/link-hello.txt", to: "hello.txt") + try t.createDir(at: "Sandbox/world.dir") + try t.createSymlink(at: "Sandbox/link-world.dir", to: "world.dir") + try t.createSymlink(at: "Sandbox/link-external-secret-a.txt", to: "../External/secret-a.txt") + try t.createSymlink(at: "Sandbox/link-secret-dir-b", to: "../External/secret-dir-b") + try t.createSymlink(at: "Sandbox/link-updown-hello.txt", to: "../Sandbox/link-updown-hello.txt") + try t.createSymlink(at: "Sandbox/link-external-non-existent.txt", to: "../External/non-existent.txt") + try t.createSymlink(at: "Sandbox/link-root", to: "/") + try t.createSymlink(at: "Sandbox/link-loop.txt", to: "link-loop.txt") + + let wasi = try WASIBridgeToHost( + preopens: ["/Sandbox": t.url.appendingPathComponent("Sandbox").path] + ) + let mntFd: WASIAbi.Fd = 3 + + func assertResolve(_ path: String, followSymlink: Bool, directory: Bool = false) throws { + let fd = try wasi.path_open( + dirFd: mntFd, + dirFlags: followSymlink ? [.SYMLINK_FOLLOW] : [], + path: path, + oflags: directory ? [.DIRECTORY] : [], + fsRightsBase: .DIRECTORY_BASE_RIGHTS, + fsRightsInheriting: .DIRECTORY_INHERITING_RIGHTS, + fdflags: [] ) - let mntFd: WASIAbi.Fd = 3 + try wasi.fd_close(fd: fd) + } - func assertResolve(_ path: String, followSymlink: Bool, directory: Bool = false) throws { - let fd = try wasi.path_open( + func assertNotResolve( + _ path: String, + followSymlink: Bool, + directory: Bool = false, + sourceLocation: SourceLocation = #_sourceLocation, + _ checkError: ((WASIAbi.Errno) throws -> Void)? + ) throws { + do { + _ = try wasi.path_open( dirFd: mntFd, dirFlags: followSymlink ? [.SYMLINK_FOLLOW] : [], path: path, @@ -41,99 +60,78 @@ fsRightsInheriting: .DIRECTORY_INHERITING_RIGHTS, fdflags: [] ) - try wasi.fd_close(fd: fd) - } - - func assertNotResolve( - _ path: String, - followSymlink: Bool, - directory: Bool = false, - sourceLocation: SourceLocation = #_sourceLocation, - _ checkError: ((WASIAbi.Errno) throws -> Void)? - ) throws { - do { - _ = try wasi.path_open( - dirFd: mntFd, - dirFlags: followSymlink ? [.SYMLINK_FOLLOW] : [], - path: path, - oflags: directory ? [.DIRECTORY] : [], - fsRightsBase: .DIRECTORY_BASE_RIGHTS, - fsRightsInheriting: .DIRECTORY_INHERITING_RIGHTS, - fdflags: [] - ) - #expect((false), "Expected not to be able to open \(path)", sourceLocation: sourceLocation) - } catch { - guard let error = error as? WASIAbi.Errno else { - #expect((false), "Expected WASIAbi.Errno error but got \(error)", sourceLocation: sourceLocation) - return - } - try checkError?(error) + #expect((false), "Expected not to be able to open \(path)", sourceLocation: sourceLocation) + } catch { + guard let error = error as? WASIAbi.Errno else { + #expect((false), "Expected WASIAbi.Errno error but got \(error)", sourceLocation: sourceLocation) + return } + try checkError?(error) } + } - try assertNotResolve("non-existent.txt", followSymlink: false) { error in - #expect(error == .ENOENT) - } + try assertNotResolve("non-existent.txt", followSymlink: false) { error in + #expect(error == .ENOENT) + } - try assertResolve("link-hello.txt", followSymlink: true) - try assertNotResolve("link-hello.txt", followSymlink: false) { error in - #expect(error == .ELOOP) - } - try assertNotResolve("link-hello.txt", followSymlink: true, directory: true) { error in - #expect(error == .ENOTDIR) - } + try assertResolve("link-hello.txt", followSymlink: true) + try assertNotResolve("link-hello.txt", followSymlink: false) { error in + #expect(error == .ELOOP) + } + try assertNotResolve("link-hello.txt", followSymlink: true, directory: true) { error in + #expect(error == .ENOTDIR) + } - try assertNotResolve("link-hello.txt/", followSymlink: true) { error in - #expect(error == .ENOTDIR) - } + try assertNotResolve("link-hello.txt/", followSymlink: true) { error in + #expect(error == .ENOTDIR) + } - try assertResolve("link-world.dir", followSymlink: true) - try assertNotResolve("link-world.dir", followSymlink: false) { error in - #expect(error == .ELOOP) - } + try assertResolve("link-world.dir", followSymlink: true) + try assertNotResolve("link-world.dir", followSymlink: false) { error in + #expect(error == .ELOOP) + } - try assertNotResolve("link-external-secret-a.txt", followSymlink: true) { error in - #expect(error == .EPERM) - } - try assertNotResolve("link-external-secret-a.txt", followSymlink: false) { error in - #expect(error == .ELOOP) - } + try assertNotResolve("link-external-secret-a.txt", followSymlink: true) { error in + #expect(error == .EPERM) + } + try assertNotResolve("link-external-secret-a.txt", followSymlink: false) { error in + #expect(error == .ELOOP) + } - try assertNotResolve("link-external-non-existent.txt", followSymlink: true) { error in - #expect(error == .EPERM) - } - try assertNotResolve("link-external-non-existent.txt", followSymlink: false) { error in - #expect(error == .ELOOP) - } + try assertNotResolve("link-external-non-existent.txt", followSymlink: true) { error in + #expect(error == .EPERM) + } + try assertNotResolve("link-external-non-existent.txt", followSymlink: false) { error in + #expect(error == .ELOOP) + } - try assertNotResolve("link-updown-hello.txt", followSymlink: true) { error in - #expect(error == .EPERM) - } - try assertNotResolve("link-updown-hello.txt", followSymlink: false) { error in - #expect(error == .ELOOP) - } + try assertNotResolve("link-updown-hello.txt", followSymlink: true) { error in + #expect(error == .EPERM) + } + try assertNotResolve("link-updown-hello.txt", followSymlink: false) { error in + #expect(error == .ELOOP) + } - try assertNotResolve("link-secret-dir-b/secret-c.txt", followSymlink: true) { error in - #expect(error == .EPERM) - } - try assertNotResolve("link-secret-dir-b/secret-c.txt", followSymlink: false) { error in - #expect(error == .ENOTDIR) - } + try assertNotResolve("link-secret-dir-b/secret-c.txt", followSymlink: true) { error in + #expect(error == .EPERM) + } + try assertNotResolve("link-secret-dir-b/secret-c.txt", followSymlink: false) { error in + #expect(error == .ENOTDIR) + } - try assertNotResolve("link-root", followSymlink: true) { error in - #expect(error == .EPERM) - } - try assertNotResolve("link-root", followSymlink: false) { error in - #expect(error == .ELOOP) - } + try assertNotResolve("link-root", followSymlink: true) { error in + #expect(error == .EPERM) + } + try assertNotResolve("link-root", followSymlink: false) { error in + #expect(error == .ELOOP) + } - try assertNotResolve("link-loop.txt", followSymlink: false) { error in - #expect(error == .ELOOP) - } - try assertNotResolve("link-loop.txt", followSymlink: true) { error in - #expect(error == .ELOOP) - } + try assertNotResolve("link-loop.txt", followSymlink: false) { error in + #expect(error == .ELOOP) + } + try assertNotResolve("link-loop.txt", followSymlink: true) { error in + #expect(error == .ELOOP) } - #endif - } -#endif + } + #endif +} diff --git a/Tests/WATTests/EncoderTests.swift b/Tests/WATTests/EncoderTests.swift index 28f5ad25..3e5ca678 100644 --- a/Tests/WATTests/EncoderTests.swift +++ b/Tests/WATTests/EncoderTests.swift @@ -1,176 +1,174 @@ -#if canImport(Testing) - import Testing - import Foundation - import WasmParser +import Testing +import Foundation +import WasmParser - @testable import WAT +@testable import WAT - @Suite - struct EncoderTests { +@Suite +struct EncoderTests { - struct CompatibilityTestStats { - var run: Int = 0 - var failed: Set = [] - } + struct CompatibilityTestStats { + var run: Int = 0 + var failed: Set = [] + } - func checkWabtCompatibility( - wast: URL, json: URL, stats parentStats: inout CompatibilityTestStats, - sourceLocation: SourceLocation = #_sourceLocation - ) throws { - var stats = parentStats - defer { parentStats = stats } - func recordFail() { - stats.failed.insert(wast.lastPathComponent) - } - func assertEqual(_ lhs: T, _ rhs: T, sourceLocation: SourceLocation = #_sourceLocation) { - #expect(lhs == rhs, sourceLocation: sourceLocation) - if lhs != rhs { - recordFail() - } + func checkWabtCompatibility( + wast: URL, json: URL, stats parentStats: inout CompatibilityTestStats, + sourceLocation: SourceLocation = #_sourceLocation + ) throws { + var stats = parentStats + defer { parentStats = stats } + func recordFail() { + stats.failed.insert(wast.lastPathComponent) + } + func assertEqual(_ lhs: T, _ rhs: T, sourceLocation: SourceLocation = #_sourceLocation) { + #expect(lhs == rhs, sourceLocation: sourceLocation) + if lhs != rhs { + recordFail() } + } - var parser = WastParser(try String(contentsOf: wast), features: Spectest.deriveFeatureSet(wast: wast)) - var watModules: [ModuleDirective] = [] + var parser = WastParser(try String(contentsOf: wast), features: Spectest.deriveFeatureSet(wast: wast)) + var watModules: [ModuleDirective] = [] - while let directive = try parser.nextDirective() { - switch directive { - case .module(let moduleDirective): - watModules.append(moduleDirective) - case .assertMalformed(let module, let message): - let diagnostic: () -> Comment = { - let (line, column) = module.location.computeLineAndColumn() - return "\(wast.path):\(line):\(column) should be malformed: \(message)" - } - switch module.source { - case .text(var wat): - #expect(throws: (any Error).self, diagnostic(), sourceLocation: sourceLocation) { - _ = try wat.encode() - recordFail() - } - case .quote(let bytes): - #expect(throws: (any Error).self, diagnostic(), sourceLocation: sourceLocation) { - _ = try wat2wasm(String(decoding: bytes, as: UTF8.self)) - recordFail() - } - case .binary: break - } - default: break + while let directive = try parser.nextDirective() { + switch directive { + case .module(let moduleDirective): + watModules.append(moduleDirective) + case .assertMalformed(let module, let message): + let diagnostic: () -> Comment = { + let (line, column) = module.location.computeLineAndColumn() + return "\(wast.path):\(line):\(column) should be malformed: \(message)" } - } - guard FileManager.default.fileExists(atPath: json.path) else { - print("Skipping binary comparison because the oracle file (\(json.path)) does not exist.") - return - } - let moduleBinaryFiles = try Spectest.moduleFiles(json: json) - assertEqual(watModules.count, moduleBinaryFiles.count) - - for (watModule, (moduleBinaryFile, expectedName)) in zip(watModules, moduleBinaryFiles) { - func assertEqual(_ lhs: T, _ rhs: T, sourceLocation: SourceLocation = #_sourceLocation) { - #expect(lhs == rhs, sourceLocation: sourceLocation) - if lhs != rhs { + switch module.source { + case .text(var wat): + #expect(throws: (any Error).self, diagnostic(), sourceLocation: sourceLocation) { + _ = try wat.encode() recordFail() } - } - stats.run += 1 - let moduleBytes: [UInt8] - let expectedBytes = try Array(Data(contentsOf: moduleBinaryFile)) - do { - assertEqual(watModule.id, expectedName) - switch watModule.source { - case .text(var watModule): - moduleBytes = try encode(module: &watModule, options: .default) - case .binary(let bytes): - moduleBytes = bytes - case .quote(let watText): - moduleBytes = try wat2wasm(String(decoding: watText, as: UTF8.self)) + case .quote(let bytes): + #expect(throws: (any Error).self, diagnostic(), sourceLocation: sourceLocation) { + _ = try wat2wasm(String(decoding: bytes, as: UTF8.self)) + recordFail() } - } catch { - recordFail() - #expect((false), "Error while encoding \(moduleBinaryFile.lastPathComponent): \(error)") - return + case .binary: break } - if moduleBytes != expectedBytes { + default: break + } + } + guard FileManager.default.fileExists(atPath: json.path) else { + print("Skipping binary comparison because the oracle file (\(json.path)) does not exist.") + return + } + let moduleBinaryFiles = try Spectest.moduleFiles(json: json) + assertEqual(watModules.count, moduleBinaryFiles.count) + + for (watModule, (moduleBinaryFile, expectedName)) in zip(watModules, moduleBinaryFiles) { + func assertEqual(_ lhs: T, _ rhs: T, sourceLocation: SourceLocation = #_sourceLocation) { + #expect(lhs == rhs, sourceLocation: sourceLocation) + if lhs != rhs { recordFail() } - assertEqual(moduleBytes.count, expectedBytes.count) - if moduleBytes.count == expectedBytes.count { - assertEqual(moduleBytes, expectedBytes) + } + stats.run += 1 + let moduleBytes: [UInt8] + let expectedBytes = try Array(Data(contentsOf: moduleBinaryFile)) + do { + assertEqual(watModule.id, expectedName) + switch watModule.source { + case .text(var watModule): + moduleBytes = try encode(module: &watModule, options: .default) + case .binary(let bytes): + moduleBytes = bytes + case .quote(let watText): + moduleBytes = try wat2wasm(String(decoding: watText, as: UTF8.self)) } + } catch { + recordFail() + #expect((false), "Error while encoding \(moduleBinaryFile.lastPathComponent): \(error)") + return + } + if moduleBytes != expectedBytes { + recordFail() + } + assertEqual(moduleBytes.count, expectedBytes.count) + if moduleBytes.count == expectedBytes.count { + assertEqual(moduleBytes, expectedBytes) } } + } - #if !(os(iOS) || os(watchOS) || os(tvOS) || os(visionOS)) - @Test( - arguments: Spectest.wastFiles(include: [], exclude: []) - ) - func spectest(wastFile: URL) throws { - guard let wast2json = TestSupport.lookupExecutable("wast2json") else { - return // Skip the test if wast2json is not found in PATH - } + #if !(os(iOS) || os(watchOS) || os(tvOS) || os(visionOS)) + @Test( + arguments: Spectest.wastFiles(include: [], exclude: []) + ) + func spectest(wastFile: URL) throws { + guard let wast2json = TestSupport.lookupExecutable("wast2json") else { + return // Skip the test if wast2json is not found in PATH + } - var stats = CompatibilityTestStats() - try TestSupport.withTemporaryDirectory { tempDir, shouldRetain in - let jsonFileName = wastFile.deletingPathExtension().lastPathComponent + ".json" - let json = URL(fileURLWithPath: tempDir).appendingPathComponent(jsonFileName) + var stats = CompatibilityTestStats() + try TestSupport.withTemporaryDirectory { tempDir, shouldRetain in + let jsonFileName = wastFile.deletingPathExtension().lastPathComponent + ".json" + let json = URL(fileURLWithPath: tempDir).appendingPathComponent(jsonFileName) - let wast2jsonProcess = try Process.run( - wast2json, - arguments: [ - wastFile.path, - "--enable-memory64", - "--enable-tail-call", - "-o", json.path, - ] - ) - wast2jsonProcess.waitUntilExit() + let wast2jsonProcess = try Process.run( + wast2json, + arguments: [ + wastFile.path, + "--enable-memory64", + "--enable-tail-call", + "-o", json.path, + ] + ) + wast2jsonProcess.waitUntilExit() - do { - try checkWabtCompatibility(wast: wastFile, json: json, stats: &stats) - } catch { - stats.failed.insert(wastFile.lastPathComponent) - shouldRetain = true - #expect((false), "Error while checking compatibility between \(wastFile) and \(json.path): \(error)") - } + do { + try checkWabtCompatibility(wast: wastFile, json: json, stats: &stats) + } catch { + stats.failed.insert(wastFile.lastPathComponent) + shouldRetain = true + #expect((false), "Error while checking compatibility between \(wastFile) and \(json.path): \(error)") } + } - if !stats.failed.isEmpty { - #expect((false), "Failed test cases: \(stats.failed.sorted())") - } + if !stats.failed.isEmpty { + #expect((false), "Failed test cases: \(stats.failed.sorted())") } - #endif + } + #endif - @Test - func encodeNameSection() throws { - let bytes = try wat2wasm( - """ - (module - (func $foo) - (func) - (func $bar) - ) - """, - options: EncodeOptions(nameSection: true) + @Test + func encodeNameSection() throws { + let bytes = try wat2wasm( + """ + (module + (func $foo) + (func) + (func $bar) ) + """, + options: EncodeOptions(nameSection: true) + ) - var parser = WasmParser.Parser(bytes: bytes) - var customSections: [CustomSection] = [] - while let payload = try parser.parseNext() { - guard case .customSection(let section) = payload else { - continue - } - customSections.append(section) - } - let nameSection = customSections.first(where: { $0.name == "name" }) - let nameParser = NameSectionParser( - stream: StaticByteStream(bytes: nameSection?.bytes ?? []) - ) - let names = try nameParser.parseAll() - #expect(names.count == 1) - guard case .functions(let functionNames) = try #require(names.first) else { - #expect((false), "Expected functions name section") - return + var parser = WasmParser.Parser(bytes: bytes) + var customSections: [CustomSection] = [] + while let payload = try parser.parseNext() { + guard case .customSection(let section) = payload else { + continue } - #expect(functionNames == [0: "foo", 2: "bar"]) + customSections.append(section) + } + let nameSection = customSections.first(where: { $0.name == "name" }) + let nameParser = NameSectionParser( + stream: StaticByteStream(bytes: nameSection?.bytes ?? []) + ) + let names = try nameParser.parseAll() + #expect(names.count == 1) + guard case .functions(let functionNames) = try #require(names.first) else { + #expect((false), "Expected functions name section") + return } + #expect(functionNames == [0: "foo", 2: "bar"]) } -#endif +} diff --git a/Tests/WATTests/LexerTests.swift b/Tests/WATTests/LexerTests.swift index 440b4f98..ed075ba6 100644 --- a/Tests/WATTests/LexerTests.swift +++ b/Tests/WATTests/LexerTests.swift @@ -1,104 +1,102 @@ -#if canImport(Testing) - import Testing - import Foundation - import WasmParser +import Testing +import Foundation +import WasmParser - @testable import WAT +@testable import WAT - @Suite - struct LexerTests { - func collectToken(_ source: String) throws -> [TokenKind] { - var lexer = Lexer(input: source) - var tokens: [TokenKind] = [] - while let token = try lexer.rawLex() { - tokens.append(token.kind) - } - return tokens +@Suite +struct LexerTests { + func collectToken(_ source: String) throws -> [TokenKind] { + var lexer = Lexer(input: source) + var tokens: [TokenKind] = [] + while let token = try lexer.rawLex() { + tokens.append(token.kind) } + return tokens + } - @Test - func lexBasics() throws { - #expect(try collectToken("") == []) - #expect(try collectToken("(module") == [.leftParen, .keyword]) - #expect(try collectToken("( module") == [.leftParen, .keyword]) - #expect(try collectToken("(\tmodule") == [.leftParen, .keyword]) - #expect(try collectToken("(\nmodule") == [.leftParen, .keyword]) - #expect(try collectToken("(module)") == [.leftParen, .keyword, .rightParen]) + @Test + func lexBasics() throws { + #expect(try collectToken("") == []) + #expect(try collectToken("(module") == [.leftParen, .keyword]) + #expect(try collectToken("( module") == [.leftParen, .keyword]) + #expect(try collectToken("(\tmodule") == [.leftParen, .keyword]) + #expect(try collectToken("(\nmodule") == [.leftParen, .keyword]) + #expect(try collectToken("(module)") == [.leftParen, .keyword, .rightParen]) - } + } - @Test - func testLexComment() throws { - #expect(try collectToken("(; foo ;)") == [.blockComment]) - #expect( - try collectToken( - """ - (; - multi-line comment - ;) - """ - ) == [.blockComment] - ) - #expect(try collectToken(";; foo") == [.lineComment]) - #expect(try collectToken(";; foo\n(bar") == [.lineComment, .leftParen, .keyword]) + @Test + func testLexComment() throws { + #expect(try collectToken("(; foo ;)") == [.blockComment]) + #expect( + try collectToken( + """ + (; + multi-line comment + ;) + """ + ) == [.blockComment] + ) + #expect(try collectToken(";; foo") == [.lineComment]) + #expect(try collectToken(";; foo\n(bar") == [.lineComment, .leftParen, .keyword]) - } + } - @Test - func lexBrokenComment() throws { - #expect(throws: (any Error).self) { try collectToken("(;)") } - #expect(throws: (any Error).self) { try collectToken("(; foo )") } - #expect(throws: (any Error).self) { try collectToken(";)") } - } + @Test + func lexBrokenComment() throws { + #expect(throws: (any Error).self) { try collectToken("(;)") } + #expect(throws: (any Error).self) { try collectToken("(; foo )") } + #expect(throws: (any Error).self) { try collectToken(";)") } + } - @Test - func lexIdAndString() throws { - #expect(try collectToken("$foo") == [.id]) - #expect(try collectToken("\"foo\"") == [.string(Array("foo".utf8))]) - #expect(try collectToken("\"\\t\\n\\r\\\"\\\\\"") == [.string(Array("\t\n\r\"\\".utf8))]) - #expect(try collectToken("\"\\u{1F600}\"") == [.string(Array("😀".utf8))]) - #expect(try collectToken("$\"foo\"") == [.id]) - #expect(try collectToken("0$x") == [.unknown]) - } + @Test + func lexIdAndString() throws { + #expect(try collectToken("$foo") == [.id]) + #expect(try collectToken("\"foo\"") == [.string(Array("foo".utf8))]) + #expect(try collectToken("\"\\t\\n\\r\\\"\\\\\"") == [.string(Array("\t\n\r\"\\".utf8))]) + #expect(try collectToken("\"\\u{1F600}\"") == [.string(Array("😀".utf8))]) + #expect(try collectToken("$\"foo\"") == [.id]) + #expect(try collectToken("0$x") == [.unknown]) + } - @Test - func lexInteger() throws { - #expect(try collectToken("inf") == [.float(nil, .inf)]) - #expect(try collectToken("+inf") == [.float(.plus, .inf)]) - #expect(try collectToken("-inf") == [.float(.minus, .inf)]) - #expect(try collectToken("nan") == [.float(nil, .nan(hexPattern: nil))]) - #expect(try collectToken("+nan") == [.float(.plus, .nan(hexPattern: nil))]) - #expect(try collectToken("-nan") == [.float(.minus, .nan(hexPattern: nil))]) - #expect(try collectToken("nan:0x7f_ffff") == [.float(nil, .nan(hexPattern: "7fffff"))]) - #expect(try collectToken("3.14") == [.float(nil, .decimalPattern("3.14"))]) - #expect(try collectToken("1e+07") == [.float(nil, .decimalPattern("1e+07"))]) - #expect(try collectToken("1E+07") == [.float(nil, .decimalPattern("1E+07"))]) - #expect(try collectToken("0xff") == [.integer(nil, .hexPattern("ff"))]) - #expect(try collectToken("8_128") == [.integer(nil, .decimalPattern("8128"))]) - #expect(try collectToken("1.e10") == [.float(nil, .decimalPattern("1.e10"))]) - } + @Test + func lexInteger() throws { + #expect(try collectToken("inf") == [.float(nil, .inf)]) + #expect(try collectToken("+inf") == [.float(.plus, .inf)]) + #expect(try collectToken("-inf") == [.float(.minus, .inf)]) + #expect(try collectToken("nan") == [.float(nil, .nan(hexPattern: nil))]) + #expect(try collectToken("+nan") == [.float(.plus, .nan(hexPattern: nil))]) + #expect(try collectToken("-nan") == [.float(.minus, .nan(hexPattern: nil))]) + #expect(try collectToken("nan:0x7f_ffff") == [.float(nil, .nan(hexPattern: "7fffff"))]) + #expect(try collectToken("3.14") == [.float(nil, .decimalPattern("3.14"))]) + #expect(try collectToken("1e+07") == [.float(nil, .decimalPattern("1e+07"))]) + #expect(try collectToken("1E+07") == [.float(nil, .decimalPattern("1E+07"))]) + #expect(try collectToken("0xff") == [.integer(nil, .hexPattern("ff"))]) + #expect(try collectToken("8_128") == [.integer(nil, .decimalPattern("8128"))]) + #expect(try collectToken("1.e10") == [.float(nil, .decimalPattern("1.e10"))]) + } - @Test - func lexFloatLiteral() throws { - #expect(try collectToken("nan:canonical") == [.keyword]) - #expect(try collectToken("0x1.921fb6p+2") == [.float(nil, .hexPattern("1.921fb6p+2"))]) - } + @Test + func lexFloatLiteral() throws { + #expect(try collectToken("nan:canonical") == [.keyword]) + #expect(try collectToken("0x1.921fb6p+2") == [.float(nil, .hexPattern("1.921fb6p+2"))]) + } - @Test - func lexMemory() throws { - #expect(try collectToken("(module (memory 1))") == [.leftParen, .keyword, .leftParen, .keyword, .integer(nil, .decimalPattern("1")), .rightParen, .rightParen]) - } + @Test + func lexMemory() throws { + #expect(try collectToken("(module (memory 1))") == [.leftParen, .keyword, .leftParen, .keyword, .integer(nil, .decimalPattern("1")), .rightParen, .rightParen]) + } - // NOTE: We do the same check as a part of the EncoderTests, so it's - // usually redundant and time-wasting to run this test every time. - // Keeping it here just for local unit testing purposes. - @Test( - .enabled(if: ProcessInfo.processInfo.environment["WASMKIT_PARSER_SPECTEST"] == "1"), - arguments: Spectest.wastFiles(include: []) - ) - func lexSpectest(wastFile: URL) throws { - let source = try String(contentsOf: wastFile) - _ = try collectToken(source) - } + // NOTE: We do the same check as a part of the EncoderTests, so it's + // usually redundant and time-wasting to run this test every time. + // Keeping it here just for local unit testing purposes. + @Test( + .enabled(if: ProcessInfo.processInfo.environment["WASMKIT_PARSER_SPECTEST"] == "1"), + arguments: Spectest.wastFiles(include: []) + ) + func lexSpectest(wastFile: URL) throws { + let source = try String(contentsOf: wastFile) + _ = try collectToken(source) } -#endif +} diff --git a/Tests/WATTests/ParserTests.swift b/Tests/WATTests/ParserTests.swift index cd60676d..2cab915e 100644 --- a/Tests/WATTests/ParserTests.swift +++ b/Tests/WATTests/ParserTests.swift @@ -1,198 +1,196 @@ -#if canImport(Testing) - import Testing - import Foundation - import WasmParser - - @testable import WAT - - @Suite - struct ParserTests { - func parseWast(_ source: String, features: WasmFeatureSet = .default) throws -> [WastDirective] { - var parser = WastParser(source, features: features) - var directives: [WastDirective] = [] - while let directive = try parser.nextDirective() { - directives.append(directive) - } - return directives +import Testing +import Foundation +import WasmParser + +@testable import WAT + +@Suite +struct ParserTests { + func parseWast(_ source: String, features: WasmFeatureSet = .default) throws -> [WastDirective] { + var parser = WastParser(source, features: features) + var directives: [WastDirective] = [] + while let directive = try parser.nextDirective() { + directives.append(directive) } + return directives + } - func parseModule(_ source: String) throws -> ModuleDirective? { - let directives = try parseWast(source) - guard case .module(let moduleDirective) = directives.first else { - #expect((false), "Expected module directive") - return nil - } - return moduleDirective + func parseModule(_ source: String) throws -> ModuleDirective? { + let directives = try parseWast(source) + guard case .module(let moduleDirective) = directives.first else { + #expect((false), "Expected module directive") + return nil } + return moduleDirective + } - func parseBinaryModule(_ source: String) throws -> (source: [UInt8], id: String?)? { - guard let module = try parseModule(source) else { return nil } - guard case .binary(let content) = module.source else { return nil } - return (content, module.id) - } + func parseBinaryModule(_ source: String) throws -> (source: [UInt8], id: String?)? { + guard let module = try parseModule(source) else { return nil } + guard case .binary(let content) = module.source else { return nil } + return (content, module.id) + } - @Test - func parseWastBinaryModule() throws { - #expect( - try parseBinaryModule(#"(module binary "\00asm\01\00\00\00")"#)?.source == [0, 97, 115, 109, 1, 0, 0, 0] - ) - #expect( - try parseBinaryModule( - #""" - (module binary - "\00asm" "\01\00\00\00" - ;; comment between strings - "foo" - ) - """#)?.source == [0, 97, 115, 109, 1, 0, 0, 0, 102, 111, 111] - ) + @Test + func parseWastBinaryModule() throws { + #expect( + try parseBinaryModule(#"(module binary "\00asm\01\00\00\00")"#)?.source == [0, 97, 115, 109, 1, 0, 0, 0] + ) + #expect( + try parseBinaryModule( + #""" + (module binary + "\00asm" "\01\00\00\00" + ;; comment between strings + "foo" + ) + """#)?.source == [0, 97, 115, 109, 1, 0, 0, 0, 102, 111, 111] + ) - do { - let m1 = try parseBinaryModule(#"(module $M1 binary "\00asm\01\00\00\00")"#) - #expect(m1?.id == "$M1") - #expect(m1?.source == [0, 97, 115, 109, 1, 0, 0, 0]) - } + do { + let m1 = try parseBinaryModule(#"(module $M1 binary "\00asm\01\00\00\00")"#) + #expect(m1?.id == "$M1") + #expect(m1?.source == [0, 97, 115, 109, 1, 0, 0, 0]) } + } - @Test - func parseWastModule() throws { - var parser = WastParser( - #""" - (module - ;; comment here - (memory 1) + @Test + func parseWastModule() throws { + var parser = WastParser( + #""" + (module + ;; comment here + (memory 1) - (func $dummy) + (func $dummy) - (func (export "empty") - (unknown expr) - ) - ) - """#, features: .default) - - while let directive = try parser.nextDirective() { - switch directive { - case .module(let directive): - guard case .text(_) = directive.source else { - #expect((false), "Expected text module field") - return - } - case _: - #expect((false), "Expected only module directive") + (func (export "empty") + (unknown expr) + ) + ) + """#, features: .default) + + while let directive = try parser.nextDirective() { + switch directive { + case .module(let directive): + guard case .text(_) = directive.source else { + #expect((false), "Expected text module field") + return } + case _: + #expect((false), "Expected only module directive") } } + } - @Test - func parseWastModuleSkip() throws { - let directives = try parseWast( - #""" - (module - ;; comment here - (memory 1) + @Test + func parseWastModuleSkip() throws { + let directives = try parseWast( + #""" + (module + ;; comment here + (memory 1) - (func $dummy) + (func $dummy) - (func (export "empty") - (unknown expr) - ) - ) - (module binary "ok") - """#) - - #expect(directives.count == 2) - guard case .module(let directive) = try #require(directives.last), - case .binary(let content) = directive.source - else { - return - } - #expect(content == Array("ok".utf8)) + (func (export "empty") + (unknown expr) + ) + ) + (module binary "ok") + """#) + + #expect(directives.count == 2) + guard case .module(let directive) = try #require(directives.last), + case .binary(let content) = directive.source + else { + return } + #expect(content == Array("ok".utf8)) + } - @Test - func specForward() throws { - let source = """ - (module - (func $even (export "even") (param $n i32) (result i32) - (if (result i32) (i32.eq (local.get $n) (i32.const 0)) - (then (i32.const 1)) - (else (call $odd (i32.sub (local.get $n) (i32.const 1)))) - ) - ) - - (func $odd (export "odd") (param $n i32) (result i32) - (if (result i32) (i32.eq (local.get $n) (i32.const 0)) - (then (i32.const 0)) - (else (call $even (i32.sub (local.get $n) (i32.const 1)))) - ) - ) + @Test + func specForward() throws { + let source = """ + (module + (func $even (export "even") (param $n i32) (result i32) + (if (result i32) (i32.eq (local.get $n) (i32.const 0)) + (then (i32.const 1)) + (else (call $odd (i32.sub (local.get $n) (i32.const 1)))) ) + ) - (assert_return (invoke "even" (i32.const 13)) (i32.const 0)) - (assert_return (invoke "even" (i32.const 20)) (i32.const 1)) - (assert_return (invoke "odd" (i32.const 13)) (i32.const 1)) - (assert_return (invoke "odd" (i32.const 20)) (i32.const 0)) - """ - let wast = try parseWast(source) - #expect(wast.count == 5) - guard case .module(let module) = wast.first, case .text(var wat) = module.source else { - #expect((false), "expect a module directive") - return - } - #expect(wat.functionsMap.count == 2) - let even = wat.functionsMap[0] - let (evenType, _) = try wat.types.resolve(use: even.typeUse) - #expect(evenType.signature.parameters == [.i32]) - #expect(evenType.signature.results.first == .i32) - #expect(evenType.parameterNames.map(\.?.value) == ["$n"]) - } - - @Test - func funcIdBinding() throws { - let source = """ - (module - (table $t 10 funcref) - (func $f) - (func $g) - - ;; Passive - (elem funcref) - (elem funcref (ref.func $f) (item ref.func $f) (item (ref.null func)) (ref.func $g)) - (elem func) - (elem func $f $f $g $g) - - (elem $p1 funcref) - (elem $p2 funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g)) - (elem $p3 func) - (elem $p4 func $f $f $g $g) - - ;; Active - (elem (table $t) (i32.const 0) funcref) - (elem (table $t) (i32.const 0) funcref (ref.func $f) (ref.null func)) - (elem (table $t) (i32.const 0) func) - (elem (table $t) (i32.const 0) func $f $g) - (elem (table $t) (offset (i32.const 0)) funcref) - (elem (table $t) (offset (i32.const 0)) func $f $g) + (func $odd (export "odd") (param $n i32) (result i32) + (if (result i32) (i32.eq (local.get $n) (i32.const 0)) + (then (i32.const 0)) + (else (call $even (i32.sub (local.get $n) (i32.const 1)))) ) - """ - let wat = try parseWAT(source) - #expect(wat.tables.count == 1) - let table = wat.tables[0] - #expect(table.type == TableType(elementType: .funcRef, limits: Limits(min: 10, max: nil))) - #expect(wat.elementsMap.count == 14) - } + ) + ) - // NOTE: We do the same check as a part of the EncoderTests, so it's - // usually redundant and time-wasting to run this test every time. - // Keeping it here just for local unit testing purposes. - @Test( - .enabled(if: ProcessInfo.processInfo.environment["WASMKIT_PARSER_SPECTEST"] == "1"), - arguments: Spectest.wastFiles(include: []) - ) - func parseSpectest(wastFile: URL) throws { - let source = try String(contentsOf: wastFile) - _ = try parseWast(source, features: Spectest.deriveFeatureSet(wast: wastFile)) + (assert_return (invoke "even" (i32.const 13)) (i32.const 0)) + (assert_return (invoke "even" (i32.const 20)) (i32.const 1)) + (assert_return (invoke "odd" (i32.const 13)) (i32.const 1)) + (assert_return (invoke "odd" (i32.const 20)) (i32.const 0)) + """ + let wast = try parseWast(source) + #expect(wast.count == 5) + guard case .module(let module) = wast.first, case .text(var wat) = module.source else { + #expect((false), "expect a module directive") + return } + #expect(wat.functionsMap.count == 2) + let even = wat.functionsMap[0] + let (evenType, _) = try wat.types.resolve(use: even.typeUse) + #expect(evenType.signature.parameters == [.i32]) + #expect(evenType.signature.results.first == .i32) + #expect(evenType.parameterNames.map(\.?.value) == ["$n"]) + } + + @Test + func funcIdBinding() throws { + let source = """ + (module + (table $t 10 funcref) + (func $f) + (func $g) + + ;; Passive + (elem funcref) + (elem funcref (ref.func $f) (item ref.func $f) (item (ref.null func)) (ref.func $g)) + (elem func) + (elem func $f $f $g $g) + + (elem $p1 funcref) + (elem $p2 funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g)) + (elem $p3 func) + (elem $p4 func $f $f $g $g) + + ;; Active + (elem (table $t) (i32.const 0) funcref) + (elem (table $t) (i32.const 0) funcref (ref.func $f) (ref.null func)) + (elem (table $t) (i32.const 0) func) + (elem (table $t) (i32.const 0) func $f $g) + (elem (table $t) (offset (i32.const 0)) funcref) + (elem (table $t) (offset (i32.const 0)) func $f $g) + ) + """ + let wat = try parseWAT(source) + #expect(wat.tables.count == 1) + let table = wat.tables[0] + #expect(table.type == TableType(elementType: .funcRef, limits: Limits(min: 10, max: nil))) + #expect(wat.elementsMap.count == 14) + } + + // NOTE: We do the same check as a part of the EncoderTests, so it's + // usually redundant and time-wasting to run this test every time. + // Keeping it here just for local unit testing purposes. + @Test( + .enabled(if: ProcessInfo.processInfo.environment["WASMKIT_PARSER_SPECTEST"] == "1"), + arguments: Spectest.wastFiles(include: []) + ) + func parseSpectest(wastFile: URL) throws { + let source = try String(contentsOf: wastFile) + _ = try parseWast(source, features: Spectest.deriveFeatureSet(wast: wastFile)) } +} -#endif diff --git a/Tests/WasmKitTests/Execution/HostModuleTests.swift b/Tests/WasmKitTests/Execution/HostModuleTests.swift index dcbbb835..f99dea23 100644 --- a/Tests/WasmKitTests/Execution/HostModuleTests.swift +++ b/Tests/WasmKitTests/Execution/HostModuleTests.swift @@ -1,83 +1,81 @@ -#if canImport(Testing) - import WAT - import Testing +import Testing +import WAT - @testable import WasmKit - @testable import WasmParser +@testable import WasmKit +@testable import WasmParser - @Suite - struct HostModuleTests { - @Test - func importMemory() throws { - let engine = Engine() - let store = Store(engine: engine) - let memoryType = MemoryType(min: 1, max: nil) - let memory = try WasmKit.Memory(store: store, type: memoryType) - let imports: Imports = [ - "env": ["memory": memory] - ] +@Suite +struct HostModuleTests { + @Test + func importMemory() throws { + let engine = Engine() + let store = Store(engine: engine) + let memoryType = MemoryType(min: 1, max: nil) + let memory = try WasmKit.Memory(store: store, type: memoryType) + let imports: Imports = [ + "env": ["memory": memory] + ] - let module = try parseWasm( - bytes: wat2wasm( - """ - (module - (import "env" "memory" (memory 1)) - ) - """)) - #expect(throws: Never.self) { try module.instantiate(store: store, imports: imports) } - // Ensure the allocated address is valid - _ = memory.data - } + let module = try parseWasm( + bytes: wat2wasm( + """ + (module + (import "env" "memory" (memory 1)) + ) + """)) + #expect(throws: Never.self) { try module.instantiate(store: store, imports: imports) } + // Ensure the allocated address is valid + _ = memory.data + } - @Test - func reentrancy() throws { - let engine = Engine() - let store = Store(engine: engine) - let voidSignature = WasmTypes.FunctionType(parameters: [], results: []) - let module = try parseWasm( - bytes: wat2wasm( - """ - (module - (import "env" "bar" (func $bar)) - (import "env" "qux" (func $qux)) - (func (export "foo") - (call $bar) - (call $bar) - (call $bar) - ) - (func (export "baz") - (call $qux) - ) + @Test + func reentrancy() throws { + let engine = Engine() + let store = Store(engine: engine) + let voidSignature = WasmTypes.FunctionType(parameters: [], results: []) + let module = try parseWasm( + bytes: wat2wasm( + """ + (module + (import "env" "bar" (func $bar)) + (import "env" "qux" (func $qux)) + (func (export "foo") + (call $bar) + (call $bar) + (call $bar) + ) + (func (export "baz") + (call $qux) ) - """) - ) + ) + """) + ) - var isExecutingFoo = false - var isQuxCalled = false - let imports: Imports = [ - "env": [ - "bar": Function(store: store, type: voidSignature) { caller, _ in - // Ensure "invoke" executes instructions under the current call - #expect(isExecutingFoo == false, "bar should not be called recursively") - isExecutingFoo = true - defer { isExecutingFoo = false } - let foo = try #require(caller.instance?.exportedFunction(name: "baz")) - _ = try foo() - return [] - }, - "qux": Function(store: store, type: voidSignature) { caller, _ in - #expect(isExecutingFoo == true) - isQuxCalled = true - return [] - }, - ] + var isExecutingFoo = false + var isQuxCalled = false + let imports: Imports = [ + "env": [ + "bar": Function(store: store, type: voidSignature) { caller, _ in + // Ensure "invoke" executes instructions under the current call + #expect(isExecutingFoo == false, "bar should not be called recursively") + isExecutingFoo = true + defer { isExecutingFoo = false } + let foo = try #require(caller.instance?.exportedFunction(name: "baz")) + _ = try foo() + return [] + }, + "qux": Function(store: store, type: voidSignature) { caller, _ in + #expect(isExecutingFoo == true) + isQuxCalled = true + return [] + }, ] - let instance = try module.instantiate(store: store, imports: imports) - // Check foo(wasm) -> bar(host) -> baz(wasm) -> qux(host) - let foo = try #require(instance.exports[function: "foo"]) - try foo() - #expect(isQuxCalled == true) - } + ] + let instance = try module.instantiate(store: store, imports: imports) + // Check foo(wasm) -> bar(host) -> baz(wasm) -> qux(host) + let foo = try #require(instance.exports[function: "foo"]) + try foo() + #expect(isQuxCalled == true) } +} -#endif diff --git a/Tests/WasmKitTests/Execution/Runtime/StoreAllocatorTests.swift b/Tests/WasmKitTests/Execution/Runtime/StoreAllocatorTests.swift index af8adcf7..15467e8c 100644 --- a/Tests/WasmKitTests/Execution/Runtime/StoreAllocatorTests.swift +++ b/Tests/WasmKitTests/Execution/Runtime/StoreAllocatorTests.swift @@ -1,53 +1,51 @@ -#if canImport(Testing) - import WAT - import WasmParser - import Testing +import WAT +import WasmParser +import Testing - @testable import WasmKit +@testable import WasmKit - @Suite - struct StoreAllocatorTests { - @Test - func bumpAllocatorDeallocates() { - class NonTrivialEntity {} - weak var weakEntity: NonTrivialEntity? +@Suite +struct StoreAllocatorTests { + @Test + func bumpAllocatorDeallocates() { + class NonTrivialEntity {} + weak var weakEntity: NonTrivialEntity? + do { + let allocator = BumpAllocator(initialCapacity: 2) do { - let allocator = BumpAllocator(initialCapacity: 2) - do { - let entity = NonTrivialEntity() - // Allocate space placing non-trivial entity - // This `allocate` call should retain the entity - _ = allocator.allocate(initializing: entity) - // Ensure that the initial page is full - _ = allocator.allocate(initializing: entity) - _ = allocator.allocate(initializing: entity) - weakEntity = entity - } - // The entity is still alive because the allocator retains it - #expect(weakEntity != nil) + let entity = NonTrivialEntity() + // Allocate space placing non-trivial entity + // This `allocate` call should retain the entity + _ = allocator.allocate(initializing: entity) + // Ensure that the initial page is full + _ = allocator.allocate(initializing: entity) + _ = allocator.allocate(initializing: entity) + weakEntity = entity } - // The entity should be deallocated when the allocator is deallocated - #expect(weakEntity == nil) + // The entity is still alive because the allocator retains it + #expect(weakEntity != nil) } + // The entity should be deallocated when the allocator is deallocated + #expect(weakEntity == nil) + } - @Test - func storeAllocatorLeak() throws { - weak var weakAllocator: StoreAllocator? - do { - let module = try parseWasm( - bytes: wat2wasm( - """ - (module - (memory (;0;) 0) - (export "a" (memory 0))) - """)) - let engine = Engine() - let store = Store(engine: engine) - _ = try module.instantiate(store: store) - weakAllocator = store.allocator - } - #expect(weakAllocator == nil) + @Test + func storeAllocatorLeak() throws { + weak var weakAllocator: StoreAllocator? + do { + let module = try parseWasm( + bytes: wat2wasm( + """ + (module + (memory (;0;) 0) + (export "a" (memory 0))) + """)) + let engine = Engine() + let store = Store(engine: engine) + _ = try module.instantiate(store: store) + weakAllocator = store.allocator } + #expect(weakAllocator == nil) } +} -#endif diff --git a/Tests/WasmKitTests/FuzzTranslatorRegressionTests.swift b/Tests/WasmKitTests/FuzzTranslatorRegressionTests.swift index 5a05580a..33c88f78 100644 --- a/Tests/WasmKitTests/FuzzTranslatorRegressionTests.swift +++ b/Tests/WasmKitTests/FuzzTranslatorRegressionTests.swift @@ -1,42 +1,40 @@ -#if canImport(Testing) - import WasmKit - import WasmKitFuzzing - import Foundation - import Testing +import WasmKit +import WasmKitFuzzing +import Foundation +import Testing - @Suite - struct FuzzTranslatorRegressionTests { +@Suite +struct FuzzTranslatorRegressionTests { - struct Case: CustomStringConvertible { - let path: URL - let description: String - } + struct Case: CustomStringConvertible { + let path: URL + let description: String + } - static let sourceRoot = URL(fileURLWithPath: #filePath) - .deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent() + static let sourceRoot = URL(fileURLWithPath: #filePath) + .deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent() - static func failCases() throws -> [Case] { - let failCasesDir = sourceRoot.appendingPathComponent("FuzzTesting/FailCases/FuzzTranslator") - return try FileManager.default.contentsOfDirectory(atPath: failCasesDir.path).map { - let url = failCasesDir.appendingPathComponent($0) - return Case(path: url, description: String(url.path.dropFirst(sourceRoot.path.count + 1))) - } + static func failCases() throws -> [Case] { + let failCasesDir = sourceRoot.appendingPathComponent("FuzzTesting/FailCases/FuzzTranslator") + return try FileManager.default.contentsOfDirectory(atPath: failCasesDir.path).map { + let url = failCasesDir.appendingPathComponent($0) + return Case(path: url, description: String(url.path.dropFirst(sourceRoot.path.count + 1))) } + } - #if !os(Android) - @Test( - .disabled("unable to run fuzz translator regression tests on Android due to missing files on emulator", platforms: [.android]), - arguments: try failCases() - ) - func run(test: Case) throws { - let data = try Data(contentsOf: test.path) - do { - try WasmKitFuzzing.fuzzInstantiation(bytes: Array(data)) - } catch { - // Skip exceptions without crash - } + #if !os(Android) + @Test( + .disabled("unable to run fuzz translator regression tests on Android due to missing files on emulator", platforms: [.android]), + arguments: try failCases() + ) + func run(test: Case) throws { + let data = try Data(contentsOf: test.path) + do { + try WasmKitFuzzing.fuzzInstantiation(bytes: Array(data)) + } catch { + // Skip exceptions without crash } - #endif - } + } + #endif +} -#endif diff --git a/Tests/WasmKitTests/SpectestTests.swift b/Tests/WasmKitTests/SpectestTests.swift index 000a9138..a5721da9 100644 --- a/Tests/WasmKitTests/SpectestTests.swift +++ b/Tests/WasmKitTests/SpectestTests.swift @@ -1,46 +1,44 @@ -#if canImport(Testing) - import Foundation - import Testing - import WasmKit +import Foundation +import Testing +import WasmKit - @Suite - struct SpectestTests { - static let projectDir = URL(fileURLWithPath: #filePath) - .deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent() - static let testsuite = - projectDir - .appendingPathComponent("Vendor/testsuite") - static var testPaths: [String] { - [ - Self.testsuite.path, - Self.testsuite.appendingPathComponent("proposals/memory64").path, - Self.testsuite.appendingPathComponent("proposals/tail-call").path, - Self.projectDir.appendingPathComponent("Tests/WasmKitTests/ExtraSuite").path, - ] - } +@Suite +struct SpectestTests { + static let projectDir = URL(fileURLWithPath: #filePath) + .deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent() + static let testsuite = + projectDir + .appendingPathComponent("Vendor/testsuite") + static var testPaths: [String] { + [ + Self.testsuite.path, + Self.testsuite.appendingPathComponent("proposals/memory64").path, + Self.testsuite.appendingPathComponent("proposals/tail-call").path, + Self.projectDir.appendingPathComponent("Tests/WasmKitTests/ExtraSuite").path, + ] + } - #if !os(Android) - @Test( - .disabled("unable to run spectest on Android due to missing files on emulator", platforms: [.android]), - arguments: try SpectestDiscovery(path: SpectestTests.testPaths).discover() - ) - func run(test: TestCase) throws { - let defaultConfig = EngineConfiguration() - let runner = try SpectestRunner(configuration: defaultConfig) - try runner.run(test: test, reporter: NullSpectestProgressReporter()) - } + #if !os(Android) + @Test( + .disabled("unable to run spectest on Android due to missing files on emulator", platforms: [.android]), + arguments: try SpectestDiscovery(path: SpectestTests.testPaths).discover() + ) + func run(test: TestCase) throws { + let defaultConfig = EngineConfiguration() + let runner = try SpectestRunner(configuration: defaultConfig) + try runner.run(test: test, reporter: NullSpectestProgressReporter()) + } - @Test( - .disabled("unable to run spectest on Android due to missing files on emulator", platforms: [.android]), - arguments: try SpectestDiscovery(path: SpectestTests.testPaths).discover() - ) - func runWithTokenThreading(test: TestCase) throws { - let defaultConfig = EngineConfiguration() - guard defaultConfig.threadingModel != .token else { return } - // Sanity check that non-default threading models work. - let runner = try SpectestRunner(configuration: defaultConfig) - try runner.run(test: test, reporter: NullSpectestProgressReporter()) - } - #endif - } -#endif + @Test( + .disabled("unable to run spectest on Android due to missing files on emulator", platforms: [.android]), + arguments: try SpectestDiscovery(path: SpectestTests.testPaths).discover() + ) + func runWithTokenThreading(test: TestCase) throws { + let defaultConfig = EngineConfiguration() + guard defaultConfig.threadingModel != .token else { return } + // Sanity check that non-default threading models work. + let runner = try SpectestRunner(configuration: defaultConfig) + try runner.run(test: test, reporter: NullSpectestProgressReporter()) + } + #endif +} diff --git a/Tests/WasmKitTests/Trait+Platform.swift b/Tests/WasmKitTests/Trait+Platform.swift index c1b86270..7d479aed 100644 --- a/Tests/WasmKitTests/Trait+Platform.swift +++ b/Tests/WasmKitTests/Trait+Platform.swift @@ -1,31 +1,29 @@ -#if canImport(Testing) - import Testing +import Testing - enum TargetPlatform { - case android +enum TargetPlatform { + case android - func isCurrentPlatform() -> Bool { - switch self { - case .android: - #if os(Android) - return true - #else - return false - #endif - } + func isCurrentPlatform() -> Bool { + switch self { + case .android: + #if os(Android) + return true + #else + return false + #endif } } +} - extension Trait where Self == ConditionTrait { - static func disabled( - _ comment: Comment? = nil, - sourceLocation: SourceLocation = #_sourceLocation, - platforms: [TargetPlatform] - ) -> Self { - return .disabled(comment, sourceLocation: sourceLocation) { - platforms.contains { $0.isCurrentPlatform() } - } +extension Trait where Self == ConditionTrait { + static func disabled( + _ comment: Comment? = nil, + sourceLocation: SourceLocation = #_sourceLocation, + platforms: [TargetPlatform] + ) -> Self { + return .disabled(comment, sourceLocation: sourceLocation) { + platforms.contains { $0.isCurrentPlatform() } } } +} -#endif From 76383ad3ff893af1c75dc74de6ada558bf5e059a Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Thu, 23 Oct 2025 00:18:45 +0100 Subject: [PATCH 4/4] Fix formatting --- Tests/WASITests/IntegrationTests.swift | 3 +-- .../Platform/SandboxPrimitives/OpenParentTests.swift | 2 +- Tests/WASITests/RandomBufferGeneratorTests.swift | 1 - Tests/WATTests/EncoderTests.swift | 2 +- Tests/WATTests/LexerTests.swift | 2 +- Tests/WATTests/ParserTests.swift | 3 +-- Tests/WasmKitTests/Execution/HostModuleTests.swift | 1 - .../WasmKitTests/Execution/Runtime/StoreAllocatorTests.swift | 3 +-- Tests/WasmKitTests/FuzzTranslatorRegressionTests.swift | 5 ++--- Tests/WasmKitTests/Trait+Platform.swift | 1 - 10 files changed, 8 insertions(+), 15 deletions(-) diff --git a/Tests/WASITests/IntegrationTests.swift b/Tests/WASITests/IntegrationTests.swift index c8400147..9f508605 100644 --- a/Tests/WASITests/IntegrationTests.swift +++ b/Tests/WASITests/IntegrationTests.swift @@ -1,8 +1,8 @@ import Foundation import SystemPackage +import Testing import WasmKit import WasmKitWASI -import Testing @Suite struct IntegrationTests { @@ -209,4 +209,3 @@ struct IntegrationTests { #expect(exitCode == manifest.exitCode ?? 0, "\(path.path)") } } - diff --git a/Tests/WASITests/Platform/SandboxPrimitives/OpenParentTests.swift b/Tests/WASITests/Platform/SandboxPrimitives/OpenParentTests.swift index acd67288..fbd63efb 100644 --- a/Tests/WASITests/Platform/SandboxPrimitives/OpenParentTests.swift +++ b/Tests/WASITests/Platform/SandboxPrimitives/OpenParentTests.swift @@ -1,5 +1,5 @@ -import Testing import SystemPackage +import Testing @testable import WASI diff --git a/Tests/WASITests/RandomBufferGeneratorTests.swift b/Tests/WASITests/RandomBufferGeneratorTests.swift index 8ab48f05..91aecc3a 100644 --- a/Tests/WASITests/RandomBufferGeneratorTests.swift +++ b/Tests/WASITests/RandomBufferGeneratorTests.swift @@ -35,4 +35,3 @@ struct RandomBufferGeneratorTests { } } } - diff --git a/Tests/WATTests/EncoderTests.swift b/Tests/WATTests/EncoderTests.swift index 3e5ca678..5fbb925d 100644 --- a/Tests/WATTests/EncoderTests.swift +++ b/Tests/WATTests/EncoderTests.swift @@ -1,5 +1,5 @@ -import Testing import Foundation +import Testing import WasmParser @testable import WAT diff --git a/Tests/WATTests/LexerTests.swift b/Tests/WATTests/LexerTests.swift index ed075ba6..0ba3afef 100644 --- a/Tests/WATTests/LexerTests.swift +++ b/Tests/WATTests/LexerTests.swift @@ -1,5 +1,5 @@ -import Testing import Foundation +import Testing import WasmParser @testable import WAT diff --git a/Tests/WATTests/ParserTests.swift b/Tests/WATTests/ParserTests.swift index 2cab915e..f505692b 100644 --- a/Tests/WATTests/ParserTests.swift +++ b/Tests/WATTests/ParserTests.swift @@ -1,5 +1,5 @@ -import Testing import Foundation +import Testing import WasmParser @testable import WAT @@ -193,4 +193,3 @@ struct ParserTests { _ = try parseWast(source, features: Spectest.deriveFeatureSet(wast: wastFile)) } } - diff --git a/Tests/WasmKitTests/Execution/HostModuleTests.swift b/Tests/WasmKitTests/Execution/HostModuleTests.swift index f99dea23..f53a3d8b 100644 --- a/Tests/WasmKitTests/Execution/HostModuleTests.swift +++ b/Tests/WasmKitTests/Execution/HostModuleTests.swift @@ -78,4 +78,3 @@ struct HostModuleTests { #expect(isQuxCalled == true) } } - diff --git a/Tests/WasmKitTests/Execution/Runtime/StoreAllocatorTests.swift b/Tests/WasmKitTests/Execution/Runtime/StoreAllocatorTests.swift index 15467e8c..9fc1bba0 100644 --- a/Tests/WasmKitTests/Execution/Runtime/StoreAllocatorTests.swift +++ b/Tests/WasmKitTests/Execution/Runtime/StoreAllocatorTests.swift @@ -1,6 +1,6 @@ +import Testing import WAT import WasmParser -import Testing @testable import WasmKit @@ -48,4 +48,3 @@ struct StoreAllocatorTests { #expect(weakAllocator == nil) } } - diff --git a/Tests/WasmKitTests/FuzzTranslatorRegressionTests.swift b/Tests/WasmKitTests/FuzzTranslatorRegressionTests.swift index 33c88f78..15344b88 100644 --- a/Tests/WasmKitTests/FuzzTranslatorRegressionTests.swift +++ b/Tests/WasmKitTests/FuzzTranslatorRegressionTests.swift @@ -1,7 +1,7 @@ -import WasmKit -import WasmKitFuzzing import Foundation import Testing +import WasmKit +import WasmKitFuzzing @Suite struct FuzzTranslatorRegressionTests { @@ -37,4 +37,3 @@ struct FuzzTranslatorRegressionTests { } #endif } - diff --git a/Tests/WasmKitTests/Trait+Platform.swift b/Tests/WasmKitTests/Trait+Platform.swift index 7d479aed..97f594bb 100644 --- a/Tests/WasmKitTests/Trait+Platform.swift +++ b/Tests/WasmKitTests/Trait+Platform.swift @@ -26,4 +26,3 @@ extension Trait where Self == ConditionTrait { } } } -