aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/moslib/safe.h2
-rw-r--r--include/moslib/tester.h30
-rw-r--r--src/safe.c8
-rw-r--r--src/tester.c71
-rw-r--r--tests/safe_tests.c12
-rw-r--r--tests/string_tests.c2
6 files changed, 68 insertions, 57 deletions
diff --git a/include/moslib/safe.h b/include/moslib/safe.h
index c855cea..7e9d817 100644
--- a/include/moslib/safe.h
+++ b/include/moslib/safe.h
@@ -42,6 +42,7 @@ typedef struct {
#define mos_safe_dup2(fd, fd2) mos_safe_dup2_fn(fd, fd2, mos_err_info)
#define mos_safe_fork() mos_safe_fork_fn(mos_err_info)
#define mos_safe_pipe(fd) mos_safe_pipe_fn(fd, mos_err_info)
+#define mos_safe_mkstemp(path) mos_safe_mkstemp_fn(path, mos_err_info)
// Function prototypes for macros
extern void *mos_safe_malloc_fn(size_t size, MosSafeErrInfo info);
@@ -53,5 +54,6 @@ extern int mos_safe_dup_fn(int fd, MosSafeErrInfo info);
extern int mos_safe_dup2_fn(int fd, int fd2, MosSafeErrInfo info);
extern pid_t mos_safe_fork_fn(MosSafeErrInfo info);
extern int mos_safe_pipe_fn(int fd[2], MosSafeErrInfo info);
+extern int mos_safe_mkstemp_fn(char *path, MosSafeErrInfo info);
#endif // MOSLIB_SAFE_H
diff --git a/include/moslib/tester.h b/include/moslib/tester.h
index 4c77d73..f62645f 100644
--- a/include/moslib/tester.h
+++ b/include/moslib/tester.h
@@ -47,21 +47,21 @@
//
// You can also test if a function writes correct output.
// You need to create a helper test and pass it into test_assert_out in main test.
-// Pass the helper test, output stream, and expected output to it.
+// Pass the helper test, output stream's fd, and expected output to it.
// Example:
// TEST_HELPER(helper_test) {
// printf("output");
// }
// TEST(main_test) {
-// test_assert_out(helper_test, stdout, "output");
+// test_assert_out(helper_test, STDOUT_FILENO, "output");
// }
//
// If your functions have output and you want to suppress them for the sake of tests,
// you can do so using suppress_output and unsupress_outputs.
// Example:
// TEST(error_test) {
-// suppress_output(stdout);
-// suppress_output(stderr);
+// suppress_output(STDOUT_FILENO);
+// suppress_output(STDERR_FILENO);
// int code = fun_that_fails_with_output();
// unsuppress_outputs();
// test_assert(code == 0, "function didn't fail");
@@ -168,20 +168,20 @@ extern void mos_test_assert(int expression, const char *fail_message);
// function
// function that is supposed to write output
//
-// stream
-// stream to write the output to
+// fd
+// file descriptor of stream to write the output to
//
// output
// expected output of the function
-#define mos_test_assert_out(function, stream, output) \
- mos_test_assert_out_fn(function, &(stream), output, #function, #stream)
+#define mos_test_assert_out(function, fd, output) \
+ mos_test_assert_out_fn(function, fd, output, #function, #fd)
// Suppress given output
//
// Arguments:
-// out
-// outpout to suppress
-#define mos_suppress_output(out) mos_suppress_output_fn(&(out))
+// fd
+// file descriptor of output to suppress
+#define mos_suppress_output(fd) mos_suppress_output_fn(fd)
// Unuppress previously suppressed outputs
// Will unsupress all of the outputs that were suppressed
@@ -218,13 +218,9 @@ extern void mos_free_tester(MosTester *tester);
extern MosTestGroup *mos_add_test_group_fn(MosTester *tester, const char *group_name);
extern void mos_test_assert_exit_fn(MosTestFn function, int code, const char *name);
extern void mos_test_assert_out_fn(
- MosTestFn function,
- FILE **stream,
- const char *output,
- const char *fn_name,
- const char *stream_name
+ MosTestFn function, int fd, const char *output, const char *fn_name, const char *fd_name
);
-extern void mos_suppress_output_fn(FILE **out);
+extern void mos_suppress_output_fn(int fd);
extern void mos_add_test_fn(MosTestGroup *group, MosTestFn test, const char *name);
#endif // MOSLIB_TESTER_H
diff --git a/src/safe.c b/src/safe.c
index fd7a1af..0701939 100644
--- a/src/safe.c
+++ b/src/safe.c
@@ -88,3 +88,11 @@ int mos_safe_pipe_fn(int fd[2], MosSafeErrInfo info) {
ERR_MESS("failed to pipe");
exit(EXIT_FAILURE);
}
+
+int mos_safe_mkstemp_fn(char *path, MosSafeErrInfo info) {
+ int fd = mkstemp(path);
+ if (fd != -1)
+ return fd;
+ ERR_MESS("failed to make temporary file");
+ exit(EXIT_FAILURE);
+}
diff --git a/src/tester.c b/src/tester.c
index e789871..2ab0c87 100644
--- a/src/tester.c
+++ b/src/tester.c
@@ -19,11 +19,11 @@
#define RENDER_WIDTH 80
static int failed = 0;
-static FILE *dev_null = NULL;
+static int dev_null = -1;
typedef struct {
- FILE ***outs;
- FILE **ogs;
+ int *outs;
+ int *ogs;
size_t n_outs;
size_t out_cap;
} Outputs;
@@ -140,62 +140,67 @@ void mos_test_assert_exit_fn(MosTestFn function, int code, const char *name) {
}
void mos_test_assert_out_fn(
- MosTestFn function,
- FILE **stream,
- const char *output,
- const char *fn_name,
- const char *stream_name
+ MosTestFn function, int fd, const char *output, const char *fn_name, const char *fd_name
) {
size_t n = strlen(output);
char *out = mos_safe_calloc(n + 2, 1);
- FILE *og = *stream;
- fflush(*stream);
- *stream = mos_safe_tmpfile();
+ int tmp = mos_safe_mkstemp(".tmp");
+ unlink(".tmp");
+
+ int og = mos_safe_dup(fd);
+ fflush(NULL);
+ mos_safe_dup2(tmp, fd);
function();
- fflush(*stream);
- rewind(*stream);
- fread(out, 1, n + 1, *stream);
- fclose(*stream);
- *stream = og;
+ fflush(NULL);
+ lseek(fd, 0, SEEK_SET);
+ read(fd, out, n + 1);
+ close(tmp);
+
+ mos_safe_dup2(og, fd);
+ close(og);
if (strcmp(out, output)) {
failed = 1;
print_color(RED, "ASSERT FAILED: ");
- printf("function %s outputed to %s:\n", fn_name, stream_name);
+ printf("function %s outputed to %s:\n", fn_name, fd_name);
printf(" %s (capped at %zu chars)\n", out, n + 1);
printf(" expected: %s\n", output);
}
free(out);
}
-void mos_suppress_output_fn(FILE **out) {
+void mos_suppress_output_fn(int fd) {
if (!suppressed.outs || suppressed.n_outs >= suppressed.out_cap) {
while (suppressed.n_outs >= suppressed.out_cap)
suppressed.out_cap *= 2;
- suppressed.outs = mos_safe_realloc(suppressed.outs, suppressed.out_cap * sizeof(FILE **));
- suppressed.ogs = mos_safe_realloc(suppressed.ogs, suppressed.out_cap * sizeof(FILE *));
+ suppressed.outs = mos_safe_realloc(suppressed.outs, suppressed.out_cap * sizeof(int));
+ suppressed.ogs = mos_safe_realloc(suppressed.ogs, suppressed.out_cap * sizeof(int));
}
- suppressed.outs[suppressed.n_outs] = out;
- suppressed.ogs[suppressed.n_outs++] = *out;
+ suppressed.outs[suppressed.n_outs] = fd;
+ suppressed.ogs[suppressed.n_outs++] = mos_safe_dup(fd);
- if (!dev_null)
- dev_null = mos_safe_tmpfile();
+ if (dev_null == -1) {
+ dev_null = mos_safe_mkstemp(".dev_null");
+ unlink(".dev_null");
+ }
- fflush(*out);
- *out = dev_null;
+ fflush(NULL);
+ mos_safe_dup2(dev_null, fd);
}
void mos_unsuppress_outputs(void) {
if (!suppressed.outs || !suppressed.ogs)
return;
- if (dev_null)
- fflush(dev_null);
+ if (dev_null != -1)
+ fflush(NULL);
- for (size_t i = suppressed.n_outs; i-- > 0;)
- *suppressed.outs[i] = suppressed.ogs[i];
+ for (size_t i = suppressed.n_outs; i-- > 0;) {
+ mos_safe_dup2(suppressed.ogs[i], suppressed.outs[i]);
+ close(suppressed.ogs[i]);
+ }
suppressed.n_outs = 0;
}
@@ -275,9 +280,9 @@ void mos_free_tester(MosTester *tester) {
free(tester);
}
mos_unsuppress_outputs();
- if (dev_null) {
- fclose(dev_null);
- dev_null = NULL;
+ if (dev_null != -1) {
+ close(dev_null);
+ dev_null = -1;
}
if (suppressed.outs) {
free(suppressed.outs);
diff --git a/tests/safe_tests.c b/tests/safe_tests.c
index b50b073..3c25dd5 100644
--- a/tests/safe_tests.c
+++ b/tests/safe_tests.c
@@ -13,7 +13,7 @@ TEST(test_safe_malloc) {
void *p = safe_malloc(1024);
test_assert(p != NULL, "Failed to malloc 1KiB");
- suppress_output(stderr);
+ suppress_output(STDERR_FILENO);
test_assert_exit(malloc_exit, EXIT_FAILURE);
unsuppress_outputs();
}
@@ -26,7 +26,7 @@ TEST(test_safe_calloc) {
void *p = safe_calloc(16, 16);
test_assert(p != NULL, "Failed to calloc 16 items of 16 bytes");
- suppress_output(stderr);
+ suppress_output(STDERR_FILENO);
test_assert_exit(calloc_exit, EXIT_FAILURE);
unsuppress_outputs();
}
@@ -44,7 +44,7 @@ TEST(test_safe_realloc) {
p = safe_realloc(p, 4096);
test_assert(p != NULL, "Failed to realloc 1KiB to 4KiB");
- suppress_output(stderr);
+ suppress_output(STDERR_FILENO);
test_assert_exit(realloc_exit, EXIT_FAILURE);
unsuppress_outputs();
}
@@ -57,7 +57,7 @@ TEST(test_safe_fopen) {
FILE *fp = safe_fopen(__FILE__, "r");
test_assert(fp != NULL, "Failed to fopen current file");
- suppress_output(stderr);
+ suppress_output(STDERR_FILENO);
test_assert_exit(fopen_exit, EXIT_FAILURE);
unsuppress_outputs();
}
@@ -76,7 +76,7 @@ TEST(test_safe_dup) {
test_assert(fd != -1, "Failed to dup STDOUT_FILENO");
close(fd);
- suppress_output(stderr);
+ suppress_output(STDERR_FILENO);
test_assert_exit(dup_exit, EXIT_FAILURE);
unsuppress_outputs();
}
@@ -96,7 +96,7 @@ TEST(test_safe_dup2) {
test_assert(res != -1, "Failed to restore STDOUT_FILENO");
close(fd);
- suppress_output(stderr);
+ suppress_output(STDERR_FILENO);
test_assert_exit(dup2_exit, EXIT_FAILURE);
unsuppress_outputs();
}
diff --git a/tests/string_tests.c b/tests/string_tests.c
index eaa9498..8ca0dcd 100644
--- a/tests/string_tests.c
+++ b/tests/string_tests.c
@@ -41,7 +41,7 @@ TEST(ss_print_helper) {
}
TEST(printing) {
- test_assert_out(ss_print_helper, stdout, "test");
+ test_assert_out(ss_print_helper, STDOUT_FILENO, "test");
StringSlice ss = ss_from_str("slice");
char buf[16];