1ffc67bb3SDavid Spickett //===-- flang/unittests/Runtime/CommandTest.cpp ---------------------------===// 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 "flang/Runtime/command.h" 10ffc67bb3SDavid Spickett #include "gmock/gmock.h" 11ffc67bb3SDavid Spickett #include "gtest/gtest.h" 12ffc67bb3SDavid Spickett #include "flang/Runtime/descriptor.h" 13e2b896aaSYi Wu #include "flang/Runtime/execute.h" 1418af032cSYi Wu #include "flang/Runtime/extensions.h" 15ffc67bb3SDavid Spickett #include "flang/Runtime/main.h" 1618af032cSYi Wu #include <cstddef> 17ffc67bb3SDavid Spickett #include <cstdlib> 18ffc67bb3SDavid Spickett 1918af032cSYi Wu #if _REENTRANT || _POSIX_C_SOURCE >= 199506L 2018af032cSYi Wu #include <limits.h> // LOGIN_NAME_MAX used in getlog test 2118af032cSYi Wu #endif 2218af032cSYi Wu 23ffc67bb3SDavid Spickett using namespace Fortran::runtime; 24ffc67bb3SDavid Spickett 25ffc67bb3SDavid Spickett template <std::size_t n = 64> 26ffc67bb3SDavid Spickett static OwningPtr<Descriptor> CreateEmptyCharDescriptor() { 27ffc67bb3SDavid Spickett OwningPtr<Descriptor> descriptor{Descriptor::Create( 28ffc67bb3SDavid Spickett sizeof(char), n, nullptr, 0, nullptr, CFI_attribute_allocatable)}; 29ffc67bb3SDavid Spickett if (descriptor->Allocate() != 0) { 30ffc67bb3SDavid Spickett return nullptr; 31ffc67bb3SDavid Spickett } 32ffc67bb3SDavid Spickett return descriptor; 33ffc67bb3SDavid Spickett } 34ffc67bb3SDavid Spickett 35ffc67bb3SDavid Spickett static OwningPtr<Descriptor> CharDescriptor(const char *value) { 36ffc67bb3SDavid Spickett std::size_t n{std::strlen(value)}; 37ffc67bb3SDavid Spickett OwningPtr<Descriptor> descriptor{Descriptor::Create( 38ffc67bb3SDavid Spickett sizeof(char), n, nullptr, 0, nullptr, CFI_attribute_allocatable)}; 39ffc67bb3SDavid Spickett if (descriptor->Allocate() != 0) { 40ffc67bb3SDavid Spickett return nullptr; 41ffc67bb3SDavid Spickett } 42ffc67bb3SDavid Spickett std::memcpy(descriptor->OffsetElement(), value, n); 43ffc67bb3SDavid Spickett return descriptor; 44ffc67bb3SDavid Spickett } 45ffc67bb3SDavid Spickett 46ffc67bb3SDavid Spickett template <int kind = sizeof(std::int64_t)> 47ffc67bb3SDavid Spickett static OwningPtr<Descriptor> EmptyIntDescriptor() { 48ffc67bb3SDavid Spickett OwningPtr<Descriptor> descriptor{Descriptor::Create(TypeCategory::Integer, 49ffc67bb3SDavid Spickett kind, nullptr, 0, nullptr, CFI_attribute_allocatable)}; 50ffc67bb3SDavid Spickett if (descriptor->Allocate() != 0) { 51ffc67bb3SDavid Spickett return nullptr; 52ffc67bb3SDavid Spickett } 53ffc67bb3SDavid Spickett return descriptor; 54ffc67bb3SDavid Spickett } 55ffc67bb3SDavid Spickett 56e2b896aaSYi Wu template <int kind = sizeof(std::int64_t)> 57e2b896aaSYi Wu static OwningPtr<Descriptor> IntDescriptor(const int &value) { 58e2b896aaSYi Wu OwningPtr<Descriptor> descriptor{Descriptor::Create(TypeCategory::Integer, 59e2b896aaSYi Wu kind, nullptr, 0, nullptr, CFI_attribute_allocatable)}; 60e2b896aaSYi Wu if (descriptor->Allocate() != 0) { 61e2b896aaSYi Wu return nullptr; 62e2b896aaSYi Wu } 63e2b896aaSYi Wu std::memcpy(descriptor->OffsetElement<int>(), &value, sizeof(int)); 64e2b896aaSYi Wu return descriptor; 65e2b896aaSYi Wu } 66e2b896aaSYi Wu 67ffc67bb3SDavid Spickett class CommandFixture : public ::testing::Test { 68ffc67bb3SDavid Spickett protected: 69ffc67bb3SDavid Spickett CommandFixture(int argc, const char *argv[]) { 70ffc67bb3SDavid Spickett RTNAME(ProgramStart)(argc, argv, {}, {}); 71ffc67bb3SDavid Spickett } 72ffc67bb3SDavid Spickett 73ffc67bb3SDavid Spickett std::string GetPaddedStr(const char *text, std::size_t len) const { 74ffc67bb3SDavid Spickett std::string res{text}; 75ffc67bb3SDavid Spickett assert(res.length() <= len && "No room to pad"); 76ffc67bb3SDavid Spickett res.append(len - res.length(), ' '); 77ffc67bb3SDavid Spickett return res; 78ffc67bb3SDavid Spickett } 79ffc67bb3SDavid Spickett 8018af032cSYi Wu void CheckCharEqStr(const char *value, const std::string &expected) const { 8118af032cSYi Wu ASSERT_NE(value, nullptr); 8218af032cSYi Wu EXPECT_EQ(std::strncmp(value, expected.c_str(), expected.size()), 0) 8318af032cSYi Wu << "expected: " << expected << "\n" 8418af032cSYi Wu << "value: " << value; 8518af032cSYi Wu } 8618af032cSYi Wu 87ffc67bb3SDavid Spickett void CheckDescriptorEqStr( 88ffc67bb3SDavid Spickett const Descriptor *value, const std::string &expected) const { 89ffc67bb3SDavid Spickett ASSERT_NE(value, nullptr); 90ffc67bb3SDavid Spickett EXPECT_EQ(std::strncmp(value->OffsetElement(), expected.c_str(), 91ffc67bb3SDavid Spickett value->ElementBytes()), 92ffc67bb3SDavid Spickett 0) 93ffc67bb3SDavid Spickett << "expected: " << expected << "\n" 94ffc67bb3SDavid Spickett << "value: " 95ffc67bb3SDavid Spickett << std::string{value->OffsetElement(), value->ElementBytes()}; 96ffc67bb3SDavid Spickett } 97ffc67bb3SDavid Spickett 98ffc67bb3SDavid Spickett template <typename INT_T = std::int64_t> 99ffc67bb3SDavid Spickett void CheckDescriptorEqInt( 100ffc67bb3SDavid Spickett const Descriptor *value, const INT_T expected) const { 101ffc67bb3SDavid Spickett if (expected != -1) { 102ffc67bb3SDavid Spickett ASSERT_NE(value, nullptr); 103ffc67bb3SDavid Spickett EXPECT_EQ(*value->OffsetElement<INT_T>(), expected); 104ffc67bb3SDavid Spickett } 105ffc67bb3SDavid Spickett } 106ffc67bb3SDavid Spickett 107ffc67bb3SDavid Spickett template <typename RuntimeCall> 108ffc67bb3SDavid Spickett void CheckValue(RuntimeCall F, const char *expectedValue, 109ffc67bb3SDavid Spickett std::int64_t expectedLength = -1, std::int32_t expectedStatus = 0, 110ffc67bb3SDavid Spickett const char *expectedErrMsg = "shouldn't change") const { 111ffc67bb3SDavid Spickett OwningPtr<Descriptor> value{CreateEmptyCharDescriptor()}; 112ffc67bb3SDavid Spickett ASSERT_NE(value, nullptr); 113ffc67bb3SDavid Spickett 114ffc67bb3SDavid Spickett OwningPtr<Descriptor> length{ 115ffc67bb3SDavid Spickett expectedLength == -1 ? nullptr : EmptyIntDescriptor()}; 116ffc67bb3SDavid Spickett 117ffc67bb3SDavid Spickett OwningPtr<Descriptor> errmsg{CharDescriptor(expectedErrMsg)}; 118ffc67bb3SDavid Spickett ASSERT_NE(errmsg, nullptr); 119ffc67bb3SDavid Spickett 120ffc67bb3SDavid Spickett std::string expectedValueStr{ 121ffc67bb3SDavid Spickett GetPaddedStr(expectedValue, value->ElementBytes())}; 122ffc67bb3SDavid Spickett 123ffc67bb3SDavid Spickett EXPECT_EQ(F(value.get(), length.get(), errmsg.get()), expectedStatus); 124ffc67bb3SDavid Spickett CheckDescriptorEqStr(value.get(), expectedValueStr); 125ffc67bb3SDavid Spickett CheckDescriptorEqInt(length.get(), expectedLength); 126ffc67bb3SDavid Spickett CheckDescriptorEqStr(errmsg.get(), expectedErrMsg); 127ffc67bb3SDavid Spickett } 128ffc67bb3SDavid Spickett 129ffc67bb3SDavid Spickett void CheckArgumentValue(const char *expectedValue, int n) const { 130ffc67bb3SDavid Spickett SCOPED_TRACE(n); 131ffc67bb3SDavid Spickett SCOPED_TRACE("Checking argument:"); 132ffc67bb3SDavid Spickett CheckValue( 133ffc67bb3SDavid Spickett [&](const Descriptor *value, const Descriptor *length, 134ffc67bb3SDavid Spickett const Descriptor *errmsg) { 135ffc67bb3SDavid Spickett return RTNAME(GetCommandArgument)(n, value, length, errmsg); 136ffc67bb3SDavid Spickett }, 137ffc67bb3SDavid Spickett expectedValue, std::strlen(expectedValue)); 138ffc67bb3SDavid Spickett } 139ffc67bb3SDavid Spickett 140ffc67bb3SDavid Spickett void CheckCommandValue(const char *args[], int n) const { 141ffc67bb3SDavid Spickett SCOPED_TRACE("Checking command:"); 142ffc67bb3SDavid Spickett ASSERT_GE(n, 1); 143ffc67bb3SDavid Spickett std::string expectedValue{args[0]}; 144ffc67bb3SDavid Spickett for (int i = 1; i < n; i++) { 145ffc67bb3SDavid Spickett expectedValue += " " + std::string{args[i]}; 146ffc67bb3SDavid Spickett } 147ffc67bb3SDavid Spickett CheckValue( 148ffc67bb3SDavid Spickett [&](const Descriptor *value, const Descriptor *length, 149ffc67bb3SDavid Spickett const Descriptor *errmsg) { 150ffc67bb3SDavid Spickett return RTNAME(GetCommand)(value, length, errmsg); 151ffc67bb3SDavid Spickett }, 152ffc67bb3SDavid Spickett expectedValue.c_str(), expectedValue.size()); 153ffc67bb3SDavid Spickett } 154ffc67bb3SDavid Spickett 155ffc67bb3SDavid Spickett void CheckEnvVarValue( 156ffc67bb3SDavid Spickett const char *expectedValue, const char *name, bool trimName = true) const { 157ffc67bb3SDavid Spickett SCOPED_TRACE(name); 158ffc67bb3SDavid Spickett SCOPED_TRACE("Checking environment variable"); 159ffc67bb3SDavid Spickett CheckValue( 160ffc67bb3SDavid Spickett [&](const Descriptor *value, const Descriptor *length, 161ffc67bb3SDavid Spickett const Descriptor *errmsg) { 162ffc67bb3SDavid Spickett return RTNAME(GetEnvVariable)( 163ffc67bb3SDavid Spickett *CharDescriptor(name), value, length, trimName, errmsg); 164ffc67bb3SDavid Spickett }, 165ffc67bb3SDavid Spickett expectedValue, std::strlen(expectedValue)); 166ffc67bb3SDavid Spickett } 167ffc67bb3SDavid Spickett 168ffc67bb3SDavid Spickett void CheckMissingEnvVarValue(const char *name, bool trimName = true) const { 169ffc67bb3SDavid Spickett SCOPED_TRACE(name); 170ffc67bb3SDavid Spickett SCOPED_TRACE("Checking missing environment variable"); 171ffc67bb3SDavid Spickett 172ffc67bb3SDavid Spickett ASSERT_EQ(nullptr, std::getenv(name)) 173ffc67bb3SDavid Spickett << "Environment variable " << name << " not expected to exist"; 174ffc67bb3SDavid Spickett 175ffc67bb3SDavid Spickett CheckValue( 176ffc67bb3SDavid Spickett [&](const Descriptor *value, const Descriptor *length, 177ffc67bb3SDavid Spickett const Descriptor *errmsg) { 178ffc67bb3SDavid Spickett return RTNAME(GetEnvVariable)( 179ffc67bb3SDavid Spickett *CharDescriptor(name), value, length, trimName, errmsg); 180ffc67bb3SDavid Spickett }, 181ffc67bb3SDavid Spickett "", 0, 1, "Missing environment variable"); 182ffc67bb3SDavid Spickett } 183ffc67bb3SDavid Spickett 184ffc67bb3SDavid Spickett void CheckMissingArgumentValue(int n, const char *errStr = nullptr) const { 185ffc67bb3SDavid Spickett OwningPtr<Descriptor> value{CreateEmptyCharDescriptor()}; 186ffc67bb3SDavid Spickett ASSERT_NE(value, nullptr); 187ffc67bb3SDavid Spickett 188ffc67bb3SDavid Spickett OwningPtr<Descriptor> length{EmptyIntDescriptor()}; 189ffc67bb3SDavid Spickett ASSERT_NE(length, nullptr); 190ffc67bb3SDavid Spickett 191ffc67bb3SDavid Spickett OwningPtr<Descriptor> err{errStr ? CreateEmptyCharDescriptor() : nullptr}; 192ffc67bb3SDavid Spickett 193ffc67bb3SDavid Spickett EXPECT_GT( 194ffc67bb3SDavid Spickett RTNAME(GetCommandArgument)(n, value.get(), length.get(), err.get()), 0); 195ffc67bb3SDavid Spickett 196ffc67bb3SDavid Spickett std::string spaces(value->ElementBytes(), ' '); 197ffc67bb3SDavid Spickett CheckDescriptorEqStr(value.get(), spaces); 198ffc67bb3SDavid Spickett 1998d0fb9f6Skkwli CheckDescriptorEqInt<std::int64_t>(length.get(), 0); 200ffc67bb3SDavid Spickett 201ffc67bb3SDavid Spickett if (errStr) { 202ffc67bb3SDavid Spickett std::string paddedErrStr(GetPaddedStr(errStr, err->ElementBytes())); 203ffc67bb3SDavid Spickett CheckDescriptorEqStr(err.get(), paddedErrStr); 204ffc67bb3SDavid Spickett } 205ffc67bb3SDavid Spickett } 206ffc67bb3SDavid Spickett 207ffc67bb3SDavid Spickett void CheckMissingCommandValue(const char *errStr = nullptr) const { 208ffc67bb3SDavid Spickett OwningPtr<Descriptor> value{CreateEmptyCharDescriptor()}; 209ffc67bb3SDavid Spickett ASSERT_NE(value, nullptr); 210ffc67bb3SDavid Spickett 211ffc67bb3SDavid Spickett OwningPtr<Descriptor> length{EmptyIntDescriptor()}; 212ffc67bb3SDavid Spickett ASSERT_NE(length, nullptr); 213ffc67bb3SDavid Spickett 214ffc67bb3SDavid Spickett OwningPtr<Descriptor> err{errStr ? CreateEmptyCharDescriptor() : nullptr}; 215ffc67bb3SDavid Spickett 216ffc67bb3SDavid Spickett EXPECT_GT(RTNAME(GetCommand)(value.get(), length.get(), err.get()), 0); 217ffc67bb3SDavid Spickett 218ffc67bb3SDavid Spickett std::string spaces(value->ElementBytes(), ' '); 219ffc67bb3SDavid Spickett CheckDescriptorEqStr(value.get(), spaces); 220ffc67bb3SDavid Spickett 2218d0fb9f6Skkwli CheckDescriptorEqInt<std::int64_t>(length.get(), 0); 222ffc67bb3SDavid Spickett 223ffc67bb3SDavid Spickett if (errStr) { 224ffc67bb3SDavid Spickett std::string paddedErrStr(GetPaddedStr(errStr, err->ElementBytes())); 225ffc67bb3SDavid Spickett CheckDescriptorEqStr(err.get(), paddedErrStr); 226ffc67bb3SDavid Spickett } 227ffc67bb3SDavid Spickett } 228ffc67bb3SDavid Spickett }; 229ffc67bb3SDavid Spickett 230ffc67bb3SDavid Spickett class NoArgv : public CommandFixture { 231ffc67bb3SDavid Spickett protected: 232ffc67bb3SDavid Spickett NoArgv() : CommandFixture(0, nullptr) {} 233ffc67bb3SDavid Spickett }; 234ffc67bb3SDavid Spickett 235959a430aSYi Wu #if _WIN32 || _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || \ 2368b6b882fSKelvin Li _SVID_SOURCE || defined(_POSIX_SOURCE) 237959a430aSYi Wu TEST_F(NoArgv, FdateGetDate) { 238959a430aSYi Wu char input[]{"24LengthCharIsJustRight"}; 239959a430aSYi Wu const std::size_t charLen = sizeof(input); 240959a430aSYi Wu 241959a430aSYi Wu FORTRAN_PROCEDURE_NAME(fdate)(input, charLen); 242959a430aSYi Wu 243959a430aSYi Wu // Tue May 26 21:51:03 2015\n\0 244959a430aSYi Wu // index at 3, 7, 10, 19 should be space 245959a430aSYi Wu // when date is less than two digit, index 8 would be space 246959a430aSYi Wu // Tue May 6 21:51:03 2015\n\0 247959a430aSYi Wu for (std::size_t i{0}; i < charLen; i++) { 248959a430aSYi Wu if (i == 8) 249959a430aSYi Wu continue; 250959a430aSYi Wu if (i == 3 || i == 7 || i == 10 || i == 19) { 251959a430aSYi Wu EXPECT_EQ(input[i], ' '); 252959a430aSYi Wu continue; 253959a430aSYi Wu } 254959a430aSYi Wu EXPECT_NE(input[i], ' '); 255959a430aSYi Wu } 256959a430aSYi Wu } 257959a430aSYi Wu 258959a430aSYi Wu TEST_F(NoArgv, FdateGetDateTooShort) { 259959a430aSYi Wu char input[]{"TooShortAllPadSpace"}; 260959a430aSYi Wu const std::size_t charLen = sizeof(input); 261959a430aSYi Wu 262959a430aSYi Wu FORTRAN_PROCEDURE_NAME(fdate)(input, charLen); 263959a430aSYi Wu 264959a430aSYi Wu for (std::size_t i{0}; i < charLen; i++) { 265959a430aSYi Wu EXPECT_EQ(input[i], ' '); 266959a430aSYi Wu } 267959a430aSYi Wu } 268959a430aSYi Wu 269959a430aSYi Wu TEST_F(NoArgv, FdateGetDatePadSpace) { 270959a430aSYi Wu char input[]{"All char after 23 pad spaces"}; 271959a430aSYi Wu const std::size_t charLen = sizeof(input); 272959a430aSYi Wu 273959a430aSYi Wu FORTRAN_PROCEDURE_NAME(fdate)(input, charLen); 274959a430aSYi Wu 275959a430aSYi Wu for (std::size_t i{24}; i < charLen; i++) { 276959a430aSYi Wu EXPECT_EQ(input[i], ' '); 277959a430aSYi Wu } 278959a430aSYi Wu } 279959a430aSYi Wu 280959a430aSYi Wu #else 281959a430aSYi Wu TEST_F(NoArgv, FdateNotSupported) { 282959a430aSYi Wu char input[]{"No change due to crash"}; 283959a430aSYi Wu 284959a430aSYi Wu EXPECT_DEATH(FORTRAN_PROCEDURE_NAME(fdate)(input, sizeof(input)), 285959a430aSYi Wu "fdate is not supported."); 286959a430aSYi Wu 287959a430aSYi Wu CheckCharEqStr(input, "No change due to crash"); 288959a430aSYi Wu } 289959a430aSYi Wu #endif 290959a430aSYi Wu 291ffc67bb3SDavid Spickett // TODO: Test other intrinsics with this fixture. 292ffc67bb3SDavid Spickett 293ffc67bb3SDavid Spickett TEST_F(NoArgv, GetCommand) { CheckMissingCommandValue(); } 294ffc67bb3SDavid Spickett 295ffc67bb3SDavid Spickett static const char *commandOnlyArgv[]{"aProgram"}; 296ffc67bb3SDavid Spickett class ZeroArguments : public CommandFixture { 297ffc67bb3SDavid Spickett protected: 298ffc67bb3SDavid Spickett ZeroArguments() : CommandFixture(1, commandOnlyArgv) {} 299ffc67bb3SDavid Spickett }; 300ffc67bb3SDavid Spickett 301ffc67bb3SDavid Spickett TEST_F(ZeroArguments, ArgumentCount) { EXPECT_EQ(0, RTNAME(ArgumentCount)()); } 302ffc67bb3SDavid Spickett 303ffc67bb3SDavid Spickett TEST_F(ZeroArguments, GetCommandArgument) { 304ffc67bb3SDavid Spickett CheckMissingArgumentValue(-1); 305ffc67bb3SDavid Spickett CheckArgumentValue(commandOnlyArgv[0], 0); 306ffc67bb3SDavid Spickett CheckMissingArgumentValue(1); 307ffc67bb3SDavid Spickett } 308ffc67bb3SDavid Spickett 309ffc67bb3SDavid Spickett TEST_F(ZeroArguments, GetCommand) { CheckCommandValue(commandOnlyArgv, 1); } 310ffc67bb3SDavid Spickett 311e2b896aaSYi Wu TEST_F(ZeroArguments, ECLValidCommandAndPadSync) { 312e2b896aaSYi Wu OwningPtr<Descriptor> command{CharDescriptor("echo hi")}; 313e2b896aaSYi Wu bool wait{true}; 314dfd2711fSYi Wu OwningPtr<Descriptor> exitStat{IntDescriptor(404)}; 315dfd2711fSYi Wu OwningPtr<Descriptor> cmdStat{IntDescriptor(202)}; 316e2b896aaSYi Wu OwningPtr<Descriptor> cmdMsg{CharDescriptor("No change")}; 317e2b896aaSYi Wu 318e2b896aaSYi Wu RTNAME(ExecuteCommandLine) 319e2b896aaSYi Wu (*command.get(), wait, exitStat.get(), cmdStat.get(), cmdMsg.get()); 320e2b896aaSYi Wu 321e2b896aaSYi Wu std::string spaces(cmdMsg->ElementBytes(), ' '); 32287ac65a9Smadanial0 CheckDescriptorEqInt<std::int64_t>(exitStat.get(), 0); 32387ac65a9Smadanial0 CheckDescriptorEqInt<std::int64_t>(cmdStat.get(), 0); 324e2b896aaSYi Wu CheckDescriptorEqStr(cmdMsg.get(), "No change"); 325e2b896aaSYi Wu } 326e2b896aaSYi Wu 327e2b896aaSYi Wu TEST_F(ZeroArguments, ECLValidCommandStatusSetSync) { 328e2b896aaSYi Wu OwningPtr<Descriptor> command{CharDescriptor("echo hi")}; 329e2b896aaSYi Wu bool wait{true}; 330e2b896aaSYi Wu OwningPtr<Descriptor> exitStat{IntDescriptor(404)}; 331e2b896aaSYi Wu OwningPtr<Descriptor> cmdStat{IntDescriptor(202)}; 332e2b896aaSYi Wu OwningPtr<Descriptor> cmdMsg{CharDescriptor("No change")}; 333e2b896aaSYi Wu 334e2b896aaSYi Wu RTNAME(ExecuteCommandLine) 335e2b896aaSYi Wu (*command.get(), wait, exitStat.get(), cmdStat.get(), cmdMsg.get()); 336e2b896aaSYi Wu 33787ac65a9Smadanial0 CheckDescriptorEqInt<std::int64_t>(exitStat.get(), 0); 33887ac65a9Smadanial0 CheckDescriptorEqInt<std::int64_t>(cmdStat.get(), 0); 339e2b896aaSYi Wu CheckDescriptorEqStr(cmdMsg.get(), "No change"); 340e2b896aaSYi Wu } 341e2b896aaSYi Wu 342dfd2711fSYi Wu TEST_F(ZeroArguments, ECLGeneralErrorCommandErrorSync) { 343*e3355638SDavid Truby OwningPtr<Descriptor> command{CharDescriptor(NOT_EXE)}; 344e2b896aaSYi Wu bool wait{true}; 345e2b896aaSYi Wu OwningPtr<Descriptor> exitStat{IntDescriptor(404)}; 346e2b896aaSYi Wu OwningPtr<Descriptor> cmdStat{IntDescriptor(202)}; 347dfd2711fSYi Wu OwningPtr<Descriptor> cmdMsg{CharDescriptor("cmd msg buffer XXXXXXXXXXXXXX")}; 348e2b896aaSYi Wu 349e2b896aaSYi Wu RTNAME(ExecuteCommandLine) 350e2b896aaSYi Wu (*command.get(), wait, exitStat.get(), cmdStat.get(), cmdMsg.get()); 351dfd2711fSYi Wu CheckDescriptorEqInt<std::int64_t>(exitStat.get(), 1); 352*e3355638SDavid Truby #if defined(_WIN32) 353dfd2711fSYi Wu CheckDescriptorEqInt<std::int64_t>(cmdStat.get(), 6); 354dfd2711fSYi Wu CheckDescriptorEqStr(cmdMsg.get(), "Invalid command lineXXXXXXXXX"); 355dfd2711fSYi Wu #else 356dfd2711fSYi Wu CheckDescriptorEqInt<std::int64_t>(cmdStat.get(), 3); 357dfd2711fSYi Wu CheckDescriptorEqStr(cmdMsg.get(), "Command line execution failed"); 358dfd2711fSYi Wu #endif 359dfd2711fSYi Wu } 360dfd2711fSYi Wu 361dfd2711fSYi Wu TEST_F(ZeroArguments, ECLNotExecutedCommandErrorSync) { 362dfd2711fSYi Wu OwningPtr<Descriptor> command{CharDescriptor( 363dfd2711fSYi Wu "touch NotExecutedCommandFile && chmod -x NotExecutedCommandFile && " 364dfd2711fSYi Wu "./NotExecutedCommandFile")}; 365dfd2711fSYi Wu bool wait{true}; 366dfd2711fSYi Wu OwningPtr<Descriptor> exitStat{IntDescriptor(404)}; 367dfd2711fSYi Wu OwningPtr<Descriptor> cmdStat{IntDescriptor(202)}; 368dfd2711fSYi Wu OwningPtr<Descriptor> cmdMsg{CharDescriptor("cmd msg buffer XXXXXXXX")}; 369dfd2711fSYi Wu 370dfd2711fSYi Wu RTNAME(ExecuteCommandLine) 371dfd2711fSYi Wu (*command.get(), wait, exitStat.get(), cmdStat.get(), cmdMsg.get()); 372dfd2711fSYi Wu #ifdef _WIN32 373dfd2711fSYi Wu CheckDescriptorEqInt<std::int64_t>(exitStat.get(), 1); 374dfd2711fSYi Wu CheckDescriptorEqInt<std::int64_t>(cmdStat.get(), 6); 375dfd2711fSYi Wu CheckDescriptorEqStr(cmdMsg.get(), "Invalid command lineXXX"); 376dfd2711fSYi Wu #else 377dfd2711fSYi Wu CheckDescriptorEqInt<std::int64_t>(exitStat.get(), 126); 378dfd2711fSYi Wu CheckDescriptorEqInt<std::int64_t>(cmdStat.get(), 4); 379dfd2711fSYi Wu CheckDescriptorEqStr(cmdMsg.get(), "Command cannot be execu"); 380dfd2711fSYi Wu // removing the file only on Linux (file is not created on Win) 381dfd2711fSYi Wu OwningPtr<Descriptor> commandClean{ 382dfd2711fSYi Wu CharDescriptor("rm -f NotExecutedCommandFile")}; 383dfd2711fSYi Wu OwningPtr<Descriptor> cmdMsgNoErr{CharDescriptor("No Error")}; 384dfd2711fSYi Wu RTNAME(ExecuteCommandLine) 385dfd2711fSYi Wu (*commandClean.get(), wait, exitStat.get(), cmdStat.get(), cmdMsgNoErr.get()); 386dfd2711fSYi Wu CheckDescriptorEqInt<std::int64_t>(exitStat.get(), 0); 387dfd2711fSYi Wu CheckDescriptorEqStr(cmdMsgNoErr.get(), "No Error"); 388dfd2711fSYi Wu CheckDescriptorEqInt<std::int64_t>(cmdStat.get(), 0); 389dfd2711fSYi Wu #endif 390dfd2711fSYi Wu } 391dfd2711fSYi Wu 392dfd2711fSYi Wu TEST_F(ZeroArguments, ECLNotFoundCommandErrorSync) { 393dfd2711fSYi Wu OwningPtr<Descriptor> command{CharDescriptor("NotFoundCommand")}; 394dfd2711fSYi Wu bool wait{true}; 395dfd2711fSYi Wu OwningPtr<Descriptor> exitStat{IntDescriptor(404)}; 396dfd2711fSYi Wu OwningPtr<Descriptor> cmdStat{IntDescriptor(202)}; 397dfd2711fSYi Wu OwningPtr<Descriptor> cmdMsg{CharDescriptor("unmodified buffer XXXXXXXXX")}; 398dfd2711fSYi Wu 399dfd2711fSYi Wu RTNAME(ExecuteCommandLine) 400dfd2711fSYi Wu (*command.get(), wait, exitStat.get(), cmdStat.get(), cmdMsg.get()); 401dfd2711fSYi Wu #ifdef _WIN32 402dfd2711fSYi Wu CheckDescriptorEqInt<std::int64_t>(exitStat.get(), 1); 403dfd2711fSYi Wu CheckDescriptorEqInt<std::int64_t>(cmdStat.get(), 6); 404dfd2711fSYi Wu CheckDescriptorEqStr(cmdMsg.get(), "Invalid command lineXXXXXXX"); 405e2b896aaSYi Wu #else 40687ac65a9Smadanial0 CheckDescriptorEqInt<std::int64_t>(exitStat.get(), 127); 407dfd2711fSYi Wu CheckDescriptorEqInt<std::int64_t>(cmdStat.get(), 5); 408dfd2711fSYi Wu CheckDescriptorEqStr(cmdMsg.get(), "Command not found with exit"); 409e2b896aaSYi Wu #endif 410e2b896aaSYi Wu } 411e2b896aaSYi Wu 412e2b896aaSYi Wu TEST_F(ZeroArguments, ECLInvalidCommandTerminatedSync) { 413e2b896aaSYi Wu OwningPtr<Descriptor> command{CharDescriptor("InvalidCommand")}; 414e2b896aaSYi Wu bool wait{true}; 415e2b896aaSYi Wu OwningPtr<Descriptor> cmdMsg{CharDescriptor("No Change")}; 416e2b896aaSYi Wu 417e2b896aaSYi Wu #ifdef _WIN32 418e2b896aaSYi Wu EXPECT_DEATH(RTNAME(ExecuteCommandLine)( 419dfd2711fSYi Wu *command.get(), wait, nullptr, nullptr, cmdMsg.get()), 420e2b896aaSYi Wu "Invalid command quit with exit status code: 1"); 421e2b896aaSYi Wu #else 422e2b896aaSYi Wu EXPECT_DEATH(RTNAME(ExecuteCommandLine)( 423dfd2711fSYi Wu *command.get(), wait, nullptr, nullptr, cmdMsg.get()), 424dfd2711fSYi Wu "Command not found with exit code: 127."); 425e2b896aaSYi Wu #endif 426e2b896aaSYi Wu CheckDescriptorEqStr(cmdMsg.get(), "No Change"); 427e2b896aaSYi Wu } 428e2b896aaSYi Wu 429e2b896aaSYi Wu TEST_F(ZeroArguments, ECLValidCommandAndExitStatNoChangeAndCMDStatusSetAsync) { 430e2b896aaSYi Wu OwningPtr<Descriptor> command{CharDescriptor("echo hi")}; 431e2b896aaSYi Wu bool wait{false}; 432e2b896aaSYi Wu OwningPtr<Descriptor> exitStat{IntDescriptor(404)}; 433e2b896aaSYi Wu OwningPtr<Descriptor> cmdStat{IntDescriptor(202)}; 434e2b896aaSYi Wu OwningPtr<Descriptor> cmdMsg{CharDescriptor("No change")}; 435e2b896aaSYi Wu 436e2b896aaSYi Wu RTNAME(ExecuteCommandLine) 437e2b896aaSYi Wu (*command.get(), wait, exitStat.get(), cmdStat.get(), cmdMsg.get()); 438e2b896aaSYi Wu 439e2b896aaSYi Wu CheckDescriptorEqInt(exitStat.get(), 404); 44087ac65a9Smadanial0 CheckDescriptorEqInt<std::int64_t>(cmdStat.get(), 0); 441e2b896aaSYi Wu CheckDescriptorEqStr(cmdMsg.get(), "No change"); 442e2b896aaSYi Wu } 443e2b896aaSYi Wu 444e2b896aaSYi Wu TEST_F(ZeroArguments, ECLInvalidCommandParentNotTerminatedAsync) { 445e2b896aaSYi Wu OwningPtr<Descriptor> command{CharDescriptor("InvalidCommand")}; 446e2b896aaSYi Wu bool wait{false}; 447e2b896aaSYi Wu OwningPtr<Descriptor> cmdMsg{CharDescriptor("No change")}; 448e2b896aaSYi Wu 449e2b896aaSYi Wu EXPECT_NO_FATAL_FAILURE(RTNAME(ExecuteCommandLine)( 450dfd2711fSYi Wu *command.get(), wait, nullptr, nullptr, cmdMsg.get())); 451e2b896aaSYi Wu CheckDescriptorEqStr(cmdMsg.get(), "No change"); 452e2b896aaSYi Wu } 453e2b896aaSYi Wu 4545a7f9a5aSYi Wu TEST_F(ZeroArguments, ECLInvalidCommandAsyncDontAffectSync) { 4555a7f9a5aSYi Wu OwningPtr<Descriptor> command{CharDescriptor("echo hi")}; 4565a7f9a5aSYi Wu 4575a7f9a5aSYi Wu EXPECT_NO_FATAL_FAILURE(RTNAME(ExecuteCommandLine)( 4585a7f9a5aSYi Wu *command.get(), false, nullptr, nullptr, nullptr)); 4595a7f9a5aSYi Wu EXPECT_NO_FATAL_FAILURE(RTNAME(ExecuteCommandLine)( 4605a7f9a5aSYi Wu *command.get(), true, nullptr, nullptr, nullptr)); 4615a7f9a5aSYi Wu } 4625a7f9a5aSYi Wu 4635a7f9a5aSYi Wu TEST_F(ZeroArguments, ECLInvalidCommandAsyncDontAffectAsync) { 4645a7f9a5aSYi Wu OwningPtr<Descriptor> command{CharDescriptor("echo hi")}; 4655a7f9a5aSYi Wu 4665a7f9a5aSYi Wu EXPECT_NO_FATAL_FAILURE(RTNAME(ExecuteCommandLine)( 4675a7f9a5aSYi Wu *command.get(), false, nullptr, nullptr, nullptr)); 4685a7f9a5aSYi Wu EXPECT_NO_FATAL_FAILURE(RTNAME(ExecuteCommandLine)( 4695a7f9a5aSYi Wu *command.get(), false, nullptr, nullptr, nullptr)); 4705a7f9a5aSYi Wu } 4715a7f9a5aSYi Wu 4727c8ef765SYi Wu TEST_F(ZeroArguments, SystemValidCommandExitStat) { 4737c8ef765SYi Wu // envrionment setup for SYSTEM from EXECUTE_COMMAND_LINE runtime 4747c8ef765SYi Wu OwningPtr<Descriptor> cmdStat{IntDescriptor(202)}; 4757c8ef765SYi Wu bool wait{true}; 4767c8ef765SYi Wu // setup finished 4777c8ef765SYi Wu 4787c8ef765SYi Wu OwningPtr<Descriptor> command{CharDescriptor("echo hi")}; 4797c8ef765SYi Wu OwningPtr<Descriptor> exitStat{EmptyIntDescriptor()}; 4807c8ef765SYi Wu 4817c8ef765SYi Wu RTNAME(ExecuteCommandLine) 4827c8ef765SYi Wu (*command.get(), wait, exitStat.get(), cmdStat.get(), nullptr); 4837c8ef765SYi Wu CheckDescriptorEqInt<std::int64_t>(exitStat.get(), 0); 4847c8ef765SYi Wu } 4857c8ef765SYi Wu 4867c8ef765SYi Wu TEST_F(ZeroArguments, SystemInvalidCommandExitStat) { 4877c8ef765SYi Wu // envrionment setup for SYSTEM from EXECUTE_COMMAND_LINE runtime 4887c8ef765SYi Wu OwningPtr<Descriptor> cmdStat{IntDescriptor(202)}; 4897c8ef765SYi Wu bool wait{true}; 4907c8ef765SYi Wu // setup finished 4917c8ef765SYi Wu 4927c8ef765SYi Wu OwningPtr<Descriptor> command{CharDescriptor("InvalidCommand")}; 4937c8ef765SYi Wu OwningPtr<Descriptor> exitStat{EmptyIntDescriptor()}; 4947c8ef765SYi Wu 4957c8ef765SYi Wu RTNAME(ExecuteCommandLine) 4967c8ef765SYi Wu (*command.get(), wait, exitStat.get(), cmdStat.get(), nullptr); 4977c8ef765SYi Wu #ifdef _WIN32 4987c8ef765SYi Wu CheckDescriptorEqInt<std::int64_t>(exitStat.get(), 1); 4997c8ef765SYi Wu #else 5007c8ef765SYi Wu CheckDescriptorEqInt<std::int64_t>(exitStat.get(), 127); 5017c8ef765SYi Wu #endif 5027c8ef765SYi Wu } 5037c8ef765SYi Wu 5047c8ef765SYi Wu TEST_F(ZeroArguments, SystemValidCommandOptionalExitStat) { 5057c8ef765SYi Wu // envrionment setup for SYSTEM from EXECUTE_COMMAND_LINE runtime 5067c8ef765SYi Wu OwningPtr<Descriptor> cmdStat{IntDescriptor(202)}; 5077c8ef765SYi Wu bool wait{true}; 5087c8ef765SYi Wu // setup finished 5097c8ef765SYi Wu 5107c8ef765SYi Wu OwningPtr<Descriptor> command{CharDescriptor("echo hi")}; 5117c8ef765SYi Wu EXPECT_NO_FATAL_FAILURE(RTNAME(ExecuteCommandLine)( 5127c8ef765SYi Wu *command.get(), wait, nullptr, cmdStat.get(), nullptr)); 5137c8ef765SYi Wu } 5147c8ef765SYi Wu 5157c8ef765SYi Wu TEST_F(ZeroArguments, SystemInvalidCommandOptionalExitStat) { 5167c8ef765SYi Wu // envrionment setup for SYSTEM from EXECUTE_COMMAND_LINE runtime 5177c8ef765SYi Wu OwningPtr<Descriptor> cmdStat{IntDescriptor(202)}; 5187c8ef765SYi Wu bool wait{true}; 5197c8ef765SYi Wu // setup finished 5207c8ef765SYi Wu 5217c8ef765SYi Wu OwningPtr<Descriptor> command{CharDescriptor("InvalidCommand")}; 5227c8ef765SYi Wu EXPECT_NO_FATAL_FAILURE(RTNAME(ExecuteCommandLine)( 5237c8ef765SYi Wu *command.get(), wait, nullptr, cmdStat.get(), nullptr);); 5247c8ef765SYi Wu } 5257c8ef765SYi Wu 526ffc67bb3SDavid Spickett static const char *oneArgArgv[]{"aProgram", "anArgumentOfLength20"}; 527ffc67bb3SDavid Spickett class OneArgument : public CommandFixture { 528ffc67bb3SDavid Spickett protected: 529ffc67bb3SDavid Spickett OneArgument() : CommandFixture(2, oneArgArgv) {} 530ffc67bb3SDavid Spickett }; 531ffc67bb3SDavid Spickett 532ffc67bb3SDavid Spickett TEST_F(OneArgument, ArgumentCount) { EXPECT_EQ(1, RTNAME(ArgumentCount)()); } 533ffc67bb3SDavid Spickett 534ffc67bb3SDavid Spickett TEST_F(OneArgument, GetCommandArgument) { 535ffc67bb3SDavid Spickett CheckMissingArgumentValue(-1); 536ffc67bb3SDavid Spickett CheckArgumentValue(oneArgArgv[0], 0); 537ffc67bb3SDavid Spickett CheckArgumentValue(oneArgArgv[1], 1); 538ffc67bb3SDavid Spickett CheckMissingArgumentValue(2); 539ffc67bb3SDavid Spickett } 540ffc67bb3SDavid Spickett 541ffc67bb3SDavid Spickett TEST_F(OneArgument, GetCommand) { CheckCommandValue(oneArgArgv, 2); } 542ffc67bb3SDavid Spickett 543ffc67bb3SDavid Spickett static const char *severalArgsArgv[]{ 544ffc67bb3SDavid Spickett "aProgram", "16-char-long-arg", "", "-22-character-long-arg", "o"}; 545ffc67bb3SDavid Spickett class SeveralArguments : public CommandFixture { 546ffc67bb3SDavid Spickett protected: 547ffc67bb3SDavid Spickett SeveralArguments() 548ffc67bb3SDavid Spickett : CommandFixture(sizeof(severalArgsArgv) / sizeof(*severalArgsArgv), 549ffc67bb3SDavid Spickett severalArgsArgv) {} 550ffc67bb3SDavid Spickett }; 551ffc67bb3SDavid Spickett 552ffc67bb3SDavid Spickett TEST_F(SeveralArguments, ArgumentCount) { 553ffc67bb3SDavid Spickett EXPECT_EQ(4, RTNAME(ArgumentCount)()); 554ffc67bb3SDavid Spickett } 555ffc67bb3SDavid Spickett 556ffc67bb3SDavid Spickett TEST_F(SeveralArguments, GetCommandArgument) { 557ffc67bb3SDavid Spickett CheckArgumentValue(severalArgsArgv[0], 0); 558ffc67bb3SDavid Spickett CheckArgumentValue(severalArgsArgv[1], 1); 559ffc67bb3SDavid Spickett CheckArgumentValue(severalArgsArgv[3], 3); 560ffc67bb3SDavid Spickett CheckArgumentValue(severalArgsArgv[4], 4); 561ffc67bb3SDavid Spickett } 562ffc67bb3SDavid Spickett 563ffc67bb3SDavid Spickett TEST_F(SeveralArguments, NoArgumentValue) { 564ffc67bb3SDavid Spickett // Make sure we don't crash if the 'value', 'length' and 'error' parameters 565ffc67bb3SDavid Spickett // aren't passed. 566ffc67bb3SDavid Spickett EXPECT_GT(RTNAME(GetCommandArgument)(2), 0); 567ffc67bb3SDavid Spickett EXPECT_EQ(RTNAME(GetCommandArgument)(1), 0); 568ffc67bb3SDavid Spickett EXPECT_GT(RTNAME(GetCommandArgument)(-1), 0); 569ffc67bb3SDavid Spickett } 570ffc67bb3SDavid Spickett 571ffc67bb3SDavid Spickett TEST_F(SeveralArguments, MissingArguments) { 572ffc67bb3SDavid Spickett CheckMissingArgumentValue(-1, "Invalid argument number"); 573ffc67bb3SDavid Spickett CheckMissingArgumentValue(2, "Missing argument"); 574ffc67bb3SDavid Spickett CheckMissingArgumentValue(5, "Invalid argument number"); 575ffc67bb3SDavid Spickett CheckMissingArgumentValue(5); 576ffc67bb3SDavid Spickett } 577ffc67bb3SDavid Spickett 578ffc67bb3SDavid Spickett TEST_F(SeveralArguments, ArgValueTooShort) { 579ffc67bb3SDavid Spickett OwningPtr<Descriptor> tooShort{CreateEmptyCharDescriptor<15>()}; 580ffc67bb3SDavid Spickett ASSERT_NE(tooShort, nullptr); 581ffc67bb3SDavid Spickett EXPECT_EQ(RTNAME(GetCommandArgument)(1, tooShort.get()), -1); 582ffc67bb3SDavid Spickett CheckDescriptorEqStr(tooShort.get(), severalArgsArgv[1]); 583ffc67bb3SDavid Spickett 584ffc67bb3SDavid Spickett OwningPtr<Descriptor> length{EmptyIntDescriptor()}; 585ffc67bb3SDavid Spickett ASSERT_NE(length, nullptr); 586ffc67bb3SDavid Spickett OwningPtr<Descriptor> errMsg{CreateEmptyCharDescriptor()}; 587ffc67bb3SDavid Spickett ASSERT_NE(errMsg, nullptr); 588ffc67bb3SDavid Spickett 589ffc67bb3SDavid Spickett EXPECT_EQ( 590ffc67bb3SDavid Spickett RTNAME(GetCommandArgument)(1, tooShort.get(), length.get(), errMsg.get()), 591ffc67bb3SDavid Spickett -1); 592ffc67bb3SDavid Spickett 5938d0fb9f6Skkwli CheckDescriptorEqInt<std::int64_t>(length.get(), 16); 594ffc67bb3SDavid Spickett std::string expectedErrMsg{ 595ffc67bb3SDavid Spickett GetPaddedStr("Value too short", errMsg->ElementBytes())}; 596ffc67bb3SDavid Spickett CheckDescriptorEqStr(errMsg.get(), expectedErrMsg); 597ffc67bb3SDavid Spickett } 598ffc67bb3SDavid Spickett 599ffc67bb3SDavid Spickett TEST_F(SeveralArguments, ArgErrMsgTooShort) { 600ffc67bb3SDavid Spickett OwningPtr<Descriptor> errMsg{CreateEmptyCharDescriptor<3>()}; 601ffc67bb3SDavid Spickett EXPECT_GT(RTNAME(GetCommandArgument)(-1, nullptr, nullptr, errMsg.get()), 0); 602ffc67bb3SDavid Spickett CheckDescriptorEqStr(errMsg.get(), "Inv"); 603ffc67bb3SDavid Spickett } 604ffc67bb3SDavid Spickett 605ffc67bb3SDavid Spickett TEST_F(SeveralArguments, GetCommand) { 606ffc67bb3SDavid Spickett CheckMissingCommandValue(); 607ffc67bb3SDavid Spickett CheckMissingCommandValue("Missing argument"); 608ffc67bb3SDavid Spickett } 609ffc67bb3SDavid Spickett 610ffc67bb3SDavid Spickett TEST_F(SeveralArguments, CommandErrMsgTooShort) { 611ffc67bb3SDavid Spickett OwningPtr<Descriptor> value{CreateEmptyCharDescriptor()}; 612ffc67bb3SDavid Spickett OwningPtr<Descriptor> length{EmptyIntDescriptor()}; 613ffc67bb3SDavid Spickett OwningPtr<Descriptor> errMsg{CreateEmptyCharDescriptor<3>()}; 614ffc67bb3SDavid Spickett 615ffc67bb3SDavid Spickett EXPECT_GT(RTNAME(GetCommand)(value.get(), length.get(), errMsg.get()), 0); 616ffc67bb3SDavid Spickett 617ffc67bb3SDavid Spickett std::string spaces(value->ElementBytes(), ' '); 618ffc67bb3SDavid Spickett CheckDescriptorEqStr(value.get(), spaces); 6198d0fb9f6Skkwli CheckDescriptorEqInt<std::int64_t>(length.get(), 0); 620ffc67bb3SDavid Spickett CheckDescriptorEqStr(errMsg.get(), "Mis"); 621ffc67bb3SDavid Spickett } 622ffc67bb3SDavid Spickett 623ffc67bb3SDavid Spickett TEST_F(SeveralArguments, GetCommandCanTakeNull) { 624ffc67bb3SDavid Spickett EXPECT_GT(RTNAME(GetCommand)(nullptr, nullptr, nullptr), 0); 625ffc67bb3SDavid Spickett } 626ffc67bb3SDavid Spickett 627ffc67bb3SDavid Spickett static const char *onlyValidArgsArgv[]{ 628ffc67bb3SDavid Spickett "aProgram", "-f", "has/a/few/slashes", "has\\a\\few\\backslashes"}; 629ffc67bb3SDavid Spickett class OnlyValidArguments : public CommandFixture { 630ffc67bb3SDavid Spickett protected: 631ffc67bb3SDavid Spickett OnlyValidArguments() 632ffc67bb3SDavid Spickett : CommandFixture(sizeof(onlyValidArgsArgv) / sizeof(*onlyValidArgsArgv), 633ffc67bb3SDavid Spickett onlyValidArgsArgv) {} 634ffc67bb3SDavid Spickett }; 635ffc67bb3SDavid Spickett 636ffc67bb3SDavid Spickett TEST_F(OnlyValidArguments, GetCommand) { 637ffc67bb3SDavid Spickett CheckCommandValue(onlyValidArgsArgv, 4); 638ffc67bb3SDavid Spickett } 639ffc67bb3SDavid Spickett 640ffc67bb3SDavid Spickett TEST_F(OnlyValidArguments, CommandValueTooShort) { 641ffc67bb3SDavid Spickett OwningPtr<Descriptor> tooShort{CreateEmptyCharDescriptor<50>()}; 642ffc67bb3SDavid Spickett ASSERT_NE(tooShort, nullptr); 643ffc67bb3SDavid Spickett OwningPtr<Descriptor> length{EmptyIntDescriptor()}; 644ffc67bb3SDavid Spickett ASSERT_NE(length, nullptr); 645ffc67bb3SDavid Spickett 646ffc67bb3SDavid Spickett EXPECT_EQ(RTNAME(GetCommand)(tooShort.get(), length.get(), nullptr), -1); 647ffc67bb3SDavid Spickett 648ffc67bb3SDavid Spickett CheckDescriptorEqStr( 649ffc67bb3SDavid Spickett tooShort.get(), "aProgram -f has/a/few/slashes has\\a\\few\\backslashe"); 6508d0fb9f6Skkwli CheckDescriptorEqInt<std::int64_t>(length.get(), 51); 651ffc67bb3SDavid Spickett 652ffc67bb3SDavid Spickett OwningPtr<Descriptor> errMsg{CreateEmptyCharDescriptor()}; 653ffc67bb3SDavid Spickett ASSERT_NE(errMsg, nullptr); 654ffc67bb3SDavid Spickett 655ffc67bb3SDavid Spickett EXPECT_EQ(-1, RTNAME(GetCommand)(tooShort.get(), nullptr, errMsg.get())); 656ffc67bb3SDavid Spickett 657ffc67bb3SDavid Spickett std::string expectedErrMsg{ 658ffc67bb3SDavid Spickett GetPaddedStr("Value too short", errMsg->ElementBytes())}; 659ffc67bb3SDavid Spickett CheckDescriptorEqStr(errMsg.get(), expectedErrMsg); 660ffc67bb3SDavid Spickett } 661ffc67bb3SDavid Spickett 662ffc67bb3SDavid Spickett TEST_F(OnlyValidArguments, GetCommandCanTakeNull) { 663ffc67bb3SDavid Spickett EXPECT_EQ(0, RTNAME(GetCommand)(nullptr, nullptr, nullptr)); 664ffc67bb3SDavid Spickett 665ffc67bb3SDavid Spickett OwningPtr<Descriptor> value{CreateEmptyCharDescriptor()}; 666ffc67bb3SDavid Spickett ASSERT_NE(value, nullptr); 667ffc67bb3SDavid Spickett OwningPtr<Descriptor> length{EmptyIntDescriptor()}; 668ffc67bb3SDavid Spickett ASSERT_NE(length, nullptr); 669ffc67bb3SDavid Spickett 670ffc67bb3SDavid Spickett EXPECT_EQ(0, RTNAME(GetCommand)(value.get(), nullptr, nullptr)); 671ffc67bb3SDavid Spickett CheckDescriptorEqStr(value.get(), 672ffc67bb3SDavid Spickett GetPaddedStr("aProgram -f has/a/few/slashes has\\a\\few\\backslashes", 673ffc67bb3SDavid Spickett value->ElementBytes())); 674ffc67bb3SDavid Spickett 675ffc67bb3SDavid Spickett EXPECT_EQ(0, RTNAME(GetCommand)(nullptr, length.get(), nullptr)); 6768d0fb9f6Skkwli CheckDescriptorEqInt<std::int64_t>(length.get(), 51); 677ffc67bb3SDavid Spickett } 678ffc67bb3SDavid Spickett 679ffc67bb3SDavid Spickett TEST_F(OnlyValidArguments, GetCommandShortLength) { 680ffc67bb3SDavid Spickett OwningPtr<Descriptor> length{EmptyIntDescriptor<sizeof(short)>()}; 681ffc67bb3SDavid Spickett ASSERT_NE(length, nullptr); 682ffc67bb3SDavid Spickett 683ffc67bb3SDavid Spickett EXPECT_EQ(0, RTNAME(GetCommand)(nullptr, length.get(), nullptr)); 684ffc67bb3SDavid Spickett CheckDescriptorEqInt<short>(length.get(), 51); 685ffc67bb3SDavid Spickett } 686ffc67bb3SDavid Spickett 687de58aa83SYi Wu TEST_F(ZeroArguments, GetPID) { 688de58aa83SYi Wu // pid should always greater than 0, in both linux and windows 689de58aa83SYi Wu EXPECT_GT(RTNAME(GetPID)(), 0); 690de58aa83SYi Wu } 691de58aa83SYi Wu 692ffc67bb3SDavid Spickett class EnvironmentVariables : public CommandFixture { 693ffc67bb3SDavid Spickett protected: 694ffc67bb3SDavid Spickett EnvironmentVariables() : CommandFixture(0, nullptr) { 695ffc67bb3SDavid Spickett SetEnv("NAME", "VALUE"); 69618af032cSYi Wu #ifdef _WIN32 69718af032cSYi Wu SetEnv("USERNAME", "loginName"); 69818af032cSYi Wu #else 69918af032cSYi Wu SetEnv("LOGNAME", "loginName"); 70018af032cSYi Wu #endif 701ffc67bb3SDavid Spickett SetEnv("EMPTY", ""); 702ffc67bb3SDavid Spickett } 703ffc67bb3SDavid Spickett 704ffc67bb3SDavid Spickett // If we have access to setenv, we can run some more fine-grained tests. 705ffc67bb3SDavid Spickett template <typename ParamType = char> 706ffc67bb3SDavid Spickett void SetEnv(const ParamType *name, const ParamType *value, 707ffc67bb3SDavid Spickett decltype(setenv(name, value, 1)) *Enabled = nullptr) { 708ffc67bb3SDavid Spickett ASSERT_EQ(0, setenv(name, value, /*overwrite=*/1)); 709ffc67bb3SDavid Spickett canSetEnv = true; 710ffc67bb3SDavid Spickett } 711ffc67bb3SDavid Spickett 712ffc67bb3SDavid Spickett // Fallback method if setenv is not available. 713ffc67bb3SDavid Spickett template <typename Unused = void> void SetEnv(const void *, const void *) {} 714ffc67bb3SDavid Spickett 715ffc67bb3SDavid Spickett bool EnableFineGrainedTests() const { return canSetEnv; } 716ffc67bb3SDavid Spickett 717ffc67bb3SDavid Spickett private: 718ffc67bb3SDavid Spickett bool canSetEnv{false}; 719ffc67bb3SDavid Spickett }; 720ffc67bb3SDavid Spickett 721ffc67bb3SDavid Spickett TEST_F(EnvironmentVariables, Nonexistent) { 722ffc67bb3SDavid Spickett CheckMissingEnvVarValue("DOESNT_EXIST"); 723ffc67bb3SDavid Spickett CheckMissingEnvVarValue(" "); 724ffc67bb3SDavid Spickett CheckMissingEnvVarValue(""); 725ffc67bb3SDavid Spickett } 726ffc67bb3SDavid Spickett 727ffc67bb3SDavid Spickett TEST_F(EnvironmentVariables, Basic) { 728ffc67bb3SDavid Spickett // Test a variable that's expected to exist in the environment. 729ffc67bb3SDavid Spickett char *path{std::getenv("PATH")}; 730ffc67bb3SDavid Spickett auto expectedLen{static_cast<int64_t>(std::strlen(path))}; 731ffc67bb3SDavid Spickett OwningPtr<Descriptor> length{EmptyIntDescriptor()}; 732ffc67bb3SDavid Spickett EXPECT_EQ(0, 733ffc67bb3SDavid Spickett RTNAME(GetEnvVariable)(*CharDescriptor("PATH"), 734ffc67bb3SDavid Spickett /*value=*/nullptr, length.get())); 735ffc67bb3SDavid Spickett CheckDescriptorEqInt(length.get(), expectedLen); 736ffc67bb3SDavid Spickett } 737ffc67bb3SDavid Spickett 738ffc67bb3SDavid Spickett TEST_F(EnvironmentVariables, Trim) { 739ffc67bb3SDavid Spickett if (EnableFineGrainedTests()) { 740ffc67bb3SDavid Spickett CheckEnvVarValue("VALUE", "NAME "); 741ffc67bb3SDavid Spickett } 742ffc67bb3SDavid Spickett } 743ffc67bb3SDavid Spickett 744ffc67bb3SDavid Spickett TEST_F(EnvironmentVariables, NoTrim) { 745ffc67bb3SDavid Spickett if (EnableFineGrainedTests()) { 746ffc67bb3SDavid Spickett CheckMissingEnvVarValue("NAME ", /*trim_name=*/false); 747ffc67bb3SDavid Spickett } 748ffc67bb3SDavid Spickett } 749ffc67bb3SDavid Spickett 750ffc67bb3SDavid Spickett TEST_F(EnvironmentVariables, Empty) { 751ffc67bb3SDavid Spickett if (EnableFineGrainedTests()) { 752ffc67bb3SDavid Spickett CheckEnvVarValue("", "EMPTY"); 753ffc67bb3SDavid Spickett } 754ffc67bb3SDavid Spickett } 755ffc67bb3SDavid Spickett 756ffc67bb3SDavid Spickett TEST_F(EnvironmentVariables, NoValueOrErrmsg) { 757ffc67bb3SDavid Spickett ASSERT_EQ(std::getenv("DOESNT_EXIST"), nullptr) 758ffc67bb3SDavid Spickett << "Environment variable DOESNT_EXIST actually exists"; 759ffc67bb3SDavid Spickett EXPECT_EQ(RTNAME(GetEnvVariable)(*CharDescriptor("DOESNT_EXIST")), 1); 760ffc67bb3SDavid Spickett 761ffc67bb3SDavid Spickett if (EnableFineGrainedTests()) { 762ffc67bb3SDavid Spickett EXPECT_EQ(RTNAME(GetEnvVariable)(*CharDescriptor("NAME")), 0); 763ffc67bb3SDavid Spickett } 764ffc67bb3SDavid Spickett } 765ffc67bb3SDavid Spickett 766ffc67bb3SDavid Spickett TEST_F(EnvironmentVariables, ValueTooShort) { 767ffc67bb3SDavid Spickett if (EnableFineGrainedTests()) { 768ffc67bb3SDavid Spickett OwningPtr<Descriptor> tooShort{CreateEmptyCharDescriptor<2>()}; 769ffc67bb3SDavid Spickett ASSERT_NE(tooShort, nullptr); 770ffc67bb3SDavid Spickett EXPECT_EQ(RTNAME(GetEnvVariable)(*CharDescriptor("NAME"), tooShort.get(), 771ffc67bb3SDavid Spickett /*length=*/nullptr, /*trim_name=*/true, nullptr), 772ffc67bb3SDavid Spickett -1); 773ffc67bb3SDavid Spickett CheckDescriptorEqStr(tooShort.get(), "VALUE"); 774ffc67bb3SDavid Spickett 775ffc67bb3SDavid Spickett OwningPtr<Descriptor> errMsg{CreateEmptyCharDescriptor()}; 776ffc67bb3SDavid Spickett ASSERT_NE(errMsg, nullptr); 777ffc67bb3SDavid Spickett 778ffc67bb3SDavid Spickett EXPECT_EQ(RTNAME(GetEnvVariable)(*CharDescriptor("NAME"), tooShort.get(), 779ffc67bb3SDavid Spickett /*length=*/nullptr, /*trim_name=*/true, errMsg.get()), 780ffc67bb3SDavid Spickett -1); 781ffc67bb3SDavid Spickett 782ffc67bb3SDavid Spickett std::string expectedErrMsg{ 783ffc67bb3SDavid Spickett GetPaddedStr("Value too short", errMsg->ElementBytes())}; 784ffc67bb3SDavid Spickett CheckDescriptorEqStr(errMsg.get(), expectedErrMsg); 785ffc67bb3SDavid Spickett } 786ffc67bb3SDavid Spickett } 787ffc67bb3SDavid Spickett 788ffc67bb3SDavid Spickett TEST_F(EnvironmentVariables, ErrMsgTooShort) { 789ffc67bb3SDavid Spickett ASSERT_EQ(std::getenv("DOESNT_EXIST"), nullptr) 790ffc67bb3SDavid Spickett << "Environment variable DOESNT_EXIST actually exists"; 791ffc67bb3SDavid Spickett 792ffc67bb3SDavid Spickett OwningPtr<Descriptor> errMsg{CreateEmptyCharDescriptor<3>()}; 793ffc67bb3SDavid Spickett EXPECT_EQ(RTNAME(GetEnvVariable)(*CharDescriptor("DOESNT_EXIST"), nullptr, 794ffc67bb3SDavid Spickett /*length=*/nullptr, /*trim_name=*/true, errMsg.get()), 795ffc67bb3SDavid Spickett 1); 796ffc67bb3SDavid Spickett CheckDescriptorEqStr(errMsg.get(), "Mis"); 797ffc67bb3SDavid Spickett } 79818af032cSYi Wu 79918af032cSYi Wu // username first char must not be null 80018af032cSYi Wu TEST_F(EnvironmentVariables, GetlogGetName) { 80118af032cSYi Wu const int charLen{3}; 80218af032cSYi Wu char input[charLen]{"\0\0"}; 8034aa04245SPeter Klausler FORTRAN_PROCEDURE_NAME(getlog)(input, charLen); 80418af032cSYi Wu EXPECT_NE(input[0], '\0'); 80518af032cSYi Wu } 80618af032cSYi Wu 80718af032cSYi Wu #if _REENTRANT || _POSIX_C_SOURCE >= 199506L 80818af032cSYi Wu TEST_F(EnvironmentVariables, GetlogPadSpace) { 80918af032cSYi Wu // guarantee 1 char longer than max, last char should be pad space 810731b2956SRainer Orth int charLen; 811731b2956SRainer Orth #ifdef LOGIN_NAME_MAX 812731b2956SRainer Orth charLen = LOGIN_NAME_MAX + 2; 813731b2956SRainer Orth #else 814731b2956SRainer Orth charLen = sysconf(_SC_LOGIN_NAME_MAX) + 2; 815731b2956SRainer Orth if (charLen == -1) 816731b2956SRainer Orth charLen = _POSIX_LOGIN_NAME_MAX + 2; 817731b2956SRainer Orth #endif 818fb094471SKazu Hirata std::vector<char> input(charLen); 8194aa04245SPeter Klausler FORTRAN_PROCEDURE_NAME(getlog)(input.data(), charLen); 82018af032cSYi Wu EXPECT_EQ(input[charLen - 1], ' '); 82118af032cSYi Wu } 82218af032cSYi Wu #endif 82318af032cSYi Wu 82418af032cSYi Wu #ifdef _WIN32 // Test ability to get name from environment variable 82518af032cSYi Wu TEST_F(EnvironmentVariables, GetlogEnvGetName) { 82618af032cSYi Wu if (EnableFineGrainedTests()) { 82718af032cSYi Wu ASSERT_NE(std::getenv("USERNAME"), nullptr) 82818af032cSYi Wu << "Environment variable USERNAME does not exist"; 82918af032cSYi Wu 83018af032cSYi Wu char input[]{"XXXXXXXXX"}; 8314aa04245SPeter Klausler FORTRAN_PROCEDURE_NAME(getlog)(input, sizeof(input)); 83218af032cSYi Wu 83318af032cSYi Wu CheckCharEqStr(input, "loginName"); 83418af032cSYi Wu } 83518af032cSYi Wu } 83618af032cSYi Wu 83718af032cSYi Wu TEST_F(EnvironmentVariables, GetlogEnvBufferShort) { 83818af032cSYi Wu if (EnableFineGrainedTests()) { 83918af032cSYi Wu ASSERT_NE(std::getenv("USERNAME"), nullptr) 84018af032cSYi Wu << "Environment variable USERNAME does not exist"; 84118af032cSYi Wu 84218af032cSYi Wu char input[]{"XXXXXX"}; 8434aa04245SPeter Klausler FORTRAN_PROCEDURE_NAME(getlog)(input, sizeof(input)); 84418af032cSYi Wu 84518af032cSYi Wu CheckCharEqStr(input, "loginN"); 84618af032cSYi Wu } 84718af032cSYi Wu } 84818af032cSYi Wu 84918af032cSYi Wu TEST_F(EnvironmentVariables, GetlogEnvPadSpace) { 85018af032cSYi Wu if (EnableFineGrainedTests()) { 85118af032cSYi Wu ASSERT_NE(std::getenv("USERNAME"), nullptr) 85218af032cSYi Wu << "Environment variable USERNAME does not exist"; 85318af032cSYi Wu 85418af032cSYi Wu char input[]{"XXXXXXXXXX"}; 8554aa04245SPeter Klausler FORTRAN_PROCEDURE_NAME(getlog)(input, sizeof(input)); 85618af032cSYi Wu 85718af032cSYi Wu CheckCharEqStr(input, "loginName "); 85818af032cSYi Wu } 85918af032cSYi Wu } 86018af032cSYi Wu #endif 861