1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "absl/random/internal/iostream_state_saver.h"
16
17 #include <sstream>
18 #include <string>
19
20 #include "gtest/gtest.h"
21
22 namespace {
23
24 using absl::random_internal::make_istream_state_saver;
25 using absl::random_internal::make_ostream_state_saver;
26 using absl::random_internal::stream_precision_helper;
27
28 template <typename T>
29 typename absl::enable_if_t<std::is_integral<T>::value, T> //
StreamRoundTrip(T t)30 StreamRoundTrip(T t) {
31 std::stringstream ss;
32 {
33 auto saver = make_ostream_state_saver(ss);
34 ss.precision(stream_precision_helper<T>::kPrecision);
35 ss << t;
36 }
37 T result = 0;
38 {
39 auto saver = make_istream_state_saver(ss);
40 ss >> result;
41 }
42 EXPECT_FALSE(ss.fail()) //
43 << ss.str() << " " //
44 << (ss.good() ? "good " : "") //
45 << (ss.bad() ? "bad " : "") //
46 << (ss.eof() ? "eof " : "") //
47 << (ss.fail() ? "fail " : "");
48
49 return result;
50 }
51
52 template <typename T>
53 typename absl::enable_if_t<std::is_floating_point<T>::value, T> //
StreamRoundTrip(T t)54 StreamRoundTrip(T t) {
55 std::stringstream ss;
56 {
57 auto saver = make_ostream_state_saver(ss);
58 ss.precision(stream_precision_helper<T>::kPrecision);
59 ss << t;
60 }
61 T result = 0;
62 {
63 auto saver = make_istream_state_saver(ss);
64 result = absl::random_internal::read_floating_point<T>(ss);
65 }
66 EXPECT_FALSE(ss.fail()) //
67 << ss.str() << " " //
68 << (ss.good() ? "good " : "") //
69 << (ss.bad() ? "bad " : "") //
70 << (ss.eof() ? "eof " : "") //
71 << (ss.fail() ? "fail " : "");
72
73 return result;
74 }
75
TEST(IOStreamStateSaver,BasicSaverState)76 TEST(IOStreamStateSaver, BasicSaverState) {
77 std::stringstream ss;
78 ss.precision(2);
79 ss.fill('x');
80 ss.flags(std::ios_base::dec | std::ios_base::right);
81
82 {
83 auto saver = make_ostream_state_saver(ss);
84 ss.precision(10);
85 EXPECT_NE('x', ss.fill());
86 EXPECT_EQ(10, ss.precision());
87 EXPECT_NE(std::ios_base::dec | std::ios_base::right, ss.flags());
88
89 ss << 1.23;
90 }
91
92 EXPECT_EQ('x', ss.fill());
93 EXPECT_EQ(2, ss.precision());
94 EXPECT_EQ(std::ios_base::dec | std::ios_base::right, ss.flags());
95 }
96
TEST(IOStreamStateSaver,RoundTripInts)97 TEST(IOStreamStateSaver, RoundTripInts) {
98 const uint64_t kUintValues[] = {
99 0,
100 1,
101 static_cast<uint64_t>(-1),
102 2,
103 static_cast<uint64_t>(-2),
104
105 1 << 7,
106 1 << 8,
107 1 << 16,
108 1ull << 32,
109 1ull << 50,
110 1ull << 62,
111 1ull << 63,
112
113 (1 << 7) - 1,
114 (1 << 8) - 1,
115 (1 << 16) - 1,
116 (1ull << 32) - 1,
117 (1ull << 50) - 1,
118 (1ull << 62) - 1,
119 (1ull << 63) - 1,
120
121 static_cast<uint64_t>(-(1 << 8)),
122 static_cast<uint64_t>(-(1 << 16)),
123 static_cast<uint64_t>(-(1ll << 32)),
124 static_cast<uint64_t>(-(1ll << 50)),
125 static_cast<uint64_t>(-(1ll << 62)),
126
127 static_cast<uint64_t>(-(1 << 8) - 1),
128 static_cast<uint64_t>(-(1 << 16) - 1),
129 static_cast<uint64_t>(-(1ll << 32) - 1),
130 static_cast<uint64_t>(-(1ll << 50) - 1),
131 static_cast<uint64_t>(-(1ll << 62) - 1),
132 };
133
134 for (const uint64_t u : kUintValues) {
135 EXPECT_EQ(u, StreamRoundTrip<uint64_t>(u));
136
137 int64_t x = static_cast<int64_t>(u);
138 EXPECT_EQ(x, StreamRoundTrip<int64_t>(x));
139
140 double d = static_cast<double>(x);
141 EXPECT_EQ(d, StreamRoundTrip<double>(d));
142
143 float f = d;
144 EXPECT_EQ(f, StreamRoundTrip<float>(f));
145 }
146 }
147
TEST(IOStreamStateSaver,RoundTripFloats)148 TEST(IOStreamStateSaver, RoundTripFloats) {
149 static_assert(
150 stream_precision_helper<float>::kPrecision >= 9,
151 "stream_precision_helper<float>::kPrecision should be at least 9");
152
153 const float kValues[] = {
154 1,
155 std::nextafter(1.0f, 0.0f), // 1 - epsilon
156 std::nextafter(1.0f, 2.0f), // 1 + epsilon
157
158 1.0e+1f,
159 1.0e-1f,
160 1.0e+2f,
161 1.0e-2f,
162 1.0e+10f,
163 1.0e-10f,
164
165 0.00000051110000111311111111f,
166 -0.00000051110000111211111111f,
167
168 1.234678912345678912345e+6f,
169 1.234678912345678912345e-6f,
170 1.234678912345678912345e+30f,
171 1.234678912345678912345e-30f,
172 1.234678912345678912345e+38f,
173 1.0234678912345678912345e-38f,
174
175 // Boundary cases.
176 std::numeric_limits<float>::max(),
177 std::numeric_limits<float>::lowest(),
178 std::numeric_limits<float>::epsilon(),
179 std::nextafter(std::numeric_limits<float>::min(),
180 1.0f), // min + epsilon
181 std::numeric_limits<float>::min(), // smallest normal
182 // There are some errors dealing with denorms on apple platforms.
183 std::numeric_limits<float>::denorm_min(), // smallest denorm
184 std::numeric_limits<float>::min() / 2,
185 std::nextafter(std::numeric_limits<float>::min(),
186 0.0f), // denorm_max
187 std::nextafter(std::numeric_limits<float>::denorm_min(), 1.0f),
188 };
189
190 for (const float f : kValues) {
191 EXPECT_EQ(f, StreamRoundTrip<float>(f));
192 EXPECT_EQ(-f, StreamRoundTrip<float>(-f));
193
194 double d = f;
195 EXPECT_EQ(d, StreamRoundTrip<double>(d));
196 EXPECT_EQ(-d, StreamRoundTrip<double>(-d));
197
198 // Avoid undefined behavior (overflow/underflow).
199 if (f <= static_cast<float>(std::numeric_limits<int64_t>::max()) &&
200 f >= static_cast<float>(std::numeric_limits<int64_t>::lowest())) {
201 int64_t x = static_cast<int64_t>(f);
202 EXPECT_EQ(x, StreamRoundTrip<int64_t>(x));
203 }
204 }
205 }
206
TEST(IOStreamStateSaver,RoundTripDoubles)207 TEST(IOStreamStateSaver, RoundTripDoubles) {
208 static_assert(
209 stream_precision_helper<double>::kPrecision >= 17,
210 "stream_precision_helper<double>::kPrecision should be at least 17");
211
212 const double kValues[] = {
213 1,
214 std::nextafter(1.0, 0.0), // 1 - epsilon
215 std::nextafter(1.0, 2.0), // 1 + epsilon
216
217 1.0e+1,
218 1.0e-1,
219 1.0e+2,
220 1.0e-2,
221 1.0e+10,
222 1.0e-10,
223
224 0.00000051110000111311111111,
225 -0.00000051110000111211111111,
226
227 1.234678912345678912345e+6,
228 1.234678912345678912345e-6,
229 1.234678912345678912345e+30,
230 1.234678912345678912345e-30,
231 1.234678912345678912345e+38,
232 1.0234678912345678912345e-38,
233
234 1.0e+100,
235 1.0e-100,
236 1.234678912345678912345e+308,
237 1.0234678912345678912345e-308,
238 2.22507385850720138e-308,
239
240 // Boundary cases.
241 std::numeric_limits<double>::max(),
242 std::numeric_limits<double>::lowest(),
243 std::numeric_limits<double>::epsilon(),
244 std::nextafter(std::numeric_limits<double>::min(),
245 1.0), // min + epsilon
246 std::numeric_limits<double>::min(), // smallest normal
247 // There are some errors dealing with denorms on apple platforms.
248 std::numeric_limits<double>::denorm_min(), // smallest denorm
249 std::numeric_limits<double>::min() / 2,
250 std::nextafter(std::numeric_limits<double>::min(),
251 0.0), // denorm_max
252 std::nextafter(std::numeric_limits<double>::denorm_min(), 1.0f),
253 };
254
255 for (const double d : kValues) {
256 EXPECT_EQ(d, StreamRoundTrip<double>(d));
257 EXPECT_EQ(-d, StreamRoundTrip<double>(-d));
258
259 // Avoid undefined behavior (overflow/underflow).
260 if (d <= std::numeric_limits<float>::max() &&
261 d >= std::numeric_limits<float>::lowest()) {
262 float f = static_cast<float>(d);
263 EXPECT_EQ(f, StreamRoundTrip<float>(f));
264 }
265
266 // Avoid undefined behavior (overflow/underflow).
267 if (d <= static_cast<double>(std::numeric_limits<int64_t>::max()) &&
268 d >= static_cast<double>(std::numeric_limits<int64_t>::lowest())) {
269 int64_t x = static_cast<int64_t>(d);
270 EXPECT_EQ(x, StreamRoundTrip<int64_t>(x));
271 }
272 }
273 }
274
275 #if !defined(__EMSCRIPTEN__)
TEST(IOStreamStateSaver,RoundTripLongDoubles)276 TEST(IOStreamStateSaver, RoundTripLongDoubles) {
277 // Technically, C++ only guarantees that long double is at least as large as a
278 // double. Practically it varies from 64-bits to 128-bits.
279 //
280 // So it is best to consider long double a best-effort extended precision
281 // type.
282
283 static_assert(
284 stream_precision_helper<long double>::kPrecision >= 36,
285 "stream_precision_helper<long double>::kPrecision should be at least 36");
286
287 using real_type = long double;
288 const real_type kValues[] = {
289 1,
290 std::nextafter(1.0, 0.0), // 1 - epsilon
291 std::nextafter(1.0, 2.0), // 1 + epsilon
292
293 1.0e+1,
294 1.0e-1,
295 1.0e+2,
296 1.0e-2,
297 1.0e+10,
298 1.0e-10,
299
300 0.00000051110000111311111111,
301 -0.00000051110000111211111111,
302
303 1.2346789123456789123456789123456789e+6,
304 1.2346789123456789123456789123456789e-6,
305 1.2346789123456789123456789123456789e+30,
306 1.2346789123456789123456789123456789e-30,
307 1.2346789123456789123456789123456789e+38,
308 1.2346789123456789123456789123456789e-38,
309 1.2346789123456789123456789123456789e+308,
310 1.2346789123456789123456789123456789e-308,
311
312 1.0e+100,
313 1.0e-100,
314 1.234678912345678912345e+308,
315 1.0234678912345678912345e-308,
316
317 // Boundary cases.
318 std::numeric_limits<real_type>::max(),
319 std::numeric_limits<real_type>::lowest(),
320 std::numeric_limits<real_type>::epsilon(),
321 std::nextafter(std::numeric_limits<real_type>::min(),
322 real_type(1)), // min + epsilon
323 std::numeric_limits<real_type>::min(), // smallest normal
324 // There are some errors dealing with denorms on apple platforms.
325 std::numeric_limits<real_type>::denorm_min(), // smallest denorm
326 std::numeric_limits<real_type>::min() / 2,
327 std::nextafter(std::numeric_limits<real_type>::min(),
328 0.0), // denorm_max
329 std::nextafter(std::numeric_limits<real_type>::denorm_min(), 1.0f),
330 };
331
332 int index = -1;
333 for (const long double dd : kValues) {
334 index++;
335 EXPECT_EQ(dd, StreamRoundTrip<real_type>(dd)) << index;
336 EXPECT_EQ(-dd, StreamRoundTrip<real_type>(-dd)) << index;
337
338 // Avoid undefined behavior (overflow/underflow).
339 if (dd <= std::numeric_limits<double>::max() &&
340 dd >= std::numeric_limits<double>::lowest()) {
341 double d = static_cast<double>(dd);
342 EXPECT_EQ(d, StreamRoundTrip<double>(d));
343 }
344
345 // Avoid undefined behavior (overflow/underflow).
346 if (dd <= std::numeric_limits<int64_t>::max() &&
347 dd >= std::numeric_limits<int64_t>::lowest()) {
348 int64_t x = static_cast<int64_t>(dd);
349 EXPECT_EQ(x, StreamRoundTrip<int64_t>(x));
350 }
351 }
352 }
353 #endif // !defined(__EMSCRIPTEN__)
354
TEST(StrToDTest,DoubleMin)355 TEST(StrToDTest, DoubleMin) {
356 const char kV[] = "2.22507385850720138e-308";
357 char* end;
358 double x = std::strtod(kV, &end);
359 EXPECT_EQ(std::numeric_limits<double>::min(), x);
360 // errno may equal ERANGE.
361 }
362
TEST(StrToDTest,DoubleDenormMin)363 TEST(StrToDTest, DoubleDenormMin) {
364 const char kV[] = "4.94065645841246544e-324";
365 char* end;
366 double x = std::strtod(kV, &end);
367 EXPECT_EQ(std::numeric_limits<double>::denorm_min(), x);
368 // errno may equal ERANGE.
369 }
370
371 } // namespace
372