diff --git a/.gitignore b/.gitignore index 68d723e..5fe5061 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,16 @@ -dunst *.o +*.gcda +*.gcno +*.gcov + core vgcore.* -dunst.1 -org.knopwob.dunst.service -dunst.systemd.service -dunstify -test/test -docs/internal/html + +/docs/dunst.1 +/docs/internal/coverage +/docs/internal/html +/dunst +/dunstify +/dunst.systemd.service +/org.knopwob.dunst.service +/test/test diff --git a/.travis.yml b/.travis.yml index 726ae4c..de3d0ed 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,19 +18,22 @@ dist: trusty sudo: false language: c +git: + depth: false + before_install: - pip install --user cpp-coveralls script: - CFLAGS="-Werror" make all dunstify test-valgrind doc-doxygen - - make clean - - CFLAGS="-Werror -fprofile-arcs -ftest-coverage -O0" make test + - CFLAGS="-Werror" make clean + - CFLAGS="-Werror" make test-coverage matrix: include: - compiler: gcc after_success: - - coveralls --exclude 'test' + - coveralls - compiler: clang after_success: - - coveralls --exclude 'test' --gcov llvm-cov --gcov-options gcov + - coveralls --gcov llvm-cov --gcov-options gcov diff --git a/Makefile b/Makefile index 5261b17..60651c1 100644 --- a/Makefile +++ b/Makefile @@ -42,8 +42,8 @@ $(error "$(PKG_CONFIG) failed!") endif endif -CFLAGS := ${DEFAULT_CPPFLAGS} ${CPPFLAGS} ${DEFAULT_CFLAGS} ${CFLAGS} -I. ${INCS} -LDFLAGS := ${DEFAULT_LDFLAGS} ${LDFLAGS} -L. ${LIBS} +CFLAGS := ${DEFAULT_CPPFLAGS} ${CPPFLAGS} ${DEFAULT_CFLAGS} ${CFLAGS} ${INCS} +LDFLAGS := ${DEFAULT_LDFLAGS} ${LDFLAGS} ${LIBS} SRC := $(sort $(shell find src/ -name '*.c')) OBJ := ${SRC:.c=.o} @@ -69,23 +69,37 @@ dunst: ${OBJ} main.o dunstify: dunstify.o ${CC} -o ${@} dunstify.o ${CFLAGS} ${LDFLAGS} -.PHONY: test test-valgrind -test: test/test - cd test && ./test +.PHONY: test test-valgrind test-coverage +test: test/test clean-coverage-run + ./test/test test-valgrind: test/test - cd ./test \ - && valgrind \ - --suppressions=../.valgrind.suppressions \ - --leak-check=full \ - --show-leak-kinds=definite \ - --errors-for-leak-kinds=definite \ - --num-callers=40 \ - --error-exitcode=123 \ - ./test + valgrind \ + --suppressions=.valgrind.suppressions \ + --leak-check=full \ + --show-leak-kinds=definite \ + --errors-for-leak-kinds=definite \ + --num-callers=40 \ + --error-exitcode=123 \ + ./test/test + +test-coverage: CFLAGS += -fprofile-arcs -ftest-coverage -O0 +test-coverage: test + +test-coverage-report: test-coverage + mkdir -p docs/internal/coverage + gcovr \ + -r . \ + --exclude=test \ + --html \ + --html-details \ + -o docs/internal/coverage/index.html + +test/%.o: test/%.c src/%.c + ${CC} -o $@ -c $< ${CFLAGS} test/test: ${OBJ} ${TEST_OBJ} - ${CC} -o ${@} ${TEST_OBJ} ${OBJ} ${CFLAGS} ${LDFLAGS} + ${CC} -o ${@} ${TEST_OBJ} $(filter-out ${TEST_OBJ:test/%=src/%},${OBJ}) ${CFLAGS} ${LDFLAGS} .PHONY: doc doc-doxygen doc: docs/dunst.1 @@ -104,8 +118,8 @@ service-systemd: @sed "s|##PREFIX##|$(PREFIX)|" dunst.systemd.service.in > dunst.systemd.service endif -.PHONY: clean clean-dunst clean-dunstify clean-doc clean-tests -clean: clean-dunst clean-dunstify clean-doc clean-tests +.PHONY: clean clean-dunst clean-dunstify clean-doc clean-tests clean-coverage clean-coverage-run +clean: clean-dunst clean-dunstify clean-doc clean-tests clean-coverage clean-coverage-run clean-dunst: rm -f dunst ${OBJ} main.o @@ -119,10 +133,19 @@ clean-dunstify: clean-doc: rm -f docs/dunst.1 rm -fr docs/internal/html + rm -fr docs/internal/coverage clean-tests: rm -f test/test test/*.o +clean-coverage: clean-coverage-run + find . -type f -name '*.gcno' -delete + find . -type f -name '*.gcna' -delete +# Cleans the coverage data before every run to not double count any lines +clean-coverage-run: + find . -type f -name '*.gcov' -delete + find . -type f -name '*.gcda' -delete + .PHONY: install install-dunst install-doc \ install-service install-service-dbus install-service-systemd \ uninstall \ diff --git a/config.h b/config.h index 40207a3..42de31d 100644 --- a/config.h +++ b/config.h @@ -12,7 +12,7 @@ struct settings defaults = { .lowfgcolor = "#000000", .format = "%s %b", /* default format */ -.timeouts = { 10*G_USEC_PER_SEC, 10*G_USEC_PER_SEC, 0 }, /* low, normal, critical */ +.timeouts = { S2US(10), S2US(10), S2US(0) }, /* low, normal, critical */ .icons = { "dialog-information", "dialog-information", "dialog-warning" }, /* low, normal, critical */ .transparency = 0, /* transparency */ diff --git a/src/draw.c b/src/draw.c index 6f56573..cf51ae1 100644 --- a/src/draw.c +++ b/src/draw.c @@ -4,17 +4,17 @@ #include #include #include +#include #include #include #include -#include #include #include "dunst.h" #include "icon.h" +#include "log.h" #include "markup.h" #include "notification.h" -#include "log.h" #include "queues.h" #include "x11/x.h" diff --git a/src/draw.h b/src/draw.h index 581d0ca..d646dc2 100644 --- a/src/draw.h +++ b/src/draw.h @@ -1,7 +1,7 @@ #ifndef DUNST_DRAW_H #define DUNST_DRAW_H -#include "src/x11/x.h" +#include "x11/x.h" extern struct window_x11 *win; // Temporary void draw_setup(void); diff --git a/src/dunst.c b/src/dunst.c index 0be3d8f..88031e8 100644 --- a/src/dunst.c +++ b/src/dunst.c @@ -2,13 +2,13 @@ #include "dunst.h" -#include -#include #include +#include #include #include #include #include +#include #include "dbus.h" #include "draw.h" @@ -22,12 +22,6 @@ #include "x11/screen.h" #include "x11/x.h" -#ifndef VERSION -#define VERSION "version info needed" -#endif - -/* index of colors fit to urgency level */ - GMainLoop *mainloop = NULL; /* misc functions */ @@ -162,7 +156,7 @@ int dunst_main(int argc, char *argv[]) n->summary = g_strdup("startup"); n->body = g_strdup("dunst is up and running"); n->progress = -1; - n->timeout = 10 * G_USEC_PER_SEC; + n->timeout = S2US(10); n->markup = MARKUP_NO; n->urgency = URG_LOW; notification_init(n); diff --git a/src/markup.c b/src/markup.c index 884fb24..3f74716 100644 --- a/src/markup.c +++ b/src/markup.c @@ -3,10 +3,10 @@ #include "markup.h" #include -#include -#include #include +#include #include +#include #include "log.h" #include "settings.h" diff --git a/src/queues.c b/src/queues.c index c90faf2..9f292ff 100644 --- a/src/queues.c +++ b/src/queues.c @@ -490,7 +490,7 @@ gint64 queues_get_next_datachange(gint64 time) if (age > settings.show_age_threshold) // sleep exactly until the next shift of the second happens - sleep = MIN(sleep, ((G_USEC_PER_SEC) - (age % (G_USEC_PER_SEC)))); + sleep = MIN(sleep, (S2US(1) - (age % S2US(1)))); else if (n->timeout == 0 || ttl > settings.show_age_threshold) sleep = MIN(sleep, settings.show_age_threshold); } diff --git a/src/settings.c b/src/settings.c index c27cc4b..bdd299f 100644 --- a/src/settings.c +++ b/src/settings.c @@ -6,15 +6,16 @@ #include #include -#include "rules.h" // put before config.h to fix missing include -#include "config.h" #include "dunst.h" #include "log.h" #include "notification.h" #include "option_parser.h" +#include "rules.h" #include "utils.h" #include "x11/x.h" +#include "../config.h" + struct settings settings; static const char *follow_mode_to_string(enum follow_mode f_mode) diff --git a/src/utils.c b/src/utils.c index 22a0c50..4dcffa5 100644 --- a/src/utils.c +++ b/src/utils.c @@ -170,7 +170,7 @@ gint64 string_to_time(const char *string) LOG_W("Time: '%s': Unknown error.", string); return 0; } else if (errno == 0 && !*endptr) { - return val * G_USEC_PER_SEC; + return S2US(val); } // endptr may point to a separating space @@ -180,13 +180,13 @@ gint64 string_to_time(const char *string) if (STRN_EQ(endptr, "ms", 2)) return val * 1000; else if (STRN_EQ(endptr, "s", 1)) - return val * G_USEC_PER_SEC; + return S2US(val); else if (STRN_EQ(endptr, "m", 1)) - return val * G_USEC_PER_SEC * 60; + return S2US(val) * 60; else if (STRN_EQ(endptr, "h", 1)) - return val * G_USEC_PER_SEC * 60 * 60; + return S2US(val) * 60 * 60; else if (STRN_EQ(endptr, "d", 1)) - return val * G_USEC_PER_SEC * 60 * 60 * 24; + return S2US(val) * 60 * 60 * 24; else return 0; } @@ -205,7 +205,6 @@ gint64 time_monotonic_now(void) #else clock_gettime(CLOCK_MONOTONIC, &tv_now); #endif - return (gint64)tv_now.tv_sec * G_USEC_PER_SEC - + tv_now.tv_nsec / 1000; + return S2US(tv_now.tv_sec) + tv_now.tv_nsec / 1000; } /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/utils.h b/src/utils.h index b77fa28..6b8a7a7 100644 --- a/src/utils.h +++ b/src/utils.h @@ -16,6 +16,9 @@ //! Test if string a and b are the same case-insensitively #define STR_CASEQ(a, b) (strcasecmp(a, b) == 0) +//! Convert a second into the internal time representation +#define S2US(s) (((gint64)(s)) * 1000 * 1000) + /** * Replaces all occurrences of the char \p needle with the char \p replacement in \p haystack. * diff --git a/src/x11/screen.c b/src/x11/screen.c index af47e85..f00431a 100644 --- a/src/x11/screen.c +++ b/src/x11/screen.c @@ -1,12 +1,5 @@ #include "screen.h" -#include -#include -#include -#include -#include -#include -#include #include #include #include @@ -14,10 +7,17 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include -#include "src/log.h" -#include "src/settings.h" -#include "src/utils.h" +#include "../log.h" +#include "../settings.h" +#include "../utils.h" #include "x.h" struct screen_info *screens; diff --git a/src/x11/screen.h b/src/x11/screen.h index 5ff2e69..13b9c44 100644 --- a/src/x11/screen.h +++ b/src/x11/screen.h @@ -2,8 +2,8 @@ #ifndef DUNST_SCREEN_H #define DUNST_SCREEN_H -#include #include +#include #define INRECT(x,y,rx,ry,rw,rh) ((x) >= (rx) && (x) < (rx)+(rw) && (y) >= (ry) && (y) < (ry)+(rh)) diff --git a/src/x11/x.c b/src/x11/x.c index 673cd1a..ca613a6 100644 --- a/src/x11/x.c +++ b/src/x11/x.c @@ -1,15 +1,9 @@ /* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ #include "x.h" -#include -#include -#include -#include -#include -#include #include -#include #include +#include #include #include #include @@ -18,17 +12,23 @@ #include #include #include +#include +#include +#include +#include +#include +#include -#include "src/draw.h" -#include "src/dbus.h" -#include "src/dunst.h" -#include "src/log.h" -#include "src/markup.h" -#include "src/menu.h" -#include "src/notification.h" -#include "src/queues.h" -#include "src/settings.h" -#include "src/utils.h" +#include "../dbus.h" +#include "../draw.h" +#include "../dunst.h" +#include "../log.h" +#include "../markup.h" +#include "../menu.h" +#include "../notification.h" +#include "../queues.h" +#include "../settings.h" +#include "../utils.h" #include "screen.h" diff --git a/src/x11/x.h b/src/x11/x.h index 3a644cf..6f4ced1 100644 --- a/src/x11/x.h +++ b/src/x11/x.h @@ -5,11 +5,11 @@ #define XLIB_ILLEGAL_ACCESS #include -#include -#include -#include #include #include +#include +#include +#include #include "screen.h" @@ -22,7 +22,7 @@ struct keyboard_shortcut { }; // Cyclical dependency -#include "src/settings.h" +#include "../settings.h" struct window_x11; diff --git a/test/icon.c b/test/icon.c index 180a324..5bd96aa 100644 --- a/test/icon.c +++ b/test/icon.c @@ -1,9 +1,5 @@ +#include "../src/icon.c" #include "greatest.h" -#include "../src/icon.h" -#include "../src/utils.h" - -#include -#include #define ICONPREFIX "/data/icons/path" @@ -14,24 +10,23 @@ #define IS_ICON_PNG(pb) 4 == gdk_pixbuf_get_width(pb) #define IS_ICON_SVG(pb) 16 == gdk_pixbuf_get_width(pb) +extern const char *base; + TEST test_get_pixbuf_from_file_tilde(void) { - char *cwd = g_get_current_dir(); const char *home = g_get_home_dir(); const char *iconpath = ICONPREFIX; - if (0 != strncmp(home, cwd, strlen(home))) { - g_free(cwd); + if (0 != strncmp(home, base, strlen(home))) { SKIPm("Current directory is not a subdirectory from user's home." " Cannot test iconpath tilde expansion.\n"); } - gchar *path = g_build_filename(cwd, iconpath, "valid", "icon1.svg", NULL); + gchar *path = g_build_filename(base, iconpath, "valid", "icon1.svg", NULL); path = string_replace_at(path, 0, strlen(home), "~"); GdkPixbuf *pixbuf = get_pixbuf_from_file(path); g_clear_pointer(&path, g_free); - g_clear_pointer(&cwd, g_free); ASSERT(pixbuf); ASSERTm("The wrong pixbuf is loaded in the icon file.", IS_ICON_SVG(pixbuf)); @@ -41,14 +36,12 @@ TEST test_get_pixbuf_from_file_tilde(void) TEST test_get_pixbuf_from_file_absolute(void) { - char *cwd = g_get_current_dir(); const char *iconpath = ICONPREFIX; - gchar *path = g_build_filename(cwd, iconpath, "valid", "icon1.svg", NULL); + gchar *path = g_build_filename(base, iconpath, "valid", "icon1.svg", NULL); GdkPixbuf *pixbuf = get_pixbuf_from_file(path); g_clear_pointer(&path, g_free); - g_clear_pointer(&cwd, g_free); ASSERT(pixbuf); ASSERTm("The wrong pixbuf is loaded in the icon file.", IS_ICON_SVG(pixbuf)); @@ -98,7 +91,7 @@ TEST test_get_pixbuf_from_icon_onlypng(void) TEST test_get_pixbuf_from_icon_filename(void) { - char *icon = string_append(g_get_current_dir(), "/data/icons/valid.png", NULL); + char *icon = g_strconcat(base, "/data/icons/valid.png", NULL); GdkPixbuf *pixbuf = get_pixbuf_from_icon(icon); ASSERT(pixbuf); ASSERTm("PNG pixbuf isn't loaded", IS_ICON_PNG(pixbuf)); @@ -110,24 +103,23 @@ TEST test_get_pixbuf_from_icon_filename(void) TEST test_get_pixbuf_from_icon_fileuri(void) { - char *curdir = g_get_current_dir(); - char *icon = g_strconcat("file://", curdir,"/data/icons/valid.svg", NULL); + char *icon = g_strconcat("file://", base, "/data/icons/valid.svg", NULL); GdkPixbuf *pixbuf = get_pixbuf_from_icon(icon); ASSERT(pixbuf); ASSERTm("SVG pixbuf isn't loaded", IS_ICON_SVG(pixbuf)); g_clear_pointer(&pixbuf, g_object_unref); g_free(icon); - g_free(curdir); PASS(); } SUITE(suite_icon) { - settings.icon_path = - "." ICONPREFIX "/invalid" - ":." ICONPREFIX "/valid" - ":." ICONPREFIX "/both"; + settings.icon_path = g_strconcat( + base, ICONPREFIX "/invalid" + ":", base, ICONPREFIX "/valid" + ":", base, ICONPREFIX "/both", + NULL); RUN_TEST(test_get_pixbuf_from_file_tilde); RUN_TEST(test_get_pixbuf_from_file_absolute); @@ -138,6 +130,6 @@ SUITE(suite_icon) RUN_TEST(test_get_pixbuf_from_icon_filename); RUN_TEST(test_get_pixbuf_from_icon_fileuri); - settings.icon_path = NULL; + g_clear_pointer(&settings.icon_path, g_free); } /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/test/markup.c b/test/markup.c index b00888d..0644dd2 100644 --- a/test/markup.c +++ b/test/markup.c @@ -1,10 +1,6 @@ +#include "../src/markup.c" #include "greatest.h" -#include -#include - -#include "src/markup.h" - TEST test_markup_strip(void) { char *ptr; diff --git a/test/misc.c b/test/misc.c new file mode 100644 index 0000000..a61b82f --- /dev/null +++ b/test/misc.c @@ -0,0 +1,21 @@ +#include "greatest.h" + +// This actually tests the buildsystem to make sure, +// the build system hands over a correct version number +// This is not testable via macros +TEST assert_version_number(void) +{ + ASSERTm("Version number is empty", + 0 != strcmp(VERSION, "")); + + ASSERTm("Version number is not seeded by git", + NULL == strstr(VERSION, "non-git")); + PASS(); +} + +SUITE(suite_misc) +{ + RUN_TEST(assert_version_number); +} + +/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/test/notification.c b/test/notification.c index b6afe2f..6738f84 100644 --- a/test/notification.c +++ b/test/notification.c @@ -1,9 +1,10 @@ +#include "../src/notification.c" #include "greatest.h" -#include "src/notification.h" -#include "src/option_parser.h" -#include "src/settings.h" -#include +#include "../src/option_parser.h" +#include "../src/settings.h" + +extern const char *base; TEST test_notification_is_duplicate_field(char **field, struct notification *a, @@ -119,7 +120,8 @@ TEST test_notification_referencing(void) SUITE(suite_notification) { cmdline_load(0, NULL); - load_settings("data/dunstrc.default"); + char *config_path = g_strconcat(base, "/data/dunstrc.default", NULL); + load_settings(config_path); struct notification *a = notification_create(); a->appname = g_strdup("Test"); @@ -146,6 +148,7 @@ SUITE(suite_notification) RUN_TEST(test_notification_referencing); g_clear_pointer(&settings.icon_path, g_free); + g_free(config_path); } /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/test/option_parser.c b/test/option_parser.c index 3b942d8..0c7f807 100644 --- a/test/option_parser.c +++ b/test/option_parser.c @@ -1,9 +1,7 @@ +#include "../src/option_parser.c" #include "greatest.h" -#include -#include - -#include "src/option_parser.h" +extern const char *base; TEST test_next_section(void) { @@ -280,7 +278,8 @@ TEST test_option_get_bool(void) SUITE(suite_option_parser) { - FILE *config_file = fopen("data/test-ini", "r"); + char *config_path = g_strconcat(base, "/data/test-ini", NULL); + FILE *config_file = fopen(config_path, "r"); if (!config_file) { fputs("\nTest config file 'data/test-ini' couldn't be opened, failing.\n", stderr); exit(1); @@ -314,6 +313,8 @@ SUITE(suite_option_parser) RUN_TEST(test_option_get_int); RUN_TEST(test_option_get_double); RUN_TEST(test_option_get_bool); + + g_free(config_path); free_ini(); g_strfreev(argv); fclose(config_file); diff --git a/test/test.c b/test/test.c index 09835fd..432911d 100644 --- a/test/test.c +++ b/test/test.c @@ -1,18 +1,31 @@ #include "greatest.h" +#include +#include #include +#include -#include "src/log.h" +#include "../src/log.h" + +const char *base; SUITE_EXTERN(suite_utils); SUITE_EXTERN(suite_option_parser); SUITE_EXTERN(suite_notification); SUITE_EXTERN(suite_markup); +SUITE_EXTERN(suite_misc); SUITE_EXTERN(suite_icon); GREATEST_MAIN_DEFS(); int main(int argc, char *argv[]) { + char *prog = realpath(argv[0], NULL); + if (!prog) { + fprintf(stderr, "Cannot determine actual path of test executable: %s\n", strerror(errno)); + exit(1); + } + base = dirname(prog); + // do not print out warning messages, when executing tests dunst_log_init(true); @@ -21,7 +34,11 @@ int main(int argc, char *argv[]) { RUN_SUITE(suite_option_parser); RUN_SUITE(suite_notification); RUN_SUITE(suite_markup); + RUN_SUITE(suite_misc); RUN_SUITE(suite_icon); GREATEST_MAIN_END(); + + base = NULL; + free(prog); } /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/test/utils.c b/test/utils.c index 91e99fb..bb79375 100644 --- a/test/utils.c +++ b/test/utils.c @@ -1,7 +1,5 @@ +#include "../src/utils.c" #include "greatest.h" -#include "src/utils.h" - -#include TEST test_string_replace_char(void) {