aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEuAndreh <eu@euandre.org>2021-03-10 04:43:34 -0300
committerEuAndreh <eu@euandre.org>2021-03-10 04:43:34 -0300
commit461f0254ccdc4af66c1d2bfd1f34dbec0ef59218 (patch)
tree9a3026d9529d35d0e407792d9bc4ed60f60e440e /src
parentTODOs.md: Add comment on #task-c1129666-b373-4b9d-8e10-927689048b05 (diff)
downloadremembering-461f0254ccdc4af66c1d2bfd1f34dbec0ef59218.tar.gz
remembering-461f0254ccdc4af66c1d2bfd1f34dbec0ef59218.tar.xz
src/remembering.c: Write more tests, make existing tests more robust
Diffstat (limited to '')
-rw-r--r--src/remembering.c312
1 files changed, 250 insertions, 62 deletions
diff --git a/src/remembering.c b/src/remembering.c
index 215aa52..a2185b5 100644
--- a/src/remembering.c
+++ b/src/remembering.c
@@ -10,26 +10,46 @@
#include <sys/stat.h>
#include <unistd.h>
+#ifdef FALLIBLE
+#include <fallible.h>
+#include <fallible/alloc.h>
+#include <fallible/string.h>
+#endif
+
#ifdef TEST
#include <assert.h>
+
static void testing(const char *message) {
fprintf(stderr, "testing: %s...", message);
}
void test_ok() { fprintf(stderr, " OK.\n"); }
-#endif
-#ifdef FALLIBLE
-#include <fallible/alloc.h>
-#include <fallible/string.h>
-#endif
+FILE *tmpfile() {
+ char filename[] = "remembering-test.XXXXXX";
+
+ errno = 0;
+ int fd = mkstemp(filename);
+ if (fd == -1) {
+ perror("tmpfile mkstemp");
+ return NULL;
+ }
-static void print_usage(FILE *stream, char *given_name) {
- char *name = "remembering";
- if (given_name && given_name[0]) {
- name = given_name;
+ errno = 0;
+ FILE *f = fdopen(fd, "w");
+ if (!f) {
+ perror("tmpfile fdopen");
+ close(fd);
+ return NULL;
}
- fprintf(stream, "Usage: %s -p PROFILE -c 'COMMAND'\n", name);
+
+ return f;
+}
+#endif
+
+static void print_usage(FILE *stream, char *name) {
+ fprintf(stream, "Usage: %s -p PROFILE -c 'COMMAND'\n",
+ name ? name : "remembering");
}
static void print_help(FILE *stream) {
@@ -49,12 +69,20 @@ static void print_missing(FILE *stream, char *text) {
fprintf(stream, "Missing option: %s\n", text);
}
-static int get_options(int argc, char *argv[], char **command, char **profile) {
+static void print_version(FILE *stream) {
+ fprintf(stream, "remembering-%s %s\n", VERSION, DATE);
+}
+
+static int get_options(FILE *out, FILE *err, int argc, char *argv[],
+ char **command, char **profile) {
for (int i = 0; i < argc; i++) {
- if (!strcmp(argv[i], "--help")) {
- print_usage(stdout, argv[0]);
- print_help(stdout);
- exit(EXIT_SUCCESS);
+ if (strcmp(argv[i], "--help") == 0) {
+ print_usage(out, argv[0]);
+ print_help(out);
+ return 1;
+ } else if (strcmp(argv[i], "--version")) {
+ print_version(out);
+ return 1;
}
}
@@ -70,42 +98,119 @@ static int get_options(int argc, char *argv[], char **command, char **profile) {
profilearg = optarg;
break;
case 'h':
- print_usage(stdout, argv[0]);
- print_help(stdout);
- exit(EXIT_SUCCESS);
+ print_usage(out, argv[0]);
+ print_help(out);
+ return 1;
case 'V':
- fprintf(stdout, "remembering-%s %s\n", VERSION, DATE);
- exit(EXIT_SUCCESS);
+ print_version(out);
+ return 1;
}
}
- if (commandarg == NULL) {
- print_missing(stderr, "-c 'COMMAND'");
- print_usage(stderr, argv[0]);
- return 2;
+ if (!commandarg) {
+ print_missing(err, "-c 'COMMAND'");
+ print_usage(err, argv[0]);
+ return -1;
}
- if (profilearg == NULL) {
- print_missing(stderr, "-p 'PROFILE'");
- print_usage(stderr, argv[0]);
- return 2;
+ if (!profilearg) {
+ print_missing(err, "-p 'PROFILE'");
+ print_usage(err, argv[0]);
+ return 1;
}
- *command = malloc(strlen(commandarg) + 1);
+ *command = strdup(commandarg);
if (!*command) {
- return 1;
+ perror("strdup");
+ return -1;
}
- *profile = malloc(strlen(profilearg) + 1);
+ *profile = strdup(profilearg);
if (!*profile) {
+ perror("strdup");
free(*command);
- return 1;
+ return -1;
}
- strcpy(*command, commandarg);
- strcpy(*profile, profilearg);
return 0;
}
+#ifdef FALLIBLE
+static int fallible_get_options(FILE *out, FILE *err, int argc, char *argv[],
+ char **command, char **profile,
+ const char *const filename, int lineno) {
+ if (fallible_should_fail(filename, lineno)) {
+ return -1;
+ }
+ return get_options(out, err, argc, argv, command, profile);
+}
+
+#define get_options(out, err, argc, argv, command, profile) \
+ fallible_get_options(out, err, argc, argv, command, profile, __FILE__, \
+ __LINE__)
+#endif
+
+#ifdef TEST
+int arrlen(char **argv) {
+ int count = 0;
+ while (argv[count] != NULL) {
+ count++;
+ }
+ return count;
+}
+
+void get_options_test() {
+ {
+ testing("get_options when given -h, -V and --help");
+ FILE *f = tmpfile();
+ if (!f) {
+ exit(EXIT_FAILURE);
+ }
+
+ char *argvs[13][6] = {
+ { "--help", NULL },
+ { "other", "arguments before", "--help", NULL },
+ { "some", "--help", "arguments after", NULL },
+ { "--help", "all", "arguments after", NULL },
+ { "-h", NULL },
+ { "-V", NULL },
+ { "-hc", "1", NULL },
+ { "-hp", "2", NULL },
+ { "-hV", NULL },
+ { "-Vh", NULL },
+ { "-p", "p", "-h", NULL },
+ { "-p", "p", "-c", "c", "-h", NULL },
+ { NULL },
+ };
+ int rows = 0;
+ while (argvs[rows][0] != NULL) {
+ rows++;
+ }
+
+#ifdef DISABLE
+ int ret;
+ char *command = NULL;
+ char *profile = NULL;
+ for (int i = 0; i < rows; i++) {
+ char **argv = argvs[i];
+ ret = get_options(f, f, arrlen(argvs[i]), argv, &command, &profile);
+ if (ret == -1) {
+ fclose(f);
+ exit(EXIT_FAILURE);
+ }
+
+ assert(command == NULL);
+ assert(profile == NULL);
+ assert(ret == 1);
+ }
+#endif
+
+ fclose(f);
+ test_ok();
+ }
+ // { "" },
+}
+#endif
+
static int mkdir_p(char *path, mode_t mode) {
struct stat s;
if (stat(path, &s) == 0 && S_ISDIR(s.st_mode)) {
@@ -120,7 +225,27 @@ static int mkdir_p(char *path, mode_t mode) {
return mkdir(path, mode);
}
-// add fallible variation? where are the tests to stress it?
+#ifdef FALLIBLE
+static int fallible_mkdir_p(char *path, mode_t mode, const char *const filename,
+ int lineno) {
+ if (fallible_should_fail(filename, lineno)) {
+ return -1;
+ }
+ return mkdir_p(path, mode);
+}
+
+#define mkdir_p(path, mode) fallible_mkdir_p(path, mode, __FILE__, __LINE__)
+#endif
+
+#ifdef TEST
+static void mkdir_p_test() {
+ {
+ testing("mkdir_p");
+ test_ok();
+ }
+}
+#endif
+
static char *expand_profile_name(const char *const profile_name) {
char *prefix = NULL;
char *env_prefix = getenv("XDG_DATA_HOME");
@@ -155,11 +280,38 @@ static char *expand_profile_name(const char *const profile_name) {
errno = 0;
int ret = mkdir_p(dirname(expanded_profile), 0755);
if (ret) {
+ perror("mkdir_p");
return NULL;
}
return expanded_profile;
}
+#ifdef FALLIBLE
+static char *fallible_expand_profile_name(const char *const profile_name,
+ const char *const filename,
+ int lineno) {
+ if (fallible_should_fail(filename, lineno)) {
+ return NULL;
+ }
+ return expand_profile_name(profile_name);
+}
+
+#define expand_profile_name(profile_name) \
+ fallible_expand_profile_name(profile_name, __FILE__, __LINE__)
+#endif
+
+#ifdef TEST
+static void expand_profile_name_test() {
+ {
+ testing("expand_profile_name");
+ if (0) {
+ expand_profile_name("oij");
+ }
+ test_ok();
+ }
+}
+#endif
+
static const size_t RANKINGS_INITIAL_SIZE = 100;
static const int RANKINGS_GROWTH_MULTIPLIER = 2;
@@ -334,20 +486,16 @@ int fallible_parse_ranked_line(FILE *stream, const char *entry, char **value,
#endif
#ifdef TEST
-void parse_ranked_line_test() {
+static void parse_ranked_line_test() {
{
testing("parse_ranked_line with an empty string");
- char *value;
- int rank;
-
- char filename[] = "remembering-test.XXXXXX";
- int fd;
- if ((fd = mkstemp(filename)) == -1) {
- fprintf(stderr, "\nERR: Can't create test tempfile.\n");
+ FILE *f = tmpfile();
+ if (!f) {
exit(EXIT_FAILURE);
}
- FILE *f = fdopen(fd, "w");
+ char *value;
+ int rank;
int ret = parse_ranked_line(f, "", &value, &rank);
assert(ret == -1);
fclose(f);
@@ -355,17 +503,13 @@ void parse_ranked_line_test() {
}
{
testing("parse_ranked_line when RANKING DELIMITER is missing");
- char *value;
- int rank;
-
- char filename[] = "remembering-test.XXXXXX";
- int fd;
- if ((fd = mkstemp(filename)) == -1) {
- fprintf(stderr, "\nERR: Can't create test tempfile.\n");
+ FILE *f = tmpfile();
+ if (!f) {
exit(EXIT_FAILURE);
}
- FILE *f = fdopen(fd, "w");
+ char *value;
+ int rank;
int ret = parse_ranked_line(f, "0 command", &value, &rank);
assert(ret == -1);
fclose(f);
@@ -378,30 +522,45 @@ void parse_ranked_line_test() {
int ret;
ret = parse_ranked_line(stderr, "0:command", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
assert(ret == 0);
assert(strcmp(value, "command") == 0);
assert(rank == 0);
free(value);
ret = parse_ranked_line(stderr, "10:another command", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
assert(ret == 0);
assert(strcmp(value, "another command") == 0);
assert(rank == 10);
free(value);
ret = parse_ranked_line(stderr, "123:123", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
assert(ret == 0);
assert(strcmp(value, "123") == 0);
assert(rank == 123);
free(value);
ret = parse_ranked_line(stderr, "-123:command", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
assert(ret == 0);
assert(strcmp(value, "command") == 0);
assert(rank == -123);
free(value);
ret = parse_ranked_line(stderr, "0:0", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
assert(ret == 0);
assert(strcmp(value, "0") == 0);
assert(rank == 0);
@@ -409,6 +568,9 @@ void parse_ranked_line_test() {
ret = parse_ranked_line(stderr, "0:command with : in the middle", &value,
&rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
assert(ret == 0);
assert(strcmp(value, "command with : in the middle") == 0);
assert(rank == 0);
@@ -416,6 +578,9 @@ void parse_ranked_line_test() {
ret = parse_ranked_line(
stderr, "0:::command:with:multiple:::in:the:middle:", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
assert(ret == 0);
assert(strcmp(value, "::command:with:multiple:::in:the:middle:") == 0);
assert(rank == 0);
@@ -429,6 +594,9 @@ void parse_ranked_line_test() {
int rank;
int ret = parse_ranked_line(stderr, "0:", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
assert(ret == 0);
assert(strcmp(value, "") == 0);
assert(rank == 0);
@@ -442,36 +610,54 @@ void parse_ranked_line_test() {
int ret;
ret = parse_ranked_line(stderr, ":command", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
assert(ret == 0);
assert(strcmp(value, "command") == 0);
assert(rank == 0);
free(value);
ret = parse_ranked_line(stderr, "1 2 3:command", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
assert(ret == 0);
assert(strcmp(value, "command") == 0);
assert(rank == 1);
free(value);
ret = parse_ranked_line(stderr, ".1:command", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
assert(ret == 0);
assert(strcmp(value, "command") == 0);
assert(rank == 0);
free(value);
ret = parse_ranked_line(stderr, "3.14:command", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
assert(ret == 0);
assert(strcmp(value, "command") == 0);
assert(rank == 3);
free(value);
ret = parse_ranked_line(stderr, ":5:command", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
assert(ret == 0);
assert(strcmp(value, "5:command") == 0);
assert(rank == 0);
free(value);
ret = parse_ranked_line(stderr, "command:command", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
assert(ret == 0);
assert(strcmp(value, "command") == 0);
assert(rank == 0);
@@ -603,7 +789,10 @@ int merge_stdin_with_profile(char *profile_name, struct Rankings *s_rankings,
*/
#ifdef TEST
-void unit_tests() {
+static void unit_tests() {
+ get_options_test();
+ mkdir_p_test();
+ expand_profile_name_test();
rankings_test();
parse_ranked_line_test();
}
@@ -612,17 +801,16 @@ void unit_tests() {
int main(int argc, char *argv[]) {
#ifdef TEST
unit_tests();
- return 0;
+ return EXIT_SUCCESS;
#endif
int ret;
- char *command;
- char *profile;
- if ((ret = get_options(argc, argv, &command, &profile))) {
- goto err;
- expand_profile_name("oijoI");
- }
-err:
- return ret;
+ char *command, *profile;
+ ret = get_options(stdout, stderr, argc, argv, &command, &profile);
+ if (ret == -1) {
+ return EXIT_FAILURE;
+ } else if (ret) {
+ return EXIT_SUCCESS;
+ }
}