1 //===-- flang/unittests/RuntimeGTest/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 //===----------------------------------------------------------------------===// 8 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 15 using namespace Fortran::runtime; 16 17 template <std::size_t n = 64> 18 static OwningPtr<Descriptor> CreateEmptyCharDescriptor() { 19 OwningPtr<Descriptor> descriptor{Descriptor::Create( 20 sizeof(char), n, nullptr, 0, nullptr, CFI_attribute_allocatable)}; 21 if (descriptor->Allocate() != 0) { 22 return nullptr; 23 } 24 return descriptor; 25 } 26 27 class CommandFixture : public ::testing::Test { 28 protected: 29 CommandFixture(int argc, const char *argv[]) { 30 RTNAME(ProgramStart)(argc, argv, {}); 31 } 32 33 std::string GetPaddedStr(const char *text, std::size_t len) const { 34 std::string res{text}; 35 assert(res.length() <= len && "No room to pad"); 36 res.append(len - res.length(), ' '); 37 return res; 38 } 39 40 void CheckDescriptorEqStr( 41 const Descriptor *value, const std::string &expected) const { 42 EXPECT_EQ(std::strncmp(value->OffsetElement(), expected.c_str(), 43 value->ElementBytes()), 44 0); 45 } 46 47 void CheckArgumentValue(int n, const char *argv) const { 48 OwningPtr<Descriptor> value{CreateEmptyCharDescriptor()}; 49 ASSERT_NE(value, nullptr); 50 51 std::string expected{GetPaddedStr(argv, value->ElementBytes())}; 52 53 EXPECT_EQ(RTNAME(ArgumentValue)(n, value.get(), nullptr), 0); 54 CheckDescriptorEqStr(value.get(), expected); 55 } 56 57 void CheckMissingArgumentValue(int n, const char *errStr = nullptr) const { 58 OwningPtr<Descriptor> value{CreateEmptyCharDescriptor()}; 59 ASSERT_NE(value, nullptr); 60 61 OwningPtr<Descriptor> err{errStr ? CreateEmptyCharDescriptor() : nullptr}; 62 63 EXPECT_GT(RTNAME(ArgumentValue)(n, value.get(), err.get()), 0); 64 65 std::string spaces(value->ElementBytes(), ' '); 66 CheckDescriptorEqStr(value.get(), spaces); 67 68 if (errStr) { 69 std::string paddedErrStr(GetPaddedStr(errStr, err->ElementBytes())); 70 CheckDescriptorEqStr(err.get(), paddedErrStr); 71 } 72 } 73 }; 74 75 static const char *commandOnlyArgv[]{"aProgram"}; 76 class ZeroArguments : public CommandFixture { 77 protected: 78 ZeroArguments() : CommandFixture(1, commandOnlyArgv) {} 79 }; 80 81 TEST_F(ZeroArguments, ArgumentCount) { EXPECT_EQ(0, RTNAME(ArgumentCount)()); } 82 83 TEST_F(ZeroArguments, ArgumentLength) { 84 EXPECT_EQ(0, RTNAME(ArgumentLength)(-1)); 85 EXPECT_EQ(8, RTNAME(ArgumentLength)(0)); 86 EXPECT_EQ(0, RTNAME(ArgumentLength)(1)); 87 } 88 89 TEST_F(ZeroArguments, ArgumentValue) { 90 CheckArgumentValue(0, commandOnlyArgv[0]); 91 } 92 93 static const char *oneArgArgv[]{"aProgram", "anArgumentOfLength20"}; 94 class OneArgument : public CommandFixture { 95 protected: 96 OneArgument() : CommandFixture(2, oneArgArgv) {} 97 }; 98 99 TEST_F(OneArgument, ArgumentCount) { EXPECT_EQ(1, RTNAME(ArgumentCount)()); } 100 101 TEST_F(OneArgument, ArgumentLength) { 102 EXPECT_EQ(0, RTNAME(ArgumentLength)(-1)); 103 EXPECT_EQ(8, RTNAME(ArgumentLength)(0)); 104 EXPECT_EQ(20, RTNAME(ArgumentLength)(1)); 105 EXPECT_EQ(0, RTNAME(ArgumentLength)(2)); 106 } 107 108 TEST_F(OneArgument, ArgumentValue) { 109 CheckArgumentValue(0, oneArgArgv[0]); 110 CheckArgumentValue(1, oneArgArgv[1]); 111 } 112 113 static const char *severalArgsArgv[]{ 114 "aProgram", "16-char-long-arg", "", "-22-character-long-arg", "o"}; 115 class SeveralArguments : public CommandFixture { 116 protected: 117 SeveralArguments() 118 : CommandFixture(sizeof(severalArgsArgv) / sizeof(*severalArgsArgv), 119 severalArgsArgv) {} 120 }; 121 122 TEST_F(SeveralArguments, ArgumentCount) { 123 EXPECT_EQ(4, RTNAME(ArgumentCount)()); 124 } 125 126 TEST_F(SeveralArguments, ArgumentLength) { 127 EXPECT_EQ(0, RTNAME(ArgumentLength)(-1)); 128 EXPECT_EQ(8, RTNAME(ArgumentLength)(0)); 129 EXPECT_EQ(16, RTNAME(ArgumentLength)(1)); 130 EXPECT_EQ(0, RTNAME(ArgumentLength)(2)); 131 EXPECT_EQ(22, RTNAME(ArgumentLength)(3)); 132 EXPECT_EQ(1, RTNAME(ArgumentLength)(4)); 133 EXPECT_EQ(0, RTNAME(ArgumentLength)(5)); 134 } 135 136 TEST_F(SeveralArguments, ArgumentValue) { 137 CheckArgumentValue(0, severalArgsArgv[0]); 138 CheckArgumentValue(1, severalArgsArgv[1]); 139 CheckArgumentValue(3, severalArgsArgv[3]); 140 CheckArgumentValue(4, severalArgsArgv[4]); 141 } 142 143 TEST_F(SeveralArguments, NoArgumentValue) { 144 // Make sure we don't crash if the 'value' and 'error' parameters aren't 145 // passed. 146 EXPECT_EQ(RTNAME(ArgumentValue)(2, nullptr, nullptr), 0); 147 EXPECT_GT(RTNAME(ArgumentValue)(-1, nullptr, nullptr), 0); 148 } 149 150 TEST_F(SeveralArguments, MissingArguments) { 151 CheckMissingArgumentValue(-1, "Invalid argument number"); 152 CheckMissingArgumentValue(2, "Missing argument"); 153 CheckMissingArgumentValue(5, "Invalid argument number"); 154 CheckMissingArgumentValue(5); 155 } 156 157 TEST_F(SeveralArguments, ValueTooShort) { 158 OwningPtr<Descriptor> tooShort{CreateEmptyCharDescriptor<15>()}; 159 ASSERT_NE(tooShort, nullptr); 160 EXPECT_EQ(RTNAME(ArgumentValue)(1, tooShort.get(), nullptr), -1); 161 CheckDescriptorEqStr(tooShort.get(), severalArgsArgv[1]); 162 163 OwningPtr<Descriptor> errMsg{CreateEmptyCharDescriptor()}; 164 ASSERT_NE(errMsg, nullptr); 165 166 EXPECT_EQ(RTNAME(ArgumentValue)(1, tooShort.get(), errMsg.get()), -1); 167 168 std::string expectedErrMsg{ 169 GetPaddedStr("Value too short", errMsg->ElementBytes())}; 170 CheckDescriptorEqStr(errMsg.get(), expectedErrMsg); 171 } 172 173 TEST_F(SeveralArguments, ErrMsgTooShort) { 174 OwningPtr<Descriptor> errMsg{CreateEmptyCharDescriptor<3>()}; 175 EXPECT_GT(RTNAME(ArgumentValue)(-1, nullptr, errMsg.get()), 0); 176 CheckDescriptorEqStr(errMsg.get(), "Inv"); 177 } 178