From 513f4ba53c39fde05d5c651ddb074024ea00b938 Mon Sep 17 00:00:00 2001
From: Tibor Nagy <xnagytibor@gmail.com>
Date: Fri, 22 Feb 2019 13:19:38 +0100
Subject: [PATCH] tests: Documentation for test_helpers.h, more refactoring

---
 tests/signal.c       | 16 +++++--------
 tests/stdio/all.c    | 29 +++++++++++++++++------
 tests/stdio/fgets.c  |  3 ++-
 tests/stdio/fputs.c  | 16 +++++++++----
 tests/stdio/fread.c  |  1 +
 tests/stdio/fseek.c  |  4 +++-
 tests/stdio/fwrite.c | 28 ++++++++++++----------
 tests/stdio/mutex.c  |  3 ++-
 tests/stdio/popen.c  | 23 ++++--------------
 tests/test_helpers.h | 56 ++++++++++++++++++++++++++++++++++++++------
 tests/waitpid.c      |  5 +++-
 11 files changed, 121 insertions(+), 63 deletions(-)

diff --git a/tests/signal.c b/tests/signal.c
index 57d1323e2..b192ad397 100644
--- a/tests/signal.c
+++ b/tests/signal.c
@@ -11,17 +11,13 @@ void handler(int sig) {
 }
 
 int main(void) {
-    if (signal(SIGUSR1, &handler) == SIG_ERR) {
-        puts("Signal error!");
-        printf("%d\n", errno);
-        exit(EXIT_FAILURE);
-    }
+    void (*signal_status)(int) = signal(SIGUSR1, &handler);
+    ERROR_IF(signal, signal_status, == SIG_ERR);
 
     puts("Raising...");
-    if (raise(SIGUSR1)) {
-        puts("Raise error!");
-        printf("%d\n", errno);
-        exit(EXIT_FAILURE);
-    }
+
+    int raise_status = raise(SIGUSR1);
+    ERROR_IF(raise, raise_status, < 0);
+
     puts("Raised.");
 }
diff --git a/tests/stdio/all.c b/tests/stdio/all.c
index 2ccc35eb4..de7c60ab6 100644
--- a/tests/stdio/all.c
+++ b/tests/stdio/all.c
@@ -4,11 +4,26 @@
 #include "test_helpers.h"
 
 int main(void) {
-	FILE *f = fopen("stdio/stdio.in", "r");
-	printf("%c\n", fgetc(f));
-	ungetc('H', f);
-	char *in = malloc(30);
-	printf("%s\n", fgets(in, 30, f));
-	setvbuf(stdout, 0, _IONBF, 0);
-	printf("Hello\n");
+    FILE *f = fopen("stdio/stdio.in", "r");
+    ERROR_IF(fopen, f, == NULL);
+
+    int c = fgetc(f);
+    ERROR_IF(fgetc, c, == EOF);
+    UNEXP_IF(fgetc, c, < 0);
+    UNEXP_IF(fgetc, c, > 255);
+    printf("%c\n", c);
+
+    int u = ungetc('J', f);
+    ERROR_IF(ungetc, u, == EOF);
+
+    char in[30] = { 0 };
+    char *s = fgets(in, 30, f);
+    ERROR_IF(fgets, s, == NULL);
+    printf("%s\n", in);
+
+    int vb = setvbuf(stdout, 0, _IONBF, 0);
+    //ERROR_IF(setvbuf, vb, > 0); // TODO: Cannot use this, doesn't set errno
+    //UNEXP_IF(setvbuf, vb, != 0);
+
+    printf("Hello\n");
 }
diff --git a/tests/stdio/fgets.c b/tests/stdio/fgets.c
index 6e2b715bf..ed02999cd 100644
--- a/tests/stdio/fgets.c
+++ b/tests/stdio/fgets.c
@@ -4,8 +4,9 @@
 #include "test_helpers.h"
 
 int main(void) {
-    //FILE *f = fopen("/etc/ssl/certs/ca-certificates.crt", "r");
     FILE *f = fopen("stdio/stdio.in", "r");
+    ERROR_IF(fopen, f, == NULL);
+
     char line[256];
 
     while (1) {
diff --git a/tests/stdio/fputs.c b/tests/stdio/fputs.c
index 7d76d12ab..e377bfe8d 100644
--- a/tests/stdio/fputs.c
+++ b/tests/stdio/fputs.c
@@ -4,8 +4,16 @@
 #include "test_helpers.h"
 
 int main(void) {
-	FILE *f = fopen("stdio/fputs.out", "w");
-	char *in = "Hello World!";
-	fputs(in, f); // calls fwrite, helpers::fwritex, internal::to_write and internal::stdio_write
-	fclose(f);
+    FILE *f = fopen("stdio/fputs.out", "w");
+    ERROR_IF(fopen, f, == NULL);
+
+    char *in = "Hello World!";
+
+    int p = fputs(in, f);
+    ERROR_IF(fputs, p, == EOF);
+    UNEXP_IF(fputs, p, < 0);
+
+    int c = fclose(f);
+    ERROR_IF(fclose, c, == EOF);
+    UNEXP_IF(fclose, c, != 0);
 }
diff --git a/tests/stdio/fread.c b/tests/stdio/fread.c
index ea14368eb..75eb7ff8f 100644
--- a/tests/stdio/fread.c
+++ b/tests/stdio/fread.c
@@ -6,6 +6,7 @@
 
 int main(void) {
     FILE *fp = fopen("stdio/fread.in", "rb");
+    ERROR_IF(fopen, fp, == NULL);
 
     char buf[33] = { 0 };
     for (int i = 1; i <= 32; ++i) {
diff --git a/tests/stdio/fseek.c b/tests/stdio/fseek.c
index c07cf79b5..8bc948799 100644
--- a/tests/stdio/fseek.c
+++ b/tests/stdio/fseek.c
@@ -4,7 +4,9 @@
 #include "test_helpers.h"
 
 int main(void) {
-	FILE *f = fopen("stdio/stdio.in", "r");
+    FILE *f = fopen("stdio/stdio.in", "r");
+    ERROR_IF(fopen, f, == NULL);
+
     if (fseek(f, 14, SEEK_CUR) < 0) {
         puts("fseek error");
         exit(EXIT_FAILURE);
diff --git a/tests/stdio/fwrite.c b/tests/stdio/fwrite.c
index 24c7040fb..308c9c296 100644
--- a/tests/stdio/fwrite.c
+++ b/tests/stdio/fwrite.c
@@ -5,21 +5,23 @@
 #include "test_helpers.h"
 
 int main(void) {
-	FILE *f = fopen("stdio/fwrite.out", "w");
-	const char ptr[] = "Hello World!";
+    FILE *f = fopen("stdio/fwrite.out", "w");
+    ERROR_IF(fopen, f, == NULL);
 
-	if (fwrite(ptr, 0, 17, f)) {
-		exit(EXIT_FAILURE);
-	}
+    const char ptr[] = "Hello World!";
 
-	if (fwrite(ptr, 7, 0, f)) {
-		exit(EXIT_FAILURE);
-	}
+    if (fwrite(ptr, 0, 17, f)) {
+        exit(EXIT_FAILURE);
+    }
 
-	if (fwrite(ptr, 0, 0, f)) {
-		exit(EXIT_FAILURE);
-	}
+    if (fwrite(ptr, 7, 0, f)) {
+        exit(EXIT_FAILURE);
+    }
 
-	fwrite(ptr, sizeof(ptr), 1, f);
-	fclose(f);
+    if (fwrite(ptr, 0, 0, f)) {
+        exit(EXIT_FAILURE);
+    }
+
+    fwrite(ptr, sizeof(ptr), 1, f);
+    fclose(f);
 }
diff --git a/tests/stdio/mutex.c b/tests/stdio/mutex.c
index aae45caa1..3d9be9d8d 100644
--- a/tests/stdio/mutex.c
+++ b/tests/stdio/mutex.c
@@ -4,7 +4,8 @@
 #include "test_helpers.h"
 
 int main(void) {
-    FILE* f = fopen("stdio/stdio.in", "r");
+    FILE *f = fopen("stdio/stdio.in", "r");
+    ERROR_IF(fopen, f, == NULL);
 
     flockfile(f);
 
diff --git a/tests/stdio/popen.c b/tests/stdio/popen.c
index 967ad78ac..3d314d52a 100644
--- a/tests/stdio/popen.c
+++ b/tests/stdio/popen.c
@@ -4,27 +4,14 @@
 #include "test_helpers.h"
 
 int main(void) {
-    FILE *fp;
-    int status;
-    char path[256];
-
-
-    fp = popen("ls -1 example_dir", "r");
-    if (fp == NULL) {
-        perror("popen");
-        exit(EXIT_FAILURE);
-    }
+    FILE *fp = popen("ls -1 example_dir", "r");
+    ERROR_IF(fopen, fp, == NULL);
 
+    char path[256] = { 0 };
     while (fgets(path, 256, fp) != NULL) {
         printf("%s", path);
     }
 
-
-    status = pclose(fp);
-    if (status == -1) {
-        perror("pclose");
-        exit(EXIT_FAILURE);
-    } else {
-        printf("status %x\n", status);
-    }
+    int status = pclose(fp);
+    ERROR_IF(pclose, status, == -1);
 }
diff --git a/tests/test_helpers.h b/tests/test_helpers.h
index 6db31e2d7..d3559a4e5 100644
--- a/tests/test_helpers.h
+++ b/tests/test_helpers.h
@@ -7,25 +7,67 @@
 #include <string.h>
 #include <unistd.h>
 
-// Throws an error on a well-defined error value.
-// Don't pass functions as status or condition, it might evaluate them multiple times.
+// Throws errors on a well-defined API error values.
+//
+// Only use with API functions that sets the errno variable.
+// Do not pass functions as the status or condition arguments, they might be
+// evaluated multiple times.
+//
+// Usage example:
+//
+// > Upon successful completion, fclose() returns 0.
+// > Otherwise, it returns EOF and sets errno to indicate the error.
+//
+// int status = fclose(fp);
+// ERROR_IF(fclose, status, == EOF);
+//
+// Use it only for checking the API error values.
+// Do not use it for checking the correctness of the results. If you need to
+// do that, print the values to the standard output and use the expected outputs
+// directory.
+//
+// For example:
+//
+// int c = fgetc(f);            // !!! DO NOT USE THIS WAY !!!
+// ERROR_IF(fgetc, c, != 'H');  // !!! DO NOT USE THIS WAY !!!
+//
+// Correct usage:
+//
+// int c = fgetc(f);            // OK
+// ERROR_IF(fgetc, c, == EOF);  // OK
+// printf("result: %c\n", c);   // OK
+//
 #define ERROR_IF(func, status, condition) { \
     if (status condition) { \
         fprintf(stderr, "%s:%s:%d: '%s' returned an error: %s (%d)\n", \
             __FILE__, __func__, __LINE__, #func, strerror(errno), errno); \
         _exit(EXIT_FAILURE); \
-    }\
+    } \
 }
 
-// Throws an error on an return value not defined by the standards.
-// Used for sanity checking the return values.
-// Don't pass functions as status or condition it might evaluate them multiple times.
+// Throws errors on API return values not defined by the standards.
+//
+// Do not pass functions as the status or condition arguments, they might be
+// evaluated multiple times.
+//
+// Use it only for detecting return values that should have never been returned
+// in any case by the API functions.
+//
+// Usage example:
+//
+// > The fgetc() function obtains the next byte as an unsigned char
+// > converted to an int.
+//
+// int c = fgetc(f);
+// UNEXP_IF(fgetc, c, < 0);
+// UNEXP_IF(fgetc, c, > 255);
+//
 #define UNEXP_IF(func, status, condition) { \
     if (status condition) { \
         fprintf(stderr, "%s:%s:%d: '%s' returned a non-standard value: %d\n", \
             __FILE__, __func__, __LINE__, #func, status); \
         _exit(EXIT_FAILURE); \
-    }\
+    } \
 }
 
 // A convenience macro to show where the test fail.
diff --git a/tests/waitpid.c b/tests/waitpid.c
index e0b77829f..ec4c6dedc 100644
--- a/tests/waitpid.c
+++ b/tests/waitpid.c
@@ -6,6 +6,8 @@
 
 int main(void) {
     pid_t pid = fork();
+    ERROR_IF(fork, pid, == -1);
+
     if (pid == 0) {
         // child
         sleep(1);
@@ -13,6 +15,7 @@ int main(void) {
     } else {
         // parent
         int stat_loc;
-        waitpid(pid, &stat_loc, 0);
+        pid_t wid = waitpid(pid, &stat_loc, 0);
+        ERROR_IF(waitpid, wid, == -1);
     }
 }
-- 
GitLab