command_line_unittest.cc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/command_line.h"
  5. #include <memory>
  6. #include <string>
  7. #include <vector>
  8. #include "base/files/file_path.h"
  9. #include "base/strings/strcat.h"
  10. #include "base/strings/utf_string_conversions.h"
  11. #include "build/build_config.h"
  12. #include "testing/gmock/include/gmock/gmock.h"
  13. #include "testing/gtest/include/gtest/gtest.h"
  14. namespace base {
  15. // To test Windows quoting behavior, we use a string that has some backslashes
  16. // and quotes.
  17. // Consider the command-line argument: q\"bs1\bs2\\bs3q\\\"
  18. // Here it is with C-style escapes.
  19. static const CommandLine::StringType kTrickyQuoted =
  20. FILE_PATH_LITERAL("q\\\"bs1\\bs2\\\\bs3q\\\\\\\"");
  21. // It should be parsed by Windows as: q"bs1\bs2\\bs3q\"
  22. // Here that is with C-style escapes.
  23. static const CommandLine::StringType kTricky =
  24. FILE_PATH_LITERAL("q\"bs1\\bs2\\\\bs3q\\\"");
  25. TEST(CommandLineTest, CommandLineConstructor) {
  26. const CommandLine::CharType* argv[] = {
  27. FILE_PATH_LITERAL("program"),
  28. FILE_PATH_LITERAL("--foo="),
  29. FILE_PATH_LITERAL("-bAr"),
  30. FILE_PATH_LITERAL("-spaetzel=pierogi"),
  31. FILE_PATH_LITERAL("-baz"),
  32. FILE_PATH_LITERAL("flim"),
  33. FILE_PATH_LITERAL("--other-switches=--dog=canine --cat=feline"),
  34. FILE_PATH_LITERAL("-spaetzle=Crepe"),
  35. FILE_PATH_LITERAL("-=loosevalue"),
  36. FILE_PATH_LITERAL("-"),
  37. FILE_PATH_LITERAL("FLAN"),
  38. FILE_PATH_LITERAL("a"),
  39. FILE_PATH_LITERAL("--input-translation=45--output-rotation"),
  40. FILE_PATH_LITERAL("--"),
  41. FILE_PATH_LITERAL("--"),
  42. FILE_PATH_LITERAL("--not-a-switch"),
  43. FILE_PATH_LITERAL("\"in the time of submarines...\""),
  44. FILE_PATH_LITERAL("unquoted arg-with-space")};
  45. CommandLine cl(std::size(argv), argv);
  46. EXPECT_FALSE(cl.GetCommandLineString().empty());
  47. EXPECT_FALSE(cl.HasSwitch("cruller"));
  48. EXPECT_FALSE(cl.HasSwitch("flim"));
  49. EXPECT_FALSE(cl.HasSwitch("program"));
  50. EXPECT_FALSE(cl.HasSwitch("dog"));
  51. EXPECT_FALSE(cl.HasSwitch("cat"));
  52. EXPECT_FALSE(cl.HasSwitch("output-rotation"));
  53. EXPECT_FALSE(cl.HasSwitch("not-a-switch"));
  54. EXPECT_FALSE(cl.HasSwitch("--"));
  55. EXPECT_EQ(FilePath(FILE_PATH_LITERAL("program")).value(),
  56. cl.GetProgram().value());
  57. EXPECT_TRUE(cl.HasSwitch("foo"));
  58. #if BUILDFLAG(IS_WIN)
  59. EXPECT_TRUE(cl.HasSwitch("bar"));
  60. #else
  61. EXPECT_FALSE(cl.HasSwitch("bar"));
  62. #endif
  63. EXPECT_TRUE(cl.HasSwitch("baz"));
  64. EXPECT_TRUE(cl.HasSwitch("spaetzle"));
  65. EXPECT_TRUE(cl.HasSwitch("other-switches"));
  66. EXPECT_TRUE(cl.HasSwitch("input-translation"));
  67. EXPECT_EQ("Crepe", cl.GetSwitchValueASCII("spaetzle"));
  68. EXPECT_EQ("", cl.GetSwitchValueASCII("foo"));
  69. EXPECT_EQ("", cl.GetSwitchValueASCII("bar"));
  70. EXPECT_EQ("", cl.GetSwitchValueASCII("cruller"));
  71. EXPECT_EQ("--dog=canine --cat=feline", cl.GetSwitchValueASCII(
  72. "other-switches"));
  73. EXPECT_EQ("45--output-rotation", cl.GetSwitchValueASCII("input-translation"));
  74. const CommandLine::StringVector& args = cl.GetArgs();
  75. ASSERT_EQ(8U, args.size());
  76. auto iter = args.begin();
  77. EXPECT_EQ(FILE_PATH_LITERAL("flim"), *iter);
  78. ++iter;
  79. EXPECT_EQ(FILE_PATH_LITERAL("-"), *iter);
  80. ++iter;
  81. EXPECT_EQ(FILE_PATH_LITERAL("FLAN"), *iter);
  82. ++iter;
  83. EXPECT_EQ(FILE_PATH_LITERAL("a"), *iter);
  84. ++iter;
  85. EXPECT_EQ(FILE_PATH_LITERAL("--"), *iter);
  86. ++iter;
  87. EXPECT_EQ(FILE_PATH_LITERAL("--not-a-switch"), *iter);
  88. ++iter;
  89. EXPECT_EQ(FILE_PATH_LITERAL("\"in the time of submarines...\""), *iter);
  90. ++iter;
  91. EXPECT_EQ(FILE_PATH_LITERAL("unquoted arg-with-space"), *iter);
  92. ++iter;
  93. EXPECT_TRUE(iter == args.end());
  94. }
  95. TEST(CommandLineTest, CommandLineFromString) {
  96. #if BUILDFLAG(IS_WIN)
  97. CommandLine cl = CommandLine::FromString(
  98. L"program --foo= -bAr /Spaetzel=pierogi /Baz flim "
  99. L"--other-switches=\"--dog=canine --cat=feline\" "
  100. L"-spaetzle=Crepe -=loosevalue FLAN "
  101. L"--input-translation=\"45\"--output-rotation "
  102. L"--quotes=" +
  103. kTrickyQuoted +
  104. L" -- -- --not-a-switch \"in the time of submarines...\"");
  105. EXPECT_FALSE(cl.GetCommandLineString().empty());
  106. EXPECT_FALSE(cl.HasSwitch("cruller"));
  107. EXPECT_FALSE(cl.HasSwitch("flim"));
  108. EXPECT_FALSE(cl.HasSwitch("program"));
  109. EXPECT_FALSE(cl.HasSwitch("dog"));
  110. EXPECT_FALSE(cl.HasSwitch("cat"));
  111. EXPECT_FALSE(cl.HasSwitch("output-rotation"));
  112. EXPECT_FALSE(cl.HasSwitch("not-a-switch"));
  113. EXPECT_FALSE(cl.HasSwitch("--"));
  114. EXPECT_EQ(FilePath(FILE_PATH_LITERAL("program")).value(),
  115. cl.GetProgram().value());
  116. EXPECT_TRUE(cl.HasSwitch("foo"));
  117. EXPECT_TRUE(cl.HasSwitch("bar"));
  118. EXPECT_TRUE(cl.HasSwitch("baz"));
  119. EXPECT_TRUE(cl.HasSwitch("spaetzle"));
  120. EXPECT_TRUE(cl.HasSwitch("other-switches"));
  121. EXPECT_TRUE(cl.HasSwitch("input-translation"));
  122. EXPECT_TRUE(cl.HasSwitch("quotes"));
  123. EXPECT_EQ("Crepe", cl.GetSwitchValueASCII("spaetzle"));
  124. EXPECT_EQ("", cl.GetSwitchValueASCII("foo"));
  125. EXPECT_EQ("", cl.GetSwitchValueASCII("bar"));
  126. EXPECT_EQ("", cl.GetSwitchValueASCII("cruller"));
  127. EXPECT_EQ("--dog=canine --cat=feline", cl.GetSwitchValueASCII(
  128. "other-switches"));
  129. EXPECT_EQ("45--output-rotation", cl.GetSwitchValueASCII("input-translation"));
  130. EXPECT_EQ(kTricky, cl.GetSwitchValueNative("quotes"));
  131. const CommandLine::StringVector& args = cl.GetArgs();
  132. ASSERT_EQ(5U, args.size());
  133. std::vector<CommandLine::StringType>::const_iterator iter = args.begin();
  134. EXPECT_EQ(FILE_PATH_LITERAL("flim"), *iter);
  135. ++iter;
  136. EXPECT_EQ(FILE_PATH_LITERAL("FLAN"), *iter);
  137. ++iter;
  138. EXPECT_EQ(FILE_PATH_LITERAL("--"), *iter);
  139. ++iter;
  140. EXPECT_EQ(FILE_PATH_LITERAL("--not-a-switch"), *iter);
  141. ++iter;
  142. EXPECT_EQ(FILE_PATH_LITERAL("in the time of submarines..."), *iter);
  143. ++iter;
  144. EXPECT_TRUE(iter == args.end());
  145. // Check that a generated string produces an equivalent command line.
  146. CommandLine cl_duplicate = CommandLine::FromString(cl.GetCommandLineString());
  147. EXPECT_EQ(cl.GetCommandLineString(), cl_duplicate.GetCommandLineString());
  148. #endif
  149. }
  150. // Tests behavior with an empty input string.
  151. TEST(CommandLineTest, EmptyString) {
  152. #if BUILDFLAG(IS_WIN)
  153. CommandLine cl_from_string = CommandLine::FromString(std::wstring());
  154. EXPECT_TRUE(cl_from_string.GetCommandLineString().empty());
  155. EXPECT_TRUE(cl_from_string.GetProgram().empty());
  156. EXPECT_EQ(1U, cl_from_string.argv().size());
  157. EXPECT_TRUE(cl_from_string.GetArgs().empty());
  158. #endif
  159. CommandLine cl_from_argv(0, nullptr);
  160. EXPECT_TRUE(cl_from_argv.GetCommandLineString().empty());
  161. EXPECT_TRUE(cl_from_argv.GetProgram().empty());
  162. EXPECT_EQ(1U, cl_from_argv.argv().size());
  163. EXPECT_TRUE(cl_from_argv.GetArgs().empty());
  164. }
  165. TEST(CommandLineTest, GetArgumentsString) {
  166. static const FilePath::CharType kPath1[] =
  167. FILE_PATH_LITERAL("C:\\Some File\\With Spaces.ggg");
  168. static const FilePath::CharType kPath2[] =
  169. FILE_PATH_LITERAL("C:\\no\\spaces.ggg");
  170. static const char kFirstArgName[] = "first-arg";
  171. static const char kSecondArgName[] = "arg2";
  172. static const char kThirdArgName[] = "arg with space";
  173. static const char kFourthArgName[] = "nospace";
  174. CommandLine cl(CommandLine::NO_PROGRAM);
  175. cl.AppendSwitchPath(kFirstArgName, FilePath(kPath1));
  176. cl.AppendSwitchPath(kSecondArgName, FilePath(kPath2));
  177. cl.AppendArg(kThirdArgName);
  178. cl.AppendArg(kFourthArgName);
  179. #if BUILDFLAG(IS_WIN)
  180. CommandLine::StringType expected_first_arg(UTF8ToWide(kFirstArgName));
  181. CommandLine::StringType expected_second_arg(UTF8ToWide(kSecondArgName));
  182. CommandLine::StringType expected_third_arg(UTF8ToWide(kThirdArgName));
  183. CommandLine::StringType expected_fourth_arg(UTF8ToWide(kFourthArgName));
  184. #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
  185. CommandLine::StringType expected_first_arg(kFirstArgName);
  186. CommandLine::StringType expected_second_arg(kSecondArgName);
  187. CommandLine::StringType expected_third_arg(kThirdArgName);
  188. CommandLine::StringType expected_fourth_arg(kFourthArgName);
  189. #endif
  190. #if BUILDFLAG(IS_WIN)
  191. #define QUOTE_ON_WIN FILE_PATH_LITERAL("\"")
  192. #else
  193. #define QUOTE_ON_WIN FILE_PATH_LITERAL("")
  194. #endif // BUILDFLAG(IS_WIN)
  195. CommandLine::StringType expected_str;
  196. expected_str.append(FILE_PATH_LITERAL("--"))
  197. .append(expected_first_arg)
  198. .append(FILE_PATH_LITERAL("="))
  199. .append(QUOTE_ON_WIN)
  200. .append(kPath1)
  201. .append(QUOTE_ON_WIN)
  202. .append(FILE_PATH_LITERAL(" "))
  203. .append(FILE_PATH_LITERAL("--"))
  204. .append(expected_second_arg)
  205. .append(FILE_PATH_LITERAL("="))
  206. .append(QUOTE_ON_WIN)
  207. .append(kPath2)
  208. .append(QUOTE_ON_WIN)
  209. .append(FILE_PATH_LITERAL(" "))
  210. .append(QUOTE_ON_WIN)
  211. .append(expected_third_arg)
  212. .append(QUOTE_ON_WIN)
  213. .append(FILE_PATH_LITERAL(" "))
  214. .append(expected_fourth_arg);
  215. EXPECT_EQ(expected_str, cl.GetArgumentsString());
  216. }
  217. // Test methods for appending switches to a command line.
  218. TEST(CommandLineTest, AppendSwitches) {
  219. std::string switch1 = "switch1";
  220. std::string switch2 = "switch2";
  221. std::string value2 = "value";
  222. std::string switch3 = "switch3";
  223. std::string value3 = "a value with spaces";
  224. std::string switch4 = "switch4";
  225. std::string value4 = "\"a value with quotes\"";
  226. std::string switch5 = "quotes";
  227. CommandLine::StringType value5 = kTricky;
  228. CommandLine cl(FilePath(FILE_PATH_LITERAL("Program")));
  229. cl.AppendSwitch(switch1);
  230. cl.AppendSwitchASCII(switch2, value2);
  231. cl.AppendSwitchASCII(switch3, value3);
  232. cl.AppendSwitchASCII(switch4, value4);
  233. cl.AppendSwitchASCII(switch5, value4);
  234. cl.AppendSwitchNative(switch5, value5);
  235. EXPECT_TRUE(cl.HasSwitch(switch1));
  236. EXPECT_TRUE(cl.HasSwitch(switch2));
  237. EXPECT_EQ(value2, cl.GetSwitchValueASCII(switch2));
  238. EXPECT_TRUE(cl.HasSwitch(switch3));
  239. EXPECT_EQ(value3, cl.GetSwitchValueASCII(switch3));
  240. EXPECT_TRUE(cl.HasSwitch(switch4));
  241. EXPECT_EQ(value4, cl.GetSwitchValueASCII(switch4));
  242. EXPECT_TRUE(cl.HasSwitch(switch5));
  243. EXPECT_EQ(value5, cl.GetSwitchValueNative(switch5));
  244. #if BUILDFLAG(IS_WIN)
  245. EXPECT_EQ(
  246. L"Program "
  247. L"--switch1 "
  248. L"--switch2=value "
  249. L"--switch3=\"a value with spaces\" "
  250. L"--switch4=\"\\\"a value with quotes\\\"\" "
  251. // Even though the switches are unique, appending can add repeat
  252. // switches to argv.
  253. L"--quotes=\"\\\"a value with quotes\\\"\" "
  254. L"--quotes=\"" +
  255. kTrickyQuoted + L"\"",
  256. cl.GetCommandLineString());
  257. #endif
  258. }
  259. TEST(CommandLineTest, AppendSwitchesDashDash) {
  260. const CommandLine::CharType* raw_argv[] = { FILE_PATH_LITERAL("prog"),
  261. FILE_PATH_LITERAL("--"),
  262. FILE_PATH_LITERAL("--arg1") };
  263. CommandLine cl(std::size(raw_argv), raw_argv);
  264. cl.AppendSwitch("switch1");
  265. cl.AppendSwitchASCII("switch2", "foo");
  266. cl.AppendArg("--arg2");
  267. EXPECT_EQ(FILE_PATH_LITERAL("prog --switch1 --switch2=foo -- --arg1 --arg2"),
  268. cl.GetCommandLineString());
  269. CommandLine::StringVector cl_argv = cl.argv();
  270. EXPECT_EQ(FILE_PATH_LITERAL("prog"), cl_argv[0]);
  271. EXPECT_EQ(FILE_PATH_LITERAL("--switch1"), cl_argv[1]);
  272. EXPECT_EQ(FILE_PATH_LITERAL("--switch2=foo"), cl_argv[2]);
  273. EXPECT_EQ(FILE_PATH_LITERAL("--"), cl_argv[3]);
  274. EXPECT_EQ(FILE_PATH_LITERAL("--arg1"), cl_argv[4]);
  275. EXPECT_EQ(FILE_PATH_LITERAL("--arg2"), cl_argv[5]);
  276. }
  277. #if BUILDFLAG(IS_WIN)
  278. TEST(CommandLineTest, GetCommandLineStringForShell) {
  279. CommandLine cl = CommandLine::FromString(
  280. FILE_PATH_LITERAL("program --switch /switch2 --"));
  281. EXPECT_EQ(
  282. cl.GetCommandLineStringForShell(),
  283. FILE_PATH_LITERAL("program --switch /switch2 -- --single-argument %1"));
  284. }
  285. TEST(CommandLineTest, GetCommandLineStringWithUnsafeInsertSequences) {
  286. CommandLine cl(FilePath(FILE_PATH_LITERAL("program")));
  287. cl.AppendSwitchASCII("switch", "%1");
  288. cl.AppendSwitch("%2");
  289. cl.AppendArg("%3");
  290. EXPECT_EQ(FILE_PATH_LITERAL("program --switch=%1 --%2 %3"),
  291. cl.GetCommandLineStringWithUnsafeInsertSequences());
  292. }
  293. #endif // BUILDFLAG(IS_WIN)
  294. // Tests that when AppendArguments is called that the program is set correctly
  295. // on the target CommandLine object and the switches from the source
  296. // CommandLine are added to the target.
  297. TEST(CommandLineTest, AppendArguments) {
  298. CommandLine cl1(FilePath(FILE_PATH_LITERAL("Program")));
  299. cl1.AppendSwitch("switch1");
  300. cl1.AppendSwitchASCII("switch2", "foo");
  301. CommandLine cl2(CommandLine::NO_PROGRAM);
  302. cl2.AppendArguments(cl1, true);
  303. EXPECT_EQ(cl1.GetProgram().value(), cl2.GetProgram().value());
  304. EXPECT_EQ(cl1.GetCommandLineString(), cl2.GetCommandLineString());
  305. CommandLine c1(FilePath(FILE_PATH_LITERAL("Program1")));
  306. c1.AppendSwitch("switch1");
  307. CommandLine c2(FilePath(FILE_PATH_LITERAL("Program2")));
  308. c2.AppendSwitch("switch2");
  309. c1.AppendArguments(c2, true);
  310. EXPECT_EQ(c1.GetProgram().value(), c2.GetProgram().value());
  311. EXPECT_TRUE(c1.HasSwitch("switch1"));
  312. EXPECT_TRUE(c1.HasSwitch("switch2"));
  313. }
  314. #if BUILDFLAG(IS_WIN)
  315. // Make sure that the command line string program paths are quoted as necessary.
  316. // This only makes sense on Windows and the test is basically here to guard
  317. // against regressions.
  318. TEST(CommandLineTest, ProgramQuotes) {
  319. // Check that quotes are not added for paths without spaces.
  320. const FilePath kProgram(L"Program");
  321. CommandLine cl_program(kProgram);
  322. EXPECT_EQ(kProgram.value(), cl_program.GetProgram().value());
  323. EXPECT_EQ(kProgram.value(), cl_program.GetCommandLineString());
  324. const FilePath kProgramPath(L"Program Path");
  325. // Check that quotes are not returned from GetProgram().
  326. CommandLine cl_program_path(kProgramPath);
  327. EXPECT_EQ(kProgramPath.value(), cl_program_path.GetProgram().value());
  328. // Check that quotes are added to command line string paths containing spaces.
  329. CommandLine::StringType cmd_string(cl_program_path.GetCommandLineString());
  330. EXPECT_EQ(L"\"Program Path\"", cmd_string);
  331. }
  332. #endif
  333. // Calling Init multiple times should not modify the previous CommandLine.
  334. TEST(CommandLineTest, Init) {
  335. // Call Init without checking output once so we know it's been called
  336. // whether or not the test runner does so.
  337. CommandLine::Init(0, nullptr);
  338. CommandLine* initial = CommandLine::ForCurrentProcess();
  339. EXPECT_FALSE(CommandLine::Init(0, nullptr));
  340. CommandLine* current = CommandLine::ForCurrentProcess();
  341. EXPECT_EQ(initial, current);
  342. }
  343. // Test that copies of CommandLine have a valid StringPiece map.
  344. TEST(CommandLineTest, Copy) {
  345. std::unique_ptr<CommandLine> initial(
  346. new CommandLine(CommandLine::NO_PROGRAM));
  347. initial->AppendSwitch("a");
  348. initial->AppendSwitch("bbbbbbbbbbbbbbb");
  349. initial->AppendSwitch("c");
  350. CommandLine copy_constructed(*initial);
  351. CommandLine assigned = *initial;
  352. CommandLine::SwitchMap switch_map = initial->GetSwitches();
  353. initial.reset();
  354. for (const auto& pair : switch_map)
  355. EXPECT_TRUE(copy_constructed.HasSwitch(pair.first));
  356. for (const auto& pair : switch_map)
  357. EXPECT_TRUE(assigned.HasSwitch(pair.first));
  358. }
  359. TEST(CommandLineTest, PrependSimpleWrapper) {
  360. CommandLine cl(FilePath(FILE_PATH_LITERAL("Program")));
  361. cl.AppendSwitch("a");
  362. cl.AppendSwitch("b");
  363. cl.PrependWrapper(FILE_PATH_LITERAL("wrapper --foo --bar"));
  364. EXPECT_EQ(6u, cl.argv().size());
  365. EXPECT_EQ(FILE_PATH_LITERAL("wrapper"), cl.argv()[0]);
  366. EXPECT_EQ(FILE_PATH_LITERAL("--foo"), cl.argv()[1]);
  367. EXPECT_EQ(FILE_PATH_LITERAL("--bar"), cl.argv()[2]);
  368. EXPECT_EQ(FILE_PATH_LITERAL("Program"), cl.argv()[3]);
  369. EXPECT_EQ(FILE_PATH_LITERAL("--a"), cl.argv()[4]);
  370. EXPECT_EQ(FILE_PATH_LITERAL("--b"), cl.argv()[5]);
  371. }
  372. TEST(CommandLineTest, PrependComplexWrapper) {
  373. CommandLine cl(FilePath(FILE_PATH_LITERAL("Program")));
  374. cl.AppendSwitch("a");
  375. cl.AppendSwitch("b");
  376. cl.PrependWrapper(
  377. FILE_PATH_LITERAL("wrapper --foo='hello world' --bar=\"let's go\""));
  378. EXPECT_EQ(6u, cl.argv().size());
  379. EXPECT_EQ(FILE_PATH_LITERAL("wrapper"), cl.argv()[0]);
  380. EXPECT_EQ(FILE_PATH_LITERAL("--foo='hello world'"), cl.argv()[1]);
  381. EXPECT_EQ(FILE_PATH_LITERAL("--bar=\"let's go\""), cl.argv()[2]);
  382. EXPECT_EQ(FILE_PATH_LITERAL("Program"), cl.argv()[3]);
  383. EXPECT_EQ(FILE_PATH_LITERAL("--a"), cl.argv()[4]);
  384. EXPECT_EQ(FILE_PATH_LITERAL("--b"), cl.argv()[5]);
  385. }
  386. TEST(CommandLineTest, RemoveSwitch) {
  387. const std::string switch1 = "switch1";
  388. const std::string switch2 = "switch2";
  389. const std::string value2 = "value";
  390. CommandLine cl(FilePath(FILE_PATH_LITERAL("Program")));
  391. cl.AppendSwitch(switch1);
  392. cl.AppendSwitchASCII(switch2, value2);
  393. EXPECT_TRUE(cl.HasSwitch(switch1));
  394. EXPECT_TRUE(cl.HasSwitch(switch2));
  395. EXPECT_EQ(value2, cl.GetSwitchValueASCII(switch2));
  396. EXPECT_THAT(cl.argv(),
  397. testing::ElementsAre(FILE_PATH_LITERAL("Program"),
  398. FILE_PATH_LITERAL("--switch1"),
  399. FILE_PATH_LITERAL("--switch2=value")));
  400. cl.RemoveSwitch(switch1);
  401. EXPECT_FALSE(cl.HasSwitch(switch1));
  402. EXPECT_TRUE(cl.HasSwitch(switch2));
  403. EXPECT_EQ(value2, cl.GetSwitchValueASCII(switch2));
  404. EXPECT_THAT(cl.argv(),
  405. testing::ElementsAre(FILE_PATH_LITERAL("Program"),
  406. FILE_PATH_LITERAL("--switch2=value")));
  407. }
  408. TEST(CommandLineTest, RemoveSwitchWithValue) {
  409. const std::string switch1 = "switch1";
  410. const std::string switch2 = "switch2";
  411. const std::string value2 = "value";
  412. CommandLine cl(FilePath(FILE_PATH_LITERAL("Program")));
  413. cl.AppendSwitch(switch1);
  414. cl.AppendSwitchASCII(switch2, value2);
  415. EXPECT_TRUE(cl.HasSwitch(switch1));
  416. EXPECT_TRUE(cl.HasSwitch(switch2));
  417. EXPECT_EQ(value2, cl.GetSwitchValueASCII(switch2));
  418. EXPECT_THAT(cl.argv(),
  419. testing::ElementsAre(FILE_PATH_LITERAL("Program"),
  420. FILE_PATH_LITERAL("--switch1"),
  421. FILE_PATH_LITERAL("--switch2=value")));
  422. cl.RemoveSwitch(switch2);
  423. EXPECT_TRUE(cl.HasSwitch(switch1));
  424. EXPECT_FALSE(cl.HasSwitch(switch2));
  425. EXPECT_THAT(cl.argv(), testing::ElementsAre(FILE_PATH_LITERAL("Program"),
  426. FILE_PATH_LITERAL("--switch1")));
  427. }
  428. TEST(CommandLineTest, RemoveSwitchDropsMultipleSameSwitches) {
  429. const std::string switch1 = "switch1";
  430. const std::string value2 = "value2";
  431. CommandLine cl(FilePath(FILE_PATH_LITERAL("Program")));
  432. cl.AppendSwitch(switch1);
  433. cl.AppendSwitchASCII(switch1, value2);
  434. EXPECT_TRUE(cl.HasSwitch(switch1));
  435. EXPECT_EQ(value2, cl.GetSwitchValueASCII(switch1));
  436. EXPECT_THAT(cl.argv(),
  437. testing::ElementsAre(FILE_PATH_LITERAL("Program"),
  438. FILE_PATH_LITERAL("--switch1"),
  439. FILE_PATH_LITERAL("--switch1=value2")));
  440. cl.RemoveSwitch(switch1);
  441. EXPECT_FALSE(cl.HasSwitch(switch1));
  442. EXPECT_THAT(cl.argv(), testing::ElementsAre(FILE_PATH_LITERAL("Program")));
  443. }
  444. TEST(CommandLineTest, AppendAndRemoveSwitchWithDefaultPrefix) {
  445. CommandLine cl(FilePath(FILE_PATH_LITERAL("Program")));
  446. cl.AppendSwitch("foo");
  447. EXPECT_THAT(cl.argv(), testing::ElementsAre(FILE_PATH_LITERAL("Program"),
  448. FILE_PATH_LITERAL("--foo")));
  449. EXPECT_EQ(0u, cl.GetArgs().size());
  450. cl.RemoveSwitch("foo");
  451. EXPECT_THAT(cl.argv(), testing::ElementsAre(FILE_PATH_LITERAL("Program")));
  452. EXPECT_EQ(0u, cl.GetArgs().size());
  453. }
  454. TEST(CommandLineTest, AppendAndRemoveSwitchWithAlternativePrefix) {
  455. CommandLine cl(FilePath(FILE_PATH_LITERAL("Program")));
  456. cl.AppendSwitch("-foo");
  457. EXPECT_THAT(cl.argv(), testing::ElementsAre(FILE_PATH_LITERAL("Program"),
  458. FILE_PATH_LITERAL("-foo")));
  459. EXPECT_EQ(0u, cl.GetArgs().size());
  460. cl.RemoveSwitch("foo");
  461. EXPECT_THAT(cl.argv(), testing::ElementsAre(FILE_PATH_LITERAL("Program")));
  462. EXPECT_EQ(0u, cl.GetArgs().size());
  463. }
  464. TEST(CommandLineTest, AppendAndRemoveSwitchPreservesOtherSwitchesAndArgs) {
  465. CommandLine cl(FilePath(FILE_PATH_LITERAL("Program")));
  466. cl.AppendSwitch("foo");
  467. cl.AppendSwitch("bar");
  468. cl.AppendArg("arg");
  469. EXPECT_THAT(cl.argv(), testing::ElementsAre(FILE_PATH_LITERAL("Program"),
  470. FILE_PATH_LITERAL("--foo"),
  471. FILE_PATH_LITERAL("--bar"),
  472. FILE_PATH_LITERAL("arg")));
  473. EXPECT_THAT(cl.GetArgs(), testing::ElementsAre(FILE_PATH_LITERAL("arg")));
  474. cl.RemoveSwitch("foo");
  475. EXPECT_THAT(cl.argv(), testing::ElementsAre(FILE_PATH_LITERAL("Program"),
  476. FILE_PATH_LITERAL("--bar"),
  477. FILE_PATH_LITERAL("arg")));
  478. EXPECT_THAT(cl.GetArgs(), testing::ElementsAre(FILE_PATH_LITERAL("arg")));
  479. }
  480. TEST(CommandLineTest, MultipleSameSwitch) {
  481. const CommandLine::CharType* argv[] = {
  482. FILE_PATH_LITERAL("program"),
  483. FILE_PATH_LITERAL("--foo=one"), // --foo first time
  484. FILE_PATH_LITERAL("-baz"),
  485. FILE_PATH_LITERAL("--foo=two") // --foo second time
  486. };
  487. CommandLine cl(std::size(argv), argv);
  488. EXPECT_TRUE(cl.HasSwitch("foo"));
  489. EXPECT_TRUE(cl.HasSwitch("baz"));
  490. EXPECT_EQ("two", cl.GetSwitchValueASCII("foo"));
  491. }
  492. // Helper class for the next test case
  493. class MergeDuplicateFoosSemicolon : public DuplicateSwitchHandler {
  494. public:
  495. ~MergeDuplicateFoosSemicolon() override;
  496. void ResolveDuplicate(base::StringPiece key,
  497. CommandLine::StringPieceType new_value,
  498. CommandLine::StringType& out_value) override;
  499. };
  500. MergeDuplicateFoosSemicolon::~MergeDuplicateFoosSemicolon() = default;
  501. void MergeDuplicateFoosSemicolon::ResolveDuplicate(
  502. base::StringPiece key,
  503. CommandLine::StringPieceType new_value,
  504. CommandLine::StringType& out_value) {
  505. if (key != "mergeable-foo") {
  506. out_value = CommandLine::StringType(new_value);
  507. return;
  508. }
  509. if (!out_value.empty()) {
  510. #if BUILDFLAG(IS_WIN)
  511. StrAppend(&out_value, {L";"});
  512. #else
  513. StrAppend(&out_value, {";"});
  514. #endif
  515. }
  516. StrAppend(&out_value, {new_value});
  517. }
  518. // This flag is an exception to the rule that the second duplicate flag wins
  519. // Not thread safe
  520. TEST(CommandLineTest, MultipleFilterFileSwitch) {
  521. const CommandLine::CharType* const argv[] = {
  522. FILE_PATH_LITERAL("program"),
  523. FILE_PATH_LITERAL("--mergeable-foo=one"), // --first time
  524. FILE_PATH_LITERAL("-baz"),
  525. FILE_PATH_LITERAL("--mergeable-foo=two") // --second time
  526. };
  527. CommandLine::SetDuplicateSwitchHandler(
  528. std::make_unique<MergeDuplicateFoosSemicolon>());
  529. CommandLine cl(std::size(argv), argv);
  530. EXPECT_TRUE(cl.HasSwitch("mergeable-foo"));
  531. EXPECT_TRUE(cl.HasSwitch("baz"));
  532. EXPECT_EQ("one;two", cl.GetSwitchValueASCII("mergeable-foo"));
  533. CommandLine::SetDuplicateSwitchHandler(nullptr);
  534. }
  535. #if BUILDFLAG(IS_WIN)
  536. TEST(CommandLineTest, ParseAsSingleArgument) {
  537. CommandLine cl = CommandLine::FromString(
  538. FILE_PATH_LITERAL("program --switch_before arg_before "
  539. "--single-argument arg with spaces \"and quotes\" \""));
  540. EXPECT_FALSE(cl.GetCommandLineString().empty());
  541. EXPECT_EQ(FilePath(FILE_PATH_LITERAL("program")), cl.GetProgram());
  542. EXPECT_TRUE(cl.HasSwitch("switch_before"));
  543. EXPECT_EQ(cl.GetArgs(), CommandLine::StringVector({FILE_PATH_LITERAL(
  544. "arg with spaces \"and quotes\" \"")}));
  545. CommandLine cl_without_arg =
  546. CommandLine::FromString(FILE_PATH_LITERAL("program --single-argument "));
  547. EXPECT_FALSE(cl_without_arg.GetCommandLineString().empty());
  548. EXPECT_EQ(FilePath(FILE_PATH_LITERAL("program")),
  549. cl_without_arg.GetProgram());
  550. EXPECT_TRUE(cl_without_arg.GetArgs().empty());
  551. }
  552. #endif // BUILDFLAG(IS_WIN)
  553. } // namespace base