@@ -268,6 +268,90 @@ public void testOptionGroup_MixedWithOtherOptions() throws Exception {
268268 assertEquals ("true" , optionValues (MixedCmd .class , line , "debug" ).get (0 ));
269269 }
270270
271+ // ========== Conflicting OptionGroup: values starting with dash (#552) ==========
272+
273+ @ Test
274+ public void testOptionList_DashValueWithConflictingOptionGroup_LongName () throws Exception {
275+ // --runtime-option -Dstdout.encoding=UTF-8 should be consumed as a value of
276+ // runtime-option, NOT matched as the -D OptionGroup (jbang #2587)
277+ List <String > vals = optionValues (JBangLikeCmd .class ,
278+ "test --runtime-option -Dstdout.encoding=UTF-8" , "runtime-option" );
279+ assertEquals (1 , vals .size ());
280+ assertEquals ("-Dstdout.encoding=UTF-8" , vals .get (0 ));
281+ }
282+
283+ @ Test
284+ public void testOptionList_DashValueWithConflictingOptionGroup_ShortName () throws Exception {
285+ // -R -Dstdout.encoding=UTF-8 — same scenario with short name
286+ List <String > vals = optionValues (JBangLikeCmd .class ,
287+ "test -R -Dstdout.encoding=UTF-8" , "runtime-option" );
288+ assertEquals (1 , vals .size ());
289+ assertEquals ("-Dstdout.encoding=UTF-8" , vals .get (0 ));
290+ }
291+
292+ @ Test
293+ public void testOptionList_DashValueWithConflictingOptionGroup_Multiple () throws Exception {
294+ // Multiple -R values that look like -D options
295+ List <String > vals = optionValues (JBangLikeCmd .class ,
296+ "test -R -Dstdout.encoding=UTF-8 -R -Dpython.console.encoding=UTF-8" ,
297+ "runtime-option" );
298+ assertEquals (2 , vals .size ());
299+ assertEquals ("-Dstdout.encoding=UTF-8" , vals .get (0 ));
300+ assertEquals ("-Dpython.console.encoding=UTF-8" , vals .get (1 ));
301+ }
302+
303+ @ Test
304+ public void testOptionList_DashValueWithConflictingOptionGroup_Equals () throws Exception {
305+ // Equals syntax should still work
306+ List <String > vals = optionValues (JBangLikeCmd .class ,
307+ "test --runtime-option=-Dstdout.encoding=UTF-8" , "runtime-option" );
308+ assertEquals (1 , vals .size ());
309+ assertEquals ("-Dstdout.encoding=UTF-8" , vals .get (0 ));
310+ }
311+
312+ @ Test
313+ public void testOptionList_DashValueWithConflictingOptionGroup_Attached () throws Exception {
314+ // Attached short name syntax should still work
315+ List <String > vals = optionValues (JBangLikeCmd .class ,
316+ "test -R-Dstdout.encoding=UTF-8" , "runtime-option" );
317+ assertEquals (1 , vals .size ());
318+ assertEquals ("-Dstdout.encoding=UTF-8" , vals .get (0 ));
319+ }
320+
321+ @ Test
322+ public void testOptionList_DashValueDoesNotBreakOptionGroup () throws Exception {
323+ // -D used directly (not as value of -R) should still work as OptionGroup
324+ Map <String , String > props = propertyValues (JBangLikeCmd .class ,
325+ "test -Dfoo=bar" , "define" );
326+ assertEquals (1 , props .size ());
327+ assertEquals ("bar" , props .get ("foo" ));
328+ }
329+
330+ @ Test
331+ public void testOptionList_MixedDashValueAndOptionGroup () throws Exception {
332+ // Both -R and -D used in same command line
333+ List <String > runtimeOpts = optionValues (JBangLikeCmd .class ,
334+ "test -R -Xmx4G -Dfoo=bar" , "runtime-option" );
335+ assertEquals (1 , runtimeOpts .size ());
336+ assertEquals ("-Xmx4G" , runtimeOpts .get (0 ));
337+
338+ Map <String , String > props = propertyValues (JBangLikeCmd .class ,
339+ "test -R -Xmx4G -Dfoo=bar" , "define" );
340+ assertEquals (1 , props .size ());
341+ assertEquals ("bar" , props .get ("foo" ));
342+ }
343+
344+ @ Test
345+ public void testOptionList_DashValueWithVerboseFlag () throws Exception {
346+ // -R with dash value, followed by a boolean flag
347+ List <String > vals = optionValues (JBangLikeCmd .class ,
348+ "test -R -Xmx4G --verbose" , "runtime-option" );
349+ assertEquals (1 , vals .size ());
350+ assertEquals ("-Xmx4G" , vals .get (0 ));
351+ assertEquals ("true" , optionValues (JBangLikeCmd .class ,
352+ "test -R -Xmx4G --verbose" , "verbose" ).get (0 ));
353+ }
354+
271355 // ========== Helpers ==========
272356
273357 @ SuppressWarnings ("rawtypes" )
@@ -387,4 +471,25 @@ public CommandResult execute(CommandInvocation ci) {
387471 return CommandResult .SUCCESS ;
388472 }
389473 }
474+
475+ // Command with OptionList AND OptionGroup(-D) — reproduces jbang #2587
476+ @ CommandDefinition (name = "test" , description = "OptionList with conflicting OptionGroup" )
477+ public static class JBangLikeCmd implements Command <CommandInvocation > {
478+ @ OptionList (shortName = 'R' , name = "runtime-option" )
479+ public List <String > runtimeOptions ;
480+
481+ @ OptionGroup (shortName = 'D' , name = "define" )
482+ public Map <String , String > properties ;
483+
484+ @ Option (hasValue = false )
485+ public boolean verbose ;
486+
487+ @ Argument (description = "Script file" )
488+ public String script ;
489+
490+ @ Override
491+ public CommandResult execute (CommandInvocation ci ) {
492+ return CommandResult .SUCCESS ;
493+ }
494+ }
390495}
0 commit comments