Skip to content

Commit 528b570

Browse files
committed
Move string-based argument conversion tests to platform-test
1 parent ed5ac99 commit 528b570

File tree

2 files changed

+349
-1
lines changed

2 files changed

+349
-1
lines changed

Diff for: jupiter-tests/src/test/java/org/junit/jupiter/params/converter/DefaultArgumentConverterTests.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ void throwsExceptionOnInvalidStringForPrimitiveTypes() {
183183
}
184184

185185
@Test
186-
void throwsExceptionWhenImplicitConverstionIsUnsupported() {
186+
void throwsExceptionWhenImplicitConversionIsUnsupported() {
187187
assertThatExceptionOfType(ArgumentConversionException.class) //
188188
.isThrownBy(() -> convert("foo", Enigma.class)) //
189189
.withMessage("No built-in converter for source type java.lang.String and target type %s",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,348 @@
1+
/*
2+
* Copyright 2015-2025 the original author or authors.
3+
*
4+
* All rights reserved. This program and the accompanying materials are
5+
* made available under the terms of the Eclipse Public License v2.0 which
6+
* accompanies this distribution and is available at
7+
*
8+
* https://www.eclipse.org/legal/epl-v20.html
9+
*/
10+
11+
package org.junit.platform.commons.support.conversion;
12+
13+
import static org.assertj.core.api.Assertions.assertThat;
14+
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
15+
16+
import java.io.File;
17+
import java.lang.reflect.Method;
18+
import java.math.BigDecimal;
19+
import java.math.BigInteger;
20+
import java.net.URI;
21+
import java.net.URL;
22+
import java.nio.charset.Charset;
23+
import java.nio.charset.StandardCharsets;
24+
import java.nio.file.Path;
25+
import java.nio.file.Paths;
26+
import java.time.Duration;
27+
import java.time.Instant;
28+
import java.time.LocalDate;
29+
import java.time.LocalDateTime;
30+
import java.time.LocalTime;
31+
import java.time.MonthDay;
32+
import java.time.OffsetDateTime;
33+
import java.time.OffsetTime;
34+
import java.time.Period;
35+
import java.time.Year;
36+
import java.time.YearMonth;
37+
import java.time.ZoneId;
38+
import java.time.ZoneOffset;
39+
import java.time.ZonedDateTime;
40+
import java.util.Currency;
41+
import java.util.Locale;
42+
import java.util.UUID;
43+
import java.util.concurrent.TimeUnit;
44+
45+
import org.junit.jupiter.api.Test;
46+
import org.junit.jupiter.params.ParameterizedTest;
47+
import org.junit.jupiter.params.provider.ValueSource;
48+
import org.junit.platform.commons.support.ReflectionSupport;
49+
import org.junit.platform.commons.test.TestClassLoader;
50+
import org.junit.platform.commons.util.ClassLoaderUtils;
51+
52+
/**
53+
* Unit tests for {@link ConversionSupport}.
54+
*
55+
* @since 5.12
56+
*/
57+
class ConversionSupportTests {
58+
59+
@Test
60+
void isAwareOfNull() {
61+
assertConverts(null, Object.class, null);
62+
assertConverts(null, String.class, null);
63+
assertConverts(null, Boolean.class, null);
64+
}
65+
66+
@Test
67+
void convertsStringsToPrimitiveTypes() {
68+
assertConverts("true", boolean.class, true);
69+
assertConverts("false", boolean.class, false);
70+
assertConverts("o", char.class, 'o');
71+
assertConverts("1", byte.class, (byte) 1);
72+
assertConverts("1_0", byte.class, (byte) 10);
73+
assertConverts("1", short.class, (short) 1);
74+
assertConverts("1_2", short.class, (short) 12);
75+
assertConverts("42", int.class, 42);
76+
assertConverts("700_050_000", int.class, 700_050_000);
77+
assertConverts("42", long.class, 42L);
78+
assertConverts("4_2", long.class, 42L);
79+
assertConverts("42.23", float.class, 42.23f);
80+
assertConverts("42.2_3", float.class, 42.23f);
81+
assertConverts("42.23", double.class, 42.23);
82+
assertConverts("42.2_3", double.class, 42.23);
83+
}
84+
85+
@Test
86+
void convertsStringsToPrimitiveWrapperTypes() {
87+
assertConverts("true", Boolean.class, true);
88+
assertConverts("false", Boolean.class, false);
89+
assertConverts("o", Character.class, 'o');
90+
assertConverts("1", Byte.class, (byte) 1);
91+
assertConverts("1_0", Byte.class, (byte) 10);
92+
assertConverts("1", Short.class, (short) 1);
93+
assertConverts("1_2", Short.class, (short) 12);
94+
assertConverts("42", Integer.class, 42);
95+
assertConverts("700_050_000", Integer.class, 700_050_000);
96+
assertConverts("42", Long.class, 42L);
97+
assertConverts("4_2", Long.class, 42L);
98+
assertConverts("42.23", Float.class, 42.23f);
99+
assertConverts("42.2_3", Float.class, 42.23f);
100+
assertConverts("42.23", Double.class, 42.23);
101+
assertConverts("42.2_3", Double.class, 42.23);
102+
}
103+
104+
@ParameterizedTest(name = "[{index}] {0}")
105+
@ValueSource(classes = { char.class, boolean.class, short.class, byte.class, int.class, long.class, float.class,
106+
double.class, void.class })
107+
void throwsExceptionForNullToPrimitiveTypeConversion(Class<?> type) {
108+
assertThatExceptionOfType(ConversionException.class) //
109+
.isThrownBy(() -> convert(null, type)) //
110+
.withMessage("Cannot convert null to primitive value of type " + type.getCanonicalName());
111+
}
112+
113+
@ParameterizedTest(name = "[{index}] {0}")
114+
@ValueSource(classes = { Boolean.class, Character.class, Short.class, Byte.class, Integer.class, Long.class,
115+
Float.class, Double.class })
116+
void throwsExceptionWhenConvertingTheWordNullToPrimitiveWrapperType(Class<?> type) {
117+
assertThatExceptionOfType(ConversionException.class) //
118+
.isThrownBy(() -> convert("null", type)) //
119+
.withMessage("Failed to convert String \"null\" to type " + type.getCanonicalName());
120+
assertThatExceptionOfType(ConversionException.class) //
121+
.isThrownBy(() -> convert("NULL", type)) //
122+
.withMessage("Failed to convert String \"NULL\" to type " + type.getCanonicalName());
123+
}
124+
125+
@Test
126+
void throwsExceptionOnInvalidStringForPrimitiveTypes() {
127+
assertThatExceptionOfType(ConversionException.class) //
128+
.isThrownBy(() -> convert("ab", char.class)) //
129+
.withMessage("Failed to convert String \"ab\" to type char") //
130+
.havingCause() //
131+
.withMessage("String must have length of 1: ab");
132+
133+
assertThatExceptionOfType(ConversionException.class) //
134+
.isThrownBy(() -> convert("tru", boolean.class)) //
135+
.withMessage("Failed to convert String \"tru\" to type boolean") //
136+
.havingCause() //
137+
.withMessage("String must be 'true' or 'false' (ignoring case): tru");
138+
139+
assertThatExceptionOfType(ConversionException.class) //
140+
.isThrownBy(() -> convert("null", boolean.class)) //
141+
.withMessage("Failed to convert String \"null\" to type boolean") //
142+
.havingCause() //
143+
.withMessage("String must be 'true' or 'false' (ignoring case): null");
144+
145+
assertThatExceptionOfType(ConversionException.class) //
146+
.isThrownBy(() -> convert("NULL", boolean.class)) //
147+
.withMessage("Failed to convert String \"NULL\" to type boolean") //
148+
.havingCause() //
149+
.withMessage("String must be 'true' or 'false' (ignoring case): NULL");
150+
}
151+
152+
@Test
153+
void throwsExceptionWhenImplicitConversionIsUnsupported() {
154+
assertThatExceptionOfType(ConversionException.class) //
155+
.isThrownBy(() -> convert("foo", Enigma.class)) //
156+
.withMessage("No built-in converter for source type java.lang.String and target type %s",
157+
Enigma.class.getName());
158+
}
159+
160+
/**
161+
* @since 5.4
162+
*/
163+
@Test
164+
@SuppressWarnings("OctalInteger") // We test parsing octal integers here as well as hex.
165+
void convertsEncodedStringsToIntegralTypes() {
166+
assertConverts("0x1f", byte.class, (byte) 0x1F);
167+
assertConverts("-0x1F", byte.class, (byte) -0x1F);
168+
assertConverts("010", byte.class, (byte) 010);
169+
170+
assertConverts("0x1f00", short.class, (short) 0x1F00);
171+
assertConverts("-0x1F00", short.class, (short) -0x1F00);
172+
assertConverts("01000", short.class, (short) 01000);
173+
174+
assertConverts("0x1f000000", int.class, 0x1F000000);
175+
assertConverts("-0x1F000000", int.class, -0x1F000000);
176+
assertConverts("010000000", int.class, 010000000);
177+
178+
assertConverts("0x1f000000000", long.class, 0x1F000000000L);
179+
assertConverts("-0x1F000000000", long.class, -0x1F000000000L);
180+
assertConverts("0100000000000", long.class, 0100000000000L);
181+
}
182+
183+
@Test
184+
void convertsStringsToEnumConstants() {
185+
assertConverts("DAYS", TimeUnit.class, TimeUnit.DAYS);
186+
}
187+
188+
// --- java.io and java.nio ------------------------------------------------
189+
190+
@Test
191+
void convertsStringToCharset() {
192+
assertConverts("ISO-8859-1", Charset.class, StandardCharsets.ISO_8859_1);
193+
assertConverts("UTF-8", Charset.class, StandardCharsets.UTF_8);
194+
}
195+
196+
@Test
197+
void convertsStringToFile() {
198+
assertConverts("file", File.class, new File("file"));
199+
assertConverts("/file", File.class, new File("/file"));
200+
assertConverts("/some/file", File.class, new File("/some/file"));
201+
}
202+
203+
@Test
204+
void convertsStringToPath() {
205+
assertConverts("path", Path.class, Paths.get("path"));
206+
assertConverts("/path", Path.class, Paths.get("/path"));
207+
assertConverts("/some/path", Path.class, Paths.get("/some/path"));
208+
}
209+
210+
// --- java.lang -----------------------------------------------------------
211+
212+
@Test
213+
void convertsStringToClass() {
214+
assertConverts("java.lang.Integer", Class.class, Integer.class);
215+
assertConverts("java.lang.Void", Class.class, Void.class);
216+
assertConverts("java.lang.Thread$State", Class.class, Thread.State.class);
217+
assertConverts("byte", Class.class, byte.class);
218+
assertConverts("void", Class.class, void.class);
219+
assertConverts("char[]", Class.class, char[].class);
220+
assertConverts("java.lang.Long[][]", Class.class, Long[][].class);
221+
assertConverts("[[[I", Class.class, int[][][].class);
222+
assertConverts("[[Ljava.lang.String;", Class.class, String[][].class);
223+
}
224+
225+
@Test
226+
void convertsStringToClassWithCustomTypeFromDifferentClassLoader() throws Exception {
227+
String customTypeName = Enigma.class.getName();
228+
try (var testClassLoader = TestClassLoader.forClasses(Enigma.class)) {
229+
var customType = testClassLoader.loadClass(customTypeName);
230+
assertThat(customType.getClassLoader()).isSameAs(testClassLoader);
231+
232+
var declaringExecutable = ReflectionSupport.findMethod(customType, "foo").get();
233+
assertThat(declaringExecutable.getDeclaringClass().getClassLoader()).isSameAs(testClassLoader);
234+
235+
var clazz = (Class<?>) convert(customTypeName, Class.class, classLoader(declaringExecutable));
236+
assertThat(clazz).isNotEqualTo(Enigma.class);
237+
assertThat(clazz).isEqualTo(customType);
238+
assertThat(clazz.getClassLoader()).isSameAs(testClassLoader);
239+
}
240+
}
241+
242+
// --- java.math -----------------------------------------------------------
243+
244+
@Test
245+
void convertsStringToBigDecimal() {
246+
assertConverts("123.456e789", BigDecimal.class, new BigDecimal("123.456e789"));
247+
}
248+
249+
@Test
250+
void convertsStringToBigInteger() {
251+
assertConverts("1234567890123456789", BigInteger.class, new BigInteger("1234567890123456789"));
252+
}
253+
254+
// --- java.net ------------------------------------------------------------
255+
256+
@Test
257+
void convertsStringToURI() {
258+
assertConverts("https://docs.oracle.com/en/java/javase/12/", URI.class,
259+
URI.create("https://docs.oracle.com/en/java/javase/12/"));
260+
}
261+
262+
@Test
263+
void convertsStringToURL() throws Exception {
264+
assertConverts("https://junit.org/junit5", URL.class, URI.create("https://junit.org/junit5").toURL());
265+
}
266+
267+
// --- java.time -----------------------------------------------------------
268+
269+
@Test
270+
void convertsStringsToJavaTimeInstances() {
271+
assertConverts("PT1234.5678S", Duration.class, Duration.ofSeconds(1234, 567800000));
272+
assertConverts("1970-01-01T00:00:00Z", Instant.class, Instant.ofEpochMilli(0));
273+
assertConverts("2017-03-14", LocalDate.class, LocalDate.of(2017, 3, 14));
274+
assertConverts("2017-03-14T12:34:56.789", LocalDateTime.class,
275+
LocalDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000));
276+
assertConverts("12:34:56.789", LocalTime.class, LocalTime.of(12, 34, 56, 789_000_000));
277+
assertConverts("--03-14", MonthDay.class, MonthDay.of(3, 14));
278+
assertConverts("2017-03-14T12:34:56.789Z", OffsetDateTime.class,
279+
OffsetDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC));
280+
assertConverts("12:34:56.789Z", OffsetTime.class, OffsetTime.of(12, 34, 56, 789_000_000, ZoneOffset.UTC));
281+
assertConverts("P2M6D", Period.class, Period.of(0, 2, 6));
282+
assertConverts("2017", Year.class, Year.of(2017));
283+
assertConverts("2017-03", YearMonth.class, YearMonth.of(2017, 3));
284+
assertConverts("2017-03-14T12:34:56.789Z", ZonedDateTime.class,
285+
ZonedDateTime.of(2017, 3, 14, 12, 34, 56, 789_000_000, ZoneOffset.UTC));
286+
assertConverts("Europe/Berlin", ZoneId.class, ZoneId.of("Europe/Berlin"));
287+
assertConverts("+02:30", ZoneOffset.class, ZoneOffset.ofHoursMinutes(2, 30));
288+
}
289+
290+
// --- java.util -----------------------------------------------------------
291+
292+
@Test
293+
void convertsStringToCurrency() {
294+
assertConverts("JPY", Currency.class, Currency.getInstance("JPY"));
295+
}
296+
297+
@Test
298+
@SuppressWarnings("deprecation")
299+
void convertsStringToLocale() {
300+
assertConverts("en", Locale.class, Locale.ENGLISH);
301+
assertConverts("en_us", Locale.class, new Locale(Locale.US.toString()));
302+
}
303+
304+
@Test
305+
void convertsStringToUUID() {
306+
var uuid = "d043e930-7b3b-48e3-bdbe-5a3ccfb833db";
307+
assertConverts(uuid, UUID.class, UUID.fromString(uuid));
308+
}
309+
310+
// -------------------------------------------------------------------------
311+
312+
private void assertConverts(String input, Class<?> targetClass, Object expectedOutput) {
313+
var result = convert(input, targetClass);
314+
315+
assertThat(result) //
316+
.describedAs(input + " --(" + targetClass.getName() + ")--> " + expectedOutput) //
317+
.isEqualTo(expectedOutput);
318+
}
319+
320+
private Object convert(String input, Class<?> targetClass) {
321+
return convert(input, targetClass, classLoader());
322+
}
323+
324+
private Object convert(String input, Class<?> targetClass, ClassLoader classLoader) {
325+
return ConversionSupport.convert(input, targetClass, classLoader);
326+
}
327+
328+
private static ClassLoader classLoader() {
329+
Method declaringExecutable = ReflectionSupport.findMethod(ConversionSupportTests.class, "foo").get();
330+
return classLoader(declaringExecutable);
331+
}
332+
333+
private static ClassLoader classLoader(Method declaringExecutable) {
334+
return ClassLoaderUtils.getClassLoader(declaringExecutable.getDeclaringClass());
335+
}
336+
337+
@SuppressWarnings("unused")
338+
private static void foo() {
339+
}
340+
341+
private static class Enigma {
342+
343+
@SuppressWarnings("unused")
344+
void foo() {
345+
}
346+
}
347+
348+
}

0 commit comments

Comments
 (0)