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