1*b0d29bc4SBrooks Davis // Copyright 2010 The Kyua Authors.
2*b0d29bc4SBrooks Davis // All rights reserved.
3*b0d29bc4SBrooks Davis //
4*b0d29bc4SBrooks Davis // Redistribution and use in source and binary forms, with or without
5*b0d29bc4SBrooks Davis // modification, are permitted provided that the following conditions are
6*b0d29bc4SBrooks Davis // met:
7*b0d29bc4SBrooks Davis //
8*b0d29bc4SBrooks Davis // * Redistributions of source code must retain the above copyright
9*b0d29bc4SBrooks Davis //   notice, this list of conditions and the following disclaimer.
10*b0d29bc4SBrooks Davis // * Redistributions in binary form must reproduce the above copyright
11*b0d29bc4SBrooks Davis //   notice, this list of conditions and the following disclaimer in the
12*b0d29bc4SBrooks Davis //   documentation and/or other materials provided with the distribution.
13*b0d29bc4SBrooks Davis // * Neither the name of Google Inc. nor the names of its contributors
14*b0d29bc4SBrooks Davis //   may be used to endorse or promote products derived from this software
15*b0d29bc4SBrooks Davis //   without specific prior written permission.
16*b0d29bc4SBrooks Davis //
17*b0d29bc4SBrooks Davis // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*b0d29bc4SBrooks Davis // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*b0d29bc4SBrooks Davis // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*b0d29bc4SBrooks Davis // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*b0d29bc4SBrooks Davis // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*b0d29bc4SBrooks Davis // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*b0d29bc4SBrooks Davis // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*b0d29bc4SBrooks Davis // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*b0d29bc4SBrooks Davis // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*b0d29bc4SBrooks Davis // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*b0d29bc4SBrooks Davis // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*b0d29bc4SBrooks Davis 
29*b0d29bc4SBrooks Davis #include "utils/cmdline/parser.ipp"
30*b0d29bc4SBrooks Davis 
31*b0d29bc4SBrooks Davis #if defined(HAVE_CONFIG_H)
32*b0d29bc4SBrooks Davis #include "config.h"
33*b0d29bc4SBrooks Davis #endif
34*b0d29bc4SBrooks Davis 
35*b0d29bc4SBrooks Davis extern "C" {
36*b0d29bc4SBrooks Davis #include <fcntl.h>
37*b0d29bc4SBrooks Davis #include <getopt.h>
38*b0d29bc4SBrooks Davis #include <unistd.h>
39*b0d29bc4SBrooks Davis }
40*b0d29bc4SBrooks Davis 
41*b0d29bc4SBrooks Davis #include <cstdlib>
42*b0d29bc4SBrooks Davis #include <cstring>
43*b0d29bc4SBrooks Davis #include <fstream>
44*b0d29bc4SBrooks Davis #include <iostream>
45*b0d29bc4SBrooks Davis #include <string>
46*b0d29bc4SBrooks Davis #include <utility>
47*b0d29bc4SBrooks Davis 
48*b0d29bc4SBrooks Davis #include <atf-c++.hpp>
49*b0d29bc4SBrooks Davis 
50*b0d29bc4SBrooks Davis #include "utils/cmdline/exceptions.hpp"
51*b0d29bc4SBrooks Davis #include "utils/cmdline/options.hpp"
52*b0d29bc4SBrooks Davis #include "utils/format/macros.hpp"
53*b0d29bc4SBrooks Davis #include "utils/sanity.hpp"
54*b0d29bc4SBrooks Davis 
55*b0d29bc4SBrooks Davis namespace cmdline = utils::cmdline;
56*b0d29bc4SBrooks Davis 
57*b0d29bc4SBrooks Davis using cmdline::base_option;
58*b0d29bc4SBrooks Davis using cmdline::bool_option;
59*b0d29bc4SBrooks Davis using cmdline::int_option;
60*b0d29bc4SBrooks Davis using cmdline::parse;
61*b0d29bc4SBrooks Davis using cmdline::parsed_cmdline;
62*b0d29bc4SBrooks Davis using cmdline::string_option;
63*b0d29bc4SBrooks Davis 
64*b0d29bc4SBrooks Davis 
65*b0d29bc4SBrooks Davis namespace {
66*b0d29bc4SBrooks Davis 
67*b0d29bc4SBrooks Davis 
68*b0d29bc4SBrooks Davis /// Mock option type to check the validate and convert methods sequence.
69*b0d29bc4SBrooks Davis ///
70*b0d29bc4SBrooks Davis /// Instances of this option accept a string argument that must be either "zero"
71*b0d29bc4SBrooks Davis /// or "one".  These are validated and converted to integers.
72*b0d29bc4SBrooks Davis class mock_option : public base_option {
73*b0d29bc4SBrooks Davis public:
74*b0d29bc4SBrooks Davis     /// Constructs the new option.
75*b0d29bc4SBrooks Davis     ///
76*b0d29bc4SBrooks Davis     /// \param long_name_ The long name for the option.  All other option
77*b0d29bc4SBrooks Davis     ///     properties are irrelevant for the tests using this, so they are set
78*b0d29bc4SBrooks Davis     ///     to arbitrary values.
mock_option(const char * long_name_)79*b0d29bc4SBrooks Davis     mock_option(const char* long_name_) :
80*b0d29bc4SBrooks Davis         base_option(long_name_, "Irrelevant description", "arg")
81*b0d29bc4SBrooks Davis     {
82*b0d29bc4SBrooks Davis     }
83*b0d29bc4SBrooks Davis 
84*b0d29bc4SBrooks Davis     /// The type of the argument of this option.
85*b0d29bc4SBrooks Davis     typedef int option_type;
86*b0d29bc4SBrooks Davis 
87*b0d29bc4SBrooks Davis     /// Checks that the user-provided option is valid.
88*b0d29bc4SBrooks Davis     ///
89*b0d29bc4SBrooks Davis     /// \param str The user argument; must be "zero" or "one".
90*b0d29bc4SBrooks Davis     ///
91*b0d29bc4SBrooks Davis     /// \throw cmdline::option_argument_value_error If str is not valid.
92*b0d29bc4SBrooks Davis     void
validate(const std::string & str) const93*b0d29bc4SBrooks Davis     validate(const std::string& str) const
94*b0d29bc4SBrooks Davis     {
95*b0d29bc4SBrooks Davis         if (str != "zero" && str != "one")
96*b0d29bc4SBrooks Davis             throw cmdline::option_argument_value_error(F("--%s") % long_name(),
97*b0d29bc4SBrooks Davis                                                        str, "Unknown value");
98*b0d29bc4SBrooks Davis     }
99*b0d29bc4SBrooks Davis 
100*b0d29bc4SBrooks Davis     /// Converts the user-provided argument to our native integer type.
101*b0d29bc4SBrooks Davis     ///
102*b0d29bc4SBrooks Davis     /// \param str The user argument; must be "zero" or "one".
103*b0d29bc4SBrooks Davis     ///
104*b0d29bc4SBrooks Davis     /// \return 0 if the input is "zero", or 1 if the input is "one".
105*b0d29bc4SBrooks Davis     ///
106*b0d29bc4SBrooks Davis     /// \throw std::runtime_error If str is not valid.  In real life, this
107*b0d29bc4SBrooks Davis     ///     should be a precondition because validate() has already ensured that
108*b0d29bc4SBrooks Davis     ///     the values passed to convert() are correct.  However, we raise an
109*b0d29bc4SBrooks Davis     ///     exception here because we are actually validating that this code
110*b0d29bc4SBrooks Davis     ///     sequence holds true.
111*b0d29bc4SBrooks Davis     static int
convert(const std::string & str)112*b0d29bc4SBrooks Davis     convert(const std::string& str)
113*b0d29bc4SBrooks Davis     {
114*b0d29bc4SBrooks Davis         if (str == "zero")
115*b0d29bc4SBrooks Davis             return 0;
116*b0d29bc4SBrooks Davis         else if (str == "one")
117*b0d29bc4SBrooks Davis             return 1;
118*b0d29bc4SBrooks Davis         else {
119*b0d29bc4SBrooks Davis             // This would generally be an assertion but, given that this is
120*b0d29bc4SBrooks Davis             // test code, we want to catch any errors regardless of how the
121*b0d29bc4SBrooks Davis             // binary is built.
122*b0d29bc4SBrooks Davis             throw std::runtime_error("Value not validated properly.");
123*b0d29bc4SBrooks Davis         }
124*b0d29bc4SBrooks Davis     }
125*b0d29bc4SBrooks Davis };
126*b0d29bc4SBrooks Davis 
127*b0d29bc4SBrooks Davis 
128*b0d29bc4SBrooks Davis /// Redirects stdout and stderr to a file.
129*b0d29bc4SBrooks Davis ///
130*b0d29bc4SBrooks Davis /// This fails the test case in case of any error.
131*b0d29bc4SBrooks Davis ///
132*b0d29bc4SBrooks Davis /// \param file The name of the file to redirect stdout and stderr to.
133*b0d29bc4SBrooks Davis ///
134*b0d29bc4SBrooks Davis /// \return A copy of the old stdout and stderr file descriptors.
135*b0d29bc4SBrooks Davis static std::pair< int, int >
mock_stdfds(const char * file)136*b0d29bc4SBrooks Davis mock_stdfds(const char* file)
137*b0d29bc4SBrooks Davis {
138*b0d29bc4SBrooks Davis     std::cout.flush();
139*b0d29bc4SBrooks Davis     std::cerr.flush();
140*b0d29bc4SBrooks Davis 
141*b0d29bc4SBrooks Davis     const int oldout = ::dup(STDOUT_FILENO);
142*b0d29bc4SBrooks Davis     ATF_REQUIRE(oldout != -1);
143*b0d29bc4SBrooks Davis     const int olderr = ::dup(STDERR_FILENO);
144*b0d29bc4SBrooks Davis     ATF_REQUIRE(olderr != -1);
145*b0d29bc4SBrooks Davis 
146*b0d29bc4SBrooks Davis     const int fd = ::open(file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
147*b0d29bc4SBrooks Davis     ATF_REQUIRE(fd != -1);
148*b0d29bc4SBrooks Davis     ATF_REQUIRE(::dup2(fd, STDOUT_FILENO) != -1);
149*b0d29bc4SBrooks Davis     ATF_REQUIRE(::dup2(fd, STDERR_FILENO) != -1);
150*b0d29bc4SBrooks Davis     ::close(fd);
151*b0d29bc4SBrooks Davis 
152*b0d29bc4SBrooks Davis     return std::make_pair(oldout, olderr);
153*b0d29bc4SBrooks Davis }
154*b0d29bc4SBrooks Davis 
155*b0d29bc4SBrooks Davis 
156*b0d29bc4SBrooks Davis /// Restores stdout and stderr after a call to mock_stdfds.
157*b0d29bc4SBrooks Davis ///
158*b0d29bc4SBrooks Davis /// \param oldfds The copy of the previous stdout and stderr as returned by the
159*b0d29bc4SBrooks Davis ///     call to mock_fds().
160*b0d29bc4SBrooks Davis static void
restore_stdfds(const std::pair<int,int> & oldfds)161*b0d29bc4SBrooks Davis restore_stdfds(const std::pair< int, int >& oldfds)
162*b0d29bc4SBrooks Davis {
163*b0d29bc4SBrooks Davis     ATF_REQUIRE(::dup2(oldfds.first, STDOUT_FILENO) != -1);
164*b0d29bc4SBrooks Davis     ::close(oldfds.first);
165*b0d29bc4SBrooks Davis     ATF_REQUIRE(::dup2(oldfds.second, STDERR_FILENO) != -1);
166*b0d29bc4SBrooks Davis     ::close(oldfds.second);
167*b0d29bc4SBrooks Davis }
168*b0d29bc4SBrooks Davis 
169*b0d29bc4SBrooks Davis 
170*b0d29bc4SBrooks Davis /// Checks whether a '+:' prefix to the short options of getopt_long works.
171*b0d29bc4SBrooks Davis ///
172*b0d29bc4SBrooks Davis /// It turns out that the getopt_long(3) implementation of Ubuntu 10.04.1 (and
173*b0d29bc4SBrooks Davis /// very likely other distributions) does not properly report a missing argument
174*b0d29bc4SBrooks Davis /// to a second long option as such.  Instead of returning ':' when the second
175*b0d29bc4SBrooks Davis /// long option provided on the command line does not carry a required argument,
176*b0d29bc4SBrooks Davis /// it will mistakenly return '?' which translates to "unknown option".
177*b0d29bc4SBrooks Davis ///
178*b0d29bc4SBrooks Davis /// As a result of this bug, we cannot properly detect that 'flag2' requires an
179*b0d29bc4SBrooks Davis /// argument in a command line like: 'progname --flag1=foo --flag2'.
180*b0d29bc4SBrooks Davis ///
181*b0d29bc4SBrooks Davis /// I am not sure if we could fully workaround the issue in the implementation
182*b0d29bc4SBrooks Davis /// of our library.  For the time being I am just using this bug detection in
183*b0d29bc4SBrooks Davis /// the test cases to prevent failures that are not really our fault.
184*b0d29bc4SBrooks Davis ///
185*b0d29bc4SBrooks Davis /// \return bool True if getopt_long is broken and does not interpret '+:'
186*b0d29bc4SBrooks Davis ///     correctly; False otherwise.
187*b0d29bc4SBrooks Davis static bool
is_getopt_long_pluscolon_broken(void)188*b0d29bc4SBrooks Davis is_getopt_long_pluscolon_broken(void)
189*b0d29bc4SBrooks Davis {
190*b0d29bc4SBrooks Davis     struct ::option long_options[] = {
191*b0d29bc4SBrooks Davis         { "flag1", 1, NULL, '1' },
192*b0d29bc4SBrooks Davis         { "flag2", 1, NULL, '2' },
193*b0d29bc4SBrooks Davis         { NULL, 0, NULL, 0 }
194*b0d29bc4SBrooks Davis     };
195*b0d29bc4SBrooks Davis 
196*b0d29bc4SBrooks Davis     const int argc = 3;
197*b0d29bc4SBrooks Davis     char* argv[4];
198*b0d29bc4SBrooks Davis     argv[0] = ::strdup("progname");
199*b0d29bc4SBrooks Davis     argv[1] = ::strdup("--flag1=a");
200*b0d29bc4SBrooks Davis     argv[2] = ::strdup("--flag2");
201*b0d29bc4SBrooks Davis     argv[3] = NULL;
202*b0d29bc4SBrooks Davis 
203*b0d29bc4SBrooks Davis     const int old_opterr = ::opterr;
204*b0d29bc4SBrooks Davis     ::opterr = 0;
205*b0d29bc4SBrooks Davis 
206*b0d29bc4SBrooks Davis     bool got_colon = false;
207*b0d29bc4SBrooks Davis 
208*b0d29bc4SBrooks Davis     int opt;
209*b0d29bc4SBrooks Davis     while ((opt = ::getopt_long(argc, argv, "+:", long_options, NULL)) != -1) {
210*b0d29bc4SBrooks Davis         switch (opt) {
211*b0d29bc4SBrooks Davis         case '1': break;
212*b0d29bc4SBrooks Davis         case '2': break;
213*b0d29bc4SBrooks Davis         case ':': got_colon = true; break;
214*b0d29bc4SBrooks Davis         case '?': break;
215*b0d29bc4SBrooks Davis         default:  UNREACHABLE; break;
216*b0d29bc4SBrooks Davis         }
217*b0d29bc4SBrooks Davis     }
218*b0d29bc4SBrooks Davis 
219*b0d29bc4SBrooks Davis     ::opterr = old_opterr;
220*b0d29bc4SBrooks Davis     ::optind = 1;
221*b0d29bc4SBrooks Davis #if defined(HAVE_GETOPT_WITH_OPTRESET)
222*b0d29bc4SBrooks Davis     ::optreset = 1;
223*b0d29bc4SBrooks Davis #endif
224*b0d29bc4SBrooks Davis 
225*b0d29bc4SBrooks Davis     for (char** arg = &argv[0]; *arg != NULL; arg++)
226*b0d29bc4SBrooks Davis         std::free(*arg);
227*b0d29bc4SBrooks Davis 
228*b0d29bc4SBrooks Davis     return !got_colon;
229*b0d29bc4SBrooks Davis }
230*b0d29bc4SBrooks Davis 
231*b0d29bc4SBrooks Davis 
232*b0d29bc4SBrooks Davis }  // anonymous namespace
233*b0d29bc4SBrooks Davis 
234*b0d29bc4SBrooks Davis 
235*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(progname__no_options);
ATF_TEST_CASE_BODY(progname__no_options)236*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(progname__no_options)
237*b0d29bc4SBrooks Davis {
238*b0d29bc4SBrooks Davis     const int argc = 1;
239*b0d29bc4SBrooks Davis     const char* const argv[] = {"progname", NULL};
240*b0d29bc4SBrooks Davis     std::vector< const base_option* > options;
241*b0d29bc4SBrooks Davis     const parsed_cmdline cmdline = parse(argc, argv, options);
242*b0d29bc4SBrooks Davis 
243*b0d29bc4SBrooks Davis     ATF_REQUIRE(cmdline.arguments().empty());
244*b0d29bc4SBrooks Davis }
245*b0d29bc4SBrooks Davis 
246*b0d29bc4SBrooks Davis 
247*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(progname__some_options);
ATF_TEST_CASE_BODY(progname__some_options)248*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(progname__some_options)
249*b0d29bc4SBrooks Davis {
250*b0d29bc4SBrooks Davis     const int argc = 1;
251*b0d29bc4SBrooks Davis     const char* const argv[] = {"progname", NULL};
252*b0d29bc4SBrooks Davis     const string_option a('a', "a_option", "Foo", NULL);
253*b0d29bc4SBrooks Davis     const string_option b('b', "b_option", "Bar", "arg", "foo");
254*b0d29bc4SBrooks Davis     const string_option c("c_option", "Baz", NULL);
255*b0d29bc4SBrooks Davis     const string_option d("d_option", "Wohoo", "arg", "bar");
256*b0d29bc4SBrooks Davis     std::vector< const base_option* > options;
257*b0d29bc4SBrooks Davis     options.push_back(&a);
258*b0d29bc4SBrooks Davis     options.push_back(&b);
259*b0d29bc4SBrooks Davis     options.push_back(&c);
260*b0d29bc4SBrooks Davis     options.push_back(&d);
261*b0d29bc4SBrooks Davis     const parsed_cmdline cmdline = parse(argc, argv, options);
262*b0d29bc4SBrooks Davis 
263*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("foo", cmdline.get_option< string_option >("b_option"));
264*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("bar", cmdline.get_option< string_option >("d_option"));
265*b0d29bc4SBrooks Davis     ATF_REQUIRE(cmdline.arguments().empty());
266*b0d29bc4SBrooks Davis }
267*b0d29bc4SBrooks Davis 
268*b0d29bc4SBrooks Davis 
269*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(some_args__no_options);
ATF_TEST_CASE_BODY(some_args__no_options)270*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(some_args__no_options)
271*b0d29bc4SBrooks Davis {
272*b0d29bc4SBrooks Davis     const int argc = 5;
273*b0d29bc4SBrooks Davis     const char* const argv[] = {"progname", "foo", "-c", "--opt", "bar", NULL};
274*b0d29bc4SBrooks Davis     std::vector< const base_option* > options;
275*b0d29bc4SBrooks Davis     const parsed_cmdline cmdline = parse(argc, argv, options);
276*b0d29bc4SBrooks Davis 
277*b0d29bc4SBrooks Davis     ATF_REQUIRE(!cmdline.has_option("c"));
278*b0d29bc4SBrooks Davis     ATF_REQUIRE(!cmdline.has_option("opt"));
279*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(4, cmdline.arguments().size());
280*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("foo", cmdline.arguments()[0]);
281*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("-c", cmdline.arguments()[1]);
282*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("--opt", cmdline.arguments()[2]);
283*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("bar", cmdline.arguments()[3]);
284*b0d29bc4SBrooks Davis }
285*b0d29bc4SBrooks Davis 
286*b0d29bc4SBrooks Davis 
287*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(some_args__some_options);
ATF_TEST_CASE_BODY(some_args__some_options)288*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(some_args__some_options)
289*b0d29bc4SBrooks Davis {
290*b0d29bc4SBrooks Davis     const int argc = 5;
291*b0d29bc4SBrooks Davis     const char* const argv[] = {"progname", "foo", "-c", "--opt", "bar", NULL};
292*b0d29bc4SBrooks Davis     const string_option c('c', "opt", "Description", NULL);
293*b0d29bc4SBrooks Davis     std::vector< const base_option* > options;
294*b0d29bc4SBrooks Davis     options.push_back(&c);
295*b0d29bc4SBrooks Davis     const parsed_cmdline cmdline = parse(argc, argv, options);
296*b0d29bc4SBrooks Davis 
297*b0d29bc4SBrooks Davis     ATF_REQUIRE(!cmdline.has_option("c"));
298*b0d29bc4SBrooks Davis     ATF_REQUIRE(!cmdline.has_option("opt"));
299*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(4, cmdline.arguments().size());
300*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("foo", cmdline.arguments()[0]);
301*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("-c", cmdline.arguments()[1]);
302*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("--opt", cmdline.arguments()[2]);
303*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("bar", cmdline.arguments()[3]);
304*b0d29bc4SBrooks Davis }
305*b0d29bc4SBrooks Davis 
306*b0d29bc4SBrooks Davis 
307*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(some_options__all_known);
ATF_TEST_CASE_BODY(some_options__all_known)308*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(some_options__all_known)
309*b0d29bc4SBrooks Davis {
310*b0d29bc4SBrooks Davis     const int argc = 14;
311*b0d29bc4SBrooks Davis     const char* const argv[] = {
312*b0d29bc4SBrooks Davis         "progname",
313*b0d29bc4SBrooks Davis         "-a",
314*b0d29bc4SBrooks Davis         "-bvalue_b",
315*b0d29bc4SBrooks Davis         "-c", "value_c",
316*b0d29bc4SBrooks Davis         //"-d",  // Options with default optional values are unsupported.
317*b0d29bc4SBrooks Davis         "-evalue_e",  // Has default; overriden.
318*b0d29bc4SBrooks Davis         "--f_long",
319*b0d29bc4SBrooks Davis         "--g_long=value_g",
320*b0d29bc4SBrooks Davis         "--h_long", "value_h",
321*b0d29bc4SBrooks Davis         //"--i_long",  // Options with default optional values are unsupported.
322*b0d29bc4SBrooks Davis         "--j_long", "value_j",  // Has default; overriden as separate argument.
323*b0d29bc4SBrooks Davis         "arg1", "arg2", NULL,
324*b0d29bc4SBrooks Davis     };
325*b0d29bc4SBrooks Davis     const bool_option a('a', "a_long", "");
326*b0d29bc4SBrooks Davis     const string_option b('b', "b_long", "Description", "arg");
327*b0d29bc4SBrooks Davis     const string_option c('c', "c_long", "ABCD", "foo");
328*b0d29bc4SBrooks Davis     const string_option d('d', "d_long", "Description", "bar", "default_d");
329*b0d29bc4SBrooks Davis     const string_option e('e', "e_long", "Description", "baz", "default_e");
330*b0d29bc4SBrooks Davis     const bool_option f("f_long", "Description");
331*b0d29bc4SBrooks Davis     const string_option g("g_long", "Description", "arg");
332*b0d29bc4SBrooks Davis     const string_option h("h_long", "Description", "foo");
333*b0d29bc4SBrooks Davis     const string_option i("i_long", "EFGH", "bar", "default_i");
334*b0d29bc4SBrooks Davis     const string_option j("j_long", "Description", "baz", "default_j");
335*b0d29bc4SBrooks Davis     std::vector< const base_option* > options;
336*b0d29bc4SBrooks Davis     options.push_back(&a);
337*b0d29bc4SBrooks Davis     options.push_back(&b);
338*b0d29bc4SBrooks Davis     options.push_back(&c);
339*b0d29bc4SBrooks Davis     options.push_back(&d);
340*b0d29bc4SBrooks Davis     options.push_back(&e);
341*b0d29bc4SBrooks Davis     options.push_back(&f);
342*b0d29bc4SBrooks Davis     options.push_back(&g);
343*b0d29bc4SBrooks Davis     options.push_back(&h);
344*b0d29bc4SBrooks Davis     options.push_back(&i);
345*b0d29bc4SBrooks Davis     options.push_back(&j);
346*b0d29bc4SBrooks Davis     const parsed_cmdline cmdline = parse(argc, argv, options);
347*b0d29bc4SBrooks Davis 
348*b0d29bc4SBrooks Davis     ATF_REQUIRE(cmdline.has_option("a_long"));
349*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("value_b", cmdline.get_option< string_option >("b_long"));
350*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("value_c", cmdline.get_option< string_option >("c_long"));
351*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("default_d", cmdline.get_option< string_option >("d_long"));
352*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("value_e", cmdline.get_option< string_option >("e_long"));
353*b0d29bc4SBrooks Davis     ATF_REQUIRE(cmdline.has_option("f_long"));
354*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("value_g", cmdline.get_option< string_option >("g_long"));
355*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("value_h", cmdline.get_option< string_option >("h_long"));
356*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("default_i", cmdline.get_option< string_option >("i_long"));
357*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("value_j", cmdline.get_option< string_option >("j_long"));
358*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(2, cmdline.arguments().size());
359*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("arg1", cmdline.arguments()[0]);
360*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("arg2", cmdline.arguments()[1]);
361*b0d29bc4SBrooks Davis }
362*b0d29bc4SBrooks Davis 
363*b0d29bc4SBrooks Davis 
364*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(some_options__multi);
ATF_TEST_CASE_BODY(some_options__multi)365*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(some_options__multi)
366*b0d29bc4SBrooks Davis {
367*b0d29bc4SBrooks Davis     const int argc = 9;
368*b0d29bc4SBrooks Davis     const char* const argv[] = {
369*b0d29bc4SBrooks Davis         "progname",
370*b0d29bc4SBrooks Davis         "-a1",
371*b0d29bc4SBrooks Davis         "-bvalue1",
372*b0d29bc4SBrooks Davis         "-a2",
373*b0d29bc4SBrooks Davis         "--a_long=3",
374*b0d29bc4SBrooks Davis         "-bvalue2",
375*b0d29bc4SBrooks Davis         "--b_long=value3",
376*b0d29bc4SBrooks Davis         "arg1", "arg2", NULL,
377*b0d29bc4SBrooks Davis     };
378*b0d29bc4SBrooks Davis     const int_option a('a', "a_long", "Description", "arg");
379*b0d29bc4SBrooks Davis     const string_option b('b', "b_long", "Description", "arg");
380*b0d29bc4SBrooks Davis     std::vector< const base_option* > options;
381*b0d29bc4SBrooks Davis     options.push_back(&a);
382*b0d29bc4SBrooks Davis     options.push_back(&b);
383*b0d29bc4SBrooks Davis     const parsed_cmdline cmdline = parse(argc, argv, options);
384*b0d29bc4SBrooks Davis 
385*b0d29bc4SBrooks Davis     {
386*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ(3, cmdline.get_option< int_option >("a_long"));
387*b0d29bc4SBrooks Davis         const std::vector< int > multi =
388*b0d29bc4SBrooks Davis             cmdline.get_multi_option< int_option >("a_long");
389*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ(3, multi.size());
390*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ(1, multi[0]);
391*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ(2, multi[1]);
392*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ(3, multi[2]);
393*b0d29bc4SBrooks Davis     }
394*b0d29bc4SBrooks Davis 
395*b0d29bc4SBrooks Davis     {
396*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ("value3", cmdline.get_option< string_option >("b_long"));
397*b0d29bc4SBrooks Davis         const std::vector< std::string > multi =
398*b0d29bc4SBrooks Davis             cmdline.get_multi_option< string_option >("b_long");
399*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ(3, multi.size());
400*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ("value1", multi[0]);
401*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ("value2", multi[1]);
402*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ("value3", multi[2]);
403*b0d29bc4SBrooks Davis     }
404*b0d29bc4SBrooks Davis }
405*b0d29bc4SBrooks Davis 
406*b0d29bc4SBrooks Davis 
407*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(subcommands);
ATF_TEST_CASE_BODY(subcommands)408*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(subcommands)
409*b0d29bc4SBrooks Davis {
410*b0d29bc4SBrooks Davis     const int argc = 5;
411*b0d29bc4SBrooks Davis     const char* const argv[] = {"progname", "--flag1", "subcommand",
412*b0d29bc4SBrooks Davis                                 "--flag2", "arg", NULL};
413*b0d29bc4SBrooks Davis     const bool_option flag1("flag1", "");
414*b0d29bc4SBrooks Davis     std::vector< const base_option* > options;
415*b0d29bc4SBrooks Davis     options.push_back(&flag1);
416*b0d29bc4SBrooks Davis     const parsed_cmdline cmdline = parse(argc, argv, options);
417*b0d29bc4SBrooks Davis 
418*b0d29bc4SBrooks Davis     ATF_REQUIRE( cmdline.has_option("flag1"));
419*b0d29bc4SBrooks Davis     ATF_REQUIRE(!cmdline.has_option("flag2"));
420*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(3, cmdline.arguments().size());
421*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("subcommand", cmdline.arguments()[0]);
422*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("--flag2", cmdline.arguments()[1]);
423*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("arg", cmdline.arguments()[2]);
424*b0d29bc4SBrooks Davis 
425*b0d29bc4SBrooks Davis     const bool_option flag2("flag2", "");
426*b0d29bc4SBrooks Davis     std::vector< const base_option* > options2;
427*b0d29bc4SBrooks Davis     options2.push_back(&flag2);
428*b0d29bc4SBrooks Davis     const parsed_cmdline cmdline2 = parse(cmdline.arguments(), options2);
429*b0d29bc4SBrooks Davis 
430*b0d29bc4SBrooks Davis     ATF_REQUIRE(!cmdline2.has_option("flag1"));
431*b0d29bc4SBrooks Davis     ATF_REQUIRE( cmdline2.has_option("flag2"));
432*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(1, cmdline2.arguments().size());
433*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("arg", cmdline2.arguments()[0]);
434*b0d29bc4SBrooks Davis }
435*b0d29bc4SBrooks Davis 
436*b0d29bc4SBrooks Davis 
437*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(missing_option_argument_error__short);
ATF_TEST_CASE_BODY(missing_option_argument_error__short)438*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(missing_option_argument_error__short)
439*b0d29bc4SBrooks Davis {
440*b0d29bc4SBrooks Davis     const int argc = 3;
441*b0d29bc4SBrooks Davis     const char* const argv[] = {"progname", "-a3", "-b", NULL};
442*b0d29bc4SBrooks Davis     const string_option flag1('a', "flag1", "Description", "arg");
443*b0d29bc4SBrooks Davis     const string_option flag2('b', "flag2", "Description", "arg");
444*b0d29bc4SBrooks Davis     std::vector< const base_option* > options;
445*b0d29bc4SBrooks Davis     options.push_back(&flag1);
446*b0d29bc4SBrooks Davis     options.push_back(&flag2);
447*b0d29bc4SBrooks Davis 
448*b0d29bc4SBrooks Davis     try {
449*b0d29bc4SBrooks Davis         parse(argc, argv, options);
450*b0d29bc4SBrooks Davis         fail("missing_option_argument_error not raised");
451*b0d29bc4SBrooks Davis     } catch (const cmdline::missing_option_argument_error& e) {
452*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ("-b", e.option());
453*b0d29bc4SBrooks Davis     } catch (const cmdline::unknown_option_error& e) {
454*b0d29bc4SBrooks Davis         if (is_getopt_long_pluscolon_broken())
455*b0d29bc4SBrooks Davis             expect_fail("Your getopt_long is broken");
456*b0d29bc4SBrooks Davis         fail("Got unknown_option_error instead of "
457*b0d29bc4SBrooks Davis              "missing_option_argument_error");
458*b0d29bc4SBrooks Davis     }
459*b0d29bc4SBrooks Davis }
460*b0d29bc4SBrooks Davis 
461*b0d29bc4SBrooks Davis 
462*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(missing_option_argument_error__shortblock);
ATF_TEST_CASE_BODY(missing_option_argument_error__shortblock)463*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(missing_option_argument_error__shortblock)
464*b0d29bc4SBrooks Davis {
465*b0d29bc4SBrooks Davis     const int argc = 3;
466*b0d29bc4SBrooks Davis     const char* const argv[] = {"progname", "-ab3", "-ac", NULL};
467*b0d29bc4SBrooks Davis     const bool_option flag1('a', "flag1", "Description");
468*b0d29bc4SBrooks Davis     const string_option flag2('b', "flag2", "Description", "arg");
469*b0d29bc4SBrooks Davis     const string_option flag3('c', "flag2", "Description", "arg");
470*b0d29bc4SBrooks Davis     std::vector< const base_option* > options;
471*b0d29bc4SBrooks Davis     options.push_back(&flag1);
472*b0d29bc4SBrooks Davis     options.push_back(&flag2);
473*b0d29bc4SBrooks Davis     options.push_back(&flag3);
474*b0d29bc4SBrooks Davis 
475*b0d29bc4SBrooks Davis     try {
476*b0d29bc4SBrooks Davis         parse(argc, argv, options);
477*b0d29bc4SBrooks Davis         fail("missing_option_argument_error not raised");
478*b0d29bc4SBrooks Davis     } catch (const cmdline::missing_option_argument_error& e) {
479*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ("-c", e.option());
480*b0d29bc4SBrooks Davis     } catch (const cmdline::unknown_option_error& e) {
481*b0d29bc4SBrooks Davis         if (is_getopt_long_pluscolon_broken())
482*b0d29bc4SBrooks Davis             expect_fail("Your getopt_long is broken");
483*b0d29bc4SBrooks Davis         fail("Got unknown_option_error instead of "
484*b0d29bc4SBrooks Davis              "missing_option_argument_error");
485*b0d29bc4SBrooks Davis     }
486*b0d29bc4SBrooks Davis }
487*b0d29bc4SBrooks Davis 
488*b0d29bc4SBrooks Davis 
489*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(missing_option_argument_error__long);
ATF_TEST_CASE_BODY(missing_option_argument_error__long)490*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(missing_option_argument_error__long)
491*b0d29bc4SBrooks Davis {
492*b0d29bc4SBrooks Davis     const int argc = 3;
493*b0d29bc4SBrooks Davis     const char* const argv[] = {"progname", "--flag1=a", "--flag2", NULL};
494*b0d29bc4SBrooks Davis     const string_option flag1("flag1", "Description", "arg");
495*b0d29bc4SBrooks Davis     const string_option flag2("flag2", "Description", "arg");
496*b0d29bc4SBrooks Davis     std::vector< const base_option* > options;
497*b0d29bc4SBrooks Davis     options.push_back(&flag1);
498*b0d29bc4SBrooks Davis     options.push_back(&flag2);
499*b0d29bc4SBrooks Davis 
500*b0d29bc4SBrooks Davis     try {
501*b0d29bc4SBrooks Davis         parse(argc, argv, options);
502*b0d29bc4SBrooks Davis         fail("missing_option_argument_error not raised");
503*b0d29bc4SBrooks Davis     } catch (const cmdline::missing_option_argument_error& e) {
504*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ("--flag2", e.option());
505*b0d29bc4SBrooks Davis     } catch (const cmdline::unknown_option_error& e) {
506*b0d29bc4SBrooks Davis         if (is_getopt_long_pluscolon_broken())
507*b0d29bc4SBrooks Davis             expect_fail("Your getopt_long is broken");
508*b0d29bc4SBrooks Davis         fail("Got unknown_option_error instead of "
509*b0d29bc4SBrooks Davis              "missing_option_argument_error");
510*b0d29bc4SBrooks Davis     }
511*b0d29bc4SBrooks Davis }
512*b0d29bc4SBrooks Davis 
513*b0d29bc4SBrooks Davis 
514*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(unknown_option_error__short);
ATF_TEST_CASE_BODY(unknown_option_error__short)515*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(unknown_option_error__short)
516*b0d29bc4SBrooks Davis {
517*b0d29bc4SBrooks Davis     const int argc = 3;
518*b0d29bc4SBrooks Davis     const char* const argv[] = {"progname", "-a", "-b", NULL};
519*b0d29bc4SBrooks Davis     const bool_option flag1('a', "flag1", "Description");
520*b0d29bc4SBrooks Davis     std::vector< const base_option* > options;
521*b0d29bc4SBrooks Davis     options.push_back(&flag1);
522*b0d29bc4SBrooks Davis 
523*b0d29bc4SBrooks Davis     try {
524*b0d29bc4SBrooks Davis         parse(argc, argv, options);
525*b0d29bc4SBrooks Davis         fail("unknown_option_error not raised");
526*b0d29bc4SBrooks Davis     } catch (const cmdline::unknown_option_error& e) {
527*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ("-b", e.option());
528*b0d29bc4SBrooks Davis     }
529*b0d29bc4SBrooks Davis }
530*b0d29bc4SBrooks Davis 
531*b0d29bc4SBrooks Davis 
532*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(unknown_option_error__shortblock);
ATF_TEST_CASE_BODY(unknown_option_error__shortblock)533*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(unknown_option_error__shortblock)
534*b0d29bc4SBrooks Davis {
535*b0d29bc4SBrooks Davis     const int argc = 3;
536*b0d29bc4SBrooks Davis     const char* const argv[] = {"progname", "-a", "-bdc", NULL};
537*b0d29bc4SBrooks Davis     const bool_option flag1('a', "flag1", "Description");
538*b0d29bc4SBrooks Davis     const bool_option flag2('b', "flag2", "Description");
539*b0d29bc4SBrooks Davis     const bool_option flag3('c', "flag3", "Description");
540*b0d29bc4SBrooks Davis     std::vector< const base_option* > options;
541*b0d29bc4SBrooks Davis     options.push_back(&flag1);
542*b0d29bc4SBrooks Davis     options.push_back(&flag2);
543*b0d29bc4SBrooks Davis     options.push_back(&flag3);
544*b0d29bc4SBrooks Davis 
545*b0d29bc4SBrooks Davis     try {
546*b0d29bc4SBrooks Davis         parse(argc, argv, options);
547*b0d29bc4SBrooks Davis         fail("unknown_option_error not raised");
548*b0d29bc4SBrooks Davis     } catch (const cmdline::unknown_option_error& e) {
549*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ("-d", e.option());
550*b0d29bc4SBrooks Davis     }
551*b0d29bc4SBrooks Davis }
552*b0d29bc4SBrooks Davis 
553*b0d29bc4SBrooks Davis 
554*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(unknown_option_error__long);
ATF_TEST_CASE_BODY(unknown_option_error__long)555*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(unknown_option_error__long)
556*b0d29bc4SBrooks Davis {
557*b0d29bc4SBrooks Davis     const int argc = 3;
558*b0d29bc4SBrooks Davis     const char* const argv[] = {"progname", "--flag1=a", "--flag2", NULL};
559*b0d29bc4SBrooks Davis     const string_option flag1("flag1", "Description", "arg");
560*b0d29bc4SBrooks Davis     std::vector< const base_option* > options;
561*b0d29bc4SBrooks Davis     options.push_back(&flag1);
562*b0d29bc4SBrooks Davis 
563*b0d29bc4SBrooks Davis     try {
564*b0d29bc4SBrooks Davis         parse(argc, argv, options);
565*b0d29bc4SBrooks Davis         fail("unknown_option_error not raised");
566*b0d29bc4SBrooks Davis     } catch (const cmdline::unknown_option_error& e) {
567*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ("--flag2", e.option());
568*b0d29bc4SBrooks Davis     }
569*b0d29bc4SBrooks Davis }
570*b0d29bc4SBrooks Davis 
571*b0d29bc4SBrooks Davis 
572*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(unknown_plus_option_error);
ATF_TEST_CASE_BODY(unknown_plus_option_error)573*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(unknown_plus_option_error)
574*b0d29bc4SBrooks Davis {
575*b0d29bc4SBrooks Davis     const int argc = 2;
576*b0d29bc4SBrooks Davis     const char* const argv[] = {"progname", "-+", NULL};
577*b0d29bc4SBrooks Davis     const cmdline::options_vector options;
578*b0d29bc4SBrooks Davis 
579*b0d29bc4SBrooks Davis     try {
580*b0d29bc4SBrooks Davis         parse(argc, argv, options);
581*b0d29bc4SBrooks Davis         fail("unknown_option_error not raised");
582*b0d29bc4SBrooks Davis     } catch (const cmdline::unknown_option_error& e) {
583*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ("-+", e.option());
584*b0d29bc4SBrooks Davis     } catch (const cmdline::missing_option_argument_error& e) {
585*b0d29bc4SBrooks Davis         fail("Looks like getopt_long thinks a + option is defined and it "
586*b0d29bc4SBrooks Davis              "even requires an argument");
587*b0d29bc4SBrooks Davis     }
588*b0d29bc4SBrooks Davis }
589*b0d29bc4SBrooks Davis 
590*b0d29bc4SBrooks Davis 
591*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(option_types);
ATF_TEST_CASE_BODY(option_types)592*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(option_types)
593*b0d29bc4SBrooks Davis {
594*b0d29bc4SBrooks Davis     const int argc = 3;
595*b0d29bc4SBrooks Davis     const char* const argv[] = {"progname", "--flag1=a", "--flag2=one", NULL};
596*b0d29bc4SBrooks Davis     const string_option flag1("flag1", "The flag1", "arg");
597*b0d29bc4SBrooks Davis     const mock_option flag2("flag2");
598*b0d29bc4SBrooks Davis     std::vector< const base_option* > options;
599*b0d29bc4SBrooks Davis     options.push_back(&flag1);
600*b0d29bc4SBrooks Davis     options.push_back(&flag2);
601*b0d29bc4SBrooks Davis 
602*b0d29bc4SBrooks Davis     const parsed_cmdline cmdline = parse(argc, argv, options);
603*b0d29bc4SBrooks Davis 
604*b0d29bc4SBrooks Davis     ATF_REQUIRE(cmdline.has_option("flag1"));
605*b0d29bc4SBrooks Davis     ATF_REQUIRE(cmdline.has_option("flag2"));
606*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("a", cmdline.get_option< string_option >("flag1"));
607*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(1, cmdline.get_option< mock_option >("flag2"));
608*b0d29bc4SBrooks Davis }
609*b0d29bc4SBrooks Davis 
610*b0d29bc4SBrooks Davis 
611*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(option_validation_error);
ATF_TEST_CASE_BODY(option_validation_error)612*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(option_validation_error)
613*b0d29bc4SBrooks Davis {
614*b0d29bc4SBrooks Davis     const int argc = 3;
615*b0d29bc4SBrooks Davis     const char* const argv[] = {"progname", "--flag1=zero", "--flag2=foo",
616*b0d29bc4SBrooks Davis                                 NULL};
617*b0d29bc4SBrooks Davis     const mock_option flag1("flag1");
618*b0d29bc4SBrooks Davis     const mock_option flag2("flag2");
619*b0d29bc4SBrooks Davis     std::vector< const base_option* > options;
620*b0d29bc4SBrooks Davis     options.push_back(&flag1);
621*b0d29bc4SBrooks Davis     options.push_back(&flag2);
622*b0d29bc4SBrooks Davis 
623*b0d29bc4SBrooks Davis     try {
624*b0d29bc4SBrooks Davis         parse(argc, argv, options);
625*b0d29bc4SBrooks Davis         fail("option_argument_value_error not raised");
626*b0d29bc4SBrooks Davis     } catch (const cmdline::option_argument_value_error& e) {
627*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ("--flag2", e.option());
628*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ("foo", e.argument());
629*b0d29bc4SBrooks Davis     }
630*b0d29bc4SBrooks Davis }
631*b0d29bc4SBrooks Davis 
632*b0d29bc4SBrooks Davis 
633*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(silent_errors);
ATF_TEST_CASE_BODY(silent_errors)634*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(silent_errors)
635*b0d29bc4SBrooks Davis {
636*b0d29bc4SBrooks Davis     const int argc = 2;
637*b0d29bc4SBrooks Davis     const char* const argv[] = {"progname", "-h", NULL};
638*b0d29bc4SBrooks Davis     cmdline::options_vector options;
639*b0d29bc4SBrooks Davis 
640*b0d29bc4SBrooks Davis     try {
641*b0d29bc4SBrooks Davis         std::pair< int, int > oldfds = mock_stdfds("output.txt");
642*b0d29bc4SBrooks Davis         try {
643*b0d29bc4SBrooks Davis             parse(argc, argv, options);
644*b0d29bc4SBrooks Davis         } catch (...) {
645*b0d29bc4SBrooks Davis             restore_stdfds(oldfds);
646*b0d29bc4SBrooks Davis             throw;
647*b0d29bc4SBrooks Davis         }
648*b0d29bc4SBrooks Davis         restore_stdfds(oldfds);
649*b0d29bc4SBrooks Davis         fail("unknown_option_error not raised");
650*b0d29bc4SBrooks Davis     } catch (const cmdline::unknown_option_error& e) {
651*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ("-h", e.option());
652*b0d29bc4SBrooks Davis     }
653*b0d29bc4SBrooks Davis 
654*b0d29bc4SBrooks Davis     std::ifstream input("output.txt");
655*b0d29bc4SBrooks Davis     ATF_REQUIRE(input);
656*b0d29bc4SBrooks Davis 
657*b0d29bc4SBrooks Davis     bool has_output = false;
658*b0d29bc4SBrooks Davis     std::string line;
659*b0d29bc4SBrooks Davis     while (std::getline(input, line).good()) {
660*b0d29bc4SBrooks Davis         std::cout << line << '\n';
661*b0d29bc4SBrooks Davis         has_output = true;
662*b0d29bc4SBrooks Davis     }
663*b0d29bc4SBrooks Davis 
664*b0d29bc4SBrooks Davis     if (has_output)
665*b0d29bc4SBrooks Davis         fail("getopt_long printed messages on stdout/stderr by itself");
666*b0d29bc4SBrooks Davis }
667*b0d29bc4SBrooks Davis 
668*b0d29bc4SBrooks Davis 
ATF_INIT_TEST_CASES(tcs)669*b0d29bc4SBrooks Davis ATF_INIT_TEST_CASES(tcs)
670*b0d29bc4SBrooks Davis {
671*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, progname__no_options);
672*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, progname__some_options);
673*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, some_args__no_options);
674*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, some_args__some_options);
675*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, some_options__all_known);
676*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, some_options__multi);
677*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, subcommands);
678*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, missing_option_argument_error__short);
679*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, missing_option_argument_error__shortblock);
680*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, missing_option_argument_error__long);
681*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, unknown_option_error__short);
682*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, unknown_option_error__shortblock);
683*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, unknown_option_error__long);
684*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, unknown_plus_option_error);
685*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, option_types);
686*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, option_validation_error);
687*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, silent_errors);
688*b0d29bc4SBrooks Davis }
689