1 // LAF Base Library
2 // Copyright (c) 2001-2017 David Capello
3 //
4 // This file is released under the terms of the MIT license.
5 // Read LICENSE.txt for more information.
6 
7 #include <gtest/gtest.h>
8 
9 #include "base/program_options.h"
10 
11 using namespace base;
12 
TEST(ProgramOptions,OptionMembers)13 TEST(ProgramOptions, OptionMembers)
14 {
15   ProgramOptions po;
16   ProgramOptions::Option& help =
17     po.add("help").mnemonic('h').description("Show the help");
18   ProgramOptions::Option& output =
19     po.add("output").mnemonic('O').requiresValue("OUTPUT");
20 
21   EXPECT_EQ("help", help.name());
22   EXPECT_EQ("Show the help", help.description());
23   EXPECT_EQ('h', help.mnemonic());
24   EXPECT_FALSE(po.enabled(help));
25   EXPECT_FALSE(help.doesRequireValue());
26 
27   EXPECT_EQ("output", output.name());
28   EXPECT_EQ("", output.description());
29   EXPECT_EQ('O', output.mnemonic());
30   EXPECT_FALSE(po.enabled(output));
31   EXPECT_TRUE(output.doesRequireValue());
32 }
33 
TEST(ProgramOptions,Reset)34 TEST(ProgramOptions, Reset)
35 {
36   ProgramOptions po;
37   ProgramOptions::Option& help = po.add("help");
38   ProgramOptions::Option& file = po.add("file").requiresValue("FILE");
39   EXPECT_FALSE(po.enabled(help));
40   EXPECT_FALSE(po.enabled(file));
41   EXPECT_EQ("", po.value_of(file));
42 
43   const char* argv[] = { "program.exe", "--help", "--file=readme.txt" };
44   po.parse(3, argv);
45   EXPECT_TRUE(po.enabled(help));
46   EXPECT_TRUE(po.enabled(file));
47   EXPECT_EQ("readme.txt", po.value_of(file));
48 
49   po.reset();
50   EXPECT_FALSE(po.enabled(help));
51   EXPECT_FALSE(po.enabled(file));
52   EXPECT_EQ("", po.value_of(file));
53 }
54 
TEST(ProgramOptions,Parse)55 TEST(ProgramOptions, Parse)
56 {
57   ProgramOptions po;
58   ProgramOptions::Option& help = po.add("help").mnemonic('?');
59   ProgramOptions::Option& input = po.add("input").mnemonic('i').requiresValue("INPUT");
60   ProgramOptions::Option& output = po.add("output").mnemonic('o').requiresValue("OUTPUT");
61 
62   const char* argv1[] = { "program.exe", "-?" };
63   po.parse(2, argv1);
64   EXPECT_TRUE(po.enabled(help));
65 
66   const char* argv2[] = { "program.exe", "--help" };
67   po.reset();
68   po.parse(2, argv2);
69   EXPECT_TRUE(po.enabled(help));
70 
71   const char* argv3[] = { "program.exe", "--input", "hello.cpp", "--output", "hello.exe" };
72   po.reset();
73   po.parse(5, argv3);
74   EXPECT_FALSE(po.enabled(help));
75   EXPECT_TRUE(po.enabled(input));
76   EXPECT_TRUE(po.enabled(output));
77   EXPECT_EQ("hello.cpp", po.value_of(input));
78   EXPECT_EQ("hello.exe", po.value_of(output));
79 
80   const char* argv4[] = { "program.exe", "--input=hi.c", "--output=out.exe" };
81   po.reset();
82   po.parse(3, argv4);
83   EXPECT_FALSE(po.enabled(help));
84   EXPECT_TRUE(po.enabled(input));
85   EXPECT_TRUE(po.enabled(output));
86   EXPECT_EQ("hi.c", po.value_of(input));
87   EXPECT_EQ("out.exe", po.value_of(output));
88 
89   const char* argv5[] = { "program.exe", "-?i", "input.md", "-o", "output.html", "extra-file.txt" };
90   po.reset();
91   po.parse(6, argv5);
92   EXPECT_TRUE(po.enabled(help));
93   EXPECT_TRUE(po.enabled(input));
94   EXPECT_TRUE(po.enabled(output));
95   EXPECT_EQ("input.md", po.value_of(input));
96   EXPECT_EQ("output.html", po.value_of(output));
97   ASSERT_EQ(4, po.values().size());
98   EXPECT_EQ(&help, po.values()[0].option());
99   EXPECT_EQ(&input, po.values()[1].option());
100   EXPECT_EQ(&output, po.values()[2].option());
101   EXPECT_EQ(NULL, po.values()[3].option());
102   EXPECT_EQ("", po.values()[0].value());
103   EXPECT_EQ("input.md", po.values()[1].value());
104   EXPECT_EQ("output.html", po.values()[2].value());
105   EXPECT_EQ("extra-file.txt", po.values()[3].value());
106 
107   const char* argv6[] = { "program.exe", "value1", "value2", "-o", "output", "value3", "--input=input", "value4" };
108   po.reset();
109   po.parse(8, argv6);
110   ASSERT_EQ(6, po.values().size());
111   EXPECT_EQ("value1", po.values()[0].value());
112   EXPECT_EQ("value2", po.values()[1].value());
113   EXPECT_EQ("output", po.values()[2].value());
114   EXPECT_EQ("value3", po.values()[3].value());
115   EXPECT_EQ("input", po.values()[4].value());
116   EXPECT_EQ("value4", po.values()[5].value());
117 }
118 
TEST(ProgramOptions,ParseErrors)119 TEST(ProgramOptions, ParseErrors)
120 {
121   ProgramOptions po;
122   ProgramOptions::Option& help = po.add("help").mnemonic('?');
123   ProgramOptions::Option& input = po.add("input").mnemonic('i').requiresValue("INPUT");
124   ProgramOptions::Option& output = po.add("output").mnemonic('o').requiresValue("OUTPUT");
125 
126   const char* argv1[] = { "program.exe", "--input" };
127   EXPECT_THROW(po.parse(2, argv1), ProgramOptionNeedsValue);
128 
129   const char* argv2[] = { "program.exe", "-i" };
130   EXPECT_THROW(po.parse(2, argv2), ProgramOptionNeedsValue);
131 
132   const char* argv3[] = { "program.exe", "--test" };
133   EXPECT_THROW(po.parse(2, argv3), InvalidProgramOption);
134 
135   const char* argv4[] = { "program.exe", "-?a" };
136   po.reset();
137   EXPECT_FALSE(po.enabled(help));
138   EXPECT_THROW(po.parse(2, argv4), InvalidProgramOption);
139   EXPECT_TRUE(po.enabled(help));  // -? is parsed anyway, -a is the invalid option
140 
141   const char* argv5[] = { "program.exe", "-io", "input-and-output.txt" };
142   po.reset();
143   EXPECT_THROW(po.parse(2, argv5), ProgramOptionNeedsValue);
144   po.reset();
145   EXPECT_THROW(po.parse(3, argv5), InvalidProgramOptionsCombination);
146   EXPECT_TRUE(po.enabled(input));
147   EXPECT_FALSE(po.enabled(output));
148   EXPECT_EQ("input-and-output.txt", po.value_of(input));
149   EXPECT_EQ("", po.value_of(output));
150 }
151 
TEST(ProgramOptions,LongOptionWithSingleDash)152 TEST(ProgramOptions, LongOptionWithSingleDash)
153 {
154   ProgramOptions po;
155   ProgramOptions::Option& help = po.add("help").mnemonic('?');
156   ProgramOptions::Option& verbose = po.add("verbose").mnemonic('v');
157   ProgramOptions::Option& input = po.add("input").mnemonic('i').requiresValue("INPUT");
158   ProgramOptions::Option& output = po.add("output").mnemonic('o').requiresValue("OUTPUT");
159 
160   const char* argv1[] = { "program.exe", "-input", "input.txt" };
161   po.reset();
162   po.parse(3, argv1);
163   EXPECT_FALSE(po.enabled(verbose));
164   EXPECT_EQ("input.txt", po.value_of(input));
165 
166   const char* argv2[] = { "program.exe", "-vi", "input.txt" };
167   po.reset();
168   po.parse(3, argv2);
169   EXPECT_TRUE(po.enabled(verbose));
170   EXPECT_EQ("input.txt", po.value_of(input));
171 
172   const char* argv3[] = { "program.exe", "-?v", "-input", "input.txt", "-output", "output.txt" };
173   po.reset();
174   po.parse(6, argv3);
175   EXPECT_TRUE(po.enabled(help));
176   EXPECT_TRUE(po.enabled(verbose));
177   EXPECT_EQ("input.txt", po.value_of(input));
178   EXPECT_EQ("output.txt", po.value_of(output));
179 }
180 
main(int argc,char ** argv)181 int main(int argc, char** argv)
182 {
183   ::testing::InitGoogleTest(&argc, argv);
184   return RUN_ALL_TESTS();
185 }
186