1
2
3
4
5
6 package dev.metaschema.core.metapath.function.impl;
7
8 import static dev.metaschema.core.metapath.TestUtils.bool;
9 import static dev.metaschema.core.metapath.TestUtils.date;
10 import static dev.metaschema.core.metapath.TestUtils.dateTime;
11 import static dev.metaschema.core.metapath.TestUtils.dayTimeDuration;
12 import static dev.metaschema.core.metapath.TestUtils.decimal;
13 import static dev.metaschema.core.metapath.TestUtils.duration;
14 import static dev.metaschema.core.metapath.TestUtils.integer;
15 import static dev.metaschema.core.metapath.TestUtils.time;
16 import static dev.metaschema.core.metapath.TestUtils.yearMonthDuration;
17 import static org.assertj.core.api.Assertions.assertThat;
18 import static org.assertj.core.api.Assertions.from;
19 import static org.junit.jupiter.api.Assertions.assertAll;
20 import static org.junit.jupiter.api.Assertions.assertEquals;
21 import static org.junit.jupiter.api.Assertions.assertThrows;
22
23 import org.junit.jupiter.api.DisplayName;
24 import org.junit.jupiter.api.Nested;
25 import org.junit.jupiter.api.Test;
26 import org.junit.jupiter.api.TestInstance;
27 import org.junit.jupiter.params.ParameterizedTest;
28 import org.junit.jupiter.params.provider.Arguments;
29 import org.junit.jupiter.params.provider.MethodSource;
30
31 import java.util.stream.Stream;
32
33 import dev.metaschema.core.metapath.DynamicContext;
34 import dev.metaschema.core.metapath.function.ArithmeticFunctionException;
35 import dev.metaschema.core.metapath.function.CastFunctionException;
36 import dev.metaschema.core.metapath.function.DateTimeFunctionException;
37 import dev.metaschema.core.metapath.item.atomic.IBooleanItem;
38 import dev.metaschema.core.metapath.item.atomic.IDateItem;
39 import dev.metaschema.core.metapath.item.atomic.IDateTimeItem;
40 import dev.metaschema.core.metapath.item.atomic.IDayTimeDurationItem;
41 import dev.metaschema.core.metapath.item.atomic.IDecimalItem;
42 import dev.metaschema.core.metapath.item.atomic.IDurationItem;
43 import dev.metaschema.core.metapath.item.atomic.IIntegerItem;
44 import dev.metaschema.core.metapath.item.atomic.INumericItem;
45 import dev.metaschema.core.metapath.item.atomic.ITimeItem;
46 import dev.metaschema.core.metapath.item.atomic.IYearMonthDurationItem;
47 import edu.umd.cs.findbugs.annotations.NonNull;
48 import edu.umd.cs.findbugs.annotations.Nullable;
49
50 class OperationFunctionsTest {
51 @Nested
52 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
53 @DisplayName("Functions and operators on numerics")
54 class Numeric {
55 private Stream<Arguments> provideValuesOpNumericAdd() {
56 return Stream.of(
57 Arguments.of(integer(2), integer(1), integer(1)),
58 Arguments.of(decimal("2.0"), decimal("1.0"), integer(1)),
59 Arguments.of(decimal("2.0"), integer(1), decimal("1.0")),
60 Arguments.of(decimal("2.0"), decimal("1.0"), decimal("1.0")));
61 }
62
63 @ParameterizedTest
64 @MethodSource("provideValuesOpNumericAdd")
65 @DisplayName("op:numeric-add")
66 void testOpNumericAdd(
67 @NonNull INumericItem expected,
68 @NonNull INumericItem addend1,
69 @NonNull INumericItem addend2) {
70 assertEquals(expected, OperationFunctions.opNumericAdd(addend1, addend2));
71 }
72
73 private Stream<Arguments> provideValuesOpNumericSubtract() {
74 return Stream.of(
75 Arguments.of(integer(0), integer(1), integer(1)),
76 Arguments.of(decimal("0"), decimal("1.0"), integer(1)),
77 Arguments.of(decimal("0"), integer(1), decimal("1.0")),
78 Arguments.of(decimal("0"), decimal("1.0"), decimal("1.0")));
79 }
80
81 @ParameterizedTest
82 @MethodSource("provideValuesOpNumericSubtract")
83 @DisplayName("op:numeric-subtract")
84 void testOpNumericSubtract(
85 @NonNull INumericItem expected,
86 @NonNull INumericItem minuend,
87 @NonNull INumericItem subtrahend) {
88 assertEquals(expected, OperationFunctions.opNumericSubtract(minuend, subtrahend));
89 }
90
91 private Stream<Arguments> provideValuesOpNumericMultiply() {
92 return Stream.of(
93 Arguments.of(integer(0), integer(1), integer(0)),
94 Arguments.of(integer(1), integer(1), integer(1)),
95 Arguments.of(integer(2), integer(1), integer(2)),
96 Arguments.of(decimal("1.0"), decimal("1.0"), integer(1)),
97 Arguments.of(decimal("1.0"), integer(1), decimal("1.0")),
98 Arguments.of(decimal("1.0"), decimal("1.0"), decimal("1.0")));
99 }
100
101 @ParameterizedTest
102 @MethodSource("provideValuesOpNumericMultiply")
103 @DisplayName("op:numeric-multiply")
104 void testOpNumericMultiply(
105 @NonNull INumericItem expected,
106 @NonNull INumericItem multiplicand,
107 @NonNull INumericItem multiplier) {
108 assertEquals(expected, OperationFunctions.opNumericMultiply(multiplicand, multiplier));
109 }
110
111 @Nested
112 @DisplayName("op:numeric-divide")
113 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
114 class NumericDivide {
115 private Stream<Arguments> provideValuesOpNumericDivide() {
116 return Stream.of(
117 Arguments.of(decimal("0"), integer(0), integer(1)),
118 Arguments.of(decimal("1"), integer(1), integer(1)),
119 Arguments.of(decimal("0.5"), integer(1), integer(2)),
120 Arguments.of(decimal("1.0"), decimal("1.0"), integer(1)),
121 Arguments.of(decimal("1.0"), integer(1), decimal("1.0")),
122 Arguments.of(decimal("1.0"), decimal("1.0"), decimal("1.0")));
123 }
124
125 @ParameterizedTest
126 @MethodSource("provideValuesOpNumericDivide")
127 @DisplayName("op:numeric-divide - known good")
128 void testOpNumericDivide(
129 @NonNull INumericItem expected,
130 @NonNull INumericItem dividend,
131 @NonNull INumericItem divisor) {
132 assertEquals(expected, OperationFunctions.opNumericDivide(dividend, divisor));
133 }
134
135 private Stream<Arguments> provideValuesOpNumericDivideByZero() {
136 return Stream.of(
137 Arguments.of(integer(0), integer(0)),
138 Arguments.of(decimal("1.0"), integer(0)),
139 Arguments.of(integer(1), decimal("0.0")),
140 Arguments.of(integer(1), decimal("0")));
141 }
142
143 @ParameterizedTest
144 @MethodSource("provideValuesOpNumericDivideByZero")
145 @DisplayName("op:numeric-divide - by zero")
146 void testOpNumericDivideByZero(
147 @NonNull INumericItem dividend,
148 @NonNull INumericItem divisor) {
149 ArithmeticFunctionException thrown = assertThrows(ArithmeticFunctionException.class, () -> {
150 OperationFunctions.opNumericDivide(dividend, divisor);
151 });
152 assertThat(thrown)
153 .isExactlyInstanceOf(ArithmeticFunctionException.class)
154 .returns(
155 ArithmeticFunctionException.DIVISION_BY_ZERO,
156 from(ex -> ex.getErrorCode().getCode()))
157 .hasNoCause();
158 }
159 }
160
161 @Nested
162 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
163 @DisplayName("op:numeric-integer-divide")
164 class NumericIntegerDivide {
165 private Stream<Arguments> provideValuesOpNumericIntegerDivide() {
166 return Stream.of(
167 Arguments.of(integer(3), integer(10), integer(3)),
168 Arguments.of(integer(-1), integer(3), integer(-2)),
169 Arguments.of(integer(-1), integer(-3), integer(2)),
170 Arguments.of(integer(3), decimal("9.0"), integer(3)),
171 Arguments.of(integer(-1), decimal("-3.5"), integer(3)),
172 Arguments.of(integer(0), decimal("3.0"), integer(4)),
173 Arguments.of(integer(5), decimal("3.1E1"), integer(6)),
174 Arguments.of(integer(4), decimal("3.1E1"), integer(7)));
175 }
176
177 @ParameterizedTest
178 @MethodSource("provideValuesOpNumericIntegerDivide")
179 @DisplayName("op:numeric-integer-divide - by zero")
180 void testOpNumericIntegerDivide(
181 @NonNull IIntegerItem expected,
182 @NonNull INumericItem dividend,
183 @NonNull INumericItem divisor) {
184 assertEquals(expected, OperationFunctions.opNumericIntegerDivide(dividend, divisor));
185 }
186
187 private Stream<Arguments> provideValuesOpNumericIntegerDivideByZero() {
188 return Stream.of(
189 Arguments.of(integer(0), integer(0)),
190 Arguments.of(decimal("1.0"), integer(0)),
191 Arguments.of(integer(1), decimal("0.0")),
192 Arguments.of(integer(1), decimal("0")));
193 }
194
195 @ParameterizedTest
196 @MethodSource("provideValuesOpNumericIntegerDivideByZero")
197 void testOpNumericIntegerDivideByZero(
198 @NonNull INumericItem dividend,
199 @NonNull INumericItem divisor) {
200 ArithmeticFunctionException thrown = assertThrows(ArithmeticFunctionException.class, () -> {
201 OperationFunctions.opNumericIntegerDivide(dividend, divisor);
202 });
203 assertThat(thrown)
204 .isExactlyInstanceOf(ArithmeticFunctionException.class)
205 .returns(
206 ArithmeticFunctionException.DIVISION_BY_ZERO,
207 from(ex -> ex.getErrorCode().getCode()))
208 .hasNoCause();
209 }
210 }
211
212 private Stream<Arguments> provideValuesOpNumericMod() {
213 return Stream.of(
214 Arguments.of(integer(1), integer(10), integer(3)),
215 Arguments.of(decimal(0), integer(6), integer(-2)),
216 Arguments.of(decimal(3.0E0), decimal(1.23E2), decimal(0.6E1)),
217 Arguments.of(integer(2), integer(5), integer(3)),
218 Arguments.of(integer(0), integer(6), integer(-2)),
219 Arguments.of(decimal("0.9"), decimal("4.5"), decimal("1.2")),
220 Arguments.of(integer(3), integer(123), integer(6)));
221 }
222
223 @ParameterizedTest
224 @MethodSource("provideValuesOpNumericMod")
225 @DisplayName("op:numeric-mod")
226 void testOpNumericMod(@Nullable INumericItem expected, @NonNull INumericItem dividend,
227 @NonNull INumericItem divisor) {
228 assertEquals(expected, OperationFunctions.opNumericMod(dividend, divisor));
229 }
230
231 private Stream<Arguments> provideValuesOpNumericModByZero() {
232 return Stream.of(
233 Arguments.of(integer(0), integer(0)),
234 Arguments.of(decimal("1.0"), integer(0)),
235 Arguments.of(integer(1), decimal("0.0")),
236 Arguments.of(integer(1), decimal("0")));
237 }
238
239 @ParameterizedTest
240 @MethodSource("provideValuesOpNumericModByZero")
241 @DisplayName("op:numeric-mod - by zero")
242 void testOpNumericModByZero(
243 @NonNull INumericItem dividend,
244 @NonNull INumericItem divisor) {
245 ArithmeticFunctionException thrown = assertThrows(ArithmeticFunctionException.class, () -> {
246 OperationFunctions.opNumericMod(dividend, divisor);
247 });
248 assertThat(thrown)
249 .isExactlyInstanceOf(ArithmeticFunctionException.class)
250 .returns(
251 ArithmeticFunctionException.DIVISION_BY_ZERO,
252 from(ex -> ex.getErrorCode().getCode()))
253 .hasNoCause();
254 }
255
256 private Stream<Arguments> provideValuesOpNumericUnaryMinus() {
257 return Stream.of(
258 Arguments.of(integer(-10), integer(10)),
259 Arguments.of(integer(3), integer(-3)),
260 Arguments.of(decimal(0), integer(-0)),
261 Arguments.of(decimal(3.0E0), decimal(-3.0E0)),
262 Arguments.of(decimal("-0.9"), decimal("0.9")));
263 }
264
265 @ParameterizedTest
266 @MethodSource("provideValuesOpNumericUnaryMinus")
267 @DisplayName("op:numeric-unary-minus")
268 void testOpNumericUnaryMinus(@Nullable INumericItem expected, @NonNull INumericItem item) {
269 assertEquals(expected, OperationFunctions.opNumericUnaryMinus(item));
270 }
271 }
272
273 @Nested
274 @DisplayName("Comparison operators on numeric values")
275 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
276 class NumericComparison {
277
278 private Stream<Arguments> provideValuesOpNumericEqual() {
279 return Stream.of(
280 Arguments.of(bool(false), null, integer(1)),
281 Arguments.of(bool(false), integer(1), null),
282 Arguments.of(bool(false), null, null),
283 Arguments.of(bool(true), integer(1), integer(1)),
284 Arguments.of(bool(true), integer(0), integer(0)),
285 Arguments.of(bool(true), decimal(0), integer(-0)),
286 Arguments.of(bool(true), decimal(3.0E0), decimal(3.0E0)),
287 Arguments.of(bool(false), integer(-10), integer(10)),
288 Arguments.of(bool(false), integer(3), integer(-3)),
289 Arguments.of(bool(false), decimal(3.0E0), decimal(-3.0E0)),
290 Arguments.of(bool(false), decimal("-0.9"), decimal("0.9")));
291 }
292
293 @ParameterizedTest
294 @MethodSource("provideValuesOpNumericEqual")
295 @DisplayName("op:numeric-equal")
296 void testOpNumericUnaryMinus(
297 @NonNull IBooleanItem expected,
298 @Nullable INumericItem item1,
299 @Nullable INumericItem item2) {
300 assertEquals(expected, OperationFunctions.opNumericEqual(item1, item2));
301 }
302
303 private Stream<Arguments> provideValuesOpNumericLessThan() {
304 return Stream.of(
305 Arguments.of(bool(false), null, integer(1)),
306 Arguments.of(bool(false), integer(1), null),
307 Arguments.of(bool(false), null, null),
308 Arguments.of(bool(false), integer(1), integer(1)),
309 Arguments.of(bool(false), integer(0), integer(0)),
310 Arguments.of(bool(false), decimal(0), integer(-0)),
311 Arguments.of(bool(false), decimal(3.0E0), decimal(3.0E0)),
312 Arguments.of(bool(true), integer(-10), integer(10)),
313 Arguments.of(bool(false), integer(3), integer(-3)),
314 Arguments.of(bool(false), decimal(3.0E0), decimal(-3.0E0)),
315 Arguments.of(bool(true), decimal("-0.9"), decimal("0.9")));
316 }
317
318 @ParameterizedTest
319 @MethodSource("provideValuesOpNumericLessThan")
320 @DisplayName("op:numeric-less-than and op:numeric-greater-than")
321 void testOpNumericNumericLessThan(
322 @NonNull IBooleanItem expected,
323 @Nullable INumericItem item1,
324 @Nullable INumericItem item2) {
325 assertAll(
326 () -> assertEquals(expected, OperationFunctions.opNumericLessThan(item1, item2)),
327 () -> assertEquals(expected, OperationFunctions.opNumericGreaterThan(item2, item1)));
328 }
329 }
330
331 @Nested
332 @DisplayName("Functions and operators on Boolean values")
333 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
334 class Boolean {
335
336 @Nested
337 @DisplayName("Operators on Boolean values")
338 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
339 class BooleanComparison {
340 private Stream<Arguments> provideValuesOpBooleanEqual() {
341 return Stream.of(
342 Arguments.of(bool(true), bool(true), bool(true)),
343 Arguments.of(bool(false), bool(true), bool(false)),
344 Arguments.of(bool(false), bool(false), bool(true)),
345 Arguments.of(bool(true), bool(false), bool(false)));
346 }
347
348 @ParameterizedTest
349 @MethodSource("provideValuesOpBooleanEqual")
350 @DisplayName("op:boolean-equal")
351 void testOpBooleanEqual(
352 @Nullable IBooleanItem expected,
353 @NonNull IBooleanItem item1,
354 @NonNull IBooleanItem item2) {
355 assertEquals(expected, OperationFunctions.opBooleanEqual(item1, item2));
356 }
357
358 private Stream<Arguments> provideValuesOpBooleanLessThan() {
359 return Stream.of(
360 Arguments.of(bool(false), bool(true), bool(true)),
361 Arguments.of(bool(false), bool(true), bool(false)),
362 Arguments.of(bool(true), bool(false), bool(true)),
363 Arguments.of(bool(false), bool(false), bool(false)));
364 }
365
366 @ParameterizedTest
367 @MethodSource("provideValuesOpBooleanLessThan")
368 @DisplayName("op:boolean-less-than")
369 void testOpBooleanLessThan(
370 @Nullable IBooleanItem expected,
371 @NonNull IBooleanItem item1,
372 @NonNull IBooleanItem item2) {
373 assertEquals(expected, OperationFunctions.opBooleanLessThan(item1, item2));
374 }
375
376 private Stream<Arguments> provideValuesOpBooleanGreaterThan() {
377 return Stream.of(
378 Arguments.of(bool(false), bool(true), bool(true)),
379 Arguments.of(bool(true), bool(true), bool(false)),
380 Arguments.of(bool(false), bool(false), bool(true)),
381 Arguments.of(bool(false), bool(false), bool(false)));
382 }
383
384 @ParameterizedTest
385 @MethodSource("provideValuesOpBooleanGreaterThan")
386 @DisplayName("op:boolean-greater-than")
387 void testOpBooleanGreaterThan(
388 @Nullable IBooleanItem expected,
389 @NonNull IBooleanItem item1,
390 @NonNull IBooleanItem item2) {
391 assertEquals(expected, OperationFunctions.opBooleanGreaterThan(item1, item2));
392 }
393 }
394 }
395
396 @Nested
397 @DisplayName("Functions and operators on durations")
398 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
399 class Duration {
400 @Nested
401 @DisplayName("Comparison operators on durations")
402 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
403 class DurationComparison {
404 private Stream<Arguments> provideValuesDurationEqual() {
405 return Stream.of(
406 Arguments.of(bool(true), duration("P1Y"), duration("P12M")),
407 Arguments.of(bool(true), duration("PT24H"), duration("P1D")),
408 Arguments.of(bool(false), duration("P1Y"), duration("P365D")),
409 Arguments.of(bool(true), duration("P0Y"), duration("P0D")),
410 Arguments.of(bool(true), yearMonthDuration("P0Y"), dayTimeDuration("P0D")),
411 Arguments.of(bool(false), yearMonthDuration("P1Y"), dayTimeDuration("P365D")),
412 Arguments.of(bool(true), yearMonthDuration("P2Y"), yearMonthDuration("P24M")),
413 Arguments.of(bool(true), dayTimeDuration("P10D"), dayTimeDuration("PT240H")),
414 Arguments.of(bool(true), duration("P2Y0M0DT0H0M0S"), yearMonthDuration("P24M")),
415 Arguments.of(bool(true), duration("P0Y0M10D"), dayTimeDuration("PT240H")));
416 }
417
418 @ParameterizedTest
419 @DisplayName("op:duration-equal")
420 @MethodSource("provideValuesDurationEqual")
421 void testOpDurationEqual(
422 @NonNull IBooleanItem expected,
423 @NonNull IDurationItem arg1,
424 @NonNull IDurationItem arg2) {
425 assertEquals(expected, OperationFunctions.opDurationEqual(arg1, arg2));
426 }
427
428 private Stream<Arguments> provideValuesYearMonthDurationLessAndGreaterThan() {
429 return Stream.of(
430 Arguments.of(bool(false), yearMonthDuration("P1Y"), yearMonthDuration("P11M")),
431 Arguments.of(bool(true), yearMonthDuration("P2Y"), yearMonthDuration("P25M")),
432 Arguments.of(bool(false), yearMonthDuration("P2Y"), yearMonthDuration("P1Y9M")),
433 Arguments.of(bool(true), yearMonthDuration("P1Y"), yearMonthDuration("P15M")),
434 Arguments.of(bool(false), yearMonthDuration("P3Y"), yearMonthDuration("P1Y15M")),
435 Arguments.of(bool(true), yearMonthDuration("P3Y"), yearMonthDuration("P1Y72M")),
436 Arguments.of(bool(false), yearMonthDuration("P1Y"), yearMonthDuration("P12M")),
437 Arguments.of(bool(false), yearMonthDuration("P2Y"), yearMonthDuration("P24M")));
438 }
439
440 @ParameterizedTest
441 @DisplayName("op:yearMonthDuration-less-than and op:yearMonthDuration-greater-than")
442 @MethodSource("provideValuesYearMonthDurationLessAndGreaterThan")
443 void testOpYearMonthDurationLessAndGreaterThan(
444 @NonNull IBooleanItem expected,
445 @NonNull IYearMonthDurationItem item1,
446 @NonNull IYearMonthDurationItem item2) {
447 assertAll(
448 () -> assertEquals(expected, OperationFunctions.opYearMonthDurationLessThan(item1, item2)),
449 () -> assertEquals(expected, OperationFunctions.opYearMonthDurationGreaterThan(item2, item1)));
450
451 }
452
453 private Stream<Arguments> provideValuesDayTimeDurationLessAndGreaterThan() {
454 return Stream.of(
455 Arguments.of(bool(false), dayTimeDuration("P1D"), dayTimeDuration("PT24H")),
456 Arguments.of(bool(true), dayTimeDuration("P2D"), dayTimeDuration("P1DT25H")),
457 Arguments.of(bool(true), dayTimeDuration("P2D"), dayTimeDuration("P1DT86401S")),
458 Arguments.of(bool(true), dayTimeDuration("P1D"), dayTimeDuration("P2D")),
459 Arguments.of(bool(true), dayTimeDuration("P3D"), dayTimeDuration("PT4321M")),
460 Arguments.of(bool(false), dayTimeDuration("P1D"), dayTimeDuration("P1D")),
461 Arguments.of(bool(false), dayTimeDuration("PT1H"), dayTimeDuration("PT1H")),
462 Arguments.of(bool(false), dayTimeDuration("PT1M"), dayTimeDuration("PT1M")),
463 Arguments.of(bool(false), dayTimeDuration("PT1S"), dayTimeDuration("PT1S")),
464 Arguments.of(bool(true), dayTimeDuration("PT1S"), dayTimeDuration("PT2S")));
465 }
466
467 @ParameterizedTest
468 @DisplayName("op:dayTimeDuration-less-than and op:dayTimeDuration-greater-than")
469 @MethodSource("provideValuesDayTimeDurationLessAndGreaterThan")
470 void testOpDayTimeDurationLessAndGreaterThan(
471 @NonNull IBooleanItem expected,
472 @NonNull IDayTimeDurationItem item1,
473 @NonNull IDayTimeDurationItem item2) {
474 assertAll(
475 () -> assertEquals(expected, OperationFunctions.opDayTimeDurationLessThan(item1, item2)),
476 () -> assertEquals(expected, OperationFunctions.opDayTimeDurationGreaterThan(item2, item1)));
477 }
478 }
479
480 @Nested
481 @DisplayName("Arithmetic operators on durations")
482 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
483 class DurationArithmetic {
484 @Nested
485 class YearMonthDuration {
486
487 @Test
488 @DisplayName("op:add-yearMonthDurations: known good")
489 void testOpAddYearMonthDurations() {
490 assertEquals(
491 IYearMonthDurationItem.valueOf("P6Y2M"),
492 OperationFunctions.opAddYearMonthDurations(
493 IYearMonthDurationItem.valueOf("P2Y11M"),
494 IYearMonthDurationItem.valueOf("P3Y3M")));
495 }
496
497 @Test
498 @DisplayName("op:add-yearMonthDurations: overflow")
499 void testOpAddYearMonthDurationsOverflow() {
500 DateTimeFunctionException thrown = assertThrows(DateTimeFunctionException.class, () -> {
501 OperationFunctions.opAddYearMonthDurations(
502 IYearMonthDurationItem.valueOf("P" + Integer.MAX_VALUE + "Y"),
503 IYearMonthDurationItem.valueOf("P" + Integer.MAX_VALUE + "Y"));
504 });
505 assertThat(thrown)
506 .isExactlyInstanceOf(DateTimeFunctionException.class)
507 .returns(
508 DateTimeFunctionException.DURATION_OVERFLOW_UNDERFLOW_ERROR,
509 from(ex -> ex.getErrorCode().getCode()))
510 .cause()
511 .isExactlyInstanceOf(ArithmeticException.class);
512 }
513
514 @Test
515 @DisplayName("op:subtract-yearMonthDurations: known good")
516 void testOpSubtractYearMonthDurations() {
517 assertEquals(
518 IYearMonthDurationItem.valueOf("-P4M"),
519 OperationFunctions.opSubtractYearMonthDurations(
520 IYearMonthDurationItem.valueOf("P2Y11M"),
521 IYearMonthDurationItem.valueOf("P3Y3M")));
522 }
523
524 @Test
525 @DisplayName("op:subtract-yearMonthDurations: overflow")
526 void testOpSubtractYearMonthDurationsOverflow() {
527 DateTimeFunctionException thrown = assertThrows(DateTimeFunctionException.class, () -> {
528 OperationFunctions.opSubtractYearMonthDurations(
529 IYearMonthDurationItem.valueOf("-P" + Integer.MAX_VALUE + "Y"),
530 IYearMonthDurationItem.valueOf("P" + Integer.MAX_VALUE + "Y"));
531 });
532 assertThat(thrown)
533 .isExactlyInstanceOf(DateTimeFunctionException.class)
534 .returns(
535 DateTimeFunctionException.DURATION_OVERFLOW_UNDERFLOW_ERROR,
536 from(ex -> ex.getErrorCode().getCode()))
537 .cause()
538 .isExactlyInstanceOf(ArithmeticException.class);
539 }
540
541 @Test
542 @DisplayName("op:multiply-yearMonthDurations: known good")
543 void testOpMultiplyYearMonthDuration() {
544 assertAll(
545 () -> assertEquals(
546 IYearMonthDurationItem.valueOf("P6Y9M"),
547 OperationFunctions.opMultiplyYearMonthDuration(
548 IYearMonthDurationItem.valueOf("P2Y11M"),
549 IDecimalItem.valueOf("2.3"))),
550 () -> assertEquals(
551 IYearMonthDurationItem.valueOf("P0M"),
552 OperationFunctions.opMultiplyYearMonthDuration(
553 IYearMonthDurationItem.valueOf("P1Y"),
554 IDecimalItem.valueOf("0"))),
555 () -> assertEquals(
556 IYearMonthDurationItem.valueOf("-P2Y"),
557 OperationFunctions.opMultiplyYearMonthDuration(
558 IYearMonthDurationItem.valueOf("P1Y"),
559 IDecimalItem.valueOf("-2"))));
560 }
561
562 @Test
563 @DisplayName("op:multiply-yearMonthDurations: overflow")
564 void testOpMultiplyYearMonthDurationsOverflow() {
565 DateTimeFunctionException thrown = assertThrows(DateTimeFunctionException.class, () -> {
566 OperationFunctions.opMultiplyYearMonthDuration(
567 IYearMonthDurationItem.valueOf("P" + Integer.MAX_VALUE + "Y"),
568 IDecimalItem.valueOf("2.5"));
569 });
570 assertThat(thrown)
571 .isExactlyInstanceOf(DateTimeFunctionException.class)
572 .returns(
573 DateTimeFunctionException.DURATION_OVERFLOW_UNDERFLOW_ERROR,
574 from(ex -> ex.getErrorCode().getCode()))
575 .cause()
576 .isExactlyInstanceOf(CastFunctionException.class)
577 .returns(
578 CastFunctionException.INPUT_VALUE_TOO_LARGE,
579 from(ex -> ex instanceof CastFunctionException
580 ? ((CastFunctionException) ex).getErrorCode().getCode()
581 : null));
582 }
583
584 @Test
585 @DisplayName("op:divide-yearMonthDurations: known good")
586 void testOpDivideYearMonthDuration() {
587 assertEquals(
588 IYearMonthDurationItem.valueOf("P1Y11M"),
589 OperationFunctions.opDivideYearMonthDuration(
590 IYearMonthDurationItem.valueOf("P2Y11M"),
591 IDecimalItem.valueOf("1.5")));
592 }
593
594 @Test
595 @DisplayName("op:divide-yearMonthDuration-by-yearMonthDuration: known good")
596 void testOpDivideYearMonthDurationByYearMonthDuration() {
597 assertEquals(
598 IDecimalItem.valueOf("-2.5"),
599 OperationFunctions.opDivideYearMonthDurationByYearMonthDuration(
600 IYearMonthDurationItem.valueOf("P3Y4M"),
601 IYearMonthDurationItem.valueOf("-P1Y4M")));
602 }
603 }
604
605 @Nested
606 class DayTimeDuration {
607
608 @Test
609 @DisplayName("op:add-dayTimeDurations: known good")
610 void testOpAddDayTimeDurations() {
611 assertEquals(
612 IDayTimeDurationItem.valueOf("P8DT5M"),
613 OperationFunctions.opAddDayTimeDurations(
614 IDayTimeDurationItem.valueOf("P2DT12H5M"),
615 IDayTimeDurationItem.valueOf("P5DT12H")));
616 }
617
618 @Test
619 @DisplayName("op:add-dayTimeDurations: overflow")
620 void testOpAddDayTimeDurationsOverflow() {
621 DateTimeFunctionException thrown = assertThrows(DateTimeFunctionException.class, () -> {
622 OperationFunctions.opAddDayTimeDurations(
623
624 IDayTimeDurationItem.valueOf("PT" + (Long.MAX_VALUE - 807) + "S"),
625 IDayTimeDurationItem.valueOf("PT" + (Long.MAX_VALUE - 807) + "S"));
626 });
627 assertThat(thrown)
628 .isExactlyInstanceOf(DateTimeFunctionException.class)
629 .hasCauseExactlyInstanceOf(ArithmeticException.class)
630 .returns(
631 DateTimeFunctionException.DURATION_OVERFLOW_UNDERFLOW_ERROR,
632 from(ex -> ex.getErrorCode().getCode()));
633 }
634
635 @Test
636 @DisplayName("op:subtract-dayTimeDurations: known good")
637 void testOpSubtractDayTimeDurations() {
638 assertEquals(
639 IDayTimeDurationItem.valueOf("P1DT1H30M"),
640 OperationFunctions.opSubtractDayTimeDurations(
641 IDayTimeDurationItem.valueOf("P2DT12H"),
642 IDayTimeDurationItem.valueOf("P1DT10H30M")));
643 }
644
645 @Test
646 @DisplayName("op:subtract-dayTimeDurations: overflow")
647 void testOpSubtractDayTimeDurationsOverflow() {
648 DateTimeFunctionException thrown = assertThrows(DateTimeFunctionException.class, () -> {
649 OperationFunctions.opSubtractDayTimeDurations(
650 IDayTimeDurationItem.valueOf("-PT" + (Long.MAX_VALUE - 807) + "S"),
651 IDayTimeDurationItem.valueOf("PT" + (Long.MAX_VALUE - 807) + "S"));
652 });
653 assertThat(thrown)
654 .isExactlyInstanceOf(DateTimeFunctionException.class)
655 .hasCauseExactlyInstanceOf(ArithmeticException.class)
656 .returns(
657 DateTimeFunctionException.DURATION_OVERFLOW_UNDERFLOW_ERROR,
658 from(ex -> ex.getErrorCode().getCode()));
659 }
660
661 @Test
662 @DisplayName("op:multiply-dayTimeDuration: known good")
663 void testOpMultiplyDayTimeDuration() {
664 assertEquals(
665 IDayTimeDurationItem.valueOf("PT4H33M"),
666 OperationFunctions.opMultiplyDayTimeDuration(
667 IDayTimeDurationItem.valueOf("PT2H10M"),
668 IDecimalItem.valueOf("2.1")));
669 }
670
671 @Test
672 @DisplayName("op:multiply-dayTimeDuration: overflow")
673 void testOpMultiplyDayTimeDurationsOverflow() {
674 DateTimeFunctionException thrown = assertThrows(DateTimeFunctionException.class, () -> {
675 OperationFunctions.opMultiplyDayTimeDuration(
676 IDayTimeDurationItem.valueOf("PT" + Long.MAX_VALUE / 2 + "S"),
677 IDecimalItem.valueOf("5"));
678 });
679 assertThat(thrown)
680 .isExactlyInstanceOf(DateTimeFunctionException.class)
681 .returns(
682 DateTimeFunctionException.DURATION_OVERFLOW_UNDERFLOW_ERROR,
683 from(ex -> ex.getErrorCode().getCode()))
684 .cause()
685 .isExactlyInstanceOf(CastFunctionException.class)
686 .returns(
687 CastFunctionException.INPUT_VALUE_TOO_LARGE,
688 from(ex -> ex instanceof CastFunctionException
689 ? ((CastFunctionException) ex).getErrorCode().getCode()
690 : null));
691 }
692
693 @Test
694 @DisplayName("op:divide-dayTimeDuration: known good")
695 void testOpDivideDayTimeDuration() {
696 assertEquals(
697 IDayTimeDurationItem.valueOf("PT17H40M7S"),
698 OperationFunctions.opDivideDayTimeDuration(
699 IDayTimeDurationItem.valueOf("P1DT2H30M10.5S"),
700 IDecimalItem.valueOf("1.5")));
701 }
702
703 @Test
704 @DisplayName("op:divide-dayTimeDuration-by-dayTimeDuration: known good")
705 void testOpDivideDayTimeDurationByDayTimeDuration() {
706 assertAll(
707 () -> assertEquals(
708 IDecimalItem.valueOf("1.437834967320261"),
709 OperationFunctions.opDivideDayTimeDurationByDayTimeDuration(
710 IDayTimeDurationItem.valueOf("P2DT53M11S"),
711 IDayTimeDurationItem.valueOf("P1DT10H"))),
712 () -> assertEquals(
713 IDecimalItem.valueOf("175991.0"),
714 OperationFunctions.opDivideDayTimeDurationByDayTimeDuration(
715 IDayTimeDurationItem.valueOf("P2DT53M11S"),
716 IDayTimeDurationItem.valueOf("PT1S"))));
717 }
718 }
719 }
720 }
721
722 @Nested
723 @DisplayName("Functions and operators on dates and times")
724 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
725 class DateTime {
726 @Nested
727 @DisplayName("Functions and operators on dates and times")
728 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
729 class DateTimeOperators {
730 private Stream<Arguments> provideValuesDateTimeCompare() {
731 return Stream.of(
732 Arguments.of(
733 bool(true),
734 bool(false),
735 IDateTimeItem.valueOf("2002-04-02T12:00:00-01:00"),
736 IDateTimeItem.valueOf("2002-04-02T17:00:00+04:00")),
737 Arguments.of(
738 bool(true),
739 bool(false),
740 IDateTimeItem.valueOf("2002-04-02T12:00:00"),
741 IDateTimeItem.valueOf("2002-04-02T23:00:00+06:00")),
742 Arguments.of(
743 bool(false),
744 bool(true),
745 IDateTimeItem.valueOf("2002-04-02T12:00:00"),
746 IDateTimeItem.valueOf("2002-04-02T17:00:00")),
747 Arguments.of(
748 bool(true),
749 bool(false),
750 IDateTimeItem.valueOf("2002-04-02T12:00:00"),
751 IDateTimeItem.valueOf("2002-04-02T12:00:00")),
752 Arguments.of(
753 bool(true),
754 bool(false),
755 IDateTimeItem.valueOf("2002-04-02T23:00:00-04:00"),
756 IDateTimeItem.valueOf("2002-04-03T02:00:00-01:00")),
757 Arguments.of(
758 bool(true),
759 bool(false),
760 IDateTimeItem.valueOf("1999-12-31T24:00:00"),
761 IDateTimeItem.valueOf("2000-01-01T00:00:00")),
762 Arguments.of(
763 bool(false),
764 bool(false),
765 IDateTimeItem.valueOf("2005-04-04T24:00:00"),
766 IDateTimeItem.valueOf("2005-04-04T00:00:00")));
767 }
768
769 @ParameterizedTest
770 @DisplayName("op:dateTime-equal")
771 @MethodSource("provideValuesDateTimeCompare")
772 void testOpDateTimeEqual(
773 @NonNull IBooleanItem expectedEqual,
774 @SuppressWarnings("unused") @NonNull IBooleanItem expectedLessThan,
775 @NonNull IDateTimeItem arg1,
776 @NonNull IDateTimeItem arg2) {
777 DynamicContext dynamicContext = new DynamicContext();
778 dynamicContext.setImplicitTimeZone(IDayTimeDurationItem.valueOf("-PT5H"));
779 assertEquals(expectedEqual, OperationFunctions.opDateTimeEqual(arg1, arg2, dynamicContext));
780 }
781
782 @ParameterizedTest
783 @DisplayName("op:dateTime-less-than and op:dateTime-greater-than")
784 @MethodSource("provideValuesDateTimeCompare")
785 void testOpDateTimeLessGreaterThan(
786 @SuppressWarnings("unused") @NonNull IBooleanItem expectedEqual,
787 @NonNull IBooleanItem expectedLessThan,
788 @NonNull IDateTimeItem item1,
789 @NonNull IDateTimeItem item2) {
790 DynamicContext dynamicContext = new DynamicContext();
791 dynamicContext.setImplicitTimeZone(IDayTimeDurationItem.valueOf("-PT5H"));
792 assertAll(
793 () -> assertEquals(
794 expectedLessThan,
795 OperationFunctions.opDateTimeLessThan(item1, item2, dynamicContext)),
796 () -> assertEquals(
797 expectedLessThan,
798 OperationFunctions.opDateTimeGreaterThan(item2, item1, dynamicContext)));
799 }
800
801 private Stream<Arguments> provideValuesDateCompare() {
802 return Stream.of(
803 Arguments.of(
804 bool(false),
805 bool(false),
806 date("2004-12-25Z"),
807 date("2004-12-25+07:00")),
808 Arguments.of(
809 bool(true),
810 bool(false),
811 date("2004-12-25-12:00"),
812 date("2004-12-26+12:00")));
813 }
814
815 @ParameterizedTest
816 @DisplayName("op:date-equal")
817 @MethodSource("provideValuesDateCompare")
818 void testOpDateEqual(
819 @NonNull IBooleanItem expectedEqual,
820 @SuppressWarnings("unused") @NonNull IBooleanItem expectedLessThan,
821 @NonNull IDateItem arg1,
822 @NonNull IDateItem arg2) {
823 DynamicContext dynamicContext = new DynamicContext();
824 dynamicContext.setImplicitTimeZone(IDayTimeDurationItem.valueOf("-PT5H"));
825 assertEquals(expectedEqual, OperationFunctions.opDateEqual(arg1, arg2, dynamicContext));
826 }
827
828 @ParameterizedTest
829 @DisplayName("op:date-less-than and op:date-greater-than")
830 @MethodSource("provideValuesDateCompare")
831 void testOpDateLessGreaterThan(
832 @SuppressWarnings("unused") @NonNull IBooleanItem expectedEqual,
833 @NonNull IBooleanItem expectedLessThan,
834 @NonNull IDateItem item1,
835 @NonNull IDateItem item2) {
836 DynamicContext dynamicContext = new DynamicContext();
837 dynamicContext.setImplicitTimeZone(IDayTimeDurationItem.valueOf("-PT5H"));
838 assertAll(
839 () -> assertEquals(
840 expectedLessThan,
841 OperationFunctions.opDateLessThan(item1, item2, dynamicContext)),
842 () -> assertEquals(
843 expectedLessThan,
844 OperationFunctions.opDateGreaterThan(item2, item1, dynamicContext)));
845 }
846
847 private Stream<Arguments> provideValuesTimeCompare() {
848 return Stream.of(
849 Arguments.of(
850 bool(false),
851 bool(true),
852 time("08:00:00+09:00"),
853 time("17:00:00-06:00")),
854 Arguments.of(
855 bool(true),
856 bool(false),
857 time("21:30:00+10:30"),
858 time("06:00:00-05:00")),
859 Arguments.of(
860 bool(true),
861 bool(false),
862 time("24:00:00+01:00"),
863 time("00:00:00+01:00")),
864 Arguments.of(
865 bool(true),
866 bool(false),
867 time("12:00:00"),
868 time("23:00:00+06:00")),
869 Arguments.of(
870 bool(false),
871 bool(true),
872 time("11:00:00"),
873 time("17:00:00Z")),
874 Arguments.of(
875 bool(false),
876 bool(false),
877 time("23:59:59"),
878 time("24:00:00")));
879 }
880
881 @ParameterizedTest
882 @DisplayName("op:time-equal")
883 @MethodSource("provideValuesTimeCompare")
884 void testOpTimeEqual(
885 @NonNull IBooleanItem expectedEqual,
886 @SuppressWarnings("unused") @NonNull IBooleanItem expectedLessThan,
887 @NonNull ITimeItem arg1,
888 @NonNull ITimeItem arg2) {
889 DynamicContext dynamicContext = new DynamicContext();
890 dynamicContext.setImplicitTimeZone(IDayTimeDurationItem.valueOf("-PT5H"));
891 assertEquals(expectedEqual, OperationFunctions.opTimeEqual(arg1, arg2, dynamicContext));
892 }
893
894 @ParameterizedTest
895 @DisplayName("op:time-less-than and op:time-greater-than")
896 @MethodSource("provideValuesTimeCompare")
897 void testOpTimeLessGreaterThan(
898 @SuppressWarnings("unused") @NonNull IBooleanItem expectedEqual,
899 @NonNull IBooleanItem expectedLessThan,
900 @NonNull ITimeItem item1,
901 @NonNull ITimeItem item2) {
902 DynamicContext dynamicContext = new DynamicContext();
903 dynamicContext.setImplicitTimeZone(IDayTimeDurationItem.valueOf("-PT5H"));
904 assertAll(
905 () -> assertEquals(
906 expectedLessThan,
907 OperationFunctions.opTimeLessThan(item1, item2, dynamicContext)),
908 () -> assertEquals(
909 expectedLessThan,
910 OperationFunctions.opTimeGreaterThan(item2, item1, dynamicContext)));
911 }
912
913
914
915
916
917
918 }
919
920 @Nested
921 @DisplayName("Arithmetic operators on durations, dates and times")
922 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
923 class DateTimeArithmetic {
924 private Stream<Arguments> provideValuesSubtractDateTimes() {
925 return Stream.of(
926 Arguments.of(
927 dayTimeDuration("P337DT2H12M"),
928 dateTime("2000-10-30T06:12:00"),
929 dateTime("1999-11-28T09:00:00Z")));
930 }
931
932 @ParameterizedTest
933 @DisplayName("op:subtract-dateTimes")
934 @MethodSource("provideValuesSubtractDateTimes")
935 void testOpSubtractDateTimes(
936 @NonNull IDayTimeDurationItem expected,
937 @NonNull IDateTimeItem item1,
938 @NonNull IDateTimeItem item2) {
939 DynamicContext dynamicContext = new DynamicContext();
940 dynamicContext.setImplicitTimeZone(IDayTimeDurationItem.valueOf("-PT5H"));
941 assertEquals(expected, OperationFunctions.opSubtractDateTimes(item1, item2, dynamicContext));
942 }
943
944 private Stream<Arguments> provideValuesSubtractDates() {
945 return Stream.of(
946 Arguments.of(
947 dayTimeDuration("P337D"),
948 dayTimeDuration("PT0H"),
949 date("2000-10-30"),
950 date("1999-11-28")),
951 Arguments.of(
952 dayTimeDuration("P336DT19H"),
953 dayTimeDuration("PT5H"),
954 date("2000-10-30"),
955 date("1999-11-28Z")),
956 Arguments.of(
957 dayTimeDuration("P5DT7H"),
958 dayTimeDuration("PT5H"),
959 date("2000-10-15-05:00"),
960 date("2000-10-10+02:00")));
961 }
962
963 @ParameterizedTest
964 @DisplayName("op:subtract-dates")
965 @MethodSource("provideValuesSubtractDates")
966 void testOpSubtractDates(
967 @NonNull IDayTimeDurationItem expected,
968 @NonNull IDayTimeDurationItem offset,
969 @NonNull IDateItem item1,
970 @NonNull IDateItem item2) {
971 DynamicContext dynamicContext = new DynamicContext();
972 dynamicContext.setImplicitTimeZone(offset);
973 assertEquals(expected, OperationFunctions.opSubtractDates(item1, item2, dynamicContext));
974 }
975
976 private Stream<Arguments> provideValuesSubtractTimes() {
977 return Stream.of(
978 Arguments.of(
979 dayTimeDuration("PT2H12M"),
980 dayTimeDuration("-PT5H"),
981 time("11:12:00Z"),
982 time("04:00:00")),
983 Arguments.of(
984 dayTimeDuration("PT0S"),
985 dayTimeDuration("-PT5H"),
986 time("11:00:00-05:00"),
987 time("21:30:00+05:30")),
988 Arguments.of(
989 dayTimeDuration("P1D"),
990 dayTimeDuration("-PT5H"),
991 time("17:00:00-06:00"),
992 time("08:00:00+09:00")),
993 Arguments.of(
994 dayTimeDuration("-PT23H59M59S"),
995 dayTimeDuration("-PT5H"),
996 time("24:00:00"),
997 time("23:59:59")));
998 }
999
1000 @ParameterizedTest
1001 @DisplayName("op:subtract-times")
1002 @MethodSource("provideValuesSubtractTimes")
1003 void testOpSubtractTimes(
1004 @NonNull IDayTimeDurationItem expected,
1005 @NonNull IDayTimeDurationItem offset,
1006 @NonNull ITimeItem item1,
1007 @NonNull ITimeItem item2) {
1008 DynamicContext dynamicContext = new DynamicContext();
1009 dynamicContext.setImplicitTimeZone(offset);
1010 assertEquals(expected, OperationFunctions.opSubtractTimes(item1, item2, dynamicContext));
1011 }
1012
1013 private Stream<Arguments> provideValuesAddYearMonthDurationToDateTime() {
1014 return Stream.of(
1015 Arguments.of(
1016 dateTime("2001-12-30T11:12:00"),
1017 dateTime("2000-10-30T11:12:00"),
1018 yearMonthDuration("P1Y2M")));
1019 }
1020
1021 @ParameterizedTest
1022 @DisplayName("op:add-yearMonthDuration-to-dateTime")
1023 @MethodSource("provideValuesAddYearMonthDurationToDateTime")
1024 void testOpAddYearMonthDurationToDateTime(
1025 @NonNull IDateTimeItem expected,
1026 @NonNull IDateTimeItem item1,
1027 @NonNull IYearMonthDurationItem item2) {
1028 assertEquals(expected, OperationFunctions.opAddYearMonthDurationToDateTime(item1, item2));
1029 }
1030
1031 private Stream<Arguments> provideValuesAddDayTimeDurationToDateTime() {
1032 return Stream.of(
1033 Arguments.of(
1034 dateTime("2000-11-02T12:27:00"),
1035 dateTime("2000-10-30T11:12:00"),
1036 dayTimeDuration("P3DT1H15M")));
1037 }
1038
1039 @ParameterizedTest
1040 @DisplayName("op:add-dayTimeDuration-to-dateTime")
1041 @MethodSource("provideValuesAddDayTimeDurationToDateTime")
1042 void testOpAddDayTimeDurationToDateTime(
1043 @NonNull IDateTimeItem expected,
1044 @NonNull IDateTimeItem item1,
1045 @NonNull IDayTimeDurationItem item2) {
1046 assertEquals(expected, OperationFunctions.opAddDayTimeDurationToDateTime(item1, item2));
1047 }
1048
1049 private Stream<Arguments> provideValuesSubtractYearMonthDurationFromDateTime() {
1050 return Stream.of(
1051 Arguments.of(
1052 dateTime("1999-08-30T11:12:00"),
1053 dateTime("2000-10-30T11:12:00"),
1054 yearMonthDuration("P1Y2M")));
1055 }
1056
1057 @ParameterizedTest
1058 @DisplayName("op:subtract-yearMonthDuration-from-dateTime")
1059 @MethodSource("provideValuesSubtractYearMonthDurationFromDateTime")
1060 void testOpSubtractYearMonthDurationFromDateTime(
1061 @NonNull IDateTimeItem expected,
1062 @NonNull IDateTimeItem item1,
1063 @NonNull IYearMonthDurationItem item2) {
1064 assertEquals(expected, OperationFunctions.opSubtractYearMonthDurationFromDateTime(item1, item2));
1065 }
1066
1067 private Stream<Arguments> provideValuesSubtractDayTimeDurationFromDateTime() {
1068 return Stream.of(
1069 Arguments.of(
1070 dateTime("2000-10-27T09:57:00"),
1071 dateTime("2000-10-30T11:12:00"),
1072 dayTimeDuration("P3DT1H15M")));
1073 }
1074
1075 @ParameterizedTest
1076 @DisplayName("op:subtract-dayTimeDuration-from-dateTime")
1077 @MethodSource("provideValuesSubtractDayTimeDurationFromDateTime")
1078 void testOpSubtractDayTimeDurationFromDateTime(
1079 @NonNull IDateTimeItem expected,
1080 @NonNull IDateTimeItem item1,
1081 @NonNull IDayTimeDurationItem item2) {
1082 assertEquals(expected, OperationFunctions.opSubtractDayTimeDurationFromDateTime(item1, item2));
1083 }
1084
1085
1086
1087
1088
1089
1090 private Stream<Arguments> provideValuesAddYearMonthDurationToDate() {
1091 return Stream.of(
1092 Arguments.of(
1093 date("2001-12-30"),
1094 date("2000-10-30"),
1095 yearMonthDuration("P1Y2M")));
1096 }
1097
1098 @ParameterizedTest
1099 @DisplayName("op:add-yearMonthDuration-to-date")
1100 @MethodSource("provideValuesAddYearMonthDurationToDate")
1101 void testOpAddYearMonthDurationToDate(
1102 @NonNull IDateItem expected,
1103 @NonNull IDateItem item1,
1104 @NonNull IYearMonthDurationItem item2) {
1105 assertEquals(expected, OperationFunctions.opAddYearMonthDurationToDate(item1, item2));
1106 }
1107
1108 private Stream<Arguments> provideValuesAddDayTimeDurationToDate() {
1109 return Stream.of(
1110 Arguments.of(
1111 date("2004-11-01Z"),
1112 date("2004-10-30Z"),
1113 dayTimeDuration("P2DT2H30M0S")));
1114 }
1115
1116 @ParameterizedTest
1117 @DisplayName("op:add-dayTimeDuration-to-date")
1118 @MethodSource("provideValuesAddDayTimeDurationToDate")
1119 void testOpAddDayTimeDurationToDate(
1120 @NonNull IDateItem expected,
1121 @NonNull IDateItem item1,
1122 @NonNull IDayTimeDurationItem item2) {
1123 assertEquals(expected, OperationFunctions.opAddDayTimeDurationToDate(item1, item2));
1124 }
1125
1126 private Stream<Arguments> provideValuesSubtractYearMonthDurationFromDate() {
1127 return Stream.of(
1128 Arguments.of(
1129 date("1999-08-30"),
1130 date("2000-10-30"),
1131 yearMonthDuration("P1Y2M")),
1132 Arguments.of(
1133 date("1999-02-28Z"),
1134 date("2000-02-29Z"),
1135 yearMonthDuration("P1Y")),
1136 Arguments.of(
1137 date("1999-09-30-05:00"),
1138 date("2000-10-31-05:00"),
1139 yearMonthDuration("P1Y1M")));
1140 }
1141
1142 @ParameterizedTest
1143 @DisplayName("op:subtract-yearMonthDuration-from-date")
1144 @MethodSource("provideValuesSubtractYearMonthDurationFromDate")
1145 void testOpSubtractYearMonthDurationFromDate(
1146 @NonNull IDateItem expected,
1147 @NonNull IDateItem item1,
1148 @NonNull IYearMonthDurationItem item2) {
1149 assertEquals(expected, OperationFunctions.opSubtractYearMonthDurationFromDate(item1, item2));
1150 }
1151
1152 private Stream<Arguments> provideValuesSubtractDayTimeDurationFromDate() {
1153 return Stream.of(
1154 Arguments.of(
1155 date("2000-10-26"),
1156 date("2000-10-30"),
1157 dayTimeDuration("P3DT1H15M")));
1158 }
1159
1160 @ParameterizedTest
1161 @DisplayName("op:subtract-dayTimeDuration-from-date")
1162 @MethodSource("provideValuesSubtractDayTimeDurationFromDate")
1163 void testOpSubtractDayTimeDurationFromDate(
1164 @NonNull IDateItem expected,
1165 @NonNull IDateItem item1,
1166 @NonNull IDayTimeDurationItem item2) {
1167 assertEquals(expected, OperationFunctions.opSubtractDayTimeDurationFromDate(item1, item2));
1168 }
1169
1170 private Stream<Arguments> provideValuesAddDayTimeDurationToTime() {
1171 return Stream.of(
1172 Arguments.of(
1173 time("12:27:00"),
1174 time("11:12:00"),
1175 dayTimeDuration("P3DT1H15M")),
1176 Arguments.of(
1177 time("02:27:00+03:00"),
1178 time("23:12:00+03:00"),
1179 dayTimeDuration("P1DT3H15M")));
1180 }
1181
1182 @ParameterizedTest
1183 @DisplayName("op:add-dayTimeDuration-to-time")
1184 @MethodSource("provideValuesAddDayTimeDurationToTime")
1185 void testOpAddDayTimeDurationToTime(
1186 @NonNull ITimeItem expected,
1187 @NonNull ITimeItem item1,
1188 @NonNull IDayTimeDurationItem item2) {
1189 assertEquals(expected, OperationFunctions.opAddDayTimeDurationToTime(item1, item2));
1190 }
1191
1192 private Stream<Arguments> provideValuesSubtractDayTimeDurationFromTime() {
1193 return Stream.of(
1194 Arguments.of(
1195 time("09:57:00"),
1196 time("11:12:00"),
1197 dayTimeDuration("P3DT1H15M")),
1198 Arguments.of(
1199 time("22:10:00-05:00"),
1200 time("08:20:00-05:00"),
1201 dayTimeDuration("P23DT10H10M")));
1202 }
1203
1204 @ParameterizedTest
1205 @DisplayName("op:subtract-dayTimeDuration-from-time")
1206 @MethodSource("provideValuesSubtractDayTimeDurationFromTime")
1207 void testOpSubtractDayTimeDurationFromTime(
1208 @NonNull ITimeItem expected,
1209 @NonNull ITimeItem item1,
1210 @NonNull IDayTimeDurationItem item2) {
1211 assertEquals(expected, OperationFunctions.opSubtractDayTimeDurationFromTime(item1, item2));
1212 }
1213 }
1214 }
1215
1216 @Nested
1217 @DisplayName("Functions and operators related to QNames")
1218 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
1219 class QName {
1220
1221 }
1222
1223 @Nested
1224 @DisplayName("Operators on base64Binary and hexBinary")
1225 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
1226 class Binary {
1227 @Nested
1228 @DisplayName("Comparisons of base64Binary and hexBinary values")
1229 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
1230 class BinaryOperators {
1231
1232
1233
1234
1235
1236
1237 }
1238 }
1239 }