From bd5969fc876a10b18613302db7087ef3c40f18e1 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Thu, 7 Mar 2024 17:28:00 -0500 Subject: lib: Add mlibc Signed-off-by: Ian Moffett --- lib/mlibc/tests/glibc/error.c | 6 + lib/mlibc/tests/glibc/error.py | 11 + lib/mlibc/tests/glibc/error_at_line.c | 6 + lib/mlibc/tests/glibc/error_at_line.py | 11 + lib/mlibc/tests/glibc/error_expect_fail.c | 6 + lib/mlibc/tests/glibc/error_message_count.c | 11 + lib/mlibc/tests/glibc/error_one_per_line.c | 13 ++ lib/mlibc/tests/glibc/error_print_progname.c | 19 ++ lib/mlibc/tests/glibc/ffsl-ffsll.c | 36 ++++ lib/mlibc/tests/glibc/getopt.c | 288 +++++++++++++++++++++++++++ lib/mlibc/tests/glibc/gnu-basename.c | 13 ++ lib/mlibc/tests/glibc/linux-syscall.c | 14 ++ 12 files changed, 434 insertions(+) create mode 100644 lib/mlibc/tests/glibc/error.c create mode 100644 lib/mlibc/tests/glibc/error.py create mode 100644 lib/mlibc/tests/glibc/error_at_line.c create mode 100644 lib/mlibc/tests/glibc/error_at_line.py create mode 100644 lib/mlibc/tests/glibc/error_expect_fail.c create mode 100644 lib/mlibc/tests/glibc/error_message_count.c create mode 100644 lib/mlibc/tests/glibc/error_one_per_line.c create mode 100644 lib/mlibc/tests/glibc/error_print_progname.c create mode 100644 lib/mlibc/tests/glibc/ffsl-ffsll.c create mode 100644 lib/mlibc/tests/glibc/getopt.c create mode 100644 lib/mlibc/tests/glibc/gnu-basename.c create mode 100644 lib/mlibc/tests/glibc/linux-syscall.c (limited to 'lib/mlibc/tests/glibc') diff --git a/lib/mlibc/tests/glibc/error.c b/lib/mlibc/tests/glibc/error.c new file mode 100644 index 0000000..2ae752a --- /dev/null +++ b/lib/mlibc/tests/glibc/error.c @@ -0,0 +1,6 @@ +#include +#include + +int main() { + error(0, EINVAL, "test: %s", "error"); +} diff --git a/lib/mlibc/tests/glibc/error.py b/lib/mlibc/tests/glibc/error.py new file mode 100644 index 0000000..3833974 --- /dev/null +++ b/lib/mlibc/tests/glibc/error.py @@ -0,0 +1,11 @@ +import subprocess +import sys +import os +from pyexpect import expect + +wrapper = os.getenv("MESON_EXE_WRAPPER") +wrapper = [x for x in (wrapper,) if x] + +output = subprocess.check_output(wrapper + [sys.argv[1]], stderr=subprocess.STDOUT) + +expect(bytes(sys.argv[1], 'utf-8') + b': test: error: Invalid argument (EINVAL)\n').to_equal(output) diff --git a/lib/mlibc/tests/glibc/error_at_line.c b/lib/mlibc/tests/glibc/error_at_line.c new file mode 100644 index 0000000..257ddd2 --- /dev/null +++ b/lib/mlibc/tests/glibc/error_at_line.c @@ -0,0 +1,6 @@ +#include +#include + +int main() { + error_at_line(0, EINVAL, "error_at_line", 5, "test: %s", "error"); +} diff --git a/lib/mlibc/tests/glibc/error_at_line.py b/lib/mlibc/tests/glibc/error_at_line.py new file mode 100644 index 0000000..7499e05 --- /dev/null +++ b/lib/mlibc/tests/glibc/error_at_line.py @@ -0,0 +1,11 @@ +import subprocess +import sys +import os +from pyexpect import expect + +wrapper = os.getenv("MESON_EXE_WRAPPER") +wrapper = [x for x in (wrapper,) if x] + +output = subprocess.check_output(wrapper + [sys.argv[1]], stderr=subprocess.STDOUT) + +expect(bytes(sys.argv[1], 'utf-8') + b':error_at_line:5: test: error: Invalid argument (EINVAL)\n').to_equal(output) diff --git a/lib/mlibc/tests/glibc/error_expect_fail.c b/lib/mlibc/tests/glibc/error_expect_fail.c new file mode 100644 index 0000000..17f0907 --- /dev/null +++ b/lib/mlibc/tests/glibc/error_expect_fail.c @@ -0,0 +1,6 @@ +#include +#include + +int main() { + error(1, EINVAL, "test error #1"); +} diff --git a/lib/mlibc/tests/glibc/error_message_count.c b/lib/mlibc/tests/glibc/error_message_count.c new file mode 100644 index 0000000..c2c694a --- /dev/null +++ b/lib/mlibc/tests/glibc/error_message_count.c @@ -0,0 +1,11 @@ +#include +#include +#include + +int main() { + assert(error_message_count == 0); + error(0, EINVAL, "test error #1"); + assert(error_message_count == 1); + error_at_line(0, EINVAL, __FILE__, __LINE__, "test error #2"); + assert(error_message_count == 2); +} diff --git a/lib/mlibc/tests/glibc/error_one_per_line.c b/lib/mlibc/tests/glibc/error_one_per_line.c new file mode 100644 index 0000000..98721ec --- /dev/null +++ b/lib/mlibc/tests/glibc/error_one_per_line.c @@ -0,0 +1,13 @@ +#include +#include +#include + +int main() { + assert(error_one_per_line == 0); + assert(error_message_count == 0); + error_one_per_line = 1; + error_at_line(0, EINVAL, __FILE__, 0, "test error #1"); + assert(error_message_count == 1); + error_at_line(0, EINVAL, __FILE__, 0, "test error #2"); + assert(error_message_count == 1); +} diff --git a/lib/mlibc/tests/glibc/error_print_progname.c b/lib/mlibc/tests/glibc/error_print_progname.c new file mode 100644 index 0000000..8840cb2 --- /dev/null +++ b/lib/mlibc/tests/glibc/error_print_progname.c @@ -0,0 +1,19 @@ +#include +#include +#include +#include +#include + +bool ran = false; + +void test_progname(void) { + ran = true; + fprintf(stderr, "progname test"); +} + +int main() { + assert(error_print_progname == NULL); + error_print_progname = &test_progname; + error(0, EINVAL, "test error #1"); + assert(ran == true); +} diff --git a/lib/mlibc/tests/glibc/ffsl-ffsll.c b/lib/mlibc/tests/glibc/ffsl-ffsll.c new file mode 100644 index 0000000..ed70ad6 --- /dev/null +++ b/lib/mlibc/tests/glibc/ffsl-ffsll.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include + +int main(void){ + // ffsl + assert(ffsl(0x8000) == 16); + assert(ffsl(0) == 0); +#if UINTPTR_MAX == UINT64_MAX + assert(ffsl(LLONG_MAX - 1) == 2); + assert(ffsl(LLONG_MAX) == 1); +#endif + assert(ffsl(LONG_MIN) == (long)(sizeof(long) * CHAR_BIT)); + assert(ffsl(LONG_MIN + 1) == 1); + + for (int i = 1; i < 0x1000; i++) { + assert(ffsl(i) - 1 == __builtin_ctz(i)); + } + + // ffsll + assert(ffsll(0x8000) == 16); + assert(ffsll(0) == 0); +#if UINTPTR_MAX == UINT64_MAX + assert(ffsll(LLONG_MAX - 1) == 2); + assert(ffsll(LLONG_MAX) == 1); +#endif + assert(ffsll(LLONG_MIN) == (long long)(sizeof(long long) * CHAR_BIT)); + assert(ffsll(LLONG_MIN + 1) == 1); + + for (int i = 1; i < 0x1000; i++) { + assert(ffsll(i) - 1 == __builtin_ctz(i)); + } + + return 0; +} diff --git a/lib/mlibc/tests/glibc/getopt.c b/lib/mlibc/tests/glibc/getopt.c new file mode 100644 index 0000000..a0e27bb --- /dev/null +++ b/lib/mlibc/tests/glibc/getopt.c @@ -0,0 +1,288 @@ +#include +#include +#include +#include +#include +#include +#include + +#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) +#define dump(x) fprintf(stderr, "getopt c '%c' (%d), optind %d ('%s'), optarg '%s', optopt '%c' (%d)\n", \ + (x), (x), optind, (size_t)optind >= COUNT_OF(test_argv) ? "out of range" : test_argv[optind], optarg, optopt, optopt); + +void test1() { + const char *shortopts = "b:cdef"; + + const struct option longopts[] = { + {"foo", required_argument, NULL, 'f'}, + {NULL, no_argument, NULL, 0} + }; + + int test_argc = 7; + + char *test_argv[] = { + "dummy", + "--foo", + "abc", + "-b", + "abc", + "abc", + "abc" + }; + + optind = 0; + int c = getopt_long(test_argc, test_argv, shortopts, longopts, NULL); + dump(c) + assert(c == 'f'); + + c = getopt_long(test_argc, test_argv, shortopts, longopts, NULL); + dump(c) + assert(optarg && !strcmp(optarg, "abc")); + assert(c == 'b'); + + c = getopt_long(test_argc, test_argv, shortopts, longopts, NULL); + dump(c); + assert(c == -1); + assert(optarg == NULL); + + // we have 2 non-option arguments + assert((optind + 2) == test_argc); +} + +void test2() { + const struct option longopts[] = { + {"foo", required_argument, NULL, 'f'}, + {NULL, no_argument, NULL, 0} + }; + + char *test_argv[] = { + "dummy", + "-c", + }; + + fputs("Situation: we pass a non-existant short option in argv\n", stderr); + + optind = 0; + int c = getopt_long(COUNT_OF(test_argv), test_argv, "ab:", longopts, NULL); + // Exprected result: return '?', optopt is set to the offender + assert(c == '?'); + assert(optopt == 'c'); + + fputs("Situation: we pass a non-existant short option in argv, while passing a leading colon in optstring\n", stderr); + optind = 0; + + c = getopt_long(COUNT_OF(test_argv), test_argv, ":ab:", longopts, NULL); + // Exprected result: return '?', optopt is set to the offender + assert(c == '?'); + assert(optopt == 'c'); + + fputs("Situation: we omit the required arg to a short option\n", stderr); + optind = 0; + + c = getopt_long(COUNT_OF(test_argv), test_argv, "ab:c:", longopts, NULL); + // Exprected result: return '?', optopt is set to the offender + assert(c == '?'); + assert(optopt == 'c'); + + fputs("Situation: we omit the required arg to a short option, while passing a leading colon in optstring\n", stderr); + optind = 0; + + c = getopt_long(COUNT_OF(test_argv), test_argv, ":ab:c:", longopts, NULL); + // Exprected result: return ':', optopt is set to the offender + assert(c == ':'); + assert(optopt == 'c'); +} + +void test3() { + const struct option longopts[] = { + {"foo", required_argument, NULL, 'f'}, + {NULL, no_argument, NULL, 0} + }; + + char *test_argv[] = { + "dummy", + "-cmanagarm", + }; + + fputs("Situation: we pass a concatenated argument to a short option\n", stderr); + + optind = 0; + int c = getopt_long(COUNT_OF(test_argv), test_argv, "ab:c:", longopts, NULL); + dump(c); + // Exprected result: + assert(c == 'c'); + assert(!strcmp(optarg, "managarm")); +} + +void test4() { + const struct option longopts[] = { + {"foo", required_argument, NULL, 'f'}, + {NULL, no_argument, NULL, 0} + }; + + char *test_argv[] = { + "dummy", + "-acmanagarm", + }; + + fputs("Situation: we pass concatenated short options to getopt\n", stderr); + + optind = 0; + int c = getopt_long(COUNT_OF(test_argv), test_argv, "ab:c:", longopts, NULL); + assert(c == 'a'); + + c = getopt_long(COUNT_OF(test_argv), test_argv, "ab:c:", longopts, NULL); + // Exprected result: + assert(c == 'c'); + assert(!strcmp(optarg, "managarm")); +} + +void test5() { + const struct option longopts[] = { + {"foo", required_argument, NULL, 'f'}, + {NULL, no_argument, NULL, 0} + }; + + char *test_argv[] = { + "su", + "-", + "managarm", + 0 + }; + + int test_argc = 3; + + fputs("Situation: testing `su - managarm`\n", stderr); + + optind = 0; + int c = getopt_long(test_argc, test_argv, "ab:", longopts, NULL); + dump(c); + assert(c == -1); + + if (optind < test_argc && !strcmp(test_argv[optind], "-")) { + ++optind; + } + + assert(optind < test_argc); + assert(!strcmp(test_argv[optind++], "managarm")); + assert(optind == test_argc); +} + +void test6() { + char *test_argv[] = { + "telescope", + "gemini://electrode.codes", + "-S", + 0 + }; + + int test_argc = 3; + optind = 0; + + const struct option longopts[] = { + {"colors", no_argument, NULL, 'C'}, + {"colours", no_argument, NULL, 'C'}, + {"help", no_argument, NULL, 'h'}, + {"safe", no_argument, NULL, 'S'}, + {"version", no_argument, NULL, 'v'}, + {NULL, 0, NULL, 0}, + }; + + int c = getopt_long(test_argc, test_argv, "Cc:hnST:v", longopts, NULL); + dump(c); + assert(c == 'S'); + assert(optind == 3); + assert(!optarg); +} + +void test7() { + int c; + + static const struct option options[] = { + { "debug", no_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + {} + }; + const char *command; + + char *test_argv[] = { + "udevadm", + "hwdb", + "--update", + 0 + }; + + int test_argc = 3; + setenv("POSIXLY_CORRECT", "1", 1); + optind = 0; + + while ((c = getopt_long(test_argc, test_argv, "+dhV", options, NULL)) >= 0) { + switch (c) { + case 'd': + break; + case 'h': + break; + case 'V': + break; + default: + break; + } + } + + dump(c); + command = test_argv[optind]; + assert(command); + assert(!strcmp(command, "hwdb")); +} + +void test8() { + const char *shortopts = "b:cde"; + + int foo = false; + int bar = false; + + const struct option longopts[] = { + {"foo", required_argument, &foo, 'x'}, + {"bar", required_argument, &bar, 'y'}, + {NULL, no_argument, NULL, 0} + }; + + int test_argc = 6; + + char *test_argv[] = { + "dummy", + "-foo", + "abc", + "-bar=def", + "ghi", + "jkl" + }; + + #ifdef __GLIBC__ + optind = 0; + #else + optreset = 1; + #endif + optopt = 0; + int c = getopt_long_only(test_argc, test_argv, shortopts, longopts, NULL); + dump(c); + assert(foo && !c); + assert(optind == 3); + + c = getopt_long_only(test_argc, test_argv, shortopts, longopts, NULL); + dump(c); + assert(bar && !c); + assert(optind == 4); +} + +int main() { + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + test7(); + test8(); +} diff --git a/lib/mlibc/tests/glibc/gnu-basename.c b/lib/mlibc/tests/glibc/gnu-basename.c new file mode 100644 index 0000000..9566532 --- /dev/null +++ b/lib/mlibc/tests/glibc/gnu-basename.c @@ -0,0 +1,13 @@ +#define _GNU_SOURCE +#include +#include + +#define test_string(x, expectval) assert(strcmp(basename(x), expectval) == 0) + +int main() { + test_string("/usr/lib", "lib"); + test_string("/usr/", ""); + test_string("/", ""); + test_string(".", "."); + test_string("..", ".."); +} diff --git a/lib/mlibc/tests/glibc/linux-syscall.c b/lib/mlibc/tests/glibc/linux-syscall.c new file mode 100644 index 0000000..2760df4 --- /dev/null +++ b/lib/mlibc/tests/glibc/linux-syscall.c @@ -0,0 +1,14 @@ +#include +#include +#include +#include +#include + +int main() { + char *data = "hello mlibc\n"; + long ret = syscall(SYS_write, 1, data, strlen(data)); + assert(ret == (long)strlen(data)); + + syscall(SYS_exit, 0); + abort(); +} -- cgit v1.2.3