apple / apple/swift-argument-parser

Incorrect error message for .allRemainingInput options without values

Open
#750 2 comments 0 reactions 0 assignees View on GitHub
Dominant language
Swift
Stars
3.8k
Forks
411
Avg merge
7d 14h
Merged PRs (30d)
15

Description

Issue #434 reported that when a label, but no values, are provided for an array `@Option` property, the error message incorrectly signifies a missing option instead of a missing value. PR #435 fixed this for `.upToNextOption` arrays, but the bug remained for `.allRemainingInput` arrays.

### Example

```swift
@main
struct Example: ParsableCommand {
@Option(parsing: .remaining)
var test: [String]

mutating func run() throws {
print(test)
}
}
```

### Expected Behaviour

```
$ example --test
Error: Missing value for '--test '
```

### Actual Behaviour

```
$ example --test
Error: Missing expected argument '--test ...'
```

### Unexpected Side-Effect

I created a commit that fixes this issue for `.allRemainingInput` arrays at james-fletcher-01@1bf93bfcf8f597deb885ffe0ef7554a59f9b81f2. However, this change breaks the following test:

```swift
func testParsing_repeatingStringRemaining_2() {
AssertParse(Baz.self, ["--names"]) { baz in
XCTAssertFalse(baz.verbose)
XCTAssertTrue(baz.names.isEmpty)
}
}
```

This implies that for options with a default value, the expected behavior is for an option label without a value to essentially be ignored and retain the default value. For example, while the above test uses an empty array as the default value, this works as well:

```swift
struct NonEmptyDefaultValue: ParsableArguments {
@Option(parsing: .remaining)
var names = ["default"]
}

func testNonEmptyDefaultValue() {
AssertParse(NonEmptyDefaultValue.self, ["--names"]) { baz in
XCTAssertEqual(baz.names, ["default"])
}
}
```

It's surprising to me that this would be the expected behaviour.

- No other parsing strategy accepts an option label without a value. This includes single values strategies, as well as `.upToNextOption`.
- In the example where the default is an empty array, it kind of makes sense. But the example I provided above seems especially counter-intuitive, since you explicitly provided an "empty option" but ended up with a non-empty value.

So if this really is expected behaviour, I can modify my changes to detect the presence of a default value and supress the error message before I submit a PR. But I would just like to get others' thoughts on this?

**ArgumentParser version:** `main`
**Swift version: swift-driver version:** 1.115.1 Apple Swift version 6.0.3 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)

### Checklist
- [x] If possible, I've reproduced the issue using the `main` branch of this package
- [X] I've searched for [existing GitHub issues](https://github.com/apple/swift-argument-parser/issues)

Contributor guide

Open the contributing guide

Research direction

Start with testParsing_repeatingStringRemaining_2 and testNonEmptyDefaultValue, then trace the .allRemainingInput/.remaining option parsing path. Compare its missing-value handling with .upToNextOption and the behavior described in the examples. Done means the expected behavior for an option label without a value is decided and covered by tests without regressing default values.

Written by the indexing model from the issue text.

Assessment

Tech stack
swift
Domain
cli
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.