173b193aeSPeter Klausler //===-- flang/unittests/Runtime/CommandTest.cpp ---------------------------===//
20c375296SDiana Picus //
30c375296SDiana Picus // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40c375296SDiana Picus // See https://llvm.org/LICENSE.txt for license information.
50c375296SDiana Picus // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60c375296SDiana Picus //
70c375296SDiana Picus //===----------------------------------------------------------------------===//
80c375296SDiana Picus
9830c0b90SPeter Klausler #include "flang/Runtime/command.h"
1037089baeSDiana Picus #include "gmock/gmock.h"
110c375296SDiana Picus #include "gtest/gtest.h"
12830c0b90SPeter Klausler #include "flang/Runtime/descriptor.h"
13830c0b90SPeter Klausler #include "flang/Runtime/main.h"
14824bf908SDiana Picus #include <cstdlib>
150c375296SDiana Picus
160c375296SDiana Picus using namespace Fortran::runtime;
170c375296SDiana Picus
1837089baeSDiana Picus template <std::size_t n = 64>
CreateEmptyCharDescriptor()1937089baeSDiana Picus static OwningPtr<Descriptor> CreateEmptyCharDescriptor() {
2037089baeSDiana Picus OwningPtr<Descriptor> descriptor{Descriptor::Create(
2137089baeSDiana Picus sizeof(char), n, nullptr, 0, nullptr, CFI_attribute_allocatable)};
2237089baeSDiana Picus if (descriptor->Allocate() != 0) {
2337089baeSDiana Picus return nullptr;
2437089baeSDiana Picus }
2537089baeSDiana Picus return descriptor;
2637089baeSDiana Picus }
2737089baeSDiana Picus
CharDescriptor(const char * value)28fc2ba5e5SDiana Picus static OwningPtr<Descriptor> CharDescriptor(const char *value) {
29fc2ba5e5SDiana Picus std::size_t n{std::strlen(value)};
30fc2ba5e5SDiana Picus OwningPtr<Descriptor> descriptor{Descriptor::Create(
31fc2ba5e5SDiana Picus sizeof(char), n, nullptr, 0, nullptr, CFI_attribute_allocatable)};
32fc2ba5e5SDiana Picus if (descriptor->Allocate() != 0) {
33fc2ba5e5SDiana Picus return nullptr;
34fc2ba5e5SDiana Picus }
35fc2ba5e5SDiana Picus std::memcpy(descriptor->OffsetElement(), value, n);
36fc2ba5e5SDiana Picus return descriptor;
37fc2ba5e5SDiana Picus }
38fc2ba5e5SDiana Picus
39*873f081eSDiana Picus template <int kind = sizeof(std::int64_t)>
EmptyIntDescriptor()40*873f081eSDiana Picus static OwningPtr<Descriptor> EmptyIntDescriptor() {
41*873f081eSDiana Picus OwningPtr<Descriptor> descriptor{Descriptor::Create(TypeCategory::Integer,
42*873f081eSDiana Picus kind, nullptr, 0, nullptr, CFI_attribute_allocatable)};
43*873f081eSDiana Picus if (descriptor->Allocate() != 0) {
44*873f081eSDiana Picus return nullptr;
45*873f081eSDiana Picus }
46*873f081eSDiana Picus return descriptor;
47*873f081eSDiana Picus }
48*873f081eSDiana Picus
49af63d179SDiana Picus class CommandFixture : public ::testing::Test {
50af63d179SDiana Picus protected:
CommandFixture(int argc,const char * argv[])51af63d179SDiana Picus CommandFixture(int argc, const char *argv[]) {
52af63d179SDiana Picus RTNAME(ProgramStart)(argc, argv, {});
53af63d179SDiana Picus }
5437089baeSDiana Picus
GetPaddedStr(const char * text,std::size_t len) const5537089baeSDiana Picus std::string GetPaddedStr(const char *text, std::size_t len) const {
5637089baeSDiana Picus std::string res{text};
5737089baeSDiana Picus assert(res.length() <= len && "No room to pad");
5837089baeSDiana Picus res.append(len - res.length(), ' ');
5937089baeSDiana Picus return res;
6037089baeSDiana Picus }
6137089baeSDiana Picus
CheckDescriptorEqStr(const Descriptor * value,const std::string & expected) const6237089baeSDiana Picus void CheckDescriptorEqStr(
6337089baeSDiana Picus const Descriptor *value, const std::string &expected) const {
64*873f081eSDiana Picus ASSERT_NE(value, nullptr);
6537089baeSDiana Picus EXPECT_EQ(std::strncmp(value->OffsetElement(), expected.c_str(),
6637089baeSDiana Picus value->ElementBytes()),
679df0ba59SDiana Picus 0)
689df0ba59SDiana Picus << "expected: " << expected << "\n"
699df0ba59SDiana Picus << "value: "
709df0ba59SDiana Picus << std::string{value->OffsetElement(), value->ElementBytes()};
7137089baeSDiana Picus }
7237089baeSDiana Picus
73*873f081eSDiana Picus template <typename INT_T = std::int64_t>
CheckDescriptorEqInt(const Descriptor * value,const INT_T expected) const74*873f081eSDiana Picus void CheckDescriptorEqInt(
75*873f081eSDiana Picus const Descriptor *value, const INT_T expected) const {
76*873f081eSDiana Picus if (expected != -1) {
77*873f081eSDiana Picus ASSERT_NE(value, nullptr);
78*873f081eSDiana Picus EXPECT_EQ(*value->OffsetElement<INT_T>(), expected);
79*873f081eSDiana Picus }
80*873f081eSDiana Picus }
81*873f081eSDiana Picus
829df0ba59SDiana Picus template <typename RuntimeCall>
CheckValue(RuntimeCall F,const char * expectedValue,std::int64_t expectedLength=-1,std::int32_t expectedStatus=0,const char * expectedErrMsg="shouldn't change") const839df0ba59SDiana Picus void CheckValue(RuntimeCall F, const char *expectedValue,
84*873f081eSDiana Picus std::int64_t expectedLength = -1, std::int32_t expectedStatus = 0,
859df0ba59SDiana Picus const char *expectedErrMsg = "shouldn't change") const {
8637089baeSDiana Picus OwningPtr<Descriptor> value{CreateEmptyCharDescriptor()};
8737089baeSDiana Picus ASSERT_NE(value, nullptr);
8837089baeSDiana Picus
89*873f081eSDiana Picus OwningPtr<Descriptor> length{
90*873f081eSDiana Picus expectedLength == -1 ? nullptr : EmptyIntDescriptor()};
91*873f081eSDiana Picus
929df0ba59SDiana Picus OwningPtr<Descriptor> errmsg{CharDescriptor(expectedErrMsg)};
93*873f081eSDiana Picus ASSERT_NE(errmsg, nullptr);
9437089baeSDiana Picus
959df0ba59SDiana Picus std::string expectedValueStr{
969df0ba59SDiana Picus GetPaddedStr(expectedValue, value->ElementBytes())};
979df0ba59SDiana Picus
98*873f081eSDiana Picus EXPECT_EQ(F(value.get(), length.get(), errmsg.get()), expectedStatus);
999df0ba59SDiana Picus CheckDescriptorEqStr(value.get(), expectedValueStr);
100*873f081eSDiana Picus CheckDescriptorEqInt(length.get(), expectedLength);
1019df0ba59SDiana Picus CheckDescriptorEqStr(errmsg.get(), expectedErrMsg);
1029df0ba59SDiana Picus }
1039df0ba59SDiana Picus
CheckArgumentValue(const char * expectedValue,int n) const1049df0ba59SDiana Picus void CheckArgumentValue(const char *expectedValue, int n) const {
1059df0ba59SDiana Picus SCOPED_TRACE(n);
1069df0ba59SDiana Picus SCOPED_TRACE("Checking argument:");
1079df0ba59SDiana Picus CheckValue(
108*873f081eSDiana Picus [&](const Descriptor *value, const Descriptor *,
109*873f081eSDiana Picus const Descriptor *errmsg) {
1109df0ba59SDiana Picus return RTNAME(ArgumentValue)(n, value, errmsg);
1119df0ba59SDiana Picus },
1129df0ba59SDiana Picus expectedValue);
1139df0ba59SDiana Picus }
1149df0ba59SDiana Picus
CheckCommandValue(const char * args[],int n) const115*873f081eSDiana Picus void CheckCommandValue(const char *args[], int n) const {
116*873f081eSDiana Picus SCOPED_TRACE("Checking command:");
117*873f081eSDiana Picus ASSERT_GE(n, 1);
118*873f081eSDiana Picus std::string expectedValue{args[0]};
119*873f081eSDiana Picus for (int i = 1; i < n; i++) {
120*873f081eSDiana Picus expectedValue += " " + std::string{args[i]};
121*873f081eSDiana Picus }
122*873f081eSDiana Picus CheckValue(
123*873f081eSDiana Picus [&](const Descriptor *value, const Descriptor *length,
124*873f081eSDiana Picus const Descriptor *errmsg) {
125*873f081eSDiana Picus return RTNAME(GetCommand)(value, length, errmsg);
126*873f081eSDiana Picus },
127*873f081eSDiana Picus expectedValue.c_str(), expectedValue.size());
128*873f081eSDiana Picus }
129*873f081eSDiana Picus
CheckEnvVarValue(const char * expectedValue,const char * name,bool trimName=true) const1309df0ba59SDiana Picus void CheckEnvVarValue(
1319df0ba59SDiana Picus const char *expectedValue, const char *name, bool trimName = true) const {
1329df0ba59SDiana Picus SCOPED_TRACE(name);
1339df0ba59SDiana Picus SCOPED_TRACE("Checking environment variable");
1349df0ba59SDiana Picus CheckValue(
135*873f081eSDiana Picus [&](const Descriptor *value, const Descriptor *,
136*873f081eSDiana Picus const Descriptor *errmsg) {
1379df0ba59SDiana Picus return RTNAME(EnvVariableValue)(*CharDescriptor(name), value,
1389df0ba59SDiana Picus trimName, errmsg, /*sourceFile=*/nullptr, /*line=*/0);
1399df0ba59SDiana Picus },
1409df0ba59SDiana Picus expectedValue);
1419df0ba59SDiana Picus }
1429df0ba59SDiana Picus
CheckMissingEnvVarValue(const char * name,bool trimName=true) const1439df0ba59SDiana Picus void CheckMissingEnvVarValue(const char *name, bool trimName = true) const {
1449df0ba59SDiana Picus SCOPED_TRACE(name);
1459df0ba59SDiana Picus SCOPED_TRACE("Checking missing environment variable");
1469df0ba59SDiana Picus
1479df0ba59SDiana Picus ASSERT_EQ(nullptr, std::getenv(name))
1489df0ba59SDiana Picus << "Environment variable " << name << " not expected to exist";
1499df0ba59SDiana Picus
1509df0ba59SDiana Picus OwningPtr<Descriptor> nameDescriptor{CharDescriptor(name)};
1519df0ba59SDiana Picus EXPECT_EQ(0, RTNAME(EnvVariableLength)(*nameDescriptor, trimName));
1529df0ba59SDiana Picus CheckValue(
153*873f081eSDiana Picus [&](const Descriptor *value, const Descriptor *,
154*873f081eSDiana Picus const Descriptor *errmsg) {
1559df0ba59SDiana Picus return RTNAME(EnvVariableValue)(*nameDescriptor, value, trimName,
1569df0ba59SDiana Picus errmsg, /*sourceFile=*/nullptr, /*line=*/0);
1579df0ba59SDiana Picus },
158*873f081eSDiana Picus "", -1, 1, "Missing environment variable");
15937089baeSDiana Picus }
16037089baeSDiana Picus
CheckMissingArgumentValue(int n,const char * errStr=nullptr) const16137089baeSDiana Picus void CheckMissingArgumentValue(int n, const char *errStr = nullptr) const {
16237089baeSDiana Picus OwningPtr<Descriptor> value{CreateEmptyCharDescriptor()};
16337089baeSDiana Picus ASSERT_NE(value, nullptr);
16437089baeSDiana Picus
16537089baeSDiana Picus OwningPtr<Descriptor> err{errStr ? CreateEmptyCharDescriptor() : nullptr};
16637089baeSDiana Picus
16737089baeSDiana Picus EXPECT_GT(RTNAME(ArgumentValue)(n, value.get(), err.get()), 0);
16837089baeSDiana Picus
16937089baeSDiana Picus std::string spaces(value->ElementBytes(), ' ');
17037089baeSDiana Picus CheckDescriptorEqStr(value.get(), spaces);
17137089baeSDiana Picus
17237089baeSDiana Picus if (errStr) {
17337089baeSDiana Picus std::string paddedErrStr(GetPaddedStr(errStr, err->ElementBytes()));
17437089baeSDiana Picus CheckDescriptorEqStr(err.get(), paddedErrStr);
17537089baeSDiana Picus }
17637089baeSDiana Picus }
177*873f081eSDiana Picus
CheckMissingCommandValue(const char * errStr=nullptr) const178*873f081eSDiana Picus void CheckMissingCommandValue(const char *errStr = nullptr) const {
179*873f081eSDiana Picus OwningPtr<Descriptor> value{CreateEmptyCharDescriptor()};
180*873f081eSDiana Picus ASSERT_NE(value, nullptr);
181*873f081eSDiana Picus
182*873f081eSDiana Picus OwningPtr<Descriptor> length{EmptyIntDescriptor()};
183*873f081eSDiana Picus ASSERT_NE(length, nullptr);
184*873f081eSDiana Picus
185*873f081eSDiana Picus OwningPtr<Descriptor> err{errStr ? CreateEmptyCharDescriptor() : nullptr};
186*873f081eSDiana Picus
187*873f081eSDiana Picus EXPECT_GT(RTNAME(GetCommand)(value.get(), length.get(), err.get()), 0);
188*873f081eSDiana Picus
189*873f081eSDiana Picus std::string spaces(value->ElementBytes(), ' ');
190*873f081eSDiana Picus CheckDescriptorEqStr(value.get(), spaces);
191*873f081eSDiana Picus
192*873f081eSDiana Picus CheckDescriptorEqInt(length.get(), 0);
193*873f081eSDiana Picus
194*873f081eSDiana Picus if (errStr) {
195*873f081eSDiana Picus std::string paddedErrStr(GetPaddedStr(errStr, err->ElementBytes()));
196*873f081eSDiana Picus CheckDescriptorEqStr(err.get(), paddedErrStr);
197*873f081eSDiana Picus }
198*873f081eSDiana Picus }
199af63d179SDiana Picus };
200af63d179SDiana Picus
201*873f081eSDiana Picus class NoArgv : public CommandFixture {
202*873f081eSDiana Picus protected:
NoArgv()203*873f081eSDiana Picus NoArgv() : CommandFixture(0, nullptr) {}
204*873f081eSDiana Picus };
205*873f081eSDiana Picus
206*873f081eSDiana Picus // TODO: Test other intrinsics with this fixture.
207*873f081eSDiana Picus
TEST_F(NoArgv,GetCommand)208*873f081eSDiana Picus TEST_F(NoArgv, GetCommand) { CheckMissingCommandValue(); }
209*873f081eSDiana Picus
210af63d179SDiana Picus static const char *commandOnlyArgv[]{"aProgram"};
211af63d179SDiana Picus class ZeroArguments : public CommandFixture {
212af63d179SDiana Picus protected:
ZeroArguments()213af63d179SDiana Picus ZeroArguments() : CommandFixture(1, commandOnlyArgv) {}
214af63d179SDiana Picus };
215af63d179SDiana Picus
TEST_F(ZeroArguments,ArgumentCount)216af63d179SDiana Picus TEST_F(ZeroArguments, ArgumentCount) { EXPECT_EQ(0, RTNAME(ArgumentCount)()); }
217af63d179SDiana Picus
TEST_F(ZeroArguments,ArgumentLength)218af63d179SDiana Picus TEST_F(ZeroArguments, ArgumentLength) {
219af63d179SDiana Picus EXPECT_EQ(0, RTNAME(ArgumentLength)(-1));
220af63d179SDiana Picus EXPECT_EQ(8, RTNAME(ArgumentLength)(0));
221af63d179SDiana Picus EXPECT_EQ(0, RTNAME(ArgumentLength)(1));
2220c375296SDiana Picus }
2230c375296SDiana Picus
TEST_F(ZeroArguments,ArgumentValue)22437089baeSDiana Picus TEST_F(ZeroArguments, ArgumentValue) {
2259df0ba59SDiana Picus CheckArgumentValue(commandOnlyArgv[0], 0);
22637089baeSDiana Picus }
22737089baeSDiana Picus
TEST_F(ZeroArguments,GetCommand)228*873f081eSDiana Picus TEST_F(ZeroArguments, GetCommand) { CheckCommandValue(commandOnlyArgv, 1); }
229*873f081eSDiana Picus
230af63d179SDiana Picus static const char *oneArgArgv[]{"aProgram", "anArgumentOfLength20"};
231af63d179SDiana Picus class OneArgument : public CommandFixture {
232af63d179SDiana Picus protected:
OneArgument()233af63d179SDiana Picus OneArgument() : CommandFixture(2, oneArgArgv) {}
234af63d179SDiana Picus };
235af63d179SDiana Picus
TEST_F(OneArgument,ArgumentCount)236af63d179SDiana Picus TEST_F(OneArgument, ArgumentCount) { EXPECT_EQ(1, RTNAME(ArgumentCount)()); }
237af63d179SDiana Picus
TEST_F(OneArgument,ArgumentLength)238af63d179SDiana Picus TEST_F(OneArgument, ArgumentLength) {
239af63d179SDiana Picus EXPECT_EQ(0, RTNAME(ArgumentLength)(-1));
240af63d179SDiana Picus EXPECT_EQ(8, RTNAME(ArgumentLength)(0));
241af63d179SDiana Picus EXPECT_EQ(20, RTNAME(ArgumentLength)(1));
242af63d179SDiana Picus EXPECT_EQ(0, RTNAME(ArgumentLength)(2));
2430c375296SDiana Picus }
2440c375296SDiana Picus
TEST_F(OneArgument,ArgumentValue)24537089baeSDiana Picus TEST_F(OneArgument, ArgumentValue) {
2469df0ba59SDiana Picus CheckArgumentValue(oneArgArgv[0], 0);
2479df0ba59SDiana Picus CheckArgumentValue(oneArgArgv[1], 1);
24837089baeSDiana Picus }
24937089baeSDiana Picus
TEST_F(OneArgument,GetCommand)250*873f081eSDiana Picus TEST_F(OneArgument, GetCommand) { CheckCommandValue(oneArgArgv, 2); }
251*873f081eSDiana Picus
252af63d179SDiana Picus static const char *severalArgsArgv[]{
253af63d179SDiana Picus "aProgram", "16-char-long-arg", "", "-22-character-long-arg", "o"};
254af63d179SDiana Picus class SeveralArguments : public CommandFixture {
255af63d179SDiana Picus protected:
SeveralArguments()256af63d179SDiana Picus SeveralArguments()
257af63d179SDiana Picus : CommandFixture(sizeof(severalArgsArgv) / sizeof(*severalArgsArgv),
258af63d179SDiana Picus severalArgsArgv) {}
259af63d179SDiana Picus };
260af63d179SDiana Picus
TEST_F(SeveralArguments,ArgumentCount)261af63d179SDiana Picus TEST_F(SeveralArguments, ArgumentCount) {
2620c375296SDiana Picus EXPECT_EQ(4, RTNAME(ArgumentCount)());
2630c375296SDiana Picus }
264af63d179SDiana Picus
TEST_F(SeveralArguments,ArgumentLength)265af63d179SDiana Picus TEST_F(SeveralArguments, ArgumentLength) {
266af63d179SDiana Picus EXPECT_EQ(0, RTNAME(ArgumentLength)(-1));
267af63d179SDiana Picus EXPECT_EQ(8, RTNAME(ArgumentLength)(0));
268af63d179SDiana Picus EXPECT_EQ(16, RTNAME(ArgumentLength)(1));
269af63d179SDiana Picus EXPECT_EQ(0, RTNAME(ArgumentLength)(2));
270af63d179SDiana Picus EXPECT_EQ(22, RTNAME(ArgumentLength)(3));
271af63d179SDiana Picus EXPECT_EQ(1, RTNAME(ArgumentLength)(4));
272af63d179SDiana Picus EXPECT_EQ(0, RTNAME(ArgumentLength)(5));
273af63d179SDiana Picus }
27437089baeSDiana Picus
TEST_F(SeveralArguments,ArgumentValue)27537089baeSDiana Picus TEST_F(SeveralArguments, ArgumentValue) {
2769df0ba59SDiana Picus CheckArgumentValue(severalArgsArgv[0], 0);
2779df0ba59SDiana Picus CheckArgumentValue(severalArgsArgv[1], 1);
2789df0ba59SDiana Picus CheckArgumentValue(severalArgsArgv[3], 3);
2799df0ba59SDiana Picus CheckArgumentValue(severalArgsArgv[4], 4);
28037089baeSDiana Picus }
28137089baeSDiana Picus
TEST_F(SeveralArguments,NoArgumentValue)28237089baeSDiana Picus TEST_F(SeveralArguments, NoArgumentValue) {
28337089baeSDiana Picus // Make sure we don't crash if the 'value' and 'error' parameters aren't
28437089baeSDiana Picus // passed.
28537089baeSDiana Picus EXPECT_EQ(RTNAME(ArgumentValue)(2, nullptr, nullptr), 0);
28637089baeSDiana Picus EXPECT_GT(RTNAME(ArgumentValue)(-1, nullptr, nullptr), 0);
28737089baeSDiana Picus }
28837089baeSDiana Picus
TEST_F(SeveralArguments,MissingArguments)28937089baeSDiana Picus TEST_F(SeveralArguments, MissingArguments) {
29037089baeSDiana Picus CheckMissingArgumentValue(-1, "Invalid argument number");
29137089baeSDiana Picus CheckMissingArgumentValue(2, "Missing argument");
29237089baeSDiana Picus CheckMissingArgumentValue(5, "Invalid argument number");
29337089baeSDiana Picus CheckMissingArgumentValue(5);
29437089baeSDiana Picus }
29537089baeSDiana Picus
TEST_F(SeveralArguments,ArgValueTooShort)296*873f081eSDiana Picus TEST_F(SeveralArguments, ArgValueTooShort) {
29737089baeSDiana Picus OwningPtr<Descriptor> tooShort{CreateEmptyCharDescriptor<15>()};
29837089baeSDiana Picus ASSERT_NE(tooShort, nullptr);
29937089baeSDiana Picus EXPECT_EQ(RTNAME(ArgumentValue)(1, tooShort.get(), nullptr), -1);
30037089baeSDiana Picus CheckDescriptorEqStr(tooShort.get(), severalArgsArgv[1]);
30137089baeSDiana Picus
30237089baeSDiana Picus OwningPtr<Descriptor> errMsg{CreateEmptyCharDescriptor()};
30337089baeSDiana Picus ASSERT_NE(errMsg, nullptr);
30437089baeSDiana Picus
30537089baeSDiana Picus EXPECT_EQ(RTNAME(ArgumentValue)(1, tooShort.get(), errMsg.get()), -1);
30637089baeSDiana Picus
30737089baeSDiana Picus std::string expectedErrMsg{
30837089baeSDiana Picus GetPaddedStr("Value too short", errMsg->ElementBytes())};
30937089baeSDiana Picus CheckDescriptorEqStr(errMsg.get(), expectedErrMsg);
31037089baeSDiana Picus }
31137089baeSDiana Picus
TEST_F(SeveralArguments,ArgErrMsgTooShort)312*873f081eSDiana Picus TEST_F(SeveralArguments, ArgErrMsgTooShort) {
31337089baeSDiana Picus OwningPtr<Descriptor> errMsg{CreateEmptyCharDescriptor<3>()};
31437089baeSDiana Picus EXPECT_GT(RTNAME(ArgumentValue)(-1, nullptr, errMsg.get()), 0);
31537089baeSDiana Picus CheckDescriptorEqStr(errMsg.get(), "Inv");
31637089baeSDiana Picus }
317fc2ba5e5SDiana Picus
TEST_F(SeveralArguments,GetCommand)318*873f081eSDiana Picus TEST_F(SeveralArguments, GetCommand) {
319*873f081eSDiana Picus CheckMissingCommandValue();
320*873f081eSDiana Picus CheckMissingCommandValue("Missing argument");
321*873f081eSDiana Picus }
322*873f081eSDiana Picus
TEST_F(SeveralArguments,CommandErrMsgTooShort)323*873f081eSDiana Picus TEST_F(SeveralArguments, CommandErrMsgTooShort) {
324*873f081eSDiana Picus OwningPtr<Descriptor> value{CreateEmptyCharDescriptor()};
325*873f081eSDiana Picus OwningPtr<Descriptor> length{EmptyIntDescriptor()};
326*873f081eSDiana Picus OwningPtr<Descriptor> errMsg{CreateEmptyCharDescriptor<3>()};
327*873f081eSDiana Picus
328*873f081eSDiana Picus EXPECT_GT(RTNAME(GetCommand)(value.get(), length.get(), errMsg.get()), 0);
329*873f081eSDiana Picus
330*873f081eSDiana Picus std::string spaces(value->ElementBytes(), ' ');
331*873f081eSDiana Picus CheckDescriptorEqStr(value.get(), spaces);
332*873f081eSDiana Picus CheckDescriptorEqInt(length.get(), 0);
333*873f081eSDiana Picus CheckDescriptorEqStr(errMsg.get(), "Mis");
334*873f081eSDiana Picus }
335*873f081eSDiana Picus
TEST_F(SeveralArguments,GetCommandCanTakeNull)336*873f081eSDiana Picus TEST_F(SeveralArguments, GetCommandCanTakeNull) {
337*873f081eSDiana Picus EXPECT_GT(RTNAME(GetCommand)(nullptr, nullptr, nullptr), 0);
338*873f081eSDiana Picus }
339*873f081eSDiana Picus
340*873f081eSDiana Picus static const char *onlyValidArgsArgv[]{
341*873f081eSDiana Picus "aProgram", "-f", "has/a/few/slashes", "has\\a\\few\\backslashes"};
342*873f081eSDiana Picus class OnlyValidArguments : public CommandFixture {
343*873f081eSDiana Picus protected:
OnlyValidArguments()344*873f081eSDiana Picus OnlyValidArguments()
345*873f081eSDiana Picus : CommandFixture(sizeof(onlyValidArgsArgv) / sizeof(*onlyValidArgsArgv),
346*873f081eSDiana Picus onlyValidArgsArgv) {}
347*873f081eSDiana Picus };
348*873f081eSDiana Picus
TEST_F(OnlyValidArguments,GetCommand)349*873f081eSDiana Picus TEST_F(OnlyValidArguments, GetCommand) {
350*873f081eSDiana Picus CheckCommandValue(onlyValidArgsArgv, 4);
351*873f081eSDiana Picus }
352*873f081eSDiana Picus
TEST_F(OnlyValidArguments,CommandValueTooShort)353*873f081eSDiana Picus TEST_F(OnlyValidArguments, CommandValueTooShort) {
354*873f081eSDiana Picus OwningPtr<Descriptor> tooShort{CreateEmptyCharDescriptor<50>()};
355*873f081eSDiana Picus ASSERT_NE(tooShort, nullptr);
356*873f081eSDiana Picus OwningPtr<Descriptor> length{EmptyIntDescriptor()};
357*873f081eSDiana Picus ASSERT_NE(length, nullptr);
358*873f081eSDiana Picus
359*873f081eSDiana Picus EXPECT_EQ(RTNAME(GetCommand)(tooShort.get(), length.get(), nullptr), -1);
360*873f081eSDiana Picus
361*873f081eSDiana Picus CheckDescriptorEqStr(
362*873f081eSDiana Picus tooShort.get(), "aProgram -f has/a/few/slashes has\\a\\few\\backslashe");
363*873f081eSDiana Picus CheckDescriptorEqInt(length.get(), 51);
364*873f081eSDiana Picus
365*873f081eSDiana Picus OwningPtr<Descriptor> errMsg{CreateEmptyCharDescriptor()};
366*873f081eSDiana Picus ASSERT_NE(errMsg, nullptr);
367*873f081eSDiana Picus
368*873f081eSDiana Picus EXPECT_EQ(-1, RTNAME(GetCommand)(tooShort.get(), nullptr, errMsg.get()));
369*873f081eSDiana Picus
370*873f081eSDiana Picus std::string expectedErrMsg{
371*873f081eSDiana Picus GetPaddedStr("Value too short", errMsg->ElementBytes())};
372*873f081eSDiana Picus CheckDescriptorEqStr(errMsg.get(), expectedErrMsg);
373*873f081eSDiana Picus }
374*873f081eSDiana Picus
TEST_F(OnlyValidArguments,GetCommandCanTakeNull)375*873f081eSDiana Picus TEST_F(OnlyValidArguments, GetCommandCanTakeNull) {
376*873f081eSDiana Picus EXPECT_EQ(0, RTNAME(GetCommand)(nullptr, nullptr, nullptr));
377*873f081eSDiana Picus
378*873f081eSDiana Picus OwningPtr<Descriptor> value{CreateEmptyCharDescriptor()};
379*873f081eSDiana Picus ASSERT_NE(value, nullptr);
380*873f081eSDiana Picus OwningPtr<Descriptor> length{EmptyIntDescriptor()};
381*873f081eSDiana Picus ASSERT_NE(length, nullptr);
382*873f081eSDiana Picus
383*873f081eSDiana Picus EXPECT_EQ(0, RTNAME(GetCommand)(value.get(), nullptr, nullptr));
384*873f081eSDiana Picus CheckDescriptorEqStr(value.get(),
385*873f081eSDiana Picus GetPaddedStr("aProgram -f has/a/few/slashes has\\a\\few\\backslashes",
386*873f081eSDiana Picus value->ElementBytes()));
387*873f081eSDiana Picus
388*873f081eSDiana Picus EXPECT_EQ(0, RTNAME(GetCommand)(nullptr, length.get(), nullptr));
389*873f081eSDiana Picus CheckDescriptorEqInt(length.get(), 51);
390*873f081eSDiana Picus }
391*873f081eSDiana Picus
TEST_F(OnlyValidArguments,GetCommandShortLength)392*873f081eSDiana Picus TEST_F(OnlyValidArguments, GetCommandShortLength) {
393*873f081eSDiana Picus OwningPtr<Descriptor> length{EmptyIntDescriptor<sizeof(short)>()};
394*873f081eSDiana Picus ASSERT_NE(length, nullptr);
395*873f081eSDiana Picus
396*873f081eSDiana Picus EXPECT_EQ(0, RTNAME(GetCommand)(nullptr, length.get(), nullptr));
397*873f081eSDiana Picus CheckDescriptorEqInt<short>(length.get(), 51);
398*873f081eSDiana Picus }
399*873f081eSDiana Picus
400fc2ba5e5SDiana Picus class EnvironmentVariables : public CommandFixture {
401fc2ba5e5SDiana Picus protected:
EnvironmentVariables()402824bf908SDiana Picus EnvironmentVariables() : CommandFixture(0, nullptr) {
403824bf908SDiana Picus SetEnv("NAME", "VALUE");
4049df0ba59SDiana Picus SetEnv("EMPTY", "");
405824bf908SDiana Picus }
406824bf908SDiana Picus
407824bf908SDiana Picus // If we have access to setenv, we can run some more fine-grained tests.
408824bf908SDiana Picus template <typename ParamType = char>
409824bf908SDiana Picus void SetEnv(const ParamType *name, const ParamType *value,
410824bf908SDiana Picus decltype(setenv(name, value, 1)) *Enabled = nullptr) {
411824bf908SDiana Picus ASSERT_EQ(0, setenv(name, value, /*overwrite=*/1));
412824bf908SDiana Picus canSetEnv = true;
413824bf908SDiana Picus }
414824bf908SDiana Picus
415824bf908SDiana Picus // Fallback method if setenv is not available.
SetEnv(const void *,const void *)416824bf908SDiana Picus template <typename Unused = void> void SetEnv(const void *, const void *) {}
417824bf908SDiana Picus
EnableFineGrainedTests() const418824bf908SDiana Picus bool EnableFineGrainedTests() const { return canSetEnv; }
419824bf908SDiana Picus
420824bf908SDiana Picus private:
421824bf908SDiana Picus bool canSetEnv{false};
422fc2ba5e5SDiana Picus };
423fc2ba5e5SDiana Picus
TEST_F(EnvironmentVariables,Nonexistent)4249df0ba59SDiana Picus TEST_F(EnvironmentVariables, Nonexistent) {
4259df0ba59SDiana Picus CheckMissingEnvVarValue("DOESNT_EXIST");
426fc2ba5e5SDiana Picus
4279df0ba59SDiana Picus CheckMissingEnvVarValue(" ");
4289df0ba59SDiana Picus CheckMissingEnvVarValue("");
4299df0ba59SDiana Picus }
430824bf908SDiana Picus
TEST_F(EnvironmentVariables,Basic)4319df0ba59SDiana Picus TEST_F(EnvironmentVariables, Basic) {
432824bf908SDiana Picus // Test a variable that's expected to exist in the environment.
433824bf908SDiana Picus char *path{std::getenv("PATH")};
434824bf908SDiana Picus auto expectedLen{static_cast<int64_t>(std::strlen(path))};
435824bf908SDiana Picus EXPECT_EQ(expectedLen, RTNAME(EnvVariableLength)(*CharDescriptor("PATH")));
4369df0ba59SDiana Picus }
437824bf908SDiana Picus
TEST_F(EnvironmentVariables,Trim)4389df0ba59SDiana Picus TEST_F(EnvironmentVariables, Trim) {
439824bf908SDiana Picus if (EnableFineGrainedTests()) {
440824bf908SDiana Picus EXPECT_EQ(5, RTNAME(EnvVariableLength)(*CharDescriptor("NAME ")));
4419df0ba59SDiana Picus CheckEnvVarValue("VALUE", "NAME ");
442824bf908SDiana Picus }
443fc2ba5e5SDiana Picus }
4449df0ba59SDiana Picus
TEST_F(EnvironmentVariables,NoTrim)4459df0ba59SDiana Picus TEST_F(EnvironmentVariables, NoTrim) {
4469df0ba59SDiana Picus if (EnableFineGrainedTests()) {
4479df0ba59SDiana Picus CheckMissingEnvVarValue("NAME ", /*trim_name=*/false);
4489df0ba59SDiana Picus }
4499df0ba59SDiana Picus }
4509df0ba59SDiana Picus
TEST_F(EnvironmentVariables,Empty)4519df0ba59SDiana Picus TEST_F(EnvironmentVariables, Empty) {
4529df0ba59SDiana Picus if (EnableFineGrainedTests()) {
4539df0ba59SDiana Picus EXPECT_EQ(0, RTNAME(EnvVariableLength)(*CharDescriptor("EMPTY")));
4549df0ba59SDiana Picus CheckEnvVarValue("", "EMPTY");
4559df0ba59SDiana Picus }
4569df0ba59SDiana Picus }
4579df0ba59SDiana Picus
TEST_F(EnvironmentVariables,NoValueOrErrmsg)4589df0ba59SDiana Picus TEST_F(EnvironmentVariables, NoValueOrErrmsg) {
4599df0ba59SDiana Picus ASSERT_EQ(std::getenv("DOESNT_EXIST"), nullptr)
4609df0ba59SDiana Picus << "Environment variable DOESNT_EXIST actually exists";
4619df0ba59SDiana Picus EXPECT_EQ(RTNAME(EnvVariableValue)(*CharDescriptor("DOESNT_EXIST")), 1);
4629df0ba59SDiana Picus
4639df0ba59SDiana Picus if (EnableFineGrainedTests()) {
4649df0ba59SDiana Picus EXPECT_EQ(RTNAME(EnvVariableValue)(*CharDescriptor("NAME")), 0);
4659df0ba59SDiana Picus }
4669df0ba59SDiana Picus }
4679df0ba59SDiana Picus
TEST_F(EnvironmentVariables,ValueTooShort)4689df0ba59SDiana Picus TEST_F(EnvironmentVariables, ValueTooShort) {
4699df0ba59SDiana Picus if (EnableFineGrainedTests()) {
4709df0ba59SDiana Picus OwningPtr<Descriptor> tooShort{CreateEmptyCharDescriptor<2>()};
4719df0ba59SDiana Picus ASSERT_NE(tooShort, nullptr);
4729df0ba59SDiana Picus EXPECT_EQ(RTNAME(EnvVariableValue)(*CharDescriptor("NAME"), tooShort.get(),
4739df0ba59SDiana Picus /*trim_name=*/true, nullptr),
4749df0ba59SDiana Picus -1);
4759df0ba59SDiana Picus CheckDescriptorEqStr(tooShort.get(), "VALUE");
4769df0ba59SDiana Picus
4779df0ba59SDiana Picus OwningPtr<Descriptor> errMsg{CreateEmptyCharDescriptor()};
4789df0ba59SDiana Picus ASSERT_NE(errMsg, nullptr);
4799df0ba59SDiana Picus
4809df0ba59SDiana Picus EXPECT_EQ(RTNAME(EnvVariableValue)(*CharDescriptor("NAME"), tooShort.get(),
4819df0ba59SDiana Picus /*trim_name=*/true, errMsg.get()),
4829df0ba59SDiana Picus -1);
4839df0ba59SDiana Picus
4849df0ba59SDiana Picus std::string expectedErrMsg{
4859df0ba59SDiana Picus GetPaddedStr("Value too short", errMsg->ElementBytes())};
4869df0ba59SDiana Picus CheckDescriptorEqStr(errMsg.get(), expectedErrMsg);
4879df0ba59SDiana Picus }
4889df0ba59SDiana Picus }
4899df0ba59SDiana Picus
TEST_F(EnvironmentVariables,ErrMsgTooShort)4909df0ba59SDiana Picus TEST_F(EnvironmentVariables, ErrMsgTooShort) {
4919df0ba59SDiana Picus ASSERT_EQ(std::getenv("DOESNT_EXIST"), nullptr)
4929df0ba59SDiana Picus << "Environment variable DOESNT_EXIST actually exists";
4939df0ba59SDiana Picus
4949df0ba59SDiana Picus OwningPtr<Descriptor> errMsg{CreateEmptyCharDescriptor<3>()};
4959df0ba59SDiana Picus EXPECT_EQ(RTNAME(EnvVariableValue)(*CharDescriptor("DOESNT_EXIST"), nullptr,
4969df0ba59SDiana Picus /*trim_name=*/true, errMsg.get()),
4979df0ba59SDiana Picus 1);
4989df0ba59SDiana Picus CheckDescriptorEqStr(errMsg.get(), "Mis");
4999df0ba59SDiana Picus }
500