• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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