332 lines · cpp
1//===-- ArgsTest.cpp ------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "gtest/gtest.h"10 11#include "lldb/Utility/Args.h"12#include "lldb/Utility/FileSpec.h"13#include "lldb/Utility/StringList.h"14 15#include <limits>16#include <sstream>17 18using namespace lldb_private;19 20TEST(ArgsTest, TestSingleArg) {21 Args args;22 args.SetCommandString("arg");23 EXPECT_EQ(1u, args.GetArgumentCount());24 EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg");25}26 27TEST(ArgsTest, TestSingleQuotedArgWithSpace) {28 Args args;29 args.SetCommandString("\"arg with space\"");30 EXPECT_EQ(1u, args.GetArgumentCount());31 EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg with space");32}33 34TEST(ArgsTest, TestSingleArgWithQuotedSpace) {35 Args args;36 args.SetCommandString("arg\\ with\\ space");37 EXPECT_EQ(1u, args.GetArgumentCount());38 EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg with space");39}40 41TEST(ArgsTest, TestTrailingBackslash) {42 Args args;43 args.SetCommandString("arg\\");44 EXPECT_EQ(1u, args.GetArgumentCount());45 EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg\\");46}47 48TEST(ArgsTest, TestQuotedTrailingBackslash) {49 Args args;50 args.SetCommandString("\"arg\\");51 EXPECT_EQ(1u, args.GetArgumentCount());52 EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg\\");53}54 55TEST(ArgsTest, TestUnknownEscape) {56 Args args;57 args.SetCommandString("arg\\y");58 EXPECT_EQ(1u, args.GetArgumentCount());59 EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg\\y");60}61 62TEST(ArgsTest, TestQuotedUnknownEscape) {63 Args args;64 args.SetCommandString("\"arg\\y");65 EXPECT_EQ(1u, args.GetArgumentCount());66 EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg\\y");67}68 69TEST(ArgsTest, TestMultipleArgs) {70 Args args;71 args.SetCommandString("this has multiple args");72 EXPECT_EQ(4u, args.GetArgumentCount());73 EXPECT_STREQ(args.GetArgumentAtIndex(0), "this");74 EXPECT_STREQ(args.GetArgumentAtIndex(1), "has");75 EXPECT_STREQ(args.GetArgumentAtIndex(2), "multiple");76 EXPECT_STREQ(args.GetArgumentAtIndex(3), "args");77}78 79TEST(ArgsTest, TestOverwriteArgs) {80 Args args;81 args.SetCommandString("this has multiple args");82 EXPECT_EQ(4u, args.GetArgumentCount());83 args.SetCommandString("arg");84 EXPECT_EQ(1u, args.GetArgumentCount());85 EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg");86}87 88TEST(ArgsTest, TestAppendArg) {89 Args args;90 args.SetCommandString("first_arg");91 EXPECT_EQ(1u, args.GetArgumentCount());92 args.AppendArgument(llvm::StringRef("second_arg"));93 EXPECT_EQ(2u, args.GetArgumentCount());94 EXPECT_STREQ(args.GetArgumentAtIndex(0), "first_arg");95 EXPECT_STREQ(args.GetArgumentAtIndex(1), "second_arg");96}97 98TEST(ArgsTest, TestInsertArg) {99 Args args;100 args.AppendArgument("1");101 args.AppendArgument("2");102 args.AppendArgument("3");103 args.InsertArgumentAtIndex(1, "1.5");104 args.InsertArgumentAtIndex(4, "3.5");105 106 ASSERT_EQ(5u, args.GetArgumentCount());107 EXPECT_STREQ("1", args.GetArgumentAtIndex(0));108 EXPECT_STREQ("1.5", args.GetArgumentAtIndex(1));109 EXPECT_STREQ("2", args.GetArgumentAtIndex(2));110 EXPECT_STREQ("3", args.GetArgumentAtIndex(3));111 EXPECT_STREQ("3.5", args.GetArgumentAtIndex(4));112}113 114TEST(ArgsTest, TestArgv) {115 Args args;116 EXPECT_EQ(nullptr, args.GetArgumentVector());117 118 args.AppendArgument("1");119 EXPECT_NE(nullptr, args.GetArgumentVector()[0]);120 EXPECT_EQ(nullptr, args.GetArgumentVector()[1]);121 122 args.AppendArgument("2");123 EXPECT_NE(nullptr, args.GetArgumentVector()[0]);124 EXPECT_NE(nullptr, args.GetArgumentVector()[1]);125 EXPECT_EQ(nullptr, args.GetArgumentVector()[2]);126 127 args.AppendArgument("3");128 EXPECT_NE(nullptr, args.GetArgumentVector()[0]);129 EXPECT_NE(nullptr, args.GetArgumentVector()[1]);130 EXPECT_NE(nullptr, args.GetArgumentVector()[2]);131 EXPECT_EQ(nullptr, args.GetArgumentVector()[3]);132 133 args.InsertArgumentAtIndex(1, "1.5");134 EXPECT_NE(nullptr, args.GetArgumentVector()[0]);135 EXPECT_NE(nullptr, args.GetArgumentVector()[1]);136 EXPECT_NE(nullptr, args.GetArgumentVector()[2]);137 EXPECT_NE(nullptr, args.GetArgumentVector()[3]);138 EXPECT_EQ(nullptr, args.GetArgumentVector()[4]);139 140 args.InsertArgumentAtIndex(4, "3.5");141 EXPECT_NE(nullptr, args.GetArgumentVector()[0]);142 EXPECT_NE(nullptr, args.GetArgumentVector()[1]);143 EXPECT_NE(nullptr, args.GetArgumentVector()[2]);144 EXPECT_NE(nullptr, args.GetArgumentVector()[3]);145 EXPECT_NE(nullptr, args.GetArgumentVector()[4]);146 EXPECT_EQ(nullptr, args.GetArgumentVector()[5]);147}148 149TEST(ArgsTest, StringListConstructor) {150 StringList list;151 list << "foo"152 << "bar"153 << "baz";154 Args args(list);155 ASSERT_EQ(3u, args.GetArgumentCount());156 EXPECT_EQ("foo", args[0].ref());157 EXPECT_EQ("bar", args[1].ref());158 EXPECT_EQ("baz", args[2].ref());159}160 161TEST(ArgsTest, GetQuotedCommandString) {162 Args args;163 const char *str = "process launch -o stdout.txt -- \"a b c\"";164 args.SetCommandString(str);165 166 std::string stdstr;167 ASSERT_TRUE(args.GetQuotedCommandString(stdstr));168 EXPECT_EQ(str, stdstr);169}170 171TEST(ArgsTest, BareSingleQuote) {172 Args args;173 args.SetCommandString("a\\'b");174 EXPECT_EQ(1u, args.GetArgumentCount());175 176 EXPECT_STREQ("a'b", args.GetArgumentAtIndex(0));177}178 179TEST(ArgsTest, DoubleQuotedItem) {180 Args args;181 args.SetCommandString("\"a b c\"");182 EXPECT_EQ(1u, args.GetArgumentCount());183 184 EXPECT_STREQ("a b c", args.GetArgumentAtIndex(0));185}186 187TEST(ArgsTest, AppendArguments) {188 Args args;189 const char *argv[] = {"1", "2", nullptr};190 const char *argv2[] = {"3", "4", nullptr};191 192 args.AppendArguments(argv);193 ASSERT_EQ(2u, args.GetArgumentCount());194 EXPECT_STREQ("1", args.GetArgumentVector()[0]);195 EXPECT_STREQ("2", args.GetArgumentVector()[1]);196 EXPECT_EQ(nullptr, args.GetArgumentVector()[2]);197 EXPECT_STREQ("1", args.GetArgumentAtIndex(0));198 EXPECT_STREQ("2", args.GetArgumentAtIndex(1));199 200 args.AppendArguments(argv2);201 ASSERT_EQ(4u, args.GetArgumentCount());202 EXPECT_STREQ("1", args.GetArgumentVector()[0]);203 EXPECT_STREQ("2", args.GetArgumentVector()[1]);204 EXPECT_STREQ("3", args.GetArgumentVector()[2]);205 EXPECT_STREQ("4", args.GetArgumentVector()[3]);206 EXPECT_EQ(nullptr, args.GetArgumentVector()[4]);207 EXPECT_STREQ("1", args.GetArgumentAtIndex(0));208 EXPECT_STREQ("2", args.GetArgumentAtIndex(1));209 EXPECT_STREQ("3", args.GetArgumentAtIndex(2));210 EXPECT_STREQ("4", args.GetArgumentAtIndex(3));211}212 213TEST(ArgsTest, GetArgumentArrayRef) {214 Args args("foo bar");215 auto ref = args.GetArgumentArrayRef();216 ASSERT_EQ(2u, ref.size());217 EXPECT_STREQ("foo", ref[0]);218 EXPECT_STREQ("bar", ref[1]);219}220 221TEST(ArgsTest, EscapeLLDBCommandArgument) {222 const std::string foo = "foo'";223 EXPECT_EQ("foo\\'", Args::EscapeLLDBCommandArgument(foo, '\0'));224 EXPECT_EQ("foo'", Args::EscapeLLDBCommandArgument(foo, '\''));225 EXPECT_EQ("foo'", Args::EscapeLLDBCommandArgument(foo, '`'));226 EXPECT_EQ("foo'", Args::EscapeLLDBCommandArgument(foo, '"'));227 228 const std::string bar = "bar\"";229 EXPECT_EQ("bar\\\"", Args::EscapeLLDBCommandArgument(bar, '\0'));230 EXPECT_EQ("bar\"", Args::EscapeLLDBCommandArgument(bar, '\''));231 EXPECT_EQ("bar\"", Args::EscapeLLDBCommandArgument(bar, '`'));232 EXPECT_EQ("bar\\\"", Args::EscapeLLDBCommandArgument(bar, '"'));233 234 const std::string baz = "baz`";235 EXPECT_EQ("baz\\`", Args::EscapeLLDBCommandArgument(baz, '\0'));236 EXPECT_EQ("baz`", Args::EscapeLLDBCommandArgument(baz, '\''));237 EXPECT_EQ("baz`", Args::EscapeLLDBCommandArgument(baz, '`'));238 EXPECT_EQ("baz\\`", Args::EscapeLLDBCommandArgument(baz, '"'));239 240 const std::string quux = "quux\t";241 EXPECT_EQ("quux\\\t", Args::EscapeLLDBCommandArgument(quux, '\0'));242 EXPECT_EQ("quux\t", Args::EscapeLLDBCommandArgument(quux, '\''));243 EXPECT_EQ("quux\t", Args::EscapeLLDBCommandArgument(quux, '`'));244 EXPECT_EQ("quux\t", Args::EscapeLLDBCommandArgument(quux, '"'));245}246 247TEST(ArgsTest, ReplaceArgumentAtIndexShort) {248 Args args;249 args.SetCommandString("foo ba b");250 args.ReplaceArgumentAtIndex(0, "f");251 EXPECT_EQ(3u, args.GetArgumentCount());252 EXPECT_STREQ(args.GetArgumentAtIndex(0), "f");253}254 255TEST(ArgsTest, ReplaceArgumentAtIndexEqual) {256 Args args;257 args.SetCommandString("foo ba b");258 args.ReplaceArgumentAtIndex(0, "bar");259 EXPECT_EQ(3u, args.GetArgumentCount());260 EXPECT_STREQ(args.GetArgumentAtIndex(0), "bar");261}262 263TEST(ArgsTest, ReplaceArgumentAtIndexLonger) {264 Args args;265 args.SetCommandString("foo ba b");266 args.ReplaceArgumentAtIndex(0, "baar");267 EXPECT_EQ(3u, args.GetArgumentCount());268 EXPECT_STREQ(args.GetArgumentAtIndex(0), "baar");269}270 271TEST(ArgsTest, ReplaceArgumentAtIndexOutOfRange) {272 Args args;273 args.SetCommandString("foo ba b");274 args.ReplaceArgumentAtIndex(3, "baar");275 EXPECT_EQ(3u, args.GetArgumentCount());276 EXPECT_STREQ(args.GetArgumentAtIndex(2), "b");277}278 279TEST(ArgsTest, ReplaceArgumentAtIndexFarOutOfRange) {280 Args args;281 args.SetCommandString("foo ba b");282 args.ReplaceArgumentAtIndex(4, "baar");283 EXPECT_EQ(3u, args.GetArgumentCount());284 EXPECT_STREQ(args.GetArgumentAtIndex(2), "b");285}286 287TEST(ArgsTest, GetShellSafeArgument) {288 // Try escaping with bash at start/middle/end of the argument.289 FileSpec bash("/bin/bash", FileSpec::Style::posix);290 EXPECT_EQ(Args::GetShellSafeArgument(bash, "\"b"), "\\\"b");291 EXPECT_EQ(Args::GetShellSafeArgument(bash, "a\""), "a\\\"");292 EXPECT_EQ(Args::GetShellSafeArgument(bash, "a\"b"), "a\\\"b");293 294 FileSpec zsh("/bin/zsh", FileSpec::Style::posix);295 EXPECT_EQ(Args::GetShellSafeArgument(zsh, R"('";()<>&|\)"),296 R"(\'\"\;\(\)\<\>\&\|\\)");297 // Normal characters and expressions that shouldn't be escaped.298 EXPECT_EQ(Args::GetShellSafeArgument(zsh, "aA$1*"), "aA$1*");299 300 // Test escaping bash special characters.301 EXPECT_EQ(Args::GetShellSafeArgument(bash, R"( '"<>()&;)"),302 R"(\ \'\"\<\>\(\)\&\;)");303 // Normal characters and globbing expressions that shouldn't be escaped.304 EXPECT_EQ(Args::GetShellSafeArgument(bash, "aA$1*"), "aA$1*");305 306 // Test escaping tcsh special characters.307 FileSpec tcsh("/bin/tcsh", FileSpec::Style::posix);308 EXPECT_EQ(Args::GetShellSafeArgument(tcsh, R"( '"<>()&;)"),309 R"(\ \'\"\<\>\(\)\&\;)");310 // Normal characters and globbing expressions that shouldn't be escaped.311 EXPECT_EQ(Args::GetShellSafeArgument(tcsh, "aA1*"), "aA1*");312 313 // Test escaping sh special characters.314 FileSpec sh("/bin/sh", FileSpec::Style::posix);315 EXPECT_EQ(Args::GetShellSafeArgument(sh, R"( '"<>()&;)"),316 R"(\ \'\"\<\>\(\)\&\;)");317 // Normal characters and globbing expressions that shouldn't be escaped.318 EXPECT_EQ(Args::GetShellSafeArgument(sh, "aA$1*"), "aA$1*");319 320 // Test escaping fish special characters.321 FileSpec fish("/bin/fish", FileSpec::Style::posix);322 EXPECT_EQ(Args::GetShellSafeArgument(fish, R"( '"<>()&\|;)"),323 R"(\ \'\"\<\>\(\)\&\\\|\;)");324 // Normal characters and expressions that shouldn't be escaped.325 EXPECT_EQ(Args::GetShellSafeArgument(fish, "aA$1*"), "aA$1*");326 327 // Try escaping with an unknown shell.328 FileSpec unknown_shell("/bin/unknown_shell", FileSpec::Style::posix);329 EXPECT_EQ(Args::GetShellSafeArgument(unknown_shell, "a'b"), "a\\'b");330 EXPECT_EQ(Args::GetShellSafeArgument(unknown_shell, "a\"b"), "a\\\"b");331}332