This is an automated email from the ASF dual-hosted git repository.
sunlan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new 95850f840c Add `DatumDependentDurationTest`
95850f840c is described below
commit 95850f840c816b38bbe9747dd6664ff4db52d425
Author: Daniel Sun <[email protected]>
AuthorDate: Sun Feb 1 18:21:21 2026 +0900
Add `DatumDependentDurationTest`
---
.../groovy/time/DatumDependentDurationTest.groovy | 746 +++++++++++++++++++++
1 file changed, 746 insertions(+)
diff --git a/src/test/groovy/groovy/time/DatumDependentDurationTest.groovy
b/src/test/groovy/groovy/time/DatumDependentDurationTest.groovy
new file mode 100644
index 0000000000..fb703429b8
--- /dev/null
+++ b/src/test/groovy/groovy/time/DatumDependentDurationTest.groovy
@@ -0,0 +1,746 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.time
+
+import org.junit.jupiter.api.Test
+
+import static org.junit.jupiter.api.Assertions.*
+
+/**
+ * Tests for DatumDependentDuration class.
+ * DatumDependentDuration represents durations whose length in milliseconds
+ * cannot be determined without knowing the datum point (e.g., months, years).
+ */
+class DatumDependentDurationTest {
+
+ // ===== Constructor and Getter Tests =====
+
+ @Test
+ void testConstructorAndGetters() {
+ def duration = new DatumDependentDuration(2, 3, 4, 5, 6, 7, 8)
+
+ assertEquals 2, duration.getYears()
+ assertEquals 3, duration.getMonths()
+ assertEquals 4, duration.getDays()
+ assertEquals 5, duration.getHours()
+ assertEquals 6, duration.getMinutes()
+ assertEquals 7, duration.getSeconds()
+ assertEquals 8, duration.getMillis()
+ }
+
+ @Test
+ void testConstructorWithZeroValues() {
+ def duration = new DatumDependentDuration(0, 0, 0, 0, 0, 0, 0)
+
+ assertEquals 0, duration.getYears()
+ assertEquals 0, duration.getMonths()
+ assertEquals 0, duration.getDays()
+ assertEquals 0, duration.getHours()
+ assertEquals 0, duration.getMinutes()
+ assertEquals 0, duration.getSeconds()
+ assertEquals 0, duration.getMillis()
+ }
+
+ @Test
+ void testConstructorWithNegativeValues() {
+ def duration = new DatumDependentDuration(-1, -2, -3, -4, -5, -6, -7)
+
+ assertEquals(-1, duration.getYears())
+ assertEquals(-2, duration.getMonths())
+ assertEquals(-3, duration.getDays())
+ assertEquals(-4, duration.getHours())
+ assertEquals(-5, duration.getMinutes())
+ assertEquals(-6, duration.getSeconds())
+ assertEquals(-7, duration.getMillis())
+ }
+
+ // ===== Plus DatumDependentDuration Tests =====
+
+ @Test
+ void testPlusDatumDependentDuration() {
+ def duration1 = new DatumDependentDuration(1, 2, 3, 4, 5, 6, 7)
+ def duration2 = new DatumDependentDuration(1, 1, 1, 1, 1, 1, 1)
+
+ def result = duration1.plus(duration2)
+
+ assertEquals 2, result.getYears()
+ assertEquals 3, result.getMonths()
+ assertEquals 4, result.getDays()
+ assertEquals 5, result.getHours()
+ assertEquals 6, result.getMinutes()
+ assertEquals 7, result.getSeconds()
+ assertEquals 8, result.getMillis()
+ }
+
+ @Test
+ void testPlusDatumDependentDurationWithZero() {
+ def duration1 = new DatumDependentDuration(1, 2, 3, 4, 5, 6, 7)
+ def zeroDuration = new DatumDependentDuration(0, 0, 0, 0, 0, 0, 0)
+
+ def result = duration1.plus(zeroDuration)
+
+ assertEquals 1, result.getYears()
+ assertEquals 2, result.getMonths()
+ assertEquals 3, result.getDays()
+ assertEquals 4, result.getHours()
+ assertEquals 5, result.getMinutes()
+ assertEquals 6, result.getSeconds()
+ assertEquals 7, result.getMillis()
+ }
+
+ @Test
+ void testPlusDatumDependentDurationWithNegative() {
+ def duration1 = new DatumDependentDuration(5, 6, 7, 8, 9, 10, 11)
+ def duration2 = new DatumDependentDuration(-2, -3, -4, -5, -6, -7, -8)
+
+ def result = duration1.plus(duration2)
+
+ assertEquals 3, result.getYears()
+ assertEquals 3, result.getMonths()
+ assertEquals 3, result.getDays()
+ assertEquals 3, result.getHours()
+ assertEquals 3, result.getMinutes()
+ assertEquals 3, result.getSeconds()
+ assertEquals 3, result.getMillis()
+ }
+
+ // ===== Plus TimeDatumDependentDuration Tests =====
+
+ @Test
+ void testPlusTimeDatumDependentDuration() {
+ def datumDuration = new DatumDependentDuration(1, 2, 3, 4, 5, 6, 7)
+ def timeDatumDuration = new TimeDatumDependentDuration(2, 3, 4, 5, 6,
7, 8)
+
+ def result = datumDuration.plus(timeDatumDuration)
+
+ assertEquals 3, result.getYears()
+ assertEquals 5, result.getMonths()
+ assertEquals 7, result.getDays()
+ assertEquals 9, result.getHours()
+ assertEquals 11, result.getMinutes()
+ assertEquals 13, result.getSeconds()
+ assertEquals 15, result.getMillis()
+ }
+
+ // ===== Plus Duration Tests =====
+
+ @Test
+ void testPlusDuration() {
+ def datumDuration = new DatumDependentDuration(1, 2, 3, 4, 5, 6, 7)
+ def duration = new Duration(10, 11, 12, 13, 14)
+
+ def result = datumDuration.plus(duration)
+
+ assertEquals 1, result.getYears()
+ assertEquals 2, result.getMonths()
+ assertEquals 13, result.getDays()
+ assertEquals 15, result.getHours()
+ assertEquals 17, result.getMinutes()
+ assertEquals 19, result.getSeconds()
+ assertEquals 21, result.getMillis()
+ }
+
+ @Test
+ void testPlusDurationWithZeroYearsAndMonths() {
+ def datumDuration = new DatumDependentDuration(0, 0, 5, 6, 7, 8, 9)
+ def duration = new Duration(1, 2, 3, 4, 5)
+
+ def result = datumDuration.plus(duration)
+
+ assertEquals 0, result.getYears()
+ assertEquals 0, result.getMonths()
+ assertEquals 6, result.getDays()
+ assertEquals 8, result.getHours()
+ assertEquals 10, result.getMinutes()
+ assertEquals 12, result.getSeconds()
+ assertEquals 14, result.getMillis()
+ }
+
+ // ===== Plus TimeDuration Tests =====
+
+ @Test
+ void testPlusTimeDuration() {
+ def datumDuration = new DatumDependentDuration(1, 2, 3, 4, 5, 6, 7)
+ def timeDuration = new TimeDuration(10, 11, 12, 13, 14)
+
+ def result = datumDuration.plus(timeDuration)
+
+ // TimeDuration.plus(DatumDependentDuration) returns
TimeDatumDependentDuration
+ assertTrue result instanceof DatumDependentDuration
+ assertEquals 1, result.getYears()
+ assertEquals 2, result.getMonths()
+ assertEquals 13, result.getDays()
+ assertEquals 15, result.getHours()
+ assertEquals 17, result.getMinutes()
+ assertEquals 19, result.getSeconds()
+ assertEquals 21, result.getMillis()
+ }
+
+ // ===== Minus DatumDependentDuration Tests =====
+
+ @Test
+ void testMinusDatumDependentDuration() {
+ def duration1 = new DatumDependentDuration(5, 6, 7, 8, 9, 10, 11)
+ def duration2 = new DatumDependentDuration(1, 2, 3, 4, 5, 6, 7)
+
+ def result = duration1.minus(duration2)
+
+ assertEquals 4, result.getYears()
+ assertEquals 4, result.getMonths()
+ assertEquals 4, result.getDays()
+ assertEquals 4, result.getHours()
+ assertEquals 4, result.getMinutes()
+ assertEquals 4, result.getSeconds()
+ assertEquals 4, result.getMillis()
+ }
+
+ @Test
+ void testMinusDatumDependentDurationResultingInNegative() {
+ def duration1 = new DatumDependentDuration(1, 2, 3, 4, 5, 6, 7)
+ def duration2 = new DatumDependentDuration(5, 6, 7, 8, 9, 10, 11)
+
+ def result = duration1.minus(duration2)
+
+ assertEquals(-4, result.getYears())
+ assertEquals(-4, result.getMonths())
+ assertEquals(-4, result.getDays())
+ assertEquals(-4, result.getHours())
+ assertEquals(-4, result.getMinutes())
+ assertEquals(-4, result.getSeconds())
+ assertEquals(-4, result.getMillis())
+ }
+
+ @Test
+ void testMinusDatumDependentDurationSameValues() {
+ def duration1 = new DatumDependentDuration(1, 2, 3, 4, 5, 6, 7)
+ def duration2 = new DatumDependentDuration(1, 2, 3, 4, 5, 6, 7)
+
+ def result = duration1.minus(duration2)
+
+ assertEquals 0, result.getYears()
+ assertEquals 0, result.getMonths()
+ assertEquals 0, result.getDays()
+ assertEquals 0, result.getHours()
+ assertEquals 0, result.getMinutes()
+ assertEquals 0, result.getSeconds()
+ assertEquals 0, result.getMillis()
+ }
+
+ // ===== Minus Duration Tests =====
+
+ @Test
+ void testMinusDuration() {
+ def datumDuration = new DatumDependentDuration(1, 2, 10, 11, 12, 13,
14)
+ def duration = new Duration(3, 4, 5, 6, 7)
+
+ def result = datumDuration.minus(duration)
+
+ assertEquals 1, result.getYears()
+ assertEquals 2, result.getMonths()
+ assertEquals 7, result.getDays()
+ assertEquals 7, result.getHours()
+ assertEquals 7, result.getMinutes()
+ assertEquals 7, result.getSeconds()
+ assertEquals 7, result.getMillis()
+ }
+
+ @Test
+ void testMinusDurationPreservesYearsAndMonths() {
+ def datumDuration = new DatumDependentDuration(5, 6, 10, 10, 10, 10,
10)
+ def duration = new Duration(5, 5, 5, 5, 5)
+
+ def result = datumDuration.minus(duration)
+
+ assertEquals 5, result.getYears()
+ assertEquals 6, result.getMonths()
+ assertEquals 5, result.getDays()
+ assertEquals 5, result.getHours()
+ assertEquals 5, result.getMinutes()
+ assertEquals 5, result.getSeconds()
+ assertEquals 5, result.getMillis()
+ }
+
+ // ===== toMilliseconds Tests =====
+
+ @Test
+ void testToMillisecondsWithOnlyDays() {
+ def duration = new DatumDependentDuration(0, 0, 1, 0, 0, 0, 0)
+ def expectedMillis = 24L * 60 * 60 * 1000
+
+ assertEquals expectedMillis, duration.toMilliseconds()
+ }
+
+ @Test
+ void testToMillisecondsWithOnlyHours() {
+ def duration = new DatumDependentDuration(0, 0, 0, 1, 0, 0, 0)
+ def expectedMillis = 60L * 60 * 1000
+
+ assertEquals expectedMillis, duration.toMilliseconds()
+ }
+
+ @Test
+ void testToMillisecondsWithOnlyMinutes() {
+ def duration = new DatumDependentDuration(0, 0, 0, 0, 1, 0, 0)
+ def expectedMillis = 60L * 1000
+
+ assertEquals expectedMillis, duration.toMilliseconds()
+ }
+
+ @Test
+ void testToMillisecondsWithOnlySeconds() {
+ def duration = new DatumDependentDuration(0, 0, 0, 0, 0, 1, 0)
+ def expectedMillis = 1000L
+
+ assertEquals expectedMillis, duration.toMilliseconds()
+ }
+
+ @Test
+ void testToMillisecondsWithOnlyMillis() {
+ def duration = new DatumDependentDuration(0, 0, 0, 0, 0, 0, 500)
+
+ assertEquals 500L, duration.toMilliseconds()
+ }
+
+ @Test
+ void testToMillisecondsZero() {
+ def duration = new DatumDependentDuration(0, 0, 0, 0, 0, 0, 0)
+
+ assertEquals 0L, duration.toMilliseconds()
+ }
+
+ // ===== getAgo Tests =====
+
+ @Test
+ void testGetAgo() {
+ def duration = new DatumDependentDuration(1, 2, 3, 4, 5, 6, 7)
+ def before = duration.getAgo()
+
+ def expected = Calendar.getInstance()
+ expected.add(Calendar.YEAR, -1)
+ expected.add(Calendar.MONTH, -2)
+ expected.add(Calendar.DAY_OF_YEAR, -3)
+ expected.add(Calendar.HOUR_OF_DAY, -4)
+ expected.add(Calendar.MINUTE, -5)
+ expected.add(Calendar.SECOND, -6)
+ expected.add(Calendar.MILLISECOND, -7)
+ expected.set(Calendar.HOUR_OF_DAY, 0)
+ expected.set(Calendar.MINUTE, 0)
+ expected.set(Calendar.SECOND, 0)
+ expected.set(Calendar.MILLISECOND, 0)
+
+ assertEquals expected.getTimeInMillis(), before.getTime()
+ }
+
+ @Test
+ void testGetAgoWithZeroDuration() {
+ def duration = new DatumDependentDuration(0, 0, 0, 0, 0, 0, 0)
+ def before = duration.getAgo()
+
+ def expected = Calendar.getInstance()
+ expected.set(Calendar.HOUR_OF_DAY, 0)
+ expected.set(Calendar.MINUTE, 0)
+ expected.set(Calendar.SECOND, 0)
+ expected.set(Calendar.MILLISECOND, 0)
+
+ assertEquals expected.getTimeInMillis(), before.getTime()
+ }
+
+ @Test
+ void testGetAgoZerosOutTime() {
+ def duration = new DatumDependentDuration(0, 0, 1, 0, 0, 0, 0)
+ def before = duration.getAgo()
+
+ def cal = Calendar.getInstance()
+ cal.setTime(before)
+
+ assertEquals 0, cal.get(Calendar.HOUR_OF_DAY)
+ assertEquals 0, cal.get(Calendar.MINUTE)
+ assertEquals 0, cal.get(Calendar.SECOND)
+ assertEquals 0, cal.get(Calendar.MILLISECOND)
+ }
+
+ // ===== getFrom().getNow() Tests =====
+
+ @Test
+ void testGetFromNow() {
+ def duration = new DatumDependentDuration(1, 2, 3, 4, 5, 6, 7)
+ def future = duration.getFrom().getNow()
+
+ def expected = Calendar.getInstance()
+ expected.add(Calendar.YEAR, 1)
+ expected.add(Calendar.MONTH, 2)
+ expected.add(Calendar.DAY_OF_YEAR, 3)
+ expected.add(Calendar.HOUR_OF_DAY, 4)
+ expected.add(Calendar.MINUTE, 5)
+ expected.add(Calendar.SECOND, 6)
+ expected.add(Calendar.MILLISECOND, 7)
+ expected.set(Calendar.HOUR_OF_DAY, 0)
+ expected.set(Calendar.MINUTE, 0)
+ expected.set(Calendar.SECOND, 0)
+ expected.set(Calendar.MILLISECOND, 0)
+
+ assertEquals expected.getTimeInMillis(), future.getTime()
+ }
+
+ @Test
+ void testGetFromNowWithZeroDuration() {
+ def duration = new DatumDependentDuration(0, 0, 0, 0, 0, 0, 0)
+ def future = duration.getFrom().getNow()
+
+ def expected = Calendar.getInstance()
+ expected.set(Calendar.HOUR_OF_DAY, 0)
+ expected.set(Calendar.MINUTE, 0)
+ expected.set(Calendar.SECOND, 0)
+ expected.set(Calendar.MILLISECOND, 0)
+
+ assertEquals expected.getTimeInMillis(), future.getTime()
+ }
+
+ @Test
+ void testGetFromNowZerosOutTime() {
+ def duration = new DatumDependentDuration(0, 0, 1, 0, 0, 0, 0)
+ def future = duration.getFrom().getNow()
+
+ def cal = Calendar.getInstance()
+ cal.setTime(future)
+
+ assertEquals 0, cal.get(Calendar.HOUR_OF_DAY)
+ assertEquals 0, cal.get(Calendar.MINUTE)
+ assertEquals 0, cal.get(Calendar.SECOND)
+ assertEquals 0, cal.get(Calendar.MILLISECOND)
+ }
+
+ @Test
+ void testGetFromToday() {
+ def duration = new DatumDependentDuration(0, 1, 0, 0, 0, 0, 0)
+ def fromObj = duration.getFrom()
+
+ // getToday() should return the same as getNow()
+ assertEquals fromObj.getNow(), fromObj.getToday()
+ }
+
+ // ===== TimeCategory Integration Tests =====
+
+ @Test
+ void testTimeCategoryYearsCreation() {
+ use(TimeCategory) {
+ def oneYear = 1.year
+ assertTrue oneYear instanceof DatumDependentDuration
+ assertEquals 1, oneYear.getYears()
+ assertEquals 0, oneYear.getMonths()
+
+ def twoYears = 2.years
+ assertEquals 2, twoYears.getYears()
+ }
+ }
+
+ @Test
+ void testTimeCategoryMonthsCreation() {
+ use(TimeCategory) {
+ def oneMonth = 1.month
+ assertTrue oneMonth instanceof DatumDependentDuration
+ assertEquals 0, oneMonth.getYears()
+ assertEquals 1, oneMonth.getMonths()
+
+ def threeMonths = 3.months
+ assertEquals 3, threeMonths.getMonths()
+ }
+ }
+
+ @Test
+ void testTimeCategoryMixedDuration() {
+ use(TimeCategory) {
+ def mixed = 1.year + 2.months + 3.days
+ assertTrue mixed instanceof DatumDependentDuration
+ assertEquals 1, mixed.getYears()
+ assertEquals 2, mixed.getMonths()
+ assertEquals 3, mixed.getDays()
+ }
+ }
+
+ @Test
+ void testTimeCategoryAgo() {
+ use(TimeCategory) {
+ def now = Calendar.getInstance()
+ def oneMonthAgo = 1.month.ago
+
+ now.add(Calendar.MONTH, -1)
+ now.set(Calendar.HOUR_OF_DAY, 0)
+ now.set(Calendar.MINUTE, 0)
+ now.set(Calendar.SECOND, 0)
+ now.set(Calendar.MILLISECOND, 0)
+
+ assertEquals now.getTimeInMillis(), oneMonthAgo.getTime()
+ }
+ }
+
+ @Test
+ void testTimeCategoryFromNow() {
+ use(TimeCategory) {
+ def expected = Calendar.getInstance()
+ expected.add(Calendar.YEAR, 1)
+ expected.set(Calendar.HOUR_OF_DAY, 0)
+ expected.set(Calendar.MINUTE, 0)
+ expected.set(Calendar.SECOND, 0)
+ expected.set(Calendar.MILLISECOND, 0)
+
+ def oneYearFromNow = 1.year.from.now
+
+ assertEquals expected.getTimeInMillis(), oneYearFromNow.getTime()
+ }
+ }
+
+ // ===== Date Arithmetic Tests =====
+
+ @Test
+ void testPlusDate() {
+ def duration = new DatumDependentDuration(1, 0, 0, 0, 0, 0, 0)
+ def date = new Date(100, 0, 1, 0, 0, 0) // Jan 1, 2000
+
+ def result = duration.plus(date)
+
+ def expected = Calendar.getInstance()
+ expected.setTime(date)
+ expected.add(Calendar.YEAR, 1)
+
+ assertEquals expected.getTime(), result
+ }
+
+ @Test
+ void testPlusDateWithMonths() {
+ def duration = new DatumDependentDuration(0, 1, 0, 0, 0, 0, 0)
+ def date = new Date(100, 0, 1, 0, 0, 0) // Jan 1, 2000
+
+ def result = duration.plus(date)
+
+ def expected = new Date(100, 1, 1, 0, 0, 0) // Feb 1, 2000
+
+ assertEquals expected, result
+ }
+
+ @Test
+ void testPlusDateWithAllFields() {
+ def duration = new DatumDependentDuration(1, 2, 3, 4, 5, 6, 7)
+ def date = new Date(100, 0, 1, 0, 0, 0)
+
+ def result = duration.plus(date)
+
+ def expected = Calendar.getInstance()
+ expected.setTime(date)
+ expected.add(Calendar.YEAR, 1)
+ expected.add(Calendar.MONTH, 2)
+ expected.add(Calendar.DAY_OF_YEAR, 3)
+ expected.add(Calendar.HOUR_OF_DAY, 4)
+ expected.add(Calendar.MINUTE, 5)
+ expected.add(Calendar.SECOND, 6)
+ expected.add(Calendar.MILLISECOND, 7)
+
+ assertEquals expected.getTime(), result
+ }
+
+ // ===== toString Tests =====
+
+ @Test
+ void testToStringWithAllFields() {
+ def duration = new DatumDependentDuration(1, 2, 3, 4, 5, 6, 7)
+ def result = duration.toString()
+
+ assertTrue result.contains("1 years")
+ assertTrue result.contains("2 months")
+ assertTrue result.contains("3 days")
+ assertTrue result.contains("4 hours")
+ assertTrue result.contains("5 minutes")
+ assertTrue result.contains("seconds")
+ }
+
+ @Test
+ void testToStringWithZeroDuration() {
+ def duration = new DatumDependentDuration(0, 0, 0, 0, 0, 0, 0)
+
+ assertEquals "0", duration.toString()
+ }
+
+ @Test
+ void testToStringWithOnlyYears() {
+ def duration = new DatumDependentDuration(2, 0, 0, 0, 0, 0, 0)
+
+ assertEquals "2 years", duration.toString()
+ }
+
+ @Test
+ void testToStringWithOnlyMonths() {
+ def duration = new DatumDependentDuration(0, 3, 0, 0, 0, 0, 0)
+
+ assertEquals "3 months", duration.toString()
+ }
+
+ @Test
+ void testToStringWithSecondsAndMillis() {
+ def duration = new DatumDependentDuration(0, 0, 0, 0, 0, 5, 12)
+
+ assertEquals "5.012 seconds", duration.toString()
+ }
+
+ @Test
+ void testToStringWithOnlyMillis() {
+ def duration = new DatumDependentDuration(0, 0, 0, 0, 0, 0, 500)
+
+ assertEquals "0.500 seconds", duration.toString()
+ }
+
+ // ===== Comparison Tests =====
+
+ @Test
+ void testCompareTo() {
+ use(TimeCategory) {
+ def oneMonth = 1.month
+ def twoMonths = 2.months
+
+ assertTrue oneMonth < twoMonths
+ assertTrue twoMonths > oneMonth
+ }
+ }
+
+ @Test
+ void testCompareToEqual() {
+ use(TimeCategory) {
+ def oneYear = 1.year
+ def twelveMonths = 12.months
+
+ assertEquals 0, oneYear.compareTo(twelveMonths)
+ }
+ }
+
+ @Test
+ void testCompareToWithDifferentTypes() {
+ use(TimeCategory) {
+ def oneMonth = 1.month
+ def oneDay = 1.day
+
+ assertTrue oneMonth > oneDay
+ }
+ }
+
+ // ===== Edge Cases =====
+
+ @Test
+ void testLeapYearHandling() {
+ use(TimeCategory) {
+ // Feb 29, 2000 (leap year)
+ def leapYearDate = new Date(100, 1, 29, 0, 0, 0)
+ def oneYear = 1.year
+
+ def result = oneYear.plus(leapYearDate)
+
+ // Calendar handles leap year to non-leap year transition
+ def expected = Calendar.getInstance()
+ expected.setTime(leapYearDate)
+ expected.add(Calendar.YEAR, 1)
+
+ assertEquals expected.getTime(), result
+ }
+ }
+
+ @Test
+ void testMonthEndHandling() {
+ use(TimeCategory) {
+ // Jan 31
+ def janEnd = new Date(100, 0, 31, 0, 0, 0)
+ def oneMonth = 1.month
+
+ def result = oneMonth.plus(janEnd)
+
+ // Calendar handles month-end transitions
+ def expected = Calendar.getInstance()
+ expected.setTime(janEnd)
+ expected.add(Calendar.MONTH, 1)
+
+ assertEquals expected.getTime(), result
+ }
+ }
+
+ @Test
+ void testLargeDurationValues() {
+ def duration = new DatumDependentDuration(100, 120, 365, 24, 60, 60,
1000)
+
+ assertEquals 100, duration.getYears()
+ assertEquals 120, duration.getMonths()
+ assertEquals 365, duration.getDays()
+ assertEquals 24, duration.getHours()
+ assertEquals 60, duration.getMinutes()
+ assertEquals 60, duration.getSeconds()
+ assertEquals 1000, duration.getMillis()
+ }
+
+ @Test
+ void testChainedOperations() {
+ use(TimeCategory) {
+ def duration = 1.year + 2.months - 1.month + 3.days - 1.day
+
+ assertEquals 1, duration.getYears()
+ assertEquals 1, duration.getMonths()
+ assertEquals 2, duration.getDays()
+ }
+ }
+
+ @Test
+ void testDurationWithTimeCategoryDateArithmetic() {
+ use(TimeCategory) {
+ def start = new Date(100, 0, 1, 0, 0, 0)
+ def future = start + 1.year + 6.months
+
+ def expected = Calendar.getInstance()
+ expected.setTime(start)
+ expected.add(Calendar.YEAR, 1)
+ expected.add(Calendar.MONTH, 6)
+
+ assertEquals expected.getTime(), future
+ }
+ }
+
+ @Test
+ void testNegativeDurationAgo() {
+ def duration = new DatumDependentDuration(-1, 0, 0, 0, 0, 0, 0)
+ def result = duration.getAgo()
+
+ def expected = Calendar.getInstance()
+ expected.add(Calendar.YEAR, 1) // -(-1) = +1
+ expected.set(Calendar.HOUR_OF_DAY, 0)
+ expected.set(Calendar.MINUTE, 0)
+ expected.set(Calendar.SECOND, 0)
+ expected.set(Calendar.MILLISECOND, 0)
+
+ assertEquals expected.getTimeInMillis(), result.getTime()
+ }
+
+ @Test
+ void testNegativeDurationFromNow() {
+ def duration = new DatumDependentDuration(-1, 0, 0, 0, 0, 0, 0)
+ def result = duration.getFrom().getNow()
+
+ def expected = Calendar.getInstance()
+ expected.add(Calendar.YEAR, -1)
+ expected.set(Calendar.HOUR_OF_DAY, 0)
+ expected.set(Calendar.MINUTE, 0)
+ expected.set(Calendar.SECOND, 0)
+ expected.set(Calendar.MILLISECOND, 0)
+
+ assertEquals expected.getTimeInMillis(), result.getTime()
+ }
+}