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-exception 6 // 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 18 using namespace lldb_private; 19 20 TEST(ArgsTest, TestSingleArg) { 21 Args args; 22 args.SetCommandString("arg"); 23 EXPECT_EQ(1u, args.GetArgumentCount()); 24 EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg"); 25 } 26 27 TEST(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 34 TEST(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 41 TEST(ArgsTest, TestTrailingBackslash) { 42 Args args; 43 args.SetCommandString("arg\\"); 44 EXPECT_EQ(1u, args.GetArgumentCount()); 45 EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg\\"); 46 } 47 48 TEST(ArgsTest, TestQuotedTrailingBackslash) { 49 Args args; 50 args.SetCommandString("\"arg\\"); 51 EXPECT_EQ(1u, args.GetArgumentCount()); 52 EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg\\"); 53 } 54 55 TEST(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 62 TEST(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 69 TEST(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 79 TEST(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 88 TEST(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 98 TEST(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 114 TEST(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 149 TEST(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 161 TEST(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 171 TEST(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 179 TEST(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 187 TEST(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 213 TEST(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 221 TEST(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 247 TEST(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 255 TEST(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 263 TEST(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 271 TEST(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 279 TEST(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 287 TEST(ArgsTest, Yaml) { 288 std::string buffer; 289 llvm::raw_string_ostream os(buffer); 290 291 // Serialize. 292 Args args; 293 args.SetCommandString("this 'has' \"multiple\" args"); 294 llvm::yaml::Output yout(os); 295 yout << args; 296 os.flush(); 297 298 llvm::outs() << buffer; 299 300 // Deserialize. 301 Args deserialized; 302 llvm::yaml::Input yin(buffer); 303 yin >> deserialized; 304 305 EXPECT_EQ(4u, deserialized.GetArgumentCount()); 306 EXPECT_STREQ(deserialized.GetArgumentAtIndex(0), "this"); 307 EXPECT_STREQ(deserialized.GetArgumentAtIndex(1), "has"); 308 EXPECT_STREQ(deserialized.GetArgumentAtIndex(2), "multiple"); 309 EXPECT_STREQ(deserialized.GetArgumentAtIndex(3), "args"); 310 311 llvm::ArrayRef<Args::ArgEntry> entries = deserialized.entries(); 312 EXPECT_EQ(entries[0].GetQuoteChar(), '\0'); 313 EXPECT_EQ(entries[1].GetQuoteChar(), '\''); 314 EXPECT_EQ(entries[2].GetQuoteChar(), '"'); 315 EXPECT_EQ(entries[3].GetQuoteChar(), '\0'); 316 } 317 318 TEST(ArgsTest, GetShellSafeArgument) { 319 // Try escaping with bash at start/middle/end of the argument. 320 FileSpec bash("/bin/bash", FileSpec::Style::posix); 321 EXPECT_EQ(Args::GetShellSafeArgument(bash, "\"b"), "\\\"b"); 322 EXPECT_EQ(Args::GetShellSafeArgument(bash, "a\""), "a\\\""); 323 EXPECT_EQ(Args::GetShellSafeArgument(bash, "a\"b"), "a\\\"b"); 324 325 FileSpec zsh("/bin/zsh", FileSpec::Style::posix); 326 EXPECT_EQ(Args::GetShellSafeArgument(zsh, R"('";()<>&|\)"), 327 R"(\'\"\;\(\)\<\>\&\|\\)"); 328 // Normal characters and expressions that shouldn't be escaped. 329 EXPECT_EQ(Args::GetShellSafeArgument(zsh, "aA$1*"), "aA$1*"); 330 331 // String that doesn't need to be escaped 332 EXPECT_EQ(Args::GetShellSafeArgument(bash, "a"), "a"); 333 334 // Try escaping with tcsh and the tcsh-specific "$" escape. 335 FileSpec tcsh("/bin/tcsh", FileSpec::Style::posix); 336 EXPECT_EQ(Args::GetShellSafeArgument(tcsh, "a$b"), "a\\$b"); 337 // Bash however doesn't need escaping for "$". 338 EXPECT_EQ(Args::GetShellSafeArgument(bash, "a$b"), "a$b"); 339 340 // Try escaping with an unknown shell. 341 FileSpec unknown_shell("/bin/unknown_shell", FileSpec::Style::posix); 342 EXPECT_EQ(Args::GetShellSafeArgument(unknown_shell, "a'b"), "a\\'b"); 343 EXPECT_EQ(Args::GetShellSafeArgument(unknown_shell, "a\"b"), "a\\\"b"); 344 } 345