iostream_state_saver_test.cc (11359B)
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> // 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> // 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 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 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 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 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 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 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 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