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/ansi/abs.c | 16 ++++ lib/mlibc/tests/ansi/alloc.c | 37 +++++++ lib/mlibc/tests/ansi/calloc.c | 20 ++++ lib/mlibc/tests/ansi/creal-cimag.c | 37 +++++++ lib/mlibc/tests/ansi/fenv.c | 91 ++++++++++++++++++ lib/mlibc/tests/ansi/fopen.c | 59 ++++++++++++ lib/mlibc/tests/ansi/freopen.c | 49 ++++++++++ lib/mlibc/tests/ansi/locale.c | 17 ++++ lib/mlibc/tests/ansi/longjmp.c | 29 ++++++ lib/mlibc/tests/ansi/mbrtoc32.c | 53 ++++++++++ lib/mlibc/tests/ansi/memmem.c | 22 +++++ lib/mlibc/tests/ansi/qsort.c | 31 ++++++ lib/mlibc/tests/ansi/snprintf.c | 23 +++++ lib/mlibc/tests/ansi/sprintf.c | 191 +++++++++++++++++++++++++++++++++++++ lib/mlibc/tests/ansi/sscanf.c | 143 +++++++++++++++++++++++++++ lib/mlibc/tests/ansi/strchr.c | 20 ++++ lib/mlibc/tests/ansi/strftime.c | 48 ++++++++++ lib/mlibc/tests/ansi/strrchr.c | 11 +++ lib/mlibc/tests/ansi/strtof.c | 83 ++++++++++++++++ lib/mlibc/tests/ansi/strtol.c | 140 +++++++++++++++++++++++++++ lib/mlibc/tests/ansi/strverscmp.c | 16 ++++ lib/mlibc/tests/ansi/strxfrm.c | 14 +++ lib/mlibc/tests/ansi/timegm.c | 45 +++++++++ lib/mlibc/tests/ansi/ungetc.c | 74 ++++++++++++++ lib/mlibc/tests/ansi/utf8.c | 63 ++++++++++++ lib/mlibc/tests/ansi/wcsdup.c | 11 +++ lib/mlibc/tests/ansi/wcsncasecmp.c | 11 +++ lib/mlibc/tests/ansi/wcsrtombs.c | 12 +++ lib/mlibc/tests/ansi/wmemcmp.c | 19 ++++ 29 files changed, 1385 insertions(+) create mode 100644 lib/mlibc/tests/ansi/abs.c create mode 100644 lib/mlibc/tests/ansi/alloc.c create mode 100644 lib/mlibc/tests/ansi/calloc.c create mode 100644 lib/mlibc/tests/ansi/creal-cimag.c create mode 100644 lib/mlibc/tests/ansi/fenv.c create mode 100644 lib/mlibc/tests/ansi/fopen.c create mode 100644 lib/mlibc/tests/ansi/freopen.c create mode 100644 lib/mlibc/tests/ansi/locale.c create mode 100644 lib/mlibc/tests/ansi/longjmp.c create mode 100644 lib/mlibc/tests/ansi/mbrtoc32.c create mode 100644 lib/mlibc/tests/ansi/memmem.c create mode 100644 lib/mlibc/tests/ansi/qsort.c create mode 100644 lib/mlibc/tests/ansi/snprintf.c create mode 100644 lib/mlibc/tests/ansi/sprintf.c create mode 100644 lib/mlibc/tests/ansi/sscanf.c create mode 100644 lib/mlibc/tests/ansi/strchr.c create mode 100644 lib/mlibc/tests/ansi/strftime.c create mode 100644 lib/mlibc/tests/ansi/strrchr.c create mode 100644 lib/mlibc/tests/ansi/strtof.c create mode 100644 lib/mlibc/tests/ansi/strtol.c create mode 100644 lib/mlibc/tests/ansi/strverscmp.c create mode 100644 lib/mlibc/tests/ansi/strxfrm.c create mode 100644 lib/mlibc/tests/ansi/timegm.c create mode 100644 lib/mlibc/tests/ansi/ungetc.c create mode 100644 lib/mlibc/tests/ansi/utf8.c create mode 100644 lib/mlibc/tests/ansi/wcsdup.c create mode 100644 lib/mlibc/tests/ansi/wcsncasecmp.c create mode 100644 lib/mlibc/tests/ansi/wcsrtombs.c create mode 100644 lib/mlibc/tests/ansi/wmemcmp.c (limited to 'lib/mlibc/tests/ansi') diff --git a/lib/mlibc/tests/ansi/abs.c b/lib/mlibc/tests/ansi/abs.c new file mode 100644 index 0000000..492040c --- /dev/null +++ b/lib/mlibc/tests/ansi/abs.c @@ -0,0 +1,16 @@ +#include +#include +#include + +int main(){ + assert(abs(-10) == 10); + assert(abs(2021) == 2021); + + assert(labs(-256) == 256); + assert(labs(10034890) == 10034890); + + assert(llabs(-0x2deadbeef) == 0x2deadbeef); + assert(llabs(49238706947) == 49238706947); + + return 0; +} \ No newline at end of file diff --git a/lib/mlibc/tests/ansi/alloc.c b/lib/mlibc/tests/ansi/alloc.c new file mode 100644 index 0000000..c6ce870 --- /dev/null +++ b/lib/mlibc/tests/ansi/alloc.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include + +int main() { + void *p; + + p = aligned_alloc(sizeof(void *), sizeof(void *)); + assert(p != NULL && (uintptr_t)p % sizeof(void *) == 0); + free(p); + + p = aligned_alloc(256, 256); + assert(p != NULL && (uintptr_t)p % 256 == 0); + free(p); + + // small alignments are okay + p = aligned_alloc(1, 8); + assert(p != NULL); + free(p); + p = aligned_alloc(1, 1); + assert(p != NULL); + free(p); + + // It seems that glibc doesn't report error in these cases. +#if !(defined(USE_HOST_LIBC) && defined(__GLIBC__)) + // size % align must be 0 + p = aligned_alloc(256, 1); + assert(errno == EINVAL); + assert(p == NULL); + + // align must be a 'valid alignment supported by the implementation' + p = aligned_alloc(3, 1); + assert(errno == EINVAL); + assert(p == NULL); +#endif +} diff --git a/lib/mlibc/tests/ansi/calloc.c b/lib/mlibc/tests/ansi/calloc.c new file mode 100644 index 0000000..6cfc87d --- /dev/null +++ b/lib/mlibc/tests/ansi/calloc.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + +int main() { + errno = 0; + void *ptr = calloc((SIZE_MAX / 2) + 2, 2); + assert(!ptr); + assert(errno); + + errno = 0; + ptr = calloc(sizeof(size_t), 10); + assert(ptr); + for(size_t i = 0; i < 10; i++) { + size_t *p = ptr; + assert(!p[i]); + } +} diff --git a/lib/mlibc/tests/ansi/creal-cimag.c b/lib/mlibc/tests/ansi/creal-cimag.c new file mode 100644 index 0000000..fc70aa3 --- /dev/null +++ b/lib/mlibc/tests/ansi/creal-cimag.c @@ -0,0 +1,37 @@ +#include +#include +#include + +// FIXME: We should create a proper floating point facility +// in order for other functions to be tested properly + +#define APPROXIMATELY_EQUAL(calculated, expected) fabs((calculated) - (expected)) <= 0.0000005 +#define APPROXIMATELY_EQUALF(calculated, expected) fabsf((calculated) - (expected)) <= 0.0000005f +#define APPROXIMATELY_EQUALL(calculated, expected) fabsl((calculated) - (expected)) <= 0.0000005L + +#define IS_COMPLEX_NUMBER(Z) \ + _Generic((Z), \ + double complex: 1, \ + float complex: 1, \ + long double complex: 1, \ + default: 0 \ + ) + +int main() { + assert(IS_COMPLEX_NUMBER(CMPLX(5.2, 4.3))); + double complex cz = CMPLX(5.2, 4.3); + assert(APPROXIMATELY_EQUAL(creal(cz), 5.2)); + assert(APPROXIMATELY_EQUAL(cimag(cz), 4.3)); + + assert(IS_COMPLEX_NUMBER(CMPLXF(1.2f, 2.5f))); + float complex czf = CMPLXF(1.2f, 2.5f); + assert(APPROXIMATELY_EQUALF(crealf(czf), 1.2f)); + assert(APPROXIMATELY_EQUALF(cimagf(czf), 2.5f)); + + assert(IS_COMPLEX_NUMBER(CMPLXL(0.1L, 123.54L))); + long double complex czl = CMPLXL(0.1L, 123.54L); + assert(APPROXIMATELY_EQUALL(creall(czl), 0.1L)); + assert(APPROXIMATELY_EQUALL(cimagl(czl), 123.54L)); + + return 0; +} \ No newline at end of file diff --git a/lib/mlibc/tests/ansi/fenv.c b/lib/mlibc/tests/ansi/fenv.c new file mode 100644 index 0000000..629a5cb --- /dev/null +++ b/lib/mlibc/tests/ansi/fenv.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include + +#define NO_OPTIMIZE(x) asm volatile("" :: "r,m" (x) : "memory") + +static void div_by_zero() { + volatile float zero = 0.0f; + NO_OPTIMIZE(69.0f / zero); +} + +static bool float_cmp(float a, float b) { + return a == b || fabs(a - b) < (fabs(a) + fabs(b)) * FLT_EPSILON; +} + +static void test_rounding(float expectation1, float expectation2) { + float x; + volatile float f = 1.968750f; + volatile float m = 0x1.0p23f; + + NO_OPTIMIZE(x = f + m); + assert(float_cmp(expectation1, x)); + NO_OPTIMIZE(x = x - m); + assert(x == expectation2); +} + +void test0() { + // test whether the divide-by-zero exception is raised + feclearexcept(FE_ALL_EXCEPT); + assert(fetestexcept(FE_ALL_EXCEPT) == 0); + + div_by_zero(); + int raised = fetestexcept(FE_DIVBYZERO); + assert((raised & FE_DIVBYZERO)); +} + +void test1() { + // test various rounding modes + feclearexcept(FE_DIVBYZERO); + assert(fetestexcept(FE_ALL_EXCEPT) == 0); + + fesetround(FE_UPWARD); + assert(fegetround() == FE_UPWARD); + test_rounding(8388610.0f, 2.0f); + + fesetround(FE_DOWNWARD); + assert(fegetround() == FE_DOWNWARD); + test_rounding(8388609.0f, 1.0f); + + fesetround(FE_TONEAREST); + assert(fegetround() == FE_TONEAREST); + test_rounding(8388610.0f, 2.0f); + + fesetround(FE_TOWARDZERO); + assert(fegetround() == FE_TOWARDZERO); + test_rounding(8388609.0f, 1.0f); +} + +void test2() { + // test feraiseexcept + feclearexcept(FE_ALL_EXCEPT); + assert(fetestexcept(FE_ALL_EXCEPT) == 0); + assert(feraiseexcept(FE_DIVBYZERO | FE_OVERFLOW) == 0); + assert(fetestexcept(FE_ALL_EXCEPT) == (FE_DIVBYZERO | FE_OVERFLOW)); +} + +void test3() { + // test fe{get,set}env + feclearexcept(FE_ALL_EXCEPT); + assert(fetestexcept(FE_ALL_EXCEPT) == 0); + assert(feraiseexcept(FE_OVERFLOW) == 0); + + fenv_t state; + assert(fegetenv(&state) == 0); + assert(fetestexcept(FE_ALL_EXCEPT) == FE_OVERFLOW); + + div_by_zero(); + assert(fetestexcept(FE_ALL_EXCEPT) == (FE_DIVBYZERO | FE_OVERFLOW)); + + assert(fesetenv(&state) == 0); + assert(fetestexcept(FE_ALL_EXCEPT) == FE_OVERFLOW); +} + +int main() { + test0(); + test1(); + test2(); + test3(); +} diff --git a/lib/mlibc/tests/ansi/fopen.c b/lib/mlibc/tests/ansi/fopen.c new file mode 100644 index 0000000..f4818b2 --- /dev/null +++ b/lib/mlibc/tests/ansi/fopen.c @@ -0,0 +1,59 @@ +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define TEST_FILE "fopen-host-libc.tmp" +#else +#define TEST_FILE "fopen.tmp" +#endif + +int main() { + FILE *file; + char str[] = "mlibc fopen test"; + char str2[] = " mlibc appending"; + char completestr[] = "mlibc fopen test mlibc appending"; + char buffer[100]; + char buffer2[100]; + + // Clear all the buffers to zero. + memset(buffer, 0, sizeof(buffer)); + memset(buffer2, 0, sizeof(buffer2)); + + // Open the file for writing. + file = fopen(TEST_FILE, "w"); + assert(file); + + // Write string minus null terminator, flush and close. + fwrite(str, 1, sizeof(str) - 1, file); + fflush(file); + fclose(file); + + // Open the file for reading. + file = fopen(TEST_FILE, "r"); + assert(file); + + // Verify that we read back the written string and close the file. + assert(fread(buffer, 1, sizeof(str) - 1, file)); + assert(!strcmp(buffer, str)); + fclose(file); + + // Open the file in appending mode, append string 2 (minus the null terminator) to the file, flush and close. + file = fopen(TEST_FILE, "a"); + fwrite(str2, 1, sizeof(str2) - 1, file); + fflush(file); + fclose(file); + + // Open the file for reading again, verify the contents, close the file and return. + file = fopen(TEST_FILE, "r"); + assert(fread(buffer2, 1, sizeof(completestr) - 1, file)); + assert(!strcmp(buffer2, completestr)); + fclose(file); + + // Check that stdout, stdin and stderr can be closed by the application (issue #12). + fclose(stdout); + fclose(stdin); + fclose(stderr); + + return 0; +} diff --git a/lib/mlibc/tests/ansi/freopen.c b/lib/mlibc/tests/ansi/freopen.c new file mode 100644 index 0000000..c91577f --- /dev/null +++ b/lib/mlibc/tests/ansi/freopen.c @@ -0,0 +1,49 @@ +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define TEST_FILE "freopen-host-libc.tmp" +#else +#define TEST_FILE "freopen.tmp" +#endif + +int main() { + FILE *file = fopen(TEST_FILE, "w"); + assert(file); + + assert(freopen("/dev/null", "w", file)); + + char str[] = "mlibc freopen test"; + fwrite(str, 1, sizeof(str) - 1, file); + fflush(file); + fclose(file); + + file = fopen(TEST_FILE, "r"); + assert(file); + + char buf[sizeof(str)]; + memset(buf, 0, sizeof(buf)); + int ret = fread(buf, 1, sizeof(buf) - 1, file); + fprintf(stderr, "ret %d\n", ret); + assert(ret == 0); + fclose(file); + + file = fopen("/dev/null", "w"); + assert(file); + + assert(freopen(TEST_FILE, "w", file)); + fwrite(str, 1, sizeof(str) - 1, file); + fflush(file); + fclose(file); + + memset(buf, 0, sizeof(buf)); + file = fopen(TEST_FILE, "r"); + assert(fread(buf, 1, sizeof(buf) - 1, file)); + + fprintf(stderr, "buffer content '%s'\n", buf); + assert(!strcmp(buf, "mlibc freopen test")); + fclose(file); + + return 0; +} diff --git a/lib/mlibc/tests/ansi/locale.c b/lib/mlibc/tests/ansi/locale.c new file mode 100644 index 0000000..056298b --- /dev/null +++ b/lib/mlibc/tests/ansi/locale.c @@ -0,0 +1,17 @@ +#include +#include +#include +#include + +int main() { + wchar_t c = 0xC9; + unsigned char buf[sizeof(wchar_t)] = { 0 }; + setlocale(LC_ALL, ""); + if (sprintf(buf, "%lc", c) < 0) + return -1; + + assert(buf[0] == 0xc3 && buf[1] == 0x89 + && buf[2] == '\0' && buf[3] == '\0'); + + return 0; +} diff --git a/lib/mlibc/tests/ansi/longjmp.c b/lib/mlibc/tests/ansi/longjmp.c new file mode 100644 index 0000000..9f9c1ed --- /dev/null +++ b/lib/mlibc/tests/ansi/longjmp.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include + +jmp_buf buf; + +noreturn void do_jump(int arg) { + longjmp(buf, 2 * arg); +} + +int main(void) { + volatile int times_called = 0; + + if (setjmp(buf) != 8) { + do_jump(++times_called); + } + + assert(times_called == 4); + + times_called = 0; + int ret = setjmp(buf); + assert(ret == times_called); + + if (!ret) { + times_called = 1; + longjmp(buf, 0); + } +} diff --git a/lib/mlibc/tests/ansi/mbrtoc32.c b/lib/mlibc/tests/ansi/mbrtoc32.c new file mode 100644 index 0000000..781bc71 --- /dev/null +++ b/lib/mlibc/tests/ansi/mbrtoc32.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include + +struct { + size_t ret; + char32_t c32; + uint8_t bytes[4]; +} expected_results[] = { + {1, 0x7A, {0x7A, 0, 0, 0}}, + {2, 0xDF, {0xC3, 0x9F, 0, 0}}, + {3, 0x6C34, {0xE6, 0xB0, 0xB4, 0}}, + {4, 0x1F34C, {0xF0, 0x9F, 0x8D, 0x8C}}, +}; + +int main() { + setlocale(LC_ALL, "en_US.utf8"); + + size_t ret = 0; + + char *str = "z\u00df\u6c34\U0001F34C"; + + fprintf(stderr, "string: '%s'\n", str); + + mbstate_t state = {}; + char32_t c32; + size_t loop = 0; + while((ret = mbrtoc32(&c32, str, strlen(str), &state))) { + assert(ret != (size_t)-3); + if(ret == (size_t)-1) + break; + if(ret == (size_t)-2) + break; + + fprintf(stderr, "Next UTF-32 char: 0x%x obtained from %zu bytes [", c32, ret); + for(size_t n = 0; n < ret; ++n) { + fprintf(stderr, " 0x%02x ", (uint8_t) str[n]); + } + fprintf(stderr, "]\n"); + + assert(ret == expected_results[loop].ret); + assert(c32 == expected_results[loop].c32); + for(size_t n = 0; n < ret; ++n) { + assert((uint8_t) str[n] == expected_results[loop].bytes[n]); + } + + str += ret; + loop++; + } +} diff --git a/lib/mlibc/tests/ansi/memmem.c b/lib/mlibc/tests/ansi/memmem.c new file mode 100644 index 0000000..8de558f --- /dev/null +++ b/lib/mlibc/tests/ansi/memmem.c @@ -0,0 +1,22 @@ +#include +#include + +int main() { + char *haystack = "abc123\0x45"; + + char *needle1 = "abc"; + void *rv = memmem(haystack, strlen(haystack), needle1, strlen(needle1)); + assert(rv == haystack); + + char *needle2 = "123"; + rv = memmem(haystack, strlen(haystack), needle2, strlen(needle2)); + assert(rv == haystack + 3); + + char *needle3 = "1234"; + rv = memmem(haystack, strlen(haystack), needle3, strlen(needle3)); + assert(rv == NULL); + + char *needle4 = "23\0x45"; + rv = memmem(haystack, 10, needle4, 6); + assert(rv == haystack + 4); +} diff --git a/lib/mlibc/tests/ansi/qsort.c b/lib/mlibc/tests/ansi/qsort.c new file mode 100644 index 0000000..bb48a23 --- /dev/null +++ b/lib/mlibc/tests/ansi/qsort.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include + +static const char *arr[] = { "xyz", "abc", "ghi", "def" }; + +static const size_t magic = 0xDEADBEEF; + +static int cmpstringp(const void *p1, const void *p2, void *ctx) { + /* The actual arguments to this function are "pointers to + * pointers to char", but strcmp(3) arguments are "pointers + * to char", hence the following cast plus dereference. */ + assert(*(size_t *) ctx == magic); + return strcmp(*(const char **) p1, *(const char **) p2); +} + +int main() { + qsort_r(&arr[0], sizeof(arr) / sizeof(*arr), sizeof(char *), cmpstringp, (void *) &magic); + + assert(!strcmp(arr[0], "abc")); + assert(!strcmp(arr[1], "def")); + assert(!strcmp(arr[2], "ghi")); + assert(!strcmp(arr[3], "xyz")); + + for(size_t i = 0; i < sizeof(arr) / sizeof(*arr); i++) { + fprintf(stderr, "%s\n", arr[i]); + } + + return 0; +} diff --git a/lib/mlibc/tests/ansi/snprintf.c b/lib/mlibc/tests/ansi/snprintf.c new file mode 100644 index 0000000..82e4640 --- /dev/null +++ b/lib/mlibc/tests/ansi/snprintf.c @@ -0,0 +1,23 @@ +#include +#include +#include + +int main() { + char buffer[10]; + int ret = snprintf(buffer, 10, "%d", 123456789); + assert(strncmp("123456789", buffer, 10) == 0); + assert(ret == 9); + + // We deliberately induce a warning here. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-truncation" + ret = snprintf(buffer, 10, "%d", 1234567890); + assert(strncmp("123456789", buffer, 10) == 0); + assert(ret == 10); +#pragma GCC diagnostic pop + + // mlibc issue #118. + ret = snprintf(NULL, 0, "%d", 123456789); + assert(ret == 9); + return 0; +} diff --git a/lib/mlibc/tests/ansi/sprintf.c b/lib/mlibc/tests/ansi/sprintf.c new file mode 100644 index 0000000..fd9398c --- /dev/null +++ b/lib/mlibc/tests/ansi/sprintf.c @@ -0,0 +1,191 @@ +#include +#include +#include +#include + +int main() { + char buf[11] = { 0 }; + sprintf(buf, "%d", 12); + assert(!strcmp(buf, "12")); + sprintf(buf, "%f", 3.14); + assert(!strcmp(buf, "3.140000")); + + // Test %c right padding. + sprintf(buf, "%-2c", 'a'); + assert(!strcmp(buf, "a ")); + + // Test %c left padding. + sprintf(buf, "%2c", 'a'); + assert(!strcmp(buf, " a")); + + // Test %d right padding - mlibc issue #58. + sprintf(buf, "%-2d", 1); + assert(!strcmp(buf, "1 ")); + sprintf(buf, "%-2.2d", 1); + assert(!strcmp(buf, "01")); + sprintf(buf, "%-3.2d", 1); + assert(!strcmp(buf, "01 ")); + sprintf(buf, "%-3.2d", 12); + assert(!strcmp(buf, "12 ")); + sprintf(buf, "%-3.2d", 123); + assert(!strcmp(buf, "123")); + sprintf(buf, "%-3.2u", 12); + assert(!strcmp(buf, "12 ")); + + // Test %d left padding. + sprintf(buf, "%2d", 1); + assert(!strcmp(buf, " 1")); + sprintf(buf, "%3.2d", 1); + assert(!strcmp(buf, " 01")); + sprintf(buf, "%3.2d", 12); + assert(!strcmp(buf, " 12")); + sprintf(buf, "%3.2d", 123); + assert(!strcmp(buf, "123")); + sprintf(buf, "%3.2u", 12); + assert(!strcmp(buf, " 12")); + + // Test %f padding. + // TODO: Test printing of huge numbers (larger than 2^64) + sprintf(buf, "%2.f", 1.2); + assert(!strcmp(buf, " 1")); + sprintf(buf, "%2.f", 12.3); + assert(!strcmp(buf, "12")); + sprintf(buf, "%5.2f", 1.0); + assert(!strcmp(buf, " 1.00")); + sprintf(buf, "%.1f", -4.0); + assert(!strcmp(buf, "-4.0")); + sprintf(buf, "%-3.f", 8.0); + assert(!strcmp(buf, "8 ")); + sprintf(buf, "%4f", INFINITY); + assert(!strcmp(buf, " inf") || !strcmp(buf, "infinity")); + sprintf(buf, "%4f", NAN); + assert(!strcmp(buf, " nan")); + sprintf(buf, "%4F", INFINITY); + assert(!strcmp(buf, " INF") || !strcmp(buf, "INFINITY")); + sprintf(buf, "%4F", NAN); + assert(!strcmp(buf, " NAN")); + sprintf(buf, "%05.2f", 1.0); + assert(!strcmp(buf, "01.00")); + sprintf(buf, "%09f", INFINITY); // 0 ignored when padding infs + assert(!strcmp(buf, " inf") || !strcmp(buf, " infinity")); + // TODO: We don't yet round properly + // sprintf(buf, "%5.2f", 1.2); + // assert(!strcmp(buf, " 1.20")); + // sprintf(buf, "%5.2f", 1.23); + // assert(!strcmp(buf, " 1.23")); + // sprintf(buf, "%5.2f", 1.234); + // assert(!strcmp(buf, " 1.23")); + // sprintf(buf, "%5.2f", 12.345); + // assert(!strcmp(buf, "12.35")); + // sprintf(buf, "%-5.2f", 1.2); + // assert(!strcmp(buf, "1.20 ")); + + // Test '+' and ' ' flags - mlibc issue #229. + // Disable -Wformat here since we deliberately induce some warnings. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" + sprintf(buf, "%+d", 12); + assert(!strcmp(buf, "+12")); + sprintf(buf, "% d", 12); + assert(!strcmp(buf, " 12")); + sprintf(buf, "% +d", 12); + assert(!strcmp(buf, "+12")); + sprintf(buf, "%+ d", 12); + assert(!strcmp(buf, "+12")); + sprintf(buf, "%+d", -12); + assert(!strcmp(buf, "-12")); + sprintf(buf, "% d", -12); + assert(!strcmp(buf, "-12")); + sprintf(buf, "% +d", -12); + assert(!strcmp(buf, "-12")); + sprintf(buf, "%+ d", -12); + assert(!strcmp(buf, "-12")); +#pragma GCC diagnostic pop + + // Test '#' flag. + // TODO: Test with a, A, e, E, f, F, g, G conversions. + sprintf(buf, "%#x", 12); + assert(!strcmp(buf, "0xc")); + sprintf(buf, "%#X", 12); + assert(!strcmp(buf, "0XC")); + sprintf(buf, "%#o", 12); + assert(!strcmp(buf, "014")); + sprintf(buf, "%#x", 0); + assert(!strcmp(buf, "0")); + sprintf(buf, "%#X", 0); + assert(!strcmp(buf, "0")); + sprintf(buf, "%#o", 0); + assert(!strcmp(buf, "0")); + + // Test 'd' with different size mods to see + // if they work + sprintf(buf, "%d", 12); + assert(!strcmp(buf, "12")); + sprintf(buf, "%ld", 12L); + assert(!strcmp(buf, "12")); + sprintf(buf, "%lld", 12LL); + assert(!strcmp(buf, "12")); + sprintf(buf, "%zd", (size_t)12); + assert(!strcmp(buf, "12")); + sprintf(buf, "%hd", 12); + assert(!strcmp(buf, "12")); + sprintf(buf, "%hhd", 12); + assert(!strcmp(buf, "12")); + + // Test 'x' with different size mods to see + // if they work + sprintf(buf, "%x", 12); + assert(!strcmp(buf, "c")); + sprintf(buf, "%lx", 12L); + assert(!strcmp(buf, "c")); + sprintf(buf, "%llx", 12LL); + assert(!strcmp(buf, "c")); + sprintf(buf, "%zx", (size_t)12); + assert(!strcmp(buf, "c")); + sprintf(buf, "%hx", 12); + assert(!strcmp(buf, "c")); + sprintf(buf, "%hhx", 12); + assert(!strcmp(buf, "c")); + + // Test 'X' with different size mods to see + // if they work + sprintf(buf, "%X", 12); + assert(!strcmp(buf, "C")); + sprintf(buf, "%lX", 12L); + assert(!strcmp(buf, "C")); + sprintf(buf, "%llX", 12LL); + assert(!strcmp(buf, "C")); + sprintf(buf, "%zX", (size_t)12); + assert(!strcmp(buf, "C")); + sprintf(buf, "%hX", 12); + assert(!strcmp(buf, "C")); + sprintf(buf, "%hhX", 12); + assert(!strcmp(buf, "C")); + + // Test 'o' with different size mods to see + // if they work + sprintf(buf, "%o", 12); + assert(!strcmp(buf, "14")); + sprintf(buf, "%lo", 12L); + assert(!strcmp(buf, "14")); + sprintf(buf, "%llo", 12LL); + assert(!strcmp(buf, "14")); + sprintf(buf, "%zo", (size_t)12); + assert(!strcmp(buf, "14")); + sprintf(buf, "%ho", 12); + assert(!strcmp(buf, "14")); + sprintf(buf, "%hho", 12); + assert(!strcmp(buf, "14")); + + // Test %n$ syntax. + sprintf(buf, "%1$d", 12); + assert(!strcmp(buf, "12")); + sprintf(buf, "%1$d %1$d", 12); + assert(!strcmp(buf, "12 12")); + sprintf(buf, "%1$d %2$d %1$d", 12, 14); + assert(!strcmp(buf, "12 14 12")); + sprintf(buf, "%1$d %2$s %2$s", 12, "foo"); + assert(!strcmp(buf, "12 foo foo")); + + return 0; +} diff --git a/lib/mlibc/tests/ansi/sscanf.c b/lib/mlibc/tests/ansi/sscanf.c new file mode 100644 index 0000000..f3a881f --- /dev/null +++ b/lib/mlibc/tests/ansi/sscanf.c @@ -0,0 +1,143 @@ +#include +#include +#include + +struct format_test_cases { + const char *format; + const char *data; + int expected_int; + enum { + T_INT, + T_UINT, + T_CHAR, + T_NONE, + } type; + int ret; +} formats[] = { + {"%i", "0x420", 0x420, T_INT, 1}, + {"%i", "0420", 0420, T_INT, 1}, + {"%i", "420", 420, T_INT, 1}, + {"%i", "-420", -420, T_INT, 1}, + {"%d", "-12345", -12345, T_INT, 1}, + {"%u", "69", 69, T_UINT, 1}, + {"%u", "0420", 420, T_UINT, 1}, + {"%o", "0420", 0420, T_UINT, 1}, + {"%x", "0xCB7", 0xCB7, T_UINT, 1}, + {"%%", "%", 0, T_NONE, 0}, + {"%c", " I am not a fan of this solution.", ' ', T_CHAR, 1}, + {" %c", " CBT (capybara therapy)", 'C', T_CHAR, 1}, +}; + +#pragma GCC diagnostic ignored "-Wformat-security" + +static void test_matrix() { + for(size_t i = 0; i < (sizeof(formats) / sizeof(*formats)); i++) { + struct format_test_cases *f = &formats[i]; + int ret = -1; + int data_int; + unsigned int data_uint; + char data_char; + + switch(f->type) { + case T_INT: { + ret = sscanf(f->data, f->format, &data_int); + assert(data_int == f->expected_int); + break; + } + case T_UINT: { + ret = sscanf(f->data, f->format, &data_uint); + assert(data_uint == (unsigned int) f->expected_int); + break; + } + case T_CHAR: { + ret = sscanf(f->data, f->format, &data_char); + assert(data_char == (unsigned char) f->expected_int); + break; + } + case T_NONE: { + ret = sscanf(f->data, f->format); + break; + } + + } + + assert(ret == f->ret); + } +} + +int main() { + { + int x = 0; + char buf[] = "12345"; + sscanf(buf, "%d", &x); + assert(x == 12345); + } + + { + char c; + int n1; + int n2; + char buf[] = "z$ 7 5 440";; + int count = sscanf(buf, "%*c%c %d %*d %d", &c, &n1, &n2); + assert(count == 3); + assert(c == '$'); + assert(n1 == 7); + assert(n2 == 440); + } + + { + // From dsda-doom + char buf[] = "process_priority 0\n"; + char def[80], strparm[128]; + memset(def, '!', 80); + memset(strparm, '!', 128); + sscanf(buf, "%s %[^\n]\n", def, strparm); + assert(!strcmp(def, "process_priority")); + assert(!strcmp(strparm, "0")); + } + + { + char buf[] = "fffff100"; + unsigned long y = 0; + sscanf(buf, "%lx", &y); + assert(y == 0xfffff100); + } + +#if !defined(__i386__) + { + char buf[] = "fffffffff100"; + unsigned long y = 0; + sscanf(buf, "%lx", &y); + assert(y == 0xfffffffff100); + } +#endif + + { + char buf[] = "410dc000"; + unsigned long y = 0; + sscanf(buf, "%lx", &y); + assert(y == 0x410dc000); + } + + { + // From webkitgtk + char buf[] = "MemTotal: 16299664 kB\n"; + char token[51] = {0}; + size_t amount = 0; + int ret = sscanf(buf, "%50s%zukB", token, &amount); + assert(ret == 2); + assert(!strcmp(token, "MemTotal:")); + assert(amount == 16299664); + } + + { + char buf[] = "SIGINT"; + int sig; + int ret = sscanf(buf, "%d", &sig); + assert(!ret); + } + + test_matrix(); + + return 0; +} diff --git a/lib/mlibc/tests/ansi/strchr.c b/lib/mlibc/tests/ansi/strchr.c new file mode 100644 index 0000000..a80a1f9 --- /dev/null +++ b/lib/mlibc/tests/ansi/strchr.c @@ -0,0 +1,20 @@ +#include +#include +#include + +int main() { + char str[] = "This is a sample string"; + char *pch; + // The character 's' is at position 4, 7, 11 and 18 + pch = strchr(str, 's'); + assert(pch - str + 1 == 4); + pch = strchr(pch + 1, 's'); + assert(pch - str + 1 == 7); + pch = strchr(pch + 1, 's'); + assert(pch - str + 1 == 11); + pch = strchr(pch + 1, 's'); + assert(pch - str + 1 == 18); + pch = strchr(pch + 1, 's'); + assert(pch == NULL); + return 0; +} diff --git a/lib/mlibc/tests/ansi/strftime.c b/lib/mlibc/tests/ansi/strftime.c new file mode 100644 index 0000000..69ec642 --- /dev/null +++ b/lib/mlibc/tests/ansi/strftime.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include + +int main() { + // Date representation depends on locale, here only C is tested. + // Maybe consider testing more locales? + if (setlocale (LC_ALL, "C") == NULL) { + fputs("strftime testcase could not set locale, errors may be expected!", stderr); + } + + char timebuf[16]; + char result[16] = " 8"; + struct tm tm; + tm.tm_sec = 0; + tm.tm_min = 17; + tm.tm_hour = 17; + tm.tm_mday = 8; + tm.tm_mon = 2; + tm.tm_year = 121; + tm.tm_wday = 2; + tm.tm_yday = 39; + strftime(timebuf, sizeof(timebuf), "%e", &tm); + assert(!strcmp(timebuf, result)); + + memset(timebuf, 0, sizeof(timebuf)); + strftime(timebuf, sizeof(timebuf), "%x", &tm); + assert(!strcmp(timebuf, "03/08/21")); + + memset(timebuf, 0, sizeof(timebuf)); + strftime(timebuf, sizeof(timebuf), "%X", &tm); + assert(!strcmp(timebuf, "17:17:00")); + + memset(timebuf, 0, sizeof(timebuf)); + strftime(timebuf, sizeof(timebuf), "%a %A", &tm); + assert(!strcmp(timebuf, "Tue Tuesday")); + + memset(timebuf, 0, sizeof(timebuf)); + strftime(timebuf, sizeof(timebuf), "%b %B %h", &tm); + assert(!strcmp(timebuf, "Mar March Mar")); + + memset(timebuf, 0, sizeof(timebuf)); + assert(!strftime(timebuf, sizeof(timebuf), "%a %A %a %A %b %B %h", &tm)); + + return 0; +} diff --git a/lib/mlibc/tests/ansi/strrchr.c b/lib/mlibc/tests/ansi/strrchr.c new file mode 100644 index 0000000..2de9821 --- /dev/null +++ b/lib/mlibc/tests/ansi/strrchr.c @@ -0,0 +1,11 @@ +#include +#include + +int main() { + char str[] = "This is a sample string"; + char *pch; + pch = strrchr(str, 's'); + // The last occurence of 's' is at position 18 + assert(pch - str + 1 == 18); + return 0; +} diff --git a/lib/mlibc/tests/ansi/strtof.c b/lib/mlibc/tests/ansi/strtof.c new file mode 100644 index 0000000..a13af90 --- /dev/null +++ b/lib/mlibc/tests/ansi/strtof.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include + +#define FLT_RANGE 0.000001f +#define DBL_RANGE 0.000001 +#define LDBL_RANGE 0.000001 + +#define DO_TEST(str, value, off, func, range) ({ \ + char s[] = (str); \ + char *pEnd = NULL; \ + __typeof(func(s, &pEnd)) result = func(s, &pEnd); \ + assert(result >= (value) - (range)); \ + assert(result <= (value) + (range)); \ + assert(pEnd == (off == -1 ? s + strlen(s) : s + off)); }) + +#define DO_TEST_SUCCESS_FUNC(str, success_func, off, func) ({ \ + char s[] = (str); \ + char *pEnd = NULL; \ + assert(success_func(func(s, &pEnd))); \ + assert(pEnd == (off == -1 ? s + strlen(s) : s + off)); }) + +int main () { + DO_TEST("0", 0.0f, -1, strtof, FLT_RANGE); + DO_TEST("0.12", 0.12f, -1, strtof, FLT_RANGE); + DO_TEST("12", 12.0f, -1, strtof, FLT_RANGE); + DO_TEST("12.13", 12.13f, -1, strtof, FLT_RANGE); + DO_TEST("10.0e1", 100.0f, -1, strtof, FLT_RANGE); + DO_TEST("10.0e10", 100000000000.0f, -1, strtof, FLT_RANGE); + DO_TEST("100.0e-1", 10.0f, -1, strtof, FLT_RANGE); + DO_TEST("0x0", 0.0f, -1, strtof, FLT_RANGE); + DO_TEST("0x0.12", 0.0703125f, -1, strtof, FLT_RANGE); + DO_TEST("0x12", 18.0f, -1, strtof, FLT_RANGE); + DO_TEST("0x12.13", 18.07421875f, -1, strtof, FLT_RANGE); + DO_TEST("0x10.0p1", 32.0f, -1, strtof, FLT_RANGE); + DO_TEST("0x10.0p10", 16384.0f, -1, strtof, FLT_RANGE); + DO_TEST("0x100.0p-1", 128.0f, -1, strtof, FLT_RANGE); + DO_TEST_SUCCESS_FUNC("NAN", isnan, -1, strtof); + DO_TEST_SUCCESS_FUNC("nan", isnan, -1, strtof); + DO_TEST_SUCCESS_FUNC("INF", isinf, -1, strtof); + DO_TEST_SUCCESS_FUNC("INFINITY", isinf, -1, strtof); + + DO_TEST("0", 0.0, -1, strtod, DBL_RANGE); + DO_TEST("0.12", 0.12, -1, strtod, DBL_RANGE); + DO_TEST("12", 12.0, -1, strtod, DBL_RANGE); + DO_TEST("12.13", 12.13, -1, strtod, DBL_RANGE); + DO_TEST("10.0e1", 100.0, -1, strtod, DBL_RANGE); + DO_TEST("10.0e10", 100000000000.0, -1, strtod, DBL_RANGE); + DO_TEST("100.0e-1", 10.0, -1, strtod, DBL_RANGE); + DO_TEST("0x0", 0.0, -1, strtod, DBL_RANGE); + DO_TEST("0x0.12", 0.0703125, -1, strtod, DBL_RANGE); + DO_TEST("0x12", 18.0, -1, strtod, DBL_RANGE); + DO_TEST("0x12.13", 18.07421875, -1, strtod, DBL_RANGE); + DO_TEST("0x10.0p1", 32.0, -1, strtod, DBL_RANGE); + DO_TEST("0x10.0p10", 16384.0, -1, strtod, DBL_RANGE); + DO_TEST("0x100.0p-1", 128.0, -1, strtod, DBL_RANGE); + DO_TEST_SUCCESS_FUNC("NAN", isnan, -1, strtod); + DO_TEST_SUCCESS_FUNC("nan", isnan, -1, strtod); + DO_TEST_SUCCESS_FUNC("INF", isinf, -1, strtod); + DO_TEST_SUCCESS_FUNC("INFINITY", isinf, -1, strtod); + + DO_TEST("0", 0.0, -1, strtold, LDBL_RANGE); + DO_TEST("0.12", 0.12, -1, strtold, LDBL_RANGE); + DO_TEST("12", 12.0, -1, strtold, LDBL_RANGE); + DO_TEST("12.13", 12.13, -1, strtold, LDBL_RANGE); + DO_TEST("10.0e1", 100.0, -1, strtold, LDBL_RANGE); + DO_TEST("10.0e10", 100000000000.0, -1, strtold, LDBL_RANGE); + DO_TEST("100.0e-1", 10.0, -1, strtold, LDBL_RANGE); + DO_TEST("0x0", 0.0, -1, strtold, LDBL_RANGE); + DO_TEST("0x0.12", 0.0703125, -1, strtold, LDBL_RANGE); + DO_TEST("0x12", 18.0, -1, strtold, LDBL_RANGE); + DO_TEST("0x12.13", 18.07421875, -1, strtold, LDBL_RANGE); + DO_TEST("0x10.0p1", 32.0, -1, strtold, LDBL_RANGE); + DO_TEST("0x10.0p10", 16384.0, -1, strtold, LDBL_RANGE); + DO_TEST("0x100.0p-1", 128.0, -1, strtold, LDBL_RANGE); + DO_TEST_SUCCESS_FUNC("NAN", isnan, -1, strtold); + DO_TEST_SUCCESS_FUNC("nan", isnan, -1, strtold); + DO_TEST_SUCCESS_FUNC("INF", isinf, -1, strtold); + DO_TEST_SUCCESS_FUNC("INFINITY", isinf, -1, strtold); + + return 0; +} diff --git a/lib/mlibc/tests/ansi/strtol.c b/lib/mlibc/tests/ansi/strtol.c new file mode 100644 index 0000000..823cb4a --- /dev/null +++ b/lib/mlibc/tests/ansi/strtol.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include +#include +#include + +#define DO_TEST(str, value, off, func, base) ({ \ + char s[] = (str); \ + char *pEnd = NULL; \ + errno = 0; \ + assert(func(s, &pEnd, base) == (value)); \ + assert(errno == 0); \ + assert(pEnd == (off == -1 ? s + strlen(s) : s + off)); }) + +#define DO_ERR_TEST(str, value, err, func, base) ({ \ + char s[] = (str); \ + char *pEnd = NULL; \ + errno = 0; \ + assert(func(s, &pEnd, base) == (value)); \ + assert(errno == err); \ + assert(pEnd == (err == ERANGE ? s + strlen(s) : s)); }) + +#define DO_TESTL(str, value, off, func, base) ({ \ + wchar_t s[] = (str); \ + wchar_t *pEnd = NULL; \ + errno = 0; \ + assert(func(s, &pEnd, base) == (value)); \ + assert(errno == 0); \ + assert(pEnd == (off == -1 ? s + wcslen(s) : s + off)); }) + +#define DO_ERR_TESTL(str, value, err, func, base) ({ \ + wchar_t s[] = (str); \ + wchar_t *pEnd = NULL; \ + errno = 0; \ + assert(func(s, &pEnd, base) == (value)); \ + assert(errno == err); \ + assert(pEnd == (err == ERANGE ? s + wcslen(s) : s)); }) + +int main () { + // A few generic checks. + DO_TEST("0", 0, -1, strtol, 0); + DO_TEST("0", 0, -1, strtol, 10); + DO_TEST("2001", 2001, -1, strtol, 10); + DO_TEST("+2001", 2001, -1, strtol, 10); + DO_TEST("60c0c0", 0x60c0c0, -1, strtol, 16); + DO_TEST("-1101110100110100100000", -3624224, -1, strtol, 2); + DO_TEST("0x6fffff", 0x6fffff, -1, strtol, 0); + DO_TEST("0666", 0666, -1, strtol, 0); + DO_TEST("0xzzz", 0, 1, strtol, 0); + DO_TEST("0yzzz", 0, 1, strtol, 0); + DO_TEST("00xzz", 0, 2, strtol, 0); + DO_ERR_TEST("", 0, 0, strtol, 10); + DO_ERR_TEST("asd", 0, 0, strtol, 10); + DO_ERR_TEST("999999999999999999999999999", LONG_MAX, ERANGE, strtol, 10); + DO_ERR_TEST("-999999999999999999999999999", LONG_MIN, ERANGE, strtol, 10); + + // strtol +#if defined(__i386__) + DO_TEST("-2147483648", LONG_MIN, -1, strtol, 10); + DO_TEST("2147483647", LONG_MAX, -1, strtol, 10); + DO_ERR_TEST("-2147483649", LONG_MIN, ERANGE, strtol, 10); + DO_ERR_TEST("2147483648", LONG_MAX, ERANGE, strtol, 10); +#else + DO_TEST("-9223372036854775808", LONG_MIN, -1, strtol, 10); + DO_TEST("9223372036854775807", LONG_MAX, -1, strtol, 10); + DO_ERR_TEST("9223372036854775808", LONG_MAX, ERANGE, strtol, 10); + DO_ERR_TEST("-9223372036854775809", LONG_MIN, ERANGE, strtol, 10); +#endif + + // wcstol +#if defined(__i386__) + DO_TESTL(L"-2147483648", LONG_MIN, -1, wcstol, 10); + DO_TESTL(L"2147483647", LONG_MAX, -1, wcstol, 10); + DO_ERR_TESTL(L"2147483648", LONG_MAX, ERANGE, wcstol, 10); + DO_ERR_TESTL(L"-2147483649", LONG_MIN, ERANGE, wcstol, 10); +#else + DO_TESTL(L"-9223372036854775808", LONG_MIN, -1, wcstol, 10); + DO_TESTL(L"9223372036854775807", LONG_MAX, -1, wcstol, 10); + DO_ERR_TESTL(L"9223372036854775808", LONG_MAX, ERANGE, wcstol, 10); + DO_ERR_TESTL(L"-9223372036854775809", LONG_MIN, ERANGE, wcstol, 10); +#endif + + // strtoll + DO_TEST("-9223372036854775808", LLONG_MIN, -1, strtoll, 10); + DO_TEST("9223372036854775807", LLONG_MAX, -1, strtoll, 10); + DO_ERR_TEST("9223372036854775808", LLONG_MAX, ERANGE, strtoll, 10); + DO_ERR_TEST("-9223372036854775809", LLONG_MIN, ERANGE, strtoll, 10); + // wcstoll + DO_TESTL(L"-9223372036854775808", LLONG_MIN, -1, wcstoll, 10); + DO_TESTL(L"9223372036854775807", LLONG_MAX, -1, wcstoll, 10); + DO_ERR_TESTL(L"9223372036854775808", LLONG_MAX, ERANGE, wcstoll, 10); + DO_ERR_TESTL(L"-9223372036854775809", LLONG_MIN, ERANGE, wcstoll, 10); + + // strtoul +#if defined(__i386__) + DO_TEST("-1", -(1UL), -1, strtoul, 10); + DO_TEST("2147483647", LONG_MAX, -1, strtoul, 10); + DO_TEST("4294967295", ULONG_MAX, -1, strtoul, 10); + DO_TEST("-4294967295", 1UL, -1, strtoul, 10); + DO_ERR_TEST("4294967296", ULONG_MAX, ERANGE, strtoul, 10); +#else + DO_TEST("-1", -(1UL), -1, strtoul, 10); + DO_TEST("9223372036854775807", LONG_MAX, -1, strtoul, 10); + DO_TEST("18446744073709551615", ULONG_MAX, -1, strtoul, 10); + DO_TEST("-18446744073709551615", 1UL, -1, strtoul, 10); + DO_ERR_TEST("18446744073709551616", ULONG_MAX, ERANGE, strtoul, 10); +#endif + + // wcstoul +#if defined(__i386__) + DO_TESTL(L"-1", -(1UL), -1, wcstoul, 10); + DO_TESTL(L"2147483647", LONG_MAX, -1, wcstoul, 10); + DO_TESTL(L"4294967295", ULONG_MAX, -1, wcstoul, 10); + DO_TESTL(L"-4294967295", 1UL, -1, wcstoul, 10); + DO_ERR_TESTL(L"4294967296", ULONG_MAX, ERANGE, wcstoul, 10); +#else + DO_TESTL(L"-1", -(1UL), -1, wcstoul, 10); + DO_TESTL(L"9223372036854775807", LONG_MAX, -1, wcstoul, 10); + DO_TESTL(L"18446744073709551615", ULONG_MAX, -1, wcstoul, 10); + DO_TESTL(L"-18446744073709551615", 1UL, -1, wcstoul, 10); + DO_ERR_TESTL(L"18446744073709551616", ULONG_MAX, ERANGE, wcstoul, 10); +#endif + + // strtoull + DO_TEST("-1", -(1ULL), -1, strtoull, 10); + DO_TEST("9223372036854775807", LLONG_MAX, -1, strtoull, 10); + DO_TEST("18446744073709551615", ULLONG_MAX, -1, strtoull, 10); + DO_TEST("-18446744073709551615", 1ULL, -1, strtoull, 10); + DO_ERR_TEST("18446744073709551616", ULLONG_MAX, ERANGE, strtoull, 10); + // wcstoull + DO_TESTL(L"-1", -(1ULL), -1, wcstoull, 10); + DO_TESTL(L"9223372036854775807", LLONG_MAX, -1, wcstoull, 10); + DO_TESTL(L"18446744073709551615", ULLONG_MAX, -1, wcstoull, 10); + DO_TESTL(L"-18446744073709551615", 1ULL, -1, wcstoull, 10); + DO_ERR_TESTL(L"18446744073709551616", ULLONG_MAX, ERANGE, wcstoull, 10); + + return 0; +} diff --git a/lib/mlibc/tests/ansi/strverscmp.c b/lib/mlibc/tests/ansi/strverscmp.c new file mode 100644 index 0000000..d6501a1 --- /dev/null +++ b/lib/mlibc/tests/ansi/strverscmp.c @@ -0,0 +1,16 @@ +#include +#include +#include + +int main() { + int res; + + res = strverscmp("jan1", "jan10"); + assert(res < 0); + + res = strverscmp("jan11", "jan10"); + assert(res > 0); + + res = strverscmp("jan1", "jan1"); + assert(res == 0); +} diff --git a/lib/mlibc/tests/ansi/strxfrm.c b/lib/mlibc/tests/ansi/strxfrm.c new file mode 100644 index 0000000..07a4082 --- /dev/null +++ b/lib/mlibc/tests/ansi/strxfrm.c @@ -0,0 +1,14 @@ +#include +#include +#include + +int main() { + setlocale(LC_ALL, "C"); + + const char *buf = "cbtteststring"; + char dest[14]; + size_t ret = strxfrm(dest, buf, strlen(buf) + 1); + assert(ret == 13); + int cmp = strncmp(dest, buf, 13); + assert(!cmp); +} diff --git a/lib/mlibc/tests/ansi/timegm.c b/lib/mlibc/tests/ansi/timegm.c new file mode 100644 index 0000000..f5af03e --- /dev/null +++ b/lib/mlibc/tests/ansi/timegm.c @@ -0,0 +1,45 @@ +#include +#include +#include + +int main() { + struct tm soon = {}; + soon.tm_sec = 0; + soon.tm_min = 0; + soon.tm_hour = 0; + soon.tm_mday = 1; + soon.tm_mon = 0; + soon.tm_year = 70; + time_t result; + time_t expected_result = 0; + // This should be epoch. + result = timegm(&soon); + printf("epoch: %ld\n", result); + assert(result == expected_result); + + soon.tm_sec = 12; + soon.tm_min = 8; + soon.tm_hour = 16; + soon.tm_mday = 17; + soon.tm_mon = 4; + soon.tm_year = 122; + expected_result = 1652803692; + result = timegm(&soon); + // On my host, this returned 1652803692, verify this. + printf("epoch: %ld\n", result); + assert(result == expected_result); + + soon.tm_sec = 45; + soon.tm_min = 42; + soon.tm_hour = 17; + soon.tm_mday = 16; + soon.tm_mon = 8; + soon.tm_year = 69; + expected_result = -9181035; + result = timegm(&soon); + // On my host, this returned -9181035, verify this. + printf("epoch: %ld\n", result); + assert(result == expected_result); + + return 0; +} diff --git a/lib/mlibc/tests/ansi/ungetc.c b/lib/mlibc/tests/ansi/ungetc.c new file mode 100644 index 0000000..8773c6d --- /dev/null +++ b/lib/mlibc/tests/ansi/ungetc.c @@ -0,0 +1,74 @@ +#include +#include + +#ifdef USE_HOST_LIBC +#define TEST_FILE "ungetc-host-libc.tmp" +#else +#define TEST_FILE "ungetc.tmp" +#endif + +void test(int buffering) { + FILE *f = fopen(TEST_FILE, "w"); + for(int c = '0'; c <= '9'; c++) { + fputc(c, f); + } + fclose(f); + + f = fopen(TEST_FILE, "r"); + if (!buffering) { + setbuf(f, NULL); + } + + assert(ungetc('x', f) == 'x'); + assert(fgetc(f) == 'x'); + + // Test pushing back the same character + for (int c = '0'; c <= '9'; c++) { + assert(fgetc(f) == c); + assert(ungetc(c, f) == c); + assert(fgetc(f) == c); + } + assert(fgetc(f) == EOF); + assert(ungetc(EOF, f) == EOF); + + // Even though the spec does not guarantee it, we should be able to + // ungetc more than one character. + assert(ungetc('x', f) == 'x'); + assert(ungetc('y', f) == 'y'); + assert(fgetc(f) == 'y'); + assert(fgetc(f) == 'x'); + + // Seeking should discard the effects of ungetc. + assert(ungetc('x', f) == 'x'); + rewind(f); + + // Test pushing back a different character + for (int c = '0'; c <= '9'; c++) { + assert(fgetc(f) == c); + assert(ungetc(c - '0' + 'a', f) == c - '0' + 'a'); + assert(fgetc(f) == c - '0' + 'a'); + } + +#ifndef USE_HOST_LIBC + // Too many ungetcs should fail. + int eof = 0; + for (int i = 0; i < 100; i++) { + if (ungetc('x', f) == EOF) { + eof = 1; + break; + } + } + assert(eof); +#endif + + fclose(f); + + // TODO: Test with other operations, like fread. +} + +int main() { + fprintf(stderr, "with buffering...\n"); + test(1); + fprintf(stderr, "without buffering...\n"); + test(0); +} diff --git a/lib/mlibc/tests/ansi/utf8.c b/lib/mlibc/tests/ansi/utf8.c new file mode 100644 index 0000000..18b0d5a --- /dev/null +++ b/lib/mlibc/tests/ansi/utf8.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include +#include +#include + +#if UINTPTR_MAX == UINT64_MAX +#define WCHAR_SPEC "" +#else +#define WCHAR_SPEC "l" +#endif + +#define EXPECT(func) ({ \ + if(res != expected_ret) { \ + printf(#func " decoded %d bytes (expected %d bytes), at %s:%d\n", \ + res, expected_ret, __FILE__, line); \ + fflush(stdout); \ + abort(); \ + } \ + if(wc != expected) { \ + printf(#func " output cp %" WCHAR_SPEC "x (expected cp %" WCHAR_SPEC "x), at %s:%d\n", wc, \ + expected, __FILE__, line); \ + fflush(stdout); \ + abort(); \ + } \ + }) + +void verify_decode(const char *input, wchar_t expected, int line) { + wchar_t wc; + int bytes = *input ? strlen(input) : 1; + int expected_ret = *input ? strlen(input) : 0; + + // Check mbrtowc(). + mbstate_t state; + memset(&state, 0, sizeof(state)); + assert(mbrtowc(NULL, NULL, -1, &state) == 0); + int res = mbrtowc(&wc, input, bytes, &state); + EXPECT("mbrtowc"); + res = mbrtowc(NULL, input, bytes, &state); + EXPECT("mbrtowc (pwc == NULL)"); + + // Check mbtowc(). + assert(mbtowc(NULL, NULL, -1) == 0); + res = mbtowc(&wc, input, bytes); + EXPECT("mbtowc"); + res = mbtowc(NULL, input, bytes); + EXPECT("mbtowc (pwc == NULL)"); +} + +int main() { + setlocale(LC_ALL, "C.UTF-8"); + +#define verify_decode(in, out) verify_decode(in, out, __LINE__) + verify_decode("\x24", 0x24); + verify_decode("\xC2\xA2", 0xA2); + verify_decode("\xE0\xA4\xB9", 0x939); + verify_decode("\xE2\x82\xAC", 0x20AC); + verify_decode("\xED\x95\x9C", 0xD55C); + verify_decode("\xF0\x90\x8D\x88", 0x10348); + verify_decode("", L'\0'); +} diff --git a/lib/mlibc/tests/ansi/wcsdup.c b/lib/mlibc/tests/ansi/wcsdup.c new file mode 100644 index 0000000..564b77e --- /dev/null +++ b/lib/mlibc/tests/ansi/wcsdup.c @@ -0,0 +1,11 @@ +#include +#include +#include +#include + +int main() { + wchar_t *wide_string = L"test string\n"; + wchar_t *dup_string = wcsdup(wide_string); + assert(!memcmp(wide_string, dup_string, (wcslen(wide_string) + 1) * sizeof(wchar_t))); + free(dup_string); +} diff --git a/lib/mlibc/tests/ansi/wcsncasecmp.c b/lib/mlibc/tests/ansi/wcsncasecmp.c new file mode 100644 index 0000000..fcbe98f --- /dev/null +++ b/lib/mlibc/tests/ansi/wcsncasecmp.c @@ -0,0 +1,11 @@ +#include +#include + +int main() { + assert(!wcsncasecmp(L"foo", L"foo", 3)); + assert(!wcsncasecmp(L"foo", L"FOO", 3)); + assert(!wcsncasecmp(L"fooa", L"FOOB", 3)); + assert(wcsncasecmp(L"foo", L"bar", 3)); + assert(!wcsncasecmp(L"fooa", L"FOOA", 4)); + assert(!wcsncasecmp(L"123abc", L"123AbC", 6)); +} diff --git a/lib/mlibc/tests/ansi/wcsrtombs.c b/lib/mlibc/tests/ansi/wcsrtombs.c new file mode 100644 index 0000000..80df257 --- /dev/null +++ b/lib/mlibc/tests/ansi/wcsrtombs.c @@ -0,0 +1,12 @@ +#include +#include +#include +#include + +int main() { + const wchar_t str[] = L"wcsrtombs"; + const wchar_t *p = str; + int ret = wcsrtombs(NULL, &p, 343245234, NULL); + assert(ret == 9); + return 0; +} diff --git a/lib/mlibc/tests/ansi/wmemcmp.c b/lib/mlibc/tests/ansi/wmemcmp.c new file mode 100644 index 0000000..74de9bd --- /dev/null +++ b/lib/mlibc/tests/ansi/wmemcmp.c @@ -0,0 +1,19 @@ +#include +#include +#include + +int main(void){ + wchar_t *ws1 = calloc(10, sizeof(wchar_t)); + wchar_t *ws2 = calloc(10, sizeof(wchar_t)); + + mbstowcs(ws1, "Test 1", 10); + mbstowcs(ws2, "Tester 2", 10); + + assert(wmemcmp(ws1, ws2, 10) < 0); + assert(wmemcmp(ws2, ws1, 10) > 0); + assert(wmemcmp(ws2, ws2, 10) == 0); + + free(ws1); + free(ws2); + return 0; +} -- cgit v1.2.3