Repository: apple/swift-argument-parser
Pull request #445 (2022-05-13 01:57:12)

List valid options in error messages for enum array argument
When an array of argument values fails to parse, no custom error message is
provided, and a list of valid candidate values is available, include the
list as part of the error message.

Addresses #401.

### Checklist
- [x] I've added at least one test that validates that my change is working, if appropriate
- [x] I've followed the code style of the rest of the project
- [x] I've read the [Contribution Guidelines](https://github.com/apple/swift-argument-parser/blob/main/CONTRIBUTING.md)
- [x] I've updated the documentation if necessary


konomae: @swift-ci Please test
natecook1000: @swift-ci Please test
natecook1000: @konomae Thanks for this improvement! 👏🏻

Patch:
diff --git a/Sources/ArgumentParser/Parsable Properties/Argument.swift b/Sources/ArgumentParser/Parsable Properties/Argument.swift
index 2847f77..54e0e09 100644
--- a/Sources/ArgumentParser/Parsable Properties/Argument.swift
+++ b/Sources/ArgumentParser/Parsable Properties/Argument.swift
@@ -338,7 +338,12 @@ extension Argument {
         helpDefaultValue = nil
       }
 
-      let help = ArgumentDefinition.Help(options: [.isOptional, .isRepeating], help: help, key: key)
+      let help = ArgumentDefinition.Help(
+        allValues: Element.allValueStrings,
+        options: [.isOptional, .isRepeating],
+        help: help,
+        key: key
+      )
       var arg = ArgumentDefinition(
         kind: .positional,
         help: help,


Test patch:
diff --git a/Tests/ArgumentParserUnitTests/ErrorMessageTests.swift b/Tests/ArgumentParserUnitTests/ErrorMessageTests.swift
index 597c959..d3cf274 100644
--- a/Tests/ArgumentParserUnitTests/ErrorMessageTests.swift
+++ b/Tests/ArgumentParserUnitTests/ErrorMessageTests.swift
@@ -64,28 +64,39 @@ extension ErrorMessageTests {
   }
 }
 
-fileprivate struct Foo: ParsableArguments {
-  enum Format: String, Equatable, Decodable, ExpressibleByArgument, CaseIterable {
-    case text
-    case json
-    case csv
-  }
+fileprivate enum Format: String, Equatable, Decodable, ExpressibleByArgument, CaseIterable {
+  case text
+  case json
+  case csv
+}
 
-  enum Name: String, Equatable, Decodable, ExpressibleByArgument, CaseIterable {
-    case bruce
-    case clint
-    case hulk
-    case natasha
-    case steve
-    case thor
-    case tony
-  }
+fileprivate enum Name: String, Equatable, Decodable, ExpressibleByArgument, CaseIterable {
+  case bruce
+  case clint
+  case hulk
+  case natasha
+  case steve
+  case thor
+  case tony
+}
+
+fileprivate struct Foo: ParsableArguments {
   @Option(name: [.short, .long])
   var format: Format
   @Option(name: [.short, .long])
   var name: Name?
 }
 
+fileprivate struct EnumWithFewCasesArrayArgument: ParsableArguments {
+  @Argument
+  var formats: [Format]
+}
+
+fileprivate struct EnumWithManyCasesArrayArgument: ParsableArguments {
+  @Argument
+  var names: [Name]
+}
+
 extension ErrorMessageTests {
   func testWrongEnumValue() {
     AssertErrorMessage(Foo.self, ["--format", "png"], "The value 'png' is invalid for '--format <format>'. Please provide one of 'text', 'json' or 'csv'.")
@@ -112,6 +123,18 @@ extension ErrorMessageTests {
         - thor
         - tony
       """)
+    AssertErrorMessage(EnumWithFewCasesArrayArgument.self, ["png"], "The value 'png' is invalid for '<formats>'. Please provide one of 'text', 'json' or 'csv'.")
+    AssertErrorMessage(EnumWithManyCasesArrayArgument.self, ["loki"],
+      """
+      The value 'loki' is invalid for '<names>'. Please provide one of the following:
+        - bruce
+        - clint
+        - hulk
+        - natasha
+        - steve
+        - thor
+        - tony
+      """)
   }
 }