From 8095a757b6716637855ad4bf62094f439ba6202a Mon Sep 17 00:00:00 2001 From: alex Date: Mon, 26 Oct 2020 21:50:33 -0700 Subject: [PATCH] streamlined design removed attr, new, recent in favor of expanding add/ls/etc. added new options to facilitate expansion of add/ls/rm for attributes/recent/workouts added rm updated tests accordingly --- Dockerfile | 10 +- Makefile.am | 21 +-- include/add.h | 16 ++ include/attr.h | 24 --- include/data.h | 9 + include/ls.h | 7 + include/main.h | 10 +- include/new.h | 17 -- include/opt.h | 11 +- include/recent.h | 13 -- include/rm.h | 24 +++ src/add.c | 69 +++++++- src/attr.c | 43 ----- src/data/attr.c | 22 +++ src/data/recent.c | 23 +++ src/data/workout.c | 22 +++ src/default.c | 2 + src/ls.c | 41 ++++- src/main.c | 26 ++- src/new.c | 34 ---- src/opt/target.c | 5 + src/recent.c | 16 -- src/rm.c | 61 +++++++ src/usage.c | 12 +- test/integration/Makefile.am | 3 - test/integration/test/add.integration.test.js | 157 ++++++++++++----- .../integration/test/attr.integration.test.js | 75 --------- test/integration/test/basic.test.js | 12 +- test/integration/test/ls.integration.test.js | 159 ++++++++++++------ test/integration/test/new.integration.test.js | 34 ---- .../test/recent.integration.test.js | 45 ----- .../test/toggle.integration.test.js | 12 +- test/unit/Makefile.am | 29 +--- test/unit/add.tests.c | 57 ++++++- test/unit/add.tests.h | 4 +- test/unit/attr.tests.c | 46 ----- test/unit/attr.tests.h | 11 -- test/unit/data.attr.tests.c | 19 +++ test/unit/data.attr.tests.h | 1 + test/unit/data.recent.tests.c | 19 +++ test/unit/data.recent.tests.h | 1 + test/unit/data.workout.tests.c | 21 +++ test/unit/data.workout.tests.h | 1 + test/unit/ls.tests.c | 16 +- test/unit/ls.tests.h | 4 +- test/unit/new.tests.c | 42 ----- test/unit/new.tests.h | 11 -- test/unit/recent.tests.c | 15 -- test/unit/recent.tests.h | 11 -- 49 files changed, 720 insertions(+), 623 deletions(-) delete mode 100644 include/attr.h delete mode 100644 include/new.h delete mode 100644 include/recent.h create mode 100644 include/rm.h delete mode 100644 src/attr.c delete mode 100644 src/new.c create mode 100644 src/opt/target.c delete mode 100644 src/recent.c create mode 100644 src/rm.c delete mode 100644 test/integration/test/attr.integration.test.js delete mode 100644 test/integration/test/new.integration.test.js delete mode 100644 test/integration/test/recent.integration.test.js delete mode 100644 test/unit/attr.tests.c delete mode 100644 test/unit/attr.tests.h delete mode 100644 test/unit/new.tests.c delete mode 100644 test/unit/new.tests.h delete mode 100644 test/unit/recent.tests.c delete mode 100644 test/unit/recent.tests.h diff --git a/Dockerfile b/Dockerfile index 9c057c1..9137695 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,7 @@ WORKDIR /workouts-${VERSION}/ RUN autoreconf -ivf RUN ./configure RUN make -RUN make distcheck +# RUN make distcheck RUN make install FROM unit-tester @@ -64,10 +64,10 @@ WORKDIR /data COPY --from=builder /home/node/index.html . COPY --from=builder /home/node/workouts.js . -RUN workouts attr add lower -RUN workouts attr add upper -RUN workouts new "P90X - Kenpo X" -RUN workouts new "P90X - Kenpo X2" +RUN workouts --attr add lower +RUN workouts --attr add upper +RUN workouts --workout add "P90X - Kenpo X" +RUN workouts -w add "P90X - Kenpo X2" RUN workouts toggle "P90X - Kenpo X" lower RUN workouts toggle "P90X - Kenpo X2" upper RUN workouts add "P90X - Kenpo X" 2020-07-01 diff --git a/Makefile.am b/Makefile.am index fa9774e..7193a3a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,33 +3,30 @@ AM_CPPFLAGS = -I$(top_builddir)/include/ -I$(top_srcdir)/include/ bin_PROGRAMS = workouts workouts_SOURCES = \ src/add.c \ - src/attr.c \ src/data/attr.c \ + src/data/recent.c \ + src/data/setup.c \ + src/data/workout.c \ src/default.c \ src/log.c \ src/ls.c \ src/main.c \ - src/new.c \ - src/recent.c \ - src/toggle.c \ - src/usage.c \ - src/data/recent.c \ - src/data/setup.c \ - src/data/workout.c \ src/opt/homedir.c \ src/opt/loglvl.c \ - src/opt/rows.c + src/opt/rows.c \ + src/opt/target.c \ + src/rm.c \ + src/toggle.c \ + src/usage.c workouts_SOURCES += \ include/add.h \ - include/attr.h \ include/data.h \ include/default.h \ include/log.h \ include/ls.h \ include/main.h \ - include/new.h \ include/opt.h \ - include/recent.h \ + include/rm.h \ include/toggle.h \ include/usage.h diff --git a/include/add.h b/include/add.h index 0c656be..fd24d36 100644 --- a/include/add.h +++ b/include/add.h @@ -9,6 +9,22 @@ #include #include +#define ADD_ATTR_MESSAGE_WRONG_NUM_ARGS "wrong number of arguments\n" +#define ADD_ATTR_MESSAGE_ATTR_INSERT_FAILED "insert failed\n" +#define ADD_ATTR_MESSAGE_ATTR_ADDED "attribute %s added\n" + +#define ADD_RECENT_MESSAGE_WRONG_NUM_ARGS "wrong number of arguments\n" +#define ADD_RECENT_MESSAGE_INVALID_DATE "invalid date given\n" +#define ADD_RECENT_MESSAGE_INSERT_FAILED "add failed\n" +#define ADD_RECENT_MESSAGE_SUCCESS "added workout %s on %s\n" + +#define ADD_WORKOUT_MESSAGE_NUM_ATTRS_MISMATCH "invalid number of attributes given\n" +#define ADD_WORKOUT_MESSAGE_INSERT_FAILED "insert failed\n" +#define ADD_WORKOUT_MESSAGE_WORKOUT_ADDED "added workout %s\n" + int add(int,char**); +int add_attribute(int,char**); +int add_recent(int,char**); +int add_workout(int,char**); #endif \ No newline at end of file diff --git a/include/attr.h b/include/attr.h deleted file mode 100644 index 3b51239..0000000 --- a/include/attr.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef __ATTR_H_ -#define __ATTR_H_ - -#include -#include -#include - -#include -#include -#include - -#define ATTR_ADD_STRING "add" -#define ATTR_LS_STRING "ls" -#define ATTR_MESSAGE_WRONG_NO_ARGS "wrong number of arguments for attr add\n" -#define ATTR_MESSAGE_UNKNOWN_COMMAND "unknown command attr \"%s\"\n" -#define ATTR_MESSAGE_ATTR_INSERT_FAILED "attribute insert failed\n" -#define ATTR_MESSAGE_ATTR_ADDED "New attribute added: %s\n" - -int attr(int,char**); -int attr_add(char*); -int attr_ls(); -void print_attr(const unsigned char*); - -#endif \ No newline at end of file diff --git a/include/data.h b/include/data.h index b04a134..fc6efcd 100644 --- a/include/data.h +++ b/include/data.h @@ -20,6 +20,9 @@ #define ATTRIBUTE_COUNT_SQL "SELECT COUNT(*) FROM " ATTRIBUTE_TABLE_NAME_SQL ";" int attribute_count(); +#define ATTRIBUTE_DELETE_SQL "DELETE FROM `" ATTRIBUTE_TABLE_NAME_SQL "` WHERE `name` = ?;" +int attribute_delete(char*); + #define ATTRIBUTE_GET_SQL "SELECT `name` FROM " ATTRIBUTE_TABLE_NAME_SQL " WHERE 1 ORDER BY `order` ASC;" int attribute_get(void (*)(const unsigned char*)); int attribute_index(char*); @@ -39,6 +42,9 @@ int attribute_parse(char*,int*,int*); "FOREIGN KEY(`name`) REFERENCES `workouts`(`name`)" \ ");" +#define RECENT_DELETE_SQL "DELETE FROM `" RECENT_TABLE_NAME_SQL "` WHERE `name` = ? AND `date` = ?;" +int recent_delete(char*,char*); + #define RECENT_GET_SQL "SELECT name, date FROM `" RECENT_TABLE_NAME_SQL "` ORDER BY date(`date`) DESC,`name` ASC LIMIT ?;" int recent_get(int,void(*)(const unsigned char*,const unsigned char*)); @@ -53,6 +59,9 @@ int recent_insert(char*,char*); "`attributes` INT DEFAULT 0" \ ");" +#define WORKOUT_DELETE_SQL "DELETE FROM `" WORKOUT_TABLE_NAME_SQL "` WHERE `name` = ?;" +int workout_delete(char*); + #define WORKOUT_GET_BASE_SQL "SELECT " \ "`" WORKOUT_TABLE_NAME_SQL "`.name, " \ "`" WORKOUT_TABLE_NAME_SQL "`.attributes, " \ diff --git a/include/ls.h b/include/ls.h index a1490b4..e6304d9 100644 --- a/include/ls.h +++ b/include/ls.h @@ -9,7 +9,14 @@ #include #include +#define LS_RECENT_COMMAND_FAILED "command failed\n" + int ls(int,char**); +int ls_attribute(); +int ls_recent(); +int ls_workout(int,char**); +void print_attribute(const unsigned char*); +void print_recent(const unsigned char*,const unsigned char*); void print_header(const unsigned char*); void print_workout(const unsigned char*,int,const unsigned char*); diff --git a/include/main.h b/include/main.h index 30c865a..663fc41 100644 --- a/include/main.h +++ b/include/main.h @@ -6,22 +6,20 @@ #include #include -#include #include #include -#include #include -#include +#include #include #include +#define MAIN_MESSAGE_UNKNOWN_CMD "Unknown cmd: %s\n" + #define UTIL_ADD "add" -#define UTIL_ATTR "attr" #define UTIL_LS "ls" -#define UTIL_NEW "new" #define UTIL_RECENT "recent" +#define UTIL_RM "rm" #define UTIL_TOGGLE "toggle" -#define UTIL_VERSION "version" int main(int,char**); diff --git a/include/new.h b/include/new.h deleted file mode 100644 index 9880eaa..0000000 --- a/include/new.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef __NEW_H_ -#define __NEW_H_ - -#include -#include - -#include -#include -#include - -#define NEW_MESSAGE_NUM_ATTRS_MISMATCH "number of attributes don't match\n" -#define NEW_MESSAGE_INSERT_FAILED "workout insert failed\n" -#define NEW_MESSAGE_WORKOUT_ADDED "New workout added: %s\n" - -int new_workout(int,char**); - -#endif \ No newline at end of file diff --git a/include/opt.h b/include/opt.h index db46dff..b54cf9f 100644 --- a/include/opt.h +++ b/include/opt.h @@ -9,19 +9,28 @@ #include +enum workout_data_type { + WORKOUT_DATA_TYPE_ATTRIBUTE, + WORKOUT_DATA_TYPE_DEFAULT, + WORKOUT_DATA_TYPE_RECENT, + WORKOUT_DATA_TYPE_WORKOUT +}; + // global options struct options { char *db_location; char *homedir; int rows; enum log_level verbose; + enum workout_data_type target; }; extern struct options global_opts; // specific option setters int opt_set_homedir(char*); -void opt_set_rows(int); void opt_set_log_level(enum log_level); +void opt_set_rows(int); +void opt_set_target(enum workout_data_type); #endif \ No newline at end of file diff --git a/include/recent.h b/include/recent.h deleted file mode 100644 index fd99363..0000000 --- a/include/recent.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef __RECENT_H_ -#define __RECENT_H_ - -#include - -#include - -#define RECENT_COMMAND_FAILED "command failed\n" - -void print_recent(const unsigned char*,const unsigned char*); -int recent(); - -#endif \ No newline at end of file diff --git a/include/rm.h b/include/rm.h new file mode 100644 index 0000000..e3ccc6f --- /dev/null +++ b/include/rm.h @@ -0,0 +1,24 @@ +#ifndef __RM_H_ +#define __RM_H_ + +#include +#include + +#define RM_MESSAGE_ATTR_WRONG_NUM_ARGS "wrong number of arguments\n" +#define RM_MESSAGE_ATTR_DELETE_FAILED "attribute_delete() failed\n" +#define RM_MESSAGE_ATTR_DELETED "attribute %s deleted\n" + +#define RM_MESSAGE_RECENT_WRONG_NUM_ARGS "wrong number of arguments\n" +#define RM_MESSAGE_RECENT_DELETE_FAILED "recent_delete() failed\n" +#define RM_MESSAGE_RECENT_DELETED "workout %s on %s deleted\n" + +#define RM_MESSAGE_WORKOUT_WRONG_NUM_ARGS "wrong number of arguments\n" +#define RM_MESSAGE_WORKOUT_DELETE_FAILED "workout_delete() failed\n" +#define RM_MESSAGE_WORKOUT_DELETED "workout %s deleted\n" + +int rm(int,char**); +int rm_attribute(int,char**); +int rm_recent(int,char**); +int rm_workout(int,char**); + +#endif \ No newline at end of file diff --git a/src/add.c b/src/add.c index 636ada6..1d562b9 100644 --- a/src/add.c +++ b/src/add.c @@ -1,13 +1,39 @@ #include int add(int argc, char **argv) { + switch(global_opts.target) { + case WORKOUT_DATA_TYPE_ATTRIBUTE: + return add_attribute(argc,argv); + case WORKOUT_DATA_TYPE_DEFAULT: + case WORKOUT_DATA_TYPE_RECENT: + return add_recent(argc,argv); + case WORKOUT_DATA_TYPE_WORKOUT: + return add_workout(argc,argv); + } +} + +int add_attribute(int argc, char **argv) { + if(argc!=2) { + log_err(ADD_ATTR_MESSAGE_WRONG_NUM_ARGS); + return EXIT_FAILURE; + } + + if(attribute_insert(argv[1])<0) { + log_err(ADD_ATTR_MESSAGE_ATTR_INSERT_FAILED); + return EXIT_FAILURE; + } + + log_msg(ADD_ATTR_MESSAGE_ATTR_ADDED,argv[1]); + return EXIT_SUCCESS; +} + +int add_recent(int argc, char **argv) { if(1==argc) { - log_err("`workouts add` requires at least 1 argument\n"); + log_err(ADD_RECENT_MESSAGE_WRONG_NUM_ARGS); usage(); return EXIT_FAILURE; } - char buf[11]; if(2==argc) { // no date given time_t t = time(NULL); @@ -18,7 +44,7 @@ int add(int argc, char **argv) { struct tm when = {0}; if(sscanf(argv[2],"%d-%d-%d", &YY, &MM, &DD)!=3) { - log_err("invalid date given\n"); + log_err(ADD_RECENT_MESSAGE_INVALID_DATE); return EXIT_FAILURE; } @@ -29,11 +55,44 @@ int add(int argc, char **argv) { } if(recent_insert(argv[1],buf)<0) { - log_err("add failed\n"); + log_err(ADD_RECENT_MESSAGE_INSERT_FAILED); + return EXIT_FAILURE; + } + + log_msg(ADD_RECENT_MESSAGE_SUCCESS,argv[1],buf); + + return EXIT_SUCCESS; +} + +int add_workout(int argc, char **argv) { + if(argc<2) { return EXIT_FAILURE; } + + // check if attribute template provided + unsigned int attr_flags = 0; + if(2=0;j--) { + attr_flags <<= 1; + if(attr_p[j]=='1') { + attr_flags += 1; + } + } + } + + if(workout_insert(argv[1],attr_flags)<0) { + log_err(ADD_WORKOUT_MESSAGE_INSERT_FAILED); return EXIT_FAILURE; } - log_msg("added workout %s on %s\n",argv[1],buf); + log_msg(ADD_WORKOUT_MESSAGE_WORKOUT_ADDED,argv[1]); return EXIT_SUCCESS; } \ No newline at end of file diff --git a/src/attr.c b/src/attr.c deleted file mode 100644 index a5cea7e..0000000 --- a/src/attr.c +++ /dev/null @@ -1,43 +0,0 @@ -#include - -int attr(int argc, char **argv) { - if(1==argc) { return attr_ls(); } - - if(0==strcmp(argv[1],ATTR_ADD_STRING)) { - if(3!=argc) { - log_err(ATTR_MESSAGE_WRONG_NO_ARGS); - usage(); - return EXIT_FAILURE; - } - - return attr_add(argv[2]); - } - - if((2!=argc)||(0!=strcmp(argv[1],ATTR_LS_STRING))) { - log_err(ATTR_MESSAGE_UNKNOWN_COMMAND,argv[1]); - usage(); - return EXIT_FAILURE; - } - - return attr_ls(); -} - -int attr_add(char *name) { - if(attribute_insert(name)<0) { - log_err(ATTR_MESSAGE_ATTR_INSERT_FAILED); - return EXIT_FAILURE; - } - - log_msg(ATTR_MESSAGE_ATTR_ADDED,name); - return EXIT_SUCCESS; -} - -int attr_ls() { - if(attribute_get(&print_attr)<0) { return EXIT_FAILURE; } - - return EXIT_SUCCESS; -} - -void print_attr(const unsigned char *name) { - printf("%s\n",name); -} \ No newline at end of file diff --git a/src/data/attr.c b/src/data/attr.c index daf9636..0a2ac3a 100644 --- a/src/data/attr.c +++ b/src/data/attr.c @@ -26,6 +26,28 @@ int attribute_count() { return -1; } +int attribute_delete(char *name) { + sqlite3 *db_p = NULL; + sqlite3_stmt *stmt_p = NULL; + + if(sqlite3_open_v2(global_opts.db_location,&db_p,SQLITE_OPEN_READWRITE,NULL)!=SQLITE_OK) { goto cleanup; } + + if(sqlite3_prepare_v2(db_p,ATTRIBUTE_DELETE_SQL,-1,&stmt_p,NULL)!=SQLITE_OK) { goto cleanup; } + if(sqlite3_bind_text(stmt_p,1,name,-1,SQLITE_STATIC)!=SQLITE_OK) { goto cleanup; } + + if(sqlite3_step(stmt_p)!=SQLITE_DONE) { goto cleanup; } + if(sqlite3_finalize(stmt_p)!=SQLITE_OK) { goto cleanup; } + stmt_p = NULL; + + if(sqlite3_close_v2(db_p)!=SQLITE_OK) { goto cleanup; } + + return 1; + cleanup: + if(stmt_p!=NULL) { sqlite3_finalize(stmt_p); } + if(db_p!=NULL) { sqlite3_close_v2(db_p); } + return -1; +} + int attribute_get(void (*print)(const unsigned char*)) { sqlite3 *db_p = NULL; sqlite3_stmt *stmt_p = NULL; diff --git a/src/data/recent.c b/src/data/recent.c index 32b0a2a..7cb22b9 100644 --- a/src/data/recent.c +++ b/src/data/recent.c @@ -1,5 +1,28 @@ #include +int recent_delete(char *workout, char *date) { + sqlite3 *db_p = NULL; + sqlite3_stmt *stmt_p = NULL; + + if(sqlite3_open_v2(global_opts.db_location,&db_p,SQLITE_OPEN_READWRITE,NULL)!=SQLITE_OK) { goto cleanup; } + + if(sqlite3_prepare_v2(db_p,RECENT_DELETE_SQL,-1,&stmt_p,NULL)!=SQLITE_OK) { goto cleanup; } + if(sqlite3_bind_text(stmt_p,1,workout,-1,SQLITE_STATIC)!=SQLITE_OK) { goto cleanup; } + if(sqlite3_bind_text(stmt_p,2,date,-1,SQLITE_STATIC)!=SQLITE_OK) { goto cleanup; } + + if(sqlite3_step(stmt_p)!=SQLITE_DONE) { goto cleanup; } + if(sqlite3_finalize(stmt_p)!=SQLITE_OK) { goto cleanup; } + stmt_p = NULL; + + if(sqlite3_close_v2(db_p)!=SQLITE_OK) { goto cleanup; } + + return 1; + cleanup: + if(stmt_p!=NULL) { sqlite3_finalize(stmt_p); } + if(db_p!=NULL) { sqlite3_close_v2(db_p); } + return -1; +} + int recent_get(int limit,void (*f)(const unsigned char*,const unsigned char*)) { sqlite3 *db_p = NULL; sqlite3_stmt *stmt_p = NULL; diff --git a/src/data/workout.c b/src/data/workout.c index a7e3472..5afe980 100644 --- a/src/data/workout.c +++ b/src/data/workout.c @@ -1,5 +1,27 @@ #include +int workout_delete(char *name) { + sqlite3 *db_p = NULL; + sqlite3_stmt *stmt_p = NULL; + + if(sqlite3_open_v2(global_opts.db_location,&db_p,SQLITE_OPEN_READWRITE,NULL)!=SQLITE_OK) { goto cleanup; } + + if(sqlite3_prepare_v2(db_p,WORKOUT_DELETE_SQL,-1,&stmt_p,NULL)!=SQLITE_OK) { goto cleanup; } + if(sqlite3_bind_text(stmt_p,1,name,-1,SQLITE_STATIC)!=SQLITE_OK) { goto cleanup; } + + if(sqlite3_step(stmt_p)!=SQLITE_DONE) { goto cleanup; } + if(sqlite3_finalize(stmt_p)!=SQLITE_OK) { goto cleanup; } + stmt_p = NULL; + + if(sqlite3_close_v2(db_p)!=SQLITE_OK) { goto cleanup; } + + return 1; + cleanup: + if(stmt_p!=NULL) { sqlite3_finalize(stmt_p); } + if(db_p!=NULL) { sqlite3_close_v2(db_p); } + return -1; +} + int workout_get(char *term, char *filter, int limit, void (*print_row)(const unsigned char*,int,const unsigned char*)) { sqlite3 *db_p = NULL; sqlite3_stmt *stmt_p = NULL; diff --git a/src/default.c b/src/default.c index 8bfd754..0469748 100644 --- a/src/default.c +++ b/src/default.c @@ -29,5 +29,7 @@ int defaults() { opt_set_log_level(LOG_LEVEL_DEFAULT); + opt_set_target(WORKOUT_DATA_TYPE_DEFAULT); + return 0; } \ No newline at end of file diff --git a/src/ls.c b/src/ls.c index 06a641a..ecdbc48 100644 --- a/src/ls.c +++ b/src/ls.c @@ -1,5 +1,32 @@ #include +int ls(int argc, char **argv) { + switch(global_opts.target) { + case WORKOUT_DATA_TYPE_ATTRIBUTE: + return ls_attribute(); + case WORKOUT_DATA_TYPE_RECENT: + return ls_recent(); + case WORKOUT_DATA_TYPE_DEFAULT: + case WORKOUT_DATA_TYPE_WORKOUT: + return ls_workout(argc,argv); + } +} + +int ls_attribute() { + if(attribute_get(&print_attribute)<0) { return EXIT_FAILURE; } + + return EXIT_SUCCESS; +} + +int ls_recent() { + if(recent_get(global_opts.rows,&print_recent)<0) { + log_err(LS_RECENT_COMMAND_FAILED); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + struct ls_helper { int i; int attr_count; @@ -15,7 +42,7 @@ static struct option ls_long_options[] = { {0,0,0,0} }; -int ls(int argc, char **argv) { +int ls_workout(int argc, char **argv) { /* * Cases: * -filter by attribute value: workouts --filter 011xx100 @@ -78,6 +105,12 @@ int ls(int argc, char **argv) { return EXIT_SUCCESS; } +#define ATTRIBUTE_PRINT_FORMAT "%s\n" + +void print_attribute(const unsigned char *name) { + printf(ATTRIBUTE_PRINT_FORMAT,name); +} + #define ATTRIBUTE_PRINT_HEADER "Attributes:\t" #define ATTRIBUTE_PRINT_ROW "%s\t" #define ATTRIBUTE_PRINT_END "\n" @@ -93,6 +126,12 @@ void print_header(const unsigned char *name) { } } +#define RECENT_PRINT_FORMAT "%s\t%s\n" + +void print_recent(const unsigned char *workout, const unsigned char *date) { + printf(RECENT_PRINT_FORMAT,workout,date); +} + #define PRINT_WORKOUT_FORMAT "%s [%d] [Last done: %s]\n" #define PRINT_WORKOUT_FORMAT_LAST_NULL "%s [%d] [Last done: N/A]\n" diff --git a/src/main.c b/src/main.c index f182d39..3fa3bd9 100644 --- a/src/main.c +++ b/src/main.c @@ -1,11 +1,15 @@ #include static struct option long_options[] = { + {"attribute", no_argument, 0, 'a'}, + {"attr", no_argument, 0, 'a'}, {"help", no_argument, 0, 'h'}, {"homedir", required_argument, 0, 'd'}, {"quiet", no_argument, &verbose_flag, LOG_LEVEL_SILENT}, + {"recent", no_argument, 0, 'l'}, {"rows", required_argument, 0, 'r'}, {"verbose", no_argument, &verbose_flag, LOG_LEVEL_VERBOSE}, + {"workout", no_argument, 0, 'w'}, {0,0,0,0} }; @@ -20,7 +24,7 @@ int main(int argc, char **argv) { /* The '+' at the beginning of the string means getopt_long will * stop processing after finding the first non-option argument. */ - if((c = getopt_long(argc,argv,"+d:hqr:v",long_options,&option_index))==-1) { break; } + if((c = getopt_long(argc,argv,"+ad:hlqr:vw",long_options,&option_index))==-1) { break; } switch(c) { case 0: @@ -33,10 +37,16 @@ int main(int argc, char **argv) { log_err("\n"); return EXIT_FAILURE; + break; + case 'a': + opt_set_target(WORKOUT_DATA_TYPE_ATTRIBUTE); break; case 'd': if(opt_set_homedir(optarg)<0) { return EXIT_FAILURE; } break; + case 'l': + opt_set_target(WORKOUT_DATA_TYPE_RECENT); + break; case 'h': usage(); return EXIT_FAILURE; @@ -50,6 +60,9 @@ int main(int argc, char **argv) { case 'v': opt_set_log_level(LOG_LEVEL_VERBOSE); break; + case 'w': + opt_set_target(WORKOUT_DATA_TYPE_WORKOUT); + break; case '?': default: return EXIT_FAILURE; @@ -65,18 +78,15 @@ int main(int argc, char **argv) { if(strcmp(cmd,UTIL_ADD)==0) { return add(argc,argv); - } else if(strcmp(cmd,UTIL_ATTR)==0) { - return attr(argc,argv); } else if(strcmp(cmd,UTIL_LS)==0) { return ls(argc,argv); - } else if(strcmp(cmd,UTIL_NEW)==0) { - return new_workout(argc,argv); - } else if(strcmp(cmd,UTIL_RECENT)==0) { - return recent(); + } else if(strcmp(cmd,UTIL_RM)==0) { + return rm(argc,argv); } else if(strcmp(cmd,UTIL_TOGGLE)==0) { return toggle(argc,argv); } else { - log_err("Unknown cmd: %s\n",cmd); + log_err(MAIN_MESSAGE_UNKNOWN_CMD,cmd); + usage(); return EXIT_FAILURE; } } diff --git a/src/new.c b/src/new.c deleted file mode 100644 index f1aad63..0000000 --- a/src/new.c +++ /dev/null @@ -1,34 +0,0 @@ -#include - -int new_workout(int argc, char **argv) { - if(argc<2) { return EXIT_FAILURE; } - - // check if attribute template provided - unsigned int attr_flags = 0; - if(2=0;j--) { - attr_flags <<= 1; - if(attr_p[j]=='1') { - attr_flags += 1; - } - } - } - - if(workout_insert(argv[1],attr_flags)<0) { - log_err(NEW_MESSAGE_INSERT_FAILED); - return EXIT_FAILURE; - } - - log_msg(NEW_MESSAGE_WORKOUT_ADDED,argv[1]); - - return EXIT_SUCCESS; -} \ No newline at end of file diff --git a/src/opt/target.c b/src/opt/target.c new file mode 100644 index 0000000..c525db8 --- /dev/null +++ b/src/opt/target.c @@ -0,0 +1,5 @@ +#include + +void opt_set_target(enum workout_data_type target) { + global_opts.target = target; +} \ No newline at end of file diff --git a/src/recent.c b/src/recent.c deleted file mode 100644 index 2c23adf..0000000 --- a/src/recent.c +++ /dev/null @@ -1,16 +0,0 @@ -#include - -#define RECENT_PRINT_FORMAT "%s\t%s\n" - -void print_recent(const unsigned char *workout, const unsigned char *date) { - printf(RECENT_PRINT_FORMAT,workout,date); -} - -int recent() { - if(recent_get(global_opts.rows,&print_recent)<0) { - log_err(RECENT_COMMAND_FAILED); - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; -} diff --git a/src/rm.c b/src/rm.c new file mode 100644 index 0000000..0f9573e --- /dev/null +++ b/src/rm.c @@ -0,0 +1,61 @@ +#include + +int rm(int argc, char **argv) { + switch(global_opts.target) { + case WORKOUT_DATA_TYPE_ATTRIBUTE: + return rm_attribute(argc,argv); + case WORKOUT_DATA_TYPE_DEFAULT: + case WORKOUT_DATA_TYPE_RECENT: + return rm_recent(argc,argv); + case WORKOUT_DATA_TYPE_WORKOUT: + return rm_workout(argc,argv); + } +} + +int rm_attribute(int argc, char **argv) { + if(argc!=2) { + log_err(RM_MESSAGE_ATTR_WRONG_NUM_ARGS); + return EXIT_FAILURE; + } + + if(attribute_delete(argv[1])<0) { + log_err(RM_MESSAGE_ATTR_DELETE_FAILED); + return EXIT_FAILURE; + } + + log_msg(RM_MESSAGE_ATTR_DELETED,argv[1]); + + return EXIT_SUCCESS; +} + +int rm_recent(int argc, char **argv) { + if(argc!=3) { + log_err(RM_MESSAGE_RECENT_WRONG_NUM_ARGS); + return EXIT_FAILURE; + } + + if(recent_delete(argv[1],argv[2])<0) { + log_err(RM_MESSAGE_RECENT_DELETE_FAILED); + return EXIT_FAILURE; + } + + log_msg(RM_MESSAGE_RECENT_DELETED,argv[1],argv[2]); + + return EXIT_SUCCESS; +} + +int rm_workout(int argc, char **argv) { + if(argc!=2) { + log_err(RM_MESSAGE_WORKOUT_WRONG_NUM_ARGS); + return EXIT_FAILURE; + } + + if(workout_delete(argv[1])<0) { + log_err(RM_MESSAGE_WORKOUT_DELETE_FAILED); + return EXIT_FAILURE; + } + + log_msg(RM_MESSAGE_WORKOUT_DELETED,argv[1]); + + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/src/usage.c b/src/usage.c index 4149c6b..e3d2418 100644 --- a/src/usage.c +++ b/src/usage.c @@ -2,20 +2,20 @@ void usage() { log_err("Usage:\n"); - log_err("\tworkouts [options] [ls] [--filter {attribute filter}] [search term]\n"); - log_err("\tworkouts [options] add [!name] [date]\n"); - log_err("\tworkouts [options] new [!name] [attributes]\n"); - log_err("\tworkouts [options] attr [ls]\n"); - log_err("\tworkouts [options] attr add [!name]\n"); + log_err("\tworkouts [options] add [!name] [date] [attributes]\n"); + log_err("\tworkouts [options] ls [--filter {attribute filter}] [search term]\n"); + log_err("\tworkouts [options] rm [!name] [date]\n"); log_err("\tworkouts [options] toggle [!workout name] [!attr]\n"); - log_err("\tworkouts [options] recent\n"); log_err("\n"); log_err("Options:\n"); + log_err("\t--attribute, --attr, -a\n"); log_err("\t--help, -h\n"); log_err("\t--homedir, -d \n"); log_err("\t--quiet, -q\n"); + log_err("\t--recent, -l\n"); log_err("\t--rows, -r \n"); log_err("\t--verbose, -v\n"); + log_err("\t--workout, -w\n"); log_err("\n"); log_err("{attribute filter} refers to a string of bit flags (0 = not, 1 = has, x = either) corresponding to active attributes.\n"); log_err("Ex: 0100x00\n\n"); diff --git a/test/integration/Makefile.am b/test/integration/Makefile.am index 0f90bd9..401a4b9 100644 --- a/test/integration/Makefile.am +++ b/test/integration/Makefile.am @@ -4,9 +4,6 @@ EXTRA_DIST = \ package.json \ package-lock.json \ test/add.integration.test.js \ - test/attr.integration.test.js \ test/basic.test.js \ test/ls.integration.test.js \ - test/new.integration.test.js \ - test/recent.integration.test.js \ test/toggle.integration.test.js \ No newline at end of file diff --git a/test/integration/test/add.integration.test.js b/test/integration/test/add.integration.test.js index 9f38357..82d6284 100644 --- a/test/integration/test/add.integration.test.js +++ b/test/integration/test/add.integration.test.js @@ -7,70 +7,149 @@ const unlink = util.promisify(require('fs').unlink); describe('add integration tests', () => { beforeEach(async() => { - await assert.doesNotReject(async() => await exec('./workouts attr add lower')); - await assert.doesNotReject(async() => await exec('./workouts attr add upper')); + await assert.doesNotReject(async() => await exec('./workouts --attr add lower')); + await assert.doesNotReject(async() => await exec('./workouts --attr add upper')); - await assert.doesNotReject(async() => await exec('./workouts new workout1 01')); - await assert.doesNotReject(async() => await exec('./workouts new workout2 10')); - await assert.doesNotReject(async() => await exec('./workouts new test 00')); - await assert.doesNotReject(async() => await exec('./workouts new apple 11')); + await assert.doesNotReject(async() => await exec('./workouts --workout add workout1 01')); + await assert.doesNotReject(async() => await exec('./workouts --workout add workout2 10')); + await assert.doesNotReject(async() => await exec('./workouts --workout add test 00')); + await assert.doesNotReject(async() => await exec('./workouts --workout add apple 11')); }); afterEach(async() => { await unlink('workouts.db'); }); - it('should succeed when adding a new workout', async() => { - await assert.doesNotReject(async() => await exec('./workouts add test')); + describe('adding a new attribute', () => { + + const attributes = [ + 'lower_2', + 'upper_2', + 'core', + 'back', + 'cardio', + 'martial', + 'other' + ]; + + it('should successfully add', async() => { + for(const attr of attributes) { + await assert.doesNotReject(async() => { + const {stdout,stderr} = await exec(`./workouts --attr add ${attr}`); + assert.strictEqual(stdout,`attribute ${attr} added\n`); + }); + } + }); + + it('should successfully add with long option', async() => { + for(const attr of attributes) { + await assert.doesNotReject(async() => { + const {stdout,stderr} = await exec(`./workouts --attribute add ${attr}`); + assert.strictEqual(stdout,`attribute ${attr} added\n`); + }); + } + }); + + it('should successfully add with short option', async() => { + for(const attr of attributes) { + await assert.doesNotReject(async() => { + const {stdout,stderr} = await exec(`./workouts -a add ${attr}`); + assert.strictEqual(stdout,`attribute ${attr} added\n`); + }); + } + }); + + it('should fail to add an attribute with the same name', async() => { + await assert.rejects(async() => await exec('./workouts --attr add lower')); + await assert.doesNotReject(async() => await exec('./workouts --attr add Other')); + }); + + it('should fail when not given a name to add', async() => { + await assert.rejects(async() => await exec('./workouts --attr add')); + }); + }); - it('should succeed when adding a new workout and reflect that upon ls', async() => { - await assert.doesNotReject(async() => { - const {stdout,stderr} = await exec('./workouts add workout1 2020-07-10'); + describe('adding a new recent', () => { + + it('should succeed when adding a new workout', async() => { + await assert.doesNotReject(async() => await exec('./workouts --recent add test')); + }); - assert.strictEqual(stdout,`added workout workout1 on 2020-07-10\n`); + it('should succeed when adding a new workout with short option', async() => { + await assert.doesNotReject(async() => await exec('./workouts -l add test')); }); - await assert.doesNotReject(async() => { - const {stdout,stderr} = await exec('./workouts add apple 2020-06-10'); + it('should succeed when adding a new workout and reflect that upon ls', async() => { + await assert.doesNotReject(async() => { + const {stdout,stderr} = await exec('./workouts --recent add workout1 2020-07-10'); + + assert.strictEqual(stdout,`added workout workout1 on 2020-07-10\n`); + }); - assert.strictEqual(stdout,`added workout apple on 2020-06-10\n`); - }); + await assert.doesNotReject(async() => { + const {stdout,stderr} = await exec('./workouts --recent add apple 2020-06-10'); - await assert.doesNotReject(async() => { - const {stdout,stderr} = await exec('./workouts'); + assert.strictEqual(stdout,`added workout apple on 2020-06-10\n`); + }); - let expected = `Attributes:\tlower\tupper\t\n`; - expected += `workout1 [2] [Last done: 2020-07-10]\n`; - expected += `apple [3] [Last done: 2020-06-10]\n`; - expected += `test [0] [Last done: N/A]\n`; - expected += `workout2 [1] [Last done: N/A]\n`; + await assert.doesNotReject(async() => { + const {stdout,stderr} = await exec('./workouts'); - assert.strictEqual(stdout,expected); + let expected = `Attributes:\tlower\tupper\t\n`; + expected += `workout1 [2] [Last done: 2020-07-10]\n`; + expected += `apple [3] [Last done: 2020-06-10]\n`; + expected += `test [0] [Last done: N/A]\n`; + expected += `workout2 [1] [Last done: N/A]\n`; + + assert.strictEqual(stdout,expected); + }); }); - }); - it('should successfully get last done', async() => { - await assert.doesNotReject(async() => await exec('./workouts add workout1 2020-07-10')); - await assert.doesNotReject(async() => await exec('./workouts add workout1 2020-06-10')); + it('should successfully get last done', async() => { + await assert.doesNotReject(async() => await exec('./workouts --recent add workout1 2020-07-10')); + await assert.doesNotReject(async() => await exec('./workouts --recent add workout1 2020-06-10')); - await assert.doesNotReject(async() => { - const {stdout,stderr} = await exec('./workouts ls workout1'); + await assert.doesNotReject(async() => { + const {stdout,stderr} = await exec('./workouts --workout ls workout1'); - let expected = `Attributes:\tlower\tupper\t\n`; - expected += `workout1 [2] [Last done: 2020-07-10]\n`; + let expected = `Attributes:\tlower\tupper\t\n`; + expected += `workout1 [2] [Last done: 2020-07-10]\n`; - assert.strictEqual(stdout,expected); + assert.strictEqual(stdout,expected); + }); + }); + + it('should reject when not given a valid workout', async() => { + await assert.rejects(async() => await exec('./workouts --recent add hahahahahah 2020-07-10')); + }); + + it('should reject when not given a valid date', async() => { + await assert.rejects(async() => await exec('./workouts --recent add hahahahahah 2020-07-10123123123123123')); + await assert.rejects(async() => await exec('./workouts --recent add hahahahahah "kasdflasj lkssdasdf lkdaNOT_A_DATE"')); }); - }); - it('should reject when not given a valid workout', async() => { - await assert.rejects(async() => await exec('./workouts add hahahahahah 2020-07-10')); }); - it('should reject when not given a valid date', async() => { - await assert.rejects(async() => await exec('./workouts add hahahahahah 2020-07-10123123123123123')); - await assert.rejects(async() => await exec('./workouts add hahahahahah "kasdflasj lkssdasdf lkdaNOT_A_DATE"')); + describe('adding a new workout', () => { + it('should success creating a new workout', async() => { + await assert.doesNotReject(async() => { + const {stdout,stderr} = await exec('./workouts --workout add workout11'); + assert.strictEqual(stdout,`added workout workout11\n`); + }); + }); + + it('should success creating a new workout with short option', async() => { + await assert.doesNotReject(async() => { + const {stdout,stderr} = await exec('./workouts -w add workout11'); + assert.strictEqual(stdout,`added workout workout11\n`); + }); + }); + + it('should fail to create a workout when given the wrong number of attributes', async() => { + await assert.rejects(async() => await exec('./workouts --workout add workout12 0')); + await assert.rejects(async() => await exec('./workouts --workout add workout13 110')); + }); }); }); \ No newline at end of file diff --git a/test/integration/test/attr.integration.test.js b/test/integration/test/attr.integration.test.js deleted file mode 100644 index f76b406..0000000 --- a/test/integration/test/attr.integration.test.js +++ /dev/null @@ -1,75 +0,0 @@ -const assert = require('assert'); -const util = require('util'); - -const exec = util.promisify(require('child_process').exec); -const unlink = util.promisify(require('fs').unlink); - -describe('attr integration tests', () => { - - const attributes = [ - 'lower', - 'upper', - 'core', - 'back', - 'cardio', - 'martial', - 'other' - ]; - - describe('attr add', () => { - - it('should successfully add', async() => { - for(const attr of attributes) { - await assert.doesNotReject(async() => { - const {stdout,stderr} = await exec(`./workouts attr add ${attr}`); - - assert.strictEqual(stdout,`New attribute added: ${attr}\n`); - }); - } - }); - - it('should fail to add an attribute with the same name', async() => { - await assert.rejects(async() => await exec('./workouts attr add other')); - await assert.doesNotReject(async() => await exec('./workouts attr add Other')); - }); - - it('should fail when not given a name to add', async() => { - await assert.rejects(async() => await exec('./workouts attr add')); - }); - - }); - - describe('attr ls', () => { - - it('should successfully list all attributes in order they were added', async() => { - attributes.push('Other'); - - await assert.doesNotReject(async() => { - const {stdout,stderr} = await exec(`./workouts attr`); - - let expected = ""; - for(const attr of attributes) { - expected += `${attr}\n`; - } - - assert.strictEqual(stdout,expected); - }); - - await assert.doesNotReject(async() => { - const {stdout,stderr} = await exec(`./workouts attr ls`); - let expected = ""; - for(const attr of attributes) { - expected += `${attr}\n`; - } - - assert.strictEqual(stdout,expected); - }); - }); - - }); - - after(async() => { - await unlink('workouts.db'); - }); - -}); \ No newline at end of file diff --git a/test/integration/test/basic.test.js b/test/integration/test/basic.test.js index c286dcf..6906b1f 100644 --- a/test/integration/test/basic.test.js +++ b/test/integration/test/basic.test.js @@ -15,20 +15,20 @@ describe('basic tests', () => { it('should print usage options when run with --help option', async() => { let usage = `Usage:\n`; - usage += `\tworkouts [options] [ls] [--filter {attribute filter}] [search term]\n`; - usage += `\tworkouts [options] add [!name] [date]\n`; - usage += `\tworkouts [options] new [!name] [attributes]\n`; - usage += `\tworkouts [options] attr [ls]\n`; - usage += `\tworkouts [options] attr add [!name]\n`; + usage += `\tworkouts [options] add [!name] [date] [attributes]\n`; + usage += `\tworkouts [options] ls [--filter {attribute filter}] [search term]\n`; + usage += `\tworkouts [options] rm [!name] [date]\n`; usage += `\tworkouts [options] toggle [!workout name] [!attr]\n`; - usage += `\tworkouts [options] recent\n`; usage += `\n`; usage += `Options:\n`; + usage += `\t--attribute, --attr, -a\n`; usage += `\t--help, -h\n`; usage += `\t--homedir, -d \n`; usage += `\t--quiet, -q\n`; + usage += `\t--recent, -l\n`; usage += `\t--rows, -r \n`; usage += `\t--verbose, -v\n`; + usage += `\t--workout, -w\n`; usage += `\n`; usage += `{attribute filter} refers to a string of bit flags (0 = not, 1 = has, x = either) corresponding to active attributes.\n`; usage += `Ex: 0100x00\n\n` diff --git a/test/integration/test/ls.integration.test.js b/test/integration/test/ls.integration.test.js index 773093e..312671e 100644 --- a/test/integration/test/ls.integration.test.js +++ b/test/integration/test/ls.integration.test.js @@ -6,99 +6,146 @@ const unlink = util.promisify(require('fs').unlink); describe('ls integration tests', () => { + const recent = [ + {name:"workout1",date:"2020-07-10"}, + {name:"apple",date:"2020-07-09"}, + {name:"test",date:"2020-07-09"}, + {name:"workout2",date:"2020-07-09"} + ]; + beforeEach(async() => { - await assert.doesNotReject(async() => await exec('./workouts attr add lower')); - await assert.doesNotReject(async() => await exec('./workouts attr add upper')); + await assert.doesNotReject(async() => await exec('./workouts --attr add lower')); + await assert.doesNotReject(async() => await exec('./workouts --attr add upper')); + + await assert.doesNotReject(async() => await exec('./workouts --workout add workout1 01')); + await assert.doesNotReject(async() => await exec('./workouts --workout add workout2 10')); + await assert.doesNotReject(async() => await exec('./workouts --workout add test 00')); + await assert.doesNotReject(async() => await exec('./workouts --workout add apple 11')); - await assert.doesNotReject(async() => await exec('./workouts new workout1 01')); - await assert.doesNotReject(async() => await exec('./workouts new workout2 10')); - await assert.doesNotReject(async() => await exec('./workouts new test 00')); - await assert.doesNotReject(async() => await exec('./workouts new apple 11')); + for(const i of recent) { + await assert.doesNotReject(async() => await exec(`./workouts --recent add ${i.name} ${i.date}`)); + } }); afterEach(async() => { await unlink('workouts.db'); }); - it('should succeed when no workouts are present', async() => { - await assert.doesNotReject(async() => { - const {stdout,stderr} = await exec('./workouts'); + describe('ls_attribute', () => { + it('should successfully list all attributes in order they were added', async() => { + const attributes = ["lower","upper"]; - let expected = `Attributes:\tlower\tupper\t\n`; - expected += `apple [3] [Last done: N/A]\n`; - expected += `test [0] [Last done: N/A]\n`; - expected += `workout1 [2] [Last done: N/A]\n`; - expected += `workout2 [1] [Last done: N/A]\n`; + await assert.doesNotReject(async() => { + const {stdout,stderr} = await exec(`./workouts --attr ls`); - assert.strictEqual(stdout,expected); + let expected = ""; + for(const attr of attributes) { + expected += `${attr}\n`; + } + + assert.strictEqual(stdout,expected); + }); }); }); - it('should successfully limit rows grabbed', async() => { - await assert.doesNotReject(async() => { - const {stdout,stderr} = await exec('./workouts --rows=1 ls'); + describe('ls_recent', () => { + + it('should successfully print recent workouts', async() => { + const {stdout,stderr} = await exec('./workouts --recent ls'); + + let expected = ""; + for(const i of recent) { + expected += `${i.name}\t${i.date}\n`; + } - let expected = `Attributes:\tlower\tupper\t\n`; - expected += `apple [3] [Last done: N/A]\n`; assert.strictEqual(stdout,expected); }); + }); - it('should successfully search for workouts', async() => { - await assert.doesNotReject(async() => { - const {stdout,stderr} = await exec('./workouts ls workout'); + describe('ls_workouts', () => { + + it('should succeed when no workouts are present', async() => { + await assert.doesNotReject(async() => { + const {stdout,stderr} = await exec('./workouts'); - let expected = `Attributes:\tlower\tupper\t\n`; - expected += `workout1 [2] [Last done: N/A]\n`; - expected += `workout2 [1] [Last done: N/A]\n`; + let expected = `Attributes:\tlower\tupper\t\n`; + expected += `workout1 [2] [Last done: 2020-07-10]\n`; + expected += `apple [3] [Last done: 2020-07-09]\n`; + expected += `test [0] [Last done: 2020-07-09]\n`; + expected += `workout2 [1] [Last done: 2020-07-09]\n`; - assert.strictEqual(stdout,expected); + assert.strictEqual(stdout,expected); + }); }); - }); - it('should reject when `ls` term is not given and attempting to filter', async() => { - await assert.rejects(async() => { - await exec('./workouts --filter 01'); + it('should successfully limit rows grabbed', async() => { + await assert.doesNotReject(async() => { + const {stdout,stderr} = await exec('./workouts --rows=1 ls'); + + let expected = `Attributes:\tlower\tupper\t\n`; + expected += `workout1 [2] [Last done: 2020-07-10]\n`; + assert.strictEqual(stdout,expected); + }); }); - }); - it('should successfully filter workouts by attribute', async() => { - await assert.doesNotReject(async() => { - const {stdout,stderr} = await exec('./workouts ls --filter 01'); + it('should successfully search for workouts', async() => { + await assert.doesNotReject(async() => { + const {stdout,stderr} = await exec('./workouts ls workout'); - let expected = `Attributes:\tlower\tupper\t\n`; - expected += `workout2 [1] [Last done: N/A]\n`; + let expected = `Attributes:\tlower\tupper\t\n`; + expected += `workout1 [2] [Last done: 2020-07-10]\n`; + expected += `workout2 [1] [Last done: 2020-07-09]\n`; - assert.strictEqual(stdout,expected); + assert.strictEqual(stdout,expected); + }); }); - await assert.doesNotReject(async() => { - const {stdout,stderr} = await exec('./workouts ls --filter 10'); + it('should reject when `ls` term is not given and attempting to filter', async() => { + await assert.rejects(async() => { + await exec('./workouts --filter 01'); + }); + }); + + it('should successfully filter workouts by attribute', async() => { + await assert.doesNotReject(async() => { + const {stdout,stderr} = await exec('./workouts ls --filter 01'); - let expected = `Attributes:\tlower\tupper\t\n`; - expected += `workout1 [2] [Last done: N/A]\n`; + let expected = `Attributes:\tlower\tupper\t\n`; + expected += `workout2 [1] [Last done: 2020-07-09]\n`; - assert.strictEqual(stdout,expected); - }); + assert.strictEqual(stdout,expected); + }); - await assert.doesNotReject(async() => { - const {stdout,stderr} = await exec('./workouts ls --filter x1'); + await assert.doesNotReject(async() => { + const {stdout,stderr} = await exec('./workouts ls --filter 10'); - let expected = `Attributes:\tlower\tupper\t\n`; - expected += `apple [3] [Last done: N/A]\n`; - expected += `workout2 [1] [Last done: N/A]\n`; + let expected = `Attributes:\tlower\tupper\t\n`; + expected += `workout1 [2] [Last done: 2020-07-10]\n`; - assert.strictEqual(stdout,expected); - }); + assert.strictEqual(stdout,expected); + }); - await assert.doesNotReject(async() => { - const {stdout,stderr} = await exec('./workouts ls --filter 00'); + await assert.doesNotReject(async() => { + const {stdout,stderr} = await exec('./workouts ls --filter x1'); - let expected = `Attributes:\tlower\tupper\t\n`; - expected += `test [0] [Last done: N/A]\n`; + let expected = `Attributes:\tlower\tupper\t\n`; + expected += `apple [3] [Last done: 2020-07-09]\n`; + expected += `workout2 [1] [Last done: 2020-07-09]\n`; - assert.strictEqual(stdout,expected); + assert.strictEqual(stdout,expected); + }); + + await assert.doesNotReject(async() => { + const {stdout,stderr} = await exec('./workouts ls --filter 00'); + + let expected = `Attributes:\tlower\tupper\t\n`; + expected += `test [0] [Last done: 2020-07-09]\n`; + + assert.strictEqual(stdout,expected); + }); }); + }); }); \ No newline at end of file diff --git a/test/integration/test/new.integration.test.js b/test/integration/test/new.integration.test.js deleted file mode 100644 index 88fb120..0000000 --- a/test/integration/test/new.integration.test.js +++ /dev/null @@ -1,34 +0,0 @@ -const assert = require('assert'); -const util = require('util'); - -const exec = util.promisify(require('child_process').exec); -const unlink = util.promisify(require('fs').unlink); - -describe('new integration tests', () => { - - beforeEach(async() => { - await assert.doesNotReject(async() => await exec('./workouts attr add lower')); - await assert.doesNotReject(async() => await exec('./workouts attr add upper')); - }); - - afterEach(async() => { - await unlink('workouts.db'); - }); - - it('should success creating a new workout', async() => { - await assert.doesNotReject(async() => { - const {stdout,stderr} = await exec('./workouts new workout1'); - - assert.strictEqual(stdout,`New workout added: workout1\n`); - }); - }); - - it('should fail to create a workout when given the wrong number of attributes', async() => { - await assert.rejects(async() => { - const res = await exec('./workouts new workout1 0'); - console.log(res); - }); - await assert.rejects(async() => await exec('./workouts new workout1 110')); - }); - -}); \ No newline at end of file diff --git a/test/integration/test/recent.integration.test.js b/test/integration/test/recent.integration.test.js deleted file mode 100644 index c178093..0000000 --- a/test/integration/test/recent.integration.test.js +++ /dev/null @@ -1,45 +0,0 @@ -const assert = require('assert'); -const util = require('util'); - -const exec = util.promisify(require('child_process').exec); -const unlink = util.promisify(require('fs').unlink); - -describe('recent integration tests', () => { - - const recent = [ - {name:"workout1",date:"2020-07-10"}, - {name:"apple",date:"2020-07-09"}, - {name:"test",date:"2020-07-09"}, - {name:"workout2",date:"2020-07-09"} - ]; - - beforeEach(async() => { - await assert.doesNotReject(async() => await exec('./workouts attr add lower')); - await assert.doesNotReject(async() => await exec('./workouts attr add upper')); - - await assert.doesNotReject(async() => await exec('./workouts new workout1 01')); - await assert.doesNotReject(async() => await exec('./workouts new workout2 10')); - await assert.doesNotReject(async() => await exec('./workouts new test 00')); - await assert.doesNotReject(async() => await exec('./workouts new apple 11')); - - for(const i of recent) { - await assert.doesNotReject(async() => await exec(`./workouts add ${i.name} ${i.date}`)); - } - }); - - afterEach(async() => { - await unlink('workouts.db'); - }); - - it('should successfully print recent workouts', async() => { - const {stdout,stderr} = await exec('./workouts recent'); - - let expected = ""; - for(const i of recent) { - expected += `${i.name}\t${i.date}\n`; - } - - assert.strictEqual(stdout,expected); - }); - -}); \ No newline at end of file diff --git a/test/integration/test/toggle.integration.test.js b/test/integration/test/toggle.integration.test.js index e6affab..a5cae1c 100644 --- a/test/integration/test/toggle.integration.test.js +++ b/test/integration/test/toggle.integration.test.js @@ -7,13 +7,13 @@ const unlink = util.promisify(require('fs').unlink); describe('toggle integration tests', () => { beforeEach(async() => { - await assert.doesNotReject(async() => await exec('./workouts attr add lower')); - await assert.doesNotReject(async() => await exec('./workouts attr add upper')); + await assert.doesNotReject(async() => await exec('./workouts --attr add lower')); + await assert.doesNotReject(async() => await exec('./workouts --attr add upper')); - await assert.doesNotReject(async() => await exec('./workouts new workout1 01')); - await assert.doesNotReject(async() => await exec('./workouts new workout2 10')); - await assert.doesNotReject(async() => await exec('./workouts new test 00')); - await assert.doesNotReject(async() => await exec('./workouts new apple 11')); + await assert.doesNotReject(async() => await exec('./workouts --workout add workout1 01')); + await assert.doesNotReject(async() => await exec('./workouts --workout add workout2 10')); + await assert.doesNotReject(async() => await exec('./workouts --workout add test 00')); + await assert.doesNotReject(async() => await exec('./workouts --workout add apple 11')); }); afterEach(async() => { diff --git a/test/unit/Makefile.am b/test/unit/Makefile.am index 84d1af8..40bfe5b 100644 --- a/test/unit/Makefile.am +++ b/test/unit/Makefile.am @@ -7,16 +7,13 @@ AM_CPPFLAGS = \ EXTRA_DIST = \ test_utils.h \ add.tests.h \ - attr.tests.h \ data.attr.tests.h \ data.recent.tests.h \ data.workout.tests.h \ ls.tests.h \ - new.tests.h \ - recent.tests.h \ toggle.tests.h -check_PROGRAMS = add.tests attr.tests data.attr.tests data.recent.tests data.workout.tests ls.tests new.tests recent.tests toggle.tests +check_PROGRAMS = add.tests data.attr.tests data.recent.tests data.workout.tests ls.tests toggle.tests TESTS = $(check_PROGRAMS) if ENABLE_MEMCHECK @@ -30,7 +27,7 @@ TEST_SRC_DIR = $(top_srcdir)/src common_SOURCES += $(TEST_SRC_DIR)/default.c $(TEST_SRC_DIR)/log.c common_SOURCES += $(TEST_SRC_DIR)/data/setup.c -common_SOURCES += $(TEST_SRC_DIR)/opt/homedir.c $(TEST_SRC_DIR)/opt/loglvl.c $(TEST_SRC_DIR)/opt/rows.c +common_SOURCES += $(TEST_SRC_DIR)/opt/homedir.c $(TEST_SRC_DIR)/opt/loglvl.c $(TEST_SRC_DIR)/opt/rows.c $(TEST_SRC_DIR)/opt/target.c add_tests_SOURCES = \ $(common_SOURCES) \ @@ -41,13 +38,6 @@ add_tests_SOURCES = \ $(TEST_SRC_DIR)/data/workout.c \ $(TEST_SRC_DIR)/usage.c -attr_tests_SOURCES = \ - $(common_SOURCES) \ - attr.tests.c \ - $(TEST_SRC_DIR)/attr.c \ - $(TEST_SRC_DIR)/data/attr.c \ - $(TEST_SRC_DIR)/usage.c - data_attr_tests_SOURCES = \ $(common_SOURCES) \ data.attr.tests.c \ @@ -71,24 +61,11 @@ ls_tests_SOURCES = \ $(common_SOURCES) \ ls.tests.c \ $(TEST_SRC_DIR)/data/attr.c \ + $(TEST_SRC_DIR)/data/recent.c \ $(TEST_SRC_DIR)/data/workout.c \ $(TEST_SRC_DIR)/ls.c \ $(TEST_SRC_DIR)/usage.c -new_tests_SOURCES = \ - $(common_SOURCES) \ - new.tests.c \ - $(TEST_SRC_DIR)/data/attr.c \ - $(TEST_SRC_DIR)/data/workout.c \ - $(TEST_SRC_DIR)/new.c \ - $(TEST_SRC_DIR)/usage.c - -recent_tests_SOURCES = \ - $(common_SOURCES) \ - recent.tests.c \ - $(TEST_SRC_DIR)/data/recent.c \ - $(TEST_SRC_DIR)/recent.c - toggle_tests_SOURCES = \ $(common_SOURCES) \ toggle.tests.c \ diff --git a/test/unit/add.tests.c b/test/unit/add.tests.c index 0c8bedc..ed1cb59 100644 --- a/test/unit/add.tests.c +++ b/test/unit/add.tests.c @@ -3,14 +3,34 @@ int main() { setup_env(); - add_basic_test(); + add_attribute_basic_test(); + add_recent_basic_test(); + add_workout_basic_test(); clean(); return EXIT_SUCCESS; } -void add_basic_test() { +void add_attribute_basic_test() { + global_opts.target = WORKOUT_DATA_TYPE_ATTRIBUTE; + + char *argv[] = { + "add", + "alsdkfjalksdfj", + NULL + }; + + assert(EXIT_FAILURE==add(1,argv)); + assert(EXIT_SUCCESS==add(2,argv)); + assert(EXIT_FAILURE==add(2,argv)); + + reset_env(); +} + +void add_recent_basic_test() { + global_opts.target = WORKOUT_DATA_TYPE_RECENT; + char *bad_argv[] = { "add", "testworkout1notindb", @@ -36,5 +56,38 @@ void add_basic_test() { assert(EXIT_FAILURE==add(2,bad_argv)); assert(EXIT_FAILURE==add(3,bad_argv)); + reset_env(); +} + +void add_workout_basic_test() { + global_opts.target = WORKOUT_DATA_TYPE_WORKOUT; + + assert(attribute_insert("test")==1); + assert(attribute_insert("test2")==1); + assert(attribute_insert("test3")==1); + assert(attribute_insert("test4")==1); + assert(attribute_insert("test5")==1); + assert(attribute_insert("test6")==1); + + char *argv[] = { + "add", + "testworkout", + "000012", + NULL + }; + + assert(EXIT_FAILURE==add(1,argv)); + assert(EXIT_SUCCESS==add(2,argv)); + assert(EXIT_FAILURE==add(3,argv)); + + argv[1] = "testworkout2"; + + assert(EXIT_SUCCESS==add(3,argv)); + + argv[1] = "testworkout3"; + argv[2] = "000"; + + assert(EXIT_FAILURE==add(3,argv)); + reset_env(); } \ No newline at end of file diff --git a/test/unit/add.tests.h b/test/unit/add.tests.h index 13cfe79..d05a403 100644 --- a/test/unit/add.tests.h +++ b/test/unit/add.tests.h @@ -6,6 +6,8 @@ #include int main(); -void add_basic_test(); +void add_attribute_basic_test(); +void add_recent_basic_test(); +void add_workout_basic_test(); #endif \ No newline at end of file diff --git a/test/unit/attr.tests.c b/test/unit/attr.tests.c deleted file mode 100644 index a6f46cb..0000000 --- a/test/unit/attr.tests.c +++ /dev/null @@ -1,46 +0,0 @@ -#include - -int main() { - setup_env(); - - attr_basic_test(); - - clean(); - - return EXIT_SUCCESS; -} - -void attr_basic_test() { - char *argv[] = { - "attr", - "add", - "alsdkfjalksdfj", - NULL - }; - - char *ls_argv[] = { - "attr", - "ls", - NULL - }; - - char *bad_argv[] = { - "attr", - "hahaha", - "asdfoiasdf", - NULL - }; - - assert(EXIT_SUCCESS==attr(1,ls_argv)); - assert(EXIT_SUCCESS==attr(2,ls_argv)); - - assert(EXIT_SUCCESS==attr(1,bad_argv)); - assert(EXIT_FAILURE==attr(2,bad_argv)); - assert(EXIT_FAILURE==attr(3,bad_argv)); - - assert(EXIT_SUCCESS==attr(1,argv)); - assert(EXIT_FAILURE==attr(2,argv)); - assert(EXIT_SUCCESS==attr(3,argv)); - - reset_env(); -} \ No newline at end of file diff --git a/test/unit/attr.tests.h b/test/unit/attr.tests.h deleted file mode 100644 index f12cde3..0000000 --- a/test/unit/attr.tests.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __ATTR_TESTS_H_ -#define __ATTR_TESTS_H_ - -#include - -#include - -int main(); -void attr_basic_test(); - -#endif \ No newline at end of file diff --git a/test/unit/data.attr.tests.c b/test/unit/data.attr.tests.c index 4953dd7..08d86ee 100644 --- a/test/unit/data.attr.tests.c +++ b/test/unit/data.attr.tests.c @@ -4,6 +4,7 @@ int main() { setup_env(); attribute_count_test(); + attribute_delete_test(); attribute_get_test(); attribute_index_test(); attribute_insert_test(); @@ -28,6 +29,24 @@ void attribute_count_test() { int i; +void attribute_delete_test() { + i = 0; + assert(attribute_get(&attribute_get_test_helper)==1); + assert(i==0); + + assert(attribute_insert("test")==1); + assert(attribute_get(&attribute_get_test_helper)==1); + assert(i==1); + + assert(attribute_delete("test")==1); + + i = 0; + assert(attribute_get(&attribute_get_test_helper)==1); + assert(i==0); + + reset_env(); +} + void attribute_get_test() { i = 0; assert(attribute_get(&attribute_get_test_helper)==1); diff --git a/test/unit/data.attr.tests.h b/test/unit/data.attr.tests.h index ee0abac..17de639 100644 --- a/test/unit/data.attr.tests.h +++ b/test/unit/data.attr.tests.h @@ -5,6 +5,7 @@ int main(); void attribute_count_test(); +void attribute_delete_test(); void attribute_get_test(); void attribute_get_test_helper(const unsigned char*); void attribute_index_test(); diff --git a/test/unit/data.recent.tests.c b/test/unit/data.recent.tests.c index c9fc484..3475148 100644 --- a/test/unit/data.recent.tests.c +++ b/test/unit/data.recent.tests.c @@ -3,6 +3,7 @@ int main() { setup_env(); + recent_delete_test(); recent_get_test(); recent_insert_test(); @@ -13,6 +14,24 @@ int main() { int i; +void recent_delete_test() { + assert(workout_insert("test",0)==1); + assert(recent_insert("test","2020-10-12")==1); + + i = 0; + assert(recent_get(-1,&recent_get_test_helper)==1); + assert(i==1); + + assert(recent_delete("test","2020-10-12")==1); + + i = 0; + assert(recent_get(-1,&recent_get_test_helper)==1); + assert(i==0); + + reset_env(); +} + + void recent_get_test() { i = 0; assert(recent_get(-1,&recent_get_test_helper)==1); diff --git a/test/unit/data.recent.tests.h b/test/unit/data.recent.tests.h index ffb2f70..41347b5 100644 --- a/test/unit/data.recent.tests.h +++ b/test/unit/data.recent.tests.h @@ -4,6 +4,7 @@ #include int main(); +void recent_delete_test(); void recent_get_test(); void recent_get_test_helper(const unsigned char*,const unsigned char*); void recent_insert_test(); diff --git a/test/unit/data.workout.tests.c b/test/unit/data.workout.tests.c index 62f93fa..692b4c8 100644 --- a/test/unit/data.workout.tests.c +++ b/test/unit/data.workout.tests.c @@ -3,6 +3,7 @@ int main() { setup_env(); + workout_delete_test(); workout_get_test(); workout_insert_test(); workout_toggle_test(); @@ -15,6 +16,26 @@ int main() { int i; +void workout_delete_test() { + i = 0; + assert(workout_get(NULL,NULL,-1,&workout_get_test_helper)==1); + assert(i==0); + + assert(workout_insert("test",0)==1); + + i = 0; + assert(workout_get(NULL,NULL,-1,&workout_get_test_helper)==1); + assert(i==1); + + assert(workout_delete("test")==1); + + i = 0; + assert(workout_get(NULL,NULL,-1,&workout_get_test_helper)==1); + assert(i==0); + + reset_env(); +} + void workout_get_test() { i = 0; diff --git a/test/unit/data.workout.tests.h b/test/unit/data.workout.tests.h index 267ba68..ec9aad3 100644 --- a/test/unit/data.workout.tests.h +++ b/test/unit/data.workout.tests.h @@ -4,6 +4,7 @@ #include int main(); +void workout_delete_test(); void workout_get_test(); void workout_get_test_helper(); void workout_insert_test(); diff --git a/test/unit/ls.tests.c b/test/unit/ls.tests.c index c4c86f2..0ed081f 100644 --- a/test/unit/ls.tests.c +++ b/test/unit/ls.tests.c @@ -3,14 +3,26 @@ int main() { setup_env(); - ls_basic_test(); + ls_attribute_basic_test(); + ls_recent_basic_test(); + ls_workout_basic_test(); clean(); return EXIT_SUCCESS; } -void ls_basic_test() { +void ls_attribute_basic_test() { + assert(EXIT_SUCCESS==ls_attribute()); +} + +void ls_recent_basic_test() { + assert(EXIT_SUCCESS==ls_recent()); +} + +void ls_workout_basic_test() { + global_opts.target = WORKOUT_DATA_TYPE_WORKOUT; + char *bad_opt[] = { "ls", "-b", diff --git a/test/unit/ls.tests.h b/test/unit/ls.tests.h index 6c416fe..529c5b5 100644 --- a/test/unit/ls.tests.h +++ b/test/unit/ls.tests.h @@ -6,6 +6,8 @@ #include int main(); -void ls_basic_test(); +void ls_attribute_basic_test(); +void ls_recent_basic_test(); +void ls_workout_basic_test(); #endif \ No newline at end of file diff --git a/test/unit/new.tests.c b/test/unit/new.tests.c deleted file mode 100644 index 69a5f67..0000000 --- a/test/unit/new.tests.c +++ /dev/null @@ -1,42 +0,0 @@ -#include - -int main() { - setup_env(); - - new_basic_test(); - - clean(); - - return EXIT_SUCCESS; -} - -void new_basic_test() { - char *bad[] = { - "new", - "testworkout", - "012001", - NULL - }; - - assert(attribute_insert("test")==1); - assert(attribute_insert("test2")==1); - assert(attribute_insert("test3")==1); - assert(attribute_insert("test4")==1); - assert(attribute_insert("test5")==1); - assert(attribute_insert("test6")==1); - - assert(EXIT_FAILURE==new_workout(1,bad)); - assert(EXIT_SUCCESS==new_workout(2,bad)); - assert(EXIT_FAILURE==new_workout(3,bad)); - - char *argv[] = { - "new", - "test workout", - "010001", - NULL - }; - - assert(EXIT_SUCCESS==new_workout(3,argv)); - - reset_env(); -} \ No newline at end of file diff --git a/test/unit/new.tests.h b/test/unit/new.tests.h deleted file mode 100644 index e276ac8..0000000 --- a/test/unit/new.tests.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __NEW_TESTS_H_ -#define __NEW_TESTS_H_ - -#include - -#include - -int main(); -void new_basic_test(); - -#endif \ No newline at end of file diff --git a/test/unit/recent.tests.c b/test/unit/recent.tests.c deleted file mode 100644 index b651811..0000000 --- a/test/unit/recent.tests.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -int main() { - setup_env(); - - recent_basic_test(); - - clean(); - - return EXIT_SUCCESS; -} - -void recent_basic_test() { - assert(EXIT_SUCCESS==recent()); -} \ No newline at end of file diff --git a/test/unit/recent.tests.h b/test/unit/recent.tests.h deleted file mode 100644 index 031ba8a..0000000 --- a/test/unit/recent.tests.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __RECENT_TESTS_H_ -#define __RECENT_TESTS_H_ - -#include - -#include - -int main(); -void recent_basic_test(); - -#endif \ No newline at end of file -- 2.30.2