[lldb] Add ability to hide the root name of a value
[llvm-project.git] / flang / unittests / Runtime / NumericalFormatTest.cpp
blob40191137fe189cb49bbb5840b314e5a5425db7c1
1 //===-- flang/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-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "CrashHandlerFixture.h"
10 #include "flang/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>
18 using namespace Fortran::runtime;
19 using namespace Fortran::runtime::io;
21 static 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;
28 static bool CompareFormattedStrings(
29 const char *expect, const std::string &&got) {
30 return CompareFormattedStrings(std::string(expect), std::move(got));
33 // Perform format and compare the result with expected value
34 static 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);
47 return CompareFormattedStrings(expect, got);
50 // Convert raw uint64 into double, perform format, and compare with expected
51 static 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);
60 struct IOApiTests : CrashHandlerFixture {};
62 TEST(IOApiTests, HelloWorldOutputTest) {
63 static constexpr int bufferSize{32};
64 char buffer[bufferSize];
66 // Create format for all types and values to be written
67 const char *format{"(6HHELLO,,A6,2X,I3,1X,'0x',Z8,1X,L1)"};
68 auto cookie{IONAME(BeginInternalFormattedOutput)(
69 buffer, bufferSize, format, std::strlen(format))};
71 // Write string, integer, and logical values to buffer
72 IONAME(OutputAscii)(cookie, "WORLD", 5);
73 IONAME(OutputInteger64)(cookie, 678);
74 IONAME(OutputInteger32)(cookie, 0xfeedface);
75 IONAME(OutputLogical)(cookie, true);
77 // Ensure IO succeeded
78 auto status{IONAME(EndIoStatement)(cookie)};
79 ASSERT_EQ(status, 0) << "hello: '" << format << "' failed, status "
80 << static_cast<int>(status);
82 // Ensure final buffer matches expected string output
83 static const std::string expect{"HELLO, WORLD 678 0xFEEDFACE T"};
84 ASSERT_TRUE(
85 CompareFormattedStrings(expect, std::string{buffer, sizeof buffer}))
86 << "Expected '" << expect << "', got " << buffer;
89 TEST(IOApiTests, MultilineOutputTest) {
90 // Allocate buffer for multiline output
91 static constexpr int numLines{5};
92 static constexpr int lineLength{32};
93 char buffer[numLines][lineLength];
95 // Create descriptor for entire buffer
96 static constexpr int staticDescriptorMaxRank{1};
97 StaticDescriptor<staticDescriptorMaxRank> wholeStaticDescriptor;
98 Descriptor &whole{wholeStaticDescriptor.descriptor()};
99 static const SubscriptValue extent[]{numLines};
100 whole.Establish(TypeCode{CFI_type_char}, /*elementBytes=*/lineLength, &buffer,
101 staticDescriptorMaxRank, extent, CFI_attribute_pointer);
102 whole.Dump(stderr);
103 whole.Check();
105 // Create descriptor for buffer section
106 StaticDescriptor<staticDescriptorMaxRank> sectionStaticDescriptor;
107 Descriptor &section{sectionStaticDescriptor.descriptor()};
108 static const SubscriptValue lowers[]{0}, uppers[]{4}, strides[]{1};
109 section.Establish(whole.type(), /*elementBytes=*/whole.ElementBytes(),
110 nullptr, /*maxRank=*/staticDescriptorMaxRank, extent,
111 CFI_attribute_pointer);
113 // Ensure C descriptor address `section.raw()` is updated without error
114 const auto error{
115 CFI_section(&section.raw(), &whole.raw(), lowers, uppers, strides)};
116 ASSERT_EQ(error, 0) << "multiline: CFI_section failed: " << error;
117 section.Dump(stderr);
118 section.Check();
120 // Create format string and initialize IO operation
121 const char *format{
122 "('?abcde,',T1,'>',T9,A,TL12,A,TR25,'<'//G0,17X,'abcd',1(2I4))"};
123 auto cookie{IONAME(BeginInternalArrayFormattedOutput)(
124 section, format, std::strlen(format))};
126 // Fill last line with periods
127 std::memset(buffer[numLines - 1], '.', lineLength);
129 // Write data to buffer
130 IONAME(OutputAscii)(cookie, "WORLD", 5);
131 IONAME(OutputAscii)(cookie, "HELLO", 5);
132 IONAME(OutputInteger64)(cookie, 789);
133 for (int j{666}; j <= 999; j += 111) {
134 IONAME(OutputInteger64)(cookie, j);
137 // Ensure no errors occured in write operations above
138 const auto status{IONAME(EndIoStatement)(cookie)};
139 ASSERT_EQ(status, 0) << "multiline: '" << format << "' failed, status "
140 << static_cast<int>(status);
142 static const std::string expect{">HELLO, WORLD <"
144 "789 abcd 666 777"
145 " 888 999 "
146 "................................"};
147 // Ensure formatted string matches expected output
148 EXPECT_TRUE(
149 CompareFormattedStrings(expect, std::string{buffer[0], sizeof buffer}))
150 << "Expected '" << expect << "' but got '"
151 << std::string{buffer[0], sizeof buffer} << "'";
154 TEST(IOApiTests, ListInputTest) {
155 static const char input[]{",1*,(5.,6.),(7.0,8.0)"};
156 auto cookie{IONAME(BeginInternalListInput)(input, sizeof input - 1)};
158 // Create real values for IO tests
159 static constexpr int numRealValues{8};
160 float z[numRealValues];
161 for (int j{0}; j < numRealValues; ++j) {
162 z[j] = -(j + 1);
165 // Ensure reading complex values to floats does not result in an error
166 for (int j{0}; j < numRealValues; j += 2) {
167 ASSERT_TRUE(IONAME(InputComplex32)(cookie, &z[j]))
168 << "InputComplex32 failed with value " << z[j];
171 // Ensure no IO errors occured during IO operations above
172 auto status{IONAME(EndIoStatement)(cookie)};
173 ASSERT_EQ(status, 0) << "Failed complex list-directed input, status "
174 << static_cast<int>(status);
176 // Ensure writing complex values from floats does not result in an error
177 static constexpr int bufferSize{39};
178 char output[bufferSize];
179 output[bufferSize - 1] = '\0';
180 cookie = IONAME(BeginInternalListOutput)(output, bufferSize - 1);
181 for (int j{0}; j < numRealValues; j += 2) {
182 ASSERT_TRUE(IONAME(OutputComplex32)(cookie, z[j], z[j + 1]))
183 << "OutputComplex32 failed when outputting value " << z[j] << ", "
184 << z[j + 1];
187 // Ensure no IO errors occured during IO operations above
188 status = IONAME(EndIoStatement)(cookie);
189 ASSERT_EQ(status, 0) << "Failed complex list-directed output, status "
190 << static_cast<int>(status);
192 // Verify output buffer against expected value
193 static const char expect[bufferSize]{
194 " (-1.,-2.) (-3.,-4.) (5.,6.) (7.,8.) "};
195 ASSERT_EQ(std::strncmp(output, expect, bufferSize), 0)
196 << "Failed complex list-directed output, expected '" << expect
197 << "', but got '" << output << "'";
200 TEST(IOApiTests, DescriptorOutputTest) {
201 static constexpr int bufferSize{10};
202 char buffer[bufferSize];
203 const char *format{"(2A4)"};
204 auto cookie{IONAME(BeginInternalFormattedOutput)(
205 buffer, bufferSize, format, std::strlen(format))};
207 // Create descriptor for output
208 static constexpr int staticDescriptorMaxRank{1};
209 StaticDescriptor<staticDescriptorMaxRank> staticDescriptor;
210 Descriptor &desc{staticDescriptor.descriptor()};
211 static constexpr int subscriptExtent{2};
212 static const SubscriptValue extent[]{subscriptExtent};
214 // Manually write to descriptor buffer
215 static constexpr int dataLength{4};
216 char data[subscriptExtent][dataLength];
217 std::memcpy(data[0], "ABCD", dataLength);
218 std::memcpy(data[1], "EFGH", dataLength);
219 desc.Establish(TypeCode{CFI_type_char}, dataLength, &data,
220 staticDescriptorMaxRank, extent);
221 desc.Dump(stderr);
222 desc.Check();
223 IONAME(OutputDescriptor)(cookie, desc);
225 // Ensure no errors were encountered in initializing the cookie and descriptor
226 auto formatStatus{IONAME(EndIoStatement)(cookie)};
227 ASSERT_EQ(formatStatus, 0)
228 << "descrOutputTest: '" << format << "' failed, status "
229 << static_cast<int>(formatStatus);
231 // Ensure buffer matches expected output
232 EXPECT_TRUE(
233 CompareFormattedStrings("ABCDEFGH ", std::string{buffer, sizeof buffer}))
234 << "descrOutputTest: formatted: got '"
235 << std::string{buffer, sizeof buffer} << "'";
237 // Begin list-directed output on cookie by descriptor
238 cookie = IONAME(BeginInternalListOutput)(buffer, sizeof buffer);
239 IONAME(OutputDescriptor)(cookie, desc);
241 // Ensure list-directed output does not result in an IO error
242 auto listDirectedStatus{IONAME(EndIoStatement)(cookie)};
243 ASSERT_EQ(listDirectedStatus, 0)
244 << "descrOutputTest: list-directed failed, status "
245 << static_cast<int>(listDirectedStatus);
247 // Ensure buffer matches expected output
248 EXPECT_TRUE(
249 CompareFormattedStrings(" ABCDEFGH ", std::string{buffer, sizeof buffer}))
250 << "descrOutputTest: list-directed: got '"
251 << std::string{buffer, sizeof buffer} << "'";
254 //------------------------------------------------------------------------------
255 /// Tests for output formatting real values
256 //------------------------------------------------------------------------------
258 TEST(IOApiTests, FormatZeroes) {
259 static constexpr std::pair<const char *, const char *> zeroes[]{
260 {"(E32.17,';')", " 0.00000000000000000E+00;"},
261 {"(F32.17,';')", " 0.00000000000000000;"},
262 {"(G32.17,';')", " 0.0000000000000000 ;"},
263 {"(DC,E32.17,';')", " 0,00000000000000000E+00;"},
264 {"(DC,F32.17,';')", " 0,00000000000000000;"},
265 {"(DC,G32.17,';')", " 0,0000000000000000 ;"},
266 {"(D32.17,';')", " 0.00000000000000000D+00;"},
267 {"(E32.17E1,';')", " 0.00000000000000000E+0;"},
268 {"(G32.17E1,';')", " 0.0000000000000000 ;"},
269 {"(E32.17E0,';')", " 0.00000000000000000E+0;"},
270 {"(G32.17E0,';')", " 0.0000000000000000 ;"},
271 {"(1P,E32.17,';')", " 0.00000000000000000E+00;"},
272 {"(1PE32.17,';')", " 0.00000000000000000E+00;"}, // no comma
273 {"(1P,F32.17,';')", " 0.00000000000000000;"},
274 {"(1P,G32.17,';')", " 0.0000000000000000 ;"},
275 {"(2P,E32.17,';')", " 00.0000000000000000E+00;"},
276 {"(-1P,E32.17,';')", " 0.00000000000000000E+00;"},
277 {"(G0,';')", "0.;"},
280 for (auto const &[format, expect] : zeroes) {
281 std::string got;
282 ASSERT_TRUE(CompareFormatReal(format, 0.0, expect, got))
283 << "Failed to format " << format << ", expected '" << expect
284 << "', got '" << got << "'";
288 TEST(IOApiTests, FormatOnes) {
289 static constexpr std::pair<const char *, const char *> ones[]{
290 {"(E32.17,';')", " 0.10000000000000000E+01;"},
291 {"(F32.17,';')", " 1.00000000000000000;"},
292 {"(G32.17,';')", " 1.0000000000000000 ;"},
293 {"(E32.17E1,';')", " 0.10000000000000000E+1;"},
294 {"(G32.17E1,';')", " 1.0000000000000000 ;"},
295 {"(E32.17E0,';')", " 0.10000000000000000E+1;"},
296 {"(G32.17E0,';')", " 1.0000000000000000 ;"},
297 {"(E32.17E4,';')", " 0.10000000000000000E+0001;"},
298 {"(G32.17E4,';')", " 1.0000000000000000 ;"},
299 {"(1P,E32.17,';')", " 1.00000000000000000E+00;"},
300 {"(1PE32.17,';')", " 1.00000000000000000E+00;"}, // no comma
301 {"(1P,F32.17,';')", " 10.00000000000000000;"},
302 {"(1P,G32.17,';')", " 1.0000000000000000 ;"},
303 {"(ES32.17,';')", " 1.00000000000000000E+00;"},
304 {"(2P,E32.17,';')", " 10.0000000000000000E-01;"},
305 {"(2P,G32.17,';')", " 1.0000000000000000 ;"},
306 {"(-1P,E32.17,';')", " 0.01000000000000000E+02;"},
307 {"(-1P,G32.17,';')", " 1.0000000000000000 ;"},
308 {"(G0,';')", "1.;"},
311 for (auto const &[format, expect] : ones) {
312 std::string got;
313 ASSERT_TRUE(CompareFormatReal(format, 1.0, expect, got))
314 << "Failed to format " << format << ", expected '" << expect
315 << "', got '" << got << "'";
319 TEST(IOApiTests, FormatNegativeOnes) {
320 static constexpr std::tuple<const char *, const char *> negOnes[]{
321 {"(E32.17,';')", " -0.10000000000000000E+01;"},
322 {"(F32.17,';')", " -1.00000000000000000;"},
323 {"(G32.17,';')", " -1.0000000000000000 ;"},
324 {"(G0,';')", "-1.;"},
326 for (auto const &[format, expect] : negOnes) {
327 std::string got;
328 ASSERT_TRUE(CompareFormatReal(format, -1.0, expect, got))
329 << "Failed to format " << format << ", expected '" << expect
330 << "', got '" << got << "'";
334 // Each test case contains a raw uint64, a format string for a real value, and
335 // the expected resulting string from formatting the raw uint64. The double
336 // representation of the uint64 is commented above each test case.
337 TEST(IOApiTests, FormatDoubleValues) {
339 using TestCaseTy = std::tuple<std::uint64_t,
340 std::vector<std::tuple<const char *, const char *>>>;
341 static const std::vector<TestCaseTy> testCases{
342 {// -0
343 0x8000000000000000,
345 {"(E9.1,';')", " -0.0E+00;"},
346 {"(F4.0,';')", " -0.;"},
347 {"(F0.1,';')", "-.0;"},
348 {"(G8.0,';')", "-0.0E+00;"},
349 {"(G8.1,';')", " -0. ;"},
350 {"(G0,';')", "-0.;"},
351 {"(E9.1,';')", " -0.0E+00;"},
353 {// +Inf
354 0x7ff0000000000000,
356 {"(E9.1,';')", " Inf;"},
357 {"(F9.1,';')", " Inf;"},
358 {"(G9.1,';')", " Inf;"},
359 {"(SP,E9.1,';')", " +Inf;"},
360 {"(SP,F9.1,';')", " +Inf;"},
361 {"(SP,G9.1,';')", " +Inf;"},
362 {"(G0,';')", "Inf;"},
364 {// -Inf
365 0xfff0000000000000,
367 {"(E9.1,';')", " -Inf;"},
368 {"(F9.1,';')", " -Inf;"},
369 {"(G9.1,';')", " -Inf;"},
370 {"(G0,';')", "-Inf;"},
372 {// NaN
373 0x7ff0000000000001,
375 {"(E9.1,';')", " NaN;"},
376 {"(F9.1,';')", " NaN;"},
377 {"(G9.1,';')", " NaN;"},
378 {"(G0,';')", "NaN;"},
380 {// NaN (sign irrelevant)
381 0xfff0000000000001,
383 {"(E9.1,';')", " NaN;"},
384 {"(F9.1,';')", " NaN;"},
385 {"(G9.1,';')", " NaN;"},
386 {"(SP,E9.1,';')", " NaN;"},
387 {"(SP,F9.1,';')", " NaN;"},
388 {"(SP,G9.1,';')", " NaN;"},
389 {"(G0,';')", "NaN;"},
391 {// 0.1 rounded
392 0x3fb999999999999a,
394 {"(E62.55,';')",
395 " 0.1000000000000000055511151231257827021181583404541015625E+"
396 "00;"},
397 {"(E0.0,';')", ".1E+00;"},
398 {"(E0.55,';')",
399 ".1000000000000000055511151231257827021181583404541015625E+"
400 "00;"},
401 {"(E0,';')", ".1E+00;"},
402 {"(F58.55,';')",
403 " 0."
404 "1000000000000000055511151231257827021181583404541015625;"},
405 {"(F0.0,';')", "0.;"},
406 {"(F0.55,';')",
407 ".1000000000000000055511151231257827021181583404541015625;"},
408 {"(F0,';')", ".1;"},
409 {"(G62.55,';')",
410 " 0.1000000000000000055511151231257827021181583404541015625 "
411 " ;"},
412 {"(G0.0,';')", "0.;"},
413 {"(G0.55,';')",
414 ".1000000000000000055511151231257827021181583404541015625;"},
415 {"(G0,';')", ".1;"},
417 {// 1.5
418 0x3ff8000000000000,
420 {"(E9.2,';')", " 0.15E+01;"},
421 {"(F4.1,';')", " 1.5;"},
422 {"(G7.1,';')", " 2. ;"},
423 {"(RN,E8.1,';')", " 0.2E+01;"},
424 {"(RN,F3.0,';')", " 2.;"},
425 {"(RN,G7.0,';')", " 0.E+01;"},
426 {"(RN,G7.1,';')", " 2. ;"},
427 {"(RD,E8.1,';')", " 0.1E+01;"},
428 {"(RD,F3.0,';')", " 1.;"},
429 {"(RD,G7.0,';')", " 0.E+01;"},
430 {"(RD,G7.1,';')", " 1. ;"},
431 {"(RU,E8.1,';')", " 0.2E+01;"},
432 {"(RU,G7.0,';')", " 0.E+01;"},
433 {"(RU,G7.1,';')", " 2. ;"},
434 {"(RZ,E8.1,';')", " 0.1E+01;"},
435 {"(RZ,F3.0,';')", " 1.;"},
436 {"(RZ,G7.0,';')", " 0.E+01;"},
437 {"(RZ,G7.1,';')", " 1. ;"},
438 {"(RC,E8.1,';')", " 0.2E+01;"},
439 {"(RC,F3.0,';')", " 2.;"},
440 {"(RC,G7.0,';')", " 0.E+01;"},
441 {"(RC,G7.1,';')", " 2. ;"},
443 {// -1.5
444 0xbff8000000000000,
446 {"(E9.2,';')", "-0.15E+01;"},
447 {"(RN,E8.1,';')", "-0.2E+01;"},
448 {"(RD,E8.1,';')", "-0.2E+01;"},
449 {"(RU,E8.1,';')", "-0.1E+01;"},
450 {"(RZ,E8.1,';')", "-0.1E+01;"},
451 {"(RC,E8.1,';')", "-0.2E+01;"},
453 {// 2.5
454 0x4004000000000000,
456 {"(E9.2,';')", " 0.25E+01;"},
457 {"(RN,E8.1,';')", " 0.2E+01;"},
458 {"(RD,E8.1,';')", " 0.2E+01;"},
459 {"(RU,E8.1,';')", " 0.3E+01;"},
460 {"(RZ,E8.1,';')", " 0.2E+01;"},
461 {"(RC,E8.1,';')", " 0.3E+01;"},
463 {// -2.5
464 0xc004000000000000,
466 {"(E9.2,';')", "-0.25E+01;"},
467 {"(RN,E8.1,';')", "-0.2E+01;"},
468 {"(RD,E8.1,';')", "-0.3E+01;"},
469 {"(RU,E8.1,';')", "-0.2E+01;"},
470 {"(RZ,E8.1,';')", "-0.2E+01;"},
471 {"(RC,E8.1,';')", "-0.3E+01;"},
473 {// least positive nonzero subnormal
476 {"(E32.17,';')", " 0.49406564584124654-323;"},
477 {"(ES32.17,';')", " 4.94065645841246544-324;"},
478 {"(EN32.17,';')", " 4.94065645841246544-324;"},
479 {"(E759.752,';')",
480 " 0."
481 "494065645841246544176568792868221372365059802614324764425585"
482 "682500675507270208751865299836361635992379796564695445717730"
483 "926656710355939796398774796010781878126300713190311404527845"
484 "817167848982103688718636056998730723050006387409153564984387"
485 "312473397273169615140031715385398074126238565591171026658556"
486 "686768187039560310624931945271591492455329305456544401127480"
487 "129709999541931989409080416563324524757147869014726780159355"
488 "238611550134803526493472019379026810710749170333222684475333"
489 "572083243193609238289345836806010601150616980975307834227731"
490 "832924790498252473077637592724787465608477820373446969953364"
491 "701797267771758512566055119913150489110145103786273816725095"
492 "583738973359899366480994116420570263709027924276754456522908"
493 "75386825064197182655334472656250-323;"},
494 {"(G0,';')", ".5E-323;"},
495 {"(E757.750,';')",
496 " 0."
497 "494065645841246544176568792868221372365059802614324764425585"
498 "682500675507270208751865299836361635992379796564695445717730"
499 "926656710355939796398774796010781878126300713190311404527845"
500 "817167848982103688718636056998730723050006387409153564984387"
501 "312473397273169615140031715385398074126238565591171026658556"
502 "686768187039560310624931945271591492455329305456544401127480"
503 "129709999541931989409080416563324524757147869014726780159355"
504 "238611550134803526493472019379026810710749170333222684475333"
505 "572083243193609238289345836806010601150616980975307834227731"
506 "832924790498252473077637592724787465608477820373446969953364"
507 "701797267771758512566055119913150489110145103786273816725095"
508 "583738973359899366480994116420570263709027924276754456522908"
509 "753868250641971826553344726562-323;"},
510 {"(RN,E757.750,';')",
511 " 0."
512 "494065645841246544176568792868221372365059802614324764425585"
513 "682500675507270208751865299836361635992379796564695445717730"
514 "926656710355939796398774796010781878126300713190311404527845"
515 "817167848982103688718636056998730723050006387409153564984387"
516 "312473397273169615140031715385398074126238565591171026658556"
517 "686768187039560310624931945271591492455329305456544401127480"
518 "129709999541931989409080416563324524757147869014726780159355"
519 "238611550134803526493472019379026810710749170333222684475333"
520 "572083243193609238289345836806010601150616980975307834227731"
521 "832924790498252473077637592724787465608477820373446969953364"
522 "701797267771758512566055119913150489110145103786273816725095"
523 "583738973359899366480994116420570263709027924276754456522908"
524 "753868250641971826553344726562-323;"},
525 {"(RD,E757.750,';')",
526 " 0."
527 "494065645841246544176568792868221372365059802614324764425585"
528 "682500675507270208751865299836361635992379796564695445717730"
529 "926656710355939796398774796010781878126300713190311404527845"
530 "817167848982103688718636056998730723050006387409153564984387"
531 "312473397273169615140031715385398074126238565591171026658556"
532 "686768187039560310624931945271591492455329305456544401127480"
533 "129709999541931989409080416563324524757147869014726780159355"
534 "238611550134803526493472019379026810710749170333222684475333"
535 "572083243193609238289345836806010601150616980975307834227731"
536 "832924790498252473077637592724787465608477820373446969953364"
537 "701797267771758512566055119913150489110145103786273816725095"
538 "583738973359899366480994116420570263709027924276754456522908"
539 "753868250641971826553344726562-323;"},
540 {"(RU,E757.750,';')",
541 " 0."
542 "494065645841246544176568792868221372365059802614324764425585"
543 "682500675507270208751865299836361635992379796564695445717730"
544 "926656710355939796398774796010781878126300713190311404527845"
545 "817167848982103688718636056998730723050006387409153564984387"
546 "312473397273169615140031715385398074126238565591171026658556"
547 "686768187039560310624931945271591492455329305456544401127480"
548 "129709999541931989409080416563324524757147869014726780159355"
549 "238611550134803526493472019379026810710749170333222684475333"
550 "572083243193609238289345836806010601150616980975307834227731"
551 "832924790498252473077637592724787465608477820373446969953364"
552 "701797267771758512566055119913150489110145103786273816725095"
553 "583738973359899366480994116420570263709027924276754456522908"
554 "753868250641971826553344726563-323;"},
555 {"(RC,E757.750,';')",
556 " 0."
557 "494065645841246544176568792868221372365059802614324764425585"
558 "682500675507270208751865299836361635992379796564695445717730"
559 "926656710355939796398774796010781878126300713190311404527845"
560 "817167848982103688718636056998730723050006387409153564984387"
561 "312473397273169615140031715385398074126238565591171026658556"
562 "686768187039560310624931945271591492455329305456544401127480"
563 "129709999541931989409080416563324524757147869014726780159355"
564 "238611550134803526493472019379026810710749170333222684475333"
565 "572083243193609238289345836806010601150616980975307834227731"
566 "832924790498252473077637592724787465608477820373446969953364"
567 "701797267771758512566055119913150489110145103786273816725095"
568 "583738973359899366480994116420570263709027924276754456522908"
569 "753868250641971826553344726563-323;"},
571 {// least positive nonzero normal
572 0x10000000000000,
574 {"(E723.716,';')",
575 " 0."
576 "222507385850720138309023271733240406421921598046233183055332"
577 "741688720443481391819585428315901251102056406733973103581100"
578 "515243416155346010885601238537771882113077799353200233047961"
579 "014744258363607192156504694250373420837525080665061665815894"
580 "872049117996859163964850063590877011830487479978088775374994"
581 "945158045160505091539985658247081864511353793580499211598108"
582 "576605199243335211435239014879569960959128889160299264151106"
583 "346631339366347758651302937176204732563178148566435087212282"
584 "863764204484681140761391147706280168985324411002416144742161"
585 "856716615054015428508471675290190316132277889672970737312333"
586 "408698898317506783884692609277397797285865965494109136909540"
587 "61364675687023986783152906809846172109246253967285156250-"
588 "307;"},
589 {"(G0,';')", ".22250738585072014E-307;"},
591 {// greatest finite
592 0x7fefffffffffffffuLL,
594 {"(E32.17,';')", " 0.17976931348623157+309;"},
595 {"(E317.310,';')",
596 " 0."
597 "179769313486231570814527423731704356798070567525844996598917"
598 "476803157260780028538760589558632766878171540458953514382464"
599 "234321326889464182768467546703537516986049910576551282076245"
600 "490090389328944075868508455133942304583236903222948165808559"
601 "332123348274797826204144723168738177180919299881250404026184"
602 "1248583680+309;"},
603 {"(ES317.310,';')",
604 " 1."
605 "797693134862315708145274237317043567980705675258449965989174"
606 "768031572607800285387605895586327668781715404589535143824642"
607 "343213268894641827684675467035375169860499105765512820762454"
608 "900903893289440758685084551339423045832369032229481658085593"
609 "321233482747978262041447231687381771809192998812504040261841"
610 "2485836800+308;"},
611 {"(EN319.310,';')",
612 " 179."
613 "769313486231570814527423731704356798070567525844996598917476"
614 "803157260780028538760589558632766878171540458953514382464234"
615 "321326889464182768467546703537516986049910576551282076245490"
616 "090389328944075868508455133942304583236903222948165808559332"
617 "123348274797826204144723168738177180919299881250404026184124"
618 "8583680000+306;"},
619 {"(G0,';')", ".17976931348623157E+309;"},
623 for (auto const &[value, cases] : testCases) {
624 for (auto const &[format, expect] : cases) {
625 std::string got;
626 ASSERT_TRUE(CompareFormatReal(format, value, expect, got))
627 << "Failed to format " << format << ", expected '" << expect
628 << "', got '" << got << "'";
632 using IndividualTestCaseTy = std::tuple<const char *, double, const char *>;
633 static const std::vector<IndividualTestCaseTy> individualTestCases{
634 {"(F5.3,';')", 25., "*****;"},
635 {"(F5.3,';')", 2.5, "2.500;"},
636 {"(F5.3,';')", 0.25, "0.250;"},
637 {"(F5.3,';')", 0.025, "0.025;"},
638 {"(F5.3,';')", 0.0025, "0.003;"},
639 {"(F5.3,';')", 0.00025, "0.000;"},
640 {"(F5.3,';')", 0.000025, "0.000;"},
641 {"(F5.3,';')", -25., "*****;"},
642 {"(F5.3,';')", -2.5, "*****;"},
643 {"(F5.3,';')", -0.25, "-.250;"},
644 {"(F5.3,';')", -0.025, "-.025;"},
645 {"(F5.3,';')", -0.0025, "-.003;"},
646 {"(F5.3,';')", -0.00025, "-.000;"},
647 {"(F5.3,';')", -0.000025, "-.000;"},
648 {"(F5.3,';')", 99.999, "*****;"},
649 {"(F5.3,';')", 9.9999, "*****;"},
650 {"(F5.3,';')", 0.99999, "1.000;"},
651 {"(F5.3,';')", 0.099999, "0.100;"},
652 {"(F5.3,';')", 0.0099999, "0.010;"},
653 {"(F5.3,';')", 0.00099999, "0.001;"},
654 {"(F5.3,';')", 0.0005, "0.001;"},
655 {"(F5.3,';')", 0.00049999, "0.000;"},
656 {"(F5.3,';')", 0.000099999, "0.000;"},
657 {"(F5.3,';')", -99.999, "*****;"},
658 {"(F5.3,';')", -9.9999, "*****;"},
659 {"(F5.3,';')", -0.99999, "*****;"},
660 {"(F5.3,';')", -0.099999, "-.100;"},
661 {"(F5.3,';')", -0.0099999, "-.010;"},
662 {"(F5.3,';')", -0.00099999, "-.001;"},
663 {"(F5.3,';')", -0.0005, "-.001;"},
664 {"(F5.3,';')", -0.00049999, "-.000;"},
665 {"(F5.3,';')", -0.000099999, "-.000;"},
666 {"(F0.1,';')", 0.0, ".0;"},
669 for (auto const &[format, value, expect] : individualTestCases) {
670 std::string got;
671 ASSERT_TRUE(CompareFormatReal(format, value, expect, got))
672 << "Failed to format " << format << ", expected '" << expect
673 << "', got '" << got << "'";
676 // Problematic EN formatting edge cases with rounding
677 using IndividualENTestCaseTy = std::tuple<std::uint64_t, const char *>;
678 static const std::vector<IndividualENTestCaseTy> individualENTestCases{
679 {0x3E11183197785F8C, " 995.0E-12"}, // 0.9950312500000000115852E-09
680 {0x3E11180E68455D30, " 995.0E-12"}, // 0.9949999999999999761502E-09
681 {0x3E112BD8F4F6B0D7, " 999.5E-12"}, // 0.9994999999999999089118E-09
682 {0x3E45794883CA8782, " 10.0E-09"}, // 0.9999499999999999642266E-08
683 {0x3F506218230C7482, " 999.9E-06"}, // 0.9999499999999998840761E-03
684 {0x3FB99652BD3C3612, " 100.0E-03"}, // 0.9999500000000000055067E+00
685 {0x4023E66666666667, " 10.0E+00"}, // 0.9950000000000001065814E+01
688 for (auto const &[value, expect] : individualENTestCases) {
689 std::string got;
690 ASSERT_TRUE(CompareFormatReal("(EN10.1)", value, expect, got))
691 << "Failed to format EN10.1, expected '" << expect << "', got '" << got
692 << "'";
696 //------------------------------------------------------------------------------
697 /// Tests for input formatting real values
698 //------------------------------------------------------------------------------
700 // Ensure double input values correctly map to raw uint64 values
701 TEST(IOApiTests, FormatDoubleInputValues) {
702 using TestCaseTy = std::tuple<const char *, const char *, std::uint64_t>;
703 static const std::vector<TestCaseTy> testCases{
704 {"(F18.0)", " 0", 0x0},
705 {"(F18.0)", " ", 0x0},
706 {"(F18.0)", " -0", 0x8000000000000000},
707 {"(F18.0)", " 01", 0x3ff0000000000000},
708 {"(F18.0)", " 1", 0x3ff0000000000000},
709 {"(F18.0)", " 125.", 0x405f400000000000},
710 {"(F18.0)", " 12.5", 0x4029000000000000},
711 {"(F18.0)", " 1.25", 0x3ff4000000000000},
712 {"(F18.0)", " 01.25", 0x3ff4000000000000},
713 {"(F18.0)", " .125", 0x3fc0000000000000},
714 {"(F18.0)", " 0.125", 0x3fc0000000000000},
715 {"(F18.0)", " .0625", 0x3fb0000000000000},
716 {"(F18.0)", " 0.0625", 0x3fb0000000000000},
717 {"(F18.0)", " 125", 0x405f400000000000},
718 {"(F18.1)", " 125", 0x4029000000000000},
719 {"(F18.2)", " 125", 0x3ff4000000000000},
720 {"(F18.3)", " 125", 0x3fc0000000000000},
721 {"(-1P,F18.0)", " 125", 0x4093880000000000}, // 1250
722 {"(1P,F18.0)", " 125", 0x4029000000000000}, // 12.5
723 {"(BZ,F18.0)", " 125 ", 0x4093880000000000}, // 1250
724 {"(BZ,F18.0)", " 125 . e +1 ", 0x42a6bcc41e900000}, // 1.25e13
725 {"(BZ,F18.0)", " . ", 0x0},
726 {"(BZ,F18.0)", " . e +1 ", 0x0},
727 {"(DC,F18.0)", " 12,5", 0x4029000000000000},
729 for (auto const &[format, data, want] : testCases) {
730 auto cookie{IONAME(BeginInternalFormattedInput)(
731 data, std::strlen(data), format, std::strlen(format))};
732 union {
733 double x;
734 std::uint64_t raw;
735 } u;
736 u.raw = 0;
738 // Read buffer into union value
739 IONAME(EnableHandlers)(cookie, true, true, true, true, true);
740 IONAME(InputReal64)(cookie, u.x);
742 static constexpr int bufferSize{65};
743 char iomsg[bufferSize];
744 std::memset(iomsg, '\0', bufferSize - 1);
746 // Ensure no errors were encountered reading input buffer into union value
747 IONAME(GetIoMsg)(cookie, iomsg, bufferSize - 1);
748 auto status{IONAME(EndIoStatement)(cookie)};
749 ASSERT_EQ(status, 0) << '\'' << format << "' failed reading '" << data
750 << "', status " << static_cast<int>(status)
751 << " iomsg '" << iomsg << "'";
753 // Ensure raw uint64 value matches expected conversion from double
754 ASSERT_EQ(u.raw, want) << '\'' << format << "' failed reading '" << data
755 << "', want " << want << ", got " << u.raw;