blob: 158d0dd085ef31b104a2ed656299b9dcf3b88e75 [file] [log] [blame]
/*
* Copyright (c) 2021 Nordic Semiconductor
*
* SPDX-License-Identifier: Apache-2.0
*/
/** @file
* @brief Interactive getopt test suite
*
*/
#include <zephyr/kernel.h>
#include <zephyr/ztest.h>
#include <string.h>
#include <zephyr/posix/unistd.h>
#include <getopt.h>
ZTEST_SUITE(getopt_test_suite, NULL, NULL, NULL, NULL, NULL);
ZTEST(getopt_test_suite, test_getopt_basic)
{
static const char *const nargv[] = {
"cmd_name",
"-b",
"-a",
"-h",
"-c",
"-l",
"-h",
"-a",
"-i",
"-w",
};
static const char *accepted_opt = "abchw";
static const char *expected = "bahc?ha?w";
size_t argc = ARRAY_SIZE(nargv);
int cnt = 0;
int c;
char **argv;
argv = (char **)nargv;
/* Get state of the current thread */
getopt_init();
do {
c = getopt(argc, argv, accepted_opt);
if (cnt >= strlen(expected)) {
break;
}
zassert_equal(c, expected[cnt++], "unexpected opt character");
} while (c != -1);
c = getopt(argc, argv, accepted_opt);
zassert_equal(c, -1, "unexpected opt character");
}
enum getopt_idx {
GETOPT_IDX_CMD_NAME,
GETOPT_IDX_OPTION1,
GETOPT_IDX_OPTION2,
GETOPT_IDX_OPTARG
};
ZTEST(getopt_test_suite, test_getopt)
{
struct getopt_state *state;
static const char *test_opts = "ac:";
static const char *const nargv[] = {
[GETOPT_IDX_CMD_NAME] = "cmd_name",
[GETOPT_IDX_OPTION1] = "-a",
[GETOPT_IDX_OPTION2] = "-c",
[GETOPT_IDX_OPTARG] = "foo",
};
int argc = ARRAY_SIZE(nargv);
char **argv;
int c;
/* Get state of the current thread */
getopt_init();
argv = (char **)nargv;
/* Test uknown option */
c = getopt(argc, argv, test_opts);
zassert_equal(c, 'a', "unexpected opt character");
c = getopt(argc, argv, test_opts);
zassert_equal(c, 'c', "unexpected opt character");
c = getopt(argc, argv, test_opts);
state = getopt_state_get();
/* Thread safe usge: */
zassert_equal(0, strcmp(argv[GETOPT_IDX_OPTARG], state->optarg),
"unexpected optarg result");
/* Non thread safe usage: */
zassert_equal(0, strcmp(argv[GETOPT_IDX_OPTARG], optarg),
"unexpected optarg result");
}
enum getopt_long_idx {
GETOPT_LONG_IDX_CMD_NAME,
GETOPT_LONG_IDX_VERBOSE,
GETOPT_LONG_IDX_OPT,
GETOPT_LONG_IDX_OPTARG
};
ZTEST(getopt_test_suite, test_getopt_long)
{
/* Below test is based on example
* https://www.gnu.org/software/libc/manual/html_node/Getopt-Long-Option-Example.html
*/
struct getopt_state *state;
int verbose_flag = 0;
/* getopt_long stores the option index here. */
int option_index = 0;
char **argv;
int c;
struct option long_options[] = {
/* These options set a flag. */
{"verbose", no_argument, &verbose_flag, 1},
{"brief", no_argument, &verbose_flag, 0},
/* These options don’t set a flag.
* We distinguish them by their indices.
*/
{"add", no_argument, 0, 'a'},
{"create", required_argument, 0, 'c'},
{"delete", required_argument, 0, 'd'},
{"long", required_argument, 0, 'e'},
{0, 0, 0, 0}
};
static const char *accepted_opt = "ac:d:e:";
static const char *const argv1[] = {
[GETOPT_LONG_IDX_CMD_NAME] = "cmd_name",
[GETOPT_LONG_IDX_VERBOSE] = "--verbose",
[GETOPT_LONG_IDX_OPT] = "--create",
[GETOPT_LONG_IDX_OPTARG] = "some_file",
};
int argc1 = ARRAY_SIZE(argv1);
static const char *const argv2[] = {
[GETOPT_LONG_IDX_CMD_NAME] = "cmd_name",
[GETOPT_LONG_IDX_VERBOSE] = "--brief",
[GETOPT_LONG_IDX_OPT] = "-d",
[GETOPT_LONG_IDX_OPTARG] = "other_file",
};
int argc2 = ARRAY_SIZE(argv2);
static const char *const argv3[] = {
[GETOPT_LONG_IDX_CMD_NAME] = "cmd_name",
[GETOPT_LONG_IDX_VERBOSE] = "--brief",
[GETOPT_LONG_IDX_OPT] = "-a",
};
int argc3 = ARRAY_SIZE(argv3);
/* this test distinguish getopt_long and getopt_long_only functions */
static const char *const argv4[] = {
[GETOPT_LONG_IDX_CMD_NAME] = "cmd_name",
[GETOPT_LONG_IDX_VERBOSE] = "--brief",
/* below should not be interpreted as "--long/-e" option */
[GETOPT_LONG_IDX_OPT] = "-l",
[GETOPT_LONG_IDX_OPTARG] = "long_argument",
};
int argc4 = ARRAY_SIZE(argv4);
/* Test scenario 1 */
/* Get state of the current thread */
getopt_init();
argv = (char **)argv1;
c = getopt_long(argc1, argv, accepted_opt,
long_options, &option_index);
zassert_equal(verbose_flag, 1, "verbose flag expected");
c = getopt_long(argc1, argv, accepted_opt, long_options, &option_index);
state = getopt_state_get();
zassert_equal('c', c, "unexpected option");
zassert_equal(0, strcmp(state->optarg, argv[GETOPT_LONG_IDX_OPTARG]),
"unexpected optarg");
c = getopt_long(argc1, argv, accepted_opt,
long_options, &option_index);
zassert_equal(-1, c, "getopt_long shall return -1");
/* Test scenario 2 */
argv = (char **)argv2;
getopt_init();
c = getopt_long(argc2, argv, accepted_opt,
long_options, &option_index);
zassert_equal(verbose_flag, 0, "verbose flag expected");
c = getopt_long(argc2, argv, accepted_opt,
long_options, &option_index);
zassert_equal('d', c, "unexpected option");
state = getopt_state_get();
zassert_equal(0, strcmp(state->optarg, argv[GETOPT_LONG_IDX_OPTARG]),
"unexpected optarg");
c = getopt_long(argc2, argv, accepted_opt,
long_options, &option_index);
zassert_equal(-1, c, "getopt_long shall return -1");
/* Test scenario 3 */
argv = (char **)argv3;
getopt_init();
c = getopt_long(argc3, argv, accepted_opt,
long_options, &option_index);
zassert_equal(verbose_flag, 0, "verbose flag expected");
c = getopt_long(argc3, argv, accepted_opt,
long_options, &option_index);
zassert_equal('a', c, "unexpected option");
c = getopt_long(argc3, argv, accepted_opt,
long_options, &option_index);
zassert_equal(-1, c, "getopt_long shall return -1");
/* Test scenario 4 */
argv = (char **)argv4;
getopt_init();
c = getopt_long(argc4, argv, accepted_opt,
long_options, &option_index);
zassert_equal(verbose_flag, 0, "verbose flag expected");
c = getopt_long(argc4, argv, accepted_opt,
long_options, &option_index);
/* Function was called with option '-l'. It is expected it will be
* NOT evaluated to '--long' which has flag 'e'.
*/
zassert_not_equal('e', c, "unexpected option match");
c = getopt_long(argc4, argv, accepted_opt,
long_options, &option_index);
}
ZTEST(getopt_test_suite, test_getopt_long_only)
{
/* Below test is based on example
* https://www.gnu.org/software/libc/manual/html_node/Getopt-Long-Option-Example.html
*/
struct getopt_state *state;
int verbose_flag = 0;
/* getopt_long stores the option index here. */
int option_index = 0;
char **argv;
int c;
struct option long_options[] = {
/* These options set a flag. */
{"verbose", no_argument, &verbose_flag, 1},
{"brief", no_argument, &verbose_flag, 0},
/* These options don’t set a flag.
* We distinguish them by their indices.
*/
{"add", no_argument, 0, 'a'},
{"create", required_argument, 0, 'c'},
{"delete", required_argument, 0, 'd'},
{"long", required_argument, 0, 'e'},
{0, 0, 0, 0}
};
static const char *accepted_opt = "ac:d:e:";
static const char *const argv1[] = {
[GETOPT_LONG_IDX_CMD_NAME] = "cmd_name",
[GETOPT_LONG_IDX_VERBOSE] = "--verbose",
[GETOPT_LONG_IDX_OPT] = "--create",
[GETOPT_LONG_IDX_OPTARG] = "some_file",
};
int argc1 = ARRAY_SIZE(argv1);
static const char *const argv2[] = {
[GETOPT_LONG_IDX_CMD_NAME] = "cmd_name",
[GETOPT_LONG_IDX_VERBOSE] = "--brief",
[GETOPT_LONG_IDX_OPT] = "-d",
[GETOPT_LONG_IDX_OPTARG] = "other_file",
};
int argc2 = ARRAY_SIZE(argv2);
static const char *const argv3[] = {
[GETOPT_LONG_IDX_CMD_NAME] = "cmd_name",
[GETOPT_LONG_IDX_VERBOSE] = "--brief",
[GETOPT_LONG_IDX_OPT] = "-a",
};
int argc3 = ARRAY_SIZE(argv3);
/* this test distinguish getopt_long and getopt_long_only functions */
static const char *const argv4[] = {
[GETOPT_LONG_IDX_CMD_NAME] = "cmd_name",
[GETOPT_LONG_IDX_VERBOSE] = "--brief",
/* below should be interpreted as "--long/-e" option */
[GETOPT_LONG_IDX_OPT] = "-l",
[GETOPT_LONG_IDX_OPTARG] = "long_argument",
};
int argc4 = ARRAY_SIZE(argv4);
/* Test scenario 1 */
argv = (char **)argv1;
getopt_init();
c = getopt_long_only(argc1, argv, accepted_opt,
long_options, &option_index);
zassert_equal(verbose_flag, 1, "verbose flag expected");
c = getopt_long_only(argc1, argv, accepted_opt,
long_options, &option_index);
state = getopt_state_get();
zassert_equal('c', c, "unexpected option");
zassert_equal(0, strcmp(state->optarg, argv[GETOPT_LONG_IDX_OPTARG]),
"unexpected optarg");
c = getopt_long_only(argc1, argv, accepted_opt,
long_options, &option_index);
zassert_equal(-1, c, "getopt_long_only shall return -1");
/* Test scenario 2 */
argv = (char **)argv2;
getopt_init();
state = getopt_state_get();
c = getopt_long_only(argc2, argv, accepted_opt,
long_options, &option_index);
zassert_equal(verbose_flag, 0, "verbose flag expected");
c = getopt_long_only(argc2, argv, accepted_opt,
long_options, &option_index);
state = getopt_state_get();
zassert_equal('d', c, "unexpected option");
zassert_equal(0, strcmp(state->optarg, argv[GETOPT_LONG_IDX_OPTARG]),
"unexpected optarg");
c = getopt_long_only(argc2, argv, accepted_opt,
long_options, &option_index);
zassert_equal(-1, c, "getopt_long_only shall return -1");
/* Test scenario 3 */
argv = (char **)argv3;
getopt_init();
c = getopt_long_only(argc3, argv, accepted_opt,
long_options, &option_index);
zassert_equal(verbose_flag, 0, "verbose flag expected");
c = getopt_long_only(argc3, argv, accepted_opt,
long_options, &option_index);
zassert_equal('a', c, "unexpected option");
c = getopt_long_only(argc3, argv, accepted_opt,
long_options, &option_index);
zassert_equal(-1, c, "getopt_long_only shall return -1");
/* Test scenario 4 */
argv = (char **)argv4;
getopt_init();
c = getopt_long_only(argc4, argv, accepted_opt,
long_options, &option_index);
zassert_equal(verbose_flag, 0, "verbose flag expected");
c = getopt_long_only(argc4, argv, accepted_opt,
long_options, &option_index);
/* Function was called with option '-l'. It is expected it will be
* evaluated to '--long' which has flag 'e'.
*/
zassert_equal('e', c, "unexpected option");
c = getopt_long_only(argc4, argv, accepted_opt,
long_options, &option_index);
}