aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEuAndreh <eu@euandre.org>2021-06-27 10:42:57 -0300
committerEuAndreh <eu@euandre.org>2021-06-27 10:46:06 -0300
commit757c8963101a0bce5dbb5ad389acdcf7ceb2ecc4 (patch)
tree12e61b5eabb5be8634c506aeb37267041aa3390a
parentsrc/remembering-c.c: Add get_profile_file() (diff)
downloadremembering-757c8963101a0bce5dbb5ad389acdcf7ceb2ecc4.tar.gz
remembering-757c8963101a0bce5dbb5ad389acdcf7ceb2ecc4.tar.xz
src/remembering-c.c: Add unit tests for get_profile_file()
Those tests led me to handling the case where $XDG_DATA_HOME was set, but as an empty string. This is the equivalent of the "[ -z ".." ]" test. I also parameterized get_profile_file() to receive the stream where it should write to in case of failing to getenv("HOME"). Even though this makes the arguments of functions that print longer, it looks like an overall good pattern. It is the equivalent of every sh function printing to STDOUT, and let the caller decide if it should go to STDOUT or STDERR.
-rw-r--r--src/remembering-c.c146
-rw-r--r--src/unit-test.h23
2 files changed, 164 insertions, 5 deletions
diff --git a/src/remembering-c.c b/src/remembering-c.c
index 2e7395f..a6bd8c2 100644
--- a/src/remembering-c.c
+++ b/src/remembering-c.c
@@ -7,6 +7,12 @@
#include <string.h>
#include <unistd.h>
+#ifdef TEST
+#include "unit-test.h"
+#include <stdbool.h>
+#endif
+
+
const int EXIT_ERROR = 1;
const int EXIT_USAGE = 2;
@@ -52,11 +58,11 @@ static int missing(FILE *stream, const char *const argument) {
return 0;
}
-static char *get_profile_file(const char *const profile) {
- char *home = NULL;
- if (!(home = getenv("XDG_DATA_HOME"))) {
+static char *get_profile_file(const char *const profile, FILE *stream) {
+ char *home = getenv("XDG_DATA_HOME");
+ if (!home || (strcmp(home, "")) == 0) {
if (!(home = getenv("HOME"))) {
- fprintf(stderr, "Unable to get $XDG_DATA_HOME or $HOME environment variables\n");
+ fprintf(stream, "Unable to get $XDG_DATA_HOME or $HOME environment variables\n");
return NULL;
}
const char *const suffix = "/.local/share/remembering";
@@ -97,8 +103,138 @@ static char *get_profile_file(const char *const profile) {
return profile_file;
}
+#ifdef TEST
+void test_get_profile_file() {
+ #define EXPECTED_FMT "\nexpected: %s\ngot: %s\n"
+ FILE *f = fopen("/dev/null", "w");
+ assert(f);
+
+ {
+ testing("get_profile_file() when $XDG_DATA_HOME is *unset*");
+ const char *const previous_xdg_data_home = getenv("XDG_DATA_HOME");
+ unsetenv("XDG_DATA_HOME");
+
+ const char *const HOME = getenv("HOME");
+ const char *const SUFFIX = "/.local/share/remembering/";
+ const char *const A_PROFILE = "A-PROFILE-NAME";
+ assert(HOME);
+
+ const size_t expected_size =
+ strlen(HOME) +
+ strlen(SUFFIX) +
+ strlen(A_PROFILE) +
+ sizeof(char);
+ char *const expected = malloc(expected_size);
+ assert(expected);
+ strcat(expected, HOME);
+ strcat(expected, SUFFIX);
+ strcat(expected, A_PROFILE);
+
+ char *const profile_file = get_profile_file(A_PROFILE, f);
+ assert(profile_file);
+ assertf(
+ strcmp(profile_file, expected) == 0,
+ EXPECTED_FMT,
+ expected,
+ profile_file
+ );
+
+ free(profile_file);
+ free(expected);
+ if (previous_xdg_data_home) {
+ setenv("XDG_DATA_HOME", previous_xdg_data_home, true);
+ }
+ test_ok();
+ }
+ {
+ testing("get_profile_file() when $XDG_DATA_HOME is *empty*");
+ const char *const previous_xdg_data_home = getenv("XDG_DATA_HOME");
+ setenv("XDG_DATA_HOME", "", true);
+
+ const char *const HOME = getenv("HOME");
+ const char *const SUFFIX = "/.local/share/remembering/";
+ const char *const A_PROFILE = "ANOTHER-PROFILE-NAME";
+ assert(HOME);
+
+ const size_t expected_size =
+ strlen(HOME) +
+ strlen(SUFFIX) +
+ strlen(A_PROFILE) +
+ sizeof(char);
+ char *const expected = malloc(expected_size);
+ assert(expected);
+ strcat(expected, HOME);
+ strcat(expected, SUFFIX);
+ strcat(expected, A_PROFILE);
+
+ char *const profile_file = get_profile_file(A_PROFILE, f);
+ assert(profile_file);
+ assertf(
+ strcmp(profile_file, expected) == 0,
+ EXPECTED_FMT,
+ expected,
+ profile_file
+ );
+
+ free(profile_file);
+ free(expected);
+ if (previous_xdg_data_home) {
+ setenv("XDG_DATA_HOME", previous_xdg_data_home, true);
+ } else {
+ unsetenv("XDG_DATA_HOME");
+ }
+ test_ok();
+ }
+ {
+ testing("get_profile_file() when $XDG_DATA_HOME is *set*");
+ const char *const previous_xdg_data_home = getenv("XDG_DATA_HOME");
+
+ const char *const XDG_DATA_HOME = "/a/custom/path";
+ const char *const A_PROFILE = "YET-ANOTHER-PROFILE-NAME";
+ const char *const EXPECTED = "/a/custom/path/YET-ANOTHER-PROFILE-NAME";
+
+ setenv("XDG_DATA_HOME", XDG_DATA_HOME, true);
+
+ char *const profile_file = get_profile_file(A_PROFILE, f);
+ assert(profile_file);
+ assertf(
+ strcmp(profile_file, EXPECTED) == 0,
+ EXPECTED_FMT,
+ EXPECTED,
+ profile_file
+ );
+
+ free(profile_file);
+ if (previous_xdg_data_home) {
+ setenv("XDG_DATA_HOME", previous_xdg_data_home, true);
+ } else {
+ unsetenv("XDG_DATA_HOME");
+ }
+ test_ok();
+ }
+ {
+ testing("get_profile_file() when $HOME is *unset*");
+ const char *const previous_home = getenv("HOME");
+ const char *const previous_xdg_data_home = getenv("XDG_DATA_HOME");
+ unsetenv("XDG_DATA_HOME");
+ unsetenv("HOME");
+
+ assert(get_profile_file("ANY-PROFILE", f) == NULL);
+
+ setenv("HOME", previous_home, true);
+ if (previous_xdg_data_home) {
+ setenv("XDG_DATA_HOME", previous_xdg_data_home, true);
+ }
+ test_ok();
+ }
+
+ fclose(f);
+}
+#endif
+
int main(int argc, char *argv[]) {
#ifdef TEST
+ test_get_profile_file();
return EXIT_SUCCESS;
#endif
@@ -151,7 +287,7 @@ int main(int argc, char *argv[]) {
return EXIT_USAGE;
}
- char *const profile_file = get_profile_file(profile);
+ char *const profile_file = get_profile_file(profile, stderr);
if(!profile_file) {
return EXIT_ERROR;
}
diff --git a/src/unit-test.h b/src/unit-test.h
new file mode 100644
index 0000000..1dcd53c
--- /dev/null
+++ b/src/unit-test.h
@@ -0,0 +1,23 @@
+#ifndef UNIT_TEST_H
+#define UNIT_TEST_H
+
+#include <assert.h>
+
+#define COLOUR_RESET "\033[0m"
+#define COLOUR_RED "\033[0;31m"
+#define COLOUR_GREEN "\033[0;32m"
+#define COLOUR_YELLOW "\033[0;33m"
+
+void testing(const char *const message) {
+ fprintf(stderr, "testing: " COLOUR_YELLOW "%s" COLOUR_RESET "...", message);
+}
+
+void test_ok() {
+ fprintf(stderr, " " COLOUR_GREEN "OK" COLOUR_RESET ".\n");
+}
+
+#define ASSERT_MSG "\n" COLOUR_RED "ERROR" COLOUR_RESET ": "
+#define assertf(A, M, ...) if (!(A)) { fprintf(stderr, (ASSERT_MSG M "\n"), __VA_ARGS__); assert(A); }
+#define asserte(A) if (!(A)) { fprintf(stderr, ASSERT_MSG "\n"); assert(A); }
+
+#endif