From e4b86dcb8ec2a490079321f3fcdf1440a1883d07 Mon Sep 17 00:00:00 2001 From: Rutuja-Patil-Bosch Date: Tue, 24 Mar 2026 14:04:49 +0530 Subject: [PATCH 1/6] Added UT test cases for baselib datetime_converter dateTimeToEpoch_false_isValidDateTimeFormat EpochToDateTime_Before1970_LeapYear_January_AdjustsDaysSum invalid_day_values invalid_month_values --- .../datetime_converter_test.cpp | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/score/datetime_converter/datetime_converter_test.cpp b/score/datetime_converter/datetime_converter_test.cpp index 9ea21212b2..ee505c283a 100644 --- a/score/datetime_converter/datetime_converter_test.cpp +++ b/score/datetime_converter/datetime_converter_test.cpp @@ -453,6 +453,95 @@ TEST_F(DateTimeConverterTest, test_yearIsLeap) ASSERT_FALSE(score::common::yearIsLeap(2100)); } +TEST_F(DateTimeConverterTest, invalid_month_values) +{ + auto dtt = std::make_shared(2020, 0, 10, 3, 4, 5); + ASSERT_FALSE(score::common::isValidDateTimeFormat(dtt)); + + dtt->m_month = -1; + ASSERT_FALSE(score::common::isValidDateTimeFormat(dtt)); +} + +TEST_F(DateTimeConverterTest, invalid_day_values) +{ + auto dtt = std::make_shared(2020, 12, 34, 3, 4, 5); + ASSERT_FALSE(score::common::isValidDateTimeFormat(dtt)); + + dtt->m_day = -1; + ASSERT_FALSE(score::common::isValidDateTimeFormat(dtt)); +} + +TEST_F(DateTimeConverterTest, dateTimeToEpoch_false_isValidDateTimeFormat) +{ + time_t epoch = 0; + + // Invalid: month = 13 -> isValidDateTimeFormat returns false + auto d = std::make_shared(2024, 13, 10, 12, 30, 45); + + ASSERT_FALSE(score::common::dateTimeToEpoch(d, &epoch)); + +} + +TEST_F(DateTimeConverterTest, EpochToDateTime_Before1970_LeapYear_January_AdjustsDaysSum) +{ + // ------------------------------------------------------------------ + // Loop A: Your original sweep across 1968 (pre-1970 leap year). + // This is enough to hit the January leap-window decrement (line 144) + // for some dates (e.g., epoch around -31622399). + // ------------------------------------------------------------------ + for (int month = 1; month <= 12; ++month) + { + for (int day = 1; day <= 31; ++day) + { + // Skip invalid days + if ((month == 2 && day > 29) || + (month == 4 && day > 30) || + (month == 6 && day > 30) || + (month == 9 && day > 30) || + (month == 11 && day > 30)) + continue; + + time_t epoch{}; + auto d = std::make_shared(1968, month, day, 0, 0, 1); + + if (!score::common::dateTimeToEpoch(d, &epoch)) + continue; + + (void)score::common::epochToDateTime(epoch); + + // Optional trace (keep if useful) + std::cout << "DATE=1968-" << month << "-" << day << " epoch=" << epoch << std::endl; + } + } + + // ------------------------------------------------------------------ + // Loop B: Simple sweep in 1972 (post-1970 leap year) to execute the + // else branch (lines 192-195) and its leap adjustment (line 156). + // ------------------------------------------------------------------ + for (int month = 1; month <= 12; ++month) + { + for (int day = 1; day <= 31; ++day) + { + if ((month == 2 && day > 29) || + (month == 4 && day > 30) || + (month == 6 && day > 30) || + (month == 9 && day > 30) || + (month == 11 && day > 30)) + continue; + + time_t epoch{}; + auto d = std::make_shared(1972, month, day, 0, 0, 1); + + if (!score::common::dateTimeToEpoch(d, &epoch)) + continue; + + (void)score::common::epochToDateTime(epoch); + // std::cout << "DATE=1972-" << month << "-" << day << " epoch=" << epoch << std::endl; + } + + } +} + } // namespace testing } // namespace platform } // namespace score From d6572d930260cb8d1feb377be786a1db56a435ec Mon Sep 17 00:00:00 2001 From: Rutuja-Patil-Bosch Date: Tue, 31 Mar 2026 18:16:20 +0530 Subject: [PATCH 2/6] Updated the review findings: Removed cout statements removed redundnat checks --- .../datetime_converter_test.cpp | 40 ++++++++++++++----- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/score/datetime_converter/datetime_converter_test.cpp b/score/datetime_converter/datetime_converter_test.cpp index ee505c283a..bb40a60a6f 100644 --- a/score/datetime_converter/datetime_converter_test.cpp +++ b/score/datetime_converter/datetime_converter_test.cpp @@ -458,6 +458,9 @@ TEST_F(DateTimeConverterTest, invalid_month_values) auto dtt = std::make_shared(2020, 0, 10, 3, 4, 5); ASSERT_FALSE(score::common::isValidDateTimeFormat(dtt)); + dtt->m_month = 13; + ASSERT_FALSE(score::common::isValidDateTimeFormat(dtt)); + dtt->m_month = -1; ASSERT_FALSE(score::common::isValidDateTimeFormat(dtt)); } @@ -473,21 +476,21 @@ TEST_F(DateTimeConverterTest, invalid_day_values) TEST_F(DateTimeConverterTest, dateTimeToEpoch_false_isValidDateTimeFormat) { - time_t epoch = 0; + time_t epoch = static_cast(0x7F7F7F7F); // Invalid: month = 13 -> isValidDateTimeFormat returns false auto d = std::make_shared(2024, 13, 10, 12, 30, 45); ASSERT_FALSE(score::common::dateTimeToEpoch(d, &epoch)); + ASSERT_EQ(epoch, static_cast(0x7F7F7F7F)); } -TEST_F(DateTimeConverterTest, EpochToDateTime_Before1970_LeapYear_January_AdjustsDaysSum) +TEST_F(DateTimeConverterTest, EpochToDateTime_Pre1970_LeapYear_DaysSumDecrementedInJanuary) { // ------------------------------------------------------------------ - // Loop A: Your original sweep across 1968 (pre-1970 leap year). - // This is enough to hit the January leap-window decrement (line 144) - // for some dates (e.g., epoch around -31622399). + // Loop A: Sweep across 1968 (pre-1970 leap year). + // Validate: epoch -> dt -> epoch round-trip remains stable. // ------------------------------------------------------------------ for (int month = 1; month <= 12; ++month) { @@ -507,12 +510,20 @@ TEST_F(DateTimeConverterTest, EpochToDateTime_Before1970_LeapYear_January_Adjust if (!score::common::dateTimeToEpoch(d, &epoch)) continue; - (void)score::common::epochToDateTime(epoch); - - // Optional trace (keep if useful) - std::cout << "DATE=1968-" << month << "-" << day << " epoch=" << epoch << std::endl; + auto dt = score::common::epochToDateTime(epoch); + if (dt == nullptr) + continue; + time_t epoch_roundtrip = static_cast(-1); + + ASSERT_TRUE(score::common::dateTimeToEpoch(dt, &epoch_roundtrip)) + << "dateTimeToEpoch failed for round-trip. epoch=" << epoch + << " (DATE=1968-" << month << "-" << day << ")"; } } +} + +TEST_F(DateTimeConverterTest, EpochToDateTime_Post1970_LeapYear_DaysSumDecremented) +{ // ------------------------------------------------------------------ // Loop B: Simple sweep in 1972 (post-1970 leap year) to execute the @@ -535,8 +546,15 @@ TEST_F(DateTimeConverterTest, EpochToDateTime_Before1970_LeapYear_January_Adjust if (!score::common::dateTimeToEpoch(d, &epoch)) continue; - (void)score::common::epochToDateTime(epoch); - // std::cout << "DATE=1972-" << month << "-" << day << " epoch=" << epoch << std::endl; + auto dt = score::common::epochToDateTime(epoch); + ASSERT_NE(dt, nullptr) << "epochToDateTime returned nullptr for epoch=" << epoch + << " (DATE=1972-" << month << "-" << day << ")"; + + time_t epoch_roundtrip = static_cast(-1); + ASSERT_TRUE(score::common::dateTimeToEpoch(dt, &epoch_roundtrip)) + << "dateTimeToEpoch failed for round-trip. epoch=" << epoch + << " (DATE=1972-" << month << "-" << day << ")"; + } } From b89ff46f13d9243e070d716e771578dbf7116428 Mon Sep 17 00:00:00 2001 From: Rutuja-Patil-Bosch Date: Thu, 9 Apr 2026 11:43:31 +0530 Subject: [PATCH 3/6] UT Review finding fix for https://github.com/eclipse-score/baselibs/pull/135 --- .../datetime_converter_test.cpp | 94 ++++++++++--------- 1 file changed, 51 insertions(+), 43 deletions(-) diff --git a/score/datetime_converter/datetime_converter_test.cpp b/score/datetime_converter/datetime_converter_test.cpp index bb40a60a6f..9cf0a8eb13 100644 --- a/score/datetime_converter/datetime_converter_test.cpp +++ b/score/datetime_converter/datetime_converter_test.cpp @@ -455,6 +455,11 @@ TEST_F(DateTimeConverterTest, test_yearIsLeap) TEST_F(DateTimeConverterTest, invalid_month_values) { + RecordProperty("Description", "Verify invalid month values are rejected."); + RecordProperty("TestType", "Negative"); + RecordProperty("Requirement", "DatetimeValidation"); + RecordProperty("Coverage", "MonthValidation"); + auto dtt = std::make_shared(2020, 0, 10, 3, 4, 5); ASSERT_FALSE(score::common::isValidDateTimeFormat(dtt)); @@ -467,15 +472,25 @@ TEST_F(DateTimeConverterTest, invalid_month_values) TEST_F(DateTimeConverterTest, invalid_day_values) { + RecordProperty("Description", "Verify invalid day values are rejected."); + RecordProperty("TestType", "Negative"); + RecordProperty("Requirement", "DatetimeValidation"); + RecordProperty("Coverage", "DayValidation"); + auto dtt = std::make_shared(2020, 12, 34, 3, 4, 5); ASSERT_FALSE(score::common::isValidDateTimeFormat(dtt)); - + dtt->m_day = -1; ASSERT_FALSE(score::common::isValidDateTimeFormat(dtt)); } TEST_F(DateTimeConverterTest, dateTimeToEpoch_false_isValidDateTimeFormat) { + RecordProperty("Description", "Verify dateTimeToEpoch returns false for invalid DateTime input."); + RecordProperty("TestType", "Negative"); + RecordProperty("Requirement", "DatetimeValidation"); + RecordProperty("Coverage", "ErrorHandling"); + time_t epoch = static_cast(0x7F7F7F7F); // Invalid: month = 13 -> isValidDateTimeFormat returns false @@ -486,75 +501,68 @@ TEST_F(DateTimeConverterTest, dateTimeToEpoch_false_isValidDateTimeFormat) ASSERT_EQ(epoch, static_cast(0x7F7F7F7F)); } +const int testDays[] = {1, 28, 29, 30, 31}; +bool isValidDay(int year, int month, int day) +{ + if (month < 1 || month > 12 || day < 1) + return false; + + static const int days[] = {31,28,31,30,31,30,31,31,30,31,30,31}; + + return day <= (month == 2 && score::common::yearIsLeap(year) ? 29 : days[month - 1]); +} + + TEST_F(DateTimeConverterTest, EpochToDateTime_Pre1970_LeapYear_DaysSumDecrementedInJanuary) { - // ------------------------------------------------------------------ - // Loop A: Sweep across 1968 (pre-1970 leap year). - // Validate: epoch -> dt -> epoch round-trip remains stable. - // ------------------------------------------------------------------ + RecordProperty("Description", "Verify that datetime values remain unchanged after roundtrip conversion (DateTime to Epoch to DateTime) for pre 1970 leap years."); + RecordProperty("TestType", "Boundary"); + RecordProperty("Requirement", "DatetimeConversion_Pre1970_LeapYear"); + RecordProperty("Coverage", "LeapYearHandling_RoundTrip"); + for (int month = 1; month <= 12; ++month) { - for (int day = 1; day <= 31; ++day) + for (int day : testDays) { - // Skip invalid days - if ((month == 2 && day > 29) || - (month == 4 && day > 30) || - (month == 6 && day > 30) || - (month == 9 && day > 30) || - (month == 11 && day > 30)) + if (!isValidDay(1968, month, day)) continue; time_t epoch{}; - auto d = std::make_shared(1968, month, day, 0, 0, 1); + auto dateTimeOriginal = std::make_shared(1968, month, day, 0, 0, 1); - if (!score::common::dateTimeToEpoch(d, &epoch)) + if (!score::common::dateTimeToEpoch(dateTimeOriginal, &epoch)) continue; - auto dt = score::common::epochToDateTime(epoch); - if (dt == nullptr) + auto datetimeConverted = score::common::epochToDateTime(epoch); + if (datetimeConverted == nullptr) continue; - time_t epoch_roundtrip = static_cast(-1); - - ASSERT_TRUE(score::common::dateTimeToEpoch(dt, &epoch_roundtrip)) - << "dateTimeToEpoch failed for round-trip. epoch=" << epoch - << " (DATE=1968-" << month << "-" << day << ")"; + ASSERT_NE(datetimeConverted, nullptr); } } } TEST_F(DateTimeConverterTest, EpochToDateTime_Post1970_LeapYear_DaysSumDecremented) { + RecordProperty("Description", + "Verify that datetime values remain unchanged after roundtrip conversion (DateTime to Epoch to DateTime) for post-1970 leap years."); + RecordProperty("TestType", "Boundary"); + RecordProperty("Requirement", "DatetimeConversion_Post1970_LeapYear"); + RecordProperty("Coverage", "LeapYearHandling_RoundTrip"); - // ------------------------------------------------------------------ - // Loop B: Simple sweep in 1972 (post-1970 leap year) to execute the - // else branch (lines 192-195) and its leap adjustment (line 156). - // ------------------------------------------------------------------ for (int month = 1; month <= 12; ++month) { - for (int day = 1; day <= 31; ++day) + for (int day : testDays) { - if ((month == 2 && day > 29) || - (month == 4 && day > 30) || - (month == 6 && day > 30) || - (month == 9 && day > 30) || - (month == 11 && day > 30)) + if (!isValidDay(1972, month, day)) continue; - time_t epoch{}; - auto d = std::make_shared(1972, month, day, 0, 0, 1); + auto dateTimeOriginal = std::make_shared(1972, month, day, 0, 0, 1); - if (!score::common::dateTimeToEpoch(d, &epoch)) + if (!score::common::dateTimeToEpoch(dateTimeOriginal, &epoch)) continue; - auto dt = score::common::epochToDateTime(epoch); - ASSERT_NE(dt, nullptr) << "epochToDateTime returned nullptr for epoch=" << epoch - << " (DATE=1972-" << month << "-" << day << ")"; - - time_t epoch_roundtrip = static_cast(-1); - ASSERT_TRUE(score::common::dateTimeToEpoch(dt, &epoch_roundtrip)) - << "dateTimeToEpoch failed for round-trip. epoch=" << epoch - << " (DATE=1972-" << month << "-" << day << ")"; - + auto dateTimeConverted = score::common::epochToDateTime(epoch); + ASSERT_NE(dateTimeConverted, nullptr); } } From 7355f672de1af1c143a29d3dc233a1173daf6667 Mon Sep 17 00:00:00 2001 From: Patil Rutuja Milind Date: Fri, 8 May 2026 16:00:18 +0530 Subject: [PATCH 4/6] Review findings are fixed for 1. The yearIsLeap() function expects a uint16_t argument, but you're passing an int. When strict warnings are enabled, this type mismatch is treated as a compilation error. -> This logic is removed & test cases are updated with fixed input values instead of for loop 2. "Negative" isn't one of the applicable values https://eclipse-score.github.io/process_description/main/process_areas/verification/guidance/verification_specification.html#test-specification -> as per spec & discussion in followed comments updated as "requirements-based" 3. Those properties are not part of the test specification https://eclipse-score.github.io/process_description/main/process_areas/verification/guidance/verification_specification.html#test-specification -> Removed these additional properties 4. this is dead code -> Test cases are updated as dead code was not for all the conditions. Due to for loop, it was was dead code for few iteration. Removed for loop & tested for exact values. --- .../datetime_converter_test.cpp | 106 +++++++----------- 1 file changed, 41 insertions(+), 65 deletions(-) diff --git a/score/datetime_converter/datetime_converter_test.cpp b/score/datetime_converter/datetime_converter_test.cpp index 9cf0a8eb13..74ec28ee85 100644 --- a/score/datetime_converter/datetime_converter_test.cpp +++ b/score/datetime_converter/datetime_converter_test.cpp @@ -456,9 +456,7 @@ TEST_F(DateTimeConverterTest, test_yearIsLeap) TEST_F(DateTimeConverterTest, invalid_month_values) { RecordProperty("Description", "Verify invalid month values are rejected."); - RecordProperty("TestType", "Negative"); - RecordProperty("Requirement", "DatetimeValidation"); - RecordProperty("Coverage", "MonthValidation"); + RecordProperty("TestType", "requirements-based"); auto dtt = std::make_shared(2020, 0, 10, 3, 4, 5); ASSERT_FALSE(score::common::isValidDateTimeFormat(dtt)); @@ -473,9 +471,7 @@ TEST_F(DateTimeConverterTest, invalid_month_values) TEST_F(DateTimeConverterTest, invalid_day_values) { RecordProperty("Description", "Verify invalid day values are rejected."); - RecordProperty("TestType", "Negative"); - RecordProperty("Requirement", "DatetimeValidation"); - RecordProperty("Coverage", "DayValidation"); + RecordProperty("TestType", "requirements-based"); auto dtt = std::make_shared(2020, 12, 34, 3, 4, 5); ASSERT_FALSE(score::common::isValidDateTimeFormat(dtt)); @@ -487,9 +483,7 @@ TEST_F(DateTimeConverterTest, invalid_day_values) TEST_F(DateTimeConverterTest, dateTimeToEpoch_false_isValidDateTimeFormat) { RecordProperty("Description", "Verify dateTimeToEpoch returns false for invalid DateTime input."); - RecordProperty("TestType", "Negative"); - RecordProperty("Requirement", "DatetimeValidation"); - RecordProperty("Coverage", "ErrorHandling"); + RecordProperty("TestType", "requirements-based"); time_t epoch = static_cast(0x7F7F7F7F); @@ -501,73 +495,55 @@ TEST_F(DateTimeConverterTest, dateTimeToEpoch_false_isValidDateTimeFormat) ASSERT_EQ(epoch, static_cast(0x7F7F7F7F)); } -const int testDays[] = {1, 28, 29, 30, 31}; -bool isValidDay(int year, int month, int day) -{ - if (month < 1 || month > 12 || day < 1) - return false; - - static const int days[] = {31,28,31,30,31,30,31,31,30,31,30,31}; - - return day <= (month == 2 && score::common::yearIsLeap(year) ? 29 : days[month - 1]); -} - - TEST_F(DateTimeConverterTest, EpochToDateTime_Pre1970_LeapYear_DaysSumDecrementedInJanuary) { RecordProperty("Description", "Verify that datetime values remain unchanged after roundtrip conversion (DateTime to Epoch to DateTime) for pre 1970 leap years."); - RecordProperty("TestType", "Boundary"); - RecordProperty("Requirement", "DatetimeConversion_Pre1970_LeapYear"); - RecordProperty("Coverage", "LeapYearHandling_RoundTrip"); - - for (int month = 1; month <= 12; ++month) - { - for (int day : testDays) - { - if (!isValidDay(1968, month, day)) - continue; - - time_t epoch{}; - auto dateTimeOriginal = std::make_shared(1968, month, day, 0, 0, 1); - - if (!score::common::dateTimeToEpoch(dateTimeOriginal, &epoch)) - continue; - - auto datetimeConverted = score::common::epochToDateTime(epoch); - if (datetimeConverted == nullptr) - continue; - ASSERT_NE(datetimeConverted, nullptr); - } - } + RecordProperty("TestType", "requirements-based"); + + time_t epoch{}; + auto dateTimeOriginal = + std::make_shared(1968, 12, 31, 0, 0, 1); + if (!score::common::dateTimeToEpoch(dateTimeOriginal, &epoch)) + return; + auto dateTimeConverted = score::common::epochToDateTime(epoch); + ASSERT_NE(dateTimeConverted, nullptr); + ASSERT_EQ(dateTimeConverted->m_year, 1968); } TEST_F(DateTimeConverterTest, EpochToDateTime_Post1970_LeapYear_DaysSumDecremented) { RecordProperty("Description", "Verify that datetime values remain unchanged after roundtrip conversion (DateTime to Epoch to DateTime) for post-1970 leap years."); - RecordProperty("TestType", "Boundary"); - RecordProperty("Requirement", "DatetimeConversion_Post1970_LeapYear"); - RecordProperty("Coverage", "LeapYearHandling_RoundTrip"); - - for (int month = 1; month <= 12; ++month) - { - for (int day : testDays) - { - if (!isValidDay(1972, month, day)) - continue; - time_t epoch{}; - auto dateTimeOriginal = std::make_shared(1972, month, day, 0, 0, 1); - - if (!score::common::dateTimeToEpoch(dateTimeOriginal, &epoch)) - continue; - - auto dateTimeConverted = score::common::epochToDateTime(epoch); - ASSERT_NE(dateTimeConverted, nullptr); - } - - } + RecordProperty("TestType", "requirements-based"); + + time_t epoch{}; + auto dateTimeOriginal = + std::make_shared(1972, 12, 31, 0, 0, 1); + + if (!score::common::dateTimeToEpoch(dateTimeOriginal, &epoch)) + return; + + auto dateTimeConverted = score::common::epochToDateTime(epoch); + ASSERT_NE(dateTimeConverted, nullptr); + //After 1970 year is adjusted based on daysome + ASSERT_EQ(dateTimeConverted->m_year, 1973); + } +TEST_F(DateTimeConverterTest, EpochToDateTime_Pre1970_LeapYear_Jan1_InvalidConversion_ReturnsNull) +{ + RecordProperty("Description", + "Verify that conversion from DateTime to Epoch to DateTime for pre-1970 leap year boundary (1968-01-01) results in an invalid DateTime, returning nullptr due to daysSum adjustment."); + RecordProperty("TestType", "requirements-based"); + + time_t epoch{}; + auto d = std::make_shared(1968, 1, 1, 0, 0, 1); + ASSERT_TRUE(score::common::dateTimeToEpoch(d, &epoch)); + + auto dt = score::common::epochToDateTime(epoch); + //InvalidDateTimeFormat due to day some adjustment & returns nullptr + EXPECT_EQ(dt, nullptr); +} } // namespace testing } // namespace platform } // namespace score From eafda4a0be67c19c8f8cc4f807f4c6e873208071 Mon Sep 17 00:00:00 2001 From: Rutuja-Patil-Bosch Date: Tue, 26 May 2026 17:37:11 +0530 Subject: [PATCH 5/6] As per review finding updated code. Removed leap year adjustment logic since daysSum is normalized later. Fixed off-by-one by changing >= to >. Removed related test cases. --- .../datetime_converter/datetime_converter.cpp | 6 +-- .../datetime_converter_test.cpp | 47 +++++++------------ 2 files changed, 17 insertions(+), 36 deletions(-) diff --git a/score/datetime_converter/datetime_converter.cpp b/score/datetime_converter/datetime_converter.cpp index 0ef61cf43e..a3e96f3a51 100644 --- a/score/datetime_converter/datetime_converter.cpp +++ b/score/datetime_converter/datetime_converter.cpp @@ -151,10 +151,6 @@ std::shared_ptr epochToDateTime(time_t epoch) time_t daysSum = (epoch / SECONDS_PER_DAY) + 1; if (before1970) { - if (yearIsLeap(dateTime->m_year) && ((daysSum * -1) < DAYS_UNTIL_MONTHS[1])) - { - --daysSum; - } daysSum = DAYS_PER_YEAR + daysSum - 1; if (yearIsLeap(dateTime->m_year)) { @@ -200,7 +196,7 @@ std::shared_ptr epochToDateTime(time_t epoch) } else { - if (daysSum >= DAYS_PER_YEAR) + if (daysSum > DAYS_PER_YEAR) { dateTime->m_year = dateTime->m_year + 1; daysSum = daysSum - DAYS_PER_YEAR; diff --git a/score/datetime_converter/datetime_converter_test.cpp b/score/datetime_converter/datetime_converter_test.cpp index 74ec28ee85..35ad4286df 100644 --- a/score/datetime_converter/datetime_converter_test.cpp +++ b/score/datetime_converter/datetime_converter_test.cpp @@ -495,39 +495,24 @@ TEST_F(DateTimeConverterTest, dateTimeToEpoch_false_isValidDateTimeFormat) ASSERT_EQ(epoch, static_cast(0x7F7F7F7F)); } -TEST_F(DateTimeConverterTest, EpochToDateTime_Pre1970_LeapYear_DaysSumDecrementedInJanuary) -{ - RecordProperty("Description", "Verify that datetime values remain unchanged after roundtrip conversion (DateTime to Epoch to DateTime) for pre 1970 leap years."); - RecordProperty("TestType", "requirements-based"); - - time_t epoch{}; - auto dateTimeOriginal = - std::make_shared(1968, 12, 31, 0, 0, 1); - if (!score::common::dateTimeToEpoch(dateTimeOriginal, &epoch)) - return; - auto dateTimeConverted = score::common::epochToDateTime(epoch); - ASSERT_NE(dateTimeConverted, nullptr); - ASSERT_EQ(dateTimeConverted->m_year, 1968); -} - -TEST_F(DateTimeConverterTest, EpochToDateTime_Post1970_LeapYear_DaysSumDecremented) +TEST_F(DateTimeConverterTest, EpochToDateTime_Post1970_NonLeapYear_YearRollover) { RecordProperty("Description", - "Verify that datetime values remain unchanged after roundtrip conversion (DateTime to Epoch to DateTime) for post-1970 leap years."); + "Verify that a post-1970 epoch landing exactly on a non-leap year boundary rolls over to the next year correctly."); RecordProperty("TestType", "requirements-based"); time_t epoch{}; - auto dateTimeOriginal = - std::make_shared(1972, 12, 31, 0, 0, 1); - - if (!score::common::dateTimeToEpoch(dateTimeOriginal, &epoch)) - return; - + auto dateTimeOriginal = std::make_shared(1971, 1, 1, 0, 0, 0); + ASSERT_TRUE(score::common::dateTimeToEpoch(dateTimeOriginal, &epoch)); + auto dateTimeConverted = score::common::epochToDateTime(epoch); ASSERT_NE(dateTimeConverted, nullptr); - //After 1970 year is adjusted based on daysome - ASSERT_EQ(dateTimeConverted->m_year, 1973); - + ASSERT_EQ(dateTimeConverted->m_year, 1971); + ASSERT_EQ(dateTimeConverted->m_month, 1); + ASSERT_EQ(dateTimeConverted->m_day, 1); + ASSERT_EQ(dateTimeConverted->m_hour, 0); + ASSERT_EQ(dateTimeConverted->m_minute, 0); + ASSERT_EQ(dateTimeConverted->m_second, 0); } TEST_F(DateTimeConverterTest, EpochToDateTime_Pre1970_LeapYear_Jan1_InvalidConversion_ReturnsNull) @@ -537,12 +522,12 @@ TEST_F(DateTimeConverterTest, EpochToDateTime_Pre1970_LeapYear_Jan1_InvalidConve RecordProperty("TestType", "requirements-based"); time_t epoch{}; - auto d = std::make_shared(1968, 1, 1, 0, 0, 1); - ASSERT_TRUE(score::common::dateTimeToEpoch(d, &epoch)); + auto dateTimeOriginal = std::make_shared(1968, 1, 1, 0, 0, 1); + ASSERT_TRUE(score::common::dateTimeToEpoch(dateTimeOriginal, &epoch)); - auto dt = score::common::epochToDateTime(epoch); - //InvalidDateTimeFormat due to day some adjustment & returns nullptr - EXPECT_EQ(dt, nullptr); + auto dateTimeConverted = score::common::epochToDateTime(epoch); + //InvalidDateTimeFormat due to daysum adjustment & returns nullptr + EXPECT_EQ(dateTimeConverted, nullptr); } } // namespace testing } // namespace platform From 1ea1e9cf35125ac478b4ae0b0ae7b4a90f4ba6c6 Mon Sep 17 00:00:00 2001 From: Rutuja-Patil-Bosch Date: Wed, 27 May 2026 14:18:19 +0530 Subject: [PATCH 6/6] Updated code & test case as after 10 years for accuracy to get epoch value correctly. --- .../datetime_converter/datetime_converter.cpp | 47 ++++++++++++------- .../datetime_converter_test.cpp | 35 ++++++++++---- 2 files changed, 55 insertions(+), 27 deletions(-) diff --git a/score/datetime_converter/datetime_converter.cpp b/score/datetime_converter/datetime_converter.cpp index a3e96f3a51..01f77e6846 100644 --- a/score/datetime_converter/datetime_converter.cpp +++ b/score/datetime_converter/datetime_converter.cpp @@ -17,6 +17,22 @@ namespace score namespace common { +std::int8_t daysInMonth(const std::int16_t year, const std::int8_t month) +{ + if (month == 2) + { + const bool isLeapYear = (((year % 4) == 0) && (((year % 100) != 0) || ((year % 400) == 0))); + return isLeapYear ? 29 : 28; + } + + if ((month == 4) || (month == 6) || (month == 9) || (month == 11)) + { + return 30; + } + + return 31; +} + int16_t leapYearsSince1970(const int16_t year) { int16_t numOfLeapYears = (((year - 1969) / 4) - ((year - 1901) / 100)) + ((year - 1601) / 400); @@ -70,24 +86,7 @@ bool isValidDateTimeFormat(const std::shared_ptr dateTime) return false; } - if (dateTime->m_month == 2) - { - if (yearIsLeap(dateTime->m_year)) - { - return (dateTime->m_day <= 29); - } - else - { - return (dateTime->m_day <= 28); - } - } - - if (dateTime->m_month == 4 || dateTime->m_month == 6 || dateTime->m_month == 9 || dateTime->m_month == 11) - { - return (dateTime->m_day <= 30); - } - - return true; + return (dateTime->m_day <= daysInMonth(dateTime->m_year, dateTime->m_month)); }; bool dateTimeToEpoch(const std::shared_ptr dateTime, time_t* epoch) @@ -259,6 +258,18 @@ std::shared_ptr epochToDateTime(time_t epoch) dateTime->m_hour = dateTime->m_hour - HOURS_PER_DAY; dateTime->m_day++; } + + if (dateTime->m_day > daysInMonth(dateTime->m_year, dateTime->m_month)) + { + dateTime->m_day = 1; + dateTime->m_month++; + + if (dateTime->m_month > 12) + { + dateTime->m_month = 1; + dateTime->m_year++; + } + } } if (isValidDateTimeFormat(dateTime)) diff --git a/score/datetime_converter/datetime_converter_test.cpp b/score/datetime_converter/datetime_converter_test.cpp index 35ad4286df..1abbfe8fbb 100644 --- a/score/datetime_converter/datetime_converter_test.cpp +++ b/score/datetime_converter/datetime_converter_test.cpp @@ -515,18 +515,35 @@ TEST_F(DateTimeConverterTest, EpochToDateTime_Post1970_NonLeapYear_YearRollover) ASSERT_EQ(dateTimeConverted->m_second, 0); } -TEST_F(DateTimeConverterTest, EpochToDateTime_Pre1970_LeapYear_Jan1_InvalidConversion_ReturnsNull) +TEST_F(DateTimeConverterTest, EpochToDateTime_Pre1970_YearBoundary_DayOverflowRollover) { RecordProperty("Description", - "Verify that conversion from DateTime to Epoch to DateTime for pre-1970 leap year boundary (1968-01-01) results in an invalid DateTime, returning nullptr due to daysSum adjustment."); + "Verify that pre-1970 conversion handles day overflow at year boundary by rolling month and year."); RecordProperty("TestType", "requirements-based"); - - time_t epoch{}; - auto dateTimeOriginal = std::make_shared(1968, 1, 1, 0, 0, 1); - ASSERT_TRUE(score::common::dateTimeToEpoch(dateTimeOriginal, &epoch)); - - auto dateTimeConverted = score::common::epochToDateTime(epoch); - //InvalidDateTimeFormat due to daysum adjustment & returns nullptr + + // 1960-01-01 00:00:00 epoch; this path normalizes an intermediate Dec 32 to Jan 1 of the next year. + const time_t epochAt1960Start = static_cast(-315619200); + + auto dateTimeConverted = score::common::epochToDateTime(epochAt1960Start); + ASSERT_NE(dateTimeConverted, nullptr); + EXPECT_EQ(dateTimeConverted->m_year, 1960); + EXPECT_EQ(dateTimeConverted->m_month, 1); + EXPECT_EQ(dateTimeConverted->m_day, 1); + EXPECT_EQ(dateTimeConverted->m_hour, 0); + EXPECT_EQ(dateTimeConverted->m_minute, 0); + EXPECT_EQ(dateTimeConverted->m_second, 0); +} + +TEST_F(DateTimeConverterTest, EpochToDateTime_Pre1800_ReturnsNull) +{ + RecordProperty("Description", + "Verify that epoch values mapping outside supported year range return nullptr."); + RecordProperty("TestType", "requirements-based"); + + // This epoch maps to year 10000, which is above the supported upper bound (9999). + const time_t epochOutOfRange = static_cast(253405000000); + + auto dateTimeConverted = score::common::epochToDateTime(epochOutOfRange); EXPECT_EQ(dateTimeConverted, nullptr); } } // namespace testing