Files
oemcrypto/util/test/wv_date_time_unittest.cpp
2025-05-22 16:33:29 -07:00

465 lines
17 KiB
C++

// Copyright 2025 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
#include "wv_date_time.h"
#include <stdint.h>
// #include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "wv_duration.h"
#include "wv_timestamp.h"
namespace wvutil {
namespace test {
namespace {
// This is a Unix time chosen for testing.
// Friday, April 19th, 2024 13:36:18.507
// April 19th is the 110th day of the year when a leap year.
constexpr uint64_t kTestUnixTimeS = 1713533778;
constexpr uint64_t kTestUnixTimeMs = 1713533778507;
constexpr Seconds kTestTimeS = Seconds(kTestUnixTimeS);
constexpr Milliseconds kTestTimeMs = Milliseconds(kTestUnixTimeMs);
constexpr uint32_t kTestYear = 2024;
constexpr uint32_t kTestMonth = 4; // April
constexpr uint32_t kTestDay = 19;
constexpr uint32_t kTestHour = 13;
constexpr uint32_t kTestMinute = 36;
constexpr uint32_t kTestSecond = 18;
constexpr uint32_t kTestMs = 507;
constexpr uint32_t kTestDayOfWeek = 6; // Friday
constexpr uint32_t kTestDayOfYear = 110;
constexpr int64_t kOneMinuteS = 60;
constexpr int64_t kOneHourS = kOneMinuteS * 60;
constexpr int64_t kOneDayS = kOneHourS * 24;
constexpr int64_t kOneCommonYearS = kOneDayS * 365;
constexpr int64_t kOneLeapYearS = kOneDayS * 366;
constexpr int64_t kOneSecondMs = 1000;
constexpr int64_t kOneMinuteMs = kOneSecondMs * 60;
constexpr int64_t kOneHourMs = kOneMinuteMs * 60;
constexpr int64_t kOneDayMs = kOneHourMs * 24;
uint32_t DayOfWeekAddition(uint32_t day_of_week, uint32_t inc) {
return ((day_of_week - 1 + inc) % 7) + 1;
}
uint32_t DayOfWeekSubtraction(uint32_t day_of_week, uint32_t dec) {
const uint32_t reverse_day_of_week = (8 - day_of_week);
const uint32_t reverse_new_day_of_week =
DayOfWeekAddition(reverse_day_of_week, dec);
return (8 - reverse_new_day_of_week);
}
} // namespace
TEST(WvDateTimeUtilTest, FromUnixSeconds) {
const DateTime datetime = DateTime::FromUnixSeconds(kTestUnixTimeS, kTestMs);
ASSERT_TRUE(datetime.IsSet());
EXPECT_EQ(datetime.epoch_seconds(), kTestTimeS);
EXPECT_EQ(datetime.epoch_milliseconds(), kTestTimeMs);
EXPECT_EQ(datetime.year(), kTestYear);
EXPECT_EQ(datetime.month(), kTestMonth);
EXPECT_EQ(datetime.day(), kTestDay);
EXPECT_EQ(datetime.day_of_year(), kTestDayOfYear);
EXPECT_EQ(datetime.day_of_week(), kTestDayOfWeek);
EXPECT_EQ(datetime.hour(), kTestHour);
EXPECT_EQ(datetime.minute(), kTestMinute);
EXPECT_EQ(datetime.second(), kTestSecond);
EXPECT_EQ(datetime.millisecond(), kTestMs);
}
TEST(WvDateTimeUtilTest, FromUnixMilliseconds) {
const DateTime datetime = DateTime::FromUnixMilliseconds(kTestUnixTimeMs);
ASSERT_TRUE(datetime.IsSet());
EXPECT_EQ(datetime.epoch_seconds(), kTestTimeS);
EXPECT_EQ(datetime.epoch_milliseconds(), kTestTimeMs);
EXPECT_EQ(datetime.year(), kTestYear);
EXPECT_EQ(datetime.month(), kTestMonth);
EXPECT_EQ(datetime.day(), kTestDay);
EXPECT_EQ(datetime.day_of_year(), kTestDayOfYear);
EXPECT_EQ(datetime.day_of_week(), kTestDayOfWeek);
EXPECT_EQ(datetime.hour(), kTestHour);
EXPECT_EQ(datetime.minute(), kTestMinute);
EXPECT_EQ(datetime.second(), kTestSecond);
EXPECT_EQ(datetime.millisecond(), kTestMs);
}
TEST(WvDateTimeUtilTest, Min) {
// Thursday, January 1st, 1970 00:00:00.001
const DateTime datetime = DateTime::Min();
ASSERT_TRUE(datetime.IsSet());
EXPECT_EQ(datetime.epoch_seconds(), Seconds(0));
EXPECT_EQ(datetime.epoch_milliseconds(), Milliseconds(1));
EXPECT_EQ(datetime.year(), 1970u);
EXPECT_EQ(datetime.month(), 1u);
EXPECT_EQ(datetime.day(), 1u);
EXPECT_EQ(datetime.day_of_year(), 1u);
EXPECT_EQ(datetime.day_of_week(), 5u);
EXPECT_EQ(datetime.hour(), 0u);
EXPECT_EQ(datetime.minute(), 0u);
EXPECT_EQ(datetime.second(), 0u);
EXPECT_EQ(datetime.millisecond(), 1u);
}
TEST(WvDateTimeUtilTest, Max) {
constexpr int64_t kMaxEpochTimeS = 253402300799;
constexpr int64_t kMaxEpochTimeMs = (kMaxEpochTimeS * 1000) + 999;
// Friday, December 31st, 9999 23:59:59.999
const DateTime datetime = DateTime::Max();
ASSERT_TRUE(datetime.IsSet());
EXPECT_EQ(datetime.epoch_seconds(), Seconds(kMaxEpochTimeS));
EXPECT_EQ(datetime.epoch_milliseconds(), Milliseconds(kMaxEpochTimeMs));
EXPECT_EQ(datetime.year(), 9999u);
EXPECT_EQ(datetime.month(), 12u);
EXPECT_EQ(datetime.day(), 31u);
EXPECT_EQ(datetime.day_of_year(), 365u);
EXPECT_EQ(datetime.day_of_week(), 6u);
EXPECT_EQ(datetime.hour(), 23u);
EXPECT_EQ(datetime.minute(), 59u);
EXPECT_EQ(datetime.second(), 59u);
EXPECT_EQ(datetime.millisecond(), 999u);
}
TEST(WvDateTimeUtilTest, Clear) {
DateTime datetime = DateTime::FromUnixMilliseconds(kTestUnixTimeMs);
ASSERT_TRUE(datetime.IsSet());
datetime.Clear();
EXPECT_FALSE(datetime.IsSet());
EXPECT_EQ(datetime.year(), 0u);
EXPECT_EQ(datetime.month(), 0u);
EXPECT_EQ(datetime.day(), 0u);
EXPECT_EQ(datetime.day_of_year(), 0u);
EXPECT_EQ(datetime.day_of_week(), 0u);
EXPECT_EQ(datetime.hour(), 0u);
EXPECT_EQ(datetime.minute(), 0u);
EXPECT_EQ(datetime.second(), 0u);
EXPECT_EQ(datetime.millisecond(), 0u);
}
TEST(WvDateTimeUtilTest, Comparison) {
const DateTime datetime_a = DateTime::Min();
const DateTime datetime_b =
DateTime::FromUnixMilliseconds(kTestUnixTimeMs - kOneDayMs);
const DateTime datetime_c = DateTime::FromUnixMilliseconds(kTestUnixTimeMs);
const DateTime datetime_d =
DateTime::FromUnixMilliseconds(kTestUnixTimeMs + 1);
const DateTime datetime_e = DateTime::Max();
// Equality
EXPECT_EQ(datetime_a, datetime_a);
EXPECT_EQ(datetime_b, datetime_b);
EXPECT_EQ(datetime_c, datetime_c);
EXPECT_EQ(datetime_d, datetime_d);
EXPECT_EQ(datetime_e, datetime_e);
// Inequality.
EXPECT_NE(datetime_a, datetime_b);
EXPECT_NE(datetime_a, datetime_c);
EXPECT_NE(datetime_a, datetime_d);
EXPECT_NE(datetime_a, datetime_e);
EXPECT_NE(datetime_b, datetime_c);
EXPECT_NE(datetime_b, datetime_d);
EXPECT_NE(datetime_b, datetime_e);
EXPECT_NE(datetime_c, datetime_d);
EXPECT_NE(datetime_c, datetime_e);
EXPECT_NE(datetime_d, datetime_e);
// Less than
EXPECT_LT(datetime_a, datetime_b);
EXPECT_LT(datetime_a, datetime_c);
EXPECT_LT(datetime_a, datetime_d);
EXPECT_LT(datetime_a, datetime_e);
EXPECT_LT(datetime_b, datetime_c);
EXPECT_LT(datetime_b, datetime_d);
EXPECT_LT(datetime_b, datetime_e);
EXPECT_LT(datetime_c, datetime_d);
EXPECT_LT(datetime_c, datetime_e);
EXPECT_LT(datetime_d, datetime_e);
// Less than or equal.
EXPECT_LE(datetime_a, datetime_a);
EXPECT_LE(datetime_a, datetime_b);
EXPECT_LE(datetime_a, datetime_c);
EXPECT_LE(datetime_a, datetime_d);
EXPECT_LE(datetime_a, datetime_e);
EXPECT_LE(datetime_b, datetime_b);
EXPECT_LE(datetime_b, datetime_c);
EXPECT_LE(datetime_b, datetime_d);
EXPECT_LE(datetime_b, datetime_e);
EXPECT_LE(datetime_c, datetime_c);
EXPECT_LE(datetime_c, datetime_d);
EXPECT_LE(datetime_c, datetime_e);
EXPECT_LE(datetime_d, datetime_d);
EXPECT_LE(datetime_d, datetime_e);
EXPECT_LE(datetime_e, datetime_e);
// Greater than
EXPECT_GT(datetime_b, datetime_a);
EXPECT_GT(datetime_c, datetime_a);
EXPECT_GT(datetime_d, datetime_a);
EXPECT_GT(datetime_e, datetime_a);
EXPECT_GT(datetime_c, datetime_b);
EXPECT_GT(datetime_d, datetime_b);
EXPECT_GT(datetime_e, datetime_b);
EXPECT_GT(datetime_d, datetime_c);
EXPECT_GT(datetime_e, datetime_c);
EXPECT_GT(datetime_e, datetime_d);
// Greater than or equal.
EXPECT_GE(datetime_a, datetime_a);
EXPECT_GE(datetime_b, datetime_a);
EXPECT_GE(datetime_c, datetime_a);
EXPECT_GE(datetime_d, datetime_a);
EXPECT_GE(datetime_e, datetime_a);
EXPECT_GE(datetime_b, datetime_b);
EXPECT_GE(datetime_c, datetime_b);
EXPECT_GE(datetime_d, datetime_b);
EXPECT_GE(datetime_e, datetime_b);
EXPECT_GE(datetime_c, datetime_c);
EXPECT_GE(datetime_d, datetime_c);
EXPECT_GE(datetime_e, datetime_c);
EXPECT_GE(datetime_d, datetime_d);
EXPECT_GE(datetime_e, datetime_d);
EXPECT_GE(datetime_e, datetime_e);
}
TEST(WvDateTimeUtilTest, Addition_WithDuration) {
const DateTime start = DateTime::FromUnixMilliseconds(kTestUnixTimeMs);
ASSERT_TRUE(start.IsSet());
const Duration one_day = Duration::FromMilliseconds(kOneDayMs);
const DateTime tomorrow = start + one_day;
ASSERT_TRUE(tomorrow.IsSet());
EXPECT_EQ(tomorrow.epoch_seconds(), kTestTimeS + Seconds(kOneDayS));
EXPECT_EQ(tomorrow.epoch_milliseconds(),
kTestTimeMs + Milliseconds(kOneDayMs));
EXPECT_EQ(tomorrow.year(), kTestYear);
EXPECT_EQ(tomorrow.month(), kTestMonth);
EXPECT_EQ(tomorrow.day(), kTestDay + 1);
EXPECT_EQ(tomorrow.day_of_year(), kTestDayOfYear + 1);
EXPECT_EQ(tomorrow.day_of_week(), DayOfWeekAddition(kTestDayOfWeek, 1));
EXPECT_EQ(tomorrow.hour(), kTestHour);
EXPECT_EQ(tomorrow.minute(), kTestMinute);
EXPECT_EQ(tomorrow.second(), kTestSecond);
EXPECT_EQ(tomorrow.millisecond(), kTestMs);
// Note: This is 30 days for April to May.
const Duration one_month = Duration::FromSeconds(kOneDayS * 30);
const DateTime next_month = start + one_month;
EXPECT_EQ(next_month.year(), kTestYear);
EXPECT_EQ(next_month.month(), kTestMonth + 1);
EXPECT_EQ(next_month.day(), kTestDay);
EXPECT_EQ(next_month.day_of_year(), kTestDayOfYear + 30);
EXPECT_EQ(next_month.day_of_week(), DayOfWeekAddition(kTestDayOfWeek, 30));
EXPECT_EQ(next_month.hour(), kTestHour);
EXPECT_EQ(next_month.minute(), kTestMinute);
EXPECT_EQ(next_month.second(), kTestSecond);
EXPECT_EQ(next_month.millisecond(), kTestMs);
// Note: This should roll over a day.
const uint32_t day_inc_11h = (kTestHour + 11) / 24;
const Duration eleven_hours = Duration::FromSeconds(kOneHourS * 11);
const DateTime hours_later = start + eleven_hours;
EXPECT_EQ(hours_later.year(), kTestYear);
EXPECT_EQ(hours_later.month(), kTestMonth);
EXPECT_EQ(hours_later.day(), kTestDay + day_inc_11h);
EXPECT_EQ(hours_later.day_of_year(), kTestDayOfYear + day_inc_11h);
EXPECT_EQ(hours_later.day_of_week(),
DayOfWeekAddition(kTestDayOfWeek, day_inc_11h));
const uint32_t new_hour_11h = (kTestHour + 11) % 24;
EXPECT_EQ(hours_later.hour(), new_hour_11h);
EXPECT_EQ(hours_later.minute(), kTestMinute);
EXPECT_EQ(hours_later.second(), kTestSecond);
EXPECT_EQ(hours_later.millisecond(), kTestMs);
const Duration five_years =
Duration::FromSeconds(kOneCommonYearS * 4 + kOneLeapYearS);
const DateTime fewer_years_later = start + five_years;
EXPECT_EQ(fewer_years_later.year(), kTestYear + 5);
EXPECT_EQ(fewer_years_later.month(), kTestMonth);
EXPECT_EQ(fewer_years_later.day(), kTestDay);
EXPECT_EQ(fewer_years_later.hour(), kTestHour);
EXPECT_EQ(fewer_years_later.minute(), kTestMinute);
EXPECT_EQ(fewer_years_later.second(), kTestSecond);
EXPECT_EQ(fewer_years_later.millisecond(), kTestMs);
const DateTime same_time = start + Duration::Zero();
EXPECT_EQ(start, same_time);
}
TEST(WvDateTimeUtilTest, Addition_WithDuration_Invalid) {
// Addition with an unset date time is not allowed.
const DateTime unset;
ASSERT_FALSE(unset.IsSet());
const Duration one_month = Duration::FromSeconds(kOneDayS * 30);
DateTime result = unset + one_month;
EXPECT_FALSE(result.IsSet());
// Addition that causes overflow is not allowed.
result = DateTime::Max() + Duration::FromMilliseconds(1);
EXPECT_FALSE(result.IsSet());
result = DateTime::Min() + Duration::FromSeconds(kOneCommonYearS * 10000);
EXPECT_FALSE(result.IsSet());
}
TEST(WvDateTimeUtilTest, Subtraction_WithDuration) {
const DateTime start = DateTime::FromUnixMilliseconds(kTestUnixTimeMs);
ASSERT_TRUE(start.IsSet());
const Duration one_day = Duration::FromMilliseconds(kOneDayMs);
const DateTime yesterday = start - one_day;
ASSERT_TRUE(yesterday.IsSet());
EXPECT_EQ(yesterday.epoch_seconds(), Seconds(kTestUnixTimeS - kOneDayS));
EXPECT_EQ(yesterday.epoch_milliseconds(),
Milliseconds(kTestUnixTimeMs - kOneDayMs));
EXPECT_EQ(yesterday.year(), kTestYear);
EXPECT_EQ(yesterday.month(), kTestMonth);
EXPECT_EQ(yesterday.day(), kTestDay - 1);
EXPECT_EQ(yesterday.day_of_year(), kTestDayOfYear - 1);
EXPECT_EQ(yesterday.day_of_week(), DayOfWeekSubtraction(kTestDayOfWeek, 1));
EXPECT_EQ(yesterday.hour(), kTestHour);
EXPECT_EQ(yesterday.minute(), kTestMinute);
EXPECT_EQ(yesterday.second(), kTestSecond);
EXPECT_EQ(yesterday.millisecond(), kTestMs);
// Note: This is a 31 days for March.
const Duration one_month = Duration::FromSeconds(kOneDayS * 31);
const DateTime previous_month = start - one_month;
EXPECT_EQ(previous_month.year(), kTestYear);
EXPECT_EQ(previous_month.month(), kTestMonth - 1);
EXPECT_EQ(previous_month.day(), kTestDay);
EXPECT_EQ(previous_month.day_of_year(), kTestDayOfYear - 31);
EXPECT_EQ(previous_month.day_of_week(),
DayOfWeekSubtraction(kTestDayOfWeek, 31));
EXPECT_EQ(previous_month.hour(), kTestHour);
EXPECT_EQ(previous_month.minute(), kTestMinute);
EXPECT_EQ(previous_month.second(), kTestSecond);
EXPECT_EQ(previous_month.millisecond(), kTestMs);
const uint32_t day_dec_14h = (kTestHour < 14) ? 1 : 0;
const Duration fourteen_hours = Duration::FromSeconds(kOneHourS * 14);
const DateTime hours_earlier = start - fourteen_hours;
EXPECT_EQ(yesterday.year(), kTestYear);
EXPECT_EQ(yesterday.month(), kTestMonth);
EXPECT_EQ(yesterday.day(), kTestDay - day_dec_14h);
EXPECT_EQ(yesterday.day_of_year(), kTestDayOfYear - day_dec_14h);
EXPECT_EQ(yesterday.day_of_week(),
DayOfWeekSubtraction(kTestDayOfWeek, day_dec_14h));
const uint32_t new_hour_14h =
(kTestHour < 14) ? (kTestHour + 10) : kTestHour - 14;
EXPECT_EQ(hours_earlier.hour(), new_hour_14h);
EXPECT_EQ(hours_earlier.minute(), kTestMinute);
EXPECT_EQ(hours_earlier.second(), kTestSecond);
EXPECT_EQ(hours_earlier.millisecond(), kTestMs);
const Duration five_years =
Duration::FromSeconds(kOneCommonYearS * 3 + kOneLeapYearS * 2);
const DateTime few_years_earlier = start - five_years;
EXPECT_EQ(few_years_earlier.year(), kTestYear - 5);
EXPECT_EQ(few_years_earlier.month(), kTestMonth);
EXPECT_EQ(few_years_earlier.day(), kTestDay);
EXPECT_EQ(few_years_earlier.hour(), kTestHour);
EXPECT_EQ(few_years_earlier.minute(), kTestMinute);
EXPECT_EQ(few_years_earlier.second(), kTestSecond);
EXPECT_EQ(few_years_earlier.millisecond(), kTestMs);
const DateTime same_time = start - Duration::Zero();
EXPECT_EQ(start, same_time);
}
TEST(WvDateTimeUtilTest, Subtraction_WithDuration_Invalid) {
// Subtract with an unset date time is not allowed.
const DateTime unset;
ASSERT_FALSE(unset.IsSet());
const Duration one_month = Duration::FromSeconds(kOneDayS * 30);
DateTime result = unset - one_month;
EXPECT_FALSE(result.IsSet());
// Subtract that causes overflow is not allowed.
result = DateTime::Min() - Duration::FromMilliseconds(1);
EXPECT_FALSE(result.IsSet());
result = DateTime::Max() - Duration::FromSeconds(kOneCommonYearS * 10000);
EXPECT_FALSE(result.IsSet());
}
TEST(WvDateTimeUtilTest, Difference) {
const Duration expected_diff =
Duration(Hours(15) + Minutes(6) + Seconds(30) + Milliseconds(123));
const DateTime datetime_a =
DateTime::FromUnixSeconds(kTestUnixTimeS, kTestMs);
const DateTime datetime_b = DateTime::FromUnixMilliseconds(
datetime_a.epoch_milliseconds() + expected_diff.total_milliseconds());
const Duration diff_ab = datetime_b - datetime_a;
EXPECT_EQ(diff_ab, expected_diff);
const Duration diff_ba = datetime_a - datetime_b;
EXPECT_EQ(diff_ba, -expected_diff);
// Very big diff
const Duration diff_min_max = DateTime::Max() - DateTime::Min();
EXPECT_TRUE(diff_min_max.IsPositive());
const Duration diff_max_min = DateTime::Min() - DateTime::Max();
EXPECT_TRUE(diff_max_min.IsNegative());
EXPECT_EQ(diff_min_max, -diff_max_min);
// No difference.
const Duration diff_aa = datetime_a - datetime_a;
EXPECT_TRUE(diff_aa.IsZero());
}
TEST(WvDateTimeUtilTest, Difference_Invalid) {
const DateTime datetime = DateTime::FromUnixSeconds(kTestUnixTimeS, kTestMs);
const DateTime unset;
Duration diff = datetime - unset;
EXPECT_TRUE(diff.IsZero());
diff = unset - datetime;
EXPECT_TRUE(diff.IsZero());
}
TEST(WvDateTimeUtilTest, ToString) {
// Default should ISO date times with short timezones, and milliseconds
// only printed if non-zero.
DateTime datetime = DateTime::FromUnixSeconds(kTestUnixTimeS, kTestMs);
EXPECT_EQ(datetime.ToString(), "2024-04-19T13:36:18.507Z");
datetime = DateTime::FromUnixSeconds(kTestUnixTimeS);
EXPECT_EQ(datetime.ToString(), "2024-04-19T13:36:18Z");
EXPECT_EQ(DateTime::Min().ToString(), "1970-01-01T00:00:00.001Z");
EXPECT_EQ(DateTime::Max().ToString(), "9999-12-31T23:59:59.999Z");
EXPECT_EQ(DateTime().ToString(), "<unset>");
}
} // namespace test
} // namespace wvutil