memgraph/tests/unit/utils_temporal.cpp

682 lines
35 KiB
C++
Raw Normal View History

2022-02-22 20:33:45 +08:00
// Copyright 2022 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
// License, and you may not use this file except in compliance with the Business Source License.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#include <chrono>
#include <iostream>
#include <limits>
#include <optional>
#include <sstream>
#include <gtest/gtest.h>
#include "utils/exceptions.hpp"
#include "utils/memory.hpp"
#include "utils/temporal.hpp"
namespace {
2022-02-22 20:33:45 +08:00
std::string ToString(const memgraph::utils::DateParameters &date_parameters) {
return fmt::format("{:04d}-{:02d}-{:02d}", date_parameters.year, date_parameters.month, date_parameters.day);
}
2022-02-22 20:33:45 +08:00
std::string ToString(const memgraph::utils::LocalTimeParameters &local_time_parameters) {
return fmt::format("{:02}:{:02d}:{:02d}", local_time_parameters.hour, local_time_parameters.minute,
local_time_parameters.second);
}
struct TestDateParameters {
2022-02-22 20:33:45 +08:00
memgraph::utils::DateParameters date_parameters;
bool should_throw;
};
inline constexpr std::array test_dates{
TestDateParameters{{-1996, 11, 22}, true}, TestDateParameters{{1996, -11, 22}, true},
TestDateParameters{{1996, 11, -22}, true}, TestDateParameters{{1, 13, 3}, true},
TestDateParameters{{1, 12, 32}, true}, TestDateParameters{{1, 2, 29}, true},
TestDateParameters{{2020, 2, 29}, false}, TestDateParameters{{1700, 2, 29}, true},
TestDateParameters{{1200, 2, 29}, false}, TestDateParameters{{10000, 12, 3}, true}};
struct TestLocalTimeParameters {
2022-02-22 20:33:45 +08:00
memgraph::utils::LocalTimeParameters local_time_parameters;
bool should_throw;
};
inline constexpr std::array test_local_times{TestLocalTimeParameters{{.hour = 24}, true},
TestLocalTimeParameters{{.hour = -1}, true},
TestLocalTimeParameters{{.minute = -1}, true},
TestLocalTimeParameters{{.minute = 60}, true},
TestLocalTimeParameters{{.second = -1}, true},
TestLocalTimeParameters{{.minute = 60}, true},
TestLocalTimeParameters{{.millisecond = -1}, true},
TestLocalTimeParameters{{.millisecond = 1000}, true},
TestLocalTimeParameters{{.microsecond = -1}, true},
TestLocalTimeParameters{{.microsecond = 1000}, true},
TestLocalTimeParameters{{23, 59, 59, 999, 999}, false},
TestLocalTimeParameters{{0, 0, 0, 0, 0}, false}};
} // namespace
TEST(TemporalTest, DateConstruction) {
2022-02-22 20:33:45 +08:00
std::optional<memgraph::utils::Date> test_date;
for (const auto [date_parameters, should_throw] : test_dates) {
if (should_throw) {
2022-02-22 20:33:45 +08:00
EXPECT_THROW(test_date.emplace(date_parameters), memgraph::utils::BasicException) << ToString(date_parameters);
} else {
EXPECT_NO_THROW(test_date.emplace(date_parameters)) << ToString(date_parameters);
}
}
}
TEST(TemporalTest, DateMicrosecondsSinceEpochConversion) {
const auto check_microseconds = [](const auto date_parameters) {
2022-02-22 20:33:45 +08:00
memgraph::utils::Date initial_date{date_parameters};
const auto microseconds = initial_date.MicrosecondsSinceEpoch();
2022-02-22 20:33:45 +08:00
memgraph::utils::Date new_date{microseconds};
ASSERT_EQ(initial_date, new_date);
};
2022-02-22 20:33:45 +08:00
check_microseconds(memgraph::utils::DateParameters{2020, 11, 22});
check_microseconds(memgraph::utils::DateParameters{1900, 2, 22});
check_microseconds(memgraph::utils::DateParameters{0, 1, 1});
check_microseconds(memgraph::utils::DateParameters{1994, 12, 7});
2022-02-22 20:33:45 +08:00
ASSERT_THROW(check_microseconds(memgraph::utils::DateParameters{-10, 1, 1}), memgraph::utils::BasicException);
{
2022-02-22 20:33:45 +08:00
memgraph::utils::Date date{memgraph::utils::DateParameters{1970, 1, 1}};
ASSERT_EQ(date.MicrosecondsSinceEpoch(), 0);
}
{
2022-02-22 20:33:45 +08:00
memgraph::utils::Date date{memgraph::utils::DateParameters{1910, 1, 1}};
ASSERT_LT(date.MicrosecondsSinceEpoch(), 0);
}
{
2022-02-22 20:33:45 +08:00
memgraph::utils::Date date{memgraph::utils::DateParameters{2021, 1, 1}};
ASSERT_GT(date.MicrosecondsSinceEpoch(), 0);
}
}
TEST(TemporalTest, LocalTimeConstruction) {
2022-02-22 20:33:45 +08:00
std::optional<memgraph::utils::LocalTime> test_local_time;
for (const auto [local_time_parameters, should_throw] : test_local_times) {
if (should_throw) {
2022-02-22 20:33:45 +08:00
ASSERT_THROW(test_local_time.emplace(local_time_parameters), memgraph::utils::BasicException);
} else {
ASSERT_NO_THROW(test_local_time.emplace(local_time_parameters));
}
}
}
TEST(TemporalTest, LocalTimeMicrosecondsSinceEpochConversion) {
2022-02-22 20:33:45 +08:00
const auto check_microseconds = [](const memgraph::utils::LocalTimeParameters &parameters) {
memgraph::utils::LocalTime initial_local_time{parameters};
const auto microseconds = initial_local_time.MicrosecondsSinceEpoch();
2022-02-22 20:33:45 +08:00
memgraph::utils::LocalTime new_local_time{microseconds};
ASSERT_EQ(initial_local_time, new_local_time);
};
2022-02-22 20:33:45 +08:00
check_microseconds(memgraph::utils::LocalTimeParameters{23, 59, 59, 999, 999});
check_microseconds(memgraph::utils::LocalTimeParameters{0, 0, 0, 0, 0});
check_microseconds(memgraph::utils::LocalTimeParameters{14, 8, 55, 321, 452});
}
TEST(TemporalTest, LocalDateTimeMicrosecondsSinceEpochConversion) {
2022-02-22 20:33:45 +08:00
const auto check_microseconds = [](const memgraph::utils::DateParameters date_parameters,
const memgraph::utils::LocalTimeParameters &local_time_parameters) {
memgraph::utils::LocalDateTime initial_local_date_time{date_parameters, local_time_parameters};
const auto microseconds = initial_local_date_time.MicrosecondsSinceEpoch();
2022-02-22 20:33:45 +08:00
memgraph::utils::LocalDateTime new_local_date_time{microseconds};
ASSERT_EQ(initial_local_date_time, new_local_date_time);
};
2022-02-22 20:33:45 +08:00
check_microseconds(memgraph::utils::DateParameters{2020, 11, 22},
memgraph::utils::LocalTimeParameters{0, 0, 0, 0, 0});
check_microseconds(memgraph::utils::DateParameters{1900, 2, 22}, memgraph::utils::LocalTimeParameters{0, 0, 0, 0, 0});
check_microseconds(memgraph::utils::DateParameters{0, 1, 1}, memgraph::utils::LocalTimeParameters{0, 0, 0, 0, 0});
2022-02-22 20:33:45 +08:00
check_microseconds(memgraph::utils::DateParameters{1961, 1, 1}, memgraph::utils::LocalTimeParameters{15, 44, 12});
check_microseconds(memgraph::utils::DateParameters{1969, 12, 31}, memgraph::utils::LocalTimeParameters{23, 59, 59});
{
2022-02-22 20:33:45 +08:00
memgraph::utils::LocalDateTime local_date_time(memgraph::utils::DateParameters{1970, 1, 1},
memgraph::utils::LocalTimeParameters{0, 0, 0, 0, 0});
ASSERT_EQ(local_date_time.MicrosecondsSinceEpoch(), 0);
}
{
2022-02-22 20:33:45 +08:00
memgraph::utils::LocalDateTime local_date_time(memgraph::utils::DateParameters{1970, 1, 1},
memgraph::utils::LocalTimeParameters{0, 0, 0, 0, 1});
ASSERT_GT(local_date_time.MicrosecondsSinceEpoch(), 0);
}
{
2022-02-22 20:33:45 +08:00
memgraph::utils::LocalTimeParameters local_time_parameters{12, 10, 40, 42, 42};
memgraph::utils::LocalDateTime local_date_time{memgraph::utils::DateParameters{1970, 1, 1}, local_time_parameters};
ASSERT_EQ(local_date_time.MicrosecondsSinceEpoch(),
2022-02-22 20:33:45 +08:00
memgraph::utils::LocalTime{local_time_parameters}.MicrosecondsSinceEpoch());
}
{
2022-02-22 20:33:45 +08:00
memgraph::utils::LocalDateTime local_date_time(memgraph::utils::DateParameters{1910, 1, 1},
memgraph::utils::LocalTimeParameters{0, 0, 0, 0, 0});
ASSERT_LT(local_date_time.MicrosecondsSinceEpoch(), 0);
}
{
2022-02-22 20:33:45 +08:00
memgraph::utils::LocalDateTime local_date_time(memgraph::utils::DateParameters{2021, 1, 1},
memgraph::utils::LocalTimeParameters{0, 0, 0, 0, 0});
ASSERT_GT(local_date_time.MicrosecondsSinceEpoch(), 0);
}
{
// Assert ordering for dates prior the unix epoch.
// If this test fails, our storage indexes will be incorrect.
2022-02-22 20:33:45 +08:00
memgraph::utils::LocalDateTime ldt({1969, 12, 31}, {0, 0, 0});
memgraph::utils::LocalDateTime ldt2({1969, 12, 31}, {23, 59, 59});
ASSERT_LT(ldt.MicrosecondsSinceEpoch(), ldt2.MicrosecondsSinceEpoch());
}
}
TEST(TemporalTest, DurationConversion) {
{
2022-02-22 20:33:45 +08:00
memgraph::utils::Duration duration{{.minute = 123.25}};
const auto microseconds = duration.microseconds;
2022-02-22 20:33:45 +08:00
memgraph::utils::LocalDateTime local_date_time{microseconds};
ASSERT_EQ(local_date_time.date.year, 1970);
ASSERT_EQ(local_date_time.date.month, 1);
ASSERT_EQ(local_date_time.date.day, 1);
ASSERT_EQ(local_date_time.local_time.hour, 2);
ASSERT_EQ(local_date_time.local_time.minute, 3);
ASSERT_EQ(local_date_time.local_time.second, 15);
};
}
namespace {
using namespace std::literals;
inline constexpr std::array parsing_test_dates_extended{
2022-02-22 20:33:45 +08:00
std::make_pair("2020-11-22"sv, memgraph::utils::DateParameters{2020, 11, 22}),
std::make_pair("2020-11"sv, memgraph::utils::DateParameters{2020, 11}),
};
inline constexpr std::array parsing_test_dates_basic{
2022-02-22 20:33:45 +08:00
std::make_pair("20201122"sv, memgraph::utils::DateParameters{2020, 11, 22})};
inline constexpr std::array parsing_test_local_time_extended{
2022-02-22 20:33:45 +08:00
std::make_pair("19:23:21.123456"sv, memgraph::utils::LocalTimeParameters{19, 23, 21, 123, 456}),
std::make_pair("19:23:21.123"sv, memgraph::utils::LocalTimeParameters{19, 23, 21, 123}),
std::make_pair("19:23:21"sv, memgraph::utils::LocalTimeParameters{19, 23, 21}),
std::make_pair("19:23"sv, memgraph::utils::LocalTimeParameters{19, 23}),
std::make_pair("00:00:00.000000"sv, memgraph::utils::LocalTimeParameters{0, 0, 0, 0, 0}),
std::make_pair("01:02:03.004005"sv, memgraph::utils::LocalTimeParameters{1, 2, 3, 4, 5}),
};
inline constexpr std::array parsing_test_local_time_basic{
2022-02-22 20:33:45 +08:00
std::make_pair("192321.123456"sv, memgraph::utils::LocalTimeParameters{19, 23, 21, 123, 456}),
std::make_pair("192321.123"sv, memgraph::utils::LocalTimeParameters{19, 23, 21, 123}),
std::make_pair("192321"sv, memgraph::utils::LocalTimeParameters{19, 23, 21}),
std::make_pair("1923"sv, memgraph::utils::LocalTimeParameters{19, 23}),
std::make_pair("19"sv, memgraph::utils::LocalTimeParameters{19}),
std::make_pair("000000.000000"sv, memgraph::utils::LocalTimeParameters{0, 0, 0, 0, 0}),
std::make_pair("010203.004005"sv, memgraph::utils::LocalTimeParameters{1, 2, 3, 4, 5}),
};
} // namespace
TEST(TemporalTest, DateParsing) {
for (const auto &[string, date_parameters] : parsing_test_dates_extended) {
2022-02-22 20:33:45 +08:00
ASSERT_EQ(memgraph::utils::ParseDateParameters(string).first, date_parameters);
}
for (const auto &[string, date_parameters] : parsing_test_dates_basic) {
2022-02-22 20:33:45 +08:00
ASSERT_EQ(memgraph::utils::ParseDateParameters(string).first, date_parameters);
}
2022-02-22 20:33:45 +08:00
ASSERT_THROW(memgraph::utils::ParseDateParameters("202-011-22"), memgraph::utils::BasicException);
ASSERT_THROW(memgraph::utils::ParseDateParameters("2020-1-022"), memgraph::utils::BasicException);
ASSERT_THROW(memgraph::utils::ParseDateParameters("2020-11-2-"), memgraph::utils::BasicException);
}
TEST(TemporalTest, LocalTimeParsing) {
for (const auto &[string, local_time_parameters] : parsing_test_local_time_extended) {
2022-02-22 20:33:45 +08:00
ASSERT_EQ(memgraph::utils::ParseLocalTimeParameters(string).first, local_time_parameters)
<< ToString(local_time_parameters);
2021-12-07 18:05:33 +08:00
const auto time_string = fmt::format("T{}", string);
2022-02-22 20:33:45 +08:00
ASSERT_EQ(memgraph::utils::ParseLocalTimeParameters(time_string).first, local_time_parameters)
<< ToString(local_time_parameters);
}
for (const auto &[string, local_time_parameters] : parsing_test_local_time_basic) {
2022-02-22 20:33:45 +08:00
ASSERT_EQ(memgraph::utils::ParseLocalTimeParameters(string).first, local_time_parameters)
<< ToString(local_time_parameters);
ASSERT_EQ(memgraph::utils::ParseLocalTimeParameters(fmt::format("T{}", string)).first, local_time_parameters)
<< ToString(local_time_parameters);
}
2022-02-22 20:33:45 +08:00
ASSERT_THROW(memgraph::utils::ParseLocalTimeParameters("19:20:21s"), memgraph::utils::BasicException);
ASSERT_THROW(memgraph::utils::ParseLocalTimeParameters("1920:21"), memgraph::utils::BasicException);
}
TEST(TemporalTest, LocalDateTimeParsing) {
const auto check_local_date_time_combinations = [](const auto &dates, const auto &local_times, const bool is_valid) {
for (const auto &[date_string, date_parameters] : dates) {
for (const auto &[local_time_string, local_time_parameters] : local_times) {
const auto local_date_time_string = fmt::format("{}T{}", date_string, local_time_string);
if (is_valid) {
2022-02-22 20:33:45 +08:00
EXPECT_EQ(memgraph::utils::ParseLocalDateTimeParameters(local_date_time_string),
(std::pair{date_parameters, local_time_parameters}));
}
}
}
};
check_local_date_time_combinations(parsing_test_dates_basic, parsing_test_local_time_basic, true);
check_local_date_time_combinations(parsing_test_dates_extended, parsing_test_local_time_extended, true);
check_local_date_time_combinations(parsing_test_dates_basic, parsing_test_local_time_extended, false);
check_local_date_time_combinations(parsing_test_dates_extended, parsing_test_local_time_basic, false);
}
void CheckDurationParameters(const auto &values, const auto &expected) {
ASSERT_EQ(values.day, expected.day);
ASSERT_EQ(values.hour, expected.hour);
ASSERT_EQ(values.minute, expected.minute);
ASSERT_EQ(values.second, expected.second);
ASSERT_EQ(values.millisecond, expected.millisecond);
ASSERT_EQ(values.microsecond, expected.microsecond);
}
TEST(TemporalTest, DurationParsing) {
2022-02-22 20:33:45 +08:00
ASSERT_THROW(memgraph::utils::ParseDurationParameters("P12Y"), memgraph::utils::BasicException);
ASSERT_THROW(memgraph::utils::ParseDurationParameters("P12Y32DT2M"), memgraph::utils::BasicException);
CheckDurationParameters(memgraph::utils::ParseDurationParameters("PT26H"),
memgraph::utils::DurationParameters{.hour = 26});
CheckDurationParameters(memgraph::utils::ParseDurationParameters("PT2M"),
memgraph::utils::DurationParameters{.minute = 2.0});
CheckDurationParameters(memgraph::utils::ParseDurationParameters("PT22S"),
memgraph::utils::DurationParameters{.second = 22});
CheckDurationParameters(memgraph::utils::ParseDurationParameters("PT.33S"),
memgraph::utils::DurationParameters{.second = 0.33});
CheckDurationParameters(memgraph::utils::ParseDurationParameters("PT2M3S"),
memgraph::utils::DurationParameters{.minute = 2.0, .second = 3.0});
CheckDurationParameters(memgraph::utils::ParseDurationParameters("PT2.5H"),
memgraph::utils::DurationParameters{.hour = 2.5});
CheckDurationParameters(memgraph::utils::ParseDurationParameters("P2DT2.5H"),
memgraph::utils::DurationParameters{.day = 2.0, .hour = 2.5});
ASSERT_THROW(memgraph::utils::ParseDurationParameters("P2M3S"), memgraph::utils::BasicException);
ASSERT_THROW(memgraph::utils::ParseDurationParameters("PTM3S"), memgraph::utils::BasicException);
ASSERT_THROW(memgraph::utils::ParseDurationParameters("P2M3Y"), memgraph::utils::BasicException);
ASSERT_THROW(memgraph::utils::ParseDurationParameters("PT2Y3M"), memgraph::utils::BasicException);
ASSERT_THROW(memgraph::utils::ParseDurationParameters("12Y32DT2M"), memgraph::utils::BasicException);
ASSERT_THROW(memgraph::utils::ParseDurationParameters("PY"), memgraph::utils::BasicException);
ASSERT_THROW(memgraph::utils::ParseDurationParameters(""), memgraph::utils::BasicException);
ASSERT_THROW(memgraph::utils::ParseDurationParameters("PT2M3SX"), memgraph::utils::BasicException);
ASSERT_THROW(memgraph::utils::ParseDurationParameters("PT2M3S32"), memgraph::utils::BasicException);
ASSERT_THROW(memgraph::utils::ParseDurationParameters("PT2.5M3S"), memgraph::utils::BasicException);
ASSERT_THROW(memgraph::utils::ParseDurationParameters("PT2.5M3.5S"), memgraph::utils::BasicException);
ASSERT_THROW(memgraph::utils::ParseDurationParameters("PT2.5M3.-5S"), memgraph::utils::BasicException);
CheckDurationParameters(memgraph::utils::ParseDurationParameters("P1256.5D"),
memgraph::utils::DurationParameters{1256.5});
CheckDurationParameters(memgraph::utils::ParseDurationParameters("P1222DT2H"),
memgraph::utils::DurationParameters{1222, 2});
CheckDurationParameters(memgraph::utils::ParseDurationParameters("P1222DT2H44M"),
memgraph::utils::DurationParameters{1222, 2, 44});
CheckDurationParameters(memgraph::utils::ParseDurationParameters("P22DT1H9M20S"),
memgraph::utils::DurationParameters{22, 1, 9, 20});
CheckDurationParameters(memgraph::utils::ParseDurationParameters("P22DT1H9M20.100S"),
memgraph::utils::DurationParameters{
22,
1,
9,
20.1,
});
CheckDurationParameters(memgraph::utils::ParseDurationParameters("P-22222222DT1H9M20.100S"),
memgraph::utils::DurationParameters{-22222222, 1, 9, 20.1});
CheckDurationParameters(memgraph::utils::ParseDurationParameters("P-22222222DT-10H8M21.200S"),
memgraph::utils::DurationParameters{-22222222, -10, 8, 21.2});
CheckDurationParameters(memgraph::utils::ParseDurationParameters("P-22222222DT-1H-7M22.300S"),
memgraph::utils::DurationParameters{-22222222, -1, -7, 22.3});
CheckDurationParameters(memgraph::utils::ParseDurationParameters("P-22222222DT-1H-6M-20.100S"),
memgraph::utils::DurationParameters{-22222222, -1, -6, -20.1});
CheckDurationParameters(memgraph::utils::ParseDurationParameters("P-22222222DT-1H-5M-20.100S"),
memgraph::utils::DurationParameters{-22222222, -1, -5, -20.1});
}
TEST(TemporalTest, PrintDate) {
2022-02-22 20:33:45 +08:00
const auto unix_epoch = memgraph::utils::Date(memgraph::utils::DateParameters{1970, 1, 1});
std::ostringstream stream;
stream << unix_epoch;
ASSERT_TRUE(stream);
ASSERT_EQ(stream.view(), "1970-01-01");
}
TEST(TemporalTest, PrintLocalTime) {
2022-02-22 20:33:45 +08:00
const auto lt = memgraph::utils::LocalTime({13, 2, 40, 100, 50});
std::ostringstream stream;
stream << lt;
ASSERT_TRUE(stream);
ASSERT_EQ(stream.view(), "13:02:40.100050");
}
TEST(TemporalTest, PrintDuration) {
2022-02-22 20:33:45 +08:00
const auto dur = memgraph::utils::Duration({1, 0, 0, 0, 0, 0});
std::ostringstream stream;
stream << dur;
ASSERT_TRUE(stream);
2021-09-20 22:53:42 +08:00
ASSERT_EQ(stream.view(), "P1DT0H0M0.000000S");
stream.str("");
stream.clear();
2022-02-22 20:33:45 +08:00
const auto complex_dur = memgraph::utils::Duration({10, 3, 30, 33, 100, 50});
stream << complex_dur;
ASSERT_TRUE(stream);
2021-09-20 22:53:42 +08:00
ASSERT_EQ(stream.view(), "P10DT3H30M33.100050S");
stream.str("");
stream.clear();
2022-02-22 20:33:45 +08:00
const auto negative_dur = memgraph::utils::Duration({-10, -3, -30, -33, -100, -50});
stream << negative_dur;
ASSERT_TRUE(stream);
2021-09-20 22:53:42 +08:00
ASSERT_EQ(stream.view(), "P-10DT-3H-30M-33.100050S");
}
TEST(TemporalTest, PrintLocalDateTime) {
2022-02-22 20:33:45 +08:00
const auto unix_epoch = memgraph::utils::Date(memgraph::utils::DateParameters{1970, 1, 1});
const auto lt = memgraph::utils::LocalTime({13, 2, 40, 100, 50});
memgraph::utils::LocalDateTime ldt(unix_epoch, lt);
std::ostringstream stream;
stream << ldt;
ASSERT_TRUE(stream);
ASSERT_EQ(stream.view(), "1970-01-01T13:02:40.100050");
}
TEST(TemporalTest, DurationAddition) {
// a >= 0 && b >= 0
2022-02-22 20:33:45 +08:00
const auto zero = memgraph::utils::Duration(0);
const auto one = memgraph::utils::Duration(1);
const auto two = one + one;
const auto four = two + two;
ASSERT_EQ(two.microseconds, 2);
ASSERT_EQ(four.microseconds, 4);
2022-02-22 20:33:45 +08:00
const auto max = memgraph::utils::Duration(std::numeric_limits<int64_t>::max());
ASSERT_THROW(max + one, memgraph::utils::BasicException);
ASSERT_EQ(zero + zero, zero);
ASSERT_EQ(max + zero, max);
// a < 0 && b < 0
const auto neg_one = -one;
const auto neg_two = neg_one + neg_one;
const auto neg_four = neg_two + neg_two;
ASSERT_EQ(neg_two.microseconds, -2);
ASSERT_EQ(neg_four.microseconds, -4);
2022-02-22 20:33:45 +08:00
const auto min = memgraph::utils::Duration(std::numeric_limits<int64_t>::min());
ASSERT_THROW(min + neg_one, memgraph::utils::BasicException);
ASSERT_EQ(min + zero, min);
// a < 0, b > 0 && a > 0 , b < 0
ASSERT_EQ(neg_one + one, zero);
ASSERT_EQ(neg_two + one, neg_one);
ASSERT_EQ(neg_two + four, two);
ASSERT_EQ(four + neg_two, two);
// a {min, max} && b {min, max}
ASSERT_EQ(min + max, neg_one);
ASSERT_EQ(max + min, neg_one);
2022-02-22 20:33:45 +08:00
ASSERT_THROW(min + min, memgraph::utils::BasicException);
ASSERT_THROW(max + max, memgraph::utils::BasicException);
}
TEST(TemporalTest, DurationSubtraction) {
// a >= 0 && b >= 0
2022-02-22 20:33:45 +08:00
const auto one = memgraph::utils::Duration(1);
const auto two = one + one;
const auto zero = one - one;
ASSERT_EQ(zero.microseconds, 0);
const auto neg_one = zero - one;
const auto neg_two = zero - two;
ASSERT_EQ(neg_one.microseconds, -1);
ASSERT_EQ(neg_two.microseconds, -2);
2022-02-22 20:33:45 +08:00
const auto max = memgraph::utils::Duration(std::numeric_limits<int64_t>::max());
const auto min_minus_one = memgraph::utils::Duration(std::numeric_limits<int64_t>::min() + 1);
ASSERT_EQ(max - zero, max);
ASSERT_EQ(zero - max, min_minus_one);
// a < 0 && b < 0
ASSERT_EQ(neg_two - neg_two, zero);
2022-02-22 20:33:45 +08:00
const auto min = memgraph::utils::Duration(std::numeric_limits<int64_t>::min());
ASSERT_THROW(min - one, memgraph::utils::BasicException);
ASSERT_EQ(min - zero, min);
// a < 0, b > 0 && a > 0 , b < 0
ASSERT_EQ(neg_one - one, neg_two);
ASSERT_EQ(one - neg_one, two);
2022-02-22 20:33:45 +08:00
const auto neg_three = memgraph::utils::Duration(-3);
const auto three = -neg_three;
ASSERT_EQ(neg_two - one, neg_three);
ASSERT_EQ(one - neg_two, three);
// a {min, max} && b {min, max}
2022-02-22 20:33:45 +08:00
ASSERT_THROW(min - max, memgraph::utils::BasicException);
ASSERT_THROW(max - min, memgraph::utils::BasicException);
// There is no positive representation of min
2022-02-22 20:33:45 +08:00
ASSERT_THROW(min - min, memgraph::utils::BasicException);
ASSERT_EQ(max - max, zero);
}
TEST(TemporalTest, LocalTimeAndDurationAddition) {
2022-02-22 20:33:45 +08:00
const auto half_past_one = memgraph::utils::LocalTime({1, 30, 10});
const auto three = half_past_one + memgraph::utils::Duration({10, 1, 30, 2, 22, 45});
const auto three_symmetrical = memgraph::utils::Duration({10, 1, 30, 2, 22, 45}) + half_past_one;
ASSERT_EQ(three, memgraph::utils::LocalTime({3, 0, 12, 22, 45}));
ASSERT_EQ(three_symmetrical, memgraph::utils::LocalTime({3, 0, 12, 22, 45}));
2022-02-22 20:33:45 +08:00
const auto half_an_hour_before_midnight = memgraph::utils::LocalTime({23, 30, 10});
{
2022-02-22 20:33:45 +08:00
const auto half_past_midnight = half_an_hour_before_midnight + memgraph::utils::Duration({1, 1, 0, 0});
ASSERT_EQ(half_past_midnight, memgraph::utils::LocalTime({.minute = 30, .second = 10}));
}
2022-02-22 20:33:45 +08:00
const auto identity = half_an_hour_before_midnight + memgraph::utils::Duration({.day = 1});
ASSERT_EQ(identity, half_an_hour_before_midnight);
2022-02-22 20:33:45 +08:00
ASSERT_EQ(identity, half_an_hour_before_midnight + memgraph::utils::Duration({.day = 1, .hour = 24}));
const auto an_hour_and_a_half_before_midnight = memgraph::utils::LocalTime({22, 30, 10});
ASSERT_EQ(half_an_hour_before_midnight + memgraph::utils::Duration({.hour = 23}), an_hour_and_a_half_before_midnight);
2022-02-22 20:33:45 +08:00
const auto minus_one_hour = memgraph::utils::Duration({-10, -1, 0, 0, -20, -20});
const auto minus_one_hour_exact = memgraph::utils::Duration({.day = -10, .hour = -1});
{
const auto half_past_midnight = half_past_one + minus_one_hour;
2022-02-22 20:33:45 +08:00
ASSERT_EQ(half_past_midnight, memgraph::utils::LocalTime({0, 30, 9, 979, 980}));
ASSERT_EQ(half_past_midnight + minus_one_hour_exact, memgraph::utils::LocalTime({23, 30, 9, 979, 980}));
const auto minus_two_hours_thirty_mins = memgraph::utils::Duration({-10, -2, -30, -9});
ASSERT_EQ(half_past_midnight + minus_two_hours_thirty_mins, memgraph::utils::LocalTime({22, 0, 0, 979, 980}));
ASSERT_NO_THROW(half_past_midnight + (memgraph::utils::Duration(std::numeric_limits<int64_t>::max())));
ASSERT_EQ(half_past_midnight + (memgraph::utils::Duration(std::numeric_limits<int64_t>::max())),
memgraph::utils::LocalTime({4, 31, 4, 755, 787}));
ASSERT_NO_THROW(half_past_midnight + (memgraph::utils::Duration(std::numeric_limits<int64_t>::min())));
ASSERT_EQ(half_past_midnight + (memgraph::utils::Duration(std::numeric_limits<int64_t>::min())),
memgraph::utils::LocalTime({20, 29, 15, 204, 172}));
}
}
TEST(TemporalTest, LocalTimeAndDurationSubtraction) {
2022-02-22 20:33:45 +08:00
const auto half_past_one = memgraph::utils::LocalTime({1, 30, 10});
const auto midnight = half_past_one - memgraph::utils::Duration({10, 1, 30, 10});
ASSERT_EQ(midnight, memgraph::utils::LocalTime());
ASSERT_EQ(midnight - memgraph::utils::Duration({-10, -1, -30, -10}), memgraph::utils::LocalTime({1, 30, 10}));
const auto almost_an_hour_and_a_half_before_midnight = midnight - memgraph::utils::Duration({10, 1, 30, 1, 20, 20});
ASSERT_EQ(almost_an_hour_and_a_half_before_midnight, memgraph::utils::LocalTime({22, 29, 58, 979, 980}));
ASSERT_NO_THROW(midnight - (memgraph::utils::Duration(std::numeric_limits<int64_t>::max())));
ASSERT_EQ(midnight - (memgraph::utils::Duration(std::numeric_limits<int64_t>::max())),
memgraph::utils::LocalTime({19, 59, 5, 224, 193}));
ASSERT_THROW(midnight - memgraph::utils::Duration(std::numeric_limits<int64_t>::min()),
memgraph::utils::BasicException);
}
TEST(TemporalTest, LocalTimeDeltaDuration) {
2022-02-22 20:33:45 +08:00
const auto half_past_one = memgraph::utils::LocalTime({1, 30, 10});
const auto half_past_two = memgraph::utils::LocalTime({2, 30, 10});
const auto an_hour_negative = half_past_one - half_past_two;
2022-02-22 20:33:45 +08:00
ASSERT_EQ(an_hour_negative, memgraph::utils::Duration({.hour = -1}));
const auto an_hour = half_past_two - half_past_one;
2022-02-22 20:33:45 +08:00
ASSERT_EQ(an_hour, memgraph::utils::Duration({.hour = 1}));
}
TEST(TemporalTest, DateAddition) {
2022-02-22 20:33:45 +08:00
const auto unix_epoch = memgraph::utils::Date({1970, 1, 1});
const auto one_day_after_unix_epoch = unix_epoch + memgraph::utils::Duration({.day = 1});
const auto one_day_after_unix_epoch_symmetrical = memgraph::utils::Duration({.day = 1}) + unix_epoch;
ASSERT_EQ(one_day_after_unix_epoch, memgraph::utils::Date({1970, 1, 2}));
ASSERT_EQ(one_day_after_unix_epoch_symmetrical, one_day_after_unix_epoch);
2022-02-22 20:33:45 +08:00
const auto one_month_after_unix_epoch = unix_epoch + memgraph::utils::Duration({.day = 31});
ASSERT_EQ(one_month_after_unix_epoch, memgraph::utils::Date({1970, 2, 1}));
2022-02-22 20:33:45 +08:00
const auto one_year_after_unix_epoch = unix_epoch + memgraph::utils::Duration({.day = 365});
ASSERT_EQ(one_year_after_unix_epoch, memgraph::utils::Date({1971, 1, 1}));
2022-02-22 20:33:45 +08:00
const auto last_day_of_unix_epoch = one_year_after_unix_epoch + memgraph::utils::Duration({.day = -1});
ASSERT_EQ(last_day_of_unix_epoch, memgraph::utils::Date({1970, 12, 31}));
2022-02-22 20:33:45 +08:00
const auto one_day_before_unix_epoch = unix_epoch + memgraph::utils::Duration({.day = -1});
ASSERT_EQ(one_day_before_unix_epoch, memgraph::utils::Date({1969, 12, 31}));
2022-02-22 20:33:45 +08:00
ASSERT_EQ(last_day_of_unix_epoch + memgraph::utils::Duration({.day = -31}), memgraph::utils::Date({1970, 11, 30}));
ASSERT_THROW(unix_epoch + memgraph::utils::Duration(std::numeric_limits<int64_t>::max()),
memgraph::utils::BasicException);
ASSERT_THROW(unix_epoch + memgraph::utils::Duration(std::numeric_limits<int64_t>::min()),
memgraph::utils::BasicException);
}
TEST(TemporalTest, DateSubstraction) {
2022-02-22 20:33:45 +08:00
const auto day_after_unix_epoch = memgraph::utils::Date({1970, 1, 2});
const auto unix_epoch = day_after_unix_epoch - memgraph::utils::Duration({.day = 1});
ASSERT_EQ(unix_epoch, memgraph::utils::Date({1970, 1, 1}));
ASSERT_EQ(memgraph::utils::Date({1971, 1, 1}) - memgraph::utils::Duration({.day = 1}),
memgraph::utils::Date({1970, 12, 31}));
ASSERT_EQ(memgraph::utils::Date({1971, 1, 1}) - memgraph::utils::Duration({.day = -1}),
memgraph::utils::Date({1971, 1, 2}));
ASSERT_THROW(unix_epoch - memgraph::utils::Duration(std::numeric_limits<int64_t>::max()),
memgraph::utils::BasicException);
ASSERT_THROW(unix_epoch - memgraph::utils::Duration(std::numeric_limits<int64_t>::min()),
memgraph::utils::BasicException);
}
TEST(TemporalTest, DateDelta) {
2022-02-22 20:33:45 +08:00
const auto unix_epoch = memgraph::utils::Date({1970, 1, 1});
const auto one_year_after_unix_epoch = memgraph::utils::Date({1971, 1, 1});
ASSERT_EQ(one_year_after_unix_epoch - unix_epoch, memgraph::utils::Duration({.day = 365}));
ASSERT_EQ(unix_epoch - one_year_after_unix_epoch, memgraph::utils::Duration({.day = -365}));
}
TEST(TemporalTest, LocalDateTimeAdditionSubtraction) {
2022-02-22 20:33:45 +08:00
const auto unix_epoch = memgraph::utils::LocalDateTime({1970, 1, 1}, {.hour = 12});
auto one_day_after_unix_epoch = unix_epoch + memgraph::utils::Duration({.hour = 24});
auto one_day_after_unix_epoch_symmetrical = memgraph::utils::Duration({.hour = 24}) + unix_epoch;
ASSERT_EQ(one_day_after_unix_epoch, memgraph::utils::LocalDateTime({1970, 1, 2}, {.hour = 12}));
ASSERT_EQ(one_day_after_unix_epoch_symmetrical, one_day_after_unix_epoch);
2022-02-22 20:33:45 +08:00
const auto one_day_before_unix_epoch = memgraph::utils::LocalDateTime({1969, 12, 31}, {23, 59, 59});
ASSERT_EQ(one_day_before_unix_epoch + memgraph::utils::Duration({.second = 1}),
memgraph::utils::LocalDateTime({1970, 1, 1}, {}));
one_day_after_unix_epoch = unix_epoch + memgraph::utils::Duration({.day = 1});
ASSERT_EQ(one_day_after_unix_epoch, memgraph::utils::LocalDateTime({1970, 1, 2}, {.hour = 12}));
ASSERT_EQ(one_day_after_unix_epoch + memgraph::utils::Duration({.day = -1}), unix_epoch);
ASSERT_EQ(one_day_after_unix_epoch - memgraph::utils::Duration({.day = 1}), unix_epoch);
ASSERT_THROW(one_day_after_unix_epoch + memgraph::utils::Duration(std::numeric_limits<int64_t>::max()),
memgraph::utils::BasicException);
ASSERT_THROW(one_day_after_unix_epoch + memgraph::utils::Duration(std::numeric_limits<int64_t>::min()),
memgraph::utils::BasicException);
ASSERT_THROW(one_day_after_unix_epoch - memgraph::utils::Duration(std::numeric_limits<int64_t>::max()),
memgraph::utils::BasicException);
ASSERT_THROW(one_day_after_unix_epoch - memgraph::utils::Duration(std::numeric_limits<int64_t>::min()),
memgraph::utils::BasicException);
}
TEST(TemporalTest, LocalDateTimeDelta) {
2022-02-22 20:33:45 +08:00
const auto unix_epoch = memgraph::utils::LocalDateTime({1970, 1, 1}, {1, 1, 1});
const auto one_year_after_unix_epoch = memgraph::utils::LocalDateTime({1971, 2, 1}, {12, 1, 1});
const auto two_years_after_unix_epoch = memgraph::utils::LocalDateTime({1972, 2, 1}, {1, 1, 1, 20, 34});
ASSERT_EQ(one_year_after_unix_epoch - unix_epoch, memgraph::utils::Duration({.day = 396, .hour = 11}));
ASSERT_EQ(unix_epoch - one_year_after_unix_epoch, memgraph::utils::Duration({.day = -396, .hour = -11}));
ASSERT_EQ(two_years_after_unix_epoch - unix_epoch,
2022-02-22 20:33:45 +08:00
memgraph::utils::Duration({.day = 761, .millisecond = 20, .microsecond = 34}));
}
TEST(TemporalTest, DateConvertsToString) {
const auto date1 = memgraph::utils::Date({1970, 1, 2});
const std::string date1_expected_str = "1970-01-02";
const auto date2 = memgraph::utils::Date({0000, 1, 1});
const std::string date2_expected_str = "0000-01-01";
const auto date3 = memgraph::utils::Date({2022, 7, 4});
const std::string date3_expected_str = "2022-07-04";
ASSERT_EQ(date1_expected_str, date1.ToString());
ASSERT_EQ(date2_expected_str, date2.ToString());
ASSERT_EQ(date3_expected_str, date3.ToString());
}
TEST(TemporalTest, LocalTimeConvertsToString) {
const auto lt1 = memgraph::utils::LocalTime({13, 2, 40, 100, 50});
const std::string lt1_expected_str = "13:02:40.100050";
const auto lt2 = memgraph::utils::LocalTime({13, 2, 40});
const std::string lt2_expected_str = "13:02:40.000000";
const auto lt3 = memgraph::utils::LocalTime({0, 0, 0});
const std::string lt3_expected_str = "00:00:00.000000";
const auto lt4 = memgraph::utils::LocalTime({3, 2, 4, 6, 7});
const std::string lt4_expected_str = "03:02:04.006007";
ASSERT_EQ(lt1_expected_str, lt1.ToString());
ASSERT_EQ(lt2_expected_str, lt2.ToString());
ASSERT_EQ(lt3_expected_str, lt3.ToString());
ASSERT_EQ(lt4_expected_str, lt4.ToString());
}
TEST(TemporalTest, LocalDateTimeConvertsToString) {
const auto ldt1 = memgraph::utils::LocalDateTime({1970, 1, 2}, {23, 02, 59});
const std::string ldt1_expected_str = "1970-01-02T23:02:59.000000";
const auto ldt2 = memgraph::utils::LocalDateTime({1970, 1, 2}, {23, 02, 59, 456, 123});
const std::string ldt2_expected_str = "1970-01-02T23:02:59.456123";
const auto ldt3 = memgraph::utils::LocalDateTime({1997, 8, 24}, {16, 32, 9});
const std::string ldt3_expected_str = "1997-08-24T16:32:09.000000";
ASSERT_EQ(ldt1_expected_str, ldt1.ToString());
ASSERT_EQ(ldt2_expected_str, ldt2.ToString());
ASSERT_EQ(ldt3_expected_str, ldt3.ToString());
}
TEST(TemporalTest, DurationConvertsToString) {
memgraph::utils::Duration duration1{{.minute = 2, .second = 2, .microsecond = 33}};
const std::string duration1_expected_str = "P0DT0H2M2.000033S";
memgraph::utils::Duration duration2{{.hour = 2.5, .minute = 2, .second = 2, .microsecond = 33}};
const std::string duration2_expected_str = "P0DT2H32M2.000033S";
memgraph::utils::Duration duration3{{.hour = 1.25, .minute = 2, .second = 2}};
const std::string duration3_expected_str = "P0DT1H17M2.000000S";
memgraph::utils::Duration duration4{{.day = 20, .hour = 1.25, .minute = 2, .second = 2}};
const std::string duration4_expected_str = "P20DT1H17M2.000000S";
memgraph::utils::Duration duration5{{.hour = -3, .minute = 2, .second = 2, .microsecond = -33}};
const std::string duration5_expected_str = "P0DT-2H-57M-58.000033S";
memgraph::utils::Duration duration6{{.day = -2, .hour = 3, .minute = 2, .second = 2, .microsecond = 33}};
const std::string duration6_expected_str = "P-1DT-20H-57M-57.999967S";
memgraph::utils::Duration duration7{{.day = 20, .hour = 72, .minute = 154, .second = 312}};
const std::string duration7_expected_str = "P23DT2H39M12.000000S";
memgraph::utils::Duration duration8{{.day = 1, .hour = 23, .minute = 59, .second = 60}};
const std::string duration8_expected_str = "P2DT0H0M0.000000S";
ASSERT_EQ(duration1_expected_str, duration1.ToString());
ASSERT_EQ(duration2_expected_str, duration2.ToString());
ASSERT_EQ(duration3_expected_str, duration3.ToString());
ASSERT_EQ(duration4_expected_str, duration4.ToString());
ASSERT_EQ(duration5_expected_str, duration5.ToString());
ASSERT_EQ(duration6_expected_str, duration6.ToString());
ASSERT_EQ(duration7_expected_str, duration7.ToString());
ASSERT_EQ(duration8_expected_str, duration8.ToString());
}