Skip to content

Commit 9214cfb

Browse files
committed
Cover DurationFormatterUtilsTests with tests
1 parent d9e1ecf commit 9214cfb

File tree

1 file changed

+281
-0
lines changed

1 file changed

+281
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
/*
2+
* Copyright 2002-2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.format.datetime.standard;
18+
19+
import java.time.Duration;
20+
import java.time.format.DateTimeParseException;
21+
import java.time.temporal.ChronoUnit;
22+
23+
import org.junit.jupiter.api.Test;
24+
25+
import static org.assertj.core.api.Assertions.assertThat;
26+
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
27+
import static org.springframework.format.annotation.DurationFormat.Style.ISO8601;
28+
import static org.springframework.format.annotation.DurationFormat.Style.SIMPLE;
29+
30+
class DurationFormatterUtilsTests {
31+
32+
@Test
33+
void parseSimpleWithUnits() {
34+
Duration nanos = DurationFormatterUtils.parse("1ns", SIMPLE, ChronoUnit.SECONDS);
35+
Duration micros = DurationFormatterUtils.parse("-2us", SIMPLE, ChronoUnit.SECONDS);
36+
Duration millis = DurationFormatterUtils.parse("+3ms", SIMPLE, ChronoUnit.SECONDS);
37+
Duration seconds = DurationFormatterUtils.parse("4s", SIMPLE, ChronoUnit.SECONDS);
38+
Duration minutes = DurationFormatterUtils.parse("5m", SIMPLE, ChronoUnit.SECONDS);
39+
Duration hours = DurationFormatterUtils.parse("6h", SIMPLE, ChronoUnit.SECONDS);
40+
Duration days = DurationFormatterUtils.parse("-10d", SIMPLE, ChronoUnit.SECONDS);
41+
42+
assertThat(nanos).hasNanos(1);
43+
assertThat(micros).hasNanos(-2 * 1000);
44+
assertThat(millis).hasMillis(3);
45+
assertThat(seconds).hasSeconds(4);
46+
assertThat(minutes).hasMinutes(5);
47+
assertThat(hours).hasHours(6);
48+
assertThat(days).hasDays(-10);
49+
}
50+
51+
@Test
52+
void parseSimpleWithoutUnits() {
53+
assertThat(DurationFormatterUtils.parse("-123", SIMPLE, ChronoUnit.SECONDS))
54+
.hasSeconds(-123);
55+
assertThat(DurationFormatterUtils.parse("456", SIMPLE, ChronoUnit.SECONDS))
56+
.hasSeconds(456);
57+
}
58+
59+
@Test
60+
void parseNoChronoUnitSimpleWithoutUnitsDefaultsToMillis() {
61+
assertThat(DurationFormatterUtils.parse("-123", SIMPLE))
62+
.hasMillis(-123);
63+
assertThat(DurationFormatterUtils.parse("456", SIMPLE))
64+
.hasMillis(456);
65+
}
66+
67+
@Test
68+
void parseNullChronoUnitSimpleWithoutUnitsDefaultsToMillis() {
69+
assertThat(DurationFormatterUtils.parse("-123", SIMPLE, null))
70+
.hasMillis(-123);
71+
assertThat(DurationFormatterUtils.parse("456", SIMPLE, null))
72+
.hasMillis(456);
73+
}
74+
75+
@Test
76+
void parseSimpleThrows() {
77+
assertThatIllegalArgumentException().isThrownBy(() -> DurationFormatterUtils.parse(";23s", SIMPLE))
78+
.withMessage("';23s' is not a valid simple duration")
79+
.withCause(new IllegalStateException("Does not match simple duration pattern"));
80+
81+
assertThatIllegalArgumentException().isThrownBy(() -> DurationFormatterUtils.parse("+23y", SIMPLE))
82+
.withMessage("'+23y' is not a valid simple duration")
83+
.withCause(new IllegalArgumentException("'y' is not a valid simple duration unit"));
84+
}
85+
86+
@Test
87+
void parseIsoNoChronoUnit() {
88+
//these are based on the examples given in Duration.parse
89+
// "PT20.345S" -- parses as "20.345 seconds"
90+
assertThat(DurationFormatterUtils.parse("PT20.345S", ISO8601))
91+
.hasMillis(20345);
92+
// "PT15M" -- parses as "15 minutes" (where a minute is 60 seconds)
93+
assertThat(DurationFormatterUtils.parse("PT15M", ISO8601))
94+
.hasSeconds(15*60);
95+
// "PT10H" -- parses as "10 hours" (where an hour is 3600 seconds)
96+
assertThat(DurationFormatterUtils.parse("PT10H", ISO8601))
97+
.hasHours(10);
98+
// "P2D" -- parses as "2 days" (where a day is 24 hours or 86400 seconds)
99+
assertThat(DurationFormatterUtils.parse("P2D", ISO8601))
100+
.hasDays(2);
101+
// "P2DT3H4M" -- parses as "2 days, 3 hours and 4 minutes"
102+
assertThat(DurationFormatterUtils.parse("P2DT3H4M", ISO8601))
103+
.isEqualTo(Duration.ofDays(2).plusHours(3).plusMinutes(4));
104+
// "PT-6H3M" -- parses as "-6 hours and +3 minutes"
105+
assertThat(DurationFormatterUtils.parse("PT-6H3M", ISO8601))
106+
.isEqualTo(Duration.ofHours(-6).plusMinutes(3));
107+
// "-PT6H3M" -- parses as "-6 hours and -3 minutes"
108+
assertThat(DurationFormatterUtils.parse("-PT6H3M", ISO8601))
109+
.isEqualTo(Duration.ofHours(-6).plusMinutes(-3));
110+
// "-PT-6H+3M" -- parses as "+6 hours and -3 minutes"
111+
assertThat(DurationFormatterUtils.parse("-PT-6H+3M", ISO8601))
112+
.isEqualTo(Duration.ofHours(6).plusMinutes(-3));
113+
}
114+
115+
@Test
116+
void parseIsoIgnoresFallbackChronoUnit() {
117+
assertThat(DurationFormatterUtils.parse("P2DT3H4M", ISO8601, ChronoUnit.NANOS))
118+
.isEqualTo(Duration.ofDays(2).plusHours(3).plusMinutes(4));
119+
}
120+
121+
@Test
122+
void parseIsoThrows() {
123+
assertThatIllegalArgumentException().isThrownBy(() -> DurationFormatterUtils.parse("P2DWV3H-4M", ISO8601))
124+
.withMessage("'P2DWV3H-4M' is not a valid ISO-8601 duration")
125+
.withCause(new DateTimeParseException("Text cannot be parsed to a Duration", "", 0));
126+
}
127+
128+
@Test
129+
void printSimple() {
130+
assertThat(DurationFormatterUtils.print(Duration.ofNanos(12345), SIMPLE, ChronoUnit.NANOS))
131+
.isEqualTo("12345ns");
132+
assertThat(DurationFormatterUtils.print(Duration.ofNanos(-12345), SIMPLE, ChronoUnit.MICROS))
133+
.isEqualTo("-12us");
134+
}
135+
136+
@Test
137+
void printSimpleNoChronoUnit() {
138+
assertThat(DurationFormatterUtils.print(Duration.ofNanos(12345), SIMPLE))
139+
.isEqualTo("0ms");
140+
assertThat(DurationFormatterUtils.print(Duration.ofSeconds(-3), SIMPLE))
141+
.isEqualTo("-3000ms");
142+
}
143+
144+
@Test
145+
void printIsoNoChronoUnit() {
146+
assertThat(DurationFormatterUtils.print(Duration.ofNanos(12345), ISO8601))
147+
.isEqualTo("PT0.000012345S");
148+
assertThat(DurationFormatterUtils.print(Duration.ofSeconds(-3), ISO8601))
149+
.isEqualTo("PT-3S");
150+
}
151+
152+
@Test
153+
void printIsoIgnoresChronoUnit() {
154+
assertThat(DurationFormatterUtils.print(Duration.ofNanos(12345), ISO8601, ChronoUnit.HOURS))
155+
.isEqualTo("PT0.000012345S");
156+
assertThat(DurationFormatterUtils.print(Duration.ofSeconds(-3), ISO8601, ChronoUnit.HOURS))
157+
.isEqualTo("PT-3S");
158+
}
159+
160+
@Test
161+
void detectAndParse() {
162+
assertThat(DurationFormatterUtils.detectAndParse("PT1.234S", ChronoUnit.NANOS))
163+
.as("iso")
164+
.isEqualTo(Duration.ofMillis(1234));
165+
166+
assertThat(DurationFormatterUtils.detectAndParse("1234ms", ChronoUnit.NANOS))
167+
.as("simple with explicit unit")
168+
.isEqualTo(Duration.ofMillis(1234));
169+
170+
assertThat(DurationFormatterUtils.detectAndParse("1234", ChronoUnit.NANOS))
171+
.as("simple without suffix")
172+
.isEqualTo(Duration.ofNanos(1234));
173+
}
174+
175+
@Test
176+
void detectAndParseNoChronoUnit() {
177+
assertThat(DurationFormatterUtils.detectAndParse("PT1.234S"))
178+
.as("iso")
179+
.isEqualTo(Duration.ofMillis(1234));
180+
181+
assertThat(DurationFormatterUtils.detectAndParse("1234ms"))
182+
.as("simple with explicit unit")
183+
.isEqualTo(Duration.ofMillis(1234));
184+
185+
assertThat(DurationFormatterUtils.detectAndParse("1234"))
186+
.as("simple without suffix")
187+
.isEqualTo(Duration.ofMillis(1234));
188+
}
189+
190+
@Test
191+
void detect() {
192+
assertThat(DurationFormatterUtils.detect("+3ms"))
193+
.as("SIMPLE")
194+
.isEqualTo(SIMPLE);
195+
assertThat(DurationFormatterUtils.detect("-10y"))
196+
.as("invalid yet matching SIMPLE pattern")
197+
.isEqualTo(SIMPLE);
198+
199+
assertThat(DurationFormatterUtils.detect("P2DT3H-4M"))
200+
.as("ISO8601")
201+
.isEqualTo(ISO8601);
202+
assertThat(DurationFormatterUtils.detect("P2DWV3H-4M"))
203+
.as("invalid yet matching ISO8601 pattern")
204+
.isEqualTo(ISO8601);
205+
206+
assertThatIllegalArgumentException().isThrownBy(() -> DurationFormatterUtils.detect("WPT2H-4M"))
207+
.withMessage("'WPT2H-4M' is not a valid duration, cannot detect any known style")
208+
.withNoCause();
209+
}
210+
211+
@Test
212+
void longValueFromUnit() {
213+
Duration nanos = Duration.ofSeconds(3).plusMillis(22).plusNanos(1111);
214+
assertThat(DurationFormatterUtils.longValueFromUnit(nanos, ChronoUnit.NANOS))
215+
.as("NANOS")
216+
.isEqualTo(3022001111L);
217+
assertThat(DurationFormatterUtils.longValueFromUnit(nanos, ChronoUnit.MICROS))
218+
.as("MICROS")
219+
.isEqualTo(3022001);
220+
assertThat(DurationFormatterUtils.longValueFromUnit(nanos, ChronoUnit.MILLIS))
221+
.as("MILLIS")
222+
.isEqualTo(3022);
223+
assertThat(DurationFormatterUtils.longValueFromUnit(nanos, ChronoUnit.SECONDS))
224+
.as("SECONDS")
225+
.isEqualTo(3);
226+
227+
Duration minutes = Duration.ofHours(1).plusMinutes(23);
228+
assertThat(DurationFormatterUtils.longValueFromUnit(minutes, ChronoUnit.MINUTES))
229+
.as("MINUTES")
230+
.isEqualTo(83);
231+
assertThat(DurationFormatterUtils.longValueFromUnit(minutes, ChronoUnit.HOURS))
232+
.as("HOURS")
233+
.isEqualTo(1);
234+
235+
Duration days = Duration.ofHours(48 + 5);
236+
assertThat(DurationFormatterUtils.longValueFromUnit(days, ChronoUnit.HOURS))
237+
.as("HOURS in days")
238+
.isEqualTo(53);
239+
assertThat(DurationFormatterUtils.longValueFromUnit(days, ChronoUnit.DAYS))
240+
.as("DAYS")
241+
.isEqualTo(2);
242+
}
243+
244+
@Test
245+
void longValueFromUnsupportedUnit() {
246+
assertThatIllegalArgumentException().isThrownBy(() -> DurationFormatterUtils.longValueFromUnit(Duration.ofDays(3),
247+
ChronoUnit.HALF_DAYS)).as("HALF_DAYS")
248+
.withMessage("'HALF_DAYS' is not a supported ChronoUnit for simple duration representation");
249+
assertThatIllegalArgumentException().isThrownBy(() -> DurationFormatterUtils.longValueFromUnit(Duration.ofDays(23),
250+
ChronoUnit.WEEKS)).as("WEEKS")
251+
.withMessage("'WEEKS' is not a supported ChronoUnit for simple duration representation");
252+
}
253+
254+
@Test
255+
void unitFromSuffix() {
256+
assertThat(DurationFormatterUtils.unitFromSuffix("ns")).as("ns").isEqualTo(ChronoUnit.NANOS);
257+
assertThat(DurationFormatterUtils.unitFromSuffix("us")).as("us").isEqualTo(ChronoUnit.MICROS);
258+
assertThat(DurationFormatterUtils.unitFromSuffix("ms")).as("ms").isEqualTo(ChronoUnit.MILLIS);
259+
assertThat(DurationFormatterUtils.unitFromSuffix("s")).as("s").isEqualTo(ChronoUnit.SECONDS);
260+
assertThat(DurationFormatterUtils.unitFromSuffix("m")).as("m").isEqualTo(ChronoUnit.MINUTES);
261+
assertThat(DurationFormatterUtils.unitFromSuffix("h")).as("h").isEqualTo(ChronoUnit.HOURS);
262+
assertThat(DurationFormatterUtils.unitFromSuffix("d")).as("d").isEqualTo(ChronoUnit.DAYS);
263+
264+
assertThatIllegalArgumentException().isThrownBy(() -> DurationFormatterUtils.unitFromSuffix("ws"))
265+
.withMessage("'ws' is not a valid simple duration unit");
266+
}
267+
268+
@Test
269+
void suffixFromUnit() {
270+
assertThat(DurationFormatterUtils.suffixFromUnit(ChronoUnit.NANOS)).as("NANOS").isEqualTo("ns");
271+
assertThat(DurationFormatterUtils.suffixFromUnit(ChronoUnit.MICROS)).as("MICROS").isEqualTo("us");
272+
assertThat(DurationFormatterUtils.suffixFromUnit(ChronoUnit.MILLIS)).as("MILLIS").isEqualTo("ms");
273+
assertThat(DurationFormatterUtils.suffixFromUnit(ChronoUnit.SECONDS)).as("SECONDS").isEqualTo("s");
274+
assertThat(DurationFormatterUtils.suffixFromUnit(ChronoUnit.MINUTES)).as("MINUTES").isEqualTo("m");
275+
assertThat(DurationFormatterUtils.suffixFromUnit(ChronoUnit.HOURS)).as("HOURS").isEqualTo("h");
276+
assertThat(DurationFormatterUtils.suffixFromUnit(ChronoUnit.DAYS)).as("DAYS").isEqualTo("d");
277+
278+
assertThatIllegalArgumentException().isThrownBy(() -> DurationFormatterUtils.suffixFromUnit(ChronoUnit.MILLENNIA))
279+
.withMessage("'MILLENNIA' is not a supported ChronoUnit for simple duration representation");
280+
}
281+
}

0 commit comments

Comments
 (0)