mirror of
https://github.com/apple/swift-argument-parser.git
synced 2026-06-06 20:18:23 +00:00
863 lines
31 KiB
Swift
863 lines
31 KiB
Swift
//===----------------------------------------------------------*- swift -*-===//
|
|
//
|
|
// This source file is part of the Swift Argument Parser open source project
|
|
//
|
|
// Copyright (c) 2020 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 ArgumentParserTestHelpers
|
|
import ArgumentParser
|
|
|
|
final class DefaultsEndToEndTests: XCTestCase {
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
fileprivate struct Foo: ParsableArguments {
|
|
struct Name: RawRepresentable, ExpressibleByArgument {
|
|
var rawValue: String
|
|
}
|
|
@Option
|
|
var name: Name = Name(rawValue: "A")
|
|
@Option
|
|
var max: Int = 3
|
|
}
|
|
|
|
extension DefaultsEndToEndTests {
|
|
func testParsing_Defaults() throws {
|
|
AssertParse(Foo.self, []) { foo in
|
|
XCTAssertEqual(foo.name.rawValue, "A")
|
|
XCTAssertEqual(foo.max, 3)
|
|
}
|
|
|
|
AssertParse(Foo.self, ["--name", "B"]) { foo in
|
|
XCTAssertEqual(foo.name.rawValue, "B")
|
|
XCTAssertEqual(foo.max, 3)
|
|
}
|
|
|
|
AssertParse(Foo.self, ["--max", "5"]) { foo in
|
|
XCTAssertEqual(foo.name.rawValue, "A")
|
|
XCTAssertEqual(foo.max, 5)
|
|
}
|
|
|
|
AssertParse(Foo.self, ["--max", "5", "--name", "B"]) { foo in
|
|
XCTAssertEqual(foo.name.rawValue, "B")
|
|
XCTAssertEqual(foo.max, 5)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
fileprivate struct Bar: ParsableArguments {
|
|
enum Format: String, ExpressibleByArgument {
|
|
case A
|
|
case B
|
|
case C
|
|
}
|
|
@Option
|
|
var name: String = "N"
|
|
@Option
|
|
var format: Format = .A
|
|
@Option()
|
|
var foo: String
|
|
@Argument()
|
|
var bar: String?
|
|
}
|
|
|
|
extension DefaultsEndToEndTests {
|
|
func testParsing_Optional_WithAllValues_1() {
|
|
AssertParse(Bar.self, ["--name", "A", "--format", "B", "--foo", "C", "D"]) { bar in
|
|
XCTAssertEqual(bar.name, "A")
|
|
XCTAssertEqual(bar.format, .B)
|
|
XCTAssertEqual(bar.foo, "C")
|
|
XCTAssertEqual(bar.bar, "D")
|
|
}
|
|
}
|
|
|
|
func testParsing_Optional_WithAllValues_2() {
|
|
AssertParse(Bar.self, ["D", "--format", "B", "--foo", "C", "--name", "A"]) { bar in
|
|
XCTAssertEqual(bar.name, "A")
|
|
XCTAssertEqual(bar.format, .B)
|
|
XCTAssertEqual(bar.foo, "C")
|
|
XCTAssertEqual(bar.bar, "D")
|
|
}
|
|
}
|
|
|
|
func testParsing_Optional_WithAllValues_3() {
|
|
AssertParse(Bar.self, ["--format", "B", "--foo", "C", "D", "--name", "A"]) { bar in
|
|
XCTAssertEqual(bar.name, "A")
|
|
XCTAssertEqual(bar.format, .B)
|
|
XCTAssertEqual(bar.foo, "C")
|
|
XCTAssertEqual(bar.bar, "D")
|
|
}
|
|
}
|
|
|
|
func testParsing_Optional_WithMissingValues_1() {
|
|
AssertParse(Bar.self, ["--format", "B", "--foo", "C", "D"]) { bar in
|
|
XCTAssertEqual(bar.name, "N")
|
|
XCTAssertEqual(bar.format, .B)
|
|
XCTAssertEqual(bar.foo, "C")
|
|
XCTAssertEqual(bar.bar, "D")
|
|
}
|
|
}
|
|
|
|
func testParsing_Optional_WithMissingValues_2() {
|
|
AssertParse(Bar.self, ["D", "--format", "B", "--foo", "C"]) { bar in
|
|
XCTAssertEqual(bar.name, "N")
|
|
XCTAssertEqual(bar.format, .B)
|
|
XCTAssertEqual(bar.foo, "C")
|
|
XCTAssertEqual(bar.bar, "D")
|
|
}
|
|
}
|
|
|
|
func testParsing_Optional_WithMissingValues_3() {
|
|
AssertParse(Bar.self, ["--format", "B", "--foo", "C", "D"]) { bar in
|
|
XCTAssertEqual(bar.name, "N")
|
|
XCTAssertEqual(bar.format, .B)
|
|
XCTAssertEqual(bar.foo, "C")
|
|
XCTAssertEqual(bar.bar, "D")
|
|
}
|
|
}
|
|
|
|
func testParsing_Optional_WithMissingValues_4() {
|
|
AssertParse(Bar.self, ["--name", "A", "--format", "B", "--foo", "C"]) { bar in
|
|
XCTAssertEqual(bar.name, "A")
|
|
XCTAssertEqual(bar.format, .B)
|
|
XCTAssertEqual(bar.foo, "C")
|
|
XCTAssertEqual(bar.bar, nil)
|
|
}
|
|
}
|
|
|
|
func testParsing_Optional_WithMissingValues_5() {
|
|
AssertParse(Bar.self, ["--format", "B", "--foo", "C", "--name", "A"]) { bar in
|
|
XCTAssertEqual(bar.name, "A")
|
|
XCTAssertEqual(bar.format,.B)
|
|
XCTAssertEqual(bar.foo, "C")
|
|
XCTAssertEqual(bar.bar, nil)
|
|
}
|
|
}
|
|
|
|
func testParsing_Optional_WithMissingValues_6() {
|
|
AssertParse(Bar.self, ["--format", "B", "--foo", "C", "--name", "A"]) { bar in
|
|
XCTAssertEqual(bar.name, "A")
|
|
XCTAssertEqual(bar.format, .B)
|
|
XCTAssertEqual(bar.foo, "C")
|
|
XCTAssertEqual(bar.bar, nil)
|
|
}
|
|
}
|
|
|
|
func testParsing_Optional_WithMissingValues_7() {
|
|
AssertParse(Bar.self, ["--foo", "C"]) { bar in
|
|
XCTAssertEqual(bar.name, "N")
|
|
XCTAssertEqual(bar.format, .A)
|
|
XCTAssertEqual(bar.foo, "C")
|
|
XCTAssertEqual(bar.bar, nil)
|
|
}
|
|
}
|
|
|
|
func testParsing_Optional_WithMissingValues_8() {
|
|
AssertParse(Bar.self, ["--format", "B", "--foo", "C"]) { bar in
|
|
XCTAssertEqual(bar.name, "N")
|
|
XCTAssertEqual(bar.format, .B)
|
|
XCTAssertEqual(bar.foo, "C")
|
|
XCTAssertEqual(bar.bar, nil)
|
|
}
|
|
}
|
|
|
|
func testParsing_Optional_WithMissingValues_9() {
|
|
AssertParse(Bar.self, ["--format", "B", "--foo", "C"]) { bar in
|
|
XCTAssertEqual(bar.name, "N")
|
|
XCTAssertEqual(bar.format, .B)
|
|
XCTAssertEqual(bar.foo, "C")
|
|
XCTAssertEqual(bar.bar, nil)
|
|
}
|
|
}
|
|
|
|
func testParsing_Optional_WithMissingValues_10() {
|
|
AssertParse(Bar.self, ["--format", "B", "--foo", "C"]) { bar in
|
|
XCTAssertEqual(bar.name, "N")
|
|
XCTAssertEqual(bar.format, .B)
|
|
XCTAssertEqual(bar.foo, "C")
|
|
XCTAssertEqual(bar.bar, nil)
|
|
}
|
|
}
|
|
|
|
func testParsing_Optional_Fails() throws {
|
|
XCTAssertThrowsError(try Bar.parse([]))
|
|
XCTAssertThrowsError(try Bar.parse(["--fooz", "C"]))
|
|
XCTAssertThrowsError(try Bar.parse(["--nam", "A", "--foo", "C"]))
|
|
XCTAssertThrowsError(try Bar.parse(["--name"]))
|
|
XCTAssertThrowsError(try Bar.parse(["A"]))
|
|
XCTAssertThrowsError(try Bar.parse(["--name", "A", "D"]))
|
|
XCTAssertThrowsError(try Bar.parse(["--name", "A", "--foo"]))
|
|
XCTAssertThrowsError(try Bar.parse(["--name", "A", "--format", "B"]))
|
|
XCTAssertThrowsError(try Bar.parse(["--name", "A", "-f"]))
|
|
XCTAssertThrowsError(try Bar.parse(["D", "--name", "A"]))
|
|
XCTAssertThrowsError(try Bar.parse(["-f", "--name", "A"]))
|
|
XCTAssertThrowsError(try Bar.parse(["--foo", "--name", "A"]))
|
|
XCTAssertThrowsError(try Bar.parse(["--foo", "--name", "AA", "BB"]))
|
|
}
|
|
}
|
|
|
|
fileprivate struct Bar_NextInput: ParsableArguments {
|
|
enum Format: String, ExpressibleByArgument {
|
|
case A
|
|
case B
|
|
case C
|
|
case D = "-d"
|
|
}
|
|
@Option(parsing: .unconditional)
|
|
var name: String = "N"
|
|
@Option(parsing: .unconditional)
|
|
var format: Format = .A
|
|
@Option(parsing: .unconditional)
|
|
var foo: String
|
|
@Argument()
|
|
var bar: String?
|
|
}
|
|
|
|
extension DefaultsEndToEndTests {
|
|
func testParsing_Optional_WithOverlappingValues_1() {
|
|
AssertParse(Bar_NextInput.self, ["--format", "B", "--name", "--foo", "--foo", "--name"]) { bar in
|
|
XCTAssertEqual(bar.name, "--foo")
|
|
XCTAssertEqual(bar.format, .B)
|
|
XCTAssertEqual(bar.foo, "--name")
|
|
XCTAssertEqual(bar.bar, nil)
|
|
}
|
|
}
|
|
|
|
func testParsing_Optional_WithOverlappingValues_2() {
|
|
AssertParse(Bar_NextInput.self, ["--format", "-d", "--foo", "--name", "--name", "--foo"]) { bar in
|
|
XCTAssertEqual(bar.name, "--foo")
|
|
XCTAssertEqual(bar.format, .D)
|
|
XCTAssertEqual(bar.foo, "--name")
|
|
XCTAssertEqual(bar.bar, nil)
|
|
}
|
|
}
|
|
|
|
func testParsing_Optional_WithOverlappingValues_3() {
|
|
AssertParse(Bar_NextInput.self, ["--format", "-d", "--name", "--foo", "--foo", "--name", "bar"]) { bar in
|
|
XCTAssertEqual(bar.name, "--foo")
|
|
XCTAssertEqual(bar.format, .D)
|
|
XCTAssertEqual(bar.foo, "--name")
|
|
XCTAssertEqual(bar.bar, "bar")
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
fileprivate struct Baz: ParsableArguments {
|
|
@Option(parsing: .unconditional) var int: Int = 0
|
|
@Option(parsing: .unconditional) var int8: Int8 = 0
|
|
@Option(parsing: .unconditional) var int16: Int16 = 0
|
|
@Option(parsing: .unconditional) var int32: Int32 = 0
|
|
@Option(parsing: .unconditional) var int64: Int64 = 0
|
|
@Option var uint: UInt = 0
|
|
@Option var uint8: UInt8 = 0
|
|
@Option var uint16: UInt16 = 0
|
|
@Option var uint32: UInt32 = 0
|
|
@Option var uint64: UInt64 = 0
|
|
|
|
@Option(parsing: .unconditional) var float: Float = 0
|
|
@Option(parsing: .unconditional) var double: Double = 0
|
|
|
|
@Option var bool: Bool = false
|
|
}
|
|
|
|
extension DefaultsEndToEndTests {
|
|
func testParsing_AllTypes_1() {
|
|
AssertParse(Baz.self, []) { baz in
|
|
XCTAssertEqual(baz.int, 0)
|
|
XCTAssertEqual(baz.int8, 0)
|
|
XCTAssertEqual(baz.int16, 0)
|
|
XCTAssertEqual(baz.int32, 0)
|
|
XCTAssertEqual(baz.int64, 0)
|
|
XCTAssertEqual(baz.uint, 0)
|
|
XCTAssertEqual(baz.uint8, 0)
|
|
XCTAssertEqual(baz.uint16, 0)
|
|
XCTAssertEqual(baz.uint32, 0)
|
|
XCTAssertEqual(baz.uint64, 0)
|
|
XCTAssertEqual(baz.float, 0)
|
|
XCTAssertEqual(baz.double, 0)
|
|
XCTAssertEqual(baz.bool, false)
|
|
}
|
|
}
|
|
|
|
func testParsing_AllTypes_2() {
|
|
AssertParse(Baz.self, [
|
|
"--int", "-1", "--int8", "-2", "--int16", "-3", "--int32", "-4", "--int64", "-5",
|
|
"--uint", "1", "--uint8", "2", "--uint16", "3", "--uint32", "4", "--uint64", "5",
|
|
"--float", "1.25", "--double", "2.5", "--bool", "true"
|
|
]) { baz in
|
|
XCTAssertEqual(baz.int, -1)
|
|
XCTAssertEqual(baz.int8, -2)
|
|
XCTAssertEqual(baz.int16, -3)
|
|
XCTAssertEqual(baz.int32, -4)
|
|
XCTAssertEqual(baz.int64, -5)
|
|
XCTAssertEqual(baz.uint, 1)
|
|
XCTAssertEqual(baz.uint8, 2)
|
|
XCTAssertEqual(baz.uint16, 3)
|
|
XCTAssertEqual(baz.uint32, 4)
|
|
XCTAssertEqual(baz.uint64, 5)
|
|
XCTAssertEqual(baz.float, 1.25)
|
|
XCTAssertEqual(baz.double, 2.5)
|
|
XCTAssertEqual(baz.bool, true)
|
|
}
|
|
}
|
|
|
|
func testParsing_AllTypes_Fails() throws {
|
|
XCTAssertThrowsError(try Baz.parse(["--int8", "256"]))
|
|
XCTAssertThrowsError(try Baz.parse(["--int16", "32768"]))
|
|
XCTAssertThrowsError(try Baz.parse(["--int32", "2147483648"]))
|
|
XCTAssertThrowsError(try Baz.parse(["--int64", "9223372036854775808"]))
|
|
XCTAssertThrowsError(try Baz.parse(["--int", "9223372036854775808"]))
|
|
|
|
XCTAssertThrowsError(try Baz.parse(["--uint8", "512"]))
|
|
XCTAssertThrowsError(try Baz.parse(["--uint16", "65536"]))
|
|
XCTAssertThrowsError(try Baz.parse(["--uint32", "4294967296"]))
|
|
XCTAssertThrowsError(try Baz.parse(["--uint64", "18446744073709551616"]))
|
|
XCTAssertThrowsError(try Baz.parse(["--uint", "18446744073709551616"]))
|
|
|
|
XCTAssertThrowsError(try Baz.parse(["--uint8", "-1"]))
|
|
XCTAssertThrowsError(try Baz.parse(["--uint16", "-1"]))
|
|
XCTAssertThrowsError(try Baz.parse(["--uint32", "-1"]))
|
|
XCTAssertThrowsError(try Baz.parse(["--uint64", "-1"]))
|
|
XCTAssertThrowsError(try Baz.parse(["--uint", "-1"]))
|
|
|
|
XCTAssertThrowsError(try Baz.parse(["--float", "zzz"]))
|
|
XCTAssertThrowsError(try Baz.parse(["--double", "zzz"]))
|
|
XCTAssertThrowsError(try Baz.parse(["--bool", "truthy"]))
|
|
}
|
|
}
|
|
|
|
fileprivate struct Qux: ParsableArguments {
|
|
@Argument
|
|
var name: String = "quux"
|
|
}
|
|
|
|
extension DefaultsEndToEndTests {
|
|
func testParsing_ArgumentDefaults() throws {
|
|
AssertParse(Qux.self, []) { qux in
|
|
XCTAssertEqual(qux.name, "quux")
|
|
}
|
|
AssertParse(Qux.self, ["Bar"]) { qux in
|
|
XCTAssertEqual(qux.name, "Bar")
|
|
}
|
|
AssertParse(Qux.self, ["Bar-"]) { qux in
|
|
XCTAssertEqual(qux.name, "Bar-")
|
|
}
|
|
AssertParse(Qux.self, ["Bar--"]) { qux in
|
|
XCTAssertEqual(qux.name, "Bar--")
|
|
}
|
|
AssertParse(Qux.self, ["--", "-Bar"]) { qux in
|
|
XCTAssertEqual(qux.name, "-Bar")
|
|
}
|
|
AssertParse(Qux.self, ["--", "--Bar"]) { qux in
|
|
XCTAssertEqual(qux.name, "--Bar")
|
|
}
|
|
AssertParse(Qux.self, ["--", "--"]) { qux in
|
|
XCTAssertEqual(qux.name, "--")
|
|
}
|
|
}
|
|
|
|
func testParsing_ArgumentDefaults_Fails() throws {
|
|
XCTAssertThrowsError(try Qux.parse(["--name"]))
|
|
XCTAssertThrowsError(try Qux.parse(["Foo", "Bar"]))
|
|
}
|
|
}
|
|
|
|
fileprivate func exclaim(_ input: String) throws -> String {
|
|
return input + "!"
|
|
}
|
|
|
|
fileprivate struct OptionPropertyInitArguments_Default: ParsableArguments {
|
|
@Option
|
|
var data: String = "test"
|
|
|
|
@Option(transform: exclaim)
|
|
var transformedData: String = "test"
|
|
}
|
|
|
|
fileprivate struct OptionPropertyInitArguments_NoDefault_NoTransform: ParsableArguments {
|
|
@Option()
|
|
var data: String
|
|
}
|
|
|
|
fileprivate struct OptionPropertyInitArguments_NoDefault_Transform: ParsableArguments {
|
|
@Option(transform: exclaim)
|
|
var transformedData: String
|
|
}
|
|
|
|
extension DefaultsEndToEndTests {
|
|
/// Tests that using default property initialization syntax parses the default value for the argument when nothing is provided from the command-line.
|
|
func testParsing_OptionPropertyInit_Default_NoTransform_UseDefault() throws {
|
|
AssertParse(OptionPropertyInitArguments_Default.self, []) { arguments in
|
|
XCTAssertEqual(arguments.data, "test")
|
|
}
|
|
}
|
|
|
|
/// Tests that using default property initialization syntax parses the command-line-provided value for the argument when provided.
|
|
func testParsing_OptionPropertyInit_Default_NoTransform_OverrideDefault() throws {
|
|
AssertParse(OptionPropertyInitArguments_Default.self, ["--data", "test2"]) { arguments in
|
|
XCTAssertEqual(arguments.data, "test2")
|
|
}
|
|
}
|
|
|
|
/// Tests that *not* providing a default value still parses the argument correctly from the command-line.
|
|
/// This test is almost certainly duplicated by others in the repository, but allows for quick use of test filtering during development on the initialization functionality.
|
|
func testParsing_OptionPropertyInit_NoDefault_NoTransform() throws {
|
|
AssertParse(OptionPropertyInitArguments_NoDefault_NoTransform.self, ["--data", "test"]) { arguments in
|
|
XCTAssertEqual(arguments.data, "test")
|
|
}
|
|
}
|
|
|
|
/// Tests that using default property initialization syntax on a property with a `transform` function provided parses the default value for the argument when nothing is provided from the command-line.
|
|
func testParsing_OptionPropertyInit_Default_Transform_UseDefault() throws {
|
|
AssertParse(OptionPropertyInitArguments_Default.self, []) { arguments in
|
|
XCTAssertEqual(arguments.transformedData, "test")
|
|
}
|
|
}
|
|
|
|
/// Tests that using default property initialization syntax on a property with a `transform` function provided parses and transforms the command-line-provided value for the argument when provided.
|
|
func testParsing_OptionPropertyInit_Default_Transform_OverrideDefault() throws {
|
|
AssertParse(OptionPropertyInitArguments_Default.self, ["--transformed-data", "test2"]) { arguments in
|
|
XCTAssertEqual(arguments.transformedData, "test2!")
|
|
}
|
|
}
|
|
|
|
/// Tests that *not* providing a default value for a property with a `transform` function still parses the argument correctly from the command-line.
|
|
/// This test is almost certainly duplicated by others in the repository, but allows for quick use of test filtering during development on the initialization functionality.
|
|
func testParsing_OptionPropertyInit_NoDefault_Transform() throws {
|
|
AssertParse(OptionPropertyInitArguments_NoDefault_Transform.self, ["--transformed-data", "test"]) { arguments in
|
|
XCTAssertEqual(arguments.transformedData, "test!")
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
fileprivate struct ArgumentPropertyInitArguments_Default_NoTransform: ParsableArguments {
|
|
@Argument
|
|
var data: String = "test"
|
|
}
|
|
|
|
fileprivate struct ArgumentPropertyInitArguments_NoDefault_NoTransform: ParsableArguments {
|
|
@Argument()
|
|
var data: String
|
|
}
|
|
|
|
fileprivate struct ArgumentPropertyInitArguments_Default_Transform: ParsableArguments {
|
|
@Argument(transform: exclaim)
|
|
var transformedData: String = "test"
|
|
}
|
|
|
|
fileprivate struct ArgumentPropertyInitArguments_NoDefault_Transform: ParsableArguments {
|
|
@Argument(transform: exclaim)
|
|
var transformedData: String
|
|
}
|
|
|
|
extension DefaultsEndToEndTests {
|
|
/// Tests that using default property initialization syntax parses the default value for the argument when nothing is provided from the command-line.
|
|
func testParsing_ArgumentPropertyInit_Default_NoTransform_UseDefault() throws {
|
|
AssertParse(ArgumentPropertyInitArguments_Default_NoTransform.self, []) { arguments in
|
|
XCTAssertEqual(arguments.data, "test")
|
|
}
|
|
}
|
|
|
|
/// Tests that using default property initialization syntax parses the command-line-provided value for the argument when provided.
|
|
func testParsing_ArgumentPropertyInit_Default_NoTransform_OverrideDefault() throws {
|
|
AssertParse(ArgumentPropertyInitArguments_Default_NoTransform.self, ["test2"]) { arguments in
|
|
XCTAssertEqual(arguments.data, "test2")
|
|
}
|
|
}
|
|
|
|
/// Tests that *not* providing a default value still parses the argument correctly from the command-line.
|
|
/// This test is almost certainly duplicated by others in the repository, but allows for quick use of test filtering during development on the initialization functionality.
|
|
func testParsing_ArgumentPropertyInit_NoDefault_NoTransform() throws {
|
|
AssertParse(ArgumentPropertyInitArguments_NoDefault_NoTransform.self, ["test"]) { arguments in
|
|
XCTAssertEqual(arguments.data, "test")
|
|
}
|
|
}
|
|
|
|
/// Tests that using default property initialization syntax on a property with a `transform` function provided parses the default value for the argument when nothing is provided from the command-line.
|
|
func testParsing_ArgumentPropertyInit_Default_Transform_UseDefault() throws {
|
|
AssertParse(ArgumentPropertyInitArguments_Default_Transform.self, []) { arguments in
|
|
XCTAssertEqual(arguments.transformedData, "test")
|
|
}
|
|
}
|
|
|
|
/// Tests that using default property initialization syntax on a property with a `transform` function provided parses and transforms the command-line-provided value for the argument when provided.
|
|
func testParsing_ArgumentPropertyInit_Default_Transform_OverrideDefault() throws {
|
|
AssertParse(ArgumentPropertyInitArguments_Default_Transform.self, ["test2"]) { arguments in
|
|
XCTAssertEqual(arguments.transformedData, "test2!")
|
|
}
|
|
}
|
|
|
|
/// Tests that *not* providing a default value for a property with a `transform` function still parses the argument correctly from the command-line.
|
|
/// This test is almost certainly duplicated by others in the repository, but allows for quick use of test filtering during development on the initialization functionality.
|
|
func testParsing_ArgumentPropertyInit_NoDefault_Transform() throws {
|
|
AssertParse(ArgumentPropertyInitArguments_NoDefault_Transform.self, ["test"]) { arguments in
|
|
XCTAssertEqual(arguments.transformedData, "test!")
|
|
}
|
|
}
|
|
}
|
|
|
|
fileprivate struct Quux: ParsableArguments {
|
|
@Option(parsing: .upToNextOption)
|
|
var letters: [String] = ["A", "B"]
|
|
|
|
@Argument()
|
|
var numbers: [Int] = [1, 2]
|
|
}
|
|
|
|
extension DefaultsEndToEndTests {
|
|
func testParsing_ArrayDefaults() throws {
|
|
AssertParse(Quux.self, []) { qux in
|
|
XCTAssertEqual(qux.letters, ["A", "B"])
|
|
XCTAssertEqual(qux.numbers, [1, 2])
|
|
}
|
|
AssertParse(Quux.self, ["--letters", "C", "D"]) { qux in
|
|
XCTAssertEqual(qux.letters, ["C", "D"])
|
|
XCTAssertEqual(qux.numbers, [1, 2])
|
|
}
|
|
AssertParse(Quux.self, ["3", "4"]) { qux in
|
|
XCTAssertEqual(qux.letters, ["A", "B"])
|
|
XCTAssertEqual(qux.numbers, [3, 4])
|
|
}
|
|
AssertParse(Quux.self, ["3", "4", "--letters", "C", "D"]) { qux in
|
|
XCTAssertEqual(qux.letters, ["C", "D"])
|
|
XCTAssertEqual(qux.numbers, [3, 4])
|
|
}
|
|
}
|
|
}
|
|
|
|
fileprivate struct FlagPropertyInitArguments_Bool_Default: ParsableArguments {
|
|
@Flag(inversion: .prefixedNo)
|
|
var data: Bool = false
|
|
}
|
|
|
|
fileprivate struct FlagPropertyInitArguments_Bool_NoDefault: ParsableArguments {
|
|
@Flag(inversion: .prefixedNo)
|
|
var data: Bool
|
|
}
|
|
|
|
extension DefaultsEndToEndTests {
|
|
/// Tests that using default property initialization syntax parses the default value for the argument when nothing is provided from the command-line.
|
|
func testParsing_FlagPropertyInit_Bool_Default_UseDefault() throws {
|
|
AssertParse(FlagPropertyInitArguments_Bool_Default.self, []) { arguments in
|
|
XCTAssertEqual(arguments.data, false)
|
|
}
|
|
}
|
|
|
|
/// Tests that using default property initialization syntax parses the command-line-provided value for the argument when provided.
|
|
func testParsing_FlagPropertyInit_Bool_Default_OverrideDefault() throws {
|
|
AssertParse(FlagPropertyInitArguments_Bool_Default.self, ["--data"]) { arguments in
|
|
XCTAssertEqual(arguments.data, true)
|
|
}
|
|
}
|
|
|
|
/// Tests that *not* providing a default value still parses the argument correctly from the command-line.
|
|
/// This test is almost certainly duplicated by others in the repository, but allows for quick use of test filtering during development on the initialization functionality.
|
|
func testParsing_FlagPropertyInit_Bool_NoDefault() throws {
|
|
AssertParse(FlagPropertyInitArguments_Bool_NoDefault.self, ["--data"]) { arguments in
|
|
XCTAssertEqual(arguments.data, true)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
fileprivate enum HasData: EnumerableFlag {
|
|
case noData
|
|
case data
|
|
}
|
|
|
|
fileprivate struct FlagPropertyInitArguments_EnumerableFlag_Default: ParsableArguments {
|
|
@Flag
|
|
var data: HasData = .noData
|
|
}
|
|
|
|
fileprivate struct FlagPropertyInitArguments_EnumerableFlag_NoDefault: ParsableArguments {
|
|
@Flag()
|
|
var data: HasData
|
|
}
|
|
|
|
|
|
extension DefaultsEndToEndTests {
|
|
/// Tests that using default property initialization syntax parses the default value for the argument when nothing is provided from the command-line.
|
|
func testParsing_FlagPropertyInit_EnumerableFlag_Default_UseDefault() throws {
|
|
AssertParse(FlagPropertyInitArguments_EnumerableFlag_Default.self, []) { arguments in
|
|
XCTAssertEqual(arguments.data, .noData)
|
|
}
|
|
}
|
|
|
|
/// Tests that using default property initialization syntax parses the command-line-provided value for the argument when provided.
|
|
func testParsing_FlagPropertyInit_EnumerableFlag_Default_OverrideDefault() throws {
|
|
AssertParse(FlagPropertyInitArguments_EnumerableFlag_Default.self, ["--data"]) { arguments in
|
|
XCTAssertEqual(arguments.data, .data)
|
|
}
|
|
}
|
|
|
|
/// Tests that *not* providing a default value still parses the argument correctly from the command-line.
|
|
/// This test is almost certainly duplicated by others in the repository, but allows for quick use of test filtering during development on the initialization functionality.
|
|
func testParsing_FlagPropertyInit_EnumerableFlag_NoDefault() throws {
|
|
AssertParse(FlagPropertyInitArguments_EnumerableFlag_NoDefault.self, ["--data"]) { arguments in
|
|
XCTAssertEqual(arguments.data, .data)
|
|
}
|
|
}
|
|
}
|
|
|
|
fileprivate struct Main: ParsableCommand {
|
|
static var configuration = CommandConfiguration(
|
|
shouldPromptForMissing: false,
|
|
subcommands: [Sub.self],
|
|
defaultSubcommand: Sub.self
|
|
)
|
|
|
|
struct Options: ParsableArguments {
|
|
@Option(parsing: .upToNextOption)
|
|
var letters: [String] = ["A", "B"]
|
|
}
|
|
|
|
struct Sub: ParsableCommand {
|
|
static var configuration = CommandConfiguration(shouldPromptForMissing: false)
|
|
@Argument()
|
|
var numbers: [Int] = [1, 2]
|
|
|
|
@OptionGroup()
|
|
var options: Main.Options
|
|
}
|
|
}
|
|
|
|
extension DefaultsEndToEndTests {
|
|
func testParsing_ArrayDefaults_Subcommands() {
|
|
AssertParseCommand(Main.self, Main.Sub.self, []) { sub in
|
|
XCTAssertEqual(sub.options.letters, ["A", "B"])
|
|
XCTAssertEqual(sub.numbers, [1, 2])
|
|
}
|
|
AssertParseCommand(Main.self, Main.Sub.self, ["--letters", "C", "D"]) { sub in
|
|
XCTAssertEqual(sub.options.letters, ["C", "D"])
|
|
XCTAssertEqual(sub.numbers, [1, 2])
|
|
}
|
|
AssertParseCommand(Main.self, Main.Sub.self, ["3", "4"]) { sub in
|
|
XCTAssertEqual(sub.options.letters, ["A", "B"])
|
|
XCTAssertEqual(sub.numbers, [3, 4])
|
|
}
|
|
AssertParseCommand(Main.self, Main.Sub.self, ["3", "4", "--letters", "C", "D"]) { sub in
|
|
XCTAssertEqual(sub.options.letters, ["C", "D"])
|
|
XCTAssertEqual(sub.numbers, [3, 4])
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
fileprivate struct RequiredArray_Option_NoTransform: ParsableArguments {
|
|
@Option(parsing: .remaining)
|
|
var array: [String]
|
|
}
|
|
|
|
fileprivate struct RequiredArray_Option_Transform: ParsableArguments {
|
|
@Option(parsing: .remaining, transform: exclaim)
|
|
var array: [String]
|
|
}
|
|
|
|
fileprivate struct RequiredArray_Argument_NoTransform: ParsableArguments {
|
|
@Argument()
|
|
var array: [String]
|
|
}
|
|
|
|
fileprivate struct RequiredArray_Argument_Transform: ParsableArguments {
|
|
@Argument(transform: exclaim)
|
|
var array: [String]
|
|
}
|
|
|
|
fileprivate struct RequiredArray_Flag: ParsableArguments {
|
|
@Flag
|
|
var array: [HasData]
|
|
}
|
|
|
|
extension DefaultsEndToEndTests {
|
|
/// Tests that not providing an argument for a required array option produces an error.
|
|
func testParsing_RequiredArray_Option_NoTransform_NoInput() {
|
|
XCTAssertThrowsError(try RequiredArray_Option_NoTransform.parse([]))
|
|
}
|
|
|
|
/// Tests that providing a single argument for a required array option parses that value correctly.
|
|
func testParsing_RequiredArray_Option_NoTransform_SingleInput() {
|
|
AssertParse(RequiredArray_Option_NoTransform.self, ["--array", "1"]) { arguments in
|
|
XCTAssertEqual(arguments.array, ["1"])
|
|
}
|
|
}
|
|
|
|
/// Tests that providing multiple arguments for a required array option parses those values correctly.
|
|
func testParsing_RequiredArray_Option_NoTransform_MultipleInput() {
|
|
AssertParse(RequiredArray_Option_NoTransform.self, ["--array", "2", "3"]) { arguments in
|
|
XCTAssertEqual(arguments.array, ["2", "3"])
|
|
}
|
|
}
|
|
|
|
/// Tests that not providing an argument for a required array option with a transform produces an error.
|
|
func testParsing_RequiredArray_Option_Transform_NoInput() {
|
|
XCTAssertThrowsError(try RequiredArray_Option_Transform.parse([]))
|
|
}
|
|
|
|
/// Tests that providing a single argument for a required array option with a transform parses that value correctly.
|
|
func testParsing_RequiredArray_Option_Transform_SingleInput() {
|
|
AssertParse(RequiredArray_Option_Transform.self, ["--array", "1"]) { arguments in
|
|
XCTAssertEqual(arguments.array, ["1!"])
|
|
}
|
|
}
|
|
|
|
/// Tests that providing multiple arguments for a required array option with a transform parses those values correctly.
|
|
func testParsing_RequiredArray_Option_Transform_MultipleInput() {
|
|
AssertParse(RequiredArray_Option_Transform.self, ["--array", "2", "3"]) { arguments in
|
|
XCTAssertEqual(arguments.array, ["2!", "3!"])
|
|
}
|
|
}
|
|
|
|
|
|
/// Tests that not providing an argument for a required array argument produces an error.
|
|
func testParsing_RequiredArray_Argument_NoTransform_NoInput() {
|
|
XCTAssertThrowsError(try RequiredArray_Argument_NoTransform.parse([]))
|
|
}
|
|
|
|
/// Tests that providing a single argument for a required array argument parses that value correctly.
|
|
func testParsing_RequiredArray_Argument_NoTransform_SingleInput() {
|
|
AssertParse(RequiredArray_Argument_NoTransform.self, ["1"]) { arguments in
|
|
XCTAssertEqual(arguments.array, ["1"])
|
|
}
|
|
}
|
|
|
|
/// Tests that providing multiple arguments for a required array argument parses those values correctly.
|
|
func testParsing_RequiredArray_Argument_NoTransform_MultipleInput() {
|
|
AssertParse(RequiredArray_Argument_NoTransform.self, ["2", "3"]) { arguments in
|
|
XCTAssertEqual(arguments.array, ["2", "3"])
|
|
}
|
|
}
|
|
|
|
/// Tests that not providing an argument for a required array argument with a transform produces an error.
|
|
func testParsing_RequiredArray_Argument_Transform_NoInput() {
|
|
XCTAssertThrowsError(try RequiredArray_Argument_Transform.parse([]))
|
|
}
|
|
|
|
/// Tests that providing a single argument for a required array argument with a transform parses that value correctly.
|
|
func testParsing_RequiredArray_Argument_Transform_SingleInput() {
|
|
AssertParse(RequiredArray_Argument_Transform.self, ["1"]) { arguments in
|
|
XCTAssertEqual(arguments.array, ["1!"])
|
|
}
|
|
}
|
|
|
|
/// Tests that providing multiple arguments for a required array argument with a transform parses those values correctly.
|
|
func testParsing_RequiredArray_Argument_Transform_MultipleInput() {
|
|
AssertParse(RequiredArray_Argument_Transform.self, ["2", "3"]) { arguments in
|
|
XCTAssertEqual(arguments.array, ["2!", "3!"])
|
|
}
|
|
}
|
|
|
|
|
|
/// Tests that not providing an argument for a required array flag produces an error.
|
|
func testParsing_RequiredArray_Flag_NoInput() {
|
|
XCTAssertThrowsError(try RequiredArray_Flag.parse([]))
|
|
}
|
|
|
|
/// Tests that providing a single argument for a required array flag parses that value correctly.
|
|
func testParsing_RequiredArray_Flag_SingleInput() {
|
|
AssertParse(RequiredArray_Flag.self, ["--data"]) { arguments in
|
|
XCTAssertEqual(arguments.array, [.data])
|
|
}
|
|
}
|
|
|
|
/// Tests that providing multiple arguments for a required array flag parses those values correctly.
|
|
func testParsing_RequiredArray_Flag_MultipleInput() {
|
|
AssertParse(RequiredArray_Flag.self, ["--data", "--no-data"]) { arguments in
|
|
XCTAssertEqual(arguments.array, [.data, .noData])
|
|
}
|
|
}
|
|
}
|
|
|
|
@available(*, deprecated)
|
|
fileprivate struct OptionPropertyDeprecatedInit_NoDefault: ParsableArguments {
|
|
@Option(completion: .file(), help: "")
|
|
var data: String = "test"
|
|
}
|
|
|
|
extension DefaultsEndToEndTests {
|
|
/// Tests that instances created using deprecated initializer with completion and help arguments swapped are constructed and parsed correctly.
|
|
@available(*, deprecated)
|
|
func testParsing_OptionPropertyDeprecatedInit_NoDefault() {
|
|
AssertParse(OptionPropertyDeprecatedInit_NoDefault.self, []) { arguments in
|
|
XCTAssertEqual(arguments.data, "test")
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: Overload selection
|
|
|
|
extension DefaultsEndToEndTests {
|
|
private struct AbsolutePath: ExpressibleByArgument {
|
|
init(_ value: String) {}
|
|
init?(argument: String) {}
|
|
}
|
|
|
|
private struct TwoPaths: ParsableCommand {
|
|
@Argument(help: .init("The path"))
|
|
var path1 = AbsolutePath("abc")
|
|
|
|
@Argument(help: "The path")
|
|
var path2 = AbsolutePath("abc")
|
|
|
|
@Option(help: .init("The path"))
|
|
var path3 = AbsolutePath("abc")
|
|
|
|
@Option(help: "The path")
|
|
var path4 = AbsolutePath("abc")
|
|
}
|
|
|
|
/// Tests that a non-optional `Value` type is inferred, regardless of how the
|
|
/// initializer parameters are spelled. Previously, string literals and
|
|
/// `.init` calls for the help parameter inferred different generic types.
|
|
func testHelpInitInferredType() throws {
|
|
AssertParse(TwoPaths.self, []) { cmd in
|
|
XCTAssert(type(of: cmd.path1) == AbsolutePath.self)
|
|
XCTAssert(type(of: cmd.path2) == AbsolutePath.self)
|
|
XCTAssert(type(of: cmd.path3) == AbsolutePath.self)
|
|
XCTAssert(type(of: cmd.path4) == AbsolutePath.self)
|
|
}
|
|
}
|
|
}
|
|
|
|
extension DefaultsEndToEndTests {
|
|
private struct UnderscoredOptional: ParsableCommand {
|
|
@Option(name: .customLong("arg"))
|
|
var _arg: String?
|
|
}
|
|
|
|
private struct UnderscoredArray: ParsableCommand {
|
|
@Option(name: .customLong("columns"), parsing: .upToNextOption)
|
|
var _columns: [String] = []
|
|
}
|
|
|
|
func testUnderscoredOptional() throws {
|
|
AssertParse(UnderscoredOptional.self, []) { parsed in
|
|
XCTAssertNil(parsed._arg)
|
|
}
|
|
AssertParse(UnderscoredOptional.self, ["--arg", "foo"]) { parsed in
|
|
XCTAssertEqual(parsed._arg, "foo")
|
|
}
|
|
}
|
|
|
|
func testUnderscoredArray() throws {
|
|
AssertParse(UnderscoredArray.self, []) { parsed in
|
|
XCTAssertEqual(parsed._columns, [])
|
|
}
|
|
AssertParse(UnderscoredArray.self, ["--columns", "foo", "bar", "baz"]) { parsed in
|
|
XCTAssertEqual(parsed._columns, ["foo", "bar", "baz"])
|
|
}
|
|
}
|
|
}
|