Xclox
C++11 header-only cross-platform date and time library with an asynchronous NTP client
timestamp.h
1 /*
2  * Copyright (c) 2024 Abdullatif Kalla.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE.txt file in the root directory of this source tree.
6  */
7 
8 #include "xclox/ntp/timestamp.hpp"
9 
10 #include "tools/helper.hpp"
11 
12 using namespace xclox::ntp;
13 using namespace std::chrono;
14 
15 TEST_SUITE("Timestamp")
16 {
17  constexpr uint32_t ShortFormMax { std::numeric_limits<uint32_t>::max() };
18  constexpr uint32_t ShortFormMid { ShortFormMax / 2 + 1 };
19  constexpr uint64_t ShortFormLen { ShortFormMax + 1ull };
20  constexpr uint64_t LongFormMax { std::numeric_limits<uint64_t>::max() };
21 
22  TEST_CASE("constant values")
23  {
24  CHECK(ShortFormMid == 0x80000000);
25  CHECK(ShortFormLen == 0x100000000);
26  }
27 
28  TEST_CASE("default constructible to zero")
29  {
30  Timestamp t;
31  CHECK(t.value() == 0);
32  }
33 
34  TEST_CASE("constructible from a raw timestamp value")
35  {
36  Timestamp t1(0);
37  CHECK(t1.value() == 0);
38 
39  Timestamp t2(LongFormMax);
40  CHECK(t2.value() == LongFormMax);
41  }
42 
43  TEST_CASE("constructible from seconds and a fraction")
44  {
45  Timestamp t1(0, 0);
46  CHECK(t1.value() == 0);
47 
48  Timestamp t2(0, ShortFormMax);
49  CHECK(t2.value() == ShortFormMax);
50 
51  Timestamp t3(ShortFormMax, ShortFormMax);
52  CHECK(t3.value() == LongFormMax);
53  }
54 
55  TEST_CASE("constructible from a duration")
56  {
57  Timestamp t1(seconds(0));
58  CHECK(t1.value() == 0);
59 
60  Timestamp t2(seconds(1));
61  CHECK(t2.value() == ShortFormLen);
62 
63  Timestamp t3(milliseconds(500));
64  CHECK(t3.value() == ShortFormMid);
65 
66  Timestamp t4(seconds { ShortFormLen });
67  CHECK(t4.value() == 0);
68 
69  Timestamp t5(seconds { ShortFormLen + 1 });
70  CHECK(t5.value() == ShortFormLen);
71  }
72 
73  TEST_CASE("constructible from a time point")
74  {
75  Timestamp t1(system_clock::time_point {});
76  CHECK(t1.seconds() == xclox::ntp::internal::EpochDeltaSeconds.count());
77  CHECK(t1.fraction() == 0);
78 
79  Timestamp t2(system_clock::time_point { milliseconds(500) - xclox::ntp::internal::EpochDeltaSeconds });
80  CHECK(t2.seconds() == 0);
81  CHECK(t2.fraction() == ShortFormMid);
82 
83  Timestamp t3(system_clock::time_point { seconds(ShortFormLen) - xclox::ntp::internal::EpochDeltaSeconds + milliseconds(500) });
84  CHECK(t3.seconds() == 0);
85  CHECK(t3.fraction() == ShortFormMid);
86  }
87 
88  TEST_CASE("breakable down into seconds and a fraction")
89  {
90  Timestamp t1(0);
91  CHECK(t1.seconds() == 0);
92  CHECK(t1.fraction() == 0);
93 
94  Timestamp t2(ShortFormMax);
95  CHECK(t2.seconds() == 0);
96  CHECK(t2.fraction() == ShortFormMax);
97 
98  Timestamp t3(ShortFormLen);
99  CHECK(t3.seconds() == 1);
100  CHECK(t3.fraction() == 0);
101 
102  Timestamp t4(LongFormMax);
103  CHECK(t4.seconds() == ShortFormMax);
104  CHECK(t4.fraction() == ShortFormMax);
105  }
106 
107  TEST_CASE("convertible into duration")
108  {
109  Timestamp t1(0);
110  CHECK(t1.duration() == seconds(0));
111 
112  Timestamp t2(ShortFormLen);
113  CHECK(t2.duration() == seconds(1));
114 
115  Timestamp t3(ShortFormMid);
116  CHECK(t3.duration() == microseconds(500000));
117 
118  Timestamp t4(LongFormMax);
119  CHECK(t4.duration() == seconds(ShortFormLen) - system_clock::duration(1));
120  }
121 
122  TEST_CASE("retains duration with system clock precision ± 1 unit")
123  {
124  auto currentDuration = system_clock::duration(0);
125  const auto& endDuration = currentDuration + milliseconds(1);
126  while (currentDuration < endDuration) {
127  CHECK(abs((currentDuration - Timestamp(currentDuration).duration()).count()) <= 1);
128  currentDuration = currentDuration + system_clock::duration(1);
129  }
130  }
131 
132  TEST_CASE("comparable")
133  {
134  CHECK(Timestamp() == Timestamp());
135  CHECK(Timestamp(1) == Timestamp(1));
136  CHECK(Timestamp(1, 1) == Timestamp(1, 1));
137  CHECK_FALSE(Timestamp(1) == Timestamp(1, 1));
138  CHECK(Timestamp(system_clock::duration(1)) == Timestamp(system_clock::duration(1)));
139  CHECK(Timestamp() != Timestamp(1));
140  CHECK(Timestamp(1) != Timestamp(1, 1));
141  CHECK(Timestamp(system_clock::duration(0)) != Timestamp(system_clock::duration(1)));
142  CHECK_FALSE(Timestamp(system_clock::duration(1)) != Timestamp(system_clock::duration(1)));
143  }
144 
145  TEST_CASE("subtractable")
146  {
147  CHECK(Timestamp() - Timestamp() == system_clock::duration(0));
148  CHECK(Timestamp(ShortFormLen) - Timestamp(0) == seconds(1));
149  CHECK(Timestamp(0) - Timestamp(ShortFormLen) == -seconds(1));
150  CHECK(Timestamp(LongFormMax) - Timestamp(LongFormMax) == system_clock::duration(0));
151  }
152 } // TEST_SUITE
Timestamp is an immutable class representing a NTP timestamp.
Definition: timestamp.hpp:45
uint64_t value() const
Returns the NTP timestamp in long format.
Definition: timestamp.hpp:87