testing/ostest: Add a test of the getopt() family of interfaces.

This new test was used to verify the new implementations of getopt_long() and getopt_long_only() and to verify that there are no regressions to the existing getopts().

Only the OS test is affect by this change.

Verified with the getopt() modifications on a modified version of the sim:nsh configuration.
This commit is contained in:
Gregory Nutt 2021-04-01 14:17:07 -06:00 committed by Xiang Xiao
parent b9042a3666
commit 99138f6b39
4 changed files with 489 additions and 1 deletions

View File

@ -29,7 +29,7 @@ MODULE = $(CONFIG_TESTING_OSTEST)
# NuttX OS Test
CSRCS = dev_null.c restart.c sigprocmask.c sighand.c signest.c
CSRCS = getopt.c dev_null.c restart.c sigprocmask.c sighand.c signest.c
MAINSRC = ostest_main.c
ifeq ($(CONFIG_SIG_SIGSTOP_ACTION),y)

476
testing/ostest/getopt.c Normal file
View File

@ -0,0 +1,476 @@
/****************************************************************************
* apps/testing/ostest/getopt.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdio.h>
#include <getopt.h>
#include "ostest.h"
/****************************************************************************
* Pre-processor DEFINTIONS
****************************************************************************/
#define SHORT_RESULT_A(n) \
{ \
results[n].ret = 'a'; \
results[n].flag = 0; \
results[n].arg = NULL; \
}
#define SHORT_RESULT_B(n) \
{ \
results[n].ret = 'b'; \
results[n].flag = 0; \
results[n].arg = NULL; \
}
#define SHORT_RESULT_C1(n) \
{ \
results[n].ret = 'c'; \
results[n].flag = 0; \
results[n].arg = "Arg1"; \
}
#define SHORT_RESULT_C2(n) \
{ \
results[n].ret = 'c'; \
results[n].flag = 0; \
results[n].arg = NULL; \
}
#define SHORT_RESULT_D(n) \
{ \
results[n].ret = 'd'; \
results[n].flag = 0; \
results[n].arg = "Arg2"; \
}
#define LONG_OPTION_A(n) \
{ \
long_options[n].name = "OptionA"; \
long_options[n].has_arg = no_argument; \
long_options[n].flag = NULL; \
long_options[n].val = 'a'; \
}
#define LONG_OPTION_B(n) \
{ \
long_options[n].name = "OptionB"; \
long_options[n].has_arg = no_argument; \
long_options[n].flag = &g_flag; \
long_options[n].val = 'b'; \
}
#define LONG_OPTION_C(n) \
{ \
long_options[n].name = "OptionC"; \
long_options[n].has_arg = required_argument; \
long_options[n].flag = NULL; \
long_options[n].val = 'c'; \
}
#define LONG_OPTION_D(n) \
{ \
long_options[n].name = "OptionD"; \
long_options[n].has_arg = optional_argument; \
long_options[n].flag = &g_flag; \
long_options[n].val = 'd'; \
}
#define LONG_OPTION_END(n) \
{ \
long_options[n].name = NULL; \
long_options[n].has_arg = 0; \
long_options[n].flag = NULL; \
long_options[n].val = 0; \
}
#define LONG_RESULT_A(n) \
{ \
results[n].ret = 'a'; \
results[n].flag = 0; \
results[n].arg = NULL; \
}
#define LONG_RESULT_B(n) \
{ \
results[n].ret = OK; \
results[n].flag = 'b'; \
results[n].arg = NULL; \
}
#define LONG_RESULT_C(n) \
{ \
results[n].ret = 'c'; \
results[n].flag = 0; \
results[n].arg = "Arg1"; \
}
#define LONG_RESULT_D1(n) \
{ \
results[n].ret = OK; \
results[n].flag = 'd'; \
results[n].arg = "Arg2"; \
}
#define LONG_RESULT_D2(n) \
{ \
results[n].ret = OK; \
results[n].flag = 'd'; \
results[n].arg = NULL; \
}
/****************************************************************************
* Private Types
****************************************************************************/
struct result_s
{
int ret;
int flag;
FAR char *arg;
};
/****************************************************************************
* Private Data
****************************************************************************/
static int g_flag;
static const char *g_optstring = "abc::d:";
/****************************************************************************
* Private Functions
****************************************************************************/
static int getopt_short_test(int argc, FAR char **argv,
FAR const char *optstring,
FAR const struct result_s *expected)
{
int ndx;
int ret;
optarg = NULL;
for (ndx = 0;
(ret = getopt(argc, argv, g_optstring)) != ERROR;
ndx++)
{
if (optind < 1 || optind >= argc)
{
printf("ERROR: optind=%d\n", optind);
}
if (expected[ndx].ret != ret)
{
printf("ERROR: ret=%d (expected %d)\n",
ret, expected[ndx].ret);
}
if (expected[ndx].arg != optarg)
{
printf("ERROR: optarg=%s (expected %s)\n",
optarg == NULL ? "null" : optarg,
expected[ndx].arg == NULL ? "null" :
expected[ndx].arg);
}
optarg = NULL;
}
return OK;
}
static int getopt_long_test(int argc, FAR char **argv,
FAR const char *optstring,
FAR const struct option *longopts,
FAR int *longindex,
FAR const struct result_s *expected)
{
int ndx;
int ret;
optarg = NULL;
g_flag = 0;
for (ndx = 0;
(ret = getopt_long(argc, argv, g_optstring, longopts,
longindex)) != ERROR;
ndx++)
{
if (optind < 1 || optind > 7)
{
printf("ERROR: optind=%d\n", optind);
}
if (expected[ndx].ret != ret)
{
printf("ERROR: ret=%d (expected %d)\n",
ret, expected[ndx].ret);
}
if (expected[ndx].flag != g_flag)
{
printf("ERROR: flag=%d (expected %d)\n",
expected[ndx].flag, g_flag);
}
if (expected[ndx].arg != optarg)
{
printf("ERROR: optarg=%s (expected %s)\n",
optarg == NULL ? "null" : optarg,
expected[ndx].arg == NULL ? "null" :
expected[ndx].arg);
}
optarg = NULL;
g_flag = 0;
}
return OK;
}
static int getopt_longonly_test(int argc, FAR char **argv,
FAR const char *optstring,
FAR const struct option *longopts,
FAR int *longindex,
FAR const struct result_s *expected)
{
int ndx;
int ret;
optarg = NULL;
g_flag = 0;
for (ndx = 0;
(ret = getopt_long_only(argc, argv, g_optstring, longopts,
longindex)) != ERROR;
ndx++)
{
if (optind < 1 || optind > 7)
{
printf("ERROR: optind=%d\n", optind);
}
if (expected[ndx].ret != ret)
{
printf("ERROR: ret=%d (expected %d)\n",
ret, expected[ndx].ret);
}
if (expected[ndx].flag != g_flag)
{
printf("ERROR: flag=%d (expected %d)\n",
expected[ndx].flag, g_flag);
}
if (expected[ndx].arg != optarg)
{
printf("ERROR: optarg=%s (expected %s)\n",
optarg == NULL ? "null" : optarg,
expected[ndx].arg == NULL ? "null" :
expected[ndx].arg);
}
optarg = NULL;
g_flag = 0;
}
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
int getopt_test(void)
{
struct option long_options[5];
struct result_s results[4];
FAR char *argv[9];
printf("getopt(): Simple test\n");
argv[0] = NULL;
argv[1] = "-a";
argv[2] = "-b";
argv[3] = "-c";
argv[4] = "Arg1";
argv[5] = "-d";
argv[6] = "Arg2";
argv[7] = "NoOption";
argv[8] = NULL;
SHORT_RESULT_A(0);
SHORT_RESULT_B(1);
SHORT_RESULT_C1(2);
SHORT_RESULT_D(3);
getopt_short_test(8, argv, g_optstring, results);
printf("getopt(): Missing optional argument\n");
argv[0] = NULL;
argv[1] = "-a";
argv[2] = "-b";
argv[3] = "-c";
argv[4] = "-d";
argv[5] = "Arg2";
argv[6] = "NoOption";
argv[7] = NULL;
SHORT_RESULT_A(0);
SHORT_RESULT_B(1);
SHORT_RESULT_C2(2);
SHORT_RESULT_D(3);
getopt_short_test(7, argv, g_optstring, results);
printf("getopt_long(): Simple test\n");
argv[0] = NULL;
argv[1] = "--OptionA";
argv[2] = "--OptionB";
argv[3] = "--OptionC";
argv[4] = "Arg1";
argv[5] = "--OptionD";
argv[6] = "Arg2";
argv[7] = "NoOption";
argv[8] = NULL;
LONG_OPTION_A(0);
LONG_OPTION_B(1);
LONG_OPTION_C(2);
LONG_OPTION_D(3);
LONG_OPTION_END(4)
LONG_RESULT_A(0);
LONG_RESULT_B(1);
LONG_RESULT_C(2);
LONG_RESULT_D1(3);
getopt_long_test(8, argv, g_optstring, long_options, NULL,
results);
printf("getopt_long(): No short options\n");
getopt_long_test(8, argv, NULL, long_options, NULL,
results);
printf("getopt_long(): Mixed long and short options\n");
argv[0] = NULL;
argv[1] = "--OptionA";
argv[2] = "-b";
argv[3] = "--OptionC";
argv[4] = "Arg1";
argv[5] = "-d";
argv[6] = "Arg2";
argv[7] = "NoOption";
argv[8] = NULL;
LONG_OPTION_A(0);
LONG_OPTION_C(1);
LONG_OPTION_END(2)
LONG_RESULT_A(0);
SHORT_RESULT_B(1);
LONG_RESULT_C(2);
SHORT_RESULT_D(3);
getopt_long_test(8, argv, g_optstring, long_options, NULL,
results);
printf("getopt_long(): Missing optional arguments\n");
argv[0] = NULL;
argv[1] = "--OptionA";
argv[2] = "--OptionB";
argv[3] = "-c";
argv[4] = "--OptionD";
argv[5] = NULL;
LONG_OPTION_A(0);
LONG_OPTION_B(1);
LONG_OPTION_D(2);
LONG_OPTION_END(3)
LONG_RESULT_A(0);
LONG_RESULT_B(1);
SHORT_RESULT_C2(2);
LONG_RESULT_D2(3);
getopt_long_test(6, argv, g_optstring, long_options, NULL,
results);
printf("getopt_long_only(): Mixed long and short options\n");
argv[0] = NULL;
argv[1] = "-a";
argv[2] = "--OptionB";
argv[3] = "-c";
argv[4] = "Arg1";
argv[5] = "--OptionD";
argv[6] = "Arg2";
argv[7] = "NoOption";
argv[8] = NULL;
LONG_OPTION_B(0);
LONG_OPTION_D(1);
LONG_OPTION_END(2)
SHORT_RESULT_A(0);
LONG_RESULT_B(1);
SHORT_RESULT_C1(2);
LONG_RESULT_D1(3);
getopt_longonly_test(8, argv, g_optstring, long_options, NULL,
results);
printf("getopt_long_only(): Single hyphen long options\n");
argv[0] = NULL;
argv[1] = "-OptionA";
argv[2] = "-b";
argv[3] = "--OptionC";
argv[4] = "Arg1";
argv[5] = "-d";
argv[6] = "Arg2";
argv[7] = "NoOption";
argv[8] = NULL;
LONG_OPTION_A(0);
LONG_OPTION_C(1);
LONG_OPTION_END(2)
LONG_RESULT_A(0);
SHORT_RESULT_B(1);
LONG_RESULT_C(2);
SHORT_RESULT_D(3);
getopt_longonly_test(8, argv, g_optstring, long_options, NULL,
results);
return OK;
}

View File

@ -92,6 +92,10 @@
* Public Function Prototypes
****************************************************************************/
/* getopt.c *****************************************************************/
int getopt_test(void);
/* setvbuf.c ****************************************************************/
#ifndef CONFIG_STDIO_DISABLE_BUFFERING

View File

@ -246,6 +246,14 @@ static int user_main(int argc, char *argv[])
check_test_memory_usage();
/* Test additional getopt(), getopt_long(), and getopt_long_only()
* features.
*/
printf("\nuser_main: getopt() test\n");
getopt_test();
check_test_memory_usage();
/* If retention of child status is enable, then suppress it for this task.
* This task may produce many, many children (especially if
* CONFIG_TESTING_OSTEST_LOOPS) and it does not harvest their exit status.