1021 lines · cpp
1//===-- unittests/Runtime/NumericalFormatTest.cpp ---------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "CrashHandlerFixture.h"10#include "flang-rt/runtime/descriptor.h"11#include "flang/Runtime/io-api.h"12#include <algorithm>13#include <array>14#include <cstring>15#include <gtest/gtest.h>16#include <tuple>17 18using namespace Fortran::runtime;19using namespace Fortran::runtime::io;20 21static bool CompareFormattedStrings(22 const std::string &expect, const std::string &got) {23 std::string want{expect};24 want.resize(got.size(), ' ');25 return want == got;26}27 28static bool CompareFormattedStrings(29 const char *expect, const std::string &&got) {30 return CompareFormattedStrings(std::string(expect), std::move(got));31}32 33// Perform format and compare the result with expected value34static bool CompareFormatReal(35 const char *format, double x, const char *expect, std::string &got) {36 char buffer[800];37 auto cookie{IONAME(BeginInternalFormattedOutput)(38 buffer, sizeof buffer, format, std::strlen(format))};39 EXPECT_TRUE(IONAME(OutputReal64)(cookie, x));40 auto status{IONAME(EndIoStatement)(cookie)};41 EXPECT_EQ(status, 0);42 got = std::string{buffer, sizeof buffer};43 auto lastNonBlank{got.find_last_not_of(" ")};44 if (lastNonBlank != std::string::npos) {45 got.resize(lastNonBlank + 1);46 }47 return CompareFormattedStrings(expect, got);48}49 50// Convert raw uint64 into double, perform format, and compare with expected51static bool CompareFormatReal(const char *format, std::uint64_t xInt,52 const char *expect, std::string &got) {53 double x;54 static_assert(sizeof(double) == sizeof(std::uint64_t),55 "Size of double != size of uint64_t!");56 std::memcpy(&x, &xInt, sizeof xInt);57 return CompareFormatReal(format, x, expect, got);58}59 60static bool CompareFormatInteger(61 const char *format, std::int64_t x, const char *expect, std::string &got) {62 char buffer[800];63 auto cookie{IONAME(BeginInternalFormattedOutput)(64 buffer, sizeof buffer, format, std::strlen(format))};65 EXPECT_TRUE(IONAME(OutputInteger64)(cookie, x));66 auto status{IONAME(EndIoStatement)(cookie)};67 EXPECT_EQ(status, 0);68 got = std::string{buffer, sizeof buffer};69 auto lastNonBlank{got.find_last_not_of(" ")};70 if (lastNonBlank != std::string::npos) {71 got.resize(lastNonBlank + 1);72 }73 return CompareFormattedStrings(expect, got);74}75 76struct IOApiTests : CrashHandlerFixture {};77 78TEST(IOApiTests, HelloWorldOutputTest) {79 static constexpr int bufferSize{32};80 char buffer[bufferSize];81 82 // Create format for all types and values to be written83 const char *format{"(6HHELLO,,A6,2X,I3,1X,'0x',Z8,1X,L1)"};84 auto cookie{IONAME(BeginInternalFormattedOutput)(85 buffer, bufferSize, format, std::strlen(format))};86 87 // Write string, integer, and logical values to buffer88 IONAME(OutputAscii)(cookie, "WORLD", 5);89 IONAME(OutputInteger64)(cookie, 678);90 IONAME(OutputInteger32)(cookie, 0xfeedface);91 IONAME(OutputLogical)(cookie, true);92 93 // Ensure IO succeeded94 auto status{IONAME(EndIoStatement)(cookie)};95 ASSERT_EQ(status, 0) << "hello: '" << format << "' failed, status "96 << static_cast<int>(status);97 98 // Ensure final buffer matches expected string output99 static const std::string expect{"HELLO, WORLD 678 0xFEEDFACE T"};100 ASSERT_TRUE(101 CompareFormattedStrings(expect, std::string{buffer, sizeof buffer}))102 << "Expected '" << expect << "', got " << buffer;103}104 105TEST(IOApiTests, MultilineOutputTest) {106 // Allocate buffer for multiline output107 static constexpr int numLines{5};108 static constexpr int lineLength{32};109 char buffer[numLines][lineLength];110 111 // Create descriptor for entire buffer112 static constexpr int staticDescriptorMaxRank{1};113 StaticDescriptor<staticDescriptorMaxRank> wholeStaticDescriptor;114 Descriptor &whole{wholeStaticDescriptor.descriptor()};115 static const SubscriptValue extent[]{numLines};116 whole.Establish(TypeCode{CFI_type_char}, /*elementBytes=*/lineLength, &buffer,117 staticDescriptorMaxRank, extent, CFI_attribute_pointer);118 whole.Dump(stderr);119 whole.Check();120 121 // Create descriptor for buffer section122 StaticDescriptor<staticDescriptorMaxRank> sectionStaticDescriptor;123 Descriptor §ion{sectionStaticDescriptor.descriptor()};124 static const SubscriptValue lowers[]{0}, uppers[]{4}, strides[]{1};125 section.Establish(whole.type(), /*elementBytes=*/whole.ElementBytes(),126 nullptr, /*maxRank=*/staticDescriptorMaxRank, extent,127 CFI_attribute_pointer);128 129 // Ensure C descriptor address `section.raw()` is updated without error130 const auto error{131 CFI_section(§ion.raw(), &whole.raw(), lowers, uppers, strides)};132 ASSERT_EQ(error, 0) << "multiline: CFI_section failed: " << error;133 section.Dump(stderr);134 section.Check();135 136 // Create format string and initialize IO operation137 const char *format{138 "('?abcde,',T1,'>',T9,A,TL12,A,TR25,'<'//G0,17X,'abcd',1(2I4))"};139 auto cookie{IONAME(BeginInternalArrayFormattedOutput)(140 section, format, std::strlen(format))};141 142 // Fill last line with periods143 std::memset(buffer[numLines - 1], '.', lineLength);144 145 // Write data to buffer146 IONAME(OutputAscii)(cookie, "WORLD", 5);147 IONAME(OutputAscii)(cookie, "HELLO", 5);148 IONAME(OutputInteger64)(cookie, 789);149 for (int j{666}; j <= 999; j += 111) {150 IONAME(OutputInteger64)(cookie, j);151 }152 153 // Ensure no errors occured in write operations above154 const auto status{IONAME(EndIoStatement)(cookie)};155 ASSERT_EQ(status, 0) << "multiline: '" << format << "' failed, status "156 << static_cast<int>(status);157 158 static const std::string expect{">HELLO, WORLD <"159 " "160 "789 abcd 666 777"161 " 888 999 "162 "................................"};163 // Ensure formatted string matches expected output164 EXPECT_TRUE(165 CompareFormattedStrings(expect, std::string{buffer[0], sizeof buffer}))166 << "Expected '" << expect << "' but got '"167 << std::string{buffer[0], sizeof buffer} << "'";168}169 170TEST(IOApiTests, ListInputTest) {171 static const char input[]{",1*,(5.,6.),(7.0,8.0)"};172 auto cookie{IONAME(BeginInternalListInput)(input, sizeof input - 1)};173 174 // Create real values for IO tests175 static constexpr int numRealValues{8};176 float z[numRealValues];177 for (int j{0}; j < numRealValues; ++j) {178 z[j] = -(j + 1);179 }180 181 // Ensure reading complex values to floats does not result in an error182 for (int j{0}; j < numRealValues; j += 2) {183 ASSERT_TRUE(IONAME(InputComplex32)(cookie, &z[j]))184 << "InputComplex32 failed with value " << z[j];185 }186 187 // Ensure no IO errors occured during IO operations above188 auto status{IONAME(EndIoStatement)(cookie)};189 ASSERT_EQ(status, 0) << "Failed complex list-directed input, status "190 << static_cast<int>(status);191 192 // Ensure writing complex values from floats does not result in an error193 static constexpr int bufferSize{39};194 char output[bufferSize];195 output[bufferSize - 1] = '\0';196 cookie = IONAME(BeginInternalListOutput)(output, bufferSize - 1);197 for (int j{0}; j < numRealValues; j += 2) {198 ASSERT_TRUE(IONAME(OutputComplex32)(cookie, z[j], z[j + 1]))199 << "OutputComplex32 failed when outputting value " << z[j] << ", "200 << z[j + 1];201 }202 203 // Ensure no IO errors occured during IO operations above204 status = IONAME(EndIoStatement)(cookie);205 ASSERT_EQ(status, 0) << "Failed complex list-directed output, status "206 << static_cast<int>(status);207 208 // Verify output buffer against expected value209 static const char expect[bufferSize]{210 " (-1.,-2.) (-3.,-4.) (5.,6.) (7.,8.) "};211 ASSERT_EQ(std::strncmp(output, expect, bufferSize), 0)212 << "Failed complex list-directed output, expected '" << expect213 << "', but got '" << output << "'";214}215 216TEST(IOApiTests, ListInputComplexRegressionTest) {217 static const char input[]{"(1,;2, );(3,;4,)"};218 auto cookie{IONAME(BeginInternalListInput)(input, sizeof input - 1)};219 static constexpr int numRealValues{4};220 float z[numRealValues];221 ASSERT_TRUE(IONAME(SetDecimal)(cookie, "COMMA", 5));222 for (int j{0}; j < numRealValues; j += 2) {223 ASSERT_TRUE(IONAME(InputComplex32)(cookie, &z[j]))224 << "InputComplex32 failed with value " << z[j];225 }226 auto status{IONAME(EndIoStatement)(cookie)};227 ASSERT_EQ(status, 0) << "Failed complex list-directed input, status "228 << static_cast<int>(status);229 static constexpr int bufferSize{18};230 char output[bufferSize];231 output[bufferSize - 1] = '\0';232 cookie = IONAME(BeginInternalListOutput)(output, bufferSize - 1);233 for (int j{0}; j < numRealValues; j += 2) {234 ASSERT_TRUE(IONAME(OutputComplex32)(cookie, z[j], z[j + 1]))235 << "OutputComplex32 failed when outputting value " << z[j] << ", "236 << z[j + 1];237 }238 status = IONAME(EndIoStatement)(cookie);239 ASSERT_EQ(status, 0) << "Failed complex list-directed output, status "240 << static_cast<int>(status);241 static const char expect[bufferSize]{" (1.,2.) (3.,4.) "};242 ASSERT_EQ(std::strncmp(output, expect, bufferSize), 0)243 << "Failed complex list-directed output, expected '" << expect244 << "', but got '" << output << "'";245}246 247TEST(IOApiTests, DescriptorOutputTest) {248 static constexpr int bufferSize{10};249 char buffer[bufferSize];250 const char *format{"(2A4)"};251 auto cookie{IONAME(BeginInternalFormattedOutput)(252 buffer, bufferSize, format, std::strlen(format))};253 254 // Create descriptor for output255 static constexpr int staticDescriptorMaxRank{1};256 StaticDescriptor<staticDescriptorMaxRank> staticDescriptor;257 Descriptor &desc{staticDescriptor.descriptor()};258 static constexpr int subscriptExtent{2};259 static const SubscriptValue extent[]{subscriptExtent};260 261 // Manually write to descriptor buffer262 static constexpr int dataLength{4};263 char data[subscriptExtent][dataLength];264 std::memcpy(data[0], "ABCD", dataLength);265 std::memcpy(data[1], "EFGH", dataLength);266 desc.Establish(TypeCode{CFI_type_char}, dataLength, &data,267 staticDescriptorMaxRank, extent);268 desc.Dump(stderr);269 desc.Check();270 IONAME(OutputDescriptor)(cookie, desc);271 272 // Ensure no errors were encountered in initializing the cookie and descriptor273 auto formatStatus{IONAME(EndIoStatement)(cookie)};274 ASSERT_EQ(formatStatus, 0)275 << "descrOutputTest: '" << format << "' failed, status "276 << static_cast<int>(formatStatus);277 278 // Ensure buffer matches expected output279 EXPECT_TRUE(280 CompareFormattedStrings("ABCDEFGH ", std::string{buffer, sizeof buffer}))281 << "descrOutputTest: formatted: got '"282 << std::string{buffer, sizeof buffer} << "'";283 284 // Begin list-directed output on cookie by descriptor285 cookie = IONAME(BeginInternalListOutput)(buffer, sizeof buffer);286 IONAME(OutputDescriptor)(cookie, desc);287 288 // Ensure list-directed output does not result in an IO error289 auto listDirectedStatus{IONAME(EndIoStatement)(cookie)};290 ASSERT_EQ(listDirectedStatus, 0)291 << "descrOutputTest: list-directed failed, status "292 << static_cast<int>(listDirectedStatus);293 294 // Ensure buffer matches expected output295 EXPECT_TRUE(296 CompareFormattedStrings(" ABCDEFGH ", std::string{buffer, sizeof buffer}))297 << "descrOutputTest: list-directed: got '"298 << std::string{buffer, sizeof buffer} << "'";299}300 301//------------------------------------------------------------------------------302/// Tests for output formatting real values303//------------------------------------------------------------------------------304 305TEST(IOApiTests, FormatZeroes) {306 static constexpr std::pair<const char *, const char *> zeroes[]{307 {"(E32.17,';')", " 0.00000000000000000E+00;"},308 {"(F32.17,';')", " 0.00000000000000000;"},309 {"(G32.17,';')", " 0.0000000000000000 ;"},310 {"(DC,E32.17,';')", " 0,00000000000000000E+00;"},311 {"(DC,F32.17,';')", " 0,00000000000000000;"},312 {"(DC,G32.17,';')", " 0,0000000000000000 ;"},313 {"(D32.17,';')", " 0.00000000000000000D+00;"},314 {"(E32.17E1,';')", " 0.00000000000000000E+0;"},315 {"(G32.17E1,';')", " 0.0000000000000000 ;"},316 {"(E32.17E0,';')", " 0.00000000000000000E+0;"},317 {"(G32.17E0,';')", " 0.0000000000000000 ;"},318 {"(1P,E32.17,';')", " 0.00000000000000000E+00;"},319 {"(1PE32.17,';')", " 0.00000000000000000E+00;"}, // no comma320 {"(1P,F32.17,';')", " 0.00000000000000000;"},321 {"(1P,G32.17,';')", " 0.0000000000000000 ;"},322 {"(2P,E32.17,';')", " 00.0000000000000000E+00;"},323 {"(-1P,E32.17,';')", " 0.00000000000000000E+00;"},324 {"(EX32.17,';')", " 0X0.00000000000000000P+0;"},325 {"(DC,EX32.17,';')", " 0X0,00000000000000000P+0;"},326 {"(G0,';')", "0.;"},327 };328 329 for (auto const &[format, expect] : zeroes) {330 std::string got;331 ASSERT_TRUE(CompareFormatReal(format, 0.0, expect, got))332 << "Failed to format " << format << ", expected '" << expect333 << "', got '" << got << "'";334 }335}336 337TEST(IOApiTests, FormatOnes) {338 static constexpr std::pair<const char *, const char *> ones[]{339 {"(E32.17,';')", " 0.10000000000000000E+01;"},340 {"(F32.17,';')", " 1.00000000000000000;"},341 {"(G32.17,';')", " 1.0000000000000000 ;"},342 {"(E32.17E1,';')", " 0.10000000000000000E+1;"},343 {"(G32.17E1,';')", " 1.0000000000000000 ;"},344 {"(E32.17E0,';')", " 0.10000000000000000E+1;"},345 {"(G32.17E0,';')", " 1.0000000000000000 ;"},346 {"(E32.17E4,';')", " 0.10000000000000000E+0001;"},347 {"(G32.17E4,';')", " 1.0000000000000000 ;"},348 {"(1P,E32.17,';')", " 1.00000000000000000E+00;"},349 {"(1PE32.17,';')", " 1.00000000000000000E+00;"}, // no comma350 {"(1P,F32.17,';')", " 10.00000000000000000;"},351 {"(1P,G32.17,';')", " 1.0000000000000000 ;"},352 {"(ES32.17,';')", " 1.00000000000000000E+00;"},353 {"(2P,E32.17,';')", " 10.0000000000000000E-01;"},354 {"(2P,G32.17,';')", " 1.0000000000000000 ;"},355 {"(-1P,E32.17,';')", " 0.01000000000000000E+02;"},356 {"(-1P,G32.17,';')", " 1.0000000000000000 ;"},357 {"(EX32.17,';')", " 0X8.00000000000000000P-3;"},358 {"(DC,EX32.17,';')", " 0X8,00000000000000000P-3;"},359 {"(G0,';')", "1.;"},360 };361 362 for (auto const &[format, expect] : ones) {363 std::string got;364 ASSERT_TRUE(CompareFormatReal(format, 1.0, expect, got))365 << "Failed to format " << format << ", expected '" << expect366 << "', got '" << got << "'";367 }368}369 370TEST(IOApiTests, FormatNegativeOnes) {371 static constexpr std::tuple<const char *, const char *> negOnes[]{372 {"(E32.17,';')", " -0.10000000000000000E+01;"},373 {"(F32.17,';')", " -1.00000000000000000;"},374 {"(G32.17,';')", " -1.0000000000000000 ;"},375 {"(EX32.17,';')", " -0X8.00000000000000000P-3;"},376 {"(G0,';')", "-1.;"},377 };378 for (auto const &[format, expect] : negOnes) {379 std::string got;380 ASSERT_TRUE(CompareFormatReal(format, -1.0, expect, got))381 << "Failed to format " << format << ", expected '" << expect382 << "', got '" << got << "'";383 }384}385 386// Each test case contains a raw uint64, a format string for a real value, and387// the expected resulting string from formatting the raw uint64. The double388// representation of the uint64 is commented above each test case.389TEST(IOApiTests, FormatDoubleValues) {390 391 using TestCaseTy = std::tuple<std::uint64_t,392 std::vector<std::tuple<const char *, const char *>>>;393 static const std::vector<TestCaseTy> testCases{394 {// -0395 0x8000000000000000,396 {397 {"(E9.1,';')", " -0.0E+00;"},398 {"(F4.0,';')", " -0.;"},399 {"(F0.1,';')", "-.0;"},400 {"(G8.0,';')", "-0.0E+00;"},401 {"(G8.1,';')", " -0. ;"},402 {"(G0,';')", "-0.;"},403 {"(E9.1,';')", " -0.0E+00;"},404 {"(EX9.1,';')", "-0X0.0P+0;"},405 }},406 {// +Inf407 0x7ff0000000000000,408 {409 {"(E9.1,';')", " Inf;"},410 {"(F9.1,';')", " Inf;"},411 {"(G9.1,';')", " Inf;"},412 {"(EX9.1,';')", " Inf;"},413 {"(SP,E9.1,';')", " +Inf;"},414 {"(SP,F9.1,';')", " +Inf;"},415 {"(SP,G9.1,';')", " +Inf;"},416 {"(SP,EX9.1,';')", " +Inf;"},417 {"(G0,';')", "Inf;"},418 }},419 {// -Inf420 0xfff0000000000000,421 {422 {"(E9.1,';')", " -Inf;"},423 {"(F9.1,';')", " -Inf;"},424 {"(G9.1,';')", " -Inf;"},425 {"(EX9.1,';')", " -Inf;"},426 {"(G0,';')", "-Inf;"},427 }},428 {// NaN429 0x7ff0000000000001,430 {431 {"(E9.1,';')", " NaN;"},432 {"(F9.1,';')", " NaN;"},433 {"(G9.1,';')", " NaN;"},434 {"(EX9.1,';')", " NaN;"},435 {"(G0,';')", "NaN;"},436 }},437 {// NaN (sign irrelevant)438 0xfff0000000000001,439 {440 {"(E9.1,';')", " NaN;"},441 {"(F9.1,';')", " NaN;"},442 {"(G9.1,';')", " NaN;"},443 {"(SP,E9.1,';')", " NaN;"},444 {"(SP,F9.1,';')", " NaN;"},445 {"(SP,G9.1,';')", " NaN;"},446 {"(SP,EX9.1,';')", " NaN;"},447 {"(G0,';')", "NaN;"},448 }},449 {// 0.1 rounded450 0x3fb999999999999a,451 {452 {"(E62.55,';')",453 " 0.1000000000000000055511151231257827021181583404541015625E+"454 "00;"},455 {"(E0.1,';')", ".1E+00;"},456 {"(E0.55,';')",457 ".1000000000000000055511151231257827021181583404541015625E+"458 "00;"},459 {"(E0,';')", ".1E+00;"},460 {"(F58.55,';')",461 " 0."462 "1000000000000000055511151231257827021181583404541015625;"},463 {"(F0.0,';')", "0.;"},464 {"(F0.55,';')",465 ".1000000000000000055511151231257827021181583404541015625;"},466 {"(F0,';')", ".1;"},467 {"(G62.55,';')",468 " 0.1000000000000000055511151231257827021181583404541015625 "469 " ;"},470 {"(G0.0,';')", "0.;"},471 {"(G0.55,';')",472 ".1000000000000000055511151231257827021181583404541015625;"},473 {"(G0,';')", ".1;"},474 {"(EX20.12,';')", " 0XC.CCCCCCCCCCCDP-7;"},475 }},476 {// 1.5477 0x3ff8000000000000,478 {479 {"(E9.2,';')", " 0.15E+01;"},480 {"(F4.1,';')", " 1.5;"},481 {"(G7.1,';')", " 2. ;"},482 {"(EX9.1,';')", " 0XC.0P-3;"},483 {"(RN,E8.1,';')", " 0.2E+01;"},484 {"(RN,F3.0,';')", " 2.;"},485 {"(RN,G7.0,';')", " 0.E+01;"},486 {"(RN,G7.1,';')", " 2. ;"},487 {"(RD,E8.1,';')", " 0.1E+01;"},488 {"(RD,F3.0,';')", " 1.;"},489 {"(RD,G7.0,';')", " 0.E+01;"},490 {"(RD,G7.1,';')", " 1. ;"},491 {"(RU,E8.1,';')", " 0.2E+01;"},492 {"(RU,G7.0,';')", " 0.E+01;"},493 {"(RU,G7.1,';')", " 2. ;"},494 {"(RZ,E8.1,';')", " 0.1E+01;"},495 {"(RZ,F3.0,';')", " 1.;"},496 {"(RZ,G7.0,';')", " 0.E+01;"},497 {"(RZ,G7.1,';')", " 1. ;"},498 {"(RC,E8.1,';')", " 0.2E+01;"},499 {"(RC,F3.0,';')", " 2.;"},500 {"(RC,G7.0,';')", " 0.E+01;"},501 {"(RC,G7.1,';')", " 2. ;"},502 }},503 {// -1.5504 0xbff8000000000000,505 {506 {"(E9.2,';')", "-0.15E+01;"},507 {"(RN,E8.1,';')", "-0.2E+01;"},508 {"(RD,E8.1,';')", "-0.2E+01;"},509 {"(RU,E8.1,';')", "-0.1E+01;"},510 {"(RZ,E8.1,';')", "-0.1E+01;"},511 {"(RC,E8.1,';')", "-0.2E+01;"},512 {"(EX9.1,';')", "-0XC.0P-3;"},513 }},514 {// 2.5515 0x4004000000000000,516 {517 {"(E9.2,';')", " 0.25E+01;"},518 {"(RN,E8.1,';')", " 0.2E+01;"},519 {"(RD,E8.1,';')", " 0.2E+01;"},520 {"(RU,E8.1,';')", " 0.3E+01;"},521 {"(RZ,E8.1,';')", " 0.2E+01;"},522 {"(RC,E8.1,';')", " 0.3E+01;"},523 {"(EX9.1,';')", " 0XA.0P-2;"},524 }},525 {// -2.5526 0xc004000000000000,527 {528 {"(E9.2,';')", "-0.25E+01;"},529 {"(RN,E8.1,';')", "-0.2E+01;"},530 {"(RD,E8.1,';')", "-0.3E+01;"},531 {"(RU,E8.1,';')", "-0.2E+01;"},532 {"(RZ,E8.1,';')", "-0.2E+01;"},533 {"(RC,E8.1,';')", "-0.3E+01;"},534 {"(EX9.1,';')", "-0XA.0P-2;"},535 }},536 {// least positive nonzero subnormal537 1,538 {539 {"(E32.17,';')", " 0.49406564584124654-323;"},540 {"(ES32.17,';')", " 4.94065645841246544-324;"},541 {"(EN32.17,';')", " 4.94065645841246544-324;"},542 {"(E759.752,';')",543 " 0."544 "494065645841246544176568792868221372365059802614324764425585"545 "682500675507270208751865299836361635992379796564695445717730"546 "926656710355939796398774796010781878126300713190311404527845"547 "817167848982103688718636056998730723050006387409153564984387"548 "312473397273169615140031715385398074126238565591171026658556"549 "686768187039560310624931945271591492455329305456544401127480"550 "129709999541931989409080416563324524757147869014726780159355"551 "238611550134803526493472019379026810710749170333222684475333"552 "572083243193609238289345836806010601150616980975307834227731"553 "832924790498252473077637592724787465608477820373446969953364"554 "701797267771758512566055119913150489110145103786273816725095"555 "583738973359899366480994116420570263709027924276754456522908"556 "75386825064197182655334472656250-323;"},557 {"(G0,';')", ".5E-323;"},558 {"(E757.750,';')",559 " 0."560 "494065645841246544176568792868221372365059802614324764425585"561 "682500675507270208751865299836361635992379796564695445717730"562 "926656710355939796398774796010781878126300713190311404527845"563 "817167848982103688718636056998730723050006387409153564984387"564 "312473397273169615140031715385398074126238565591171026658556"565 "686768187039560310624931945271591492455329305456544401127480"566 "129709999541931989409080416563324524757147869014726780159355"567 "238611550134803526493472019379026810710749170333222684475333"568 "572083243193609238289345836806010601150616980975307834227731"569 "832924790498252473077637592724787465608477820373446969953364"570 "701797267771758512566055119913150489110145103786273816725095"571 "583738973359899366480994116420570263709027924276754456522908"572 "753868250641971826553344726562-323;"},573 {"(RN,E757.750,';')",574 " 0."575 "494065645841246544176568792868221372365059802614324764425585"576 "682500675507270208751865299836361635992379796564695445717730"577 "926656710355939796398774796010781878126300713190311404527845"578 "817167848982103688718636056998730723050006387409153564984387"579 "312473397273169615140031715385398074126238565591171026658556"580 "686768187039560310624931945271591492455329305456544401127480"581 "129709999541931989409080416563324524757147869014726780159355"582 "238611550134803526493472019379026810710749170333222684475333"583 "572083243193609238289345836806010601150616980975307834227731"584 "832924790498252473077637592724787465608477820373446969953364"585 "701797267771758512566055119913150489110145103786273816725095"586 "583738973359899366480994116420570263709027924276754456522908"587 "753868250641971826553344726562-323;"},588 {"(RD,E757.750,';')",589 " 0."590 "494065645841246544176568792868221372365059802614324764425585"591 "682500675507270208751865299836361635992379796564695445717730"592 "926656710355939796398774796010781878126300713190311404527845"593 "817167848982103688718636056998730723050006387409153564984387"594 "312473397273169615140031715385398074126238565591171026658556"595 "686768187039560310624931945271591492455329305456544401127480"596 "129709999541931989409080416563324524757147869014726780159355"597 "238611550134803526493472019379026810710749170333222684475333"598 "572083243193609238289345836806010601150616980975307834227731"599 "832924790498252473077637592724787465608477820373446969953364"600 "701797267771758512566055119913150489110145103786273816725095"601 "583738973359899366480994116420570263709027924276754456522908"602 "753868250641971826553344726562-323;"},603 {"(RU,E757.750,';')",604 " 0."605 "494065645841246544176568792868221372365059802614324764425585"606 "682500675507270208751865299836361635992379796564695445717730"607 "926656710355939796398774796010781878126300713190311404527845"608 "817167848982103688718636056998730723050006387409153564984387"609 "312473397273169615140031715385398074126238565591171026658556"610 "686768187039560310624931945271591492455329305456544401127480"611 "129709999541931989409080416563324524757147869014726780159355"612 "238611550134803526493472019379026810710749170333222684475333"613 "572083243193609238289345836806010601150616980975307834227731"614 "832924790498252473077637592724787465608477820373446969953364"615 "701797267771758512566055119913150489110145103786273816725095"616 "583738973359899366480994116420570263709027924276754456522908"617 "753868250641971826553344726563-323;"},618 {"(RC,E757.750,';')",619 " 0."620 "494065645841246544176568792868221372365059802614324764425585"621 "682500675507270208751865299836361635992379796564695445717730"622 "926656710355939796398774796010781878126300713190311404527845"623 "817167848982103688718636056998730723050006387409153564984387"624 "312473397273169615140031715385398074126238565591171026658556"625 "686768187039560310624931945271591492455329305456544401127480"626 "129709999541931989409080416563324524757147869014726780159355"627 "238611550134803526493472019379026810710749170333222684475333"628 "572083243193609238289345836806010601150616980975307834227731"629 "832924790498252473077637592724787465608477820373446969953364"630 "701797267771758512566055119913150489110145103786273816725095"631 "583738973359899366480994116420570263709027924276754456522908"632 "753868250641971826553344726563-323;"},633 {"(EX24.13,';')", " 0X8.0000000000000P-1077;"},634 }},635 {// least positive nonzero normal636 0x10000000000000,637 {638 {"(E723.716,';')",639 " 0."640 "222507385850720138309023271733240406421921598046233183055332"641 "741688720443481391819585428315901251102056406733973103581100"642 "515243416155346010885601238537771882113077799353200233047961"643 "014744258363607192156504694250373420837525080665061665815894"644 "872049117996859163964850063590877011830487479978088775374994"645 "945158045160505091539985658247081864511353793580499211598108"646 "576605199243335211435239014879569960959128889160299264151106"647 "346631339366347758651302937176204732563178148566435087212282"648 "863764204484681140761391147706280168985324411002416144742161"649 "856716615054015428508471675290190316132277889672970737312333"650 "408698898317506783884692609277397797285865965494109136909540"651 "61364675687023986783152906809846172109246253967285156250-"652 "307;"},653 {"(G0,';')", ".22250738585072014E-307;"},654 {"(EX24.13,';')", " 0X8.0000000000000P-1025;"},655 }},656 {// greatest finite657 0x7fefffffffffffffuLL,658 {659 {"(E32.17,';')", " 0.17976931348623157+309;"},660 {"(E317.310,';')",661 " 0."662 "179769313486231570814527423731704356798070567525844996598917"663 "476803157260780028538760589558632766878171540458953514382464"664 "234321326889464182768467546703537516986049910576551282076245"665 "490090389328944075868508455133942304583236903222948165808559"666 "332123348274797826204144723168738177180919299881250404026184"667 "1248583680+309;"},668 {"(ES317.310,';')",669 " 1."670 "797693134862315708145274237317043567980705675258449965989174"671 "768031572607800285387605895586327668781715404589535143824642"672 "343213268894641827684675467035375169860499105765512820762454"673 "900903893289440758685084551339423045832369032229481658085593"674 "321233482747978262041447231687381771809192998812504040261841"675 "2485836800+308;"},676 {"(EN319.310,';')",677 " 179."678 "769313486231570814527423731704356798070567525844996598917476"679 "803157260780028538760589558632766878171540458953514382464234"680 "321326889464182768467546703537516986049910576551282076245490"681 "090389328944075868508455133942304583236903222948165808559332"682 "123348274797826204144723168738177180919299881250404026184124"683 "8583680000+306;"},684 {"(G0,';')", ".17976931348623157E+309;"},685 {"(EX24.13,';')", " 0XF.FFFFFFFFFFFF8P+1020;"},686 }},687 {// EX rounding688 0x3ff0100000000000uLL,689 {690 {"(F11.8,';')", " 1.00390625;"},691 {"(EX10.2,';')", " 0X8.08P-3;"},692 {"(EX10.1,';')", " 0X8.0P-3;"},693 {"(EX10.0,';')", " 0X8.08P-3;"},694 {"(EX0.0,';')", "0X8.08P-3;"},695 {"(EX0,';')", "0X8.08P-3;"},696 {"(RN,EX10.1,';')", " 0X8.0P-3;"},697 {"(RU,EX10.1,';')", " 0X8.1P-3;"},698 {"(RD,EX10.1,';')", " 0X8.0P-3;"},699 {"(RZ,EX10.1,';')", " 0X8.0P-3;"},700 {"(RC,EX10.1,';')", " 0X8.1P-3;"},701 {"(RN,EX10.0,';')", " 0X8.08P-3;"},702 {"(RU,EX10.0,';')", " 0X8.08P-3;"},703 {"(RD,EX10.0,';')", " 0X8.08P-3;"},704 {"(RZ,EX10.0,';')", " 0X8.08P-3;"},705 {"(RC,EX10.0,';')", " 0X8.08P-3;"},706 }},707 {// EX rounding708 0xbff0100000000000uLL,709 {710 {"(F11.8,';')", "-1.00390625;"},711 {"(EX10.2,';')", "-0X8.08P-3;"},712 {"(EX10.1,';')", " -0X8.0P-3;"},713 {"(EX10.0,';')", "-0X8.08P-3;"},714 {"(EX0.0,';')", "-0X8.08P-3;"},715 {"(EX0,';')", "-0X8.08P-3;"},716 {"(RN,EX10.1,';')", " -0X8.0P-3;"},717 {"(RU,EX10.1,';')", " -0X8.0P-3;"},718 {"(RD,EX10.1,';')", " -0X8.1P-3;"},719 {"(RZ,EX10.1,';')", " -0X8.0P-3;"},720 {"(RC,EX10.1,';')", " -0X8.1P-3;"},721 {"(RN,EX10.0,';')", "-0X8.08P-3;"},722 {"(RU,EX10.0,';')", "-0X8.08P-3;"},723 {"(RD,EX10.0,';')", "-0X8.08P-3;"},724 {"(RZ,EX10.0,';')", "-0X8.08P-3;"},725 {"(RC,EX10.0,';')", "-0X8.08P-3;"},726 }},727 };728 729 for (auto const &[value, cases] : testCases) {730 for (auto const &[format, expect] : cases) {731 std::string got;732 ASSERT_TRUE(CompareFormatReal(format, value, expect, got))733 << "Failed to format " << format << ", expected '" << expect734 << "', got '" << got << "'";735 }736 }737 738 using IndividualTestCaseTy = std::tuple<const char *, double, const char *>;739 static const std::vector<IndividualTestCaseTy> individualTestCases{740 {"(F5.3,';')", 25., "*****;"},741 {"(F5.3,';')", 2.5, "2.500;"},742 {"(F5.3,';')", 0.25, "0.250;"},743 {"(F5.3,';')", 0.025, "0.025;"},744 {"(F5.3,';')", 0.0025, "0.003;"},745 {"(F5.3,';')", 0.00025, "0.000;"},746 {"(F5.3,';')", 0.000025, "0.000;"},747 {"(F5.3,';')", -25., "*****;"},748 {"(F5.3,';')", -2.5, "*****;"},749 {"(F5.3,';')", -0.25, "-.250;"},750 {"(F5.3,';')", -0.025, "-.025;"},751 {"(F5.3,';')", -0.0025, "-.003;"},752 {"(F5.3,';')", -0.00025, "-.000;"},753 {"(F5.3,';')", -0.000025, "-.000;"},754 {"(F5.3,';')", 99.999, "*****;"},755 {"(F5.3,';')", 9.9999, "*****;"},756 {"(F5.3,';')", 0.99999, "1.000;"},757 {"(F5.3,';')", 0.099999, "0.100;"},758 {"(F5.3,';')", 0.0099999, "0.010;"},759 {"(F5.3,';')", 0.00099999, "0.001;"},760 {"(F5.3,';')",761 0.0005000000000000000104083408558608425664715468883514404296875,762 "0.001;"},763 {"(F5.3,';')",764 0.000499999999999999901988123607310399165726266801357269287109375,765 "0.000;"},766 {"(F5.3,';')", 0.000099999, "0.000;"},767 {"(F5.3,';')", -99.999, "*****;"},768 {"(F5.3,';')", -9.9999, "*****;"},769 {"(F5.3,';')", -0.99999, "*****;"},770 {"(F5.3,';')", -0.099999, "-.100;"},771 {"(F5.3,';')", -0.0099999, "-.010;"},772 {"(F5.3,';')", -0.00099999, "-.001;"},773 {"(F5.3,';')",774 -0.0005000000000000000104083408558608425664715468883514404296875,775 "-.001;"},776 {"(F5.3,';')",777 -0.000499999999999999901988123607310399165726266801357269287109375,778 "-.000;"},779 {"(F5.3,';')", -0.000099999, "-.000;"},780 {"(F0.1,';')", 0.0, ".0;"},781 {"(F5.0,';')", -0.5000000000000001, " -1.;"},782 {"(F5.0,';')", -0.5, " -0.;"},783 {"(F5.0,';')", -0.49999999999999994, " -0.;"},784 {"(F5.0,';')", 0.49999999999999994, " 0.;"},785 {"(F5.0,';')", 0.5, " 0.;"},786 {"(F5.0,';')", 0.5000000000000001, " 1.;"},787 {"(ES0.0E0,';')", 0.666, "7.E-1;"},788 {"(EN0.0E0,';')", 0.666, "666.E-3;"},789 };790 791 for (auto const &[format, value, expect] : individualTestCases) {792 std::string got;793 char hex[17];794 std::snprintf(hex, sizeof hex, "%016llx",795 *reinterpret_cast<const unsigned long long *>(&value));796 ASSERT_TRUE(CompareFormatReal(format, value, expect, got))797 << "Failed to format " << value << " 0x" << hex << " with format "798 << format << ", expected '" << expect << "', got '" << got << "'";799 }800 801 // Problematic EN formatting edge cases with rounding802 using IndividualENTestCaseTy = std::tuple<std::uint64_t, const char *>;803 static const std::vector<IndividualENTestCaseTy> individualENTestCases{804 {0x3E11183197785F8C, " 995.0E-12"}, // 0.9950312500000000115852E-09805 {0x3E11180E68455D30, " 995.0E-12"}, // 0.9949999999999999761502E-09806 {0x3E112BD8F4F6B0D7, " 999.5E-12"}, // 0.9994999999999999089118E-09807 {0x3E45794883CA8782, " 10.0E-09"}, // 0.9999499999999999642266E-08808 {0x3F506218230C7482, " 999.9E-06"}, // 0.9999499999999998840761E-03809 {0x3FB99652BD3C3612, " 100.0E-03"}, // 0.9999500000000000055067E+00810 {0x4023E66666666667, " 10.0E+00"}, // 0.9950000000000001065814E+01811 };812 813 for (auto const &[value, expect] : individualENTestCases) {814 std::string got;815 ASSERT_TRUE(CompareFormatReal("(EN10.1)", value, expect, got))816 << "Failed to format EN10.1, expected '" << expect << "', got '" << got817 << "'";818 }819}820 821TEST(IOApiTests, FormatIntegerValues) {822 using IntTestCaseTy = std::tuple<const char *, std::int64_t, const char *>;823 static const std::vector<IntTestCaseTy> intTestCases{824 {"(I4)", 0, " 0"},825 {"(I4)", 1, " 1"},826 {"(I4)", 9999, "9999"},827 {"(SP,I4)", 1, " +1"},828 {"(SP,I4)", 9999, "****"},829 {"(SP,I4)", 999, "+999"},830 {"(I4)", -1, " -1"},831 {"(I4)", -9999, "****"},832 {"(I4)", -999, "-999"},833 {"(I4.2)", 1, " 01"},834 {"(I4.2)", -1, " -01"},835 {"(I4.2)", 999, " 999"},836 {"(I4.4)", 999, "0999"},837 {"(I0)", 0, "0"},838 {"(I0)", 1, "1"},839 {"(I0)", 9999, "9999"},840 {"(SP,I0)", 1, "+1"},841 {"(SP,I0)", 9999, "+9999"},842 {"(SP,I0)", 999, "+999"},843 {"(I0)", -1, "-1"},844 {"(I0)", -9999, "-9999"},845 {"(I0)", -999, "-999"},846 {"(I0.2)", 1, "01"},847 {"(I0.2)", -1, "-01"},848 {"(I0.2)", 999, "999"},849 {"(I0.4)", 999, "0999"},850 {"(G4)", 0, " 0"},851 {"(G4)", 1, " 1"},852 {"(G4)", 9999, "9999"},853 {"(SP,G4)", 1, " +1"},854 {"(SP,G4)", 9999, "****"},855 {"(SP,G4)", 999, "+999"},856 {"(G4)", -1, " -1"},857 {"(G4)", -9999, "****"},858 {"(G4)", -999, "-999"},859 {"(G4.2)", 1, " 1"},860 {"(G4.2)", -1, " -1"},861 {"(G4.2)", 999, " 999"},862 {"(G4.4)", 999, " 999"},863 {"(G0)", 0, "0"},864 {"(G0)", 1, "1"},865 {"(G0)", 9999, "9999"},866 {"(SP,G0)", 1, "+1"},867 {"(SP,G0)", 9999, "+9999"},868 {"(SP,G0)", 999, "+999"},869 {"(G0)", -1, "-1"},870 {"(G0)", -9999, "-9999"},871 {"(G0)", -999, "-999"},872 {"(G0.2)", 1, "1"},873 {"(G0.2)", -1, "-1"},874 {"(G0.2)", 999, "999"},875 {"(G0.4)", 999, "999"},876 {"(I)", 999, "999"},877 {"(G)", 999, "999"},878 {"('x',I)", 999, "x 999"},879 {"('x',G)", 999, "x 999"},880 };881 882 for (auto const &[fmt, value, expect] : intTestCases) {883 std::string got;884 ASSERT_TRUE(CompareFormatInteger(fmt, value, expect, got))885 << "Failed to format " << fmt << ", expected '" << expect << "', got '"886 << got << "'";887 }888}889 890//------------------------------------------------------------------------------891/// Tests for input editing real values892//------------------------------------------------------------------------------893 894// Ensure double input values correctly map to raw uint64 values895TEST(IOApiTests, EditDoubleInputValues) {896 using TestCaseTy = std::tuple<const char *, const char *, std::uint64_t, int>;897 int ovf{IostatRealInputOverflow};898 static const std::vector<TestCaseTy> testCases{899 {"(F18.0)", " 0", 0x0, 0},900 {"(F18.0)", " ", 0x0, 0},901 {"(F18.0)", " -0", 0x8000000000000000, 0},902 {"(F18.0)", " 01", 0x3ff0000000000000, 0},903 {"(F18.0)", " 1", 0x3ff0000000000000, 0},904 {"(F18.0)", " 125.", 0x405f400000000000, 0},905 {"(F18.0)", " 12.5", 0x4029000000000000, 0},906 {"(F18.0)", " 1.25", 0x3ff4000000000000, 0},907 {"(F18.0)", " 01.25", 0x3ff4000000000000, 0},908 {"(F18.0)", " .125", 0x3fc0000000000000, 0},909 {"(F18.0)", " 0.125", 0x3fc0000000000000, 0},910 {"(F18.0)", " .0625", 0x3fb0000000000000, 0},911 {"(F18.0)", " 0.0625", 0x3fb0000000000000, 0},912 {"(F18.0)", " 125", 0x405f400000000000, 0},913 {"(F18.1)", " 125", 0x4029000000000000, 0},914 {"(F18.2)", " 125", 0x3ff4000000000000, 0},915 {"(F18.3)", " 125", 0x3fc0000000000000, 0},916 {"('str',F3.0)", "xxx125", 0x405f400000000000, 0},917 {"(-1P,F18.0)", " 125", 0x4093880000000000, 0}, // 1250918 {"(1P,F18.0)", " 125", 0x4029000000000000, 0}, // 12.5919 {"(BZ,F18.0)", " 125 ", 0x4093880000000000, 0}, // 1250920 {"(BZ,F18.0)", " 125 . e +1 ", 0x42a6bcc41e900000, 0}, // 1.25e13921 {"(BZ,F18.0)", " . ", 0x0, 0},922 {"(BZ,F18.0)", " . e +1 ", 0x0, 0},923 {"(DC,F18.0)", " 12,5", 0x4029000000000000, 0},924 {"(DC,F18.0)", " 12,5;", 0x4029000000000000, 0},925 {"(EX22.0)", "0X0P0 ", 0x0, 0}, // +0.926 {"(EX22.0)", "-0X0P0 ", 0x8000000000000000, 0}, // -0.927 {"(EX22.0)", "0X.8P1 ", 0x3ff0000000000000, 0}, // 1.0928 {"(EX22.0)", "0X8.P-3 ", 0x3ff0000000000000, 0}, // 1.0929 {"(EX22.0)", "0X.1P4 ", 0x3ff0000000000000, 0}, // 1.0930 {"(EX22.0)", "0X10.P-4 ", 0x3ff0000000000000, 0}, // 1.0931 {"(EX22.0)", "0X8.00P-3 ", 0x3ff0000000000000, 0}, // 1.0932 {"(EX22.0)", "0X80.0P-6 ", 0x4000000000000000, 0}, // 2.0933 {"(EX22.0)", "0XC.CCCCCCCCCCCDP-7 ", 0x3fb999999999999a, 0}, // 0.1934 {"(EX22.0)", "0X.8P-1021 ", 0x0010000000000000,935 0}, // min normal936 {"(EX22.0)", "0X.8P-1022 ", 0x0008000000000000,937 0}, // subnormal938 {"(EX22.0)", "0X.8P-1073 ", 0x0000000000000001,939 0}, // min subn.940 {"(EX22.0)", "0X.FFFFFFFFFFFFF8P1024", 0x7fefffffffffffff,941 0}, // max finite942 {"(EX22.0)", "0X.8P1025 ", 0x7ff0000000000000, ovf}, // +Inf943 {"(EX22.0)", "-0X.8P1025 ", 0xfff0000000000000, ovf}, // -Inf944 {"(RC,EX22.0)", "0X1.0000000000000P0 ", 0x3ff0000000000000, 0},945 {"(RC,EX22.0)", "0X1.00000000000008P0 ", 0x3ff0000000000001, 0},946 {"(RC,EX22.0)", "0X1.000000000000008P0 ", 0x3ff0000000000000, 0},947 {"(RC,EX22.0)", "0X1.00000000000004P0 ", 0x3ff0000000000000, 0},948 {"(RC,EX22.0)", "0X.80000000000000P1 ", 0x3ff0000000000000, 0},949 {"(RC,EX22.0)", "0X.80000000000004P1 ", 0x3ff0000000000001, 0},950 {"(RC,EX22.0)", "0X.800000000000004P1 ", 0x3ff0000000000000, 0},951 {"(RC,EX22.0)", "0X.80000000000002P1 ", 0x3ff0000000000000, 0},952 {"(RZ,F7.0)", " 2.e308", 0x7fefffffffffffff, 0}, // +HUGE()953 {"(RD,F7.0)", " 2.e308", 0x7fefffffffffffff, 0}, // +HUGE()954 {"(RU,F7.0)", " 2.e308", 0x7ff0000000000000, ovf}, // +Inf955 {"(RZ,F7.0)", "-2.e308", 0xffefffffffffffff, 0}, // -HUGE()956 {"(RD,F7.0)", "-2.e308", 0xfff0000000000000, ovf}, // -Inf957 {"(RU,F7.0)", "-2.e308", 0xffefffffffffffff, 0}, // -HUGE()958 {"(RZ,F7.0)", " 1.e999", 0x7fefffffffffffff, 0}, // +HUGE()959 {"(RD,F7.0)", " 1.e999", 0x7fefffffffffffff, 0}, // +HUGE()960 {"(RU,F7.0)", " 1.e999", 0x7ff0000000000000, ovf}, // +Inf961 {"(RZ,F7.0)", "-1.e999", 0xffefffffffffffff, 0}, // -HUGE()962 {"(RD,F7.0)", "-1.e999", 0xfff0000000000000, ovf}, // -Inf963 {"(RU,F7.0)", "-1.e999", 0xffefffffffffffff, 0}, // -HUGE()964 {"(E9.1)", " 1.0E-325", 0x0, 0},965 {"(RU,E9.1)", " 1.0E-325", 0x1, 0},966 {"(E9.1)", "-1.0E-325", 0x8000000000000000, 0},967 {"(RD,E9.1)", "-1.0E-325", 0x8000000000000001, 0},968 {"(F7.0)", "+NaN(q)", 0x7ff8000000000000, 0},969 {"(G)", "D", 0, IostatBadRealInput},970 {"(G0)", "D", 0, IostatErrorInFormat},971 {"(G1.0)", "D", 0, 0},972 };973 for (auto const &[format, data, want, iostat] : testCases) {974 auto cookie{IONAME(BeginInternalFormattedInput)(975 data, std::strlen(data), format, std::strlen(format))};976 union {977 double x;978 std::uint64_t raw;979 } u;980 u.raw = 0;981 982 // Read buffer into union value983 IONAME(EnableHandlers)(cookie, true, true, true, true, true);984 IONAME(InputReal64)(cookie, u.x);985 986 static constexpr int bufferSize{65};987 char iomsg[bufferSize];988 std::memset(iomsg, '\0', bufferSize - 1);989 990 // Ensure no unexpected errors were encountered reading input buffer into991 // union value992 IONAME(GetIoMsg)(cookie, iomsg, bufferSize - 1);993 auto status{IONAME(EndIoStatement)(cookie)};994 EXPECT_EQ(status, iostat)995 << '\'' << format << "' failed reading '" << data << "', status "996 << static_cast<int>(status) << " != expected " << iostat << " iomsg '"997 << iomsg << "'";998 999 // Ensure raw uint64 value matches expected conversion from double1000 EXPECT_EQ(u.raw, want) << '\'' << format << "' failed reading '" << data1001 << "', want " << want << ", got " << u.raw;1002 }1003}1004 1005// regression test for confusing digit minimization1006TEST(IOApiTests, ConfusingMinimization) {1007 char buffer[8]{};1008 auto cookie{IONAME(BeginInternalListOutput)(buffer, sizeof buffer)};1009 StaticDescriptor<0> staticDescriptor;1010 Descriptor &desc{staticDescriptor.descriptor()};1011 std::uint16_t x{0x7bff}; // HUGE(0._2)1012 desc.Establish(TypeCode{CFI_type_half_float}, sizeof x, &x, 0, nullptr);1013 desc.Check();1014 EXPECT_TRUE(IONAME(OutputDescriptor)(cookie, desc));1015 auto status{IONAME(EndIoStatement)(cookie)};1016 EXPECT_EQ(status, 0);1017 std::string got{std::string{buffer, sizeof buffer}};1018 EXPECT_TRUE(CompareFormattedStrings(" 65504. ", got))1019 << "expected ' 65504. ', got '" << got << '\''; // not 65500.!1020}1021