brintos

brintos / llvm-project-archived public Read only

0
0
Text · 17.1 KiB · f190bea Raw
369 lines · cpp
1//===-- unittests/Runtime/Namelist.cpp --------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "flang-rt/runtime/namelist.h"10#include "CrashHandlerFixture.h"11#include "tools.h"12#include "flang-rt/runtime/descriptor.h"13#include "flang/Runtime/io-api.h"14#include <algorithm>15#include <cinttypes>16#include <complex>17#include <cstring>18#include <gtest/gtest.h>19#include <limits>20#include <string>21#include <vector>22 23using namespace Fortran::runtime;24using namespace Fortran::runtime::io;25 26struct NamelistTests : CrashHandlerFixture {};27 28static void ClearDescriptorStorage(const Descriptor &descriptor) {29  std::memset(descriptor.raw().base_addr, 0,30      descriptor.Elements() * descriptor.ElementBytes());31}32 33TEST(NamelistTests, BasicSanity) {34  static constexpr int numLines{12};35  static constexpr int lineLength{32};36  static char buffer[numLines][lineLength];37  StaticDescriptor<1, true> statDescs[1];38  Descriptor &internalDesc{statDescs[0].descriptor()};39  SubscriptValue extent[]{numLines};40  internalDesc.Establish(TypeCode{CFI_type_char}, /*elementBytes=*/lineLength,41      &buffer, 1, extent, CFI_attribute_pointer);42  // Set up data arrays43  std::vector<int> ints;44  for (int j{0}; j < 20; ++j) {45    ints.push_back(j % 2 == 0 ? (1 << j) : -(1 << j));46  }47  std::vector<double> reals{0.0, -0.0, std::numeric_limits<double>::infinity(),48      -std::numeric_limits<double>::infinity(),49      std::numeric_limits<double>::quiet_NaN(),50      std::numeric_limits<double>::max(), std::numeric_limits<double>::lowest(),51      std::numeric_limits<double>::epsilon()};52  std::vector<std::uint8_t> logicals;53  logicals.push_back(false);54  logicals.push_back(true);55  logicals.push_back(false);56  std::vector<std::complex<float>> complexes;57  complexes.push_back(std::complex<float>{123.0, -0.5});58  std::vector<std::string> characters;59  characters.emplace_back("aBcDeFgHiJkLmNoPqRsTuVwXyZ");60  characters.emplace_back("0123456789'\"..............");61  // Copy the data into new descriptors62  OwningPtr<Descriptor> intDesc{63      MakeArray<TypeCategory::Integer, static_cast<int>(sizeof(int))>(64          std::vector<int>{5, 4}, std::move(ints))};65  OwningPtr<Descriptor> realDesc{66      MakeArray<TypeCategory::Real, static_cast<int>(sizeof(double))>(67          std::vector<int>{4, 2}, std::move(reals))};68  OwningPtr<Descriptor> logicalDesc{69      MakeArray<TypeCategory::Logical, static_cast<int>(sizeof(std::uint8_t))>(70          std::vector<int>{3}, std::move(logicals))};71  OwningPtr<Descriptor> complexDesc{72      MakeArray<TypeCategory::Complex, static_cast<int>(sizeof(float))>(73          std::vector<int>{}, std::move(complexes))};74  OwningPtr<Descriptor> characterDesc{MakeArray<TypeCategory::Character, 1>(75      std::vector<int>{2}, std::move(characters), characters[0].size())};76  // Create a NAMELIST group77  static constexpr int items{5};78  const NamelistGroup::Item itemArray[items]{{"ints", *intDesc},79      {"reals", *realDesc}, {"logicals", *logicalDesc},80      {"complexes", *complexDesc}, {"characters", *characterDesc}};81  const NamelistGroup group{"group1", items, itemArray};82  // Do an internal NAMELIST write and check results83  auto outCookie1{IONAME(BeginInternalArrayListOutput)(84      internalDesc, nullptr, 0, __FILE__, __LINE__)};85  ASSERT_TRUE(IONAME(SetDelim)(outCookie1, "APOSTROPHE", 10));86  ASSERT_TRUE(IONAME(OutputNamelist)(outCookie1, group));87  auto outStatus1{IONAME(EndIoStatement)(outCookie1)};88  ASSERT_EQ(outStatus1, 0) << "Failed namelist output sanity, status "89                           << static_cast<int>(outStatus1);90 91  static const std::string expect{" &GROUP1 INTS= 1 -2 4 -8 16 -32 "92                                  " 64 -128 256 -512 1024 -2048    "93                                  " 4096 -8192 16384 -32768 65536  "94                                  " -131072 262144 -524288,REALS=  "95                                  " 0. -0. Inf -Inf NaN            "96                                  " 1.7976931348623157E+308        "97                                  " -1.7976931348623157E+308       "98                                  " 2.220446049250313E-16,LOGICALS="99                                  "F T F,COMPLEXES= (123.,-.5),    "100                                  " CHARACTERS= 'aBcDeFgHiJkLmNoPqR"101                                  "sTuVwXyZ' '0123456789''\"........"102                                  "......'/                        "};103  std::string got{buffer[0], sizeof buffer};104  EXPECT_EQ(got, expect);105 106  // Clear the arrays, read them back, write out again, and compare107  ClearDescriptorStorage(*intDesc);108  ClearDescriptorStorage(*realDesc);109  ClearDescriptorStorage(*logicalDesc);110  ClearDescriptorStorage(*complexDesc);111  ClearDescriptorStorage(*characterDesc);112  auto inCookie{IONAME(BeginInternalArrayListInput)(113      internalDesc, nullptr, 0, __FILE__, __LINE__)};114  ASSERT_TRUE(IONAME(InputNamelist)(inCookie, group));115  auto inStatus{IONAME(EndIoStatement)(inCookie)};116  ASSERT_EQ(inStatus, 0) << "Failed namelist input sanity, status "117                         << static_cast<int>(inStatus);118  auto outCookie2{IONAME(BeginInternalArrayListOutput)(119      internalDesc, nullptr, 0, __FILE__, __LINE__)};120  ASSERT_TRUE(IONAME(SetDelim)(outCookie2, "APOSTROPHE", 10));121  ASSERT_TRUE(IONAME(OutputNamelist)(outCookie2, group));122  auto outStatus2{IONAME(EndIoStatement)(outCookie2)};123  ASSERT_EQ(outStatus2, 0) << "Failed namelist output sanity rewrite, status "124                           << static_cast<int>(outStatus2);125  std::string got2{buffer[0], sizeof buffer};126  EXPECT_EQ(got2, expect);127}128 129TEST(NamelistTests, Subscripts) {130  // INTEGER :: A(-1:0, -1:1)131  OwningPtr<Descriptor> aDesc{132      MakeArray<TypeCategory::Integer, static_cast<int>(sizeof(int))>(133          std::vector<int>{2, 3}, std::vector<int>(6, 0))};134  aDesc->GetDimension(0).SetBounds(-1, 0);135  aDesc->GetDimension(1).SetBounds(-1, 1);136  const NamelistGroup::Item items[]{{"a", *aDesc}};137  const NamelistGroup group{"justa", 1, items};138  static char t1[]{"&justa A(0,+1:-1:-2)=1 2/"};139  StaticDescriptor<1, true> statDesc;140  Descriptor &internalDesc{statDesc.descriptor()};141  internalDesc.Establish(TypeCode{CFI_type_char},142      /*elementBytes=*/std::strlen(t1), t1, 0, nullptr, CFI_attribute_pointer);143  auto inCookie{IONAME(BeginInternalArrayListInput)(144      internalDesc, nullptr, 0, __FILE__, __LINE__)};145  ASSERT_TRUE(IONAME(InputNamelist)(inCookie, group));146  auto inStatus{IONAME(EndIoStatement)(inCookie)};147  ASSERT_EQ(inStatus, 0) << "Failed namelist input subscripts, status "148                         << static_cast<int>(inStatus);149  char out[40];150  internalDesc.Establish(TypeCode{CFI_type_char}, /*elementBytes=*/sizeof out,151      out, 0, nullptr, CFI_attribute_pointer);152  auto outCookie{IONAME(BeginInternalArrayListOutput)(153      internalDesc, nullptr, 0, __FILE__, __LINE__)};154  ASSERT_TRUE(IONAME(OutputNamelist)(outCookie, group));155  auto outStatus{IONAME(EndIoStatement)(outCookie)};156  ASSERT_EQ(outStatus, 0)157      << "Failed namelist output subscripts rewrite, status "158      << static_cast<int>(outStatus);159  std::string got{out, sizeof out};160  static const std::string expect{" &JUSTA A= 0 2 0 0 0 1/                 "};161  EXPECT_EQ(got, expect);162}163 164TEST(NamelistTests, ShortArrayInput) {165  OwningPtr<Descriptor> aDesc{166      MakeArray<TypeCategory::Integer, static_cast<int>(sizeof(int))>(167          std::vector<int>{2}, std::vector<int>(2, -1))};168  OwningPtr<Descriptor> bDesc{169      MakeArray<TypeCategory::Integer, static_cast<int>(sizeof(int))>(170          std::vector<int>{2}, std::vector<int>(2, -2))};171  const NamelistGroup::Item items[]{{"a", *aDesc}, {"b", *bDesc}};172  const NamelistGroup group{"nl", 2, items};173  // Two 12-character lines of internal input174  static char t1[]{"&nl a = 1 b "175                   " = 2 /      "};176  StaticDescriptor<1, true> statDesc;177  Descriptor &internalDesc{statDesc.descriptor()};178  SubscriptValue shape{2};179  internalDesc.Establish(1, 12, t1, 1, &shape, CFI_attribute_pointer);180  auto inCookie{IONAME(BeginInternalArrayListInput)(181      internalDesc, nullptr, 0, __FILE__, __LINE__)};182  ASSERT_TRUE(IONAME(InputNamelist)(inCookie, group));183  auto inStatus{IONAME(EndIoStatement)(inCookie)};184  ASSERT_EQ(inStatus, 0) << "Failed namelist input subscripts, status "185                         << static_cast<int>(inStatus);186  EXPECT_EQ(*aDesc->ZeroBasedIndexedElement<int>(0), 1);187  EXPECT_EQ(*aDesc->ZeroBasedIndexedElement<int>(1), -1);188  EXPECT_EQ(*bDesc->ZeroBasedIndexedElement<int>(0), 2);189  EXPECT_EQ(*bDesc->ZeroBasedIndexedElement<int>(1), -2);190}191 192TEST(NamelistTests, ScalarSubstring) {193  OwningPtr<Descriptor> scDesc{MakeArray<TypeCategory::Character, 1>(194      std::vector<int>{}, std::vector<std::string>{"abcdefgh"}, 8)};195  const NamelistGroup::Item items[]{{"a", *scDesc}};196  const NamelistGroup group{"justa", 1, items};197  static char t1[]{"&justa A(2:5)='BCDE'/"};198  StaticDescriptor<1, true> statDesc;199  Descriptor &internalDesc{statDesc.descriptor()};200  internalDesc.Establish(TypeCode{CFI_type_char},201      /*elementBytes=*/std::strlen(t1), t1, 0, nullptr, CFI_attribute_pointer);202  auto inCookie{IONAME(BeginInternalArrayListInput)(203      internalDesc, nullptr, 0, __FILE__, __LINE__)};204  ASSERT_TRUE(IONAME(InputNamelist)(inCookie, group));205  ASSERT_EQ(IONAME(EndIoStatement)(inCookie), IostatOk)206      << "namelist scalar substring input";207  char out[32];208  internalDesc.Establish(TypeCode{CFI_type_char}, /*elementBytes=*/sizeof out,209      out, 0, nullptr, CFI_attribute_pointer);210  auto outCookie{IONAME(BeginInternalArrayListOutput)(211      internalDesc, nullptr, 0, __FILE__, __LINE__)};212  ASSERT_TRUE(IONAME(SetDelim)(outCookie, "apostrophe", 10));213  ASSERT_TRUE(IONAME(OutputNamelist)(outCookie, group));214  ASSERT_EQ(IONAME(EndIoStatement)(outCookie), IostatOk) << "namelist output";215  std::string got{out, sizeof out};216  static const std::string expect{" &JUSTA A= 'aBCDEfgh'/          "};217  EXPECT_EQ(got, expect);218}219 220TEST(NamelistTests, ArraySubstring) {221  OwningPtr<Descriptor> scDesc{222      MakeArray<TypeCategory::Character, 1>(std::vector<int>{2},223          std::vector<std::string>{"abcdefgh", "ijklmnop"}, 8)};224  const NamelistGroup::Item items[]{{"a", *scDesc}};225  const NamelistGroup group{"justa", 1, items};226  static char t1[]{"&justa A(:)(2:+5)='BCDE' 'JKLM'/"};227  StaticDescriptor<1, true> statDesc;228  Descriptor &internalDesc{statDesc.descriptor()};229  internalDesc.Establish(TypeCode{CFI_type_char},230      /*elementBytes=*/std::strlen(t1), t1, 0, nullptr, CFI_attribute_pointer);231  auto inCookie{IONAME(BeginInternalArrayListInput)(232      internalDesc, nullptr, 0, __FILE__, __LINE__)};233  ASSERT_TRUE(IONAME(InputNamelist)(inCookie, group));234  ASSERT_EQ(IONAME(EndIoStatement)(inCookie), IostatOk)235      << "namelist scalar substring input";236  char out[40];237  internalDesc.Establish(TypeCode{CFI_type_char}, /*elementBytes=*/sizeof out,238      out, 0, nullptr, CFI_attribute_pointer);239  auto outCookie{IONAME(BeginInternalArrayListOutput)(240      internalDesc, nullptr, 0, __FILE__, __LINE__)};241  ASSERT_TRUE(IONAME(SetDelim)(outCookie, "apostrophe", 10));242  ASSERT_TRUE(IONAME(OutputNamelist)(outCookie, group));243  ASSERT_EQ(IONAME(EndIoStatement)(outCookie), IostatOk) << "namelist output";244  std::string got{out, sizeof out};245  static const std::string expect{" &JUSTA A= 'aBCDEfgh' 'iJKLMnop'/       "};246  EXPECT_EQ(got, expect);247}248 249TEST(NamelistTests, Skip) {250  OwningPtr<Descriptor> scDesc{251      MakeArray<TypeCategory::Integer, static_cast<int>(sizeof(int))>(252          std::vector<int>{}, std::vector<int>{-1})};253  const NamelistGroup::Item items[]{{"j", *scDesc}};254  const NamelistGroup group{"nml", 1, items};255  static char t1[]{"&skip a='str''ing'/&nml j=123/"};256  StaticDescriptor<1, true> statDesc;257  Descriptor &internalDesc{statDesc.descriptor()};258  internalDesc.Establish(TypeCode{CFI_type_char},259      /*elementBytes=*/std::strlen(t1), t1, 0, nullptr, CFI_attribute_pointer);260  auto inCookie{IONAME(BeginInternalArrayListInput)(261      internalDesc, nullptr, 0, __FILE__, __LINE__)};262  ASSERT_TRUE(IONAME(InputNamelist)(inCookie, group));263  ASSERT_EQ(IONAME(EndIoStatement)(inCookie), IostatOk)264      << "namelist input with skipping";265  char out[20];266  internalDesc.Establish(TypeCode{CFI_type_char}, /*elementBytes=*/sizeof out,267      out, 0, nullptr, CFI_attribute_pointer);268  auto outCookie{IONAME(BeginInternalArrayListOutput)(269      internalDesc, nullptr, 0, __FILE__, __LINE__)};270  ASSERT_TRUE(IONAME(OutputNamelist)(outCookie, group));271  ASSERT_EQ(IONAME(EndIoStatement)(outCookie), IostatOk) << "namelist output";272  std::string got{out, sizeof out};273  static const std::string expect{" &NML J= 123/       "};274  EXPECT_EQ(got, expect);275}276 277// Tests DECIMAL=COMMA mode278TEST(NamelistTests, Comma) {279  OwningPtr<Descriptor> scDesc{280      MakeArray<TypeCategory::Complex, static_cast<int>(sizeof(float))>(281          std::vector<int>{2}, std::vector<std::complex<float>>{{}, {}})};282  const NamelistGroup::Item items[]{{"z", *scDesc}};283  const NamelistGroup group{"nml", 1, items};284  static char t1[]{"&nml z=(-1,0;2,0);(-3,0;0,5)/"};285  StaticDescriptor<1, true> statDesc;286  Descriptor &internalDesc{statDesc.descriptor()};287  internalDesc.Establish(TypeCode{CFI_type_char},288      /*elementBytes=*/std::strlen(t1), t1, 0, nullptr, CFI_attribute_pointer);289  auto inCookie{IONAME(BeginInternalArrayListInput)(290      internalDesc, nullptr, 0, __FILE__, __LINE__)};291  ASSERT_TRUE(IONAME(SetDecimal)(inCookie, "COMMA", 5));292  ASSERT_TRUE(IONAME(InputNamelist)(inCookie, group));293  ASSERT_EQ(IONAME(EndIoStatement)(inCookie), IostatOk)294      << "namelist input with skipping";295  char out[30];296  internalDesc.Establish(TypeCode{CFI_type_char}, /*elementBytes=*/sizeof out,297      out, 0, nullptr, CFI_attribute_pointer);298  auto outCookie{IONAME(BeginInternalArrayListOutput)(299      internalDesc, nullptr, 0, __FILE__, __LINE__)};300  ASSERT_TRUE(IONAME(SetDecimal)(outCookie, "COMMA", 5));301  ASSERT_TRUE(IONAME(OutputNamelist)(outCookie, group));302  ASSERT_EQ(IONAME(EndIoStatement)(outCookie), IostatOk) << "namelist output";303  std::string got{out, sizeof out};304  static const std::string expect{" &NML Z= (-1,;2,) (-3,;,5)/   "};305  EXPECT_EQ(got, expect);306}307 308// Tests REAL-looking input to integers309TEST(NamelistTests, RealValueForInt) {310  OwningPtr<Descriptor> scDesc{311      MakeArray<TypeCategory::Integer, static_cast<int>(sizeof(int))>(312          std::vector<int>{}, std::vector<int>{{}})};313  const NamelistGroup::Item items[]{{"j", *scDesc}};314  const NamelistGroup group{"nml", 1, items};315  static char t1[]{"&nml j=123.456/"};316  StaticDescriptor<1, true> statDesc;317  Descriptor &internalDesc{statDesc.descriptor()};318  internalDesc.Establish(TypeCode{CFI_type_char},319      /*elementBytes=*/std::strlen(t1), t1, 0, nullptr, CFI_attribute_pointer);320  auto inCookie{IONAME(BeginInternalArrayListInput)(321      internalDesc, nullptr, 0, __FILE__, __LINE__)};322  ASSERT_TRUE(IONAME(InputNamelist)(inCookie, group));323  ASSERT_EQ(IONAME(EndIoStatement)(inCookie), IostatOk)324      << "namelist real input for integer";325  char out[16];326  internalDesc.Establish(TypeCode{CFI_type_char}, /*elementBytes=*/sizeof out,327      out, 0, nullptr, CFI_attribute_pointer);328  auto outCookie{IONAME(BeginInternalArrayListOutput)(329      internalDesc, nullptr, 0, __FILE__, __LINE__)};330  ASSERT_TRUE(IONAME(OutputNamelist)(outCookie, group));331  ASSERT_EQ(IONAME(EndIoStatement)(outCookie), IostatOk) << "namelist output";332  std::string got{out, sizeof out};333  static const std::string expect{" &NML J= 123/   "};334  EXPECT_EQ(got, expect);335}336 337TEST(NamelistTests, NanInputAmbiguity) {338  OwningPtr<Descriptor> xDesc{// real :: x(5) = 0.339      MakeArray<TypeCategory::Real, static_cast<int>(sizeof(float))>(340          std::vector<int>{5}, std::vector<float>{{0, 0, 0, 0, 0}})};341  OwningPtr<Descriptor> nanDesc{// real :: nan(2) = 0.342      MakeArray<TypeCategory::Real, static_cast<int>(sizeof(float))>(343          std::vector<int>{2}, std::vector<float>{{0, 0}})};344  const NamelistGroup::Item items[]{{"x", *xDesc}, {"nan", *nanDesc}};345  const NamelistGroup group{"nml", 2, items};346  static char t1[]{"&nml x=1 2 nan(q) 4 nan(1)=5 nan(q)/"};347  StaticDescriptor<1, true> statDesc;348  Descriptor &internalDesc{statDesc.descriptor()};349  internalDesc.Establish(TypeCode{CFI_type_char},350      /*elementBytes=*/std::strlen(t1), t1, 0, nullptr, CFI_attribute_pointer);351  auto inCookie{IONAME(BeginInternalArrayListInput)(352      internalDesc, nullptr, 0, __FILE__, __LINE__)};353  ASSERT_TRUE(IONAME(InputNamelist)(inCookie, group));354  ASSERT_EQ(IONAME(EndIoStatement)(inCookie), IostatOk)355      << "namelist real input for nans";356  char out[40];357  internalDesc.Establish(TypeCode{CFI_type_char}, /*elementBytes=*/sizeof out,358      out, 0, nullptr, CFI_attribute_pointer);359  auto outCookie{IONAME(BeginInternalArrayListOutput)(360      internalDesc, nullptr, 0, __FILE__, __LINE__)};361  ASSERT_TRUE(IONAME(OutputNamelist)(outCookie, group));362  ASSERT_EQ(IONAME(EndIoStatement)(outCookie), IostatOk) << "namelist output";363  std::string got{out, sizeof out};364  static const std::string expect{" &NML X= 1. 2. NaN 4. 0.,NAN= 5. NaN/   "};365  EXPECT_EQ(got, expect);366}367 368// TODO: Internal NAMELIST error tests369