FORMAT("J=",I3) is accepted by a few other Fortran compilers as a valid
format for input as well as for output. The character string edit
descriptor "J=" is interpreted as if it had been 2X on input, causing
two characters to be skipped over. The skipped characters don't have to
match the characters in the literal string. An optional warning is
emitted under control of the -pedantic option.
985 lines
43 KiB
C++
985 lines
43 KiB
C++
//===-- 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-rt/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.;"},
|
|
{"(ES0.0E0,';')", 0.666, "7.E-1;"},
|
|
{"(EN0.0E0,';')", 0.666, "666.E-3;"},
|
|
};
|
|
|
|
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"},
|
|
{"(I)", 999, "999"},
|
|
{"(G)", 999, "999"},
|
|
{"('x',I)", 999, "x 999"},
|
|
{"('x',G)", 999, "x 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},
|
|
{"('str',F3.0)", "xxx125", 0x405f400000000000, 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.!
|
|
}
|