From 886ca7f2db574a6fbcce7e2c77becad8eb95e11b Mon Sep 17 00:00:00 2001 From: Sam Brannen <104798+sbrannen@users.noreply.github.com> Date: Sat, 18 Jan 2025 17:03:04 +0100 Subject: [PATCH] Polish contribution and SimpleCommandLineArgs-related code Closes gh-34282 --- .../core/env/CommandLinePropertySource.java | 14 ++++----- .../core/env/SimpleCommandLineArgsParser.java | 7 +++-- .../env/SimpleCommandLinePropertySource.java | 10 ++++--- .../env/SimpleCommandLineArgsParserTests.java | 30 ++++++++++++++----- .../SimpleCommandLinePropertySourceTests.java | 11 ++++++- 5 files changed, 49 insertions(+), 23 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/core/env/CommandLinePropertySource.java b/spring-core/src/main/java/org/springframework/core/env/CommandLinePropertySource.java index a49d3e93d8..20bcc1a95c 100644 --- a/spring-core/src/main/java/org/springframework/core/env/CommandLinePropertySource.java +++ b/spring-core/src/main/java/org/springframework/core/env/CommandLinePropertySource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,8 +25,7 @@ import org.springframework.util.StringUtils; /** * Abstract base class for {@link PropertySource} implementations backed by command line * arguments. The parameterized type {@code T} represents the underlying source of command - * line options. For instance, {@link SimpleCommandLinePropertySource} uses a String - * array. + * line options. * *
That is, options must be prefixed with "{@code --}" and may or may not * specify a value. If a value is specified, the name and value must be separated * without spaces by an equals sign ("="). The value may optionally be - * an empty string. if the option is present and has multiple values (e. g. "--foo=bar --foo=baz"), -* the values are parsed as a collection. + * an empty string. If an option is present multiple times with different values + * — for example, {@code --foo=bar --foo=baz} — all supplied values + * will be stored for the option. * *
diff --git a/spring-core/src/main/java/org/springframework/core/env/SimpleCommandLinePropertySource.java b/spring-core/src/main/java/org/springframework/core/env/SimpleCommandLinePropertySource.java index 17121c2973..1c4591f3df 100644 --- a/spring-core/src/main/java/org/springframework/core/env/SimpleCommandLinePropertySource.java +++ b/spring-core/src/main/java/org/springframework/core/env/SimpleCommandLinePropertySource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,7 +22,8 @@ import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; /** - * {@link CommandLinePropertySource} implementation backed by a simple String array. + * {@link CommandLinePropertySource} implementation backed by an instance of + * {@link CommandLineArgs}. * *Purpose
*This {@code CommandLinePropertySource} implementation aims to provide the simplest @@ -40,8 +41,9 @@ import org.springframework.util.StringUtils; *
That is, options must be prefixed with "{@code --}" and may or may not * specify a value. If a value is specified, the name and value must be separated * without spaces by an equals sign ("="). The value may optionally be - * an empty string. if the option is present and has multiple values (e. g. "--foo=bar --foo=baz"), - * the values are parsed as a collection. + * an empty string. If an option is present multiple times with different values + * — for example, {@code --foo=bar --foo=baz} — all supplied values + * will be stored for the option. * *
Valid examples of option arguments
*diff --git a/spring-core/src/test/java/org/springframework/core/env/SimpleCommandLineArgsParserTests.java b/spring-core/src/test/java/org/springframework/core/env/SimpleCommandLineArgsParserTests.java index 180dfa8fbc..e7dad041c1 100644 --- a/spring-core/src/test/java/org/springframework/core/env/SimpleCommandLineArgsParserTests.java +++ b/spring-core/src/test/java/org/springframework/core/env/SimpleCommandLineArgsParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -46,7 +46,7 @@ class SimpleCommandLineArgsParserTests { void withSingleOptionAndNoValue() { CommandLineArgs args = parser.parse("--o1"); assertThat(args.containsOption("o1")).isTrue(); - assertThat(args.getOptionValues("o1")).isEqualTo(Collections.EMPTY_LIST); + assertThat(args.getOptionValues("o1")).isEmpty(); } @Test @@ -56,6 +56,20 @@ class SimpleCommandLineArgsParserTests { assertThat(args.getOptionValues("o1")).containsExactly("v1"); } + @Test + void withRepeatedOptionAndSameValues() { + CommandLineArgs args = parser.parse("--o1=v1", "--o1=v1", "--o1=v1"); + assertThat(args.containsOption("o1")).isTrue(); + assertThat(args.getOptionValues("o1")).containsExactly("v1", "v1", "v1"); + } + + @Test + void withRepeatedOptionAndDifferentValues() { + CommandLineArgs args = parser.parse("--o1=v1", "--o1=v2", "--o1=v3"); + assertThat(args.containsOption("o1")).isTrue(); + assertThat(args.getOptionValues("o1")).containsExactly("v1", "v2", "v3"); + } + @Test void withMixOfOptionsHavingValueAndOptionsHavingNoValue() { CommandLineArgs args = parser.parse("--o1=v1", "--o2"); @@ -95,17 +109,17 @@ class SimpleCommandLineArgsParserTests { } @Test - void assertOptionNamesIsUnmodifiable() { + void optionNamesSetIsUnmodifiable() { CommandLineArgs args = new SimpleCommandLineArgsParser().parse(); - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> - args.getOptionNames().add("bogus")); + assertThatExceptionOfType(UnsupportedOperationException.class) + .isThrownBy(() -> args.getOptionNames().add("bogus")); } @Test - void assertNonOptionArgsIsUnmodifiable() { + void nonOptionArgsListIsUnmodifiable() { CommandLineArgs args = new SimpleCommandLineArgsParser().parse(); - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> - args.getNonOptionArgs().add("foo")); + assertThatExceptionOfType(UnsupportedOperationException.class) + .isThrownBy(() -> args.getNonOptionArgs().add("foo")); } @Test diff --git a/spring-core/src/test/java/org/springframework/core/env/SimpleCommandLinePropertySourceTests.java b/spring-core/src/test/java/org/springframework/core/env/SimpleCommandLinePropertySourceTests.java index 86923da26e..9d6d4979e3 100644 --- a/spring-core/src/test/java/org/springframework/core/env/SimpleCommandLinePropertySourceTests.java +++ b/spring-core/src/test/java/org/springframework/core/env/SimpleCommandLinePropertySourceTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -61,6 +61,15 @@ class SimpleCommandLinePropertySourceTests { assertThat(ps.getProperty("o3")).isNull(); } + @Test // gh-34282 + void withRepeatedOptionArgs() { + CommandLinePropertySource> ps = new SimpleCommandLinePropertySource("--o1=v1", "--o1=v2", "--o1=v3"); + assertThat(ps.containsProperty("o1")).isTrue(); + assertThat(ps.containsProperty("o2")).isFalse(); + assertThat(ps.getProperty("o1")).isEqualTo("v1,v2,v3"); + assertThat(ps.getProperty("o2")).isNull(); + } + @Test // gh-24464 void withOptionalArg_andArgIsEmpty() { EnumerablePropertySource> ps = new SimpleCommandLinePropertySource("--foo=");