Home | History | Annotate | Download | only in base
      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 
      5 #include <string>
      6 #include <vector>
      7 
      8 #include "base/basictypes.h"
      9 #include "base/command_line.h"
     10 #include "base/files/file_path.h"
     11 #include "base/strings/utf_string_conversions.h"
     12 #include "testing/gtest/include/gtest/gtest.h"
     13 
     14 using base::FilePath;
     15 
     16 // To test Windows quoting behavior, we use a string that has some backslashes
     17 // and quotes.
     18 // Consider the command-line argument: q\"bs1\bs2\\bs3q\\\"
     19 // Here it is with C-style escapes.
     20 static const CommandLine::StringType kTrickyQuoted =
     21     FILE_PATH_LITERAL("q\\\"bs1\\bs2\\\\bs3q\\\\\\\"");
     22 // It should be parsed by Windows as: q"bs1\bs2\\bs3q\"
     23 // Here that is with C-style escapes.
     24 static const CommandLine::StringType kTricky =
     25     FILE_PATH_LITERAL("q\"bs1\\bs2\\\\bs3q\\\"");
     26 
     27 TEST(CommandLineTest, CommandLineConstructor) {
     28   const CommandLine::CharType* argv[] = {
     29       FILE_PATH_LITERAL("program"),
     30       FILE_PATH_LITERAL("--foo="),
     31       FILE_PATH_LITERAL("-bAr"),
     32       FILE_PATH_LITERAL("-spaetzel=pierogi"),
     33       FILE_PATH_LITERAL("-baz"),
     34       FILE_PATH_LITERAL("flim"),
     35       FILE_PATH_LITERAL("--other-switches=--dog=canine --cat=feline"),
     36       FILE_PATH_LITERAL("-spaetzle=Crepe"),
     37       FILE_PATH_LITERAL("-=loosevalue"),
     38       FILE_PATH_LITERAL("-"),
     39       FILE_PATH_LITERAL("FLAN"),
     40       FILE_PATH_LITERAL("a"),
     41       FILE_PATH_LITERAL("--input-translation=45--output-rotation"),
     42       FILE_PATH_LITERAL("--"),
     43       FILE_PATH_LITERAL("--"),
     44       FILE_PATH_LITERAL("--not-a-switch"),
     45       FILE_PATH_LITERAL("\"in the time of submarines...\""),
     46       FILE_PATH_LITERAL("unquoted arg-with-space")};
     47   CommandLine cl(arraysize(argv), argv);
     48 
     49   EXPECT_FALSE(cl.GetCommandLineString().empty());
     50   EXPECT_FALSE(cl.HasSwitch("cruller"));
     51   EXPECT_FALSE(cl.HasSwitch("flim"));
     52   EXPECT_FALSE(cl.HasSwitch("program"));
     53   EXPECT_FALSE(cl.HasSwitch("dog"));
     54   EXPECT_FALSE(cl.HasSwitch("cat"));
     55   EXPECT_FALSE(cl.HasSwitch("output-rotation"));
     56   EXPECT_FALSE(cl.HasSwitch("not-a-switch"));
     57   EXPECT_FALSE(cl.HasSwitch("--"));
     58 
     59   EXPECT_EQ(FilePath(FILE_PATH_LITERAL("program")).value(),
     60             cl.GetProgram().value());
     61 
     62   EXPECT_TRUE(cl.HasSwitch("foo"));
     63   EXPECT_TRUE(cl.HasSwitch("bAr"));
     64   EXPECT_TRUE(cl.HasSwitch("baz"));
     65   EXPECT_TRUE(cl.HasSwitch("spaetzle"));
     66 #if defined(OS_WIN)
     67   EXPECT_TRUE(cl.HasSwitch("SPAETZLE"));
     68 #endif
     69   EXPECT_TRUE(cl.HasSwitch("other-switches"));
     70   EXPECT_TRUE(cl.HasSwitch("input-translation"));
     71 
     72   EXPECT_EQ("Crepe", cl.GetSwitchValueASCII("spaetzle"));
     73   EXPECT_EQ("", cl.GetSwitchValueASCII("Foo"));
     74   EXPECT_EQ("", cl.GetSwitchValueASCII("bar"));
     75   EXPECT_EQ("", cl.GetSwitchValueASCII("cruller"));
     76   EXPECT_EQ("--dog=canine --cat=feline", cl.GetSwitchValueASCII(
     77       "other-switches"));
     78   EXPECT_EQ("45--output-rotation", cl.GetSwitchValueASCII("input-translation"));
     79 
     80   const CommandLine::StringVector& args = cl.GetArgs();
     81   ASSERT_EQ(8U, args.size());
     82 
     83   std::vector<CommandLine::StringType>::const_iterator iter = args.begin();
     84   EXPECT_EQ(FILE_PATH_LITERAL("flim"), *iter);
     85   ++iter;
     86   EXPECT_EQ(FILE_PATH_LITERAL("-"), *iter);
     87   ++iter;
     88   EXPECT_EQ(FILE_PATH_LITERAL("FLAN"), *iter);
     89   ++iter;
     90   EXPECT_EQ(FILE_PATH_LITERAL("a"), *iter);
     91   ++iter;
     92   EXPECT_EQ(FILE_PATH_LITERAL("--"), *iter);
     93   ++iter;
     94   EXPECT_EQ(FILE_PATH_LITERAL("--not-a-switch"), *iter);
     95   ++iter;
     96   EXPECT_EQ(FILE_PATH_LITERAL("\"in the time of submarines...\""), *iter);
     97   ++iter;
     98   EXPECT_EQ(FILE_PATH_LITERAL("unquoted arg-with-space"), *iter);
     99   ++iter;
    100   EXPECT_TRUE(iter == args.end());
    101 }
    102 
    103 TEST(CommandLineTest, CommandLineFromString) {
    104 #if defined(OS_WIN)
    105   CommandLine cl = CommandLine::FromString(
    106       L"program --foo= -bAr  /Spaetzel=pierogi /Baz flim "
    107       L"--other-switches=\"--dog=canine --cat=feline\" "
    108       L"-spaetzle=Crepe   -=loosevalue  FLAN "
    109       L"--input-translation=\"45\"--output-rotation "
    110       L"--quotes=" + kTrickyQuoted + L" "
    111       L"-- -- --not-a-switch "
    112       L"\"in the time of submarines...\"");
    113 
    114   EXPECT_FALSE(cl.GetCommandLineString().empty());
    115   EXPECT_FALSE(cl.HasSwitch("cruller"));
    116   EXPECT_FALSE(cl.HasSwitch("flim"));
    117   EXPECT_FALSE(cl.HasSwitch("program"));
    118   EXPECT_FALSE(cl.HasSwitch("dog"));
    119   EXPECT_FALSE(cl.HasSwitch("cat"));
    120   EXPECT_FALSE(cl.HasSwitch("output-rotation"));
    121   EXPECT_FALSE(cl.HasSwitch("not-a-switch"));
    122   EXPECT_FALSE(cl.HasSwitch("--"));
    123 
    124   EXPECT_EQ(FilePath(FILE_PATH_LITERAL("program")).value(),
    125             cl.GetProgram().value());
    126 
    127   EXPECT_TRUE(cl.HasSwitch("foo"));
    128   EXPECT_TRUE(cl.HasSwitch("bar"));
    129   EXPECT_TRUE(cl.HasSwitch("baz"));
    130   EXPECT_TRUE(cl.HasSwitch("spaetzle"));
    131   EXPECT_TRUE(cl.HasSwitch("SPAETZLE"));
    132   EXPECT_TRUE(cl.HasSwitch("other-switches"));
    133   EXPECT_TRUE(cl.HasSwitch("input-translation"));
    134   EXPECT_TRUE(cl.HasSwitch("quotes"));
    135 
    136   EXPECT_EQ("Crepe", cl.GetSwitchValueASCII("spaetzle"));
    137   EXPECT_EQ("", cl.GetSwitchValueASCII("Foo"));
    138   EXPECT_EQ("", cl.GetSwitchValueASCII("bar"));
    139   EXPECT_EQ("", cl.GetSwitchValueASCII("cruller"));
    140   EXPECT_EQ("--dog=canine --cat=feline", cl.GetSwitchValueASCII(
    141       "other-switches"));
    142   EXPECT_EQ("45--output-rotation", cl.GetSwitchValueASCII("input-translation"));
    143   EXPECT_EQ(kTricky, cl.GetSwitchValueNative("quotes"));
    144 
    145   const CommandLine::StringVector& args = cl.GetArgs();
    146   ASSERT_EQ(5U, args.size());
    147 
    148   std::vector<CommandLine::StringType>::const_iterator iter = args.begin();
    149   EXPECT_EQ(FILE_PATH_LITERAL("flim"), *iter);
    150   ++iter;
    151   EXPECT_EQ(FILE_PATH_LITERAL("FLAN"), *iter);
    152   ++iter;
    153   EXPECT_EQ(FILE_PATH_LITERAL("--"), *iter);
    154   ++iter;
    155   EXPECT_EQ(FILE_PATH_LITERAL("--not-a-switch"), *iter);
    156   ++iter;
    157   EXPECT_EQ(FILE_PATH_LITERAL("in the time of submarines..."), *iter);
    158   ++iter;
    159   EXPECT_TRUE(iter == args.end());
    160 
    161   // Check that a generated string produces an equivalent command line.
    162   CommandLine cl_duplicate = CommandLine::FromString(cl.GetCommandLineString());
    163   EXPECT_EQ(cl.GetCommandLineString(), cl_duplicate.GetCommandLineString());
    164 #endif
    165 }
    166 
    167 // Tests behavior with an empty input string.
    168 TEST(CommandLineTest, EmptyString) {
    169 #if defined(OS_WIN)
    170   CommandLine cl_from_string = CommandLine::FromString(L"");
    171   EXPECT_TRUE(cl_from_string.GetCommandLineString().empty());
    172   EXPECT_TRUE(cl_from_string.GetProgram().empty());
    173   EXPECT_EQ(1U, cl_from_string.argv().size());
    174   EXPECT_TRUE(cl_from_string.GetArgs().empty());
    175 #endif
    176   CommandLine cl_from_argv(0, NULL);
    177   EXPECT_TRUE(cl_from_argv.GetCommandLineString().empty());
    178   EXPECT_TRUE(cl_from_argv.GetProgram().empty());
    179   EXPECT_EQ(1U, cl_from_argv.argv().size());
    180   EXPECT_TRUE(cl_from_argv.GetArgs().empty());
    181 }
    182 
    183 TEST(CommandLineTest, GetArgumentsString) {
    184   static const FilePath::CharType kPath1[] =
    185       FILE_PATH_LITERAL("C:\\Some File\\With Spaces.ggg");
    186   static const FilePath::CharType kPath2[] =
    187       FILE_PATH_LITERAL("C:\\no\\spaces.ggg");
    188 
    189   static const char kFirstArgName[] = "first-arg";
    190   static const char kSecondArgName[] = "arg2";
    191   static const char kThirdArgName[] = "arg with space";
    192   static const char kFourthArgName[] = "nospace";
    193 
    194   CommandLine cl(CommandLine::NO_PROGRAM);
    195   cl.AppendSwitchPath(kFirstArgName, FilePath(kPath1));
    196   cl.AppendSwitchPath(kSecondArgName, FilePath(kPath2));
    197   cl.AppendArg(kThirdArgName);
    198   cl.AppendArg(kFourthArgName);
    199 
    200 #if defined(OS_WIN)
    201   CommandLine::StringType expected_first_arg(
    202       base::UTF8ToUTF16(kFirstArgName));
    203   CommandLine::StringType expected_second_arg(
    204       base::UTF8ToUTF16(kSecondArgName));
    205   CommandLine::StringType expected_third_arg(
    206       base::UTF8ToUTF16(kThirdArgName));
    207   CommandLine::StringType expected_fourth_arg(
    208       base::UTF8ToUTF16(kFourthArgName));
    209 #elif defined(OS_POSIX)
    210   CommandLine::StringType expected_first_arg(kFirstArgName);
    211   CommandLine::StringType expected_second_arg(kSecondArgName);
    212   CommandLine::StringType expected_third_arg(kThirdArgName);
    213   CommandLine::StringType expected_fourth_arg(kFourthArgName);
    214 #endif
    215 
    216 #if defined(OS_WIN)
    217 #define QUOTE_ON_WIN FILE_PATH_LITERAL("\"")
    218 #else
    219 #define QUOTE_ON_WIN FILE_PATH_LITERAL("")
    220 #endif  // OS_WIN
    221 
    222   CommandLine::StringType expected_str;
    223   expected_str.append(FILE_PATH_LITERAL("--"))
    224               .append(expected_first_arg)
    225               .append(FILE_PATH_LITERAL("="))
    226               .append(QUOTE_ON_WIN)
    227               .append(kPath1)
    228               .append(QUOTE_ON_WIN)
    229               .append(FILE_PATH_LITERAL(" "))
    230               .append(FILE_PATH_LITERAL("--"))
    231               .append(expected_second_arg)
    232               .append(FILE_PATH_LITERAL("="))
    233               .append(QUOTE_ON_WIN)
    234               .append(kPath2)
    235               .append(QUOTE_ON_WIN)
    236               .append(FILE_PATH_LITERAL(" "))
    237               .append(QUOTE_ON_WIN)
    238               .append(expected_third_arg)
    239               .append(QUOTE_ON_WIN)
    240               .append(FILE_PATH_LITERAL(" "))
    241               .append(expected_fourth_arg);
    242   EXPECT_EQ(expected_str, cl.GetArgumentsString());
    243 }
    244 
    245 // Test methods for appending switches to a command line.
    246 TEST(CommandLineTest, AppendSwitches) {
    247   std::string switch1 = "switch1";
    248   std::string switch2 = "switch2";
    249   std::string value2 = "value";
    250   std::string switch3 = "switch3";
    251   std::string value3 = "a value with spaces";
    252   std::string switch4 = "switch4";
    253   std::string value4 = "\"a value with quotes\"";
    254   std::string switch5 = "quotes";
    255   CommandLine::StringType value5 = kTricky;
    256 
    257   CommandLine cl(FilePath(FILE_PATH_LITERAL("Program")));
    258 
    259   cl.AppendSwitch(switch1);
    260   cl.AppendSwitchASCII(switch2, value2);
    261   cl.AppendSwitchASCII(switch3, value3);
    262   cl.AppendSwitchASCII(switch4, value4);
    263   cl.AppendSwitchNative(switch5, value5);
    264 
    265   EXPECT_TRUE(cl.HasSwitch(switch1));
    266   EXPECT_TRUE(cl.HasSwitch(switch2));
    267   EXPECT_EQ(value2, cl.GetSwitchValueASCII(switch2));
    268   EXPECT_TRUE(cl.HasSwitch(switch3));
    269   EXPECT_EQ(value3, cl.GetSwitchValueASCII(switch3));
    270   EXPECT_TRUE(cl.HasSwitch(switch4));
    271   EXPECT_EQ(value4, cl.GetSwitchValueASCII(switch4));
    272   EXPECT_TRUE(cl.HasSwitch(switch5));
    273   EXPECT_EQ(value5, cl.GetSwitchValueNative(switch5));
    274 
    275 #if defined(OS_WIN)
    276   EXPECT_EQ(L"Program "
    277             L"--switch1 "
    278             L"--switch2=value "
    279             L"--switch3=\"a value with spaces\" "
    280             L"--switch4=\"\\\"a value with quotes\\\"\" "
    281             L"--quotes=\"" + kTrickyQuoted + L"\"",
    282             cl.GetCommandLineString());
    283 #endif
    284 }
    285 
    286 TEST(CommandLineTest, AppendSwitchesDashDash) {
    287  const CommandLine::CharType* raw_argv[] = { FILE_PATH_LITERAL("prog"),
    288                                              FILE_PATH_LITERAL("--"),
    289                                              FILE_PATH_LITERAL("--arg1") };
    290   CommandLine cl(arraysize(raw_argv), raw_argv);
    291 
    292   cl.AppendSwitch("switch1");
    293   cl.AppendSwitchASCII("switch2", "foo");
    294 
    295   cl.AppendArg("--arg2");
    296 
    297   EXPECT_EQ(FILE_PATH_LITERAL("prog --switch1 --switch2=foo -- --arg1 --arg2"),
    298             cl.GetCommandLineString());
    299   CommandLine::StringVector cl_argv = cl.argv();
    300   EXPECT_EQ(FILE_PATH_LITERAL("prog"), cl_argv[0]);
    301   EXPECT_EQ(FILE_PATH_LITERAL("--switch1"), cl_argv[1]);
    302   EXPECT_EQ(FILE_PATH_LITERAL("--switch2=foo"), cl_argv[2]);
    303   EXPECT_EQ(FILE_PATH_LITERAL("--"), cl_argv[3]);
    304   EXPECT_EQ(FILE_PATH_LITERAL("--arg1"), cl_argv[4]);
    305   EXPECT_EQ(FILE_PATH_LITERAL("--arg2"), cl_argv[5]);
    306 }
    307 
    308 // Tests that when AppendArguments is called that the program is set correctly
    309 // on the target CommandLine object and the switches from the source
    310 // CommandLine are added to the target.
    311 TEST(CommandLineTest, AppendArguments) {
    312   CommandLine cl1(FilePath(FILE_PATH_LITERAL("Program")));
    313   cl1.AppendSwitch("switch1");
    314   cl1.AppendSwitchASCII("switch2", "foo");
    315 
    316   CommandLine cl2(CommandLine::NO_PROGRAM);
    317   cl2.AppendArguments(cl1, true);
    318   EXPECT_EQ(cl1.GetProgram().value(), cl2.GetProgram().value());
    319   EXPECT_EQ(cl1.GetCommandLineString(), cl2.GetCommandLineString());
    320 
    321   CommandLine c1(FilePath(FILE_PATH_LITERAL("Program1")));
    322   c1.AppendSwitch("switch1");
    323   CommandLine c2(FilePath(FILE_PATH_LITERAL("Program2")));
    324   c2.AppendSwitch("switch2");
    325 
    326   c1.AppendArguments(c2, true);
    327   EXPECT_EQ(c1.GetProgram().value(), c2.GetProgram().value());
    328   EXPECT_TRUE(c1.HasSwitch("switch1"));
    329   EXPECT_TRUE(c1.HasSwitch("switch2"));
    330 }
    331 
    332 #if defined(OS_WIN)
    333 // Make sure that the command line string program paths are quoted as necessary.
    334 // This only makes sense on Windows and the test is basically here to guard
    335 // against regressions.
    336 TEST(CommandLineTest, ProgramQuotes) {
    337   // Check that quotes are not added for paths without spaces.
    338   const FilePath kProgram(L"Program");
    339   CommandLine cl_program(kProgram);
    340   EXPECT_EQ(kProgram.value(), cl_program.GetProgram().value());
    341   EXPECT_EQ(kProgram.value(), cl_program.GetCommandLineString());
    342 
    343   const FilePath kProgramPath(L"Program Path");
    344 
    345   // Check that quotes are not returned from GetProgram().
    346   CommandLine cl_program_path(kProgramPath);
    347   EXPECT_EQ(kProgramPath.value(), cl_program_path.GetProgram().value());
    348 
    349   // Check that quotes are added to command line string paths containing spaces.
    350   CommandLine::StringType cmd_string(cl_program_path.GetCommandLineString());
    351   CommandLine::StringType program_string(cl_program_path.GetProgram().value());
    352   EXPECT_EQ('"', cmd_string[0]);
    353   EXPECT_EQ(program_string, cmd_string.substr(1, program_string.length()));
    354   EXPECT_EQ('"', cmd_string[program_string.length() + 1]);
    355 }
    356 #endif
    357 
    358 // Calling Init multiple times should not modify the previous CommandLine.
    359 TEST(CommandLineTest, Init) {
    360   CommandLine* initial = CommandLine::ForCurrentProcess();
    361   EXPECT_FALSE(CommandLine::Init(0, NULL));
    362   CommandLine* current = CommandLine::ForCurrentProcess();
    363   EXPECT_EQ(initial, current);
    364 }
    365