[AArch64] Prevent argument promotion of vector with size > 128 bits (#70034)
[llvm-project.git] / flang / unittests / Runtime / CommandTest.cpp
blobc3571c9684e4b0769d269de3637342f85cd1f5d9
1 //===-- flang/unittests/Runtime/CommandTest.cpp ---------------------------===//
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-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "flang/Runtime/command.h"
10 #include "gmock/gmock.h"
11 #include "gtest/gtest.h"
12 #include "flang/Runtime/descriptor.h"
13 #include "flang/Runtime/main.h"
14 #include <cstdlib>
16 using namespace Fortran::runtime;
18 template <std::size_t n = 64>
19 static OwningPtr<Descriptor> CreateEmptyCharDescriptor() {
20 OwningPtr<Descriptor> descriptor{Descriptor::Create(
21 sizeof(char), n, nullptr, 0, nullptr, CFI_attribute_allocatable)};
22 if (descriptor->Allocate() != 0) {
23 return nullptr;
25 return descriptor;
28 static OwningPtr<Descriptor> CharDescriptor(const char *value) {
29 std::size_t n{std::strlen(value)};
30 OwningPtr<Descriptor> descriptor{Descriptor::Create(
31 sizeof(char), n, nullptr, 0, nullptr, CFI_attribute_allocatable)};
32 if (descriptor->Allocate() != 0) {
33 return nullptr;
35 std::memcpy(descriptor->OffsetElement(), value, n);
36 return descriptor;
39 template <int kind = sizeof(std::int64_t)>
40 static OwningPtr<Descriptor> EmptyIntDescriptor() {
41 OwningPtr<Descriptor> descriptor{Descriptor::Create(TypeCategory::Integer,
42 kind, nullptr, 0, nullptr, CFI_attribute_allocatable)};
43 if (descriptor->Allocate() != 0) {
44 return nullptr;
46 return descriptor;
49 class CommandFixture : public ::testing::Test {
50 protected:
51 CommandFixture(int argc, const char *argv[]) {
52 RTNAME(ProgramStart)(argc, argv, {}, {});
55 std::string GetPaddedStr(const char *text, std::size_t len) const {
56 std::string res{text};
57 assert(res.length() <= len && "No room to pad");
58 res.append(len - res.length(), ' ');
59 return res;
62 void CheckDescriptorEqStr(
63 const Descriptor *value, const std::string &expected) const {
64 ASSERT_NE(value, nullptr);
65 EXPECT_EQ(std::strncmp(value->OffsetElement(), expected.c_str(),
66 value->ElementBytes()),
68 << "expected: " << expected << "\n"
69 << "value: "
70 << std::string{value->OffsetElement(), value->ElementBytes()};
73 template <typename INT_T = std::int64_t>
74 void CheckDescriptorEqInt(
75 const Descriptor *value, const INT_T expected) const {
76 if (expected != -1) {
77 ASSERT_NE(value, nullptr);
78 EXPECT_EQ(*value->OffsetElement<INT_T>(), expected);
82 template <typename RuntimeCall>
83 void CheckValue(RuntimeCall F, const char *expectedValue,
84 std::int64_t expectedLength = -1, std::int32_t expectedStatus = 0,
85 const char *expectedErrMsg = "shouldn't change") const {
86 OwningPtr<Descriptor> value{CreateEmptyCharDescriptor()};
87 ASSERT_NE(value, nullptr);
89 OwningPtr<Descriptor> length{
90 expectedLength == -1 ? nullptr : EmptyIntDescriptor()};
92 OwningPtr<Descriptor> errmsg{CharDescriptor(expectedErrMsg)};
93 ASSERT_NE(errmsg, nullptr);
95 std::string expectedValueStr{
96 GetPaddedStr(expectedValue, value->ElementBytes())};
98 EXPECT_EQ(F(value.get(), length.get(), errmsg.get()), expectedStatus);
99 CheckDescriptorEqStr(value.get(), expectedValueStr);
100 CheckDescriptorEqInt(length.get(), expectedLength);
101 CheckDescriptorEqStr(errmsg.get(), expectedErrMsg);
104 void CheckArgumentValue(const char *expectedValue, int n) const {
105 SCOPED_TRACE(n);
106 SCOPED_TRACE("Checking argument:");
107 CheckValue(
108 [&](const Descriptor *value, const Descriptor *length,
109 const Descriptor *errmsg) {
110 return RTNAME(GetCommandArgument)(n, value, length, errmsg);
112 expectedValue, std::strlen(expectedValue));
115 void CheckCommandValue(const char *args[], int n) const {
116 SCOPED_TRACE("Checking command:");
117 ASSERT_GE(n, 1);
118 std::string expectedValue{args[0]};
119 for (int i = 1; i < n; i++) {
120 expectedValue += " " + std::string{args[i]};
122 CheckValue(
123 [&](const Descriptor *value, const Descriptor *length,
124 const Descriptor *errmsg) {
125 return RTNAME(GetCommand)(value, length, errmsg);
127 expectedValue.c_str(), expectedValue.size());
130 void CheckEnvVarValue(
131 const char *expectedValue, const char *name, bool trimName = true) const {
132 SCOPED_TRACE(name);
133 SCOPED_TRACE("Checking environment variable");
134 CheckValue(
135 [&](const Descriptor *value, const Descriptor *length,
136 const Descriptor *errmsg) {
137 return RTNAME(GetEnvVariable)(
138 *CharDescriptor(name), value, length, trimName, errmsg);
140 expectedValue, std::strlen(expectedValue));
143 void CheckMissingEnvVarValue(const char *name, bool trimName = true) const {
144 SCOPED_TRACE(name);
145 SCOPED_TRACE("Checking missing environment variable");
147 ASSERT_EQ(nullptr, std::getenv(name))
148 << "Environment variable " << name << " not expected to exist";
150 CheckValue(
151 [&](const Descriptor *value, const Descriptor *length,
152 const Descriptor *errmsg) {
153 return RTNAME(GetEnvVariable)(
154 *CharDescriptor(name), value, length, trimName, errmsg);
156 "", 0, 1, "Missing environment variable");
159 void CheckMissingArgumentValue(int n, const char *errStr = nullptr) const {
160 OwningPtr<Descriptor> value{CreateEmptyCharDescriptor()};
161 ASSERT_NE(value, nullptr);
163 OwningPtr<Descriptor> length{EmptyIntDescriptor()};
164 ASSERT_NE(length, nullptr);
166 OwningPtr<Descriptor> err{errStr ? CreateEmptyCharDescriptor() : nullptr};
168 EXPECT_GT(
169 RTNAME(GetCommandArgument)(n, value.get(), length.get(), err.get()), 0);
171 std::string spaces(value->ElementBytes(), ' ');
172 CheckDescriptorEqStr(value.get(), spaces);
174 CheckDescriptorEqInt(length.get(), 0);
176 if (errStr) {
177 std::string paddedErrStr(GetPaddedStr(errStr, err->ElementBytes()));
178 CheckDescriptorEqStr(err.get(), paddedErrStr);
182 void CheckMissingCommandValue(const char *errStr = nullptr) const {
183 OwningPtr<Descriptor> value{CreateEmptyCharDescriptor()};
184 ASSERT_NE(value, nullptr);
186 OwningPtr<Descriptor> length{EmptyIntDescriptor()};
187 ASSERT_NE(length, nullptr);
189 OwningPtr<Descriptor> err{errStr ? CreateEmptyCharDescriptor() : nullptr};
191 EXPECT_GT(RTNAME(GetCommand)(value.get(), length.get(), err.get()), 0);
193 std::string spaces(value->ElementBytes(), ' ');
194 CheckDescriptorEqStr(value.get(), spaces);
196 CheckDescriptorEqInt(length.get(), 0);
198 if (errStr) {
199 std::string paddedErrStr(GetPaddedStr(errStr, err->ElementBytes()));
200 CheckDescriptorEqStr(err.get(), paddedErrStr);
205 class NoArgv : public CommandFixture {
206 protected:
207 NoArgv() : CommandFixture(0, nullptr) {}
210 // TODO: Test other intrinsics with this fixture.
212 TEST_F(NoArgv, GetCommand) { CheckMissingCommandValue(); }
214 static const char *commandOnlyArgv[]{"aProgram"};
215 class ZeroArguments : public CommandFixture {
216 protected:
217 ZeroArguments() : CommandFixture(1, commandOnlyArgv) {}
220 TEST_F(ZeroArguments, ArgumentCount) { EXPECT_EQ(0, RTNAME(ArgumentCount)()); }
222 TEST_F(ZeroArguments, GetCommandArgument) {
223 CheckMissingArgumentValue(-1);
224 CheckArgumentValue(commandOnlyArgv[0], 0);
225 CheckMissingArgumentValue(1);
228 TEST_F(ZeroArguments, GetCommand) { CheckCommandValue(commandOnlyArgv, 1); }
230 static const char *oneArgArgv[]{"aProgram", "anArgumentOfLength20"};
231 class OneArgument : public CommandFixture {
232 protected:
233 OneArgument() : CommandFixture(2, oneArgArgv) {}
236 TEST_F(OneArgument, ArgumentCount) { EXPECT_EQ(1, RTNAME(ArgumentCount)()); }
238 TEST_F(OneArgument, GetCommandArgument) {
239 CheckMissingArgumentValue(-1);
240 CheckArgumentValue(oneArgArgv[0], 0);
241 CheckArgumentValue(oneArgArgv[1], 1);
242 CheckMissingArgumentValue(2);
245 TEST_F(OneArgument, GetCommand) { CheckCommandValue(oneArgArgv, 2); }
247 static const char *severalArgsArgv[]{
248 "aProgram", "16-char-long-arg", "", "-22-character-long-arg", "o"};
249 class SeveralArguments : public CommandFixture {
250 protected:
251 SeveralArguments()
252 : CommandFixture(sizeof(severalArgsArgv) / sizeof(*severalArgsArgv),
253 severalArgsArgv) {}
256 TEST_F(SeveralArguments, ArgumentCount) {
257 EXPECT_EQ(4, RTNAME(ArgumentCount)());
260 TEST_F(SeveralArguments, GetCommandArgument) {
261 CheckArgumentValue(severalArgsArgv[0], 0);
262 CheckArgumentValue(severalArgsArgv[1], 1);
263 CheckArgumentValue(severalArgsArgv[3], 3);
264 CheckArgumentValue(severalArgsArgv[4], 4);
267 TEST_F(SeveralArguments, NoArgumentValue) {
268 // Make sure we don't crash if the 'value', 'length' and 'error' parameters
269 // aren't passed.
270 EXPECT_GT(RTNAME(GetCommandArgument)(2), 0);
271 EXPECT_EQ(RTNAME(GetCommandArgument)(1), 0);
272 EXPECT_GT(RTNAME(GetCommandArgument)(-1), 0);
275 TEST_F(SeveralArguments, MissingArguments) {
276 CheckMissingArgumentValue(-1, "Invalid argument number");
277 CheckMissingArgumentValue(2, "Missing argument");
278 CheckMissingArgumentValue(5, "Invalid argument number");
279 CheckMissingArgumentValue(5);
282 TEST_F(SeveralArguments, ArgValueTooShort) {
283 OwningPtr<Descriptor> tooShort{CreateEmptyCharDescriptor<15>()};
284 ASSERT_NE(tooShort, nullptr);
285 EXPECT_EQ(RTNAME(GetCommandArgument)(1, tooShort.get()), -1);
286 CheckDescriptorEqStr(tooShort.get(), severalArgsArgv[1]);
288 OwningPtr<Descriptor> length{EmptyIntDescriptor()};
289 ASSERT_NE(length, nullptr);
290 OwningPtr<Descriptor> errMsg{CreateEmptyCharDescriptor()};
291 ASSERT_NE(errMsg, nullptr);
293 EXPECT_EQ(
294 RTNAME(GetCommandArgument)(1, tooShort.get(), length.get(), errMsg.get()),
295 -1);
297 CheckDescriptorEqInt(length.get(), 16);
298 std::string expectedErrMsg{
299 GetPaddedStr("Value too short", errMsg->ElementBytes())};
300 CheckDescriptorEqStr(errMsg.get(), expectedErrMsg);
303 TEST_F(SeveralArguments, ArgErrMsgTooShort) {
304 OwningPtr<Descriptor> errMsg{CreateEmptyCharDescriptor<3>()};
305 EXPECT_GT(RTNAME(GetCommandArgument)(-1, nullptr, nullptr, errMsg.get()), 0);
306 CheckDescriptorEqStr(errMsg.get(), "Inv");
309 TEST_F(SeveralArguments, GetCommand) {
310 CheckMissingCommandValue();
311 CheckMissingCommandValue("Missing argument");
314 TEST_F(SeveralArguments, CommandErrMsgTooShort) {
315 OwningPtr<Descriptor> value{CreateEmptyCharDescriptor()};
316 OwningPtr<Descriptor> length{EmptyIntDescriptor()};
317 OwningPtr<Descriptor> errMsg{CreateEmptyCharDescriptor<3>()};
319 EXPECT_GT(RTNAME(GetCommand)(value.get(), length.get(), errMsg.get()), 0);
321 std::string spaces(value->ElementBytes(), ' ');
322 CheckDescriptorEqStr(value.get(), spaces);
323 CheckDescriptorEqInt(length.get(), 0);
324 CheckDescriptorEqStr(errMsg.get(), "Mis");
327 TEST_F(SeveralArguments, GetCommandCanTakeNull) {
328 EXPECT_GT(RTNAME(GetCommand)(nullptr, nullptr, nullptr), 0);
331 static const char *onlyValidArgsArgv[]{
332 "aProgram", "-f", "has/a/few/slashes", "has\\a\\few\\backslashes"};
333 class OnlyValidArguments : public CommandFixture {
334 protected:
335 OnlyValidArguments()
336 : CommandFixture(sizeof(onlyValidArgsArgv) / sizeof(*onlyValidArgsArgv),
337 onlyValidArgsArgv) {}
340 TEST_F(OnlyValidArguments, GetCommand) {
341 CheckCommandValue(onlyValidArgsArgv, 4);
344 TEST_F(OnlyValidArguments, CommandValueTooShort) {
345 OwningPtr<Descriptor> tooShort{CreateEmptyCharDescriptor<50>()};
346 ASSERT_NE(tooShort, nullptr);
347 OwningPtr<Descriptor> length{EmptyIntDescriptor()};
348 ASSERT_NE(length, nullptr);
350 EXPECT_EQ(RTNAME(GetCommand)(tooShort.get(), length.get(), nullptr), -1);
352 CheckDescriptorEqStr(
353 tooShort.get(), "aProgram -f has/a/few/slashes has\\a\\few\\backslashe");
354 CheckDescriptorEqInt(length.get(), 51);
356 OwningPtr<Descriptor> errMsg{CreateEmptyCharDescriptor()};
357 ASSERT_NE(errMsg, nullptr);
359 EXPECT_EQ(-1, RTNAME(GetCommand)(tooShort.get(), nullptr, errMsg.get()));
361 std::string expectedErrMsg{
362 GetPaddedStr("Value too short", errMsg->ElementBytes())};
363 CheckDescriptorEqStr(errMsg.get(), expectedErrMsg);
366 TEST_F(OnlyValidArguments, GetCommandCanTakeNull) {
367 EXPECT_EQ(0, RTNAME(GetCommand)(nullptr, nullptr, nullptr));
369 OwningPtr<Descriptor> value{CreateEmptyCharDescriptor()};
370 ASSERT_NE(value, nullptr);
371 OwningPtr<Descriptor> length{EmptyIntDescriptor()};
372 ASSERT_NE(length, nullptr);
374 EXPECT_EQ(0, RTNAME(GetCommand)(value.get(), nullptr, nullptr));
375 CheckDescriptorEqStr(value.get(),
376 GetPaddedStr("aProgram -f has/a/few/slashes has\\a\\few\\backslashes",
377 value->ElementBytes()));
379 EXPECT_EQ(0, RTNAME(GetCommand)(nullptr, length.get(), nullptr));
380 CheckDescriptorEqInt(length.get(), 51);
383 TEST_F(OnlyValidArguments, GetCommandShortLength) {
384 OwningPtr<Descriptor> length{EmptyIntDescriptor<sizeof(short)>()};
385 ASSERT_NE(length, nullptr);
387 EXPECT_EQ(0, RTNAME(GetCommand)(nullptr, length.get(), nullptr));
388 CheckDescriptorEqInt<short>(length.get(), 51);
391 class EnvironmentVariables : public CommandFixture {
392 protected:
393 EnvironmentVariables() : CommandFixture(0, nullptr) {
394 SetEnv("NAME", "VALUE");
395 SetEnv("EMPTY", "");
398 // If we have access to setenv, we can run some more fine-grained tests.
399 template <typename ParamType = char>
400 void SetEnv(const ParamType *name, const ParamType *value,
401 decltype(setenv(name, value, 1)) *Enabled = nullptr) {
402 ASSERT_EQ(0, setenv(name, value, /*overwrite=*/1));
403 canSetEnv = true;
406 // Fallback method if setenv is not available.
407 template <typename Unused = void> void SetEnv(const void *, const void *) {}
409 bool EnableFineGrainedTests() const { return canSetEnv; }
411 private:
412 bool canSetEnv{false};
415 TEST_F(EnvironmentVariables, Nonexistent) {
416 CheckMissingEnvVarValue("DOESNT_EXIST");
417 CheckMissingEnvVarValue(" ");
418 CheckMissingEnvVarValue("");
421 TEST_F(EnvironmentVariables, Basic) {
422 // Test a variable that's expected to exist in the environment.
423 char *path{std::getenv("PATH")};
424 auto expectedLen{static_cast<int64_t>(std::strlen(path))};
425 OwningPtr<Descriptor> length{EmptyIntDescriptor()};
426 EXPECT_EQ(0,
427 RTNAME(GetEnvVariable)(*CharDescriptor("PATH"),
428 /*value=*/nullptr, length.get()));
429 CheckDescriptorEqInt(length.get(), expectedLen);
432 TEST_F(EnvironmentVariables, Trim) {
433 if (EnableFineGrainedTests()) {
434 CheckEnvVarValue("VALUE", "NAME ");
438 TEST_F(EnvironmentVariables, NoTrim) {
439 if (EnableFineGrainedTests()) {
440 CheckMissingEnvVarValue("NAME ", /*trim_name=*/false);
444 TEST_F(EnvironmentVariables, Empty) {
445 if (EnableFineGrainedTests()) {
446 CheckEnvVarValue("", "EMPTY");
450 TEST_F(EnvironmentVariables, NoValueOrErrmsg) {
451 ASSERT_EQ(std::getenv("DOESNT_EXIST"), nullptr)
452 << "Environment variable DOESNT_EXIST actually exists";
453 EXPECT_EQ(RTNAME(GetEnvVariable)(*CharDescriptor("DOESNT_EXIST")), 1);
455 if (EnableFineGrainedTests()) {
456 EXPECT_EQ(RTNAME(GetEnvVariable)(*CharDescriptor("NAME")), 0);
460 TEST_F(EnvironmentVariables, ValueTooShort) {
461 if (EnableFineGrainedTests()) {
462 OwningPtr<Descriptor> tooShort{CreateEmptyCharDescriptor<2>()};
463 ASSERT_NE(tooShort, nullptr);
464 EXPECT_EQ(RTNAME(GetEnvVariable)(*CharDescriptor("NAME"), tooShort.get(),
465 /*length=*/nullptr, /*trim_name=*/true, nullptr),
466 -1);
467 CheckDescriptorEqStr(tooShort.get(), "VALUE");
469 OwningPtr<Descriptor> errMsg{CreateEmptyCharDescriptor()};
470 ASSERT_NE(errMsg, nullptr);
472 EXPECT_EQ(RTNAME(GetEnvVariable)(*CharDescriptor("NAME"), tooShort.get(),
473 /*length=*/nullptr, /*trim_name=*/true, errMsg.get()),
474 -1);
476 std::string expectedErrMsg{
477 GetPaddedStr("Value too short", errMsg->ElementBytes())};
478 CheckDescriptorEqStr(errMsg.get(), expectedErrMsg);
482 TEST_F(EnvironmentVariables, ErrMsgTooShort) {
483 ASSERT_EQ(std::getenv("DOESNT_EXIST"), nullptr)
484 << "Environment variable DOESNT_EXIST actually exists";
486 OwningPtr<Descriptor> errMsg{CreateEmptyCharDescriptor<3>()};
487 EXPECT_EQ(RTNAME(GetEnvVariable)(*CharDescriptor("DOESNT_EXIST"), nullptr,
488 /*length=*/nullptr, /*trim_name=*/true, errMsg.get()),
490 CheckDescriptorEqStr(errMsg.get(), "Mis");