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(UTF8ToUTF16(kFirstArgName));
    202   CommandLine::StringType expected_second_arg(UTF8ToUTF16(kSecondArgName));
    203   CommandLine::StringType expected_third_arg(UTF8ToUTF16(kThirdArgName));
    204   CommandLine::StringType expected_fourth_arg(UTF8ToUTF16(kFourthArgName));
    205 #elif defined(OS_POSIX)
    206   CommandLine::StringType expected_first_arg(kFirstArgName);
    207   CommandLine::StringType expected_second_arg(kSecondArgName);
    208   CommandLine::StringType expected_third_arg(kThirdArgName);
    209   CommandLine::StringType expected_fourth_arg(kFourthArgName);
    210 #endif
    211 
    212 #if defined(OS_WIN)
    213 #define QUOTE_ON_WIN FILE_PATH_LITERAL("\"")
    214 #else
    215 #define QUOTE_ON_WIN FILE_PATH_LITERAL("")
    216 #endif  // OS_WIN
    217 
    218   CommandLine::StringType expected_str;
    219   expected_str.append(FILE_PATH_LITERAL("--"))
    220               .append(expected_first_arg)
    221               .append(FILE_PATH_LITERAL("="))
    222               .append(QUOTE_ON_WIN)
    223               .append(kPath1)
    224               .append(QUOTE_ON_WIN)
    225               .append(FILE_PATH_LITERAL(" "))
    226               .append(FILE_PATH_LITERAL("--"))
    227               .append(expected_second_arg)
    228               .append(FILE_PATH_LITERAL("="))
    229               .append(QUOTE_ON_WIN)
    230               .append(kPath2)
    231               .append(QUOTE_ON_WIN)
    232               .append(FILE_PATH_LITERAL(" "))
    233               .append(QUOTE_ON_WIN)
    234               .append(expected_third_arg)
    235               .append(QUOTE_ON_WIN)
    236               .append(FILE_PATH_LITERAL(" "))
    237               .append(expected_fourth_arg);
    238   EXPECT_EQ(expected_str, cl.GetArgumentsString());
    239 }
    240 
    241 // Test methods for appending switches to a command line.
    242 TEST(CommandLineTest, AppendSwitches) {
    243   std::string switch1 = "switch1";
    244   std::string switch2 = "switch2";
    245   std::string value2 = "value";
    246   std::string switch3 = "switch3";
    247   std::string value3 = "a value with spaces";
    248   std::string switch4 = "switch4";
    249   std::string value4 = "\"a value with quotes\"";
    250   std::string switch5 = "quotes";
    251   CommandLine::StringType value5 = kTricky;
    252 
    253   CommandLine cl(FilePath(FILE_PATH_LITERAL("Program")));
    254 
    255   cl.AppendSwitch(switch1);
    256   cl.AppendSwitchASCII(switch2, value2);
    257   cl.AppendSwitchASCII(switch3, value3);
    258   cl.AppendSwitchASCII(switch4, value4);
    259   cl.AppendSwitchNative(switch5, value5);
    260 
    261   EXPECT_TRUE(cl.HasSwitch(switch1));
    262   EXPECT_TRUE(cl.HasSwitch(switch2));
    263   EXPECT_EQ(value2, cl.GetSwitchValueASCII(switch2));
    264   EXPECT_TRUE(cl.HasSwitch(switch3));
    265   EXPECT_EQ(value3, cl.GetSwitchValueASCII(switch3));
    266   EXPECT_TRUE(cl.HasSwitch(switch4));
    267   EXPECT_EQ(value4, cl.GetSwitchValueASCII(switch4));
    268   EXPECT_TRUE(cl.HasSwitch(switch5));
    269   EXPECT_EQ(value5, cl.GetSwitchValueNative(switch5));
    270 
    271 #if defined(OS_WIN)
    272   EXPECT_EQ(L"Program "
    273             L"--switch1 "
    274             L"--switch2=value "
    275             L"--switch3=\"a value with spaces\" "
    276             L"--switch4=\"\\\"a value with quotes\\\"\" "
    277             L"--quotes=\"" + kTrickyQuoted + L"\"",
    278             cl.GetCommandLineString());
    279 #endif
    280 }
    281 
    282 TEST(CommandLineTest, AppendSwitchesDashDash) {
    283  const CommandLine::CharType* raw_argv[] = { FILE_PATH_LITERAL("prog"),
    284                                              FILE_PATH_LITERAL("--"),
    285                                              FILE_PATH_LITERAL("--arg1") };
    286   CommandLine cl(arraysize(raw_argv), raw_argv);
    287 
    288   cl.AppendSwitch("switch1");
    289   cl.AppendSwitchASCII("switch2", "foo");
    290 
    291   cl.AppendArg("--arg2");
    292 
    293   EXPECT_EQ(FILE_PATH_LITERAL("prog --switch1 --switch2=foo -- --arg1 --arg2"),
    294             cl.GetCommandLineString());
    295   CommandLine::StringVector cl_argv = cl.argv();
    296   EXPECT_EQ(FILE_PATH_LITERAL("prog"), cl_argv[0]);
    297   EXPECT_EQ(FILE_PATH_LITERAL("--switch1"), cl_argv[1]);
    298   EXPECT_EQ(FILE_PATH_LITERAL("--switch2=foo"), cl_argv[2]);
    299   EXPECT_EQ(FILE_PATH_LITERAL("--"), cl_argv[3]);
    300   EXPECT_EQ(FILE_PATH_LITERAL("--arg1"), cl_argv[4]);
    301   EXPECT_EQ(FILE_PATH_LITERAL("--arg2"), cl_argv[5]);
    302 }
    303 
    304 // Tests that when AppendArguments is called that the program is set correctly
    305 // on the target CommandLine object and the switches from the source
    306 // CommandLine are added to the target.
    307 TEST(CommandLineTest, AppendArguments) {
    308   CommandLine cl1(FilePath(FILE_PATH_LITERAL("Program")));
    309   cl1.AppendSwitch("switch1");
    310   cl1.AppendSwitchASCII("switch2", "foo");
    311 
    312   CommandLine cl2(CommandLine::NO_PROGRAM);
    313   cl2.AppendArguments(cl1, true);
    314   EXPECT_EQ(cl1.GetProgram().value(), cl2.GetProgram().value());
    315   EXPECT_EQ(cl1.GetCommandLineString(), cl2.GetCommandLineString());
    316 
    317   CommandLine c1(FilePath(FILE_PATH_LITERAL("Program1")));
    318   c1.AppendSwitch("switch1");
    319   CommandLine c2(FilePath(FILE_PATH_LITERAL("Program2")));
    320   c2.AppendSwitch("switch2");
    321 
    322   c1.AppendArguments(c2, true);
    323   EXPECT_EQ(c1.GetProgram().value(), c2.GetProgram().value());
    324   EXPECT_TRUE(c1.HasSwitch("switch1"));
    325   EXPECT_TRUE(c1.HasSwitch("switch2"));
    326 }
    327 
    328 #if defined(OS_WIN)
    329 // Make sure that the command line string program paths are quoted as necessary.
    330 // This only makes sense on Windows and the test is basically here to guard
    331 // against regressions.
    332 TEST(CommandLineTest, ProgramQuotes) {
    333   // Check that quotes are not added for paths without spaces.
    334   const FilePath kProgram(L"Program");
    335   CommandLine cl_program(kProgram);
    336   EXPECT_EQ(kProgram.value(), cl_program.GetProgram().value());
    337   EXPECT_EQ(kProgram.value(), cl_program.GetCommandLineString());
    338 
    339   const FilePath kProgramPath(L"Program Path");
    340 
    341   // Check that quotes are not returned from GetProgram().
    342   CommandLine cl_program_path(kProgramPath);
    343   EXPECT_EQ(kProgramPath.value(), cl_program_path.GetProgram().value());
    344 
    345   // Check that quotes are added to command line string paths containing spaces.
    346   CommandLine::StringType cmd_string(cl_program_path.GetCommandLineString());
    347   CommandLine::StringType program_string(cl_program_path.GetProgram().value());
    348   EXPECT_EQ('"', cmd_string[0]);
    349   EXPECT_EQ(program_string, cmd_string.substr(1, program_string.length()));
    350   EXPECT_EQ('"', cmd_string[program_string.length() + 1]);
    351 }
    352 #endif
    353 
    354 // Calling Init multiple times should not modify the previous CommandLine.
    355 TEST(CommandLineTest, Init) {
    356   CommandLine* initial = CommandLine::ForCurrentProcess();
    357   EXPECT_FALSE(CommandLine::Init(0, NULL));
    358   CommandLine* current = CommandLine::ForCurrentProcess();
    359   EXPECT_EQ(initial, current);
    360 }
    361