1
0

PositionalEndToEndTests.swift 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  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 PositionalEndToEndTests: XCTestCase {
  15. }
  16. // MARK: Single value String
  17. private struct Bar: ParsableArguments {
  18. @Argument() var name: String
  19. }
  20. // swift-format-ignore: AlwaysUseLowerCamelCase
  21. // https://github.com/apple/swift-argument-parser/issues/710
  22. extension PositionalEndToEndTests {
  23. func testParsing_SinglePositional() throws {
  24. AssertParse(Bar.self, ["Bar"]) { bar in
  25. XCTAssertEqual(bar.name, "Bar")
  26. }
  27. AssertParse(Bar.self, ["Bar-"]) { bar in
  28. XCTAssertEqual(bar.name, "Bar-")
  29. }
  30. AssertParse(Bar.self, ["Bar--"]) { bar in
  31. XCTAssertEqual(bar.name, "Bar--")
  32. }
  33. AssertParse(Bar.self, ["--", "-Bar"]) { bar in
  34. XCTAssertEqual(bar.name, "-Bar")
  35. }
  36. AssertParse(Bar.self, ["--", "--Bar"]) { bar in
  37. XCTAssertEqual(bar.name, "--Bar")
  38. }
  39. AssertParse(Bar.self, ["--", "--"]) { bar in
  40. XCTAssertEqual(bar.name, "--")
  41. }
  42. }
  43. func testParsing_SinglePositional_Fails() throws {
  44. XCTAssertThrowsError(try Bar.parse([]))
  45. XCTAssertThrowsError(try Bar.parse(["--name"]))
  46. XCTAssertThrowsError(try Bar.parse(["Foo", "Bar"]))
  47. }
  48. }
  49. // MARK: Two values
  50. private struct Baz: ParsableArguments {
  51. @Argument() var name: String
  52. @Argument() var format: String
  53. }
  54. // swift-format-ignore: AlwaysUseLowerCamelCase
  55. // https://github.com/apple/swift-argument-parser/issues/710
  56. extension PositionalEndToEndTests {
  57. func testParsing_TwoPositional() throws {
  58. AssertParse(Baz.self, ["Bar", "Foo"]) { baz in
  59. XCTAssertEqual(baz.name, "Bar")
  60. XCTAssertEqual(baz.format, "Foo")
  61. }
  62. AssertParse(Baz.self, ["", "Foo"]) { baz in
  63. XCTAssertEqual(baz.name, "")
  64. XCTAssertEqual(baz.format, "Foo")
  65. }
  66. AssertParse(Baz.self, ["Bar", ""]) { baz in
  67. XCTAssertEqual(baz.name, "Bar")
  68. XCTAssertEqual(baz.format, "")
  69. }
  70. AssertParse(Baz.self, ["--", "--b", "--f"]) { baz in
  71. XCTAssertEqual(baz.name, "--b")
  72. XCTAssertEqual(baz.format, "--f")
  73. }
  74. AssertParse(Baz.self, ["b", "--", "--f"]) { baz in
  75. XCTAssertEqual(baz.name, "b")
  76. XCTAssertEqual(baz.format, "--f")
  77. }
  78. }
  79. func testParsing_TwoPositional_Fails() throws {
  80. XCTAssertThrowsError(try Baz.parse(["Bar", "Foo", "Baz"]))
  81. XCTAssertThrowsError(try Baz.parse(["Bar"]))
  82. XCTAssertThrowsError(try Baz.parse([]))
  83. XCTAssertThrowsError(try Baz.parse(["--name", "Bar", "Foo"]))
  84. XCTAssertThrowsError(try Baz.parse(["Bar", "--name", "Foo"]))
  85. XCTAssertThrowsError(try Baz.parse(["Bar", "Foo", "--name"]))
  86. }
  87. }
  88. // MARK: Multiple values
  89. private struct Qux: ParsableArguments {
  90. @Argument() var names: [String] = []
  91. }
  92. // swift-format-ignore: AlwaysUseLowerCamelCase
  93. // https://github.com/apple/swift-argument-parser/issues/710
  94. extension PositionalEndToEndTests {
  95. func testParsing_MultiplePositional() throws {
  96. AssertParse(Qux.self, []) { qux in
  97. XCTAssertEqual(qux.names, [])
  98. }
  99. AssertParse(Qux.self, ["Bar"]) { qux in
  100. XCTAssertEqual(qux.names, ["Bar"])
  101. }
  102. AssertParse(Qux.self, ["Bar", "Foo"]) { qux in
  103. XCTAssertEqual(qux.names, ["Bar", "Foo"])
  104. }
  105. AssertParse(Qux.self, ["Bar", "Foo", "Baz"]) { qux in
  106. XCTAssertEqual(qux.names, ["Bar", "Foo", "Baz"])
  107. }
  108. AssertParse(Qux.self, ["--", "--b", "--f"]) { qux in
  109. XCTAssertEqual(qux.names, ["--b", "--f"])
  110. }
  111. AssertParse(Qux.self, ["b", "--", "--f"]) { qux in
  112. XCTAssertEqual(qux.names, ["b", "--f"])
  113. }
  114. }
  115. func testParsing_MultiplePositional_Fails() throws {
  116. // TODO: Allow zero-argument arrays?
  117. XCTAssertThrowsError(try Qux.parse(["--name", "Bar", "Foo"]))
  118. XCTAssertThrowsError(try Qux.parse(["Bar", "--name", "Foo"]))
  119. XCTAssertThrowsError(try Qux.parse(["Bar", "Foo", "--name"]))
  120. }
  121. }
  122. // MARK: Single value plus multiple values
  123. private struct Wobble: ParsableArguments {
  124. @Argument() var count: Int
  125. @Argument() var names: [String] = []
  126. }
  127. // swift-format-ignore: AlwaysUseLowerCamelCase
  128. // https://github.com/apple/swift-argument-parser/issues/710
  129. extension PositionalEndToEndTests {
  130. func testParsing_SingleAndMultiplePositional() throws {
  131. AssertParse(Wobble.self, ["5"]) { wobble in
  132. XCTAssertEqual(wobble.count, 5)
  133. XCTAssertEqual(wobble.names, [])
  134. }
  135. AssertParse(Wobble.self, ["5", "Bar"]) { wobble in
  136. XCTAssertEqual(wobble.count, 5)
  137. XCTAssertEqual(wobble.names, ["Bar"])
  138. }
  139. AssertParse(Wobble.self, ["5", "Bar", "Foo"]) { wobble in
  140. XCTAssertEqual(wobble.count, 5)
  141. XCTAssertEqual(wobble.names, ["Bar", "Foo"])
  142. }
  143. AssertParse(Wobble.self, ["5", "Bar", "Foo", "Baz"]) { wobble in
  144. XCTAssertEqual(wobble.count, 5)
  145. XCTAssertEqual(wobble.names, ["Bar", "Foo", "Baz"])
  146. }
  147. AssertParse(Wobble.self, ["5", "--", "--b", "--f"]) { wobble in
  148. XCTAssertEqual(wobble.count, 5)
  149. XCTAssertEqual(wobble.names, ["--b", "--f"])
  150. }
  151. AssertParse(Wobble.self, ["--", "5", "--b", "--f"]) { wobble in
  152. XCTAssertEqual(wobble.count, 5)
  153. XCTAssertEqual(wobble.names, ["--b", "--f"])
  154. }
  155. AssertParse(Wobble.self, ["5", "b", "--", "--f"]) { wobble in
  156. XCTAssertEqual(wobble.count, 5)
  157. XCTAssertEqual(wobble.names, ["b", "--f"])
  158. }
  159. }
  160. func testParsing_SingleAndMultiplePositional_Fails() throws {
  161. XCTAssertThrowsError(try Wobble.parse([]))
  162. XCTAssertThrowsError(try Wobble.parse(["--name", "Bar", "Foo"]))
  163. XCTAssertThrowsError(try Wobble.parse(["Bar", "--name", "Foo"]))
  164. XCTAssertThrowsError(try Wobble.parse(["Bar", "Foo", "--name"]))
  165. }
  166. }
  167. // MARK: Multiple parsed values
  168. private struct Flob: ParsableArguments {
  169. @Argument() var counts: [Int] = []
  170. }
  171. // swift-format-ignore: AlwaysUseLowerCamelCase
  172. // https://github.com/apple/swift-argument-parser/issues/710
  173. extension PositionalEndToEndTests {
  174. func testParsing_MultipleParsedPositional() throws {
  175. AssertParse(Flob.self, []) { flob in
  176. XCTAssertEqual(flob.counts, [])
  177. }
  178. AssertParse(Flob.self, ["5"]) { flob in
  179. XCTAssertEqual(flob.counts, [5])
  180. }
  181. AssertParse(Flob.self, ["5", "6"]) { flob in
  182. XCTAssertEqual(flob.counts, [5, 6])
  183. }
  184. AssertParse(Flob.self, ["5", "--", "6"]) { flob in
  185. XCTAssertEqual(flob.counts, [5, 6])
  186. }
  187. AssertParse(Flob.self, ["--", "5", "6"]) { flob in
  188. XCTAssertEqual(flob.counts, [5, 6])
  189. }
  190. AssertParse(Flob.self, ["5", "6", "--"]) { flob in
  191. XCTAssertEqual(flob.counts, [5, 6])
  192. }
  193. }
  194. func testParsing_MultipleParsedPositional_Fails() throws {
  195. XCTAssertThrowsError(try Flob.parse(["a"]))
  196. XCTAssertThrowsError(try Flob.parse(["5", "6", "a"]))
  197. }
  198. }
  199. // MARK: Multiple parsed values
  200. private struct BadlyFormed: ParsableArguments {
  201. @Argument() var numbers: [Int] = []
  202. @Argument() var name: String
  203. }
  204. // swift-format-ignore: AlwaysUseLowerCamelCase
  205. // https://github.com/apple/swift-argument-parser/issues/710
  206. extension PositionalEndToEndTests {
  207. // This test results in a fatal error when run, so it can't be enabled
  208. // or CI will prevent integration. Delete `disabled_` to verify the trap
  209. // locally.
  210. func disabled_testParsing_BadlyFormedPositional() throws {
  211. AssertParse(BadlyFormed.self, []) { _ in
  212. XCTFail("This should never execute")
  213. }
  214. }
  215. }
  216. // MARK: Conditional ExpressibleByArgument conformance
  217. // Note: This retroactive conformance is a compilation test
  218. extension Range<Int>: ArgumentParser.ExpressibleByArgument {
  219. public init?(argument: String) {
  220. guard let i = argument.firstIndex(of: ":"),
  221. let low = Int(String(argument[..<i])),
  222. let high = Int(String(argument[i...].dropFirst())),
  223. low <= high
  224. else { return nil }
  225. self = low..<high
  226. }
  227. }
  228. extension PositionalEndToEndTests {
  229. struct HasRange: ParsableArguments {
  230. @Argument var range: Range<Int>
  231. }
  232. func testParseCustomRangeConformance() throws {
  233. AssertParse(HasRange.self, ["0:4"]) { args in
  234. XCTAssertEqual(args.range, 0..<4)
  235. }
  236. XCTAssertThrowsError(try HasRange.parse([]))
  237. XCTAssertThrowsError(try HasRange.parse(["1"]))
  238. XCTAssertThrowsError(try HasRange.parse(["1:0"]))
  239. }
  240. }