| //===-- flang/unittests/Runtime/NumericalFormatTest.cpp ---------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "CrashHandlerFixture.h" |
| #include "flang/Runtime/descriptor.h" |
| #include "flang/Runtime/io-api.h" |
| #include <algorithm> |
| #include <array> |
| #include <cstring> |
| #include <gtest/gtest.h> |
| #include <tuple> |
| |
| using namespace Fortran::runtime; |
| using namespace Fortran::runtime::io; |
| |
| static bool CompareFormattedStrings( |
| const std::string &expect, const std::string &got) { |
| std::string want{expect}; |
| want.resize(got.size(), ' '); |
| return want == got; |
| } |
| |
| static bool CompareFormattedStrings( |
| const char *expect, const std::string &&got) { |
| return CompareFormattedStrings(std::string(expect), std::move(got)); |
| } |
| |
| // Perform format and compare the result with expected value |
| static bool CompareFormatReal( |
| const char *format, double x, const char *expect, std::string &got) { |
| char buffer[800]; |
| auto cookie{IONAME(BeginInternalFormattedOutput)( |
| buffer, sizeof buffer, format, std::strlen(format))}; |
| EXPECT_TRUE(IONAME(OutputReal64)(cookie, x)); |
| auto status{IONAME(EndIoStatement)(cookie)}; |
| EXPECT_EQ(status, 0); |
| got = std::string{buffer, sizeof buffer}; |
| auto lastNonBlank{got.find_last_not_of(" ")}; |
| if (lastNonBlank != std::string::npos) { |
| got.resize(lastNonBlank + 1); |
| } |
| return CompareFormattedStrings(expect, got); |
| } |
| |
| // Convert raw uint64 into double, perform format, and compare with expected |
| static bool CompareFormatReal(const char *format, std::uint64_t xInt, |
| const char *expect, std::string &got) { |
| double x; |
| static_assert(sizeof(double) == sizeof(std::uint64_t), |
| "Size of double != size of uint64_t!"); |
| std::memcpy(&x, &xInt, sizeof xInt); |
| return CompareFormatReal(format, x, expect, got); |
| } |
| |
| static bool CompareFormatInteger( |
| const char *format, std::int64_t x, const char *expect, std::string &got) { |
| char buffer[800]; |
| auto cookie{IONAME(BeginInternalFormattedOutput)( |
| buffer, sizeof buffer, format, std::strlen(format))}; |
| EXPECT_TRUE(IONAME(OutputInteger64)(cookie, x)); |
| auto status{IONAME(EndIoStatement)(cookie)}; |
| EXPECT_EQ(status, 0); |
| got = std::string{buffer, sizeof buffer}; |
| auto lastNonBlank{got.find_last_not_of(" ")}; |
| if (lastNonBlank != std::string::npos) { |
| got.resize(lastNonBlank + 1); |
| } |
| return CompareFormattedStrings(expect, got); |
| } |
| |
| struct IOApiTests : CrashHandlerFixture {}; |
| |
| TEST(IOApiTests, HelloWorldOutputTest) { |
| static constexpr int bufferSize{32}; |
| char buffer[bufferSize]; |
| |
| // Create format for all types and values to be written |
| const char *format{"(6HHELLO,,A6,2X,I3,1X,'0x',Z8,1X,L1)"}; |
| auto cookie{IONAME(BeginInternalFormattedOutput)( |
| buffer, bufferSize, format, std::strlen(format))}; |
| |
| // Write string, integer, and logical values to buffer |
| IONAME(OutputAscii)(cookie, "WORLD", 5); |
| IONAME(OutputInteger64)(cookie, 678); |
| IONAME(OutputInteger32)(cookie, 0xfeedface); |
| IONAME(OutputLogical)(cookie, true); |
| |
| // Ensure IO succeeded |
| auto status{IONAME(EndIoStatement)(cookie)}; |
| ASSERT_EQ(status, 0) << "hello: '" << format << "' failed, status " |
| << static_cast<int>(status); |
| |
| // Ensure final buffer matches expected string output |
| static const std::string expect{"HELLO, WORLD 678 0xFEEDFACE T"}; |
| ASSERT_TRUE( |
| CompareFormattedStrings(expect, std::string{buffer, sizeof buffer})) |
| << "Expected '" << expect << "', got " << buffer; |
| } |
| |
| TEST(IOApiTests, MultilineOutputTest) { |
| // Allocate buffer for multiline output |
| static constexpr int numLines{5}; |
| static constexpr int lineLength{32}; |
| char buffer[numLines][lineLength]; |
| |
| // Create descriptor for entire buffer |
| static constexpr int staticDescriptorMaxRank{1}; |
| StaticDescriptor<staticDescriptorMaxRank> wholeStaticDescriptor; |
| Descriptor &whole{wholeStaticDescriptor.descriptor()}; |
| static const SubscriptValue extent[]{numLines}; |
| whole.Establish(TypeCode{CFI_type_char}, /*elementBytes=*/lineLength, &buffer, |
| staticDescriptorMaxRank, extent, CFI_attribute_pointer); |
| whole.Dump(stderr); |
| whole.Check(); |
| |
| // Create descriptor for buffer section |
| StaticDescriptor<staticDescriptorMaxRank> sectionStaticDescriptor; |
| Descriptor §ion{sectionStaticDescriptor.descriptor()}; |
| static const SubscriptValue lowers[]{0}, uppers[]{4}, strides[]{1}; |
| section.Establish(whole.type(), /*elementBytes=*/whole.ElementBytes(), |
| nullptr, /*maxRank=*/staticDescriptorMaxRank, extent, |
| CFI_attribute_pointer); |
| |
| // Ensure C descriptor address `section.raw()` is updated without error |
| const auto error{ |
| CFI_section(§ion.raw(), &whole.raw(), lowers, uppers, strides)}; |
| ASSERT_EQ(error, 0) << "multiline: CFI_section failed: " << error; |
| section.Dump(stderr); |
| section.Check(); |
| |
| // Create format string and initialize IO operation |
| const char *format{ |
| "('?abcde,',T1,'>',T9,A,TL12,A,TR25,'<'//G0,17X,'abcd',1(2I4))"}; |
| auto cookie{IONAME(BeginInternalArrayFormattedOutput)( |
| section, format, std::strlen(format))}; |
| |
| // Fill last line with periods |
| std::memset(buffer[numLines - 1], '.', lineLength); |
| |
| // Write data to buffer |
| IONAME(OutputAscii)(cookie, "WORLD", 5); |
| IONAME(OutputAscii)(cookie, "HELLO", 5); |
| IONAME(OutputInteger64)(cookie, 789); |
| for (int j{666}; j <= 999; j += 111) { |
| IONAME(OutputInteger64)(cookie, j); |
| } |
| |
| // Ensure no errors occured in write operations above |
| const auto status{IONAME(EndIoStatement)(cookie)}; |
| ASSERT_EQ(status, 0) << "multiline: '" << format << "' failed, status " |
| << static_cast<int>(status); |
| |
| static const std::string expect{">HELLO, WORLD <" |
| " " |
| "789 abcd 666 777" |
| " 888 999 " |
| "................................"}; |
| // Ensure formatted string matches expected output |
| EXPECT_TRUE( |
| CompareFormattedStrings(expect, std::string{buffer[0], sizeof buffer})) |
| << "Expected '" << expect << "' but got '" |
| << std::string{buffer[0], sizeof buffer} << "'"; |
| } |
| |
| TEST(IOApiTests, ListInputTest) { |
| static const char input[]{",1*,(5.,6.),(7.0,8.0)"}; |
| auto cookie{IONAME(BeginInternalListInput)(input, sizeof input - 1)}; |
| |
| // Create real values for IO tests |
| static constexpr int numRealValues{8}; |
| float z[numRealValues]; |
| for (int j{0}; j < numRealValues; ++j) { |
| z[j] = -(j + 1); |
| } |
| |
| // Ensure reading complex values to floats does not result in an error |
| for (int j{0}; j < numRealValues; j += 2) { |
| ASSERT_TRUE(IONAME(InputComplex32)(cookie, &z[j])) |
| << "InputComplex32 failed with value " << z[j]; |
| } |
| |
| // Ensure no IO errors occured during IO operations above |
| auto status{IONAME(EndIoStatement)(cookie)}; |
| ASSERT_EQ(status, 0) << "Failed complex list-directed input, status " |
| << static_cast<int>(status); |
| |
| // Ensure writing complex values from floats does not result in an error |
| static constexpr int bufferSize{39}; |
| char output[bufferSize]; |
| output[bufferSize - 1] = '\0'; |
| cookie = IONAME(BeginInternalListOutput)(output, bufferSize - 1); |
| for (int j{0}; j < numRealValues; j += 2) { |
| ASSERT_TRUE(IONAME(OutputComplex32)(cookie, z[j], z[j + 1])) |
| << "OutputComplex32 failed when outputting value " << z[j] << ", " |
| << z[j + 1]; |
| } |
| |
| // Ensure no IO errors occured during IO operations above |
| status = IONAME(EndIoStatement)(cookie); |
| ASSERT_EQ(status, 0) << "Failed complex list-directed output, status " |
| << static_cast<int>(status); |
| |
| // Verify output buffer against expected value |
| static const char expect[bufferSize]{ |
| " (-1.,-2.) (-3.,-4.) (5.,6.) (7.,8.) "}; |
| ASSERT_EQ(std::strncmp(output, expect, bufferSize), 0) |
| << "Failed complex list-directed output, expected '" << expect |
| << "', but got '" << output << "'"; |
| } |
| |
| TEST(IOApiTests, DescriptorOutputTest) { |
| static constexpr int bufferSize{10}; |
| char buffer[bufferSize]; |
| const char *format{"(2A4)"}; |
| auto cookie{IONAME(BeginInternalFormattedOutput)( |
| buffer, bufferSize, format, std::strlen(format))}; |
| |
| // Create descriptor for output |
| static constexpr int staticDescriptorMaxRank{1}; |
| StaticDescriptor<staticDescriptorMaxRank> staticDescriptor; |
| Descriptor &desc{staticDescriptor.descriptor()}; |
| static constexpr int subscriptExtent{2}; |
| static const SubscriptValue extent[]{subscriptExtent}; |
| |
| // Manually write to descriptor buffer |
| static constexpr int dataLength{4}; |
| char data[subscriptExtent][dataLength]; |
| std::memcpy(data[0], "ABCD", dataLength); |
| std::memcpy(data[1], "EFGH", dataLength); |
| desc.Establish(TypeCode{CFI_type_char}, dataLength, &data, |
| staticDescriptorMaxRank, extent); |
| desc.Dump(stderr); |
| desc.Check(); |
| IONAME(OutputDescriptor)(cookie, desc); |
| |
| // Ensure no errors were encountered in initializing the cookie and descriptor |
| auto formatStatus{IONAME(EndIoStatement)(cookie)}; |
| ASSERT_EQ(formatStatus, 0) |
| << "descrOutputTest: '" << format << "' failed, status " |
| << static_cast<int>(formatStatus); |
| |
| // Ensure buffer matches expected output |
| EXPECT_TRUE( |
| CompareFormattedStrings("ABCDEFGH ", std::string{buffer, sizeof buffer})) |
| << "descrOutputTest: formatted: got '" |
| << std::string{buffer, sizeof buffer} << "'"; |
| |
| // Begin list-directed output on cookie by descriptor |
| cookie = IONAME(BeginInternalListOutput)(buffer, sizeof buffer); |
| IONAME(OutputDescriptor)(cookie, desc); |
| |
| // Ensure list-directed output does not result in an IO error |
| auto listDirectedStatus{IONAME(EndIoStatement)(cookie)}; |
| ASSERT_EQ(listDirectedStatus, 0) |
| << "descrOutputTest: list-directed failed, status " |
| << static_cast<int>(listDirectedStatus); |
| |
| // Ensure buffer matches expected output |
| EXPECT_TRUE( |
| CompareFormattedStrings(" ABCDEFGH ", std::string{buffer, sizeof buffer})) |
| << "descrOutputTest: list-directed: got '" |
| << std::string{buffer, sizeof buffer} << "'"; |
| } |
| |
| //------------------------------------------------------------------------------ |
| /// Tests for output formatting real values |
| //------------------------------------------------------------------------------ |
| |
| TEST(IOApiTests, FormatZeroes) { |
| static constexpr std::pair<const char *, const char *> zeroes[]{ |
| {"(E32.17,';')", " 0.00000000000000000E+00;"}, |
| {"(F32.17,';')", " 0.00000000000000000;"}, |
| {"(G32.17,';')", " 0.0000000000000000 ;"}, |
| {"(DC,E32.17,';')", " 0,00000000000000000E+00;"}, |
| {"(DC,F32.17,';')", " 0,00000000000000000;"}, |
| {"(DC,G32.17,';')", " 0,0000000000000000 ;"}, |
| {"(D32.17,';')", " 0.00000000000000000D+00;"}, |
| {"(E32.17E1,';')", " 0.00000000000000000E+0;"}, |
| {"(G32.17E1,';')", " 0.0000000000000000 ;"}, |
| {"(E32.17E0,';')", " 0.00000000000000000E+0;"}, |
| {"(G32.17E0,';')", " 0.0000000000000000 ;"}, |
| {"(1P,E32.17,';')", " 0.00000000000000000E+00;"}, |
| {"(1PE32.17,';')", " 0.00000000000000000E+00;"}, // no comma |
| {"(1P,F32.17,';')", " 0.00000000000000000;"}, |
| {"(1P,G32.17,';')", " 0.0000000000000000 ;"}, |
| {"(2P,E32.17,';')", " 00.0000000000000000E+00;"}, |
| {"(-1P,E32.17,';')", " 0.00000000000000000E+00;"}, |
| {"(EX32.17,';')", " 0X0.00000000000000000P+0;"}, |
| {"(DC,EX32.17,';')", " 0X0,00000000000000000P+0;"}, |
| {"(G0,';')", "0.;"}, |
| }; |
| |
| for (auto const &[format, expect] : zeroes) { |
| std::string got; |
| ASSERT_TRUE(CompareFormatReal(format, 0.0, expect, got)) |
| << "Failed to format " << format << ", expected '" << expect |
| << "', got '" << got << "'"; |
| } |
| } |
| |
| TEST(IOApiTests, FormatOnes) { |
| static constexpr std::pair<const char *, const char *> ones[]{ |
| {"(E32.17,';')", " 0.10000000000000000E+01;"}, |
| {"(F32.17,';')", " 1.00000000000000000;"}, |
| {"(G32.17,';')", " 1.0000000000000000 ;"}, |
| {"(E32.17E1,';')", " 0.10000000000000000E+1;"}, |
| {"(G32.17E1,';')", " 1.0000000000000000 ;"}, |
| {"(E32.17E0,';')", " 0.10000000000000000E+1;"}, |
| {"(G32.17E0,';')", " 1.0000000000000000 ;"}, |
| {"(E32.17E4,';')", " 0.10000000000000000E+0001;"}, |
| {"(G32.17E4,';')", " 1.0000000000000000 ;"}, |
| {"(1P,E32.17,';')", " 1.00000000000000000E+00;"}, |
| {"(1PE32.17,';')", " 1.00000000000000000E+00;"}, // no comma |
| {"(1P,F32.17,';')", " 10.00000000000000000;"}, |
| {"(1P,G32.17,';')", " 1.0000000000000000 ;"}, |
| {"(ES32.17,';')", " 1.00000000000000000E+00;"}, |
| {"(2P,E32.17,';')", " 10.0000000000000000E-01;"}, |
| {"(2P,G32.17,';')", " 1.0000000000000000 ;"}, |
| {"(-1P,E32.17,';')", " 0.01000000000000000E+02;"}, |
| {"(-1P,G32.17,';')", " 1.0000000000000000 ;"}, |
| {"(EX32.17,';')", " 0X8.00000000000000000P-3;"}, |
| {"(DC,EX32.17,';')", " 0X8,00000000000000000P-3;"}, |
| {"(G0,';')", "1.;"}, |
| }; |
| |
| for (auto const &[format, expect] : ones) { |
| std::string got; |
| ASSERT_TRUE(CompareFormatReal(format, 1.0, expect, got)) |
| << "Failed to format " << format << ", expected '" << expect |
| << "', got '" << got << "'"; |
| } |
| } |
| |
| TEST(IOApiTests, FormatNegativeOnes) { |
| static constexpr std::tuple<const char *, const char *> negOnes[]{ |
| {"(E32.17,';')", " -0.10000000000000000E+01;"}, |
| {"(F32.17,';')", " -1.00000000000000000;"}, |
| {"(G32.17,';')", " -1.0000000000000000 ;"}, |
| {"(EX32.17,';')", " -0X8.00000000000000000P-3;"}, |
| {"(G0,';')", "-1.;"}, |
| }; |
| for (auto const &[format, expect] : negOnes) { |
| std::string got; |
| ASSERT_TRUE(CompareFormatReal(format, -1.0, expect, got)) |
| << "Failed to format " << format << ", expected '" << expect |
| << "', got '" << got << "'"; |
| } |
| } |
| |
| // Each test case contains a raw uint64, a format string for a real value, and |
| // the expected resulting string from formatting the raw uint64. The double |
| // representation of the uint64 is commented above each test case. |
| TEST(IOApiTests, FormatDoubleValues) { |
| |
| using TestCaseTy = std::tuple<std::uint64_t, |
| std::vector<std::tuple<const char *, const char *>>>; |
| static const std::vector<TestCaseTy> testCases{ |
| {// -0 |
| 0x8000000000000000, |
| { |
| {"(E9.1,';')", " -0.0E+00;"}, |
| {"(F4.0,';')", " -0.;"}, |
| {"(F0.1,';')", "-.0;"}, |
| {"(G8.0,';')", "-0.0E+00;"}, |
| {"(G8.1,';')", " -0. ;"}, |
| {"(G0,';')", "-0.;"}, |
| {"(E9.1,';')", " -0.0E+00;"}, |
| {"(EX9.1,';')", "-0X0.0P+0;"}, |
| }}, |
| {// +Inf |
| 0x7ff0000000000000, |
| { |
| {"(E9.1,';')", " Inf;"}, |
| {"(F9.1,';')", " Inf;"}, |
| {"(G9.1,';')", " Inf;"}, |
| {"(EX9.1,';')", " Inf;"}, |
| {"(SP,E9.1,';')", " +Inf;"}, |
| {"(SP,F9.1,';')", " +Inf;"}, |
| {"(SP,G9.1,';')", " +Inf;"}, |
| {"(SP,EX9.1,';')", " +Inf;"}, |
| {"(G0,';')", "Inf;"}, |
| }}, |
| {// -Inf |
| 0xfff0000000000000, |
| { |
| {"(E9.1,';')", " -Inf;"}, |
| {"(F9.1,';')", " -Inf;"}, |
| {"(G9.1,';')", " -Inf;"}, |
| {"(EX9.1,';')", " -Inf;"}, |
| {"(G0,';')", "-Inf;"}, |
| }}, |
| {// NaN |
| 0x7ff0000000000001, |
| { |
| {"(E9.1,';')", " NaN;"}, |
| {"(F9.1,';')", " NaN;"}, |
| {"(G9.1,';')", " NaN;"}, |
| {"(EX9.1,';')", " NaN;"}, |
| {"(G0,';')", "NaN;"}, |
| }}, |
| {// NaN (sign irrelevant) |
| 0xfff0000000000001, |
| { |
| {"(E9.1,';')", " NaN;"}, |
| {"(F9.1,';')", " NaN;"}, |
| {"(G9.1,';')", " NaN;"}, |
| {"(SP,E9.1,';')", " NaN;"}, |
| {"(SP,F9.1,';')", " NaN;"}, |
| {"(SP,G9.1,';')", " NaN;"}, |
| {"(SP,EX9.1,';')", " NaN;"}, |
| {"(G0,';')", "NaN;"}, |
| }}, |
| {// 0.1 rounded |
| 0x3fb999999999999a, |
| { |
| {"(E62.55,';')", |
| " 0.1000000000000000055511151231257827021181583404541015625E+" |
| "00;"}, |
| {"(E0.1,';')", ".1E+00;"}, |
| {"(E0.55,';')", |
| ".1000000000000000055511151231257827021181583404541015625E+" |
| "00;"}, |
| {"(E0,';')", ".1E+00;"}, |
| {"(F58.55,';')", |
| " 0." |
| "1000000000000000055511151231257827021181583404541015625;"}, |
| {"(F0.0,';')", "0.;"}, |
| {"(F0.55,';')", |
| ".1000000000000000055511151231257827021181583404541015625;"}, |
| {"(F0,';')", ".1;"}, |
| {"(G62.55,';')", |
| " 0.1000000000000000055511151231257827021181583404541015625 " |
| " ;"}, |
| {"(G0.0,';')", "0.;"}, |
| {"(G0.55,';')", |
| ".1000000000000000055511151231257827021181583404541015625;"}, |
| {"(G0,';')", ".1;"}, |
| {"(EX20.12,';')", " 0XC.CCCCCCCCCCCDP-7;"}, |
| }}, |
| {// 1.5 |
| 0x3ff8000000000000, |
| { |
| {"(E9.2,';')", " 0.15E+01;"}, |
| {"(F4.1,';')", " 1.5;"}, |
| {"(G7.1,';')", " 2. ;"}, |
| {"(EX9.1,';')", " 0XC.0P-3;"}, |
| {"(RN,E8.1,';')", " 0.2E+01;"}, |
| {"(RN,F3.0,';')", " 2.;"}, |
| {"(RN,G7.0,';')", " 0.E+01;"}, |
| {"(RN,G7.1,';')", " 2. ;"}, |
| {"(RD,E8.1,';')", " 0.1E+01;"}, |
| {"(RD,F3.0,';')", " 1.;"}, |
| {"(RD,G7.0,';')", " 0.E+01;"}, |
| {"(RD,G7.1,';')", " 1. ;"}, |
| {"(RU,E8.1,';')", " 0.2E+01;"}, |
| {"(RU,G7.0,';')", " 0.E+01;"}, |
| {"(RU,G7.1,';')", " 2. ;"}, |
| {"(RZ,E8.1,';')", " 0.1E+01;"}, |
| {"(RZ,F3.0,';')", " 1.;"}, |
| {"(RZ,G7.0,';')", " 0.E+01;"}, |
| {"(RZ,G7.1,';')", " 1. ;"}, |
| {"(RC,E8.1,';')", " 0.2E+01;"}, |
| {"(RC,F3.0,';')", " 2.;"}, |
| {"(RC,G7.0,';')", " 0.E+01;"}, |
| {"(RC,G7.1,';')", " 2. ;"}, |
| }}, |
| {// -1.5 |
| 0xbff8000000000000, |
| { |
| {"(E9.2,';')", "-0.15E+01;"}, |
| {"(RN,E8.1,';')", "-0.2E+01;"}, |
| {"(RD,E8.1,';')", "-0.2E+01;"}, |
| {"(RU,E8.1,';')", "-0.1E+01;"}, |
| {"(RZ,E8.1,';')", "-0.1E+01;"}, |
| {"(RC,E8.1,';')", "-0.2E+01;"}, |
| {"(EX9.1,';')", "-0XC.0P-3;"}, |
| }}, |
| {// 2.5 |
| 0x4004000000000000, |
| { |
| {"(E9.2,';')", " 0.25E+01;"}, |
| {"(RN,E8.1,';')", " 0.2E+01;"}, |
| {"(RD,E8.1,';')", " 0.2E+01;"}, |
| {"(RU,E8.1,';')", " 0.3E+01;"}, |
| {"(RZ,E8.1,';')", " 0.2E+01;"}, |
| {"(RC,E8.1,';')", " 0.3E+01;"}, |
| {"(EX9.1,';')", " 0XA.0P-2;"}, |
| }}, |
| {// -2.5 |
| 0xc004000000000000, |
| { |
| {"(E9.2,';')", "-0.25E+01;"}, |
| {"(RN,E8.1,';')", "-0.2E+01;"}, |
| {"(RD,E8.1,';')", "-0.3E+01;"}, |
| {"(RU,E8.1,';')", "-0.2E+01;"}, |
| {"(RZ,E8.1,';')", "-0.2E+01;"}, |
| {"(RC,E8.1,';')", "-0.3E+01;"}, |
| {"(EX9.1,';')", "-0XA.0P-2;"}, |
| }}, |
| {// least positive nonzero subnormal |
| 1, |
| { |
| {"(E32.17,';')", " 0.49406564584124654-323;"}, |
| {"(ES32.17,';')", " 4.94065645841246544-324;"}, |
| {"(EN32.17,';')", " 4.94065645841246544-324;"}, |
| {"(E759.752,';')", |
| " 0." |
| "494065645841246544176568792868221372365059802614324764425585" |
| "682500675507270208751865299836361635992379796564695445717730" |
| "926656710355939796398774796010781878126300713190311404527845" |
| "817167848982103688718636056998730723050006387409153564984387" |
| "312473397273169615140031715385398074126238565591171026658556" |
| "686768187039560310624931945271591492455329305456544401127480" |
| "129709999541931989409080416563324524757147869014726780159355" |
| "238611550134803526493472019379026810710749170333222684475333" |
| "572083243193609238289345836806010601150616980975307834227731" |
| "832924790498252473077637592724787465608477820373446969953364" |
| "701797267771758512566055119913150489110145103786273816725095" |
| "583738973359899366480994116420570263709027924276754456522908" |
| "75386825064197182655334472656250-323;"}, |
| {"(G0,';')", ".5E-323;"}, |
| {"(E757.750,';')", |
| " 0." |
| "494065645841246544176568792868221372365059802614324764425585" |
| "682500675507270208751865299836361635992379796564695445717730" |
| "926656710355939796398774796010781878126300713190311404527845" |
| "817167848982103688718636056998730723050006387409153564984387" |
| "312473397273169615140031715385398074126238565591171026658556" |
| "686768187039560310624931945271591492455329305456544401127480" |
| "129709999541931989409080416563324524757147869014726780159355" |
| "238611550134803526493472019379026810710749170333222684475333" |
| "572083243193609238289345836806010601150616980975307834227731" |
| "832924790498252473077637592724787465608477820373446969953364" |
| "701797267771758512566055119913150489110145103786273816725095" |
| "583738973359899366480994116420570263709027924276754456522908" |
| "753868250641971826553344726562-323;"}, |
| {"(RN,E757.750,';')", |
| " 0." |
| "494065645841246544176568792868221372365059802614324764425585" |
| "682500675507270208751865299836361635992379796564695445717730" |
| "926656710355939796398774796010781878126300713190311404527845" |
| "817167848982103688718636056998730723050006387409153564984387" |
| "312473397273169615140031715385398074126238565591171026658556" |
| "686768187039560310624931945271591492455329305456544401127480" |
| "129709999541931989409080416563324524757147869014726780159355" |
| "238611550134803526493472019379026810710749170333222684475333" |
| "572083243193609238289345836806010601150616980975307834227731" |
| "832924790498252473077637592724787465608477820373446969953364" |
| "701797267771758512566055119913150489110145103786273816725095" |
| "583738973359899366480994116420570263709027924276754456522908" |
| "753868250641971826553344726562-323;"}, |
| {"(RD,E757.750,';')", |
| " 0." |
| "494065645841246544176568792868221372365059802614324764425585" |
| "682500675507270208751865299836361635992379796564695445717730" |
| "926656710355939796398774796010781878126300713190311404527845" |
| "817167848982103688718636056998730723050006387409153564984387" |
| "312473397273169615140031715385398074126238565591171026658556" |
| "686768187039560310624931945271591492455329305456544401127480" |
| "129709999541931989409080416563324524757147869014726780159355" |
| "238611550134803526493472019379026810710749170333222684475333" |
| "572083243193609238289345836806010601150616980975307834227731" |
| "832924790498252473077637592724787465608477820373446969953364" |
| "701797267771758512566055119913150489110145103786273816725095" |
| "583738973359899366480994116420570263709027924276754456522908" |
| "753868250641971826553344726562-323;"}, |
| {"(RU,E757.750,';')", |
| " 0." |
| "494065645841246544176568792868221372365059802614324764425585" |
| "682500675507270208751865299836361635992379796564695445717730" |
| "926656710355939796398774796010781878126300713190311404527845" |
| "817167848982103688718636056998730723050006387409153564984387" |
| "312473397273169615140031715385398074126238565591171026658556" |
| "686768187039560310624931945271591492455329305456544401127480" |
| "129709999541931989409080416563324524757147869014726780159355" |
| "238611550134803526493472019379026810710749170333222684475333" |
| "572083243193609238289345836806010601150616980975307834227731" |
| "832924790498252473077637592724787465608477820373446969953364" |
| "701797267771758512566055119913150489110145103786273816725095" |
| "583738973359899366480994116420570263709027924276754456522908" |
| "753868250641971826553344726563-323;"}, |
| {"(RC,E757.750,';')", |
| " 0." |
| "494065645841246544176568792868221372365059802614324764425585" |
| "682500675507270208751865299836361635992379796564695445717730" |
| "926656710355939796398774796010781878126300713190311404527845" |
| "817167848982103688718636056998730723050006387409153564984387" |
| "312473397273169615140031715385398074126238565591171026658556" |
| "686768187039560310624931945271591492455329305456544401127480" |
| "129709999541931989409080416563324524757147869014726780159355" |
| "238611550134803526493472019379026810710749170333222684475333" |
| "572083243193609238289345836806010601150616980975307834227731" |
| "832924790498252473077637592724787465608477820373446969953364" |
| "701797267771758512566055119913150489110145103786273816725095" |
| "583738973359899366480994116420570263709027924276754456522908" |
| "753868250641971826553344726563-323;"}, |
| {"(EX24.13,';')", " 0X8.0000000000000P-1077;"}, |
| }}, |
| {// least positive nonzero normal |
| 0x10000000000000, |
| { |
| {"(E723.716,';')", |
| " 0." |
| "222507385850720138309023271733240406421921598046233183055332" |
| "741688720443481391819585428315901251102056406733973103581100" |
| "515243416155346010885601238537771882113077799353200233047961" |
| "014744258363607192156504694250373420837525080665061665815894" |
| "872049117996859163964850063590877011830487479978088775374994" |
| "945158045160505091539985658247081864511353793580499211598108" |
| "576605199243335211435239014879569960959128889160299264151106" |
| "346631339366347758651302937176204732563178148566435087212282" |
| "863764204484681140761391147706280168985324411002416144742161" |
| "856716615054015428508471675290190316132277889672970737312333" |
| "408698898317506783884692609277397797285865965494109136909540" |
| "61364675687023986783152906809846172109246253967285156250-" |
| "307;"}, |
| {"(G0,';')", ".22250738585072014E-307;"}, |
| {"(EX24.13,';')", " 0X8.0000000000000P-1025;"}, |
| }}, |
| {// greatest finite |
| 0x7fefffffffffffffuLL, |
| { |
| {"(E32.17,';')", " 0.17976931348623157+309;"}, |
| {"(E317.310,';')", |
| " 0." |
| "179769313486231570814527423731704356798070567525844996598917" |
| "476803157260780028538760589558632766878171540458953514382464" |
| "234321326889464182768467546703537516986049910576551282076245" |
| "490090389328944075868508455133942304583236903222948165808559" |
| "332123348274797826204144723168738177180919299881250404026184" |
| "1248583680+309;"}, |
| {"(ES317.310,';')", |
| " 1." |
| "797693134862315708145274237317043567980705675258449965989174" |
| "768031572607800285387605895586327668781715404589535143824642" |
| "343213268894641827684675467035375169860499105765512820762454" |
| "900903893289440758685084551339423045832369032229481658085593" |
| "321233482747978262041447231687381771809192998812504040261841" |
| "2485836800+308;"}, |
| {"(EN319.310,';')", |
| " 179." |
| "769313486231570814527423731704356798070567525844996598917476" |
| "803157260780028538760589558632766878171540458953514382464234" |
| "321326889464182768467546703537516986049910576551282076245490" |
| "090389328944075868508455133942304583236903222948165808559332" |
| "123348274797826204144723168738177180919299881250404026184124" |
| "8583680000+306;"}, |
| {"(G0,';')", ".17976931348623157E+309;"}, |
| {"(EX24.13,';')", " 0XF.FFFFFFFFFFFF8P+1020;"}, |
| }}, |
| {// EX rounding |
| 0x3ff0100000000000uLL, |
| { |
| {"(F11.8,';')", " 1.00390625;"}, |
| {"(EX10.2,';')", " 0X8.08P-3;"}, |
| {"(EX10.1,';')", " 0X8.0P-3;"}, |
| {"(EX10.0,';')", " 0X8.08P-3;"}, |
| {"(EX0.0,';')", "0X8.08P-3;"}, |
| {"(EX0,';')", "0X8.08P-3;"}, |
| {"(RN,EX10.1,';')", " 0X8.0P-3;"}, |
| {"(RU,EX10.1,';')", " 0X8.1P-3;"}, |
| {"(RD,EX10.1,';')", " 0X8.0P-3;"}, |
| {"(RZ,EX10.1,';')", " 0X8.0P-3;"}, |
| {"(RC,EX10.1,';')", " 0X8.1P-3;"}, |
| {"(RN,EX10.0,';')", " 0X8.08P-3;"}, |
| {"(RU,EX10.0,';')", " 0X8.08P-3;"}, |
| {"(RD,EX10.0,';')", " 0X8.08P-3;"}, |
| {"(RZ,EX10.0,';')", " 0X8.08P-3;"}, |
| {"(RC,EX10.0,';')", " 0X8.08P-3;"}, |
| }}, |
| {// EX rounding |
| 0xbff0100000000000uLL, |
| { |
| {"(F11.8,';')", "-1.00390625;"}, |
| {"(EX10.2,';')", "-0X8.08P-3;"}, |
| {"(EX10.1,';')", " -0X8.0P-3;"}, |
| {"(EX10.0,';')", "-0X8.08P-3;"}, |
| {"(EX0.0,';')", "-0X8.08P-3;"}, |
| {"(EX0,';')", "-0X8.08P-3;"}, |
| {"(RN,EX10.1,';')", " -0X8.0P-3;"}, |
| {"(RU,EX10.1,';')", " -0X8.0P-3;"}, |
| {"(RD,EX10.1,';')", " -0X8.1P-3;"}, |
| {"(RZ,EX10.1,';')", " -0X8.0P-3;"}, |
| {"(RC,EX10.1,';')", " -0X8.1P-3;"}, |
| {"(RN,EX10.0,';')", "-0X8.08P-3;"}, |
| {"(RU,EX10.0,';')", "-0X8.08P-3;"}, |
| {"(RD,EX10.0,';')", "-0X8.08P-3;"}, |
| {"(RZ,EX10.0,';')", "-0X8.08P-3;"}, |
| {"(RC,EX10.0,';')", "-0X8.08P-3;"}, |
| }}, |
| }; |
| |
| for (auto const &[value, cases] : testCases) { |
| for (auto const &[format, expect] : cases) { |
| std::string got; |
| ASSERT_TRUE(CompareFormatReal(format, value, expect, got)) |
| << "Failed to format " << format << ", expected '" << expect |
| << "', got '" << got << "'"; |
| } |
| } |
| |
| using IndividualTestCaseTy = std::tuple<const char *, double, const char *>; |
| static const std::vector<IndividualTestCaseTy> individualTestCases{ |
| {"(F5.3,';')", 25., "*****;"}, |
| {"(F5.3,';')", 2.5, "2.500;"}, |
| {"(F5.3,';')", 0.25, "0.250;"}, |
| {"(F5.3,';')", 0.025, "0.025;"}, |
| {"(F5.3,';')", 0.0025, "0.003;"}, |
| {"(F5.3,';')", 0.00025, "0.000;"}, |
| {"(F5.3,';')", 0.000025, "0.000;"}, |
| {"(F5.3,';')", -25., "*****;"}, |
| {"(F5.3,';')", -2.5, "*****;"}, |
| {"(F5.3,';')", -0.25, "-.250;"}, |
| {"(F5.3,';')", -0.025, "-.025;"}, |
| {"(F5.3,';')", -0.0025, "-.003;"}, |
| {"(F5.3,';')", -0.00025, "-.000;"}, |
| {"(F5.3,';')", -0.000025, "-.000;"}, |
| {"(F5.3,';')", 99.999, "*****;"}, |
| {"(F5.3,';')", 9.9999, "*****;"}, |
| {"(F5.3,';')", 0.99999, "1.000;"}, |
| {"(F5.3,';')", 0.099999, "0.100;"}, |
| {"(F5.3,';')", 0.0099999, "0.010;"}, |
| {"(F5.3,';')", 0.00099999, "0.001;"}, |
| {"(F5.3,';')", |
| 0.0005000000000000000104083408558608425664715468883514404296875, |
| "0.001;"}, |
| {"(F5.3,';')", |
| 0.000499999999999999901988123607310399165726266801357269287109375, |
| "0.000;"}, |
| {"(F5.3,';')", 0.000099999, "0.000;"}, |
| {"(F5.3,';')", -99.999, "*****;"}, |
| {"(F5.3,';')", -9.9999, "*****;"}, |
| {"(F5.3,';')", -0.99999, "*****;"}, |
| {"(F5.3,';')", -0.099999, "-.100;"}, |
| {"(F5.3,';')", -0.0099999, "-.010;"}, |
| {"(F5.3,';')", -0.00099999, "-.001;"}, |
| {"(F5.3,';')", |
| -0.0005000000000000000104083408558608425664715468883514404296875, |
| "-.001;"}, |
| {"(F5.3,';')", |
| -0.000499999999999999901988123607310399165726266801357269287109375, |
| "-.000;"}, |
| {"(F5.3,';')", -0.000099999, "-.000;"}, |
| {"(F0.1,';')", 0.0, ".0;"}, |
| {"(F5.0,';')", -0.5000000000000001, " -1.;"}, |
| {"(F5.0,';')", -0.5, " -0.;"}, |
| {"(F5.0,';')", -0.49999999999999994, " -0.;"}, |
| {"(F5.0,';')", 0.49999999999999994, " 0.;"}, |
| {"(F5.0,';')", 0.5, " 0.;"}, |
| {"(F5.0,';')", 0.5000000000000001, " 1.;"}, |
| }; |
| |
| for (auto const &[format, value, expect] : individualTestCases) { |
| std::string got; |
| char hex[17]; |
| std::snprintf(hex, sizeof hex, "%016llx", |
| *reinterpret_cast<const unsigned long long *>(&value)); |
| ASSERT_TRUE(CompareFormatReal(format, value, expect, got)) |
| << "Failed to format " << value << " 0x" << hex << " with format " |
| << format << ", expected '" << expect << "', got '" << got << "'"; |
| } |
| |
| // Problematic EN formatting edge cases with rounding |
| using IndividualENTestCaseTy = std::tuple<std::uint64_t, const char *>; |
| static const std::vector<IndividualENTestCaseTy> individualENTestCases{ |
| {0x3E11183197785F8C, " 995.0E-12"}, // 0.9950312500000000115852E-09 |
| {0x3E11180E68455D30, " 995.0E-12"}, // 0.9949999999999999761502E-09 |
| {0x3E112BD8F4F6B0D7, " 999.5E-12"}, // 0.9994999999999999089118E-09 |
| {0x3E45794883CA8782, " 10.0E-09"}, // 0.9999499999999999642266E-08 |
| {0x3F506218230C7482, " 999.9E-06"}, // 0.9999499999999998840761E-03 |
| {0x3FB99652BD3C3612, " 100.0E-03"}, // 0.9999500000000000055067E+00 |
| {0x4023E66666666667, " 10.0E+00"}, // 0.9950000000000001065814E+01 |
| }; |
| |
| for (auto const &[value, expect] : individualENTestCases) { |
| std::string got; |
| ASSERT_TRUE(CompareFormatReal("(EN10.1)", value, expect, got)) |
| << "Failed to format EN10.1, expected '" << expect << "', got '" << got |
| << "'"; |
| } |
| } |
| |
| TEST(IOApiTests, FormatIntegerValues) { |
| using IntTestCaseTy = std::tuple<const char *, std::int64_t, const char *>; |
| static const std::vector<IntTestCaseTy> intTestCases{ |
| {"(I4)", 0, " 0"}, |
| {"(I4)", 1, " 1"}, |
| {"(I4)", 9999, "9999"}, |
| {"(SP,I4)", 1, " +1"}, |
| {"(SP,I4)", 9999, "****"}, |
| {"(SP,I4)", 999, "+999"}, |
| {"(I4)", -1, " -1"}, |
| {"(I4)", -9999, "****"}, |
| {"(I4)", -999, "-999"}, |
| {"(I4.2)", 1, " 01"}, |
| {"(I4.2)", -1, " -01"}, |
| {"(I4.2)", 999, " 999"}, |
| {"(I4.4)", 999, "0999"}, |
| {"(I0)", 0, "0"}, |
| {"(I0)", 1, "1"}, |
| {"(I0)", 9999, "9999"}, |
| {"(SP,I0)", 1, "+1"}, |
| {"(SP,I0)", 9999, "+9999"}, |
| {"(SP,I0)", 999, "+999"}, |
| {"(I0)", -1, "-1"}, |
| {"(I0)", -9999, "-9999"}, |
| {"(I0)", -999, "-999"}, |
| {"(I0.2)", 1, "01"}, |
| {"(I0.2)", -1, "-01"}, |
| {"(I0.2)", 999, "999"}, |
| {"(I0.4)", 999, "0999"}, |
| {"(G4)", 0, " 0"}, |
| {"(G4)", 1, " 1"}, |
| {"(G4)", 9999, "9999"}, |
| {"(SP,G4)", 1, " +1"}, |
| {"(SP,G4)", 9999, "****"}, |
| {"(SP,G4)", 999, "+999"}, |
| {"(G4)", -1, " -1"}, |
| {"(G4)", -9999, "****"}, |
| {"(G4)", -999, "-999"}, |
| {"(G4.2)", 1, " 1"}, |
| {"(G4.2)", -1, " -1"}, |
| {"(G4.2)", 999, " 999"}, |
| {"(G4.4)", 999, " 999"}, |
| {"(G0)", 0, "0"}, |
| {"(G0)", 1, "1"}, |
| {"(G0)", 9999, "9999"}, |
| {"(SP,G0)", 1, "+1"}, |
| {"(SP,G0)", 9999, "+9999"}, |
| {"(SP,G0)", 999, "+999"}, |
| {"(G0)", -1, "-1"}, |
| {"(G0)", -9999, "-9999"}, |
| {"(G0)", -999, "-999"}, |
| {"(G0.2)", 1, "1"}, |
| {"(G0.2)", -1, "-1"}, |
| {"(G0.2)", 999, "999"}, |
| {"(G0.4)", 999, "999"}, |
| }; |
| |
| for (auto const &[fmt, value, expect] : intTestCases) { |
| std::string got; |
| ASSERT_TRUE(CompareFormatInteger(fmt, value, expect, got)) |
| << "Failed to format " << fmt << ", expected '" << expect << "', got '" |
| << got << "'"; |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| /// Tests for input editing real values |
| //------------------------------------------------------------------------------ |
| |
| // Ensure double input values correctly map to raw uint64 values |
| TEST(IOApiTests, EditDoubleInputValues) { |
| using TestCaseTy = std::tuple<const char *, const char *, std::uint64_t, int>; |
| int ovf{IostatRealInputOverflow}; |
| static const std::vector<TestCaseTy> testCases{ |
| {"(F18.0)", " 0", 0x0, 0}, |
| {"(F18.0)", " ", 0x0, 0}, |
| {"(F18.0)", " -0", 0x8000000000000000, 0}, |
| {"(F18.0)", " 01", 0x3ff0000000000000, 0}, |
| {"(F18.0)", " 1", 0x3ff0000000000000, 0}, |
| {"(F18.0)", " 125.", 0x405f400000000000, 0}, |
| {"(F18.0)", " 12.5", 0x4029000000000000, 0}, |
| {"(F18.0)", " 1.25", 0x3ff4000000000000, 0}, |
| {"(F18.0)", " 01.25", 0x3ff4000000000000, 0}, |
| {"(F18.0)", " .125", 0x3fc0000000000000, 0}, |
| {"(F18.0)", " 0.125", 0x3fc0000000000000, 0}, |
| {"(F18.0)", " .0625", 0x3fb0000000000000, 0}, |
| {"(F18.0)", " 0.0625", 0x3fb0000000000000, 0}, |
| {"(F18.0)", " 125", 0x405f400000000000, 0}, |
| {"(F18.1)", " 125", 0x4029000000000000, 0}, |
| {"(F18.2)", " 125", 0x3ff4000000000000, 0}, |
| {"(F18.3)", " 125", 0x3fc0000000000000, 0}, |
| {"(-1P,F18.0)", " 125", 0x4093880000000000, 0}, // 1250 |
| {"(1P,F18.0)", " 125", 0x4029000000000000, 0}, // 12.5 |
| {"(BZ,F18.0)", " 125 ", 0x4093880000000000, 0}, // 1250 |
| {"(BZ,F18.0)", " 125 . e +1 ", 0x42a6bcc41e900000, 0}, // 1.25e13 |
| {"(BZ,F18.0)", " . ", 0x0, 0}, |
| {"(BZ,F18.0)", " . e +1 ", 0x0, 0}, |
| {"(DC,F18.0)", " 12,5", 0x4029000000000000, 0}, |
| {"(EX22.0)", "0X0P0 ", 0x0, 0}, // +0. |
| {"(EX22.0)", "-0X0P0 ", 0x8000000000000000, 0}, // -0. |
| {"(EX22.0)", "0X.8P1 ", 0x3ff0000000000000, 0}, // 1.0 |
| {"(EX22.0)", "0X8.P-3 ", 0x3ff0000000000000, 0}, // 1.0 |
| {"(EX22.0)", "0X.1P4 ", 0x3ff0000000000000, 0}, // 1.0 |
| {"(EX22.0)", "0X10.P-4 ", 0x3ff0000000000000, 0}, // 1.0 |
| {"(EX22.0)", "0X8.00P-3 ", 0x3ff0000000000000, 0}, // 1.0 |
| {"(EX22.0)", "0X80.0P-6 ", 0x4000000000000000, 0}, // 2.0 |
| {"(EX22.0)", "0XC.CCCCCCCCCCCDP-7 ", 0x3fb999999999999a, 0}, // 0.1 |
| {"(EX22.0)", "0X.8P-1021 ", 0x0010000000000000, |
| 0}, // min normal |
| {"(EX22.0)", "0X.8P-1022 ", 0x0008000000000000, |
| 0}, // subnormal |
| {"(EX22.0)", "0X.8P-1073 ", 0x0000000000000001, |
| 0}, // min subn. |
| {"(EX22.0)", "0X.FFFFFFFFFFFFF8P1024", 0x7fefffffffffffff, |
| 0}, // max finite |
| {"(EX22.0)", "0X.8P1025 ", 0x7ff0000000000000, ovf}, // +Inf |
| {"(EX22.0)", "-0X.8P1025 ", 0xfff0000000000000, ovf}, // -Inf |
| {"(RC,EX22.0)", "0X1.0000000000000P0 ", 0x3ff0000000000000, 0}, |
| {"(RC,EX22.0)", "0X1.00000000000008P0 ", 0x3ff0000000000001, 0}, |
| {"(RC,EX22.0)", "0X1.000000000000008P0 ", 0x3ff0000000000000, 0}, |
| {"(RC,EX22.0)", "0X1.00000000000004P0 ", 0x3ff0000000000000, 0}, |
| {"(RC,EX22.0)", "0X.80000000000000P1 ", 0x3ff0000000000000, 0}, |
| {"(RC,EX22.0)", "0X.80000000000004P1 ", 0x3ff0000000000001, 0}, |
| {"(RC,EX22.0)", "0X.800000000000004P1 ", 0x3ff0000000000000, 0}, |
| {"(RC,EX22.0)", "0X.80000000000002P1 ", 0x3ff0000000000000, 0}, |
| {"(RZ,F7.0)", " 2.e308", 0x7fefffffffffffff, 0}, // +HUGE() |
| {"(RD,F7.0)", " 2.e308", 0x7fefffffffffffff, 0}, // +HUGE() |
| {"(RU,F7.0)", " 2.e308", 0x7ff0000000000000, ovf}, // +Inf |
| {"(RZ,F7.0)", "-2.e308", 0xffefffffffffffff, 0}, // -HUGE() |
| {"(RD,F7.0)", "-2.e308", 0xfff0000000000000, ovf}, // -Inf |
| {"(RU,F7.0)", "-2.e308", 0xffefffffffffffff, 0}, // -HUGE() |
| {"(RZ,F7.0)", " 1.e999", 0x7fefffffffffffff, 0}, // +HUGE() |
| {"(RD,F7.0)", " 1.e999", 0x7fefffffffffffff, 0}, // +HUGE() |
| {"(RU,F7.0)", " 1.e999", 0x7ff0000000000000, ovf}, // +Inf |
| {"(RZ,F7.0)", "-1.e999", 0xffefffffffffffff, 0}, // -HUGE() |
| {"(RD,F7.0)", "-1.e999", 0xfff0000000000000, ovf}, // -Inf |
| {"(RU,F7.0)", "-1.e999", 0xffefffffffffffff, 0}, // -HUGE() |
| {"(E9.1)", " 1.0E-325", 0x0, 0}, |
| {"(RU,E9.1)", " 1.0E-325", 0x1, 0}, |
| {"(E9.1)", "-1.0E-325", 0x8000000000000000, 0}, |
| {"(RD,E9.1)", "-1.0E-325", 0x8000000000000001, 0}, |
| }; |
| for (auto const &[format, data, want, iostat] : testCases) { |
| auto cookie{IONAME(BeginInternalFormattedInput)( |
| data, std::strlen(data), format, std::strlen(format))}; |
| union { |
| double x; |
| std::uint64_t raw; |
| } u; |
| u.raw = 0; |
| |
| // Read buffer into union value |
| IONAME(EnableHandlers)(cookie, true, true, true, true, true); |
| IONAME(InputReal64)(cookie, u.x); |
| |
| static constexpr int bufferSize{65}; |
| char iomsg[bufferSize]; |
| std::memset(iomsg, '\0', bufferSize - 1); |
| |
| // Ensure no unexpected errors were encountered reading input buffer into |
| // union value |
| IONAME(GetIoMsg)(cookie, iomsg, bufferSize - 1); |
| auto status{IONAME(EndIoStatement)(cookie)}; |
| ASSERT_EQ(status, iostat) |
| << '\'' << format << "' failed reading '" << data << "', status " |
| << static_cast<int>(status) << " != expected " << iostat << " iomsg '" |
| << iomsg << "'"; |
| |
| // Ensure raw uint64 value matches expected conversion from double |
| ASSERT_EQ(u.raw, want) << '\'' << format << "' failed reading '" << data |
| << "', want " << want << ", got " << u.raw; |
| } |
| } |
| |
| // regression test for confusing digit minimization |
| TEST(IOApiTests, ConfusingMinimization) { |
| char buffer[8]{}; |
| auto cookie{IONAME(BeginInternalListOutput)(buffer, sizeof buffer)}; |
| StaticDescriptor<0> staticDescriptor; |
| Descriptor &desc{staticDescriptor.descriptor()}; |
| std::uint16_t x{0x7bff}; // HUGE(0._2) |
| desc.Establish(TypeCode{CFI_type_half_float}, sizeof x, &x, 0, nullptr); |
| desc.Check(); |
| EXPECT_TRUE(IONAME(OutputDescriptor)(cookie, desc)); |
| auto status{IONAME(EndIoStatement)(cookie)}; |
| EXPECT_EQ(status, 0); |
| std::string got{std::string{buffer, sizeof buffer}}; |
| EXPECT_TRUE(CompareFormattedStrings(" 65504. ", got)) |
| << "expected ' 65504. ', got '" << got << '\''; // not 65500.! |
| } |