Skip to content

Commit b9618a8

Browse files
committed
Support CSV headers with {argumentsWithNames} display name patterns
Prior to this commit, display names using CSV header names did not work properly when using the {argumentsWithNames} display name pattern for parameterized tests. Specifically, both the parameter name and the CSV header name were present in the display name, leading to duplication -- for example: [1] fruit = FRUIT = apple This commit ensures that the parameter name is not displayed when the user has enabled the useHeadersInDisplayName flag in @⁠CsvSource and @⁠CsvFileSource. With this change the above display name is now properly generated as follows (with the superfluous "fruit = " removed). [1] FRUIT = apple See #4716 Closes #4783
1 parent 50a8240 commit b9618a8

File tree

6 files changed

+29
-18
lines changed

6 files changed

+29
-18
lines changed

documentation/src/docs/asciidoc/release-notes/release-notes-6.0.0-RC1.adoc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,11 @@ repository on GitHub.
3535
[[release-notes-6.0.0-RC1-junit-jupiter-bug-fixes]]
3636
==== Bug Fixes
3737

38-
* ❓
38+
* CSV headers are now properly supported with the default display name pattern and the
39+
explicit `{argumentsWithNames}` display name pattern for parameterized tests that
40+
utilize the `useHeadersInDisplayName` flag in `@CsvSource` and `@CsvFileSource`.
41+
Specifically, the parameter name is no longer duplicated in the display name when a CSV
42+
header is desired instead.
3943

4044
[[release-notes-6.0.0-RC1-junit-jupiter-deprecations-and-breaking-changes]]
4145
==== Deprecations and Breaking Changes

documentation/src/docs/asciidoc/user-guide/writing-tests.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2236,7 +2236,7 @@ Using a text block, the previous example can be implemented as follows.
22362236

22372237
[source,java,indent=0]
22382238
----
2239-
@ParameterizedTest(name = "[{index}] {arguments}")
2239+
@ParameterizedTest
22402240
@CsvSource(useHeadersInDisplayName = true, textBlock = """
22412241
FRUIT, RANK
22422242
apple, 1

documentation/src/test/java/example/ParameterizedTestDemo.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ void testWithCsvFileSourceFromFile(String country, int reference) {
341341
assertNotEquals(0, reference);
342342
}
343343

344-
@ParameterizedTest(name = "[{index}] {arguments}")
344+
@ParameterizedTest
345345
@CsvFileSource(resources = "/two-column.csv", useHeadersInDisplayName = true)
346346
void testWithCsvFileSourceAndHeaders(String country, int reference) {
347347
assertNotNull(country);

junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationNameFormatter.java

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,8 @@ private PartialFormatters createPartialFormatters(String displayName,
163163
ParameterizedDeclarationContext<?> declarationContext, int argumentMaxLength) {
164164

165165
PartialFormatter argumentsWithNamesFormatter = new CachingByArgumentsLengthPartialFormatter(
166-
length -> new MessageFormatPartialFormatter(argumentsWithNamesPattern(length, declarationContext),
167-
argumentMaxLength));
166+
length -> new MessageFormatPartialFormatter(argumentsPattern(length), argumentMaxLength, true,
167+
declarationContext.getResolverFacade()));
168168

169169
PartialFormatter argumentSetNameFormatter = new ArgumentSetNameFormatter(
170170
declarationContext.getAnnotationName());
@@ -185,15 +185,6 @@ private PartialFormatters createPartialFormatters(String displayName,
185185
return formatters;
186186
}
187187

188-
private static String argumentsWithNamesPattern(int length, ParameterizedDeclarationContext<?> declarationContext) {
189-
ResolverFacade resolverFacade = declarationContext.getResolverFacade();
190-
return IntStream.range(0, length) //
191-
.mapToObj(index -> resolverFacade.getParameterName(index)//
192-
.map(name -> name + " = ").orElse("") //
193-
+ "{" + index + "}") //
194-
.collect(joining(", "));
195-
}
196-
197188
private static String argumentsPattern(int length) {
198189
return IntStream.range(0, length) //
199190
.mapToObj(index -> "{" + index + "}") //
@@ -238,10 +229,19 @@ private static class MessageFormatPartialFormatter implements PartialFormatter {
238229

239230
private final MessageFormat messageFormat;
240231
private final int argumentMaxLength;
232+
private final boolean generateNameValuePairs;
233+
private final @Nullable ResolverFacade resolverFacade;
241234

242235
MessageFormatPartialFormatter(String pattern, int argumentMaxLength) {
236+
this(pattern, argumentMaxLength, false, null);
237+
}
238+
239+
MessageFormatPartialFormatter(String pattern, int argumentMaxLength, boolean generateNameValuePairs,
240+
@Nullable ResolverFacade resolverFacade) {
243241
this.messageFormat = new MessageFormat(pattern);
244242
this.argumentMaxLength = argumentMaxLength;
243+
this.generateNameValuePairs = generateNameValuePairs;
244+
this.resolverFacade = resolverFacade;
245245
}
246246

247247
// synchronized because MessageFormat is not thread-safe
@@ -262,9 +262,17 @@ public synchronized void append(ArgumentsContext context, StringBuffer result) {
262262
String prefix = "";
263263

264264
if (argument instanceof ParameterNameAndArgument parameterNameAndArgument) {
265+
// This supports the useHeadersInDisplayName attributes in @CsvSource and @CsvFileSource.
265266
prefix = parameterNameAndArgument.getName() + " = ";
266267
argument = parameterNameAndArgument.getPayload();
267268
}
269+
else if (this.generateNameValuePairs && this.resolverFacade != null) {
270+
Optional<String> parameterName = this.resolverFacade.getParameterName(i);
271+
if (parameterName.isPresent()) {
272+
// This supports the {argumentsWithNames} pattern.
273+
prefix = parameterName.get() + " = ";
274+
}
275+
}
268276

269277
if (argument instanceof Character ch) {
270278
result[i] = prefix + (quoteTextArguments ? QuoteUtils.quote(ch) : ch);

jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedInvocationNameFormatterTests.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -406,9 +406,8 @@ void quotedStringsForArgumentsWithNamesAndParameterNameAndArgument() {
406406
var name1 = format(formatter, 1, arguments(new ParameterNameAndArgument("FRUIT", "apple"), 42));
407407
var name2 = format(formatter, 2, arguments(new ParameterNameAndArgument("FRUCHT", "Banane"), 99));
408408

409-
// TODO Remove "fruit = " once #4783 has been fixed.
410-
assertThat(name1).isEqualTo("[1] fruit = FRUIT = \"apple\", ranking = 42");
411-
assertThat(name2).isEqualTo("[2] fruit = FRUCHT = \"Banane\", ranking = 99");
409+
assertThat(name1).isEqualTo("[1] FRUIT = \"apple\", ranking = 42");
410+
assertThat(name2).isEqualTo("[2] FRUCHT = \"Banane\", ranking = 99");
412411
}
413412

414413
}

jupiter-tests/src/test/java/org/junit/jupiter/params/ParameterizedTestIntegrationTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1264,7 +1264,7 @@ void executesWithRepeatableCsvFileSource(String methodName) {
12641264
results.allEvents().assertThatEvents() //
12651265
.haveExactly(1, event(test(), displayName("[1] column1 = foo, column2 = 1"),
12661266
finishedWithFailure(message("foo 1")))) //
1267-
.haveExactly(1, event(test(), displayName("[5] column1 = FRUIT = apple, column2 = RANK = 1"),
1267+
.haveExactly(1, event(test(), displayName("[5] FRUIT = apple, RANK = 1"),
12681268
finishedWithFailure(message("apple 1"))));
12691269
}
12701270

0 commit comments

Comments
 (0)