/* * %CopyrightBegin% * * Copyright Ericsson AB 2005-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * %CopyrightEnd% */ /* * Description: Test suite for the ethread thread library. * Author: Rickard Green */ #include #include #include #include #include #include #ifndef __WIN32__ #include #endif #include "erl_printf.h" #ifdef THREAD_SAFE #include "ethread.h" #endif #ifdef __WIN32__ #undef HAVE_VSNPRINTF #define HAVE_VSNPRINTF 1 #define vsnprintf _vsnprintf #endif #ifdef __WIN32__ #define signed_long_long __int64 #define unsigned_long_long unsigned __int64 #else #define signed_long_long signed long long #define unsigned_long_long unsigned long long #endif /* * Auxiliary functions */ #define PRINT_VA_LIST(FRMT) \ do { \ if (FRMT && FRMT != '\0') { \ va_list args; \ va_start(args, FRMT); \ vfprintf(stderr, FRMT, args); \ va_end(args); \ } \ } while (0) #define ASSERT(B) \ do { \ if (!(B)) \ fail("%s:%d: Assertion \"%s\" failed!",__FILE__,__LINE__,#B); \ } while (0) static void print_eol(void) { fprintf(stderr, "\n"); } static void print_line(char *frmt,...) { PRINT_VA_LIST(frmt); print_eol(); } static void print(char *frmt,...) { PRINT_VA_LIST(frmt); } static void fail(char *frmt,...) { char *abrt_env; print_eol(); fprintf(stderr, "EP-TEST-FAILURE"); PRINT_VA_LIST(frmt); print_eol(); abrt_env = getenv("ERL_ABORT_ON_FAILURE"); if (abrt_env && strcmp("true", abrt_env) == 0) abort(); else exit(1); } static void skip(char *frmt,...) { print_eol(); fprintf(stderr, "EP-TEST-SKIP"); PRINT_VA_LIST(frmt); print_eol(); exit(0); } static void succeed(char *frmt,...) { print_eol(); fprintf(stderr, "EP-TEST-SUCCESS"); PRINT_VA_LIST(frmt); print_eol(); exit(0); } #if 0 /* Not used */ static void do_sleep(unsigned secs) { #ifdef __WIN32__ Sleep((DWORD) secs*1000); #else sleep(secs); #endif } #endif static void send_my_pid(void) { #ifndef __WIN32__ int pid = (int) getpid(); fprintf(stderr, "\nEP-TEST-PID%d\n", pid); #endif } #define BUF_SIZE (1024*1024) FILE *outfile = NULL; char **expected_result; #define FENCE_SIZE 512 static void print_cmp_test(int n, char *frmt, ...) { int res = -1; static char clib_buf[BUF_SIZE]; static unsigned char the_erts_buf[BUF_SIZE]; char *erts_buf = (char *) &the_erts_buf[FENCE_SIZE]; va_list args; if (outfile) { char *fp, *tp; va_start(args, frmt); if (n < 0) res = vsprintf(erts_buf, frmt, args); else { #ifdef HAVE_VSNPRINTF res = vsnprintf(erts_buf, (size_t) n, frmt, args); #else fail("No vsnprintf()"); #endif } va_end(args); ASSERT(res >= 0); fp = erts_buf; tp = clib_buf; while (*fp) { switch (*fp) { case '\a': *(tp++) = '\\'; *(tp++) = 'a'; break; case '\b': *(tp++) = '\\'; *(tp++) = 'b'; break; case '\f': *(tp++) = '\\'; *(tp++) = 'f'; break; case '\n': *(tp++) = '\\'; *(tp++) = 'n'; break; case '\r': *(tp++) = '\\'; *(tp++) = 'r'; break; case '\t': *(tp++) = '\\'; *(tp++) = 't'; break; case '\v': *(tp++) = '\\'; *(tp++) = 'v'; break; case '\"': *(tp++) = '\\'; *(tp++) = '\"'; break; case '\\': *(tp++) = '\\'; *(tp++) = '\\'; break; default: *(tp++) = *fp; break; } fp++; } *tp = '\0'; res = fprintf(outfile, "\t\"%s\",\n", clib_buf); ASSERT(res >= 0); } else { char *xres; va_start(args, frmt); if (n < 0) res = erts_vsprintf(erts_buf, frmt, args); else { int i; int chk_sz = 2*FENCE_SIZE + n; for (i = 0; i < chk_sz; i++) the_erts_buf[i] = 0xeb; res = erts_vsnprintf(erts_buf, (size_t) n, frmt, args); for (i = 0; i < chk_sz; i++) if ((((char *) &the_erts_buf[i]) < erts_buf || erts_buf + n <= ((char *) &the_erts_buf[i])) && the_erts_buf[i] != 0xeb) { int j; for (j = 0; j < chk_sz; j++) print(j ? ",%x(%d)" : "%x(%d)", (unsigned) the_erts_buf[j], j - FENCE_SIZE); print_eol(); fail("Garbage written out of bounds (%d,%d)", i - FENCE_SIZE, n); } } va_end(args); ASSERT(res >= 0); if (expected_result) { ASSERT(*expected_result); xres = *expected_result; expected_result++; } else { va_start(args, frmt); if (n < 0) res = vsprintf(clib_buf, frmt, args); else { #ifdef HAVE_VSNPRINTF res = vsnprintf(clib_buf, (size_t) n, frmt, args); #else fail("No vsnprintf()"); #endif } va_end(args); ASSERT(res >= 0); xres = clib_buf; } if (strcmp(xres, erts_buf) != 0) { print_line("expected result : \"%s\"", xres); print_line("erts_buf : \"%s\"", erts_buf); fail("\"%s\" != \"%s\" (format=\"%s\")", xres, erts_buf, frmt); } print_line("Checked format \"%s\" with result: \"%s\"", frmt, erts_buf); } } /* * The test-cases */ #include "integer_64_test.h" #include "integer_test.h" #define INT_SUB_BATCH_TEST(FRMT, TYPE) \ print_cmp_test(-1, FRMT, ((TYPE) 4711)); \ print_cmp_test(-1, FRMT, ~((TYPE) 4711)); \ print_cmp_test(-1, FRMT, (~((TYPE) 0))/2 + (~((TYPE) 0))/4);\ print_cmp_test(-1, FRMT, ((TYPE) - 1)); \ print_cmp_test(-1, FRMT, ((TYPE) 1)); \ print_cmp_test(-1, FRMT, ((TYPE) ((long) 0xabcdef01))); \ #define INT_BATCH_TEST(P, X, S) \ print_line("%s:%d",__FILE__,__LINE__); \ INT_SUB_BATCH_TEST("%" P "h" X, S char); \ INT_SUB_BATCH_TEST("%" P "h" X, S short); \ INT_SUB_BATCH_TEST("%" P X, S int); \ INT_SUB_BATCH_TEST("%" P "l" X, S long); \ INT_SUB_BATCH_TEST("%" P "ll" X, S ## _long_long); \ static void integer_test(void) { /* This testcase should be rewritten. It assumes the following sizes of types... */ if (sizeof(char) != 1 || sizeof(short) != 2 || sizeof(int) != 4 || sizeof(long) != (sizeof(void *) == 8 ? 8 : 4) || sizeof(signed_long_long) != 8) skip("Unexpected size of primitive datatype:" " sizeof(char) == %d (expected 1);" " sizeof(short) == %d (expected 2);" " sizeof(int) == %d (expected 4);" " sizeof(long) == %d (expected %d);" " sizeof(signed_long_long) == %d (expected 8)", sizeof(char), sizeof(short), sizeof(int), sizeof(long), sizeof(void *) == 8 ? 8 : 4, sizeof(signed_long_long)); expected_result = (sizeof(void *) == 8 ? integer_64_expected_result : integer_expected_result); INT_BATCH_TEST("", "i", signed); INT_BATCH_TEST("", "d", signed); INT_BATCH_TEST("", "u", unsigned); INT_BATCH_TEST("", "o", unsigned); INT_BATCH_TEST("", "x", unsigned); INT_BATCH_TEST("", "X", unsigned); INT_BATCH_TEST("010.5", "i", signed); INT_BATCH_TEST("010.5", "d", signed); INT_BATCH_TEST("010.5", "u", unsigned); INT_BATCH_TEST("010.5", "o", unsigned); INT_BATCH_TEST("010.5", "x", unsigned); INT_BATCH_TEST("010.5", "X", unsigned); INT_BATCH_TEST("-+29", "i", signed); INT_BATCH_TEST("-+29", "d", signed); INT_BATCH_TEST("-29", "u", unsigned); INT_BATCH_TEST("-29", "o", unsigned); INT_BATCH_TEST("-29", "x", unsigned); INT_BATCH_TEST("-29", "X", unsigned); INT_BATCH_TEST("22.8", "i", signed); INT_BATCH_TEST("22.8", "d", signed); INT_BATCH_TEST("22.8", "u", unsigned); INT_BATCH_TEST("22.8", "o", unsigned); INT_BATCH_TEST("22.8", "x", unsigned); INT_BATCH_TEST("22.8", "X", unsigned); INT_BATCH_TEST("-22.8", "i", signed); INT_BATCH_TEST("-22.8", "d", signed); INT_BATCH_TEST("-22.8", "u", unsigned); INT_BATCH_TEST("-22.8", "o", unsigned); INT_BATCH_TEST("-22.8", "x", unsigned); INT_BATCH_TEST("-22.8", "X", unsigned); INT_BATCH_TEST("-823.193", "i", signed); INT_BATCH_TEST("-823.193", "d", signed); INT_BATCH_TEST("-823.193", "u", unsigned); INT_BATCH_TEST("-823.193", "o", unsigned); INT_BATCH_TEST("-823.193", "x", unsigned); INT_BATCH_TEST("-823.193", "X", unsigned); } static void float_test(void) { expected_result = NULL; print_cmp_test(-1, "%70.10f", DBL_MAX); print_cmp_test(-1, "%500.10f", DBL_MAX); print_cmp_test(-1, "%-500.10f", DBL_MAX); print_cmp_test(-1, "%500.10e", DBL_MAX); print_cmp_test(-1, "%-500.10e", DBL_MAX); print_cmp_test(-1, "%500.10E", DBL_MAX); print_cmp_test(-1, "%-500.10E", DBL_MAX); print_cmp_test(-1, "%500.10g", DBL_MAX); print_cmp_test(-1, "%-500.10g", DBL_MAX); print_cmp_test(-1, "%500.10G", DBL_MAX); print_cmp_test(-1, "%-500.10G", DBL_MAX); } char some_characters[] = "abcdefghijklmnopqrstuvwxyzċäö" "ABCDEFGHIJKLMNOPQRSTUVXYZĊÄÖ" "1234567890" "()[]{}+-;,:.@£$!\"#¤%&/\\=?'`´^~§½|<>¨*_" "\a\b\f\n\r\t\v"; #include "string_test.h" static void string_test(void) { expected_result = string_expected_result; print_cmp_test(-1, "%s", "hej"); print_cmp_test(-1, "%-10.5s", "hopp"); print_cmp_test(-1, "%10.5s", "hopp"); print_cmp_test(-1, "%-500.500s", "hopp"); print_cmp_test(-1, "%500.500s", "hopp"); print_cmp_test(-1, "\t%10.4s", some_characters); print_cmp_test(-1, "\t%500.500s", some_characters); } #include "character_test.h" static void character_test(void) { char *cp; expected_result = character_expected_result; for (cp = some_characters; *cp; cp++) { print_cmp_test(-1, "%c", *cp); print_cmp_test(-1, "%-10.5c", *cp); print_cmp_test(-1, "%10.5c", *cp); print_cmp_test(-1, "%-500.500c", *cp); print_cmp_test(-1, "%500.500c", *cp); } } #include "snprintf_test.h" static void snprintf_test(void) { expected_result = snprintf_expected_result; print_cmp_test(6, "hej hopp"); print_cmp_test(7, "hej hopp"); print_cmp_test(8, "hej hopp"); print_cmp_test(9, "hej hopp"); print_cmp_test(10, "hej hopp"); print_cmp_test(6, "hej %d", 4711); print_cmp_test(7, "hej %d", 4711); print_cmp_test(8, "hej %d", 4711); print_cmp_test(9, "hej %d", 4711); print_cmp_test(10, "hej %d", 4711); print_cmp_test(sizeof(some_characters)-2, "%s", some_characters); print_cmp_test(sizeof(some_characters)-1, "%s", some_characters); print_cmp_test(sizeof(some_characters), "%s", some_characters); print_cmp_test(sizeof(some_characters)+1, "%s", some_characters); print_cmp_test(sizeof(some_characters)+2, "%s", some_characters); print_cmp_test(sizeof(some_characters)/2, "%s%s", some_characters, some_characters); print_cmp_test(sizeof(some_characters)*3, "%s%s", some_characters, some_characters); } static void quote_test(void) { expected_result = NULL; print_cmp_test(-1, "\n"); print_cmp_test(-1, "\\n"); print_cmp_test(-1, "\r"); print_cmp_test(-1, "\\r"); print_cmp_test(-1, "\t"); print_cmp_test(-1, "\\t"); print_cmp_test(-1, "\v"); print_cmp_test(-1, "\\v"); print_cmp_test(-1, "\b"); print_cmp_test(-1, "\\b"); print_cmp_test(-1, "\f"); print_cmp_test(-1, "\\f"); print_cmp_test(-1, "\x80"); print_cmp_test(-1, "\\x80"); print_cmp_test(-1, "\x14"); print_cmp_test(-1, "\\x14"); print_cmp_test(-1, "\xff"); print_cmp_test(-1, "\\xff"); print_cmp_test(-1, "\043"); print_cmp_test(-1, "\\043"); print_cmp_test(-1, "\053"); print_cmp_test(-1, "\\053"); print_cmp_test(-1, "\0143"); print_cmp_test(-1, "\\0143"); print_cmp_test(-1, "\\lf"); print_cmp_test(-1, "\\msss"); print_cmp_test(-1, "\\ss"); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * The dispatcher * \* */ int main(int argc, char *argv[]) { if (argc < 2) fail("To few arguments for test case"); { char *testcase; int save_xres = 0; int i; send_my_pid(); testcase = argv[1]; #ifdef THREAD_SAFE { int res = ethr_init(NULL); if (res != 0) fail("Failed to initialize the ethread library"); } #endif for (i = 2; i < argc; i++) { if (strcmp(argv[i], "save_expected_result") == 0) { save_xres = 1; break; } } if (save_xres) { char filename[100]; sprintf(filename, "%s%s_test.h", testcase, sizeof(void *) == 8 ? "_64" : ""); printf("Saving expected result to %s\n", filename); outfile = fopen(filename, "w"); ASSERT(outfile); fprintf(outfile, "/*\n" " * %%CopyrightBegin%%\n" " * Copyright Ericsson AB 1996-2009. All Rights Reserved.\n" " * \n" " * Licensed under the Apache License, Version 2.0 (the \"License\");\n" " * you may not use this file except in compliance with the License.\n" " * You may obtain a copy of the License at\n" " * \n" " * http://www.apache.org/licenses/LICENSE-2.0\n" " * \n" " * Unless required by applicable law or agreed to in writing, software\n" " * distributed under the License is distributed on an \"AS IS\" BASIS,\n" " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" " * See the License for the specific language governing permissions and\n" " * limitations under the License.\n" " * %%CopyrightEnd%%\n" " */\n" "\n"); fprintf(outfile, "/* \n" " * This file has been automatically generated. Do NOT edit it; instead,\n" " * run '%s %s save_expected_result'%s.\n" " */\n" "\n", argv[0], testcase, sizeof(void *) == 8 ? " on a 64-bit machine" : ""); fprintf(outfile, "char *%s%s_expected_result[] = {\n", testcase, sizeof(void *) == 8 ? "_64" : ""); } if (strcmp("integer", testcase) == 0) integer_test(); else if (strcmp("float", testcase) == 0) float_test(); else if (strcmp("string", testcase) == 0) string_test(); else if (strcmp("character", testcase) == 0) character_test(); else if (strcmp("snprintf", testcase) == 0) snprintf_test(); else if (strcmp("quote", testcase) == 0) quote_test(); else if (!save_xres) skip("Test case \"%s\" not implemented yet", testcase); if (save_xres) { fprintf(outfile, "\tNULL};\n"); fclose(outfile); } succeed(NULL); } return 0; }