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