From 2caf587095892ff69da7b1a5a366e94c7d54ca25 Mon Sep 17 00:00:00 2001 From: Jakub Rzeszutko Date: Thu, 1 Jul 2021 11:50:16 +0200 Subject: [PATCH] tests: lib: getopt Add tests for the getopt library. Signed-off-by: Jakub Rzeszutko --- tests/posix/getopt/CMakeLists.txt | 8 + tests/posix/getopt/prj.conf | 5 + tests/posix/getopt/src/main.c | 359 ++++++++++++++++++++++++++++++ tests/posix/getopt/testcase.yaml | 9 + 4 files changed, 381 insertions(+) create mode 100644 tests/posix/getopt/CMakeLists.txt create mode 100644 tests/posix/getopt/prj.conf create mode 100644 tests/posix/getopt/src/main.c create mode 100644 tests/posix/getopt/testcase.yaml diff --git a/tests/posix/getopt/CMakeLists.txt b/tests/posix/getopt/CMakeLists.txt new file mode 100644 index 00000000000..75dc98a77ad --- /dev/null +++ b/tests/posix/getopt/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.13.1) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(getopt) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/posix/getopt/prj.conf b/tests/posix/getopt/prj.conf new file mode 100644 index 00000000000..034ce191ddf --- /dev/null +++ b/tests/posix/getopt/prj.conf @@ -0,0 +1,5 @@ +CONFIG_GETOPT=y +CONFIG_GETOPT_LONG=y +CONFIG_LOG=n +CONFIG_ZTEST=y +CONFIG_TEST_LOGGING_DEFAULTS=n diff --git a/tests/posix/getopt/src/main.c b/tests/posix/getopt/src/main.c new file mode 100644 index 00000000000..3c89ead3c65 --- /dev/null +++ b/tests/posix/getopt/src/main.c @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2021 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @file + * @brief Interactive getopt test suite + * + */ + +#include +#include +#include +#include + +static void test_getopt_basic(void) +{ + 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 +}; + +static void test_getopt(void) +{ + 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 +}; + +static void test_getopt_long(void) +{ + /* 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); +} + +static void test_getopt_long_only(void) +{ + /* 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); +} + +void test_main(void) +{ + ztest_test_suite(getopt_test_suite, + ztest_unit_test(test_getopt_basic), + ztest_unit_test(test_getopt), + ztest_unit_test(test_getopt_long), + ztest_unit_test(test_getopt_long_only) + ); + + ztest_run_test_suite(getopt_test_suite); +} diff --git a/tests/posix/getopt/testcase.yaml b/tests/posix/getopt/testcase.yaml new file mode 100644 index 00000000000..d677fa31bf1 --- /dev/null +++ b/tests/posix/getopt/testcase.yaml @@ -0,0 +1,9 @@ +tests: + shell.getopt: + tags: getopt + platform_exclude: native_posix native_posix_64 + integration_platforms: + - qemu_x86 + min_flash: 64 + min_ram: 32 + filter: (CONFIG_GETOPT and not CONFIG_NEWLIB_LIBC)