From 652c8d3b29a6a0ea15fb4528bc026c954e17a42c Mon Sep 17 00:00:00 2001 From: rhersen Date: Sun, 24 Jun 2012 16:45:33 +0200 Subject: [PATCH 1/2] added unit test --- Makefile | 6 ++- src/commander.c | 24 +++++---- src/commander.h | 3 +- unit.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 158 insertions(+), 11 deletions(-) create mode 100644 unit.c diff --git a/Makefile b/Makefile index 70df6fd..f045245 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,10 @@ +CC = gcc test: test.c src/commander.c - $(CC) $^ -std=c99 -o $@ + $(CC) -Wall $^ -std=c99 -o $@ + +unit: unit.c src/commander.c + $(CC) -Wall -g -fprofile-arcs -ftest-coverage $^ -std=c99 -o $@ clean: rm -f test diff --git a/src/commander.c b/src/commander.c index 5de10e5..98c3f03 100644 --- a/src/commander.c +++ b/src/commander.c @@ -16,9 +16,9 @@ */ static void -error(char *msg) { +error(command_t *self, char *msg) { fprintf(stderr, "%s\n", msg); - exit(1); + self->exit(1); } /* @@ -28,7 +28,12 @@ error(char *msg) { static void command_version(command_t *self) { printf("%s\n", self->version); - exit(0); + self->exit(0); +} + +static void +doExit(int status) { + exit(status); } /* @@ -50,7 +55,7 @@ command_help(command_t *self) { , option->description); } printf("\n"); - exit(0); + self->exit(0); } /* @@ -66,6 +71,7 @@ command_init(command_t *self, const char *name, const char *version) { self->usage = "[options]"; command_option(self, "-V", "--version", "output program version", command_version); command_option(self, "-h", "--help", "output help information", command_help); + self->exit = doExit; } /* @@ -102,7 +108,7 @@ parse_argname(const char *str, char *flag, char *arg) { void command_option(command_t *self, const char *small, const char *large, const char *desc, command_callback_t cb) { int n = self->option_count++; - if (n == COMMANDER_MAX_OPTIONS) error("Maximum option definitions exceeded"); + if (n == COMMANDER_MAX_OPTIONS) error(self, "Maximum option definitions exceeded"); command_option_t *option = &self->options[n]; option->cb = cb; option->small = small; @@ -142,7 +148,7 @@ command_parse(command_t *self, int argc, char **argv) { arg = argv[++i]; if (!arg || '-' == arg[0]) { fprintf(stderr, "%s %s argument required\n", option->large, option->argname); - exit(1); + self->exit(1); } self->arg = arg; } @@ -169,12 +175,12 @@ command_parse(command_t *self, int argc, char **argv) { // unrecognized if ('-' == arg[0] && !literal) { fprintf(stderr, "unrecognized flag %s\n", arg); - exit(1); + self->exit(1); } int n = self->argc++; - if (n == COMMANDER_MAX_ARGS) error("Maximum number of arguments exceeded"); + if (n == COMMANDER_MAX_ARGS) error(self, "Maximum number of arguments exceeded"); self->argv[n] = (char *) arg; match:; } -} \ No newline at end of file +} diff --git a/src/commander.h b/src/commander.h index a7589ff..0158a49 100644 --- a/src/commander.h +++ b/src/commander.h @@ -65,6 +65,7 @@ typedef struct command { command_option_t options[COMMANDER_MAX_OPTIONS]; int argc; char *argv[COMMANDER_MAX_ARGS]; + void (*exit)(int); } command_t; // prototypes @@ -81,4 +82,4 @@ command_option(command_t *self, const char *small, const char *large, const char void command_parse(command_t *self, int argc, char **argv); -#endif /* COMMANDER_H */ \ No newline at end of file +#endif /* COMMANDER_H */ diff --git a/unit.c b/unit.c new file mode 100644 index 0000000..9ceaef7 --- /dev/null +++ b/unit.c @@ -0,0 +1,136 @@ +#include +#include +#include + +#include "src/commander.h" + +#define assertEqualsI(a,e) _assertEqualsI(a,e,__FILE__,__LINE__) + +static void _assertEqualsI(int actual, int expected, char *file, int line) { + if (actual == expected) { + printf("%s:%d:\033[0;32m %d OK\033[0m\n", file, line, actual); + } else { + printf("%s:%d:\033[0;31m expected %d but got %d\033[0m\n", + file, line, expected, actual); + } +} + +#define assertFalse(a) _assertTrue(!(a),__FILE__,__LINE__) +#define assertTrue(a) _assertTrue((a),__FILE__,__LINE__) + +static void _assertTrue(int actual, char *file, int line) { + if (actual) { + printf("%s:%d:\033[0;32m %d OK\033[0m\n", file, line, actual); + } else { + printf("%s:%d:\033[0;31m got %d\033[0m\n", file, line, actual); + } +} + +static double getElapsedSecondsSince(struct timeval* start) { + struct timeval now; + gettimeofday(&now, 0); + int usec = now.tv_usec - start->tv_usec; + int sec = now.tv_sec - start->tv_sec; + + return usec * 1e-6 + sec; +} + +static int isVerboseSet = 0; +static int isRequiredSet = 0; +static int exitStatus = 0; + +static void +verbose(command_t *self) { + isVerboseSet = 1; +} + +static void +required(command_t *self) { + isRequiredSet = 1; +} + +static jmp_buf exitCalled; + +static void setStatus(int status) { + exitStatus = status; + longjmp(exitCalled, 1); +} + +static void setUp() { + isVerboseSet = 0; + isRequiredSet = 0; + exitStatus = 0; +} + +static void init(command_t* target) { + command_init(target, "name", "0.0.1"); + target->exit = setStatus; +} + +static void shouldDoNothingIfArgumentListIsEmpty(void) { + setUp(); + command_t target = {0}; + if (!setjmp(exitCalled)) command_parse(&target, 0, 0); + assertEqualsI(target.data, 0); +} + +static void shouldEnableVerbose(void) +{ + setUp(); + command_t target; + init(&target); + command_option(&target, "-v", "--verbose", "enable verbose stuff", verbose); + char* argv[] = { "name", "-v", 0 }; + if (!setjmp(exitCalled)) command_parse(&target, 2, argv); + assertTrue(isVerboseSet); +} + +static void shouldSetExitStatus(void) +{ + setUp(); + command_t target; + init(&target); + command_option(&target, "-v", "--verbose", "enable verbose stuff", verbose); + char* argv[] = { "name", "-w", 0 }; + if (!setjmp(exitCalled)) command_parse(&target, 2, argv); + assertFalse(isVerboseSet); + assertEqualsI(exitStatus, 1); +} + +static void shouldSetRequired(void) +{ + setUp(); + command_t target; + init(&target); + command_option(&target, "-r", "--required ", "required arg", required); + char* argv[] = { "name", "-r", "val", 0 }; + if (!setjmp(exitCalled)) command_parse(&target, 3, argv); + assertEqualsI(exitStatus, 0); + assertTrue(isRequiredSet); +} + +static void shouldFailIfRequiredIsMissingValue(void) +{ + setUp(); + command_t target; + init(&target); + command_option(&target, "-r", "--required ", "required arg", required); + char* argv[] = { "name", "-r", 0 }; + if (!setjmp(exitCalled)) command_parse(&target, 2, argv); + assertEqualsI(exitStatus, 1); + assertFalse(isRequiredSet); +} + +int main(void) { + struct timeval start; + gettimeofday(&start, 0); + + shouldDoNothingIfArgumentListIsEmpty(); + shouldEnableVerbose(); + shouldSetExitStatus(); + shouldSetRequired(); + shouldFailIfRequiredIsMissingValue(); + printf("%f seconds\n", getElapsedSecondsSince(&start)); + + return 0; +} From e7e28ef4a3e1ef631acca432bd315bdeb41755e7 Mon Sep 17 00:00:00 2001 From: rhersen Date: Tue, 26 Jun 2012 22:28:39 +0200 Subject: [PATCH 2/2] added more unit tests --- .gitignore | 1 + Makefile | 8 ++--- unit.c | 95 ++++++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 78 insertions(+), 26 deletions(-) diff --git a/.gitignore b/.gitignore index 76758b0..91dcf40 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.o test +unit diff --git a/Makefile b/Makefile index f045245..a0fbc37 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,10 @@ -CC = gcc - test: test.c src/commander.c - $(CC) -Wall $^ -std=c99 -o $@ + $(CC) $^ -std=c99 -o $@ unit: unit.c src/commander.c - $(CC) -Wall -g -fprofile-arcs -ftest-coverage $^ -std=c99 -o $@ + $(CC) $^ -std=c99 -o $@ clean: - rm -f test + rm -f test unit .PHONY: clean \ No newline at end of file diff --git a/unit.c b/unit.c index 9ceaef7..b9f456a 100644 --- a/unit.c +++ b/unit.c @@ -1,28 +1,30 @@ +#include #include +#include #include -#include #include "src/commander.h" -#define assertEqualsI(a,e) _assertEqualsI(a,e,__FILE__,__LINE__) +#define assertEquals(a,e) _assertEqualsI(a,e,__func__,__LINE__) +#define assertEqualStr(a,e) _assertEqualsI(strcmp(a,e),0,__func__,__LINE__) -static void _assertEqualsI(int actual, int expected, char *file, int line) { +static void _assertEqualsI(int actual, int expected, const char *file, int line) { if (actual == expected) { - printf("%s:%d:\033[0;32m %d OK\033[0m\n", file, line, actual); + printf("%s/%d:\033[0;32m OK\033[0m\n", file, line); } else { - printf("%s:%d:\033[0;31m expected %d but got %d\033[0m\n", + printf("%s/%d:\033[0;31m expected %d but got %d\033[0m\n", file, line, expected, actual); } } -#define assertFalse(a) _assertTrue(!(a),__FILE__,__LINE__) -#define assertTrue(a) _assertTrue((a),__FILE__,__LINE__) +#define assertFalse(a) _assertTrue(!(a),__func__,__LINE__) +#define assertTrue(a) _assertTrue((a),__func__,__LINE__) -static void _assertTrue(int actual, char *file, int line) { +static void _assertTrue(int actual, const char *file, int line) { if (actual) { - printf("%s:%d:\033[0;32m %d OK\033[0m\n", file, line, actual); + printf("%s/%d:\033[0;32m OK\033[0m\n", file, line); } else { - printf("%s:%d:\033[0;31m got %d\033[0m\n", file, line, actual); + printf("%s/%d:\033[0;31m got %d\033[0m\n", file, line, actual); } } @@ -37,6 +39,7 @@ static double getElapsedSecondsSince(struct timeval* start) { static int isVerboseSet = 0; static int isRequiredSet = 0; +static int isOptionalSet = 0; static int exitStatus = 0; static void @@ -48,6 +51,11 @@ static void required(command_t *self) { isRequiredSet = 1; } + +static void +optional(command_t *self) { + isOptionalSet = 1; +} static jmp_buf exitCalled; @@ -59,6 +67,7 @@ static void setStatus(int status) { static void setUp() { isVerboseSet = 0; isRequiredSet = 0; + isOptionalSet = 0; exitStatus = 0; } @@ -67,13 +76,6 @@ static void init(command_t* target) { target->exit = setStatus; } -static void shouldDoNothingIfArgumentListIsEmpty(void) { - setUp(); - command_t target = {0}; - if (!setjmp(exitCalled)) command_parse(&target, 0, 0); - assertEqualsI(target.data, 0); -} - static void shouldEnableVerbose(void) { setUp(); @@ -94,7 +96,7 @@ static void shouldSetExitStatus(void) char* argv[] = { "name", "-w", 0 }; if (!setjmp(exitCalled)) command_parse(&target, 2, argv); assertFalse(isVerboseSet); - assertEqualsI(exitStatus, 1); + assertEquals(exitStatus, 1); } static void shouldSetRequired(void) @@ -105,7 +107,7 @@ static void shouldSetRequired(void) command_option(&target, "-r", "--required ", "required arg", required); char* argv[] = { "name", "-r", "val", 0 }; if (!setjmp(exitCalled)) command_parse(&target, 3, argv); - assertEqualsI(exitStatus, 0); + assertEquals(exitStatus, 0); assertTrue(isRequiredSet); } @@ -117,19 +119,70 @@ static void shouldFailIfRequiredIsMissingValue(void) command_option(&target, "-r", "--required ", "required arg", required); char* argv[] = { "name", "-r", 0 }; if (!setjmp(exitCalled)) command_parse(&target, 2, argv); - assertEqualsI(exitStatus, 1); + assertEquals(exitStatus, 1); assertFalse(isRequiredSet); } +static void shouldSetOptional(void) +{ + setUp(); + command_t target; + init(&target); + command_option(&target, "-o", "--optional [arg]", "optional arg", optional); + char* argv[] = { "name", "-o", "val", 0 }; + if (!setjmp(exitCalled)) command_parse(&target, 3, argv); + assertEquals(exitStatus, 0); + assertTrue(isOptionalSet); +} + +static void shouldNotFailIfOptionalIsMissingValue(void) +{ + setUp(); + command_t target; + init(&target); + command_option(&target, "-o", "--optional [arg]", "optional arg", optional); + char* argv[] = { "name", "-o", 0 }; + if (!setjmp(exitCalled)) command_parse(&target, 2, argv); + assertEquals(exitStatus, 0); + assertTrue(isOptionalSet); +} + +static void shouldSetAdditional(void) +{ + setUp(); + command_t target; + init(&target); + char* argv[] = { "name", "o", 0 }; + if (!setjmp(exitCalled)) command_parse(&target, 2, argv); + assertEquals(exitStatus, 0); + assertEquals(target.argc, 1); + assertEqualStr(target.argv[0], "o"); +} + +static void shouldSetLiteral(void) +{ + setUp(); + command_t target; + init(&target); + char* argv[] = { "name", "--", "-o", 0 }; + if (!setjmp(exitCalled)) command_parse(&target, 3, argv); + assertEquals(exitStatus, 0); + assertEquals(target.argc, 1); + assertEqualStr(target.argv[0], "-o"); +} + int main(void) { struct timeval start; gettimeofday(&start, 0); - shouldDoNothingIfArgumentListIsEmpty(); shouldEnableVerbose(); shouldSetExitStatus(); shouldSetRequired(); shouldFailIfRequiredIsMissingValue(); + shouldSetOptional(); + shouldNotFailIfOptionalIsMissingValue(); + shouldSetAdditional(); + shouldSetLiteral(); printf("%f seconds\n", getElapsedSecondsSince(&start)); return 0;