1#include <gtest/gtest.h>
5#include <userver/proto-structs/duration.hpp>
6#include <userver/proto-structs/exceptions.hpp>
7#include <userver/utest/assert_macros.hpp>
8#include <userver/utils/impl/internal_tag.hpp>
10using namespace std::literals::chrono_literals;
12USERVER_NAMESPACE_BEGIN
14namespace proto_structs::tests {
16TEST(DurationTest, IsValid) {
17 using OverflowingDuration = std::chrono::duration<std::chrono::seconds::rep, std::chrono::hours::period>;
19 EXPECT_FALSE(Duration::IsValid(Duration::kMinSeconds - 1s, 0ns));
20 EXPECT_FALSE(Duration::IsValid(Duration::kMaxSeconds + 1s, 0ns));
21 EXPECT_FALSE(Duration::IsValid(0s, 1'000'000'000ns));
22 EXPECT_FALSE(Duration::IsValid(0s, -1'000'000'000ns));
23 EXPECT_FALSE(Duration::IsValid(1s, -1ns));
24 EXPECT_FALSE(Duration::IsValid(-1s, 1ns));
26 EXPECT_THROW(Duration(Duration::kMinSeconds - 1s, 0ns), ValueError);
27 EXPECT_THROW(Duration(Duration::kMinSeconds - 1s), ValueError);
28 EXPECT_THROW(Duration{OverflowingDuration::max()}, ValueError);
29 EXPECT_THROW(Duration{OverflowingDuration::min()}, ValueError);
31 Duration(utils::
impl::InternalTag{}, std::numeric_limits<int64_t>::max(), std::numeric_limits<int32_t>::max()),
35 Duration(utils::
impl::InternalTag{}, std::numeric_limits<int64_t>::min(), std::numeric_limits<int32_t>::min()),
38 UEXPECT_THROW_MSG(Duration(987'654'321'000s, 123'456'789ns), ValueError,
"987654321000s.123456789ns");
39 UEXPECT_THROW_MSG((Duration{OverflowingDuration::max()}), ValueError,
"will overflow");
41 EXPECT_TRUE(Duration::IsValid(0s, 0ns));
42 EXPECT_TRUE(Duration::IsValid(0s, 1ns));
43 EXPECT_TRUE(Duration::IsValid(0s, -1ns));
44 EXPECT_TRUE(Duration::IsValid(1s, 1ns));
45 EXPECT_TRUE(Duration::IsValid(-1s, -1ns));
46 EXPECT_TRUE(Duration::IsValid(Duration::Min().Seconds(), Duration::Min().Nanos()));
47 EXPECT_TRUE(Duration::IsValid(Duration::Max().Seconds(), Duration::Max().Nanos()));
50TEST(DurationTest, MinMax) {
51 EXPECT_EQ(Duration::Min().Seconds(), Duration::kMinSeconds);
52 EXPECT_EQ(Duration::Min().Nanos(), -999'999'999ns);
53 EXPECT_EQ(Duration::Max().Seconds(), Duration::kMaxSeconds);
54 EXPECT_EQ(Duration::Max().Nanos(), 999'999'999ns);
57TEST(DurationTest, Conversions) {
60 EXPECT_EQ(d.Seconds(), 0s);
61 EXPECT_EQ(d.Nanos(), 0ns);
63 d = Duration(123s, 987'654'321ns);
65 EXPECT_EQ(d.Seconds(), 123s);
66 EXPECT_EQ(d.Nanos(), 987'654'321ns);
67 ASSERT_TRUE(d.FitsInChronoDuration<std::chrono::minutes>());
68 EXPECT_EQ(d.ToChronoDuration<std::chrono::minutes>(), 2min);
69 EXPECT_EQ(
static_cast<std::chrono::minutes>(d), 2min);
70 EXPECT_EQ(d.ToNanos(), 123'987'654'321ns);
71 EXPECT_EQ(d.ToMicros(), 123'987'654us);
72 EXPECT_EQ(d.ToMillis(), 123'987ms);
74 d = -123'987'654'321ns;
76 EXPECT_EQ(d.Seconds(), -123s);
77 EXPECT_EQ(d.Nanos(), -987'654'321ns);
78 ASSERT_TRUE(d.FitsInChronoDuration<std::chrono::minutes>());
79 EXPECT_EQ(d.ToChronoDuration<std::chrono::minutes>(), -2min);
80 EXPECT_EQ(
static_cast<std::chrono::minutes>(d), -2min);
81 EXPECT_EQ(d.ToNanos(), -123'987'654'321ns);
82 EXPECT_EQ(d.ToMicros(), -123'987'654us);
83 EXPECT_EQ(d.ToMillis(), -123'987ms);
85 d = Duration(utils::
impl::InternalTag{}, 10, 987);
87 EXPECT_EQ(d.Seconds(), 10s);
88 EXPECT_EQ(d.Nanos(), 987ns);
91TEST(DurationTest, SaturateCast) {
92 constexpr auto kMaxSeconds = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::nanoseconds::max());
93 constexpr auto kMinSeconds = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::nanoseconds::min());
94 static_assert(kMaxSeconds < Duration::kMaxSeconds && kMinSeconds > Duration::kMinSeconds);
98 UASSERT_NO_THROW(d = std::chrono::nanoseconds::max());
99 EXPECT_TRUE(d.FitsInChronoDuration<std::chrono::nanoseconds>());
100 EXPECT_EQ(d.ToChronoDuration<std::chrono::nanoseconds>(), std::chrono::nanoseconds::max());
101 EXPECT_EQ(
static_cast<std::chrono::nanoseconds>(d), std::chrono::nanoseconds::max());
102 EXPECT_EQ(d.ToNanos(), std::chrono::nanoseconds::max());
104 UASSERT_NO_THROW(d = std::chrono::nanoseconds::min());
105 EXPECT_TRUE(d.FitsInChronoDuration<std::chrono::nanoseconds>());
106 EXPECT_EQ(d.ToChronoDuration<std::chrono::nanoseconds>(), std::chrono::nanoseconds::min());
107 EXPECT_EQ(
static_cast<std::chrono::nanoseconds>(d), std::chrono::nanoseconds::min());
108 EXPECT_EQ(d.ToNanos(), std::chrono::nanoseconds::min());
110 UASSERT_NO_THROW(d = Duration(kMaxSeconds + 1s, 0ns));
111 EXPECT_FALSE(d.FitsInChronoDuration<std::chrono::nanoseconds>());
112 EXPECT_EQ(d.ToChronoDuration<std::chrono::nanoseconds>(), std::chrono::nanoseconds::max());
113 EXPECT_EQ(
static_cast<std::chrono::nanoseconds>(d), std::chrono::nanoseconds::max());
114 EXPECT_EQ(d.ToNanos(), std::chrono::nanoseconds::max());
116 UASSERT_NO_THROW(d = Duration(kMinSeconds - 1s, 0ns));
117 EXPECT_FALSE(d.FitsInChronoDuration<std::chrono::nanoseconds>());
118 EXPECT_EQ(d.ToChronoDuration<std::chrono::nanoseconds>(), std::chrono::nanoseconds::min());
119 EXPECT_EQ(
static_cast<std::chrono::nanoseconds>(d), std::chrono::nanoseconds::min());
120 EXPECT_EQ(d.ToNanos(), std::chrono::nanoseconds::min());
122 UASSERT_NO_THROW(d = Duration(kMaxSeconds + 1s, 123'456'789ns));
123 EXPECT_FALSE(d.FitsInChronoDuration<std::chrono::nanoseconds>());
124 EXPECT_TRUE(d.FitsInChronoDuration<std::chrono::milliseconds>());
125 EXPECT_EQ(d.ToChronoDuration<std::chrono::milliseconds>(), kMaxSeconds + 1s + 123ms);
126 EXPECT_EQ(
static_cast<std::chrono::milliseconds>(d), kMaxSeconds + 1s + 123ms);
127 EXPECT_EQ(d.ToNanos(), std::chrono::nanoseconds::max());
128 EXPECT_EQ(d.ToMillis(), kMaxSeconds + 1s + 123ms);
130 UASSERT_NO_THROW(d = Duration(kMinSeconds - 1s, -123'456'789ns));
131 EXPECT_FALSE(d.FitsInChronoDuration<std::chrono::nanoseconds>());
132 EXPECT_TRUE(d.FitsInChronoDuration<std::chrono::milliseconds>());
133 EXPECT_EQ(d.ToChronoDuration<std::chrono::milliseconds>(), kMinSeconds - 1s - 123ms);
134 EXPECT_EQ(
static_cast<std::chrono::milliseconds>(d), kMinSeconds - 1s - 123ms);
135 EXPECT_EQ(d.ToNanos(), std::chrono::nanoseconds::min());
136 EXPECT_EQ(d.ToMillis(), kMinSeconds - 1s - 123ms);
139 using TestDuration = std::chrono::duration<std::int16_t, std::pico>;
142 UASSERT_NO_THROW(d = Duration::Min());
143 EXPECT_FALSE(d.FitsInChronoDuration<TestDuration>());
144 EXPECT_EQ(d.ToChronoDuration<TestDuration>(), TestDuration::min());
145 EXPECT_EQ(
static_cast<TestDuration>(d), TestDuration::min());
147 UASSERT_NO_THROW(d = Duration::Max());
148 EXPECT_FALSE(d.FitsInChronoDuration<TestDuration>());
149 EXPECT_EQ(d.ToChronoDuration<TestDuration>(), TestDuration::max());
150 EXPECT_EQ(
static_cast<TestDuration>(d), TestDuration::max());
152 UASSERT_NO_THROW(d = TestDuration::min());
153 EXPECT_TRUE(d.FitsInChronoDuration<TestDuration>());
154 EXPECT_EQ(d.Seconds(), 0s);
155 EXPECT_EQ(d.Nanos(), -32ns);
156 EXPECT_EQ(d.ToChronoDuration<TestDuration>().count(), -32'000);
157 EXPECT_EQ(
static_cast<TestDuration>(d).count(), -32'000);
159 UASSERT_NO_THROW(d = TestDuration::max());
160 EXPECT_TRUE(d.FitsInChronoDuration<TestDuration>());
161 EXPECT_EQ(d.Seconds(), 0s);
162 EXPECT_EQ(d.Nanos(), 32ns);
163 EXPECT_EQ(d.ToChronoDuration<TestDuration>().count(), 32'000);
164 EXPECT_EQ(
static_cast<TestDuration>(d).count(), 32'000);
168 using TestDuration = std::chrono::duration<std::int16_t, std::chrono::weeks::period>;
171 UASSERT_NO_THROW(d = Duration::Min());
172 EXPECT_FALSE(d.FitsInChronoDuration<TestDuration>());
173 EXPECT_EQ(d.ToChronoDuration<TestDuration>(), TestDuration::min());
174 EXPECT_EQ(
static_cast<TestDuration>(d), TestDuration::min());
176 UASSERT_NO_THROW(d = Duration::Max());
177 EXPECT_FALSE(d.FitsInChronoDuration<TestDuration>());
178 EXPECT_EQ(d.ToChronoDuration<TestDuration>(), TestDuration::max());
179 EXPECT_EQ(
static_cast<TestDuration>(d), TestDuration::max());
181 UASSERT_NO_THROW(d = TestDuration::min());
182 EXPECT_TRUE(d.FitsInChronoDuration<TestDuration>());
183 EXPECT_EQ(d.ToChronoDuration<TestDuration>(), TestDuration::min());
184 EXPECT_EQ(
static_cast<TestDuration>(d), TestDuration::min());
186 UASSERT_NO_THROW(d = TestDuration::max());
187 EXPECT_TRUE(d.FitsInChronoDuration<TestDuration>());
188 EXPECT_EQ(d.ToChronoDuration<TestDuration>(), TestDuration::max());
189 EXPECT_EQ(
static_cast<TestDuration>(d), TestDuration::max());