TransformEndToEndTests.swift 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. //===----------------------------------------------------------------------===//
  2. //
  3. // This source file is part of the Swift Argument Parser open source project
  4. //
  5. // Copyright (c) 2020 Apple Inc. and the Swift project authors
  6. // Licensed under Apache License v2.0 with Runtime Library Exception
  7. //
  8. // See https://swift.org/LICENSE.txt for license information
  9. //
  10. //===----------------------------------------------------------------------===//
  11. import ArgumentParser
  12. import ArgumentParserTestHelpers
  13. import XCTest
  14. final class TransformEndToEndTests: XCTestCase {}
  15. private enum FooBarError: Error {
  16. case outOfBounds
  17. }
  18. private protocol Convert {
  19. static func convert(_ str: String) throws -> Int
  20. }
  21. extension Convert {
  22. static func convert(_ str: String) throws -> Int {
  23. guard let converted = Int(argument: str) else {
  24. throw ValidationError("Could not transform to an Int.")
  25. }
  26. guard converted < 1000 else { throw FooBarError.outOfBounds }
  27. return converted
  28. }
  29. }
  30. // MARK: - Options
  31. private struct FooOption: Convert, ParsableArguments {
  32. static let usageString: String = """
  33. Usage: foo_option --string <int_str>
  34. See 'foo_option --help' for more information.
  35. """
  36. static let help: String =
  37. "Help: --string <int_str> Convert string to integer\n"
  38. @Option(
  39. help: ArgumentHelp("Convert string to integer", valueName: "int_str"),
  40. transform: { try convert($0) })
  41. var string: Int
  42. }
  43. private struct BarOption: Convert, ParsableCommand {
  44. static let usageString: String = """
  45. Usage: bar-option [--strings <int_str> ...]
  46. See 'bar-option --help' for more information.
  47. """
  48. static let help: String =
  49. "Help: --strings <int_str> Convert a list of strings to an array of integers\n"
  50. @Option(
  51. help: ArgumentHelp(
  52. "Convert a list of strings to an array of integers", valueName: "int_str"),
  53. transform: { try convert($0) })
  54. var strings: [Int] = []
  55. }
  56. // swift-format-ignore: AlwaysUseLowerCamelCase
  57. // https://github.com/apple/swift-argument-parser/issues/710
  58. extension TransformEndToEndTests {
  59. // MARK: Single Values
  60. func testSingleOptionTransform() throws {
  61. AssertParse(FooOption.self, ["--string", "42"]) { foo in
  62. XCTAssertEqual(foo.string, 42)
  63. }
  64. }
  65. func testSingleOptionValidation_Fail_CustomErrorMessage() throws {
  66. AssertFullErrorMessage(
  67. FooOption.self, ["--string", "Forty Two"],
  68. "Error: The value 'Forty Two' is invalid for '--string <int_str>': Could not transform to an Int.\n"
  69. + FooOption.help + FooOption.usageString)
  70. }
  71. func testSingleOptionValidation_Fail_DefaultErrorMessage() throws {
  72. AssertFullErrorMessage(
  73. FooOption.self, ["--string", "4827"],
  74. "Error: The value '4827' is invalid for '--string <int_str>': outOfBounds\n"
  75. + FooOption.help + FooOption.usageString)
  76. }
  77. // MARK: Arrays
  78. func testOptionArrayTransform() throws {
  79. AssertParse(
  80. BarOption.self, ["--strings", "42", "--strings", "72", "--strings", "99"]
  81. ) { bar in
  82. XCTAssertEqual(bar.strings, [42, 72, 99])
  83. }
  84. }
  85. func testOptionArrayValidation_Fail_CustomErrorMessage() throws {
  86. AssertFullErrorMessage(
  87. BarOption.self,
  88. ["--strings", "Forty Two", "--strings", "72", "--strings", "99"],
  89. "Error: The value 'Forty Two' is invalid for '--strings <int_str>': Could not transform to an Int.\n"
  90. + BarOption.help + BarOption.usageString)
  91. }
  92. func testOptionArrayValidation_Fail_DefaultErrorMessage() throws {
  93. AssertFullErrorMessage(
  94. BarOption.self,
  95. ["--strings", "4827", "--strings", "72", "--strings", "99"],
  96. "Error: The value '4827' is invalid for '--strings <int_str>': outOfBounds\n"
  97. + BarOption.help + BarOption.usageString)
  98. }
  99. }
  100. // MARK: - Arguments
  101. private struct FooArgument: Convert, ParsableArguments {
  102. static let usageString: String = """
  103. Usage: foo_argument <int_str>
  104. See 'foo_argument --help' for more information.
  105. """
  106. static let help: String = "Help: <int_str> Convert string to integer\n"
  107. enum FooError: Error {
  108. case outOfBounds
  109. }
  110. @Argument(
  111. help: ArgumentHelp("Convert string to integer", valueName: "int_str"),
  112. transform: { try convert($0) })
  113. var string: Int
  114. }
  115. private struct BarArgument: Convert, ParsableCommand {
  116. static let usageString: String = """
  117. Usage: bar-argument [<int_str> ...]
  118. See 'bar-argument --help' for more information.
  119. """
  120. static let help: String =
  121. "Help: <int_str> Convert a list of strings to an array of integers\n"
  122. @Argument(
  123. help: ArgumentHelp(
  124. "Convert a list of strings to an array of integers", valueName: "int_str"),
  125. transform: { try convert($0) })
  126. var strings: [Int] = []
  127. }
  128. // swift-format-ignore: AlwaysUseLowerCamelCase
  129. // https://github.com/apple/swift-argument-parser/issues/710
  130. extension TransformEndToEndTests {
  131. // MARK: Single Values
  132. func testArgumentTransform() throws {
  133. AssertParse(FooArgument.self, ["42"]) { foo in
  134. XCTAssertEqual(foo.string, 42)
  135. }
  136. }
  137. func testArgumentValidation_Fail_CustomErrorMessage() throws {
  138. AssertFullErrorMessage(
  139. FooArgument.self, ["Forty Two"],
  140. "Error: The value 'Forty Two' is invalid for '<int_str>': Could not transform to an Int.\n"
  141. + FooArgument.help + FooArgument.usageString)
  142. }
  143. func testArgumentValidation_Fail_DefaultErrorMessage() throws {
  144. AssertFullErrorMessage(
  145. FooArgument.self, ["4827"],
  146. "Error: The value '4827' is invalid for '<int_str>': outOfBounds\n"
  147. + FooArgument.help + FooArgument.usageString)
  148. }
  149. // MARK: Arrays
  150. func testArgumentArrayTransform() throws {
  151. AssertParse(BarArgument.self, ["42", "72", "99"]) { bar in
  152. XCTAssertEqual(bar.strings, [42, 72, 99])
  153. }
  154. }
  155. func testArgumentArrayValidation_Fail_CustomErrorMessage() throws {
  156. AssertFullErrorMessage(
  157. BarArgument.self, ["Forty Two", "72", "99"],
  158. "Error: The value 'Forty Two' is invalid for '<int_str>': Could not transform to an Int.\n"
  159. + BarArgument.help + BarArgument.usageString)
  160. }
  161. func testArgumentArrayValidation_Fail_DefaultErrorMessage() throws {
  162. AssertFullErrorMessage(
  163. BarArgument.self, ["4827", "72", "99"],
  164. "Error: The value '4827' is invalid for '<int_str>': outOfBounds\n"
  165. + BarArgument.help + BarArgument.usageString)
  166. }
  167. }