@@ -8,9 +8,14 @@ use crate::config::{CommitLanguage, Verbosity};
88 about = concat!(
99 "AI-based command line tool to quickly generate standardized commit messages.\n \n " ,
1010 "Version: " , env!( "CARGO_PKG_VERSION" )
11- )
11+ ) ,
12+ subcommand_required = false ,
13+ arg_required_else_help = false
1214) ]
1315pub struct Args {
16+ #[ clap( flatten) ]
17+ pub commit_args : CommitArgs ,
18+
1419 #[ clap( subcommand) ]
1520 pub command : Option < Commands > ,
1621}
@@ -126,3 +131,156 @@ pub struct PrArgs {
126131 #[ clap( flatten) ]
127132 pub common : CommonArgs ,
128133}
134+
135+ #[ cfg( test) ]
136+ mod tests {
137+ use super :: * ;
138+
139+ /// Helper function to parse args from iterator
140+ fn parse_args < I , T > ( iter : I ) -> Result < Args , clap:: Error >
141+ where
142+ I : IntoIterator < Item = T > ,
143+ T : Into < std:: ffi:: OsString > + Clone ,
144+ {
145+ Args :: try_parse_from ( iter)
146+ }
147+
148+ #[ test]
149+ fn test_top_level_short_options_combined ( ) {
150+ // Test: fastcommit -bm (generate both branch and message)
151+ let args = parse_args ( [ "fastcommit" , "-bm" ] ) . unwrap ( ) ;
152+ assert ! ( args. command. is_none( ) , "No subcommand should be set" ) ;
153+ assert ! (
154+ args. commit_args. generate_branch,
155+ "-b should set generate_branch"
156+ ) ;
157+ assert ! (
158+ args. commit_args. generate_message,
159+ "-m should set generate_message"
160+ ) ;
161+ }
162+
163+ #[ test]
164+ fn test_top_level_short_options_separate ( ) {
165+ // Test: fastcommit -b -m (generate both branch and message)
166+ let args = parse_args ( [ "fastcommit" , "-b" , "-m" ] ) . unwrap ( ) ;
167+ assert ! ( args. command. is_none( ) ) ;
168+ assert ! ( args. commit_args. generate_branch) ;
169+ assert ! ( args. commit_args. generate_message) ;
170+ }
171+
172+ #[ test]
173+ fn test_top_level_branch_only ( ) {
174+ // Test: fastcommit -b (generate branch only)
175+ let args = parse_args ( [ "fastcommit" , "-b" ] ) . unwrap ( ) ;
176+ assert ! ( args. command. is_none( ) ) ;
177+ assert ! ( args. commit_args. generate_branch) ;
178+ assert ! ( !args. commit_args. generate_message) ;
179+ }
180+
181+ #[ test]
182+ fn test_top_level_message_only ( ) {
183+ // Test: fastcommit -m (generate message only - default behavior)
184+ let args = parse_args ( [ "fastcommit" , "-m" ] ) . unwrap ( ) ;
185+ assert ! ( args. command. is_none( ) ) ;
186+ assert ! ( !args. commit_args. generate_branch) ;
187+ assert ! ( args. commit_args. generate_message) ;
188+ }
189+
190+ #[ test]
191+ fn test_no_args_uses_default ( ) {
192+ // Test: fastcommit (no args - default commit behavior)
193+ let args = parse_args ( [ "fastcommit" ] ) . unwrap ( ) ;
194+ assert ! ( args. command. is_none( ) ) ;
195+ assert ! ( !args. commit_args. generate_branch) ;
196+ assert ! ( !args. commit_args. generate_message) ;
197+ }
198+
199+ #[ test]
200+ fn test_commit_subcommand_with_options ( ) {
201+ // Test: fastcommit commit -bm (using subcommand explicitly)
202+ let args = parse_args ( [ "fastcommit" , "commit" , "-bm" ] ) . unwrap ( ) ;
203+ assert ! ( args. command. is_some( ) , "Subcommand should be set" ) ;
204+ if let Some ( Commands :: Commit ( commit_args) ) = args. command {
205+ assert ! ( commit_args. generate_branch) ;
206+ assert ! ( commit_args. generate_message) ;
207+ } else {
208+ panic ! ( "Expected Commit subcommand" ) ;
209+ }
210+ }
211+
212+ #[ test]
213+ fn test_pr_subcommand ( ) {
214+ // Test: fastcommit pr 123
215+ let args = parse_args ( [ "fastcommit" , "pr" , "123" ] ) . unwrap ( ) ;
216+ if let Some ( Commands :: Pr ( pr_args) ) = args. command {
217+ assert_eq ! ( pr_args. pr_number, Some ( 123 ) ) ;
218+ } else {
219+ panic ! ( "Expected Pr subcommand" ) ;
220+ }
221+ }
222+
223+ #[ test]
224+ fn test_top_level_range_option ( ) {
225+ // Test: fastcommit -r HEAD~1
226+ let args = parse_args ( [ "fastcommit" , "-r" , "HEAD~1" ] ) . unwrap ( ) ;
227+ assert ! ( args. command. is_none( ) ) ;
228+ assert_eq ! ( args. commit_args. range, Some ( "HEAD~1" . to_string( ) ) ) ;
229+ }
230+
231+ #[ test]
232+ fn test_top_level_with_common_args ( ) {
233+ // Test: fastcommit -bm --no-wrap --language en
234+ let args = parse_args ( [ "fastcommit" , "-bm" , "--no-wrap" , "--language" , "en" ] ) . unwrap ( ) ;
235+ assert ! ( args. command. is_none( ) ) ;
236+ assert ! ( args. commit_args. generate_branch) ;
237+ assert ! ( args. commit_args. generate_message) ;
238+ assert ! ( args. commit_args. common. no_wrap) ;
239+ assert_eq ! (
240+ args. commit_args. common. language,
241+ Some ( CommitLanguage :: English )
242+ ) ;
243+ }
244+
245+ #[ test]
246+ fn test_commit_subcommand_with_range ( ) {
247+ // Test: fastcommit commit -r HEAD~1 -b
248+ let args = parse_args ( [ "fastcommit" , "commit" , "-r" , "HEAD~1" , "-b" ] ) . unwrap ( ) ;
249+ if let Some ( Commands :: Commit ( commit_args) ) = args. command {
250+ assert ! ( commit_args. generate_branch) ;
251+ assert_eq ! ( commit_args. range, Some ( "HEAD~1" . to_string( ) ) ) ;
252+ } else {
253+ panic ! ( "Expected Commit subcommand" ) ;
254+ }
255+ }
256+
257+ #[ test]
258+ fn test_diff_file_option ( ) {
259+ // Test: fastcommit --diff-file /path/to/diff
260+ let args = parse_args ( [ "fastcommit" , "--diff-file" , "/path/to/diff" ] ) . unwrap ( ) ;
261+ assert ! ( args. command. is_none( ) ) ;
262+ assert_eq ! (
263+ args. commit_args. diff_file,
264+ Some ( "/path/to/diff" . to_string( ) )
265+ ) ;
266+ }
267+
268+ #[ test]
269+ fn test_auto_commit_option ( ) {
270+ // Test: fastcommit -c (auto commit after generating)
271+ let args = parse_args ( [ "fastcommit" , "-c" ] ) . unwrap ( ) ;
272+ assert ! ( args. command. is_none( ) ) ;
273+ assert ! ( args. commit_args. common. commit) ;
274+ }
275+
276+ #[ test]
277+ fn test_combined_all_options ( ) {
278+ // Test: fastcommit -bmc --no-sanitize (all flags combined)
279+ let args = parse_args ( [ "fastcommit" , "-bmc" , "--no-sanitize" ] ) . unwrap ( ) ;
280+ assert ! ( args. command. is_none( ) ) ;
281+ assert ! ( args. commit_args. generate_branch) ;
282+ assert ! ( args. commit_args. generate_message) ;
283+ assert ! ( args. commit_args. common. commit) ;
284+ assert ! ( args. commit_args. common. no_sanitize) ;
285+ }
286+ }
0 commit comments