194 lines · cpp
1//===-- unittests/Runtime/ListInputTest.cpp ---------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "CrashHandlerFixture.h"10#include "flang-rt/runtime/descriptor.h"11#include "flang-rt/runtime/io-error.h"12#include "flang/Runtime/io-api.h"13 14using namespace Fortran::runtime;15using namespace Fortran::runtime::io;16 17// Pads characters with whitespace when needed18void SetCharacter(char *to, std::size_t n, const char *from) {19 auto len{std::strlen(from)};20 std::memcpy(to, from, std::min(len, n));21 if (len < n) {22 std::memset(to + len, ' ', n - len);23 }24}25 26struct InputTest : CrashHandlerFixture {};27 28TEST(InputTest, TestListInputAlphabet) {29 constexpr int numInputBuffers{2};30 constexpr int maxInputBufferLength{32};31 char inputBuffers[numInputBuffers][maxInputBufferLength];32 const char expectedOutput[]{33 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ "};34 int j{0};35 36 // Use _two_ input buffers and _three_ output buffers. Note the `3*` in the37 // _inputBuffers_.38 SetCharacter(inputBuffers[j++], maxInputBufferLength,39 "3*'abcdefghijklmnopqrstuvwxyzABC");40 SetCharacter(41 inputBuffers[j++], maxInputBufferLength, "DEFGHIJKLMNOPQRSTUVWXYZ'");42 43 StaticDescriptor<1> staticDescriptor;44 Descriptor &whole{staticDescriptor.descriptor()};45 SubscriptValue extent[]{numInputBuffers};46 whole.Establish(TypeCode{CFI_type_char}, maxInputBufferLength, &inputBuffers,47 1, extent, CFI_attribute_pointer);48 whole.Check();49 auto *cookie{IONAME(BeginInternalArrayListInput)(whole)};50 51 constexpr int numOutputBuffers{3};52 constexpr int outputBufferLength{54};53 char outputBuffers[numOutputBuffers][outputBufferLength]{};54 for (j = 0; j < numOutputBuffers; ++j) {55 IONAME(InputAscii)(cookie, outputBuffers[j], outputBufferLength - 1);56 }57 58 const auto status{IONAME(EndIoStatement)(cookie)};59 ASSERT_EQ(status, 0) << "list-directed input failed, status "60 << static_cast<int>(status) << '\n';61 62 // Verify results that the _two_ ascii inputs result in _three_ alphabets63 for (j = 0; j < numOutputBuffers; ++j) {64 ASSERT_EQ(std::strcmp(outputBuffers[j], expectedOutput), 0)65 << "wanted outputBuffers[" << j << "]=" << expectedOutput << ", got '"66 << outputBuffers[j] << "'\n";67 }68}69 70TEST(InputTest, TestListInputIntegerList) {71 constexpr int numBuffers{2};72 constexpr int maxBufferLength{32};73 char buffer[numBuffers][maxBufferLength];74 int j{0};75 SetCharacter(buffer[j++], maxBufferLength, "1 2 2*3 ,");76 SetCharacter(buffer[j++], maxBufferLength, ",6,,8,2*");77 78 StaticDescriptor<1> staticDescriptor;79 Descriptor &whole{staticDescriptor.descriptor()};80 SubscriptValue extent[]{numBuffers};81 whole.Establish(TypeCode{CFI_type_char}, maxBufferLength, &buffer, 1, extent,82 CFI_attribute_pointer);83 whole.Check();84 auto *cookie{IONAME(BeginInternalArrayListInput)(whole)};85 86 constexpr int listInputLength{10};87 88 // Negative numbers will be overwritten by _expectedOutput_, and positive89 // numbers will not be as their indices are "Null values" of the Fortran 201890 // standard 13.10.3.2 in the format strings _buffer_91 std::int64_t actualOutput[listInputLength]{92 -1, -2, -3, -4, 5, -6, 7, -8, 9, 10};93 const std::int64_t expectedOutput[listInputLength]{94 1, 2, 3, 3, 5, 6, 7, 8, 9, 10};95 for (j = 0; j < listInputLength; ++j) {96 IONAME(InputInteger)(cookie, actualOutput[j]);97 }98 99 const auto status{IONAME(EndIoStatement)(cookie)};100 ASSERT_EQ(status, 0) << "list-directed input failed, status "101 << static_cast<int>(status) << '\n';102 103 // Verify the calls to _InputInteger_ resulted in _expectedOutput_104 for (j = 0; j < listInputLength; ++j) {105 ASSERT_EQ(actualOutput[j], expectedOutput[j])106 << "wanted actualOutput[" << j << "]==" << expectedOutput[j] << ", got "107 << actualOutput[j] << '\n';108 }109}110 111TEST(InputTest, TestListInputInvalidFormatWithSingleSuccess) {112 std::string formatBuffer{"1, g"};113 constexpr int numBuffers{1};114 115 StaticDescriptor<1> staticDescriptor;116 Descriptor &whole{staticDescriptor.descriptor()};117 SubscriptValue extent[]{numBuffers};118 whole.Establish(TypeCode{CFI_type_char}, formatBuffer.size(),119 formatBuffer.data(), 1, extent, CFI_attribute_pointer);120 whole.Check();121 122 auto *cookie{IONAME(BeginInternalArrayListInput)(whole)};123 std::int64_t dummy;124 125 // Perform _InputInteger_ once successfully126 IONAME(InputInteger)(cookie, dummy);127 128 // Perform failing InputInteger129 ASSERT_DEATH(IONAME(InputInteger)(cookie, dummy),130 "Bad character 'g' in INTEGER input field");131}132 133// Same test as _TestListInputInvalidFormatWithSingleSuccess_, however no134// successful call to _InputInteger_ is performed first.135TEST(InputTest, TestListInputInvalidFormat) {136 std::string formatBuffer{"g"};137 constexpr int numBuffers{1};138 139 StaticDescriptor<1> staticDescriptor;140 Descriptor &whole{staticDescriptor.descriptor()};141 SubscriptValue extent[]{numBuffers};142 whole.Establish(TypeCode{CFI_type_char}, formatBuffer.size(),143 formatBuffer.data(), 1, extent, CFI_attribute_pointer);144 whole.Check();145 146 auto *cookie{IONAME(BeginInternalArrayListInput)(whole)};147 std::int64_t dummy;148 149 // Perform failing InputInteger150 ASSERT_DEATH(IONAME(InputInteger)(cookie, dummy),151 "Bad character 'g' in INTEGER input field");152}153 154using ParamTy = std::tuple<std::string, std::vector<int>>;155 156struct SimpleListInputTest : testing::TestWithParam<ParamTy> {};157 158TEST_P(SimpleListInputTest, TestListInput) {159 auto [formatBuffer, expectedOutput] = GetParam();160 constexpr int numBuffers{1};161 162 StaticDescriptor<1> staticDescriptor;163 Descriptor &whole{staticDescriptor.descriptor()};164 SubscriptValue extent[]{numBuffers};165 whole.Establish(TypeCode{CFI_type_char}, formatBuffer.size(),166 formatBuffer.data(), 1, extent, CFI_attribute_pointer);167 whole.Check();168 auto *cookie{IONAME(BeginInternalArrayListInput)(whole)};169 170 const auto listInputLength{expectedOutput.size()};171 std::vector<std::int64_t> actualOutput(listInputLength);172 for (std::size_t j = 0; j < listInputLength; ++j) {173 IONAME(InputInteger)(cookie, actualOutput[j]);174 }175 176 const auto status{IONAME(EndIoStatement)(cookie)};177 ASSERT_EQ(status, 0) << "list-directed input failed, status "178 << static_cast<int>(status) << '\n';179 180 // Verify the calls to _InputInteger_ resulted in _expectedOutput_181 for (std::size_t j = 0; j < listInputLength; ++j) {182 ASSERT_EQ(actualOutput[j], expectedOutput[j])183 << "wanted actualOutput[" << j << "]==" << expectedOutput[j] << ", got "184 << actualOutput[j] << '\n';185 }186}187 188INSTANTIATE_TEST_SUITE_P(SimpleListInputTestInstantiation, SimpleListInputTest,189 testing::Values(std::make_tuple("", std::vector<int>{}),190 std::make_tuple("0", std::vector<int>{}),191 std::make_tuple("1", std::vector<int>{1}),192 std::make_tuple("1, 2", std::vector<int>{1, 2}),193 std::make_tuple("3*2", std::vector<int>{2, 2, 2})));194