Polish contribution and SimpleCommandLineArgs-related code

Closes gh-34282
This commit is contained in:
Sam Brannen 2025-01-18 17:03:04 +01:00
parent c463b937b8
commit 886ca7f2db
5 changed files with 49 additions and 23 deletions

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 * Abstract base class for {@link PropertySource} implementations backed by command line
* arguments. The parameterized type {@code T} represents the underlying source of command * arguments. The parameterized type {@code T} represents the underlying source of command
* line options. For instance, {@link SimpleCommandLinePropertySource} uses a String * line options.
* array.
* *
* <h3>Purpose and General Usage</h3> * <h3>Purpose and General Usage</h3>
* *
@ -259,10 +258,11 @@ public abstract class CommandLinePropertySource<T> extends EnumerablePropertySou
* This implementation first checks to see if the name specified is the special * This implementation first checks to see if the name specified is the special
* {@linkplain #setNonOptionArgsPropertyName(String) "non-option arguments" property}, * {@linkplain #setNonOptionArgsPropertyName(String) "non-option arguments" property},
* and if so delegates to the abstract {@link #getNonOptionArgs()} method. If so * and if so delegates to the abstract {@link #getNonOptionArgs()} method. If so
* and the collection of non-option arguments is empty, this method returns {@code * and the collection of non-option arguments is empty, this method returns
* null}. If not empty, it returns a comma-separated String of all non-option * {@code null}. If not empty, it returns a comma-separated String of all non-option
* arguments. Otherwise, delegates to and returns the result of the abstract {@link * arguments. Otherwise, this method delegates to and returns a comma-separated String
* #getOptionValues(String)} method. * of the results of the abstract {@link #getOptionValues(String)} method or
* {@code null} if there are no such option values.
*/ */
@Override @Override
@Nullable @Nullable

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -28,8 +28,9 @@ package org.springframework.core.env;
* <p>That is, options must be prefixed with "{@code --}" and may or may not * <p>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 * specify a value. If a value is specified, the name and value must be separated
* <em>without spaces</em> by an equals sign ("="). The value may optionally be * <em>without spaces</em> 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"), * an empty string. If an option is present multiple times with different values
* the values are parsed as a collection. * &mdash; for example, {@code --foo=bar --foo=baz} &mdash; all supplied values
* will be stored for the option.
* *
* <h4>Valid examples of option arguments</h4> * <h4>Valid examples of option arguments</h4>
* <pre class="code"> * <pre class="code">

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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; import org.springframework.util.StringUtils;
/** /**
* {@link CommandLinePropertySource} implementation backed by a simple String array. * {@link CommandLinePropertySource} implementation backed by an instance of
* {@link CommandLineArgs}.
* *
* <h3>Purpose</h3> * <h3>Purpose</h3>
* <p>This {@code CommandLinePropertySource} implementation aims to provide the simplest * <p>This {@code CommandLinePropertySource} implementation aims to provide the simplest
@ -40,8 +41,9 @@ import org.springframework.util.StringUtils;
* <p>That is, options must be prefixed with "{@code --}" and may or may not * <p>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 * specify a value. If a value is specified, the name and value must be separated
* <em>without spaces</em> by an equals sign ("="). The value may optionally be * <em>without spaces</em> 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"), * an empty string. If an option is present multiple times with different values
* the values are parsed as a collection. * &mdash; for example, {@code --foo=bar --foo=baz} &mdash; all supplied values
* will be stored for the option.
* *
* <h4>Valid examples of option arguments</h4> * <h4>Valid examples of option arguments</h4>
* <pre class="code"> * <pre class="code">

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -46,7 +46,7 @@ class SimpleCommandLineArgsParserTests {
void withSingleOptionAndNoValue() { void withSingleOptionAndNoValue() {
CommandLineArgs args = parser.parse("--o1"); CommandLineArgs args = parser.parse("--o1");
assertThat(args.containsOption("o1")).isTrue(); assertThat(args.containsOption("o1")).isTrue();
assertThat(args.getOptionValues("o1")).isEqualTo(Collections.EMPTY_LIST); assertThat(args.getOptionValues("o1")).isEmpty();
} }
@Test @Test
@ -56,6 +56,20 @@ class SimpleCommandLineArgsParserTests {
assertThat(args.getOptionValues("o1")).containsExactly("v1"); 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 @Test
void withMixOfOptionsHavingValueAndOptionsHavingNoValue() { void withMixOfOptionsHavingValueAndOptionsHavingNoValue() {
CommandLineArgs args = parser.parse("--o1=v1", "--o2"); CommandLineArgs args = parser.parse("--o1=v1", "--o2");
@ -95,17 +109,17 @@ class SimpleCommandLineArgsParserTests {
} }
@Test @Test
void assertOptionNamesIsUnmodifiable() { void optionNamesSetIsUnmodifiable() {
CommandLineArgs args = new SimpleCommandLineArgsParser().parse(); CommandLineArgs args = new SimpleCommandLineArgsParser().parse();
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> assertThatExceptionOfType(UnsupportedOperationException.class)
args.getOptionNames().add("bogus")); .isThrownBy(() -> args.getOptionNames().add("bogus"));
} }
@Test @Test
void assertNonOptionArgsIsUnmodifiable() { void nonOptionArgsListIsUnmodifiable() {
CommandLineArgs args = new SimpleCommandLineArgsParser().parse(); CommandLineArgs args = new SimpleCommandLineArgsParser().parse();
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> assertThatExceptionOfType(UnsupportedOperationException.class)
args.getNonOptionArgs().add("foo")); .isThrownBy(() -> args.getNonOptionArgs().add("foo"));
} }
@Test @Test

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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(); 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 @Test // gh-24464
void withOptionalArg_andArgIsEmpty() { void withOptionalArg_andArgIsEmpty() {
EnumerablePropertySource<?> ps = new SimpleCommandLinePropertySource("--foo="); EnumerablePropertySource<?> ps = new SimpleCommandLinePropertySource("--foo=");