xref: /llvm-project/flang/unittests/Runtime/CommandTest.cpp (revision af35e21cfe3f7cfc7ddd7a2f535e775e9205f61d)
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