From 839db2cdc009fffe156d1d7a86317172d4958750 Mon Sep 17 00:00:00 2001 From: Bassam Khouri Date: Fri, 21 Aug 2026 18:36:59 -0400 Subject: [PATCH] Migrate more test suites to Swift Testing Migrate seven test suites from XCTest to Swift Testing: - `InputOriginTests` (converted to a parameterized test using `CustomTestStringConvertible` for descriptive case IDs) - `SendableTests` (compile-time-only suite) - `RawRepresentableEndToEndTests` - `EqualsEndToEndTests` - `EnumEndToEndTests` - `SingleValueParsingStrategyTests` - `AsyncCommandEndToEndTests` (marked `@Suite(.serialized)` with `@MainActor` tests because the suite shares the global `statusCheck` state that XCTest previously serialized implicitly) Relates to #710 --- .../AsyncCommandEndToEndTests.swift | 20 +++-- .../EnumEndToEndTests.swift | 77 ++++++++++--------- .../EqualsEndToEndTests.swift | 45 ++++++----- .../RawRepresentableEndToEndTests.swift | 31 ++++---- .../SingleValueParsingStrategyTests.swift | 65 ++++++++-------- .../InputOriginTests.swift | 63 +++++++++------ .../SendableTests.swift | 7 +- 7 files changed, 166 insertions(+), 142 deletions(-) diff --git a/Tests/ArgumentParserEndToEndTests/AsyncCommandEndToEndTests.swift b/Tests/ArgumentParserEndToEndTests/AsyncCommandEndToEndTests.swift index 7fbcd4a6a..188316adc 100644 --- a/Tests/ArgumentParserEndToEndTests/AsyncCommandEndToEndTests.swift +++ b/Tests/ArgumentParserEndToEndTests/AsyncCommandEndToEndTests.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Argument Parser open source project // -// Copyright (c) 2020 Apple Inc. and the Swift project authors +// Copyright (c) 2020-2026 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,9 +10,9 @@ //===----------------------------------------------------------------------===// import ArgumentParser -import XCTest +import Testing -final class AsyncCommandEndToEndTests: XCTestCase {} +@Suite(.serialized) struct AsyncCommandEndToEndTests {} actor AsyncStatusCheck { struct Status: OptionSet { @@ -55,17 +55,15 @@ struct AsyncCommand: AsyncParsableCommand { // swift-format-ignore: AlwaysUseLowerCamelCase // https://github.com/apple/swift-argument-parser/issues/710 extension AsyncCommandEndToEndTests { - @MainActor - func testAsyncMain_root() async throws { - XCTAssertFalse(statusCheck.status.contains(.root)) + @Test @MainActor func asyncMain_root() async throws { + #expect(!statusCheck.status.contains(.root)) await AsyncCommand.main([]) - XCTAssertTrue(statusCheck.status.contains(.root)) + #expect(statusCheck.status.contains(.root)) } - @MainActor - func testAsyncMain_sub() async throws { - XCTAssertFalse(statusCheck.status.contains(.sub)) + @Test @MainActor func asyncMain_sub() async throws { + #expect(!statusCheck.status.contains(.sub)) await AsyncCommand.main(["sub-command"]) - XCTAssertTrue(statusCheck.status.contains(.sub)) + #expect(statusCheck.status.contains(.sub)) } } diff --git a/Tests/ArgumentParserEndToEndTests/EnumEndToEndTests.swift b/Tests/ArgumentParserEndToEndTests/EnumEndToEndTests.swift index 43d72effa..8607af74a 100644 --- a/Tests/ArgumentParserEndToEndTests/EnumEndToEndTests.swift +++ b/Tests/ArgumentParserEndToEndTests/EnumEndToEndTests.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Argument Parser open source project // -// Copyright (c) 2020 Apple Inc. and the Swift project authors +// Copyright (c) 2020-2026 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -12,9 +12,8 @@ import ArgumentParser import ArgumentParserTestHelpers import Testing -import XCTest -final class EnumEndToEndTests: XCTestCase {} +@Suite struct EnumEndToEndTests {} // MARK: - @@ -31,26 +30,26 @@ private struct Bar: ParsableArguments { // swift-format-ignore: AlwaysUseLowerCamelCase // https://github.com/apple/swift-argument-parser/issues/710 extension EnumEndToEndTests { - func testParsing_SingleOption() throws { - AssertParse(Bar.self, ["--index", "hello"]) { bar in - XCTAssertEqual(bar.index, Bar.Index.hello) + @Test func parsing_SingleOption() throws { + expectParse(Bar.self, ["--index", "hello"]) { bar in + #expect(bar.index == Bar.Index.hello) } - AssertParse(Bar.self, ["--index", "goodbye"]) { bar in - XCTAssertEqual(bar.index, Bar.Index.goodbye) + expectParse(Bar.self, ["--index", "goodbye"]) { bar in + #expect(bar.index == Bar.Index.goodbye) } } - func testParsing_SingleOptionMultipleTimes() throws { - AssertParse(Bar.self, ["--index", "hello", "--index", "goodbye"]) { bar in - XCTAssertEqual(bar.index, Bar.Index.goodbye) + @Test func parsing_SingleOptionMultipleTimes() throws { + expectParse(Bar.self, ["--index", "hello", "--index", "goodbye"]) { bar in + #expect(bar.index == Bar.Index.goodbye) } } - func testParsing_SingleOption_Fails() throws { - XCTAssertThrowsError(try Bar.parse([])) - XCTAssertThrowsError(try Bar.parse(["--index"])) - XCTAssertThrowsError(try Bar.parse(["--index", "hell"])) - XCTAssertThrowsError(try Bar.parse(["--index", "helloo"])) + @Test func parsing_SingleOption_Fails() throws { + #expect(throws: (any Error).self) { try Bar.parse([]) } + #expect(throws: (any Error).self) { try Bar.parse(["--index"]) } + #expect(throws: (any Error).self) { try Bar.parse(["--index", "hell"]) } + #expect(throws: (any Error).self) { try Bar.parse(["--index", "helloo"]) } } } @@ -69,32 +68,40 @@ private struct Baz: ParsableArguments { // swift-format-ignore: AlwaysUseLowerCamelCase // https://github.com/apple/swift-argument-parser/issues/710 extension EnumEndToEndTests { - func test_ParsingRawValue_Option() throws { - AssertParse(Baz.self, ["--mode", "generate-bash-script"]) { baz in - XCTAssertEqual(baz.modeOption, .generateBashScript) - XCTAssertNil(baz.modeArg) + @Test func parsingRawValue_Option() throws { + expectParse(Baz.self, ["--mode", "generate-bash-script"]) { baz in + #expect(baz.modeOption == .generateBashScript) + #expect(baz.modeArg == nil) } - AssertParse(Baz.self, ["--mode", "generateZshScript"]) { baz in - XCTAssertEqual(baz.modeOption, .generateZshScript) - XCTAssertNil(baz.modeArg) + expectParse(Baz.self, ["--mode", "generateZshScript"]) { baz in + #expect(baz.modeOption == .generateZshScript) + #expect(baz.modeArg == nil) } } - func test_ParsingRawValue_Argument() throws { - AssertParse(Baz.self, ["generate-bash-script"]) { baz in - XCTAssertEqual(baz.modeArg, .generateBashScript) - XCTAssertNil(baz.modeOption) + @Test func parsingRawValue_Argument() throws { + expectParse(Baz.self, ["generate-bash-script"]) { baz in + #expect(baz.modeArg == .generateBashScript) + #expect(baz.modeOption == nil) } - AssertParse(Baz.self, ["generateZshScript"]) { baz in - XCTAssertEqual(baz.modeArg, .generateZshScript) - XCTAssertNil(baz.modeOption) + expectParse(Baz.self, ["generateZshScript"]) { baz in + #expect(baz.modeArg == .generateZshScript) + #expect(baz.modeOption == nil) } } - func test_ParsingRawValue_Fails() throws { - XCTAssertThrowsError(try Baz.parse(["generateBashScript"])) - XCTAssertThrowsError(try Baz.parse(["--mode generateBashScript"])) - XCTAssertThrowsError(try Baz.parse(["generate-zsh-script"])) - XCTAssertThrowsError(try Baz.parse(["--mode generate-zsh-script"])) + @Test func parsingRawValue_Fails() throws { + #expect(throws: (any Error).self) { + try Baz.parse(["generateBashScript"]) + } + #expect(throws: (any Error).self) { + try Baz.parse(["--mode generateBashScript"]) + } + #expect(throws: (any Error).self) { + try Baz.parse(["generate-zsh-script"]) + } + #expect(throws: (any Error).self) { + try Baz.parse(["--mode generate-zsh-script"]) + } } } diff --git a/Tests/ArgumentParserEndToEndTests/EqualsEndToEndTests.swift b/Tests/ArgumentParserEndToEndTests/EqualsEndToEndTests.swift index c8f6d42b3..ccfb12ca6 100644 --- a/Tests/ArgumentParserEndToEndTests/EqualsEndToEndTests.swift +++ b/Tests/ArgumentParserEndToEndTests/EqualsEndToEndTests.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Argument Parser open source project // -// Copyright (c) 2020 Apple Inc. and the Swift project authors +// Copyright (c) 2020-2026 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -12,9 +12,8 @@ import ArgumentParser import ArgumentParserTestHelpers import Testing -import XCTest -final class EqualsEndToEndTests: XCTestCase {} +@Suite struct EqualsEndToEndTests {} // MARK: .short name @@ -27,24 +26,24 @@ private struct Foo: ParsableArguments { // swift-format-ignore: AlwaysUseLowerCamelCase // https://github.com/apple/swift-argument-parser/issues/710 extension EqualsEndToEndTests { - func testEquals_withShortName() throws { - AssertParse(Foo.self, ["-n=Name", "-f=Format"]) { foo in - XCTAssertEqual(foo.toggle, false) - XCTAssertEqual(foo.name, "Name") - XCTAssertEqual(foo.format, "Format") + @Test func equals_withShortName() throws { + expectParse(Foo.self, ["-n=Name", "-f=Format"]) { foo in + #expect(foo.toggle == false) + #expect(foo.name == "Name") + #expect(foo.format == "Format") } } - func testEquals_withCombinedShortName_1() throws { - AssertParse(Foo.self, ["-tf", "Format"]) { foo in - XCTAssertEqual(foo.toggle, true) - XCTAssertEqual(foo.name, nil) - XCTAssertEqual(foo.format, "Format") + @Test func equals_withCombinedShortName_1() throws { + expectParse(Foo.self, ["-tf", "Format"]) { foo in + #expect(foo.toggle == true) + #expect(foo.name == nil) + #expect(foo.format == "Format") } } - func testEquals_withCombinedShortName_2() throws { - XCTAssertThrowsError(try Foo.parse(["-tf=Format"])) + @Test func equals_withCombinedShortName_2() throws { + #expect(throws: (any Error).self) { try Foo.parse(["-tf=Format"]) } } } @@ -58,10 +57,10 @@ private struct Bar: ParsableArguments { // swift-format-ignore: AlwaysUseLowerCamelCase // https://github.com/apple/swift-argument-parser/issues/710 extension EqualsEndToEndTests { - func testEquals_withShortAndLongName() throws { - AssertParse(Bar.self, ["-n=Name", "-f=Format"]) { bar in - XCTAssertEqual(bar.name, "Name") - XCTAssertEqual(bar.format, "Format") + @Test func equals_withShortAndLongName() throws { + expectParse(Bar.self, ["-n=Name", "-f=Format"]) { bar in + #expect(bar.name == "Name") + #expect(bar.format == "Format") } } } @@ -76,10 +75,10 @@ private struct Baz: ParsableArguments { // swift-format-ignore: AlwaysUseLowerCamelCase // https://github.com/apple/swift-argument-parser/issues/710 extension EqualsEndToEndTests { - func testEquals_withCustomShortName() throws { - AssertParse(Baz.self, ["-i=Name", "-t=Format"]) { baz in - XCTAssertEqual(baz.name, "Name") - XCTAssertEqual(baz.format, "Format") + @Test func equals_withCustomShortName() throws { + expectParse(Baz.self, ["-i=Name", "-t=Format"]) { baz in + #expect(baz.name == "Name") + #expect(baz.format == "Format") } } } diff --git a/Tests/ArgumentParserEndToEndTests/RawRepresentableEndToEndTests.swift b/Tests/ArgumentParserEndToEndTests/RawRepresentableEndToEndTests.swift index 4f7563baf..234903384 100644 --- a/Tests/ArgumentParserEndToEndTests/RawRepresentableEndToEndTests.swift +++ b/Tests/ArgumentParserEndToEndTests/RawRepresentableEndToEndTests.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Argument Parser open source project // -// Copyright (c) 2020 Apple Inc. and the Swift project authors +// Copyright (c) 2020-2026 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -12,9 +12,8 @@ import ArgumentParser import ArgumentParserTestHelpers import Testing -import XCTest -final class RawRepresentableEndToEndTests: XCTestCase {} +@Suite struct RawRepresentableEndToEndTests {} // MARK: - @@ -29,24 +28,28 @@ private struct Bar: ParsableArguments { // swift-format-ignore: AlwaysUseLowerCamelCase // https://github.com/apple/swift-argument-parser/issues/710 extension RawRepresentableEndToEndTests { - func testParsing_SingleOption() throws { - AssertParse(Bar.self, ["--identifier", "123"]) { bar in - XCTAssertEqual(bar.identifier, Bar.Identifier(rawValue: 123)) + @Test func parsing_SingleOption() throws { + expectParse(Bar.self, ["--identifier", "123"]) { bar in + #expect(bar.identifier == Bar.Identifier(rawValue: 123)) } } - func testParsing_SingleOptionMultipleTimes() throws { - AssertParse(Bar.self, ["--identifier", "123", "--identifier", "456"]) { + @Test func parsing_SingleOptionMultipleTimes() throws { + expectParse(Bar.self, ["--identifier", "123", "--identifier", "456"]) { bar in - XCTAssertEqual(bar.identifier, Bar.Identifier(rawValue: 456)) + #expect(bar.identifier == Bar.Identifier(rawValue: 456)) } } - func testParsing_SingleOption_Fails() throws { - XCTAssertThrowsError(try Bar.parse([])) - XCTAssertThrowsError(try Bar.parse(["--identifier"])) - XCTAssertThrowsError(try Bar.parse(["--identifier", "not a number"])) - XCTAssertThrowsError(try Bar.parse(["--identifier", "123.456"])) + @Test func parsing_SingleOption_Fails() throws { + #expect(throws: (any Error).self) { try Bar.parse([]) } + #expect(throws: (any Error).self) { try Bar.parse(["--identifier"]) } + #expect(throws: (any Error).self) { + try Bar.parse(["--identifier", "not a number"]) + } + #expect(throws: (any Error).self) { + try Bar.parse(["--identifier", "123.456"]) + } } } diff --git a/Tests/ArgumentParserEndToEndTests/SingleValueParsingStrategyTests.swift b/Tests/ArgumentParserEndToEndTests/SingleValueParsingStrategyTests.swift index 583541211..116da1640 100644 --- a/Tests/ArgumentParserEndToEndTests/SingleValueParsingStrategyTests.swift +++ b/Tests/ArgumentParserEndToEndTests/SingleValueParsingStrategyTests.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Argument Parser open source project // -// Copyright (c) 2020 Apple Inc. and the Swift project authors +// Copyright (c) 2020-2026 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -12,9 +12,8 @@ import ArgumentParser import ArgumentParserTestHelpers import Testing -import XCTest -final class SingleValueParsingStrategyTests: XCTestCase {} +@Suite struct SingleValueParsingStrategyTests {} // MARK: Scanning for Value @@ -27,33 +26,33 @@ private struct Bar: ParsableArguments { // swift-format-ignore: AlwaysUseLowerCamelCase // https://github.com/apple/swift-argument-parser/issues/710 extension SingleValueParsingStrategyTests { - func testParsing_scanningForValue_1() throws { - AssertParse( + @Test func parsing_scanningForValue_1() throws { + expectParse( Bar.self, ["--name", "Foo", "--format", "Bar", "--input", "Baz"] ) { bar in - XCTAssertEqual(bar.name, "Foo") - XCTAssertEqual(bar.format, "Bar") - XCTAssertEqual(bar.input, "Baz") + #expect(bar.name == "Foo") + #expect(bar.format == "Bar") + #expect(bar.input == "Baz") } } - func testParsing_scanningForValue_2() throws { - AssertParse( + @Test func parsing_scanningForValue_2() throws { + expectParse( Bar.self, ["--name", "--format", "Foo", "Bar", "--input", "Baz"] ) { bar in - XCTAssertEqual(bar.name, "Foo") - XCTAssertEqual(bar.format, "Bar") - XCTAssertEqual(bar.input, "Baz") + #expect(bar.name == "Foo") + #expect(bar.format == "Bar") + #expect(bar.input == "Baz") } } - func testParsing_scanningForValue_3() throws { - AssertParse( + @Test func parsing_scanningForValue_3() throws { + expectParse( Bar.self, ["--name", "--format", "--input", "Foo", "Bar", "Baz"] ) { bar in - XCTAssertEqual(bar.name, "Foo") - XCTAssertEqual(bar.format, "Bar") - XCTAssertEqual(bar.input, "Baz") + #expect(bar.name == "Foo") + #expect(bar.format == "Bar") + #expect(bar.input == "Baz") } } } @@ -69,34 +68,34 @@ private struct Baz: ParsableArguments { // swift-format-ignore: AlwaysUseLowerCamelCase // https://github.com/apple/swift-argument-parser/issues/710 extension SingleValueParsingStrategyTests { - func testParsing_unconditional_1() throws { - AssertParse( + @Test func parsing_unconditional_1() throws { + expectParse( Baz.self, ["--name", "Foo", "--format", "Bar", "--input", "Baz"] ) { bar in - XCTAssertEqual(bar.name, "Foo") - XCTAssertEqual(bar.format, "Bar") - XCTAssertEqual(bar.input, "Baz") + #expect(bar.name == "Foo") + #expect(bar.format == "Bar") + #expect(bar.input == "Baz") } } - func testParsing_unconditional_2() throws { - AssertParse( + @Test func parsing_unconditional_2() throws { + expectParse( Baz.self, ["--name", "--name", "--format", "--format", "--input", "--input"] ) { bar in - XCTAssertEqual(bar.name, "--name") - XCTAssertEqual(bar.format, "--format") - XCTAssertEqual(bar.input, "--input") + #expect(bar.name == "--name") + #expect(bar.format == "--format") + #expect(bar.input == "--input") } } - func testParsing_unconditional_3() throws { - AssertParse( + @Test func parsing_unconditional_3() throws { + expectParse( Baz.self, ["--name", "-Foo", "--format", "-Bar", "--input", "-Baz"] ) { bar in - XCTAssertEqual(bar.name, "-Foo") - XCTAssertEqual(bar.format, "-Bar") - XCTAssertEqual(bar.input, "-Baz") + #expect(bar.name == "-Foo") + #expect(bar.format == "-Bar") + #expect(bar.input == "-Baz") } } } diff --git a/Tests/ArgumentParserUnitTests/InputOriginTests.swift b/Tests/ArgumentParserUnitTests/InputOriginTests.swift index 996bb825c..399a890ed 100644 --- a/Tests/ArgumentParserUnitTests/InputOriginTests.swift +++ b/Tests/ArgumentParserUnitTests/InputOriginTests.swift @@ -2,39 +2,58 @@ // // This source file is part of the Swift Argument Parser open source project // -// Copyright (c) 2021 Apple Inc. and the Swift project authors +// Copyright (c) 2021-2026 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // //===----------------------------------------------------------------------===// -import XCTest +import Testing @testable import ArgumentParser -final class InputOriginTests: XCTestCase {} +@Suite struct InputOriginTests {} extension InputOriginTests { - func testIsDefaultValue() { - func assert(elements: [InputOrigin.Element], expectedIsDefaultValue: Bool) { - let inputOrigin = InputOrigin(elements: elements) - if expectedIsDefaultValue { - XCTAssertTrue(inputOrigin.isDefaultValue) - } else { - XCTAssertFalse(inputOrigin.isDefaultValue) - } - } - assert(elements: [], expectedIsDefaultValue: false) - assert(elements: [.defaultValue], expectedIsDefaultValue: true) - assert( - elements: [.argumentIndex(SplitArguments.Index(inputIndex: 1))], - expectedIsDefaultValue: false) - assert( - elements: [ - .defaultValue, .argumentIndex(SplitArguments.Index(inputIndex: 1)), - ], - expectedIsDefaultValue: false) + struct IsDefaultTestData: CustomTestStringConvertible { + let id: String + let elements: [InputOrigin.Element] + let expectedIsDefaultValue: Bool + var testDescription: String { id } + } + @Test( + arguments: [ + IsDefaultTestData( + id: "empty elements", + elements: [], + expectedIsDefaultValue: false), + IsDefaultTestData( + id: "single default value", + elements: [ + .defaultValue + ], + expectedIsDefaultValue: true), + IsDefaultTestData( + id: "single argument index", + elements: [ + .argumentIndex(SplitArguments.Index(inputIndex: 1)) + ], + expectedIsDefaultValue: false + ), + IsDefaultTestData( + id: "default value with argument index", + elements: [ + .defaultValue, + .argumentIndex(SplitArguments.Index(inputIndex: 1)), + ], + expectedIsDefaultValue: false + ), + ] + ) + func isDefaultValue(tcData: IsDefaultTestData) { + let inputOrigin = InputOrigin(elements: tcData.elements) + #expect(inputOrigin.isDefaultValue == tcData.expectedIsDefaultValue) } } diff --git a/Tests/ArgumentParserUnitTests/SendableTests.swift b/Tests/ArgumentParserUnitTests/SendableTests.swift index ae0effece..227faa551 100644 --- a/Tests/ArgumentParserUnitTests/SendableTests.swift +++ b/Tests/ArgumentParserUnitTests/SendableTests.swift @@ -2,20 +2,19 @@ // // This source file is part of the Swift Argument Parser open source project // -// Copyright (c) 2023 Apple Inc. and the Swift project authors +// Copyright (c) 2026 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // //===----------------------------------------------------------------------===// -import XCTest +import Testing @testable import ArgumentParser -final class SendableTests: XCTestCase {} +@Suite struct SendableTests { -extension SendableTests { struct MyExpressibleType: ExpressibleByArgument { public init?(argument: String) {} }