src/opt/until.c \
src/postpone.c \
src/prune.c \
+ src/recur.c \
src/rm.c \
src/seek.c \
- src/usage.c
+ src/usage.c \
+ src/validate.c
ev_SOURCES += \
inc/add.h \
inc/opt.h \
inc/postpone.h \
inc/prune.h \
+ inc/recur.h \
inc/rm.h \
inc/seek.h \
- inc/usage.h
+ inc/usage.h \
+ inc/validate.h
man_MANS = man/ev.1
_ev() {
IFS=$'\n'
COMPREPLY=()
- local commands=$'add\ndismiss\nls\npostpone\nprune\nrm'
+ local commands=$'add\ndismiss\nls\npostpone\nprune\nrm\nvalidate'
declare -A options
options[--all]="--all"
echo "$rmformat"
COMPREPLY=()
;;
+ validate) ;;
ev)
COMPREPLY=($(compgen -W "${commands}" -- "$2"))
COMPREPLY+=($(compgen -W "${opts}" -- "$2"))
COMPREPLY=()
;;
esac
-} >> /tmp/ev.output
+}
complete -F _ev ev
# Checks for libraries.
# Checks for header files.
-AC_CHECK_HEADERS([limits.h stdlib.h string.h unistd.h])
+AC_CHECK_HEADERS([limits.h stdlib.h string.h time.h unistd.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_SIZE_T
SUB_COMMAND_LS,
SUB_COMMAND_POSTPONE,
SUB_COMMAND_PRUNE,
- SUB_COMMAND_RM
+ SUB_COMMAND_RM,
+ SUB_COMMAND_VALIDATE
};
int args(int,char**);
int event_place_set(struct event*, const char*);
int event_serialize(char*, size_t, const struct event*);
int event_time_compare(const struct tm*,time_t);
+int event_time_date_only(const struct tm*);
int event_time_set(struct tm*, const char*);
int event_within(struct event*, struct event_filter*);
#include<postpone.h>
#include<prune.h>
#include<rm.h>
+#include<validate.h>
int main(int,char**);
#include<stdlib.h>
#include<file.h>
+#include<recur.h>
#include<seek.h>
int prune();
--- /dev/null
+#ifndef __RECUR_H_
+#define __RECUR_H_
+
+#include<event.h>
+
+int recur(struct event*);
+
+#endif
#include<cut.h>
#include<event.h>
#include<file.h>
+#include<recur.h>
#define RM_FLAG_DISMISS 1
--- /dev/null
+#ifndef __VALIDATE_H_
+#define __VALIDATE_H_
+
+#include<stdio.h>
+#include<string.h>
+
+#include<file.h>
+
+int validate();
+
+#endif
-.TH EV "1" "2022 September 13" "v0.0.0" "Events"
+.TH EV "1" "2022 September 13" "v1.0.0" "Events"
.SH NAME
ev \- human readable events organizer
.B prune
.IP \(bu
.B rm
+.IP \(bu
+.B validate
.SH OPTIONS
.TP
.B
ev postpone 0
+.TP
+validate events file format
+.B
+ev validate
+
.SH "SEE ALSO"
.BR git (1)
if(strcmp(argv[optind],"postpone")==0) { return SUB_COMMAND_POSTPONE; }
if(strcmp(argv[optind],"prune")==0) { return SUB_COMMAND_PRUNE; }
if(strcmp(argv[optind],"rm")==0) { return SUB_COMMAND_RM; }
+ if(strcmp(argv[optind],"validate")==0) { return SUB_COMMAND_VALIDATE; }
goto fail;
fail:
token = normal;
}
+ if(strlen(buf)<1) { return -1; }
+
p = strtok(buf,token);
if(p!=NULL) {
if(event_name_set(ev,p)<0) { return -1; }
if(event_time_set(&(ev->datetime),buf)<0) { return -1; }
- memmove(buf,p,(buf_size - (p - buf)));
+ if((buf_size - (p - buf))>0) {
+ memmove(buf,p,(buf_size - (p - buf)));
+ } else {
+ buf[0] = '\0';
+ }
return 1;
}
}
static int event_serialize_time(char *buf, size_t buf_size, const struct tm *datetime) {
- size_t len;
+ size_t len, i;
assert(buf!=NULL);
len = strlen(buf);
- if(datetime->tm_sec==0 && datetime->tm_min==0 && datetime->tm_hour == 0) {
+ if(event_time_date_only(datetime)>0) {
if(0==strftime(
&(buf[len]), /* char *s */
buf_size - len, /* size_t max */
datetime /* const struct tm *tm */
)) { return -1; }
} else {
- if(0==strftime(
+ long offset = datetime->__tm_gmtoff;
+
+ i = strftime(
&(buf[len]), /* char *s */
buf_size - len, /* size_t max */
- "%Y-%m-%d %H:%M:%S %z", /* const char *format */
+ "%Y-%m-%d %H:%M:%S ", /* const char *format */
datetime /* const struct tm *tm */
- )) { return -1; }
+ );
+ if(i==0) { return -1; }
+
+ len += i;
+ if(snprintf(&(buf[len]),buf_size - len,"%+.2li%.2li", offset/3600, offset%60)<0) { return -1; }
}
return 1;
return 0;
}
+int event_time_date_only(const struct tm *date) {
+ if((*date).tm_sec != 0) { return -1; }
+ if((*date).tm_min != 0) { return -1; }
+ if((*date).tm_hour != 0) { return -1; }
+ return 1;
+}
+
int event_time_set(struct tm *datetime, const char *str) {
const char *p;
-
- p = str;
+
+ /* this call is necessary here to guarantee
+ * that extern int daylight is set correctly.
+ * see man tzset.
+ */
+ //tzset();
memset(datetime, 0, sizeof(struct tm));
+ datetime->tm_isdst = -1;
/* minimum expected date format */
- p = strptime(p,"%Y-%m-%d",datetime);
- if(NULL==p) { return -1; }
-
- /* attempt to get time information */
- p = strptime(p,"%H:%M:%S",datetime);
+ p = strptime(str,"%Y-%m-%d %H:%M:%S %z",datetime);
+ if(p!=NULL) { return 1; }
- /* attempt to get timezone information */
+ p = strptime(str,"%Y-%m-%d %H:%M:%S",datetime);
if(p!=NULL) {
- strptime(p,"%z",datetime);
+ if(mktime(datetime)<0) { return -1; }
+ return 1;
}
+ p = strptime(str,"%Y-%m-%d",datetime);
+ if(NULL==p) { return -1; }
+
return 1;
}
}
static int event_print(struct event *ev) {
+ char datebuf[20];
+ time_t timestamp;
+ struct tm *local;
+ long offset;
+
assert(ev!=NULL);
if(NULL==ev->name) { return -1; }
- char datebuf[20];
- if(
- (ev->datetime.tm_sec==0) &&
- (ev->datetime.tm_min == 0) &&
- (ev->datetime.tm_hour == 0)
- ) {
+ if(event_time_date_only(&(ev->datetime))>0) {
if(strftime(datebuf,20,"%Y-%m-%d",&(ev->datetime))!=10) { return -1; }
} else {
- if(strftime(datebuf,20,"%Y-%m-%d %H:%M:%S",&(ev->datetime))!=19) { return -1; }
+ offset = ev->datetime.tm_gmtoff;
+ timestamp = timegm(&(ev->datetime)) - offset;
+ if(timestamp<0) { return -1; }
+
+ local = localtime(×tamp);
+ if(NULL==local) { return -1; }
+
+ if(strftime(datebuf,20,"%Y-%m-%d %H:%M:%S",local)!=19) { return -1; }
}
if(fprintf(stdout,"%-20s\t",datebuf)<0) { return -1; }
return prune();
case SUB_COMMAND_RM:
return rm(argc,argv,0);
+ case SUB_COMMAND_VALIDATE:
+ return validate();
default:
return EXIT_FAILURE;
}
#include<prune.h>
+static int copy_recur_events(FILE*,FILE*);
+
+static int copy_recur_events(FILE *src, FILE *to) {
+ char buf[EVENT_SERIALIZE_MAX_LENGTH];
+ struct event ev;
+ time_t now;
+ ssize_t i;
+
+ now = time(NULL);
+
+ memset(buf,0,EVENT_SERIALIZE_MAX_LENGTH);
+ while((i = file_line_next(buf,EVENT_SERIALIZE_MAX_LENGTH,src))>0) {
+ if(event_parse(buf,EVENT_SERIALIZE_MAX_LENGTH,&ev)<0) { return -1; }
+
+ if(event_time_compare(&(ev.datetime),now)>0) {
+ event_free(&ev);
+ if(fseek(src,-i,SEEK_CUR)!=0) { return -1; }
+ break;
+ }
+
+ switch(recur(&ev)) {
+ case -1:
+ event_free(&ev);
+ return -1;
+ case 1:
+ if(event_serialize(buf,EVENT_SERIALIZE_MAX_LENGTH,&ev)<0) { return -1; }
+ if(fwrite(buf,1,i,to)!=i) { return -1; }
+ break;
+ default:
+ event_free(&ev);
+ memset(buf,0,EVENT_SERIALIZE_MAX_LENGTH);
+ break;
+ }
+ }
+
+ return 1;
+}
+
int prune() {
FILE *src, *to;
src = file_open();
if(NULL==src) { return EXIT_FAILURE; }
- if(seek(src,time(NULL))<0) { return EXIT_FAILURE; }
-
+ if(copy_recur_events(src,to)<0) { return EXIT_FAILURE; }
+
if(file_pipe(to,src)<0) { return EXIT_FAILURE; }
if(fclose(src)!=0) { return EXIT_FAILURE; }
--- /dev/null
+#include<recur.h>
+
+int recur(struct event *ev) {
+ time_t compare;
+ struct tm tm;
+
+ if(ev->options.recur==0) { return 0; }
+
+ memcpy(&tm,&(ev->datetime),sizeof(struct tm));
+
+ switch(ev->options.recur_period) {
+ case TIME_PERIOD_YEAR:
+ tm.tm_year += ev->options.recur;
+ break;
+ case TIME_PERIOD_MONTH:
+ tm.tm_mon += ev->options.recur;
+ break;
+ case TIME_PERIOD_WEEK:
+ tm.tm_mday += 7*(ev->options.recur);
+ break;
+ case TIME_PERIOD_DAY:
+ tm.tm_mday += ev->options.recur;
+ break;
+ case TIME_PERIOD_HOUR:
+ tm.tm_hour += ev->options.recur;
+ break;
+ case TIME_PERIOD_MINUTE:
+ tm.tm_min += ev->options.recur;
+ break;
+ case TIME_PERIOD_SECOND:
+ tm.tm_sec += ev->options.recur;
+ break;
+ default:
+ return -1;
+ }
+
+ tm.tm_isdst = -1;
+ compare = mktime(&tm);
+ if(compare<0) { return -1; }
+
+ ev->datetime.tm_year = tm.tm_year;
+ ev->datetime.tm_mon = tm.tm_mon;
+ ev->datetime.tm_mday = tm.tm_mday;
+ ev->datetime.tm_hour = tm.tm_hour;
+ ev->datetime.tm_min = tm.tm_min;
+ ev->datetime.tm_sec = tm.tm_sec;
+ ev->datetime.tm_wday = tm.tm_wday;
+
+ if(event_time_compare(&(ev->options.until),0)>0) {
+ if(event_time_compare(&(ev->options.until),compare)<0) { return 0; }
+ }
+
+ return 1;
+}
static int check_need_readd(struct event *ev) {
char buf[EVENT_SERIALIZE_MAX_LENGTH];
char timebuf[40];
- struct tm tm;
assert(ev!=NULL);
- if(ev->options.recur==0) { return 1; }
-
-
- switch(ev->options.recur_period) {
- case TIME_PERIOD_YEAR:
- ev->datetime.tm_year += ev->options.recur;
- break;
- case TIME_PERIOD_MONTH:
- ev->datetime.tm_mon += ev->options.recur;
- break;
- case TIME_PERIOD_WEEK:
- ev->datetime.tm_mday += 7*(ev->options.recur);
- break;
- case TIME_PERIOD_DAY:
- ev->datetime.tm_mday += ev->options.recur;
- break;
- case TIME_PERIOD_HOUR:
- ev->datetime.tm_hour += ev->options.recur;
- break;
- case TIME_PERIOD_MINUTE:
- ev->datetime.tm_min += ev->options.recur;
- break;
- case TIME_PERIOD_SECOND:
- ev->datetime.tm_sec += ev->options.recur;
- break;
- default:
+ switch(recur(ev)) {
+ case -1:
return -1;
- }
-
- memcpy(&tm,&(ev->datetime),sizeof(struct tm));
- if(event_time_compare(&(ev->options.until),0)>0) {
- if(event_time_compare(&(ev->options.until),mktime(&tm))<0) { return 1; }
+ case 0:
+ return 1;
+ default:
+ break;
}
strftime(timebuf,40,"%a, %d %b %Y %T %z",&(ev->datetime));
--- /dev/null
+#include<validate.h>
+
+int validate() {
+ char buf[EVENT_SERIALIZE_MAX_LENGTH];
+ struct event ev;
+ FILE *src;
+ ssize_t i;
+ size_t line;
+
+ src = file_open();
+ if(NULL==src) { return EXIT_FAILURE; }
+
+ line = 1;
+ memset(buf,0,EVENT_SERIALIZE_MAX_LENGTH);
+ while((i = file_line_next(buf,EVENT_SERIALIZE_MAX_LENGTH,src))>0) {
+ if(event_parse(buf,EVENT_SERIALIZE_MAX_LENGTH,&ev)<0) {
+ fprintf(stderr,"invalid event: event on line %lu failed to parse\n",line);
+ return EXIT_FAILURE;
+ }
+
+ event_free(&ev);
+ memset(buf,0,EVENT_SERIALIZE_MAX_LENGTH);
+
+ line++;
+ }
+
+ if(i<0) {
+ if(ferror(src)!=0) {
+ fprintf(stderr,"failed to get line");
+ return EXIT_FAILURE;
+ }
+ }
+
+ fprintf(stdout,"%s: \x1B[32mVALID\x1B[0m\n",global_options.file);
+
+ return EXIT_SUCCESS;
+}
test_macros.h \
test_utils.h
-check_PROGRAMS = add.tests args.tests copy.tests cut.tests event.tests file.tests ls.tests opt.tests postpone.tests prune.tests rm.tests seek.tests usage.tests
+check_PROGRAMS = add.tests args.tests copy.tests cut.tests event.tests file.tests ls.tests opt.tests postpone.tests prune.tests recur.tests rm.tests seek.tests usage.tests validate.tests
TESTS = $(check_PROGRAMS)
if ENABLE_MEMCHECK
$(event_SOURCES) \
ls.tests.c \
$(top_srcdir)/src/file/line.c \
- $(top_srcdir)/src/file/open.c
+ $(top_srcdir)/src/file/open.c \
+ $(top_srcdir)/src/file/tmp.c
ls_tests_CPPFLAGS = $(AM_CPPFLAGS) \
-DLS_SRC_FILE="$(top_srcdir)/src/ls.c"
$(top_srcdir)/src/file/pipe.c \
$(top_srcdir)/src/file/tmp.c \
$(top_srcdir)/src/prune.c \
+ $(top_srcdir)/src/recur.c \
$(top_srcdir)/src/seek.c
+recur_tests_SOURCES = \
+ $(common_SOURCES) \
+ $(event_SOURCES) \
+ recur.tests.c \
+ $(top_srcdir)/src/recur.c
+
rm_tests_SOURCES = \
$(common_SOURCES) \
$(event_SOURCES) \
$(top_srcdir)/src/file/pipe.c \
$(top_srcdir)/src/file/tmp.c \
$(top_srcdir)/src/opt/filter.c \
+ $(top_srcdir)/src/recur.c \
$(top_srcdir)/src/usage.c
rm_tests_CPPFLAGS = $(AM_CPPFLAGS) \
usage_tests_CPPFLAGS = $(AM_CPPFLAGS) \
-DARGS_SRC_FILE="$(top_srcdir)/src/args.c" \
-DUSAGE_SRC_FILE="$(top_srcdir)/src/usage.c"
+
+validate_tests_SOURCES = \
+ $(common_SOURCES) \
+ $(event_SOURCES) \
+ validate.tests.c \
+ $(top_srcdir)/src/file/open.c \
+ $(top_srcdir)/src/file/line.c \
+ $(top_srcdir)/src/validate.c
assert(1==add_time_set(&ev,"2022-09-01"));
- assert(mktime(&(ev.datetime))==1662019200);
+ assert(mktime(&(ev.datetime))==1662015600);
}
static void add_to_file_basic_test() {
memset(buf,0,1000);
assert(fread(buf,1,1000,fp)==73);
- assert(strcmp(buf,"2022-06-01 20:00:00 +0000:event3:place\n2022-08-01:name\n2022-09-01:event2\n")==0);
+ assert(strcmp(buf,"2022-06-01 20:00:00 -0700:event3:place\n2022-08-01:name\n2022-09-01:event2\n")==0);
assert(fclose(fp)==0);
static void args_prune_basic_test();
static void args_rm_basic_test();
static void args_short_opts_basic_test();
+static void args_validate_basic_test();
int main() {
setup_env();
args_postpone_basic_test();
args_prune_basic_test();
args_rm_basic_test();
+ args_validate_basic_test();
args_short_opts_basic_test();
args_long_opts_basic_test();
};
assert(SUB_COMMAND_LS==args(4,ls_end_date_short_args));
assert(global_options.event_filter.start==0);
- assert(global_options.event_filter.end==1114934400);
+ assert(global_options.event_filter.end==1114930800);
optind = 0;
reset_env();
reset_env();
}
+
+static void args_validate_basic_test() {
+ char *validate_args[] = {
+ "ev",
+ "validate",
+ NULL
+ };
+
+ assert(SUB_COMMAND_VALIDATE==args(2,validate_args));
+
+ reset_env();
+}
static void event_init_basic_test();
static void event_name_set_basic_test();
static void event_parse_basic_test();
+static void event_parse_missing_name_test();
static void event_place_set_basic_test();
static void event_serialize_basic_test();
static void event_serialize_parse_exactness_test();
event_time_compare_basic_test();
event_name_set_basic_test();
event_parse_basic_test();
+ event_parse_missing_name_test();
event_place_set_basic_test();
event_serialize_basic_test();
event_serialize_parse_exactness_test();
time_unset(&(ev1.options.until));
assert(strcmp(ev1.name,"test event")==0);
assert(strcmp(ev1.place,"test place")==0);
- assert(mktime(&(ev1.datetime))==1662019200);
+ assert(mktime(&(ev1.datetime))==1662015600);
event_init(&ev2);
char ex2[] = "2022-09-02:\"test: event2\":\"test: place2\"";
time_unset(&(ev2.options.until));
assert(strcmp(ev2.name,"test: event2")==0);
assert(strcmp(ev2.place,"test: place2")==0);
- assert(mktime(&(ev2.datetime))==1662105600);
+ assert(mktime(&(ev2.datetime))==1662102000);
event_init(&ev3);
char ex3[] = "2022-09-03 09:30:00:test event3:test place3";
time_unset(&(ev3.options.until));
assert(strcmp(ev3.name,"test event3")==0);
assert(strcmp(ev3.place,"test place3")==0);
- assert(mktime(&(ev3.datetime))==1662226200);
+ assert(mktime(&(ev3.datetime))==1662222600);
event_init(&ev4);
char ex4[] = "2022-09-04 09:30:00 -0700:test event4:test place4";
time_unset(&(ev4.options.until));
assert(strcmp(ev4.name,"test event4")==0);
assert(strcmp(ev4.place,"test place4")==0);
- assert(mktime(&(ev4.datetime))==1662312600);
+ assert(mktime(&(ev4.datetime))==1662309000);
event_init(&ev5);
char ex5[] = "[recur:1M]2022-08-04:test event5:test place5";
time_unset(&(ev5.options.until));
assert(strcmp(ev5.name,"test event5")==0);
assert(strcmp(ev5.place,"test place5")==0);
- assert(mktime(&(ev5.datetime))==1659600000);
+ assert(mktime(&(ev5.datetime))==1659596400);
event_init(&ev6);
char ex6[] = "[recur:1W]2022-06-05 09:30:00 -0700:test event6:test place6";
time_unset(&(ev6.options.until));
assert(strcmp(ev6.name,"test event6")==0);
assert(strcmp(ev6.place,"test place6")==0);
- assert(mktime(&(ev6.datetime))==1654450200);
+ assert(mktime(&(ev6.datetime))==1654446600);
event_init(&ev7);
char ex7[] = "[recur:1W,until:2022-11-01]2022-10-01 09:30:00 -0700:test event7:test place7";
assert(event_parse(ex7,sizeof(ex7),&ev7)==1);
assert(ev7.options.recur==1);
assert(ev7.options.recur_period==TIME_PERIOD_WEEK);
- assert(mktime(&(ev7.options.until))==1667289600);
+ assert(mktime(&(ev7.options.until))==1667286000);
assert(strcmp(ev7.name,"test event7")==0);
assert(strcmp(ev7.place,"test place7")==0);
- assert(mktime(&(ev7.datetime))==1664645400);
+ assert(mktime(&(ev7.datetime))==1664641800);
event_init(&ev8);
char ex8[] = "[until:2022-10-10,recur:1W]2022-10-01 09:30:00 -0700:test event8:test place8";
assert(event_parse(ex8,sizeof(ex8),&ev8)==1);
assert(ev8.options.recur==1);
assert(ev8.options.recur_period==TIME_PERIOD_WEEK);
- assert(mktime(&(ev8.options.until))==1665388800);
+ assert(mktime(&(ev8.options.until))==1665385200);
assert(strcmp(ev8.name,"test event8")==0);
assert(strcmp(ev8.place,"test place8")==0);
- assert(mktime(&(ev8.datetime))==1664645400);
+ assert(mktime(&(ev8.datetime))==1664641800);
event_init(&ev9);
char ex9[] = "2022-08-01:test";
time_unset(&(ev9.options.until));
assert(strcmp(ev9.name,"test")==0);
assert(NULL==ev9.place);
- assert(mktime(&(ev9.datetime))==1659340800);
+ assert(mktime(&(ev9.datetime))==1659337200);
event_free(&ev1);
event_free(&ev2);
event_free(&ev9);
}
+static void event_parse_missing_name_test() {
+ struct event ev;
+
+ event_init(&ev);
+ char ex[] = "2022-08-01";
+ assert(event_parse(ex,sizeof(ex),&ev)==-1);
+
+ event_free(&ev);
+}
+
static void event_place_set_basic_test() {
struct event ev;
assert(strcmp(buf,"2022-07-01 08:01:15 -0100:event:place\n")==0);
event_init(&ev);
- assert(1==event_time_set(&(ev.datetime),"2022-07-01 08:01:15 -0100"));
+ assert(1==event_time_set(&(ev.datetime),"2022-07-01 08:01:15 -0700"));
assert(1==event_name_set(&ev,"event: what?"));
assert(1==event_place_set(&ev,"place: here"));
assert(1==event_serialize(buf,EVENT_SERIALIZE_MAX_LENGTH,&ev));
- assert(strcmp(buf,"2022-07-01 08:01:15 -0100:\"event: what?\":\"place: here\"\n")==0);
+ assert(strcmp(buf,"2022-07-01 08:01:15 -0700:\"event: what?\":\"place: here\"\n")==0);
+
+ event_init(&ev);
+ assert(1==event_time_set(&(ev.datetime),"2022-07-01 08:01:15 +2300"));
+ assert(1==event_name_set(&ev,"event: what?"));
+ assert(1==event_place_set(&ev,"place: here"));
+ assert(1==event_serialize(buf,EVENT_SERIALIZE_MAX_LENGTH,&ev));
+ assert(strcmp(buf,"2022-07-01 08:01:15 +2300:\"event: what?\":\"place: here\"\n")==0);
event_init(&ev);
assert(1==event_time_set(&(ev.datetime),"2022-06-21"));
char timebuf[40];
struct event ev;
time_t timet;
- struct tm *now, got;
+ struct tm *now;
event_init(&ev);
assert(strftime(timebuf,40,"%Y-%m-%d %H:%M:%S %z",now)==25);
assert(1==event_time_set(&(ev.datetime),timebuf));
- /* daylight savings time set here for some reason.
- * resetting timet to be time set in ev...
- */
- memcpy(&got,&(ev.datetime),sizeof(struct tm));
- timet = mktime(&got);
+ timet = mktime(&(ev.datetime));
timet -= 1000;
assert(1==event_time_compare(&(ev.datetime),timet));
assert(ev.datetime.tm_year==99);
assert(ev.datetime.tm_wday==0);
assert(ev.datetime.tm_yday==58);
- assert(ev.datetime.tm_isdst==0);
- assert(ev.datetime.tm_gmtoff==0);
assert(1==event_time_set(&(ev.datetime),"1997-01-28 not a time"));
assert(ev.datetime.tm_sec==0);
assert(ev.datetime.tm_year==97);
assert(ev.datetime.tm_wday==2);
assert(ev.datetime.tm_yday==27);
- assert(ev.datetime.tm_isdst==0);
- assert(ev.datetime.tm_gmtoff==0);
assert(1==event_time_set(&(ev.datetime),"2002-05-24 121212"));
assert(ev.datetime.tm_sec==0);
assert(ev.datetime.tm_year==102);
assert(ev.datetime.tm_wday==5);
assert(ev.datetime.tm_yday==143);
- assert(ev.datetime.tm_isdst==0);
- assert(ev.datetime.tm_gmtoff==0);
assert(1==event_time_set(&(ev.datetime),"2012-12-22 12:1212"));
assert(ev.datetime.tm_sec==0);
assert(ev.datetime.tm_year==112);
assert(ev.datetime.tm_wday==6);
assert(ev.datetime.tm_yday==356);
- assert(ev.datetime.tm_isdst==0);
- assert(ev.datetime.tm_gmtoff==0);
assert(1==event_time_set(&(ev.datetime),"2022-01-24 09:19:55"));
assert(ev.datetime.tm_sec==55);
assert(ev.datetime.tm_year==122);
assert(ev.datetime.tm_wday==1);
assert(ev.datetime.tm_yday==23);
- assert(ev.datetime.tm_isdst==0);
- assert(ev.datetime.tm_gmtoff==0);
assert(1==event_time_set(&(ev.datetime),"2009-01-03 13:25:25 -0800"));
assert(ev.datetime.tm_sec==25);
assert(ev.datetime.tm_year==109);
assert(ev.datetime.tm_wday==6);
assert(ev.datetime.tm_yday==2);
- assert(ev.datetime.tm_isdst==0);
assert(ev.datetime.tm_gmtoff==-28800);
+
+ assert(1==event_time_set(&(ev.datetime),"2008-02-07 04:25:16 -0300"));
+ assert(ev.datetime.tm_sec==16);
+ assert(ev.datetime.tm_min==25);
+ assert(ev.datetime.tm_hour==4);
+ assert(ev.datetime.tm_mday==7);
+ assert(ev.datetime.tm_mon==1);
+ assert(ev.datetime.tm_year==108);
+ assert(ev.datetime.tm_wday==4);
+ assert(ev.datetime.tm_yday==37);
+ assert(ev.datetime.tm_gmtoff==-10800);
}
static void time_unset(struct tm *tm) {
int main();
static void event_print_basic_test();
+static void event_print_timezone_test();
int main() {
event_print_basic_test();
+ event_print_timezone_test();
return EXIT_SUCCESS;
}
event_free(&ev);
}
+
+static void event_print_timezone_test() {
+ struct event ev;
+ char buf[200];
+ FILE *fp;
+
+ char tempfile[] = "/tmp/XXXXXX";
+ fp = file_temp(tempfile);
+ assert(fp!=NULL);
+ assert(fclose(fp)==0);
+
+ fp = NULL;
+
+ event_init(&ev);
+
+ assert(1==event_name_set(&ev,"correct timezone"));
+ assert(1==event_time_set(&(ev.datetime),"2022-07-01 09:39:34"));
+
+ fp = freopen(tempfile,"w",stdout);
+ assert(fp!=NULL);
+
+ assert(1==event_print(&ev));
+
+ event_free(&ev);
+ event_init(&ev);
+
+ assert(1==event_name_set(&ev,"timezone test"));
+ assert(1==event_time_set(&(ev.datetime),"2022-08-01 20:30:15 -0300"));
+
+ assert(1==event_print(&ev));
+ event_free(&ev);
+
+ assert(fclose(fp)==0);
+
+ memset(buf,0,200);
+
+ fp = NULL;
+ fp = fopen(tempfile,"r");
+ assert(fp!=NULL);
+
+ assert(fread(buf,1,200,fp)==111);
+ assert(memcmp(buf,"2022-07-01 09:39:34 \tcorrect timezone \x1B[31m[OVERDUE]\x1B[0m\n2022-08-01 16:30:15 \ttimezone test \x1B[31m[OVERDUE]\x1B[0m\n",111)==0);
+
+ assert(fclose(fp)==0);
+ assert(remove(tempfile)==0);
+}
assert(global_options.event_filter.start==1230969600);
assert(1==opt_event_filter_date_set(&(global_options.event_filter.end),"2022-08-22"));
- assert(global_options.event_filter.end==1661155200);
+ assert(global_options.event_filter.end==1661151600);
reset_env();
}
assert(handle_args(4,args_with_date,&offset,&start_time)==1);
assert(offset==1);
- assert(start_time==1585123200);
+ assert(start_time==1585119600);
char *args_with_date_and_postpone[] = {
"ev",
assert(handle_args(5,args_with_date_and_postpone,&offset,&start_time)==1);
assert(offset==2);
- assert(start_time==1585123200);
+ assert(start_time==1585119600);
assert(strcmp(postpone_offset_string,"2W")==0);
int main();
static void prune_basic_test();
+static void prune_recur_test();
int main() {
setup_env();
prune_basic_test();
+ prune_recur_test();
clean_env();
reset_env();
}
+
+static void prune_recur_test() {
+ char buf[EVENT_SERIALIZE_MAX_LENGTH];
+ char got[EVENT_SERIALIZE_MAX_LENGTH];
+ char timebuf[40];
+ struct tm curr, *now;
+ time_t now_timet;
+ FILE *src;
+
+ now_timet = time(NULL);
+ now = localtime(&now_timet);
+
+ src = fopen(global_options.file,"w");
+ assert(src!=NULL);
+
+ memset(buf,0,EVENT_SERIALIZE_MAX_LENGTH);
+ memset(timebuf,0,40);
+
+ memcpy(&curr,now,sizeof(struct tm));
+ curr.tm_year -= 1;
+
+ assert(strftime(timebuf,20,"%Y-%m-%d",&curr)==10);
+ for(size_t i=0;i<10;i++) {
+ memset(buf,0,EVENT_SERIALIZE_MAX_LENGTH);
+ snprintf(buf,EVENT_SERIALIZE_MAX_LENGTH,"[recur:2Y]%s:test%lu\n",timebuf,i);
+
+ assert(fwrite(buf,1,strlen(buf),src)==27);
+ }
+
+ curr.tm_year += 2;
+ assert(strftime(timebuf,20,"%Y-%m-%d",&curr)==10);
+
+ assert(fclose(src)==0);
+
+ assert(prune()==EXIT_SUCCESS);
+
+ src = fopen(global_options.file,"r");
+ assert(src!=NULL);
+
+ assert(fread(got,1,EVENT_SERIALIZE_MAX_LENGTH,src)==270);
+
+ memset(buf,0,EVENT_SERIALIZE_MAX_LENGTH);
+ sprintf(buf,"[recur:2Y]%s:test0\n[recur:2Y]%s:test1\n[recur:2Y]%s:test2\n[recur:2Y]%s:test3\n[recur:2Y]%s:test4\n[recur:2Y]%s:test5\n[recur:2Y]%s:test6\n[recur:2Y]%s:test7\n[recur:2Y]%s:test8\n[recur:2Y]%s:test9\n",timebuf,timebuf,timebuf,timebuf,timebuf,timebuf,timebuf,timebuf,timebuf,timebuf);
+ assert(memcmp(got,buf,170)==0);
+
+ assert(fclose(src)==0);
+
+ reset_env();
+}
--- /dev/null
+#include<test_utils.h>
+
+#include<recur.h>
+
+int main();
+static void recur_basic_test();
+
+int main() {
+ setup_env();
+
+ recur_basic_test();
+
+ clean_env();
+
+ return EXIT_SUCCESS;
+}
+
+static void recur_basic_test() {
+ struct event ev;
+ struct tm *target;
+ time_t target_timet;
+
+ event_init(&ev);
+
+ assert(event_name_set(&ev,"test event")==1);
+ assert(event_time_set(&(ev.datetime),"2020-05-13")==1);
+
+ assert(recur(&ev)==0);
+
+ ev.options.recur = 1;
+ ev.options.recur_period = -1;
+ assert(recur(&ev)==-1);
+
+ ev.options.recur_period = TIME_PERIOD_MONTH;
+ target_timet = 1585850345; // ~2020-04-02
+ target = localtime(&target_timet);
+ memcpy(&(ev.options.until),target,sizeof(struct tm));
+
+ assert(recur(&ev)==0);
+
+ memset(&(ev.options.until),0,sizeof(struct tm));
+ assert(recur(&ev)==1);
+
+ assert(1594623600==mktime(&(ev.datetime)));
+
+ event_free(&ev);
+
+ reset_env();
+}
int main();
static void check_need_readd_basic_test();
+static void check_need_readd_month_boundary_test();
static void check_need_readd_until_test();
+static void check_need_readd_year_boundary_test();
static void handle_args_basic_test();
static void rm_basic_test();
static void rm_dismiss_basic_test();
rm_basic_test();
check_need_readd_basic_test();
+ check_need_readd_month_boundary_test();
check_need_readd_until_test();
+ check_need_readd_year_boundary_test();
rm_dismiss_basic_test();
clean_env();
reset_env();
}
+static void check_need_readd_month_boundary_test() {
+ char buf[EVENT_SERIALIZE_MAX_LENGTH];
+ struct event ev;
+ FILE *src;
+
+ event_init(&ev);
+
+ src = fopen(global_options.file,"w");
+ assert(src!=NULL);
+
+ assert(event_name_set(&ev,"test month boundary")==1);
+ assert(event_time_set(&(ev.datetime),"2021-01-30")==1);
+
+ ev.options.recur = 1;
+ ev.options.recur_period = TIME_PERIOD_WEEK;
+
+ assert(1==check_need_readd(&ev));
+
+ src = fopen(global_options.file,"r");
+ assert(src!=NULL);
+
+ memset(buf,0,EVENT_SERIALIZE_MAX_LENGTH);
+ assert(fread(buf,1,EVENT_SERIALIZE_MAX_LENGTH,src)==41);
+ assert(memcmp(buf,"[recur:1W]2021-02-06:test month boundary\n",41)==0);
+
+ assert(fclose(src)==0);
+
+ reset_env();
+}
+
static void check_need_readd_until_test() {
char buf[EVENT_SERIALIZE_MAX_LENGTH];
struct event ev;
reset_env();
}
+static void check_need_readd_year_boundary_test() {
+ char buf[EVENT_SERIALIZE_MAX_LENGTH];
+ struct event ev;
+ FILE *src;
+
+ event_init(&ev);
+
+ src = fopen(global_options.file,"w");
+ assert(src!=NULL);
+
+ assert(event_name_set(&ev,"test year boundary")==1);
+ assert(event_time_set(&(ev.datetime),"2019-01-15")==1);
+
+ ev.options.recur = 1;
+ ev.options.recur_period = TIME_PERIOD_YEAR;
+
+ assert(1==check_need_readd(&ev));
+
+ src = fopen(global_options.file,"r");
+ assert(src!=NULL);
+
+ memset(buf,0,EVENT_SERIALIZE_MAX_LENGTH);
+ assert(fread(buf,1,EVENT_SERIALIZE_MAX_LENGTH,src)==40);
+ assert(memcmp(buf,"[recur:1Y]2020-01-15:test year boundary\n",40)==0);
+
+ assert(fclose(src)==0);
+
+ reset_env();
+}
+
static void handle_args_basic_test() {
unsigned long int offset;
time_t start_time;
assert(1==handle_args(4,args_with_date,&offset,&start_time));
assert(offset==2);
- assert(start_time==1662019200);
+ assert(start_time==1662015600);
}
static void rm_basic_test() {
}
void setup_env() {
- assert(setenv("TZ","America/Los_Angeles",1)==0);
+ assert(setenv("TZ",":America/Los_Angeles",1)==0);
tzset();
srand(time(NULL));
--- /dev/null
+#include<test_utils.h>
+
+#include<validate.h>
+
+int main();
+static void validate_basic_test();
+
+int main() {
+ setup_env();
+
+ validate_basic_test();
+
+ clean_env();
+
+ return EXIT_SUCCESS;
+}
+
+static void validate_basic_test(){
+ char buf[1000];
+ FILE *fp;
+
+ memset(buf,0,1000);
+
+ fp = fopen(global_options.file,"w");
+ assert(fp!=NULL);
+
+ strcpy(buf,"2022-08-01:test\n2022-08-02\n");
+ assert(fwrite(buf,1,27,fp)==27);
+ assert(fclose(fp)==0);
+
+ assert(validate()==EXIT_FAILURE);
+
+ reset_env();
+
+ fp = fopen(global_options.file,"w");
+ assert(fp!=NULL);
+
+ strcpy(buf,"2022-08-01:test\n2022-08-02:test2\n");
+ assert(fwrite(buf,1,33,fp)==33);
+ assert(fclose(fp)==0);
+
+ assert(validate()==EXIT_SUCCESS);
+
+ reset_env();
+}