@@ -69,3 +69,110 @@ extension DefaultSubcommandEndToEndTests {
6969 XCTAssertThrowsError ( try Main . parseAsRoot ( [ " qux " ] ) )
7070 }
7171}
72+
73+ extension DefaultSubcommandEndToEndTests {
74+ fileprivate struct MyCommand : ParsableCommand {
75+ static var configuration = CommandConfiguration (
76+ subcommands: [ Plugin . self, NonDefault . self, Other . self] ,
77+ defaultSubcommand: Plugin . self
78+ )
79+
80+ @OptionGroup
81+ var options : CommonOptions
82+ }
83+
84+ fileprivate struct CommonOptions : ParsableArguments {
85+ @Flag ( name: [ . customLong( " verbose " ) , . customShort( " v " ) ] ,
86+ help: " Enable verbose aoutput. " )
87+ var verbose = false
88+ }
89+
90+ fileprivate struct Plugin : ParsableCommand {
91+ @OptionGroup var options : CommonOptions
92+ @Argument var pluginName : String
93+
94+ @Argument ( parsing: . unconditionalRemaining)
95+ var pluginArguments : [ String ] = [ ]
96+ }
97+
98+ fileprivate struct NonDefault : ParsableCommand {
99+ @OptionGroup var options : CommonOptions
100+ @Argument var pluginName : String
101+
102+ @Argument ( parsing: . unconditionalRemaining)
103+ var pluginArguments : [ String ] = [ ]
104+ }
105+
106+ fileprivate struct Other : ParsableCommand {
107+ @OptionGroup var options : CommonOptions
108+ }
109+
110+ func testRemainingDefaultImplicit( ) throws {
111+ AssertParseCommand ( MyCommand . self, Plugin . self, [ " my-plugin " ] ) { plugin in
112+ XCTAssertEqual ( plugin. pluginName, " my-plugin " )
113+ XCTAssertEqual ( plugin. pluginArguments, [ ] )
114+ XCTAssertEqual ( plugin. options. verbose, false )
115+ }
116+ AssertParseCommand ( MyCommand . self, Plugin . self, [ " my-plugin " , " --verbose " ] ) { plugin in
117+ XCTAssertEqual ( plugin. pluginName, " my-plugin " )
118+ XCTAssertEqual ( plugin. pluginArguments, [ " --verbose " ] )
119+ XCTAssertEqual ( plugin. options. verbose, false )
120+ }
121+ AssertParseCommand ( MyCommand . self, Plugin . self, [ " --verbose " , " my-plugin " , " --verbose " ] ) { plugin in
122+ XCTAssertEqual ( plugin. pluginName, " my-plugin " )
123+ XCTAssertEqual ( plugin. pluginArguments, [ " --verbose " ] )
124+ XCTAssertEqual ( plugin. options. verbose, true )
125+ }
126+ }
127+
128+ func testRemainingDefaultExplicit( ) throws {
129+ AssertParseCommand ( MyCommand . self, Plugin . self, [ " plugin " , " my-plugin " ] ) { plugin in
130+ XCTAssertEqual ( plugin. pluginName, " my-plugin " )
131+ XCTAssertEqual ( plugin. pluginArguments, [ ] )
132+ XCTAssertEqual ( plugin. options. verbose, false )
133+ }
134+ AssertParseCommand ( MyCommand . self, Plugin . self, [ " plugin " , " my-plugin " , " --verbose " ] ) { plugin in
135+ XCTAssertEqual ( plugin. pluginName, " my-plugin " )
136+ XCTAssertEqual ( plugin. pluginArguments, [ " --verbose " ] )
137+ XCTAssertEqual ( plugin. options. verbose, false )
138+ }
139+ AssertParseCommand ( MyCommand . self, Plugin . self, [ " --verbose " , " plugin " , " my-plugin " , " --verbose " ] ) { plugin in
140+ XCTAssertEqual ( plugin. pluginName, " my-plugin " )
141+ XCTAssertEqual ( plugin. pluginArguments, [ " --verbose " ] )
142+ XCTAssertEqual ( plugin. options. verbose, true )
143+ }
144+ }
145+
146+ func testRemainingNonDefault( ) throws {
147+ AssertParseCommand ( MyCommand . self, NonDefault . self, [ " non-default " , " my-plugin " ] ) { nondef in
148+ XCTAssertEqual ( nondef. pluginName, " my-plugin " )
149+ XCTAssertEqual ( nondef. pluginArguments, [ ] )
150+ XCTAssertEqual ( nondef. options. verbose, false )
151+ }
152+ AssertParseCommand ( MyCommand . self, NonDefault . self, [ " non-default " , " my-plugin " , " --verbose " ] ) { nondef in
153+ XCTAssertEqual ( nondef. pluginName, " my-plugin " )
154+ XCTAssertEqual ( nondef. pluginArguments, [ " --verbose " ] )
155+ XCTAssertEqual ( nondef. options. verbose, false )
156+ }
157+ AssertParseCommand ( MyCommand . self, NonDefault . self, [ " --verbose " , " non-default " , " my-plugin " , " --verbose " ] ) { nondef in
158+ XCTAssertEqual ( nondef. pluginName, " my-plugin " )
159+ XCTAssertEqual ( nondef. pluginArguments, [ " --verbose " ] )
160+ XCTAssertEqual ( nondef. options. verbose, true )
161+ }
162+ }
163+
164+ func testRemainingDefaultOther( ) throws {
165+ AssertParseCommand ( MyCommand . self, Other . self, [ " other " ] ) { other in
166+ XCTAssertEqual ( other. options. verbose, false )
167+ }
168+ AssertParseCommand ( MyCommand . self, Other . self, [ " other " , " --verbose " ] ) { other in
169+ XCTAssertEqual ( other. options. verbose, true )
170+ }
171+ }
172+
173+ func testRemainingDefaultFailure( ) {
174+ XCTAssertThrowsError ( try MyCommand . parseAsRoot ( [ ] ) )
175+ XCTAssertThrowsError ( try MyCommand . parseAsRoot ( [ " --verbose " ] ) )
176+ XCTAssertThrowsError ( try MyCommand . parseAsRoot ( [ " plugin " , " --verbose " , " my-plugin " ] ) )
177+ }
178+ }
0 commit comments