summaryrefslogtreecommitdiff
path: root/lib/mlibc/tests/glibc
diff options
context:
space:
mode:
authorIan Moffett <ian@osmora.org>2024-03-07 17:28:00 -0500
committerIan Moffett <ian@osmora.org>2024-03-07 17:28:32 -0500
commitbd5969fc876a10b18613302db7087ef3c40f18e1 (patch)
tree7c2b8619afe902abf99570df2873fbdf40a4d1a1 /lib/mlibc/tests/glibc
parenta95b38b1b92b172e6cc4e8e56a88a30cc65907b0 (diff)
lib: Add mlibc
Signed-off-by: Ian Moffett <ian@osmora.org>
Diffstat (limited to 'lib/mlibc/tests/glibc')
-rw-r--r--lib/mlibc/tests/glibc/error.c6
-rw-r--r--lib/mlibc/tests/glibc/error.py11
-rw-r--r--lib/mlibc/tests/glibc/error_at_line.c6
-rw-r--r--lib/mlibc/tests/glibc/error_at_line.py11
-rw-r--r--lib/mlibc/tests/glibc/error_expect_fail.c6
-rw-r--r--lib/mlibc/tests/glibc/error_message_count.c11
-rw-r--r--lib/mlibc/tests/glibc/error_one_per_line.c13
-rw-r--r--lib/mlibc/tests/glibc/error_print_progname.c19
-rw-r--r--lib/mlibc/tests/glibc/ffsl-ffsll.c36
-rw-r--r--lib/mlibc/tests/glibc/getopt.c288
-rw-r--r--lib/mlibc/tests/glibc/gnu-basename.c13
-rw-r--r--lib/mlibc/tests/glibc/linux-syscall.c14
12 files changed, 434 insertions, 0 deletions
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 <errno.h>
+#include <error.h>
+
+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 <errno.h>
+#include <error.h>
+
+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 <errno.h>
+#include <error.h>
+
+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 <assert.h>
+#include <errno.h>
+#include <error.h>
+
+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 <assert.h>
+#include <errno.h>
+#include <error.h>
+
+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 <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <errno.h>
+#include <error.h>
+
+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 <assert.h>
+#include <stdint.h>
+#include <string.h>
+#include <limits.h>
+
+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 <assert.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 <assert.h>
+#include <string.h>
+
+#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 <sys/syscall.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+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();
+}