summaryrefslogtreecommitdiff
path: root/ACE/tests/Get_Opt_Test.cpp
blob: 7ba700aa89c52c4ea7871a247c63a32d2c759f1e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
// ============================================================================
//
// = LIBRARY
//    tests
//
// = DESCRIPTION
//    This program tests both the short and long option support in
//    <ACE_Get_Opt>, and demonstrates how to use it.
//
// = AUTHOR
//    Don Hinton <dhinton@dresystems.com>
//
// ============================================================================

#include "test_config.h"
#include "ace/Get_Opt.h"
#include "ace/ARGV.h"
#include "ace/SString.h"
#include "ace/OS_NS_stdlib.h"
#include "test_config.h"



/*
 * This is the heart of the test. It sets up the optstring, instantiates
 * ACE_Get_Opt, add long options, processes them in a loop, and prints out
 * the results to the log.
 *
 * It returns 0 for success and 1 for error so we can keep track of the
 * total error count.
 */

static const ACE_TString empty_string (ACE_TEXT (""));

static int
parse_args (int test_number,
            int ordering,
            const ACE_TCHAR *test_args,
            int skip_argv = 1,
            int report_errors = 1,
            const ACE_TString &opt_prefix = empty_string)
{
  ACE_TString test;
  ACE_TString optstring (opt_prefix);

  // Test the skip_argv for the first test only.
  if (skip_argv > 0)
    {
      test = ACE_TEXT ("Test_");
      ACE_TCHAR s[20];
      test += ACE_OS::itoa (test_number, s, 10);
      test += ACE_TEXT (" ");
    }

  test += test_args;
  optstring += ACE_TEXT ("fr:o::sW;");

  ACE_DEBUG ((LM_INFO,
              ACE_TEXT (" TEST %d   *****************************************")
              ACE_TEXT ("*******************\n"),
              test_number));
  ACE_DEBUG ((LM_INFO, "   Command line: \"%s\"\n", test.c_str ()));

  ACE_ARGV args (test.c_str ());

  ACE_Get_Opt get_opt (args.argc (),
                       args.argv (),
                       optstring.c_str (),
                       skip_argv,
                       report_errors,
                       ordering);

  // Now add the default long args.
  if (get_opt.long_option (ACE_TEXT ("flag"),
                           'f',
                           ACE_Get_Opt::NO_ARG) != 0)
    ACE_ERROR_RETURN ((LM_ERROR,
                       ACE_TEXT ("  Unable to add long option 'f'\n")), 1);

  if (get_opt.long_option (ACE_TEXT ("requires_arg"),
                           'r',
                           ACE_Get_Opt::ARG_REQUIRED) != 0)
    ACE_ERROR_RETURN ((LM_ERROR,
                       ACE_TEXT ("  Unable to add long option 'r'\n")), 1);

  if (get_opt.long_option (ACE_TEXT ("optional_arg"),
                           'o',
                           ACE_Get_Opt::ARG_OPTIONAL) != 0)
    ACE_ERROR_RETURN ((LM_ERROR,
                       ACE_TEXT ("  Unable to add long option 'o'\n")), 1);

  if (get_opt.long_option (ACE_TEXT ("long_option"),
                           'l',
                           ACE_Get_Opt::ARG_OPTIONAL) != 0)
    ACE_ERROR_RETURN ((LM_ERROR,
                       ACE_TEXT ("  Unable to add long option 'l'\n")), 1);

  if (get_opt.long_option (ACE_TEXT ("long_only"),
                           -11,
                           ACE_Get_Opt::ARG_REQUIRED) != 0)
    ACE_ERROR_RETURN ((LM_ERROR,
                       ACE_TEXT ("  Unable to add long option ")
                       ACE_TEXT ("\"long_only\"\n")), 1);

  if (get_opt.long_option (ACE_TEXT ("long_no_arg")) != 0)
    ACE_ERROR_RETURN ((LM_ERROR,
                       ACE_TEXT ("  Unable to add long option ")
                       ACE_TEXT ("\"long_no_arg\"\n")), 1);

  // This is the special case of providing a non-alpha numeric corresponding
  // short option.  This lets you use the corresponding short option in a
  // switch statement, even thought a meaningful short options isn't available
  // (afterall, there are only so many alpha numeric characters available).
  if (get_opt.long_option (ACE_TEXT ("non_alpha-num_short"),
                           -10,
                           ACE_Get_Opt::ARG_OPTIONAL) != 0)
    ACE_ERROR_RETURN ((LM_ERROR,
                       ACE_TEXT ("  Unable to add long option ")
                       ACE_TEXT ("\"non_alpha_short\"\n")), 1);

  // We print out the optstring here because adding long_options that
  // have corresponding short options that aren't yet present, are added.
  ACE_DEBUG ((LM_INFO,
              ACE_TEXT ("      optstring: \"%s\"  skip_argv: %d\n"),
              get_opt.optstring (),  skip_argv));

  // Now, let's parse it...
  int c = 0;
  while ((c = get_opt ()) != EOF)
    {
      switch (c)
        {
        case 0:
          // Long Option.
          if (!get_opt.long_option ())
            ACE_ERROR_RETURN ((LM_ERROR, "  Long option doesn't exist.\n"), 1);

          ACE_DEBUG ((LM_INFO, "   Found long option \"%s\" %s %s\n",
                      get_opt.long_option (),
                      get_opt.opt_arg () ? ACE_TEXT ("with argument:")
                                         : ACE_TEXT (""),
                      get_opt.opt_arg () ? get_opt.opt_arg ()
                                         : ACE_TEXT ("")));
          break;
        case 'f':
          // This flag was added in both the optstring in the ctor and with
          // long_option().
        case 's':
          // This one is only short and has no long option.
          ACE_DEBUG ((LM_INFO, "   Found option flag '%s'\n",
                      get_opt.last_option ()));
          break;
        case 'r':
          // This one has a required argument, we wouldn't be here if the
          // arg were missing.  Note that we call get_opt.opt_arg () to return
          // the argument, but we could have used get_opt.opt_arg () since
          // opt_arg () is defined as "opt_arg ()".
          ACE_DEBUG ((LM_INFO,
                      "   Found option '%s' with required argument \"%s\"\n",
                      get_opt.last_option (), get_opt.opt_arg ()));
          break;
        case 'o':
          // This one has an optional argument.
        case 'l':
          // This short options was set automatically added to optstring.
          ACE_DEBUG ((LM_INFO,
                      "   Found option '%s' with optional argument \"%s\"\n",
                      get_opt.last_option (),
                      get_opt.opt_arg () ? get_opt.opt_arg ()
                                         : ACE_TEXT ("default")));
          break;
        case 1:
          // Non-option when in RETURN_IN_ORDER mode.
          ACE_DEBUG ((LM_INFO,
                      "   Found a non-option argument \"%s\" before finding "
                      "\"--\" (must be in RETURN_IN_ORDER mode).\n",
                      get_opt.opt_arg ()));
          break;
        case -10:
          // we found the short option that isn't alpha numeric.
          ACE_DEBUG ((LM_INFO,
                      "   Found option '%s' with optional argument \"%s\"\n",
                      get_opt.last_option (),
                      get_opt.opt_arg () ? get_opt.opt_arg ()
                                         : ACE_TEXT ("default")));
          break;
        case -11:
          // we found the short option that isn't alpha numeric.
          ACE_DEBUG ((LM_INFO,
                      "   Found option '%s' with argument \"%s\"\n",
                      get_opt.last_option (), get_opt.opt_arg ()));
          break;
        case ':':
          // This means an option requiring an argument didn't have one.
          ACE_DEBUG ((LM_INFO,
                      ACE_TEXT ("   Option '%c' (%s) requires an argument ")
                      ACE_TEXT ("but none was supplied\n"),
                      get_opt.opt_opt (), get_opt.last_option ()));
          break;
        case '?':
          // An unrecognized option.
        default:
          // This is an error, perhaps you could handle them, but let's
          // just log it and keep going
          ACE_DEBUG ((LM_INFO,
                      "  Found an unknown option (%s) we couldn't handle.\n",
                      get_opt.last_option ()));
        }
    }

  // Print out the rest of the arguments left in the command line (if any).
  int index = 0;
  for (index = get_opt.opt_ind (); index < args.argc (); index++)
    ACE_DEBUG ((LM_INFO, "   Found non-option argument \"%s\"\n",
                args.argv ()[index]));

  // Now print them all so we can examine the permuted cmd line.
  for (index = 0; index < args.argc (); index++)
    ACE_DEBUG ((LM_INFO, "   argv[%u] \"%s\"\n",
                index, args.argv ()[index]));
  return 0;
}

/*
 * Add new tests cases here.  We increment the test number and pass the
 * type of ordering we want so that each test can be tested with multiple
 * ordering values in order to demostrate the difference.
 *
 * The return value is cumulative, and serves as a failure count that is
 * returned at the end of all the tests.
 */
static int
run_test (int& test_number, int ordering)
{
  int retval = 0;

  ACE_DEBUG ((LM_INFO,
              " ##########   Running Tests with ordering = %C   ##########\n",
              ordering == 1 ? "REQUIRE_ORDER" :
                              ordering == 2 ? "PERMUTE_ARGS" :
                                              "RETURN_IN_ORDER"));

  // Basic test, but don't use the program name and don't skip any args.
  retval += parse_args
    (test_number++, ordering,
     ACE_TEXT ("-f -rreq-arg -oopt-arg -lopt-arg --long_only=lo_arg -s arg1 arg2"),
     0);

  // Same, but combining short args that don't take args
  retval += parse_args
    (test_number++, ordering,
     ACE_TEXT ("-fsrreq-arg -oopt-arg -lopt-arg --long_only=lo_arg arg1 arg2"));

  // Now we use defaults for options with optional args.
  retval += parse_args
    (test_number++, ordering,
     ACE_TEXT ("-fsrreq-arg -o -l --long_only=lo_arg arg1 arg2"));

  // Let's mix up the options and non-options an see what happens.
  retval += parse_args
    (test_number++, ordering,
     ACE_TEXT ("-fs arg1 -rreq-arg -o arg2 -l --long_only=lo_arg"));

  // Now we turn off options parsing explicitely by passing "--" in the middle.
  retval += parse_args
    (test_number++, ordering,
     ACE_TEXT ("-fs -rreq-arg -- arg1 -o arg2 -l --long_only=lo_arg"));

  // Let's try the same thing but mix up the options and non-options.
  retval += parse_args
    (test_number++, ordering,
     ACE_TEXT ("-fs arg1 arg2 -rreq-arg -- arg3 -o"));

  // One more time but with "-W".
  retval += parse_args
    (test_number++, ordering,
     ACE_TEXT ("-fs arg1 arg2 -rreq-arg -W long_option=opt-arg -- arg3 -o"));

  // Let's pass some long options.
  retval += parse_args
    (test_number++, ordering,
     ACE_TEXT ("--flag -s --requires_arg=req-arg --optional_arg --long_only lo_arg arg1 arg2"));

  // And long options without the '='.
  retval += parse_args
    (test_number++, ordering,
     ACE_TEXT ("--flag -s --requires_arg req-arg --optional_arg --long_only=lo_arg arg1 arg2"));

  // Pass "-W" to cause the next argument to be read as a long option.
  retval += parse_args
    (test_number++, ordering,
     ACE_TEXT ("-fso -W requires_arg=req-arg -Woptional_arg -l arg1 arg2"));

  // This is the special case of a non-alpha numeric short option.
  retval += parse_args
    (test_number++, ordering,
     ACE_TEXT ("-fso --non_alpha-num_short=xxx arg1 arg2"));

  // Now, let's test some error conditions (we turn off report_errors since they are
  // intentional, we don't want to break the test script)
  int report_errors = 0;

  // Bad short option.
  retval += parse_args (test_number++, ordering, ACE_TEXT ("-X"), 1, report_errors);

  // Short option with missing required arg.
  ACE_TString report_missing (ACE_TEXT (":"));
  retval += parse_args (test_number++, ordering, ACE_TEXT ("-r"), 1, report_errors, report_missing);

  // Short option with missing required arg with trailing "--".
  // This reads "--" as the arg, but should it?
  retval += parse_args (test_number++, ordering, ACE_TEXT ("-r --"), 1, report_errors);

  // Long option with missing required arg.
  retval += parse_args (test_number++, ordering, ACE_TEXT ("--long_only"), 1, report_errors);

  // Long option that doesn't take an arg has one.
  retval += parse_args (test_number++, ordering, ACE_TEXT ("--long_no_arg=bad_arg"), 1, report_errors);

  // Unknown long option.
  retval += parse_args (test_number++, ordering, ACE_TEXT ("--unknown"), 1, report_errors);

  // Ambigous long option.
  retval += parse_args (test_number++, ordering, ACE_TEXT ("--long"), 1, report_errors);

  return retval;
}

int
run_main (int, ACE_TCHAR *argv[])
{
  ACE_START_TEST (ACE_TEXT ("Get_Opt_Test"));
  ACE_UNUSED_ARG (argv);
  int retval = 0;
  int test_number = 0;

  // Run the tests for each type of ordering.
  retval = run_test (test_number, ACE_Get_Opt::PERMUTE_ARGS);
  retval += run_test (test_number, ACE_Get_Opt::REQUIRE_ORDER);
  retval += run_test (test_number, ACE_Get_Opt::RETURN_IN_ORDER);

  ACE_END_TEST;
  return retval;
}