/* // libunit.c // // Copyright 2010 Michael Rasmussen // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, // MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "caldav.h" #include #include #include #include #include #include #include static const char* usage[] = { "unittest is part of libcaldav for claws-mails " "vcalendar plugin.\nCopyright (C) Michael Rasmussen, 2008.\n" "This program is free software; you can redistribute it and/or modify\n" "it under the terms of the GNU General Public License as published by\n" "the Free Software Foundation; either version 3 of the License, or\n" "(at your option) any later version.\n" "\nusage:\n\tunittest [Options]\n" "\n\tOptions:\n" "\t\t-h|-?\tusage\n" "\t\t-a\tURL\n" "\t\t-d\tEnable debug\n" "\t\t-l\tDebug library\n" "\t\t-p\tpassword\n" "\t\t-u\tusername\n" }; /* * Options can be given in one of three ways: * 1) Entered as options on the command line * 2) Stored in environment variables: * - LIBCALDAV_UID -> username to use when connection to server * - LIBCALDAV_PWD -> password, if any, to use when connection to server * - LIBCALDAV_URL -> complete URL to server. prefixed with either * http:// or https:// * 3) Stored in a file found in the same directory as the program: * [server] * password=Big secret * username=username * url=http[s]://bar.tld/foo */ #define CONFFILE "caldav-unit-settings.conf" typedef struct { gchar* uid; gchar* pwd; gchar* url; } settings; typedef enum { PWD, UID, URL } CONFIG; static settings* SETTING = NULL; gboolean DEBUG = FALSE; gboolean DEBUG_LIB = FALSE; void settings_free(settings** setting) { settings* s; if (! *setting) return; s = *setting; g_free(s->url); g_free(s->uid); g_free(s->pwd); g_free(s); *setting = s = NULL; } settings* parse_cmdline(int argc, char** argv) { char c; settings* setting; setting = g_new0(settings, 1); while ((c = getopt(argc, argv, "ha:dlp:u:?")) != -1) { switch (c) { case 'h': case '?': fprintf(stdout, "%s", usage[0]); return 0; case 'a': setting->url = g_strdup(optarg); break; case 'd': DEBUG = TRUE; break; case 'l': DEBUG_LIB = TRUE; break; case 'p': setting->pwd = g_strdup(optarg); break; case 'u': setting->uid = g_strdup(optarg); break; } } if (argv[optind]) { fprintf(stderr, "No arguments after options expected\n"); fprintf(stderr, "%s", usage[0]); settings_free(&setting); return NULL; } return setting; } void read_file(const gchar* file) { GKeyFile* keyfile; if (! SETTING) { SETTING = g_new0(settings, 1); keyfile = g_key_file_new(); if (g_key_file_load_from_file(keyfile, file, G_KEY_FILE_KEEP_COMMENTS, NULL)) { SETTING->pwd = g_key_file_get_string(keyfile, "server", "password", NULL); SETTING->uid = g_key_file_get_string(keyfile, "server", "username", NULL); SETTING->url = g_key_file_get_string(keyfile, "server", "url", NULL); } g_key_file_free(keyfile); } } const gchar* get_setting_from_file(CONFIG config) { gchar* cwd; gchar* path; gchar* pos; gchar* setting = NULL; int step; gchar* filename = g_get_prgname(); if (filename[0] == '/') { /* absolute path */ cwd = g_path_get_dirname(filename); } else if ((pos = strchr(filename, '/')) != NULL) { /* relative path */ if (filename[0] == '.') { char* tmp = pos; while (tmp) { if (strncmp(tmp, "..", 2) == 0) step = 2; else step = 1; tmp = strchr(pos + step, '/'); if (tmp) pos = tmp; } if (pos == NULL) { pos = strchr(filename, '/'); } } path = g_get_current_dir(); cwd = g_build_filename(path, pos + 1, NULL); g_free(path); if (g_file_test(cwd, G_FILE_TEST_IS_REGULAR)) { pos = strrchr(cwd, '/'); if (pos) { path = g_strndup(cwd, pos - cwd); g_free(cwd); cwd = g_strdup(path); g_free(path); } } } else { /* find cwd in PATH */ cwd = g_find_program_in_path(filename); } path = g_build_filename(cwd, CONFFILE, NULL); g_free(cwd); if (g_file_test(path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) { read_file(path); switch (config) { case UID: setting = SETTING->uid; break; case PWD: setting = SETTING->pwd; break; case URL: setting = SETTING->url; break; } } g_free(path); return setting; } gboolean find_missing(settings** setting) { settings* s = *setting; const char* env; gboolean error = FALSE; if (! s) return TRUE; if (! s->uid) { if ((env = getenv("LIBCALDAV_UID")) == NULL) { env = get_setting_from_file(UID); if (env == NULL) error = TRUE; } s->uid = g_strdup(env); } if (! s->pwd) { if ((env = getenv("LIBCALDAV_PWD")) == NULL) { env = get_setting_from_file(PWD); if (env == NULL) error = TRUE; } s->pwd = g_strdup(env); } if (! s->url) { if ((env = getenv("LIBCALDAV_URL")) == NULL) { env = get_setting_from_file(URL); if (env == NULL) error = TRUE; } s->url = g_strdup(env); } settings_free(&SETTING); return error; } time_t make_time_t(const char* time_elem) { struct tm datetime = {0,0,0,0,0,0,0,0,0,0,NULL}; struct tm* tmp; gchar** elem; time_t t; t = time(NULL); tmp = localtime(&t); elem = g_strsplit(time_elem, "/", 3); datetime.tm_year = atoi(elem[0]) - 1900; datetime.tm_mon = atoi(elem[1]) - 1; datetime.tm_mday = atoi(elem[2]); g_strfreev(elem); t = mktime(&datetime); return t; } gboolean compare_freebusy(const gchar* s1, const gchar* s2) { const char* TOKEN = "FREEBUSY:"; gchar* pos1; gchar* pos2; gchar* id1; if (! s1 && ! s2) return TRUE; if (! s1 || ! s2) return FALSE; pos1 = strstr(s2, TOKEN); if (! pos1) return FALSE; pos1 += strlen(TOKEN); pos2 = strchr(pos1, '\n'); if (! pos2) return FALSE; if (*(pos2 - 1) == '\r') pos2--; id1 = g_strndup(pos1, pos2 - pos1); int res = strcmp(s1, id1); g_free(id1); return (res == 0); } gboolean compare_object(const gchar* TOKEN, const gchar* s1, const gchar* s2) { gchar* pos1; gchar* pos2; gchar* id1; gchar* id2; if (! s1 && ! s2) return TRUE; if (! s1 || ! s2) return FALSE; pos1 = strstr(s1, TOKEN); if (! pos1) return FALSE; pos1 += strlen(TOKEN) + 1; pos2 = strchr(pos1, '\n'); if (! pos2) return FALSE; if (*(pos2 - 1) == '\r') pos2--; id1 = g_strndup(pos1, pos2 - pos1); pos2 = strstr(s2, TOKEN); if (! pos2) { g_free(id1); return FALSE; } pos2 += strlen(TOKEN) + 1; pos1 = strchr(pos2, '\n'); if (! pos1) { g_free(id1); return FALSE; } if (*(pos1 - 1) == '\r') pos1--; id2 = g_strndup(pos2, pos1 - pos2); int res = strcmp(id1, id2); g_free(id1); g_free(id2); return (res == 0); } void run_tests(settings* s) { runtime_info* info = caldav_get_runtime_info(); response* resp = caldav_get_response(); gchar** parts; gchar* url; gchar* object; if (DEBUG_LIB) { info->options->debug = 1; info->options->trace_ascii = 1; } parts = g_strsplit(s->url, "//", 2); url = g_strconcat( parts[0], "//", s->uid, ":", s->pwd, "@", parts[1], NULL); g_strfreev(parts); fprintf(stdout, "Test caldav_enabled_resource:\t\t\t"); if (caldav_enabled_resource(url, info)) { fprintf(stdout, "OK\n"); if (DEBUG) fprintf(stdout, "caldav enabled server\n"); } else { fprintf(stdout, "FAIL\n"); if (DEBUG) fprintf(stdout, "%ld: %s\n", info->error->code, info->error->str); } fprintf(stdout, "Test caldav_get_displayname:\t\t\t"); if (caldav_get_displayname(resp, url, info) == OK) { fprintf(stdout, "OK\n"); if (DEBUG) fprintf(stdout, "Display Name: %s\n", resp->msg); } else { fprintf(stdout, "FAIL\n"); if (DEBUG) fprintf(stdout, "%ld: %s\n", info->error->code, info->error->str); } g_free(resp->msg); resp->msg = NULL; fprintf(stdout, "Test caldav_get_server_options:\t\t\t"); if ((parts = caldav_get_server_options(url, info)) != NULL) { fprintf(stdout, "OK\n"); if (DEBUG) { char** tmp = parts; while (*tmp) { fprintf(stdout, "--> %s\n", *tmp++); } } g_strfreev(parts); } else { fprintf(stdout, "FAIL\n"); if (DEBUG) fprintf(stdout, "%ld: %s\n", info->error->code, info->error->str); } g_file_get_contents("../ics/add.ics", &object, NULL, NULL); fprintf(stdout, "Test caldav_add_object:\t\t\t\t"); if (caldav_add_object(object, url, info) == OK) { fprintf(stdout, "OK\n"); if (DEBUG) fprintf(stdout, "Added successfully\n"); } else { fprintf(stdout, "FAIL\n"); if (DEBUG) fprintf(stdout, "%ld: %s\n", info->error->code, info->error->str); } fprintf(stdout, "Test if object was added:\t\t\t"); if (caldav_get_object(resp, make_time_t("2008/04/15"), make_time_t("2008/04/16"), url, info) == OK) { if (compare_object("UID", object, resp->msg)) fprintf(stdout, "OK\n"); else fprintf(stdout, "FAIL\n"); if (DEBUG) fprintf(stdout, "%s\n", resp->msg); } else { fprintf(stdout, "FAIL\n"); if (DEBUG) fprintf(stdout, "%ld: %s\n", info->error->code, info->error->str); } g_free(resp->msg); resp->msg = NULL; g_free(object); fprintf(stdout, "Test FREEBUSY search the same day:\t\t"); if (caldav_get_freebusy(resp, make_time_t("2008/04/15"), make_time_t("2008/04/16"), url, info) == OK) { if (compare_freebusy("20080415T151500Z/20080415T162500", resp->msg)) fprintf(stdout, "OK\n"); else fprintf(stdout, "FAIL\n"); if (DEBUG) fprintf(stdout, "%s\n", resp->msg); } else { fprintf(stdout, "FAIL\n"); if (DEBUG) fprintf(stdout, "%ld: %s\n", info->error->code, info->error->str); } g_free(resp->msg); resp->msg = NULL; g_file_get_contents("../ics/modify.ics", &object, NULL, NULL); fprintf(stdout, "Test caldav_modify_object:\t\t\t"); if (caldav_modify_object(object, url, info) == OK) { fprintf(stdout, "OK\n"); if (DEBUG) fprintf(stdout, "Modified successfully\n"); } else { fprintf(stdout, "FAIL\n"); if (DEBUG) fprintf(stdout, "%ld: %s\n", info->error->code, info->error->str); } fprintf(stdout, "Test if object was modified:\t\t\t"); if (caldav_get_object(resp, make_time_t("2008/04/16"), make_time_t("2008/04/17"), url, info) == OK) { if (compare_object("DTEND", object, resp->msg)) fprintf(stdout, "OK\n"); else fprintf(stdout, "FAIL\n"); if (DEBUG) fprintf(stdout, "%s\n", resp->msg); } else { fprintf(stdout, "FAIL\n"); if (DEBUG) fprintf(stdout, "%ld: %s\n", info->error->code, info->error->str); } g_free(resp->msg); resp->msg = NULL; fprintf(stdout, "Test caldav_getall_object:\t\t\t"); if (caldav_getall_object(resp, url, info) == OK) { fprintf(stdout, "OK\n"); if (DEBUG) fprintf(stdout, "%s\n", resp->msg); } else { fprintf(stdout, "FAIL\n"); if (DEBUG) fprintf(stdout, "%ld: %s\n", info->error->code, info->error->str); } fprintf(stdout, "Test if object exists:\t\t\t\t"); if (compare_object("UID", object, resp->msg)) fprintf(stdout, "FAIL\n"); else fprintf(stdout, "OK\n"); g_free(resp->msg); resp->msg = NULL; g_free(object); g_file_get_contents("../ics/delete.ics", &object, NULL, NULL); fprintf(stdout, "Test caldav_delete_object:\t\t\t"); if (caldav_delete_object(object, url, info) == OK) { fprintf(stdout, "OK\n"); if (DEBUG) fprintf(stdout, "Deleted successfully\n"); } else { fprintf(stdout, "FAIL\n"); if (DEBUG) fprintf(stdout, "%ld: %s\n", info->error->code, info->error->str); } fprintf(stdout, "Test if object was deleted:\t\t\t"); if (caldav_get_object(resp, make_time_t("2008/04/16"), make_time_t("2008/04/17"), url, info) == OK) { if (compare_object("UID", object, resp->msg)) fprintf(stdout, "FAIL\n"); else fprintf(stdout, "OK\n"); if (DEBUG) fprintf(stdout, "%s\n", (resp->msg) ? resp->msg : "No object found"); g_free(resp->msg); resp->msg = NULL; } else { fprintf(stdout, "FAIL\n"); if (DEBUG) fprintf(stdout, "%ld: %s\n", info->error->code, info->error->str); } g_free(object); fprintf(stdout, "\nTesting without using locks\n"); info->options->use_locking = 0; g_file_get_contents("../ics/add.ics", &object, NULL, NULL); fprintf(stdout, "Test caldav_add_object:\t\t\t\t"); if (caldav_add_object(object, url, info) == OK) { fprintf(stdout, "OK\n"); if (DEBUG) fprintf(stdout, "Added successfully\n"); } else { fprintf(stdout, "FAIL\n"); if (DEBUG) fprintf(stdout, "%ld: %s\n", info->error->code, info->error->str); } fprintf(stdout, "Test if object was added:\t\t\t"); if (caldav_get_object(resp, make_time_t("2008/04/15"), make_time_t("2008/04/16"), url, info) == OK) { if (compare_object("UID", object, resp->msg)) fprintf(stdout, "OK\n"); else fprintf(stdout, "FAIL\n"); if (DEBUG) fprintf(stdout, "%s\n", resp->msg); } else { fprintf(stdout, "FAIL\n"); if (DEBUG) fprintf(stdout, "%ld: %s\n", info->error->code, info->error->str); } g_free(resp->msg); resp->msg = NULL; g_free(object); /* fprintf(stdout, "Test FREEBUSY search the same day:\t\t"); if (caldav_get_freebusy(resp, make_time_t("2008/04/15"), make_time_t("2008/04/16"), url, info) == OK) { if (compare_freebusy("20080415T151500Z/20080415T162500", resp->msg)) fprintf(stdout, "OK\n"); else fprintf(stdout, "FAIL\n"); if (DEBUG) fprintf(stdout, "%s\n", resp->msg); } else { fprintf(stdout, "FAIL\n"); if (DEBUG) fprintf(stdout, "%ld: %s\n", info->error->code, info->error->str); } g_free(resp->msg); resp->msg = NULL;*/ g_file_get_contents("../ics/modify.ics", &object, NULL, NULL); fprintf(stdout, "Test caldav_modify_object:\t\t\t"); if (caldav_modify_object(object, url, info) == OK) { fprintf(stdout, "OK\n"); if (DEBUG) fprintf(stdout, "Modified successfully\n"); } else { fprintf(stdout, "FAIL\n"); if (DEBUG) fprintf(stdout, "%ld: %s\n", info->error->code, info->error->str); } fprintf(stdout, "Test if object was modified:\t\t\t"); if (caldav_get_object(resp, make_time_t("2008/04/16"), make_time_t("2008/04/17"), url, info) == OK) { if (compare_object("DTEND", object, resp->msg)) fprintf(stdout, "OK\n"); else fprintf(stdout, "FAIL\n"); if (DEBUG) fprintf(stdout, "%s\n", resp->msg); } else { fprintf(stdout, "FAIL\n"); if (DEBUG) fprintf(stdout, "%ld: %s\n", info->error->code, info->error->str); } g_free(resp->msg); resp->msg = NULL; g_free(object); g_file_get_contents("../ics/delete.ics", &object, NULL, NULL); fprintf(stdout, "Test caldav_delete_object:\t\t\t"); if (caldav_delete_object(object, url, info) == OK) { fprintf(stdout, "OK\n"); if (DEBUG) fprintf(stdout, "Deleted successfully\n"); } else { fprintf(stdout, "FAIL\n"); if (DEBUG) fprintf(stdout, "%ld: %s\n", info->error->code, info->error->str); } fprintf(stdout, "Test if object was deleted:\t\t\t"); if (caldav_get_object(resp, make_time_t("2008/04/16"), make_time_t("2008/04/17"), url, info) == OK) { if (compare_object("UID", object, resp->msg)) fprintf(stdout, "FAIL\n"); else fprintf(stdout, "OK\n"); if (DEBUG) fprintf(stdout, "%s\n", (resp->msg) ? resp->msg : "No object found"); g_free(resp->msg); resp->msg = NULL; } else { fprintf(stdout, "FAIL\n"); if (DEBUG) fprintf(stdout, "%ld: %s\n", info->error->code, info->error->str); } g_free(url); caldav_free_response(&resp); caldav_free_runtime_info(&info); } int main(int argc, char** argv) { settings* setting; g_set_prgname(argv[0]); setting = parse_cmdline(argc, argv); if (find_missing(&setting)) { fprintf(stderr, "missing required information\n"); fprintf(stdout, "%s", usage[0]); settings_free(&setting); return 1; } run_tests(setting); settings_free(&setting); return 0; }