diff --git a/src/stdio/snprintf.c b/src/stdio/snprintf.c new file mode 100644 index 0000000..f8768a8 --- /dev/null +++ b/src/stdio/snprintf.c @@ -0,0 +1,164 @@ +#define _XOPEN_SOURCE 700 +#include +#include +#include +#include +#include +#include "test.h" + +#define DISABLE_SLOW_TESTS + +#define TEST(r, f, x, m) ( \ + ((r) = (f)) == (x) || \ + (error("%s failed (" m ")\n", #f, r, x), 0) ) + +#define TEST_S(s, x, m) ( \ + !strcmp((s),(x)) || \ + (error("[%s] != [%s] (%s)\n", s, x, m), 0) ) + +static const struct { + const char *fmt; + int i; + const char *expect; +} int_tests[] = { + /* width, precision, alignment */ + { "%04d", 12, "0012" }, + { "%.3d", 12, "012" }, + { "%3d", 12, " 12" }, + { "%-3d", 12, "12 " }, + { "%+3d", 12, "+12" }, + { "%+-5d", 12, "+12 " }, + { "%+- 5d", 12, "+12 " }, + { "%- 5d", 12, " 12 " }, + { "% d", 12, " 12" }, + { "%0-5d", 12, "12 " }, + { "%-05d", 12, "12 " }, + + /* ...explicit precision of 0 shall be no characters. */ + { "%.0d", 0, "" }, + { "%.0o", 0, "" }, + { "%#.0d", 0, "" }, + { "%#.0o", 0, "" }, + { "%#.0x", 0, "" }, + + /* ...but it still has to honor width and flags. */ + { "%2.0u", 0, " " }, + { "%02.0u", 0, " " }, + { "%2.0d", 0, " " }, + { "%02.0d", 0, " " }, + { "% .0d", 0, " " }, + { "%+.0d", 0, "+" }, + + /* hex: test alt form and case */ + { "%x", 63, "3f" }, + { "%#x", 63, "0x3f" }, + { "%X", 63, "3F" }, + + /* octal: test alt form */ + { "%o", 15, "17" }, + { "%#o", 15, "017" }, + + { NULL, 0.0, NULL } +}; + +static const struct { + const char *fmt; + double f; + const char *expect; +} fp_tests[] = { + /* basic form, handling of exponent/precision for 0 */ + { "%e", 0.0, "0.000000e+00" }, + { "%f", 0.0, "0.000000" }, + { "%g", 0.0, "0" }, + { "%#g", 0.0, "0.00000" }, + + /* rounding */ + { "%f", 1.1, "1.100000" }, + { "%f", 1.2, "1.200000" }, + { "%f", 1.3, "1.300000" }, + { "%f", 1.4, "1.400000" }, + { "%f", 1.5, "1.500000" }, + { "%.4f", 1.06125, "1.0612" }, + { "%.2f", 1.375, "1.38" }, + { "%.1f", 1.375, "1.4" }, + { "%.15f", 1.1, "1.100000000000000" }, + { "%.16f", 1.1, "1.1000000000000001" }, + { "%.17f", 1.1, "1.10000000000000009" }, + { "%.2e", 1500001.0, "1.50e+06" }, + { "%.2e", 1505000.0, "1.50e+06" }, + { "%.2e", 1505000.00000095367431640625, "1.51e+06" }, + { "%.2e", 1505001.0, "1.51e+06" }, + { "%.2e", 1506000.0, "1.51e+06" }, + + /* correctness in DBL_DIG places */ + { "%.15g", 1.23456789012345, "1.23456789012345" }, + + /* correct choice of notation for %g */ + { "%g", 0.0001, "0.0001" }, + { "%g", 0.00001, "1e-05" }, + { "%g", 123456, "123456" }, + { "%g", 1234567, "1.23457e+06" }, + { "%.7g", 1234567, "1234567" }, + { "%.7g", 12345678, "1.234568e+07" }, + { "%.8g", 0.1, "0.1" }, + { "%.9g", 0.1, "0.1" }, + { "%.10g", 0.1, "0.1" }, + { "%.11g", 0.1, "0.1" }, + + /* pi in double precision, printed to a few extra places */ + { "%.15f", M_PI, "3.141592653589793" }, + { "%.18f", M_PI, "3.141592653589793116" }, + + /* exact conversion of large integers */ + { "%.0f", 340282366920938463463374607431768211456.0, + "340282366920938463463374607431768211456" }, + + { NULL, 0.0, NULL } +}; + +void test_snprintf(void) +{ + int i, j, k; + char b[2000], *s; + + TEST(i, snprintf(0, 0, "%d", 123456), 6, "length returned %d != %d"); + TEST(i, snprintf(0, 0, "%.4s", "hello"), 4, "length returned %d != %d"); + TEST(i, snprintf(b, 0, "%.0s", "goodbye"), 0, "length returned %d != %d"); + + strcpy(b, "xxxxxxxx"); + TEST(i, snprintf(b, 4, "%d", 123456), 6, "length returned %d != %d"); + TEST_S(b, "123", "incorrect output"); + TEST(i, b[5], 'x', "buffer overrun"); + + /* Perform ascii arithmetic to test printing tiny doubles */ + TEST(i, snprintf(b, sizeof b, "%.1022f", 0x1p-1021), 1024, "%d != %d"); + b[1] = '0'; + for (i=0; i<1021; i++) { + for (k=0, j=1023; j>0; j--) { + if (b[j]<'5') b[j]+=b[j]-'0'+k, k=0; + else b[j]+=b[j]-'0'-10+k, k=1; + } + } + TEST(i, b[1], '1', "'%c' != '%c'"); + for (j=2; b[j]=='0'; j++); + TEST(i, j, 1024, "%d != %d"); + + +#ifndef DISABLE_SLOW_TESTS + errno = 0; + TEST(i, snprintf(NULL, 0, "%.*u", 2147483647, 0), 2147483647, "cannot print max length %d"); + TEST(i, snprintf(NULL, 0, "%.*u ", 2147483647, 0), -1, "integer overflow %d"); + TEST(i, errno, EOVERFLOW, "after overflow: %d != %d"); +#endif + for (j=0; int_tests[j].fmt; j++) { + TEST(i, snprintf(b, sizeof b, int_tests[j].fmt, int_tests[j].i), strlen(b), "%d != %d"); + TEST_S(b, int_tests[j].expect, "bad integer conversion"); + } + + for (j=0; fp_tests[j].fmt; j++) { + TEST(i, snprintf(b, sizeof b, fp_tests[j].fmt, fp_tests[j].f), strlen(b), "%d != %d"); + TEST_S(b, fp_tests[j].expect, "bad floating point conversion"); + } + + TEST(i, snprintf(0, 0, "%.4a", 1.0), 11, "%d != %d"); +} diff --git a/src/stdio/sscanf.c b/src/stdio/sscanf.c new file mode 100644 index 0000000..0d49431 --- /dev/null +++ b/src/stdio/sscanf.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include "test.h" + +#define TEST(r, f, x, m) ( \ + ((r) = (f)) == (x) || \ + (error("%s failed (" m ")\n", #f, r, x), 0) ) + +#define TEST_S(s, x, m) ( \ + !strcmp((s),(x)) || \ + (error("[%s] != [%s] (%s)\n", s, x, m), 0) ) + +#define TEST_F(x) ( \ + TEST(i, sscanf(# x, "%lf", &d), 1, "got %d fields, expected %d"), \ + TEST(t, d, (double)x, "%g != %g") ) + +void test_sscanf(void) { + int i; + char a[100], b[100]; + int x, y, z, u, v; + double d, t; + + TEST(i, sscanf("hello, world\n", "%s %s", a, b), 2, "only %d fields, expected %d"); + TEST_S(a, "hello,", ""); + TEST_S(b, "world", ""); + + TEST(i, sscanf("hello, world\n", "%[hel]%s", a, b), 2, "only %d fields, expected %d"); + TEST_S(a, "hell", ""); + TEST_S(b, "o,", ""); + + TEST(i, sscanf("hello, world\n", "%[hel] %s", a, b), 2, "only %d fields, expected %d"); + TEST_S(a, "hell", ""); + TEST_S(b, "o,", ""); + + a[8] = 'X'; + a[9] = 0; + TEST(i, sscanf("hello, world\n", "%8c%8c", a, b), 1, "%d fields, expected %d"); + TEST_S(a, "hello, wX", ""); + + TEST(i, sscanf("56789 0123 56a72", "%2d%d%*d %[0123456789]\n", &x, &y, a), 3, "only %d fields, expected %d"); + TEST(i, x, 56, "%d != %d"); + TEST(i, y, 789, "%d != %d"); + TEST_S(a, "56", ""); + + TEST(i, sscanf("011 0x100 11 0x100 100", "%i %i %o %x %x\n", &x, &y, &z, &u, &v), 5, "only %d fields, expected %d"); + TEST(i, x, 9, "%d != %d"); + TEST(i, y, 256, "%d != %d"); + TEST(i, z, 9, "%d != %d"); + TEST(i, u, 256, "%d != %d"); + TEST(i, v, 256, "%d != %d"); + + TEST(i, sscanf("20 xyz", "%d %d\n", &x, &y), 1, "only %d fields, expected %d"); + TEST(i, x, 20, "%d != %d"); + + TEST(i, sscanf("xyz", "%d\n", &x, &y), 0, "got %d fields, expected no match (%d)"); + + TEST(i, sscanf("", "%d\n", &x, &y), -1, "got %d fields, expected input failure (%d)"); + + TEST(i, sscanf(" 12345 6", "%2d%d%d", &x, &y, &z), 3, "only %d fields, expected %d"); + TEST(i, x, 12, "%d != %d"); + TEST(i, y, 345, "%d != %d"); + TEST(i, z, 6, "%d != %d"); + + TEST(i, sscanf(" 0x12 0x34", "%5i%2i", &x, &y), 1, "got %d fields, expected %d"); + TEST(i, x, 0x12, "%d != %d"); + + TEST_F(123); + TEST_F(123.0); + TEST_F(123.0e+0); + TEST_F(123.0e+4); + TEST_F(1.234e1234); + TEST_F(1.234e-1234); + TEST_F(1.234e56789); + TEST_F(1.234e-56789); + TEST_F(-0.5); + TEST_F(0.1); + TEST_F(0.2); + TEST_F(0.1e-10); + TEST_F(0x1234p56); + + TEST(i, sscanf("10e", "%lf", &d), 0, "got %d fields, expected no match (%d)"); + TEST(i, sscanf("", "%lf\n", &d), -1, "got %d fields, expected input failure (%d)"); +} diff --git a/src/stdio/swprintf.c b/src/stdio/swprintf.c new file mode 100644 index 0000000..f05b150 --- /dev/null +++ b/src/stdio/swprintf.c @@ -0,0 +1,136 @@ +#define _XOPEN_SOURCE 700 +#include +#include +#include +#include +#include +#include +#include +#include +#include "test.h" + +#define TEST(r, f, x, m) ( \ + ((r) = (f)) == (x) || \ + (error("%s failed (" m ")\n", #f, r, x), 0) ) + +#define TEST_S(s, x, m) ( \ + !wcscmp((s),(x)) || \ + (error("[%ls] != [%ls] (%s)\n", s, x, m), 0) ) + +static const struct { + const wchar_t *fmt; + int i; + const wchar_t *expect; +} int_tests[] = { + /* width, precision, alignment */ + { L"%04d", 12, L"0012" }, + { L"%.3d", 12, L"012" }, + { L"%3d", 12, L" 12" }, + { L"%-3d", 12, L"12 " }, + { L"%+3d", 12, L"+12" }, + { L"%+-5d", 12, L"+12 " }, + { L"%+- 5d", 12, L"+12 " }, + { L"%- 5d", 12, L" 12 " }, + { L"% d", 12, L" 12" }, + { L"%0-5d", 12, L"12 " }, + { L"%-05d", 12, L"12 " }, + + /* ...explicit precision of 0 shall be no characters. */ + { L"%.0d", 0, L"" }, + { L"%.0o", 0, L"" }, + { L"%#.0d", 0, L"" }, + { L"%#.0o", 0, L"" }, + { L"%#.0x", 0, L"" }, + + /* hex: test alt form and case */ + { L"%x", 63, L"3f" }, + { L"%#x", 63, L"0x3f" }, + { L"%X", 63, L"3F" }, + + /* octal: test alt form */ + { L"%o", 15, L"17" }, + { L"%#o", 15, L"017" }, + + { NULL, 0.0, NULL } +}; + +static const struct { + const wchar_t *fmt; + double f; + const wchar_t *expect; +} fp_tests[] = { + /* basic form, handling of exponent/precision for 0 */ + { L"%e", 0.0, L"0.000000e+00" }, + { L"%f", 0.0, L"0.000000" }, + { L"%g", 0.0, L"0" }, + { L"%#g", 0.0, L"0.00000" }, + + /* rounding */ + { L"%f", 1.1, L"1.100000" }, + { L"%f", 1.2, L"1.200000" }, + { L"%f", 1.3, L"1.300000" }, + { L"%f", 1.4, L"1.400000" }, + { L"%f", 1.5, L"1.500000" }, + + /* correctness in DBL_DIG places */ + { L"%.15g", 1.23456789012345, L"1.23456789012345" }, + + /* correct choice of notation for %g */ + { L"%g", 0.0001, L"0.0001" }, + { L"%g", 0.00001, L"1e-05" }, + { L"%g", 123456, L"123456" }, + { L"%g", 1234567, L"1.23457e+06" }, + { L"%.7g", 1234567, L"1234567" }, + { L"%.7g", 12345678, L"1.234568e+07" }, + + /* pi in double precision, printed to a few extra places */ + { L"%.15f", M_PI, L"3.141592653589793" }, + { L"%.18f", M_PI, L"3.141592653589793116" }, + + /* exact conversion of large integers */ + { L"%.0f", 340282366920938463463374607431768211456.0, + L"340282366920938463463374607431768211456" }, + + { NULL, 0.0, NULL } +}; + +void test_swprintf(void) { + int i, j; + wchar_t b[500], *s; + + setlocale(LC_CTYPE, "en_US.UTF-8") || + setlocale(LC_CTYPE, "en_GB.UTF-8") || + setlocale(LC_CTYPE, "en.UTF-8") || + setlocale(LC_CTYPE, "POSIX.UTF-8") || + setlocale(LC_CTYPE, "C.UTF-8") || + setlocale(LC_CTYPE, "UTF-8") || + setlocale(LC_CTYPE, ""); + + TEST(i, strcmp(nl_langinfo(CODESET), "UTF-8"), 0, "no UTF-8 locale; tests might fail"); + + TEST(i, swprintf(0, 0, L"%d", 123456)<0, 1, "%d != %d"); + + TEST(i, swprintf(b, 2, L"%lc", 0xc0), 1, "%d != %d"); + TEST(i, b[0], 0xc0, "wrong character %x != %x"); + TEST(i, swprintf(b, 2, L"%lc", 0x20ac), 1, "%d != %d"); + TEST(i, b[0], 0x20ac, "wrong character %x != %x"); + TEST(i, swprintf(b, 3, L"%s", "\xc3\x80!"), 2, "%d != %d"); + TEST(i, b[0], 0xc0, "wrong character %x != %x"); + TEST(i, swprintf(b, 2, L"%.1s", "\xc3\x80!"), 1, "%d != %d"); + TEST(i, b[0], 0xc0, "wrong character %x != %x"); + + wcscpy(b, L"xxxxxxxx"); + TEST(i, swprintf(b, 4, L"%d", 123456)<0, 1, "%d != %d"); + TEST_S(b, L"123", "incorrect output"); + TEST(i, b[5], 'x', "buffer overrun"); + + for (j=0; int_tests[j].fmt; j++) { + TEST(i, swprintf(b, sizeof b/sizeof *b, int_tests[j].fmt, int_tests[j].i), wcslen(b), "%d != %d"); + TEST_S(b, int_tests[j].expect, "bad integer conversion"); + } + + for (j=0; fp_tests[j].fmt; j++) { + TEST(i, swprintf(b, sizeof b/sizeof *b, fp_tests[j].fmt, fp_tests[j].f), wcslen(b), "%d != %d"); + TEST_S(b, fp_tests[j].expect, "bad floating point conversion"); + } +} diff --git a/src/stdio/ungetc.c b/src/stdio/ungetc.c new file mode 100644 index 0000000..855ffaa --- /dev/null +++ b/src/stdio/ungetc.c @@ -0,0 +1,52 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include "test.h" + +#define TEST(r, f, x, m) ( \ + errno = 0, ((r) = (f)) == (x) || \ + (error("%s failed (" m ")\n", #f, r, x, strerror(errno)), 0) ) + +#define TEST_S(s, x, m) ( \ + !strcmp((s),(x)) || \ + (error("[%s] != [%s] (%s)\n", s, x, m), 0) ) + +void test_ungetc(void) { + int i; + char a[100]; + FILE *f; + + TEST(i, !(f = tmpfile()), 0, "failed to create temp file %d!=%d (%s)"); + + if (!f) return; + + TEST(i, fprintf(f, "hello, world\n"), 13, "%d != %d (%m)"); + TEST(i, fseek(f, 0, SEEK_SET), 0, "%d != %d (%m)"); + + TEST(i, feof(f), 0, "%d != %d"); + TEST(i, fgetc(f), 'h', "'%c' != '%c'"); + TEST(i, ftell(f), 1, "%d != %d"); + TEST(i, ungetc('x', f), 'x', "%d != %d"); + TEST(i, ftell(f), 0, "%d != %d"); + TEST(i, fscanf(f, "%[h]", a), 0, "got %d fields, expected %d"); + TEST(i, ftell(f), 0, "%d != %d"); + TEST(i, fgetc(f), 'x', "'%c' != '%c'"); + TEST(i, ftell(f), 1, "%d != %d"); + + TEST(i, fseek(f, 0, SEEK_SET), 0, "%d != %d"); + TEST(i, ungetc('x', f), 'x', "%d != %d"); + TEST(i, fread(a, 1, sizeof a, f), 14, "read %d, expected %d"); + a[14] = 0; + TEST_S(a, "xhello, world\n", "mismatch reading ungot character"); + + TEST(i, fseek(f, 0, SEEK_SET), 0, "%d != %d"); + TEST(i, fscanf(f, "%[x]", a), 0, "got %d fields, expected %d"); + TEST(i, ungetc('x', f), 'x', "unget failed after fscanf: %d != %d"); + TEST(i, fgetc(f), 'x', "'%c' != '%c'"); + TEST(i, fgetc(f), 'h', "'%c' != '%c'"); + + fclose(f); +} diff --git a/src/stdlib/strtod.c b/src/stdlib/strtod.c new file mode 100644 index 0000000..a4a8b53 --- /dev/null +++ b/src/stdlib/strtod.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include "test.h" + +/* r = place to store result + * f = function call to test (or any expression) + * x = expected result + * m = message to print on failure (with formats for r & x) +**/ + +#define TEST(r, f, x, m) ( \ + ((r) = (f)) == (x) || \ + (error("%s failed (" m ")\n", #f, r, x, r-x), 0) ) + +void test_strtod(void) { + int i; + double d, d2; + char buf[1000]; + + for (i=0; i<100; i++) { + d = sin(i); + snprintf(buf, sizeof buf, "%.300f", d); + TEST(d2, strtod(buf, 0), d, "round trip fail %a != %a (%a)"); + } + + TEST(d, strtod("0x1p4", 0), 16.0, "hex float %a != %a"); + TEST(d, strtod("0x1.1p4", 0), 17.0, "hex float %a != %a"); +} diff --git a/src/stdlib/strtol.c b/src/stdlib/strtol.c new file mode 100644 index 0000000..7d9213f --- /dev/null +++ b/src/stdlib/strtol.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include +#include "test.h" + +/* r = place to store result + * f = function call to test (or any expression) + * x = expected result + * m = message to print on failure (with formats for r & x) +**/ + +#define TEST(r, f, x, m) ( \ + errno = 0, msg = #f, ((r) = (f)) == (x) || \ + (error("%s failed (" m ")\n", #f, r, x), 0) ) + +#define TEST2(r, f, x, m) ( \ + ((r) = (f)) == (x) || \ + (error("%s failed (" m ")\n", msg, r, x), 0) ) + +void test_strtol(void) { + int i; + long l; + unsigned long ul; + char *msg=""; + char *s, *c; + + TEST(l, atol("2147483647"), 2147483647L, "max 32bit signed %ld != %ld"); + TEST(l, strtol("2147483647", 0, 0), 2147483647L, "max 32bit signed %ld != %ld"); + TEST(ul, strtoul("4294967295", 0, 0), 4294967295UL, "max 32bit unsigned %lu != %lu"); + + if (sizeof(long) == 4) { + TEST(l, strtol(s="2147483648", &c, 0), 2147483647L, "uncaught overflow %ld != %ld"); + TEST2(i, c-s, 10, "wrong final position %d != %d"); + TEST2(i, errno, ERANGE, "missing errno %d != %d"); + TEST(l, strtol(s="-2147483649", &c, 0), -2147483647L-1, "uncaught overflow %ld != %ld"); + TEST2(i, c-s, 11, "wrong final position %d != %d"); + TEST2(i, errno, ERANGE, "missing errno %d != %d"); + TEST(ul, strtoul(s="4294967296", &c, 0), 4294967295UL, "uncaught overflow %lu != %lu"); + TEST2(i, c-s, 10, "wrong final position %d != %d"); + TEST2(i, errno, ERANGE, "missing errno %d != %d"); + TEST(ul, strtoul(s="-1", &c, 0), 4294967295UL, "uncaught overflow %lu != %lu"); + TEST2(i, c-s, 2, "wrong final position %d != %d"); + TEST2(i, errno, ERANGE, "missing errno %d != %d"); + TEST(ul, strtoul(s="-2", &c, 0), 4294967295UL, "uncaught overflow %lu != %lu"); + TEST2(i, c-s, 2, "wrong final position %d != %d"); + TEST2(i, errno, ERANGE, "missing errno %d != %d"); + TEST(ul, strtoul(s="-2147483648", &c, 0), 4294967295UL, "uncaught overflow %lu != %lu"); + TEST2(i, c-s, 11, "wrong final position %d != %d"); + TEST2(i, errno, ERANGE, "missing errno %d != %d"); + TEST(ul, strtoul(s="-2147483649", &c, 0), 4294967295UL, "uncaught overflow %lu != %lu"); + TEST2(i, c-s, 11, "wrong final position %d != %d"); + TEST2(i, errno, ERANGE, "missing errno %d != %d"); + } else { + TEST(i, 0, 1, "64bit tests not implemented"); + } + + TEST(l, strtol("z", 0, 36), 35, "%ld != %ld"); + TEST(l, strtol("00010010001101000101011001111000", 0, 2), 0x12345678, "%ld != %ld"); + TEST(l, strtol(s="0F5F", &c, 16), 0x0f5f, "%ld != %ld"); + + TEST(l, strtol(s="0xz", &c, 16), 0, "%ld != %ld"); + TEST2(i, c-s, 1, "wrong final position %ld != %ld"); + + TEST(l, strtol(s="0x1234", &c, 16), 0x1234, "%ld != %ld"); + TEST2(i, c-s, 6, "wrong final position %ld != %ld"); + + c = NULL; + TEST(l, strtol(s="123", &c, 37), 0, "%ld != %ld"); + TEST2(i, c-s, 0, "wrong final position %d != %d"); + TEST2(i, errno, EINVAL, "%d != %d"); +} diff --git a/src/stdlib/wcstol.c b/src/stdlib/wcstol.c new file mode 100644 index 0000000..fe8d747 --- /dev/null +++ b/src/stdlib/wcstol.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include "test.h" + +#define TEST(r, f, x, m) ( \ + errno = 0, msg = #f, ((r) = (f)) == (x) || \ + (error("%s failed (" m ")\n", #f, r, x), 0) ) + +#define TEST2(r, f, x, m) ( \ + ((r) = (f)) == (x) || \ + (error("%s failed (" m ")\n", msg, r, x), 0) ) + +void test_wcstol(void) { + int i; + long l; + unsigned long ul; + char *msg=""; + wchar_t *s, *c; + + TEST(l, wcstol(L"2147483647", 0, 0), 2147483647L, "max 32bit signed %ld != %ld"); + TEST(ul, wcstoul(L"4294967295", 0, 0), 4294967295UL, "max 32bit unsigned %lu != %lu"); + + if (sizeof(long) == 4) { + TEST(l, wcstol(s=L"2147483648", &c, 0), 2147483647L, "uncaught overflow %ld != %ld"); + TEST2(i, c-s, 10, "wrong final position %d != %d"); + TEST2(i, errno, ERANGE, "missing errno %d != %d"); + TEST(l, wcstol(s=L"-2147483649", &c, 0), -2147483647L-1, "uncaught overflow %ld != %ld"); + TEST2(i, c-s, 11, "wrong final position %d != %d"); + TEST2(i, errno, ERANGE, "missing errno %d != %d"); + TEST(ul, wcstoul(s=L"4294967296", &c, 0), 4294967295UL, "uncaught overflow %lu != %lu"); + TEST2(i, c-s, 10, "wrong final position %d != %d"); + TEST2(i, errno, ERANGE, "missing errno %d != %d"); + TEST(ul, wcstoul(s=L"-1", &c, 0), 4294967295UL, "uncaught overflow %lu != %lu"); + TEST2(i, c-s, 2, "wrong final position %d != %d"); + TEST2(i, errno, ERANGE, "missing errno %d != %d"); + TEST(ul, wcstoul(s=L"-2", &c, 0), 4294967295UL, "uncaught overflow %lu != %lu"); + TEST2(i, c-s, 2, "wrong final position %d != %d"); + TEST2(i, errno, ERANGE, "missing errno %d != %d"); + TEST(ul, wcstoul(s=L"-2147483648", &c, 0), 4294967295UL, "uncaught overflow %lu != %lu"); + TEST2(i, c-s, 11, "wrong final position %d != %d"); + TEST2(i, errno, ERANGE, "missing errno %d != %d"); + TEST(ul, wcstoul(s=L"-2147483649", &c, 0), 4294967295UL, "uncaught overflow %lu != %lu"); + TEST2(i, c-s, 11, "wrong final position %d != %d"); + TEST2(i, errno, ERANGE, "missing errno %d != %d"); + } else { + TEST(i, 0, 1, "64bit tests not implemented"); + } + + TEST(l, wcstol(L"z", 0, 36), 35, "%ld != %ld"); + TEST(l, wcstol(L"00010010001101000101011001111000", 0, 2), 0x12345678, "%ld != %ld"); + + TEST(l, wcstol(s=L"0xz", &c, 16), 0, "%ld != %ld"); + TEST2(i, c-s, 1, "wrong final position %ld != %ld"); + + TEST(l, wcstol(s=L"0x1234", &c, 16), 0x1234, "%ld != %ld"); + TEST2(i, c-s, 6, "wrong final position %ld != %ld"); + + c = NULL; + TEST(l, wcstol(s=L"123", &c, 37), 0, "%ld != %ld"); + TEST2(i, c-s, 0, "wrong final position %d != %d"); + TEST2(i, errno, EINVAL, "%d != %d"); +} diff --git a/src/thread/sem.c b/src/thread/sem.c new file mode 100644 index 0000000..6840cd2 --- /dev/null +++ b/src/thread/sem.c @@ -0,0 +1,52 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "test.h" + +#define TEST(r, f, x, m) ( \ + ((r) = (f)) == (x) || \ + (error("%s failed (" m ")\n", #f, r, x), 0) ) + +#define TEST_S(s, x, m) ( \ + !strcmp((s),(x)) || \ + (error("[%s] != [%s] (%s)\n", s, x, m), 0) ) + +void test_sem(void) +{ + int r; + void *res; + char buf[100]; + struct timespec ts; + sem_t *sem, *sem2; + int val; + + clock_gettime(CLOCK_REALTIME, &ts); + snprintf(buf, sizeof buf, "/testsuite-%d-%d", (int)getpid(), (int)ts.tv_nsec); + + TEST(r, !(sem=sem_open(buf, O_CREAT|O_EXCL, 0700, 1)), 0, "could not open sem"); + + TEST(r, sem_getvalue(sem, &val), 0, "failed to get sem value"); + TEST(r, val, 1, "wrong initial semaphore value"); + + TEST(r, !(sem2=sem_open(buf, 0)), 0, "could not reopen sem"); + TEST(r, sem!=sem2, 0, "reopened sem has different address"); + + TEST(r, sem_wait(sem), 0, "failed on sem wait"); + TEST(r, sem_getvalue(sem2, &val), 0, "failed to get sem value"); + TEST(r, val, 0, "wrong semaphore value on second handle"); + + TEST(r, sem_post(sem), 0, "failed on sem post"); + TEST(r, sem_getvalue(sem2, &val), 0, "failed to get sem value"); + TEST(r, val, 1, "wrong semaphore value on second handle"); + + TEST(r, sem_close(sem), 0, "failed to close sem"); + TEST(r, sem_close(sem), 0, "failed to close sem second time"); + TEST(r, sem_unlink(buf), 0, "failed to unlink sem"); +}