/* * The Rin Library – library "conformance" tests * * Copyright (C) 2015-2017 Gediminas Jakutis * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; version 2.1 * of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include "test.h" #include "rin/diagnostic.h" struct stdiocap { int pipefd[2]; int origfd; int backupfd; FILE *pipe; }; static int err_test(void); static int warn_test(void); static int fixme_test(void); static int info_test(void); static int prefix_test(void); static int thread_test(void); static int clean_test(void); static struct stdiocap capture_stdio_start(FILE *stream); static void capture_stdio_stop(struct stdiocap *cap); static char *visible_newlines(const char * const in); static int test_default_channels(const char * const in, const char * const expected, size_t i, int usearg, void (*func)(const char *, ...)); int diagnostic_test(char *testname) { static const struct test tests[] = { {"err", err_test}, {"warn", warn_test}, {"fixme", fixme_test}, {"info", info_test}, {"prefix", prefix_test}, {"thread", thread_test}, {"clean", clean_test} }; size_t i; for (i = 0; i < arrlen(tests); ++i) { if (!strcmp(testname, tests[i].name)) { return tests[i].testfunc(); } } return EXIT_FAILURE; } static int err_test(void) { size_t i; int usearg; int ret; static const char *in[] = {"", "test", "test number is %zu", "%zu tests ran"}; static const char *expected[] = {"error:\n", "error:test\n", "error:test number is 3\n", "error:4 tests ran\n"}; for (i = 0; i < arrlen(in); ++i) { usearg = i < (arrlen(in) / 2) ? 0 : 1; ret = test_default_channels(in[i], expected[i], i, usearg, rin_err); } return ret; } static int warn_test(void) { return 77; } static int fixme_test(void) { return 77; } static int info_test(void) { return 77; } static int prefix_test(void) { return 77; } static int thread_test(void) { return 77; } static int clean_test(void) { return 77; } static struct stdiocap capture_stdio_start(FILE *stream) { struct stdiocap ret; ret.origfd = fileno(stream); ret.backupfd = dup(ret.origfd); if (pipe(ret.pipefd)) { close(ret.backupfd); ret.backupfd = -1; ret.origfd = -1; ret.pipefd[0] = -1; ret.pipefd[1] = -1; ret.pipe = NULL; } dup2(ret.pipefd[1], ret.origfd); ret.pipe = fdopen(ret.pipefd[0], "r"); return ret; } static void capture_stdio_stop(struct stdiocap *cap) { /* restore original fd to the stream */ dup2(cap->backupfd, cap->origfd); close(cap->backupfd); close(cap->pipefd[1]); close(cap->pipefd[0]); /* close everything we opened and invalidate all the descriptors */ fclose(cap->pipe); cap->backupfd = -1; cap->origfd = -1; cap->pipefd[0] = -1; cap->pipefd[1] = -1; cap->pipe = NULL; } static char *visible_newlines(const char * const in) { char *ret; const char *newline; const char *readptr; char *writeptr; readptr = in; ret = malloc(strlen(readptr) * 2 + 1); writeptr = ret; newline = strchr(readptr, '\n'); while (newline) { /* write chunk until the next newline */ memcpy(writeptr, readptr, newline - readptr); writeptr += newline - readptr; /* advance writing position */ readptr = newline; ++readptr; /* skip the newline */ /* toss in replacement */ memcpy(writeptr, "\\n", 2); writeptr += 2; newline = strchr(readptr, '\n'); } /* write all that remains */ strcpy(writeptr, readptr); return ret; } static int test_default_channels(const char * const in, const char * const expected, size_t i, int usearg, void (*func)(const char *, ...)) { char buf[32] = {0}; struct stdiocap cap; size_t len; int ret = 0; len = strlen(expected); ++len; cap = capture_stdio_start(stderr); if (!cap.pipe) { ret = -1; goto fail; } if (usearg) { func(in, i + 1); } else { func(in); } if (!(fgets(buf, sizeof(buf) < len ? sizeof(buf) : len, cap.pipe))) { ret = 1; goto fail; } fail: capture_stdio_stop(&cap); if (ret == -1) { ret = ok(1, "%s: unexpected test program failure on iteration %zu", __func__, i); } else { char *tmp[2]; ret = strncmp(buf, expected, sizeof(buf) < len ? sizeof(buf) : len); tmp[0] = visible_newlines(buf); tmp[1] = visible_newlines(expected); ret = ok(ret, "%s: expected: \"%s\", got: \"%s\"", __func__, tmp[1], tmp[0]); free(tmp[0]); free(tmp[1]); } return ret; }