From 0f47066b171ba99fa7ac68bb3ccf0e92b18e78ab Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 4 Mar 2014 22:57:52 -0600 Subject: update the header / menuitem text / accessible text to reflect the changes in https://wiki.ubuntu.com/Power?action=diff&rev2=44&rev1=43#Title --- tests/Makefile.am | 2 +- tests/test-device.cc | 152 +++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 113 insertions(+), 41 deletions(-) (limited to 'tests') diff --git a/tests/Makefile.am b/tests/Makefile.am index 5c7d802..47b3e84 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -18,7 +18,7 @@ nodist_libgtest_a_SOURCES = \ $(GTEST_SOURCE)/src/gtest-all.cc \ $(GTEST_SOURCE)/src/gtest_main.cc -AM_CPPFLAGS = $(GTEST_CPPFLAGS) -I${top_srcdir}/src -Wall -Werror +AM_CPPFLAGS = $(GTEST_CPPFLAGS) -I${top_srcdir}/src -Wall -Werror -std=c++11 AM_CXXFLAGS = $(GTEST_CXXFLAGS) ### diff --git a/tests/test-device.cc b/tests/test-device.cc index 2762d4a..dfbba59 100644 --- a/tests/test-device.cc +++ b/tests/test-device.cc @@ -72,12 +72,11 @@ class DeviceTest : public ::testing::Test void check_label (const IndicatorPowerDevice * device, const char * expected_label) { - char * label; - - label = indicator_power_device_get_label (device); + char label[128]; + indicator_power_device_get_readable_text (device, label, sizeof(label)); + if (expected_label == nullptr) + expected_label = ""; EXPECT_STREQ (expected_label, label); - - g_free (label); } void check_header (const IndicatorPowerDevice * device, @@ -86,32 +85,23 @@ class DeviceTest : public ::testing::Test const char * expected_percent, const char * expected_a11y) { - char * label; - char * a11y; - - indicator_power_device_get_header (device, true, true, &label, &a11y); - EXPECT_STREQ (expected_time_and_percent, label); - EXPECT_STREQ (expected_a11y, a11y); - g_free (label); - g_free (a11y); - - indicator_power_device_get_header (device, true, false, &label, &a11y); - EXPECT_STREQ (expected_time, label); - EXPECT_STREQ (expected_a11y, a11y); - g_free (label); - g_free (a11y); - - indicator_power_device_get_header (device, false, true, &label, &a11y); - EXPECT_STREQ (expected_percent, label); - EXPECT_STREQ (expected_a11y, a11y); - g_free (label); - g_free (a11y); - - indicator_power_device_get_header (device, false, false, &label, &a11y); - ASSERT_TRUE (!label || !*label); - EXPECT_STREQ (expected_a11y, a11y); - g_free (label); - g_free (a11y); + char a11y[128]; + char title[128]; + + indicator_power_device_get_readable_title (device, title, sizeof(title), true, true); + EXPECT_STREQ (expected_time_and_percent ? expected_time_and_percent : "", title); + + indicator_power_device_get_readable_title (device, title, sizeof(title), true, false); + EXPECT_STREQ (expected_time ? expected_time : "", title); + + indicator_power_device_get_readable_title (device, title, sizeof(title), false, true); + EXPECT_STREQ (expected_percent ? expected_percent : "", title); + + indicator_power_device_get_readable_title (device, title, sizeof(title), false, false); + EXPECT_STREQ ("", title); + + indicator_power_device_get_accessible_title (device, a11y, sizeof(a11y), false, false); + EXPECT_STREQ (expected_a11y ? expected_a11y : "", a11y); } }; @@ -481,14 +471,16 @@ TEST_F(DeviceTest, Labels) g_setenv ("LANG", "en_US.UTF-8", TRUE); // bad args: NULL device - log_count_ipower_expected += 5; + log_count_ipower_expected++; check_label (NULL, NULL); + log_count_ipower_expected += 5; check_header (NULL, NULL, NULL, NULL, NULL); // bad args: a GObject that isn't a device - log_count_ipower_expected += 5; GObject * o = G_OBJECT(g_cancellable_new()); + log_count_ipower_expected++; check_label ((IndicatorPowerDevice*)o, NULL); + log_count_ipower_expected += 5; check_header (NULL, NULL, NULL, NULL, NULL); g_object_unref (o); @@ -509,7 +501,7 @@ TEST_F(DeviceTest, Labels) check_header (device, "(1:01, 50%)", "(1:01)", "(50%)", - "Battery (1 hour 1 minute to charge, 50%)"); + "Battery (1 hour 1 minute to charge)"); // discharging, < 12 hours left g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY, @@ -521,7 +513,7 @@ TEST_F(DeviceTest, Labels) check_header (device, "(1:01, 50%)", "(1:01)", "(50%)", - "Battery (1 hour 1 minute left, 50%)"); + "Battery (1 hour 1 minute left)"); // discharging, > 24 hours left // we don't show the clock time when > 24 hours discharging @@ -534,7 +526,7 @@ TEST_F(DeviceTest, Labels) check_header (device, "(50%)", "", "(50%)", - "Battery (50%)"); + "Battery"); // fully charged g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY, @@ -546,7 +538,7 @@ TEST_F(DeviceTest, Labels) check_header (device, "(100%)", "", "(100%)", - "Battery (charged, 100%)"); + "Battery (charged)"); // percentage but no time estimate g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY, @@ -558,7 +550,7 @@ TEST_F(DeviceTest, Labels) check_header (device, "(estimating…, 50%)", "(estimating…)", "(50%)", - "Battery (estimating…, 50%)"); + "Battery (estimating…)"); // no percentage, no time estimate g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY, @@ -566,8 +558,8 @@ TEST_F(DeviceTest, Labels) INDICATOR_POWER_DEVICE_PERCENTAGE, 0.0, INDICATOR_POWER_DEVICE_TIME, guint64(0), NULL); - check_label (device, "Battery (not present)"); - check_header (device, "", "", "", "Battery (not present)"); + check_label (device, "Battery"); + check_header (device, "", "", "", "Battery"); // power line g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_LINE_POWER, @@ -584,6 +576,84 @@ TEST_F(DeviceTest, Labels) g_free (real_lang); } + +TEST_F(DeviceTest, Inestimable___this_takes_80_seconds) +{ + // set our language so that i18n won't break these tests + auto real_lang = g_strdup(g_getenv ("LANG")); + g_setenv ("LANG", "en_US.UTF-8", true); + + // set up the main loop + auto loop = g_main_loop_new (nullptr, false); + auto loop_quit_sourcefunc = [](gpointer l){ + g_main_loop_quit(static_cast(l)); + return G_SOURCE_REMOVE; + }; + + auto device = INDICATOR_POWER_DEVICE (g_object_new (INDICATOR_POWER_DEVICE_TYPE, nullptr)); + auto o = G_OBJECT(device); + + // percentage but no time estimate + auto timer = g_timer_new (); + g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY, + INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING, + INDICATOR_POWER_DEVICE_PERCENTAGE, 50.0, + INDICATOR_POWER_DEVICE_TIME, guint64(0), + nullptr); + + /* + * “estimating…” if the time remaining has been inestimable for + * less than 30 seconds; otherwise “unknown” if the time remaining + * has been inestimable for between 30 seconds and one minute; + * otherwise the empty string. + */ + for (;;) + { + g_timeout_add_seconds (1, loop_quit_sourcefunc, loop); + g_main_loop_run (loop); + + const auto elapsed = g_timer_elapsed (timer, nullptr); + + if (elapsed < 30) + { + check_label (device, "Battery (estimating…)"); + check_header (device, "(estimating…, 50%)", + "(estimating…)", + "(50%)", + "Battery (estimating…)"); + } + else if (elapsed < 60) + { + check_label (device, "Battery (unknown)"); + check_header (device, "(unknown, 50%)", + "(unknown)", + "(50%)", + "Battery (unknown)"); + } + else if (elapsed < 80) + { + check_label (device, "Battery"); + check_header (device, "(50%)", + "", + "(50%)", + "Battery"); + } + else + { + break; + } + } + + g_main_loop_unref (loop); + + // cleanup + g_timer_destroy (timer); + g_object_unref (o); + g_setenv ("LANG", real_lang, TRUE); + g_free (real_lang); +} + + /* The menu title should tell you at a glance what you need to know most: what device will lose power soonest (and optionally when), or otherwise which device will take longest to charge (and optionally how long it will take). */ @@ -645,10 +715,12 @@ TEST_F(DeviceTest, ChoosePrimary) INDICATOR_POWER_DEVICE_PERCENTAGE, tests[j].percentage, NULL); ASSERT_EQ (a, indicator_power_service_choose_primary_device(device_list)); + g_object_unref (G_OBJECT(a)); /* reverse the list to check that list order doesn't matter */ device_list = g_list_reverse (device_list); ASSERT_EQ (a, indicator_power_service_choose_primary_device(device_list)); + g_object_unref (G_OBJECT(a)); } } -- cgit v1.2.3 From 9936e22d5e70cd10988f328e8d86b1e5bc93ede9 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Thu, 13 Mar 2014 09:05:34 -0500 Subject: in the new indicator_power_device_get_*() functions, use heap-allocated strings rather than relying on g_snprintf(). --- src/device.c | 147 +++++++++++++++++++++------------------------------ src/device.h | 16 ++---- src/service.c | 43 ++++++++------- tests/test-device.cc | 45 ++++++++-------- 4 files changed, 113 insertions(+), 138 deletions(-) (limited to 'tests') diff --git a/src/device.c b/src/device.c index e7384ee..37b1d8b 100644 --- a/src/device.c +++ b/src/device.c @@ -543,11 +543,10 @@ device_kind_to_localised_string (UpDeviceKind kind) * between 30 seconds and one minute; otherwise * * the empty string. */ -static void -get_brief_time_remaining (const IndicatorPowerDevice * device, - char * str, - gulong size) +static char * +get_brief_time_remaining (const IndicatorPowerDevice * device) { + gchar * str = NULL; const IndicatorPowerDevicePrivate * p = device->priv; if (p->time > 0) @@ -556,7 +555,7 @@ get_brief_time_remaining (const IndicatorPowerDevice * device, int hours = minutes / 60; minutes %= 60; - g_snprintf (str, size, "%0d:%02d", hours, minutes); + str = g_strdup_printf("%0d:%02d", hours, minutes); } else if (p->inestimable != NULL) { @@ -564,21 +563,15 @@ get_brief_time_remaining (const IndicatorPowerDevice * device, if (elapsed < 30) { - g_snprintf (str, size, _("estimating…")); + str = g_strdup_printf (_("estimating…")); } else if (elapsed < 60) { - g_snprintf (str, size, _("unknown")); + str = g_strdup_printf (_("unknown")); } - else - { - *str = '\0'; - } - } - else - { - *str = '\0'; } + + return str; } /** @@ -588,16 +581,12 @@ get_brief_time_remaining (const IndicatorPowerDevice * device, * * if the component is charging, it should be “H:MM to charge” * * if the component is discharging, it should be “H:MM left”. */ -static void -get_expanded_time_remaining (const IndicatorPowerDevice * device, - char * str, - gulong size) +static char* +get_expanded_time_remaining (const IndicatorPowerDevice * device) { + char * str = NULL; const IndicatorPowerDevicePrivate * p; - g_return_if_fail (str != NULL); - g_return_if_fail (size > 0); - *str = '\0'; g_return_if_fail (INDICATOR_IS_POWER_DEVICE(device)); p = device->priv; @@ -610,35 +599,33 @@ get_expanded_time_remaining (const IndicatorPowerDevice * device, if (p->state == UP_DEVICE_STATE_CHARGING) { - g_snprintf (str, size, _("%0d:%02d to charge"), hours, minutes); + str = g_strdup_printf (_("%0d:%02d to charge"), hours, minutes); } else // discharging { - g_snprintf (str, size, _("%0d:%02d left"), hours, minutes); + str = g_strdup_printf (_("%0d:%02d left"), hours, minutes); } } else { - get_brief_time_remaining (device, str, size); + str = get_brief_time_remaining (device); } + + return str; } /** * The '''accessible time-remaining string''' for a component * should be the same as the expanded time-remaining string, * except the H:MM time should be rendered as “''H'' hours ''M'' minutes”, - * or just as “''M'' * minutes” if the time is less than one hour. + * or just as “''M'' minutes” if the time is less than one hour. */ -static void -get_accessible_time_remaining (const IndicatorPowerDevice * device, - char * str, - gulong size) +static char * +get_accessible_time_remaining (const IndicatorPowerDevice * device) { + char * str = NULL; const IndicatorPowerDevicePrivate * p; - g_return_if_fail (str != NULL); - g_return_if_fail (size > 0); - *str = '\0'; g_return_if_fail (INDICATOR_IS_POWER_DEVICE(device)); p = device->priv; @@ -652,28 +639,30 @@ get_accessible_time_remaining (const IndicatorPowerDevice * device, if (p->state == UP_DEVICE_STATE_CHARGING) { if (hours > 0) - g_snprintf (str, size, _("%d %s %d %s to charge"), + str = g_strdup_printf (_("%d %s %d %s to charge"), hours, g_dngettext (NULL, "hour", "hours", hours), minutes, g_dngettext (NULL, "minute", "minutes", minutes)); else - g_snprintf (str, size, _("%d %s to charge"), + str = g_strdup_printf (_("%d %s to charge"), minutes, g_dngettext (NULL, "minute", "minutes", minutes)); } else // discharging { if (hours > 0) - g_snprintf (str, size, _("%d %s %d %s left"), + str = g_strdup_printf (_("%d %s %d %s left"), hours, g_dngettext (NULL, "hour", "hours", hours), minutes, g_dngettext (NULL, "minute", "minutes", minutes)); else - g_snprintf (str, size, _("%d %s left"), + str = g_strdup_printf (_("%d %s left"), minutes, g_dngettext (NULL, "minute", "minutes", minutes)); } } else { - get_brief_time_remaining (device, str, size); + str = get_brief_time_remaining (device); } + + return str; } /** @@ -709,66 +698,55 @@ time_is_relevant (const IndicatorPowerDevice * device) * visible label, except with the accessible time-remaining string * instead of the expanded time-remaining string. */ -static void +static char * get_menuitem_text (const IndicatorPowerDevice * device, - gchar * str, - gulong size, gboolean accessible) { + char * str = NULL; const IndicatorPowerDevicePrivate * p = device->priv; const char * kind_str = device_kind_to_localised_string (p->kind); if (p->state == UP_DEVICE_STATE_FULLY_CHARGED) { - g_snprintf (str, size, _("%s (charged)"), kind_str); + str = g_strdup_printf (_("%s (charged)"), kind_str); } else { - char buf[64]; + char * time_str = NULL; if (time_is_relevant (device)) { if (accessible) - get_accessible_time_remaining (device, buf, sizeof(buf)); + time_str = get_accessible_time_remaining (device); else - get_expanded_time_remaining (device, buf, sizeof(buf)); - } - else - { - *buf = '\0'; + time_str = get_expanded_time_remaining (device); } - if (*buf) - g_snprintf (str, size, _("%s (%s)"), kind_str, buf); + if (time_str && *time_str) + str = g_strdup_printf (_("%s (%s)"), kind_str, time_str); else - g_strlcpy (str, kind_str, size); + str = g_strdup (kind_str); + + g_free (time_str); } + + return str; } -void -indicator_power_device_get_readable_text (const IndicatorPowerDevice * device, - gchar * str, - gulong size) +char * +indicator_power_device_get_readable_text (const IndicatorPowerDevice * device) { - g_return_if_fail (str != NULL); - g_return_if_fail (size > 0); - *str = '\0'; g_return_if_fail (INDICATOR_IS_POWER_DEVICE(device)); - get_menuitem_text (device, str, size, FALSE); + return get_menuitem_text (device, FALSE); } -void -indicator_power_device_get_accessible_text (const IndicatorPowerDevice * device, - gchar * str, - gulong size) +char * +indicator_power_device_get_accessible_text (const IndicatorPowerDevice * device) { - g_return_if_fail (str != NULL); - g_return_if_fail (size > 0); - *str = '\0'; g_return_if_fail (INDICATOR_IS_POWER_DEVICE(device)); - get_menuitem_text (device, str, size, TRUE); + return get_menuitem_text (device, TRUE); } /** @@ -783,19 +761,15 @@ indicator_power_device_get_accessible_text (const IndicatorPowerDevice * device, * * If both conditions are true, the time and percentage should be separated by a space. */ -void +char* indicator_power_device_get_readable_title (const IndicatorPowerDevice * device, - gchar * str, - gulong size, gboolean want_time, gboolean want_percent) { - char tr[64]; + char * str = NULL; + char * time_str = NULL; const IndicatorPowerDevicePrivate * p; - g_return_if_fail (str != NULL); - g_return_if_fail (size > 0); - *str = '\0'; g_return_if_fail (INDICATOR_IS_POWER_DEVICE(device)); p = device->priv; @@ -811,42 +785,41 @@ indicator_power_device_get_readable_title (const IndicatorPowerDevice * device, // try to build the time-remaining string if (want_time) { - get_brief_time_remaining (device, tr, sizeof(tr)); - - if (!*tr) - want_time = FALSE; + time_str = get_brief_time_remaining (device); + want_time = time_str && *time_str; } if (want_time && want_percent) { - g_snprintf (str, size, _("(%s, %.0lf%%)"), tr, p->percentage); + str = g_strdup_printf (_("(%s, %.0lf%%)"), time_str, p->percentage); } else if (want_time) { - g_snprintf (str, size, _("(%s)"), tr); + str = g_strdup_printf (_("(%s)"), time_str); } else if (want_percent) { - g_snprintf (str, size, _("(%.0lf%%)"), p->percentage); + str = g_strdup_printf (_("(%.0lf%%)"), p->percentage); } else { - *str = '\0'; + str = NULL; } + + g_free (time_str); + return str; } /** * Regardless, the accessible name for the whole menu title should be the same * as the accessible name for that thing’s component inside the menu itself. */ -void +char * indicator_power_device_get_accessible_title (const IndicatorPowerDevice * device, - gchar * str, - gulong size, gboolean want_time G_GNUC_UNUSED, gboolean want_percent G_GNUC_UNUSED) { - indicator_power_device_get_accessible_text (device, str, size); + return indicator_power_device_get_accessible_text (device); } /*** diff --git a/src/device.h b/src/device.h index 65c6767..3a10f89 100644 --- a/src/device.h +++ b/src/device.h @@ -126,23 +126,15 @@ GStrv indicator_power_device_get_icon_names (const IndicatorPower GIcon * indicator_power_device_get_gicon (const IndicatorPowerDevice * device); -void indicator_power_device_get_readable_text (const IndicatorPowerDevice * device, - gchar * str, - gulong size); +char * indicator_power_device_get_readable_text (const IndicatorPowerDevice * device); -void indicator_power_device_get_accessible_text (const IndicatorPowerDevice * device, - gchar * str, - gulong size); +char * indicator_power_device_get_accessible_text (const IndicatorPowerDevice * device); -void indicator_power_device_get_readable_title (const IndicatorPowerDevice * device, - gchar * str, - gulong size, +char * indicator_power_device_get_readable_title (const IndicatorPowerDevice * device, gboolean want_time, gboolean want_percent); -void indicator_power_device_get_accessible_title (const IndicatorPowerDevice * device, - gchar * str, - gulong size, +char * indicator_power_device_get_accessible_title (const IndicatorPowerDevice * device, gboolean want_time, gboolean want_percent); diff --git a/src/service.c b/src/service.c index 248f953..405ad96 100644 --- a/src/service.c +++ b/src/service.c @@ -323,26 +323,32 @@ create_header_state (IndicatorPowerService * self) if (p->primary_device != NULL) { - char buf[128]; + char * title; GIcon * icon; const gboolean want_time = g_settings_get_boolean (p->settings, SETTINGS_SHOW_TIME_S); const gboolean want_percent = g_settings_get_boolean (p->settings, SETTINGS_SHOW_PERCENTAGE_S); - indicator_power_device_get_readable_title (p->primary_device, - buf, sizeof(buf), - want_time, - want_percent); - if (*buf) - g_variant_builder_add (&b, "{sv}", "label", g_variant_new_string (buf)); - - - indicator_power_device_get_accessible_title (p->primary_device, - buf, sizeof(buf), - want_time, - want_percent); - if (*buf) - g_variant_builder_add (&b, "{sv}", "accessible-desc", g_variant_new_string (buf)); + title = indicator_power_device_get_readable_title (p->primary_device, + want_time, + want_percent); + if (title) + { + if (*title) + g_variant_builder_add (&b, "{sv}", "label", g_variant_new_take_string (title)); + else + g_free (title); + } + title = indicator_power_device_get_accessible_title (p->primary_device, + want_time, + want_percent); + if (title) + { + if (*title) + g_variant_builder_add (&b, "{sv}", "accessible-desc", g_variant_new_take_string (title)); + else + g_free (title); + } if ((icon = indicator_power_device_get_gicon (p->primary_device))) { @@ -375,12 +381,13 @@ append_device_to_menu (GMenu * menu, const IndicatorPowerDevice * device) if (kind != UP_DEVICE_KIND_LINE_POWER) { - char buf[128]; + char * label; GMenuItem * item; GIcon * icon; - indicator_power_device_get_readable_text (device, buf, sizeof(buf)); - item = g_menu_item_new (buf, "indicator.activate-statistics"); + label = indicator_power_device_get_readable_text (device); + item = g_menu_item_new (label, "indicator.activate-statistics"); + g_free (label); if ((icon = indicator_power_device_get_gicon (device))) { diff --git a/tests/test-device.cc b/tests/test-device.cc index dfbba59..dee0aa6 100644 --- a/tests/test-device.cc +++ b/tests/test-device.cc @@ -72,11 +72,9 @@ class DeviceTest : public ::testing::Test void check_label (const IndicatorPowerDevice * device, const char * expected_label) { - char label[128]; - indicator_power_device_get_readable_text (device, label, sizeof(label)); - if (expected_label == nullptr) - expected_label = ""; + char * label = indicator_power_device_get_readable_text (device); EXPECT_STREQ (expected_label, label); + g_free (label); } void check_header (const IndicatorPowerDevice * device, @@ -85,23 +83,28 @@ class DeviceTest : public ::testing::Test const char * expected_percent, const char * expected_a11y) { - char a11y[128]; - char title[128]; + char * a11y = NULL; + char * title = NULL; - indicator_power_device_get_readable_title (device, title, sizeof(title), true, true); - EXPECT_STREQ (expected_time_and_percent ? expected_time_and_percent : "", title); + title = indicator_power_device_get_readable_title (device, true, true); + EXPECT_STREQ (expected_time_and_percent, title); + g_free (title); - indicator_power_device_get_readable_title (device, title, sizeof(title), true, false); - EXPECT_STREQ (expected_time ? expected_time : "", title); + title = indicator_power_device_get_readable_title (device, true, false); + EXPECT_STREQ (expected_time, title); + g_free (title); - indicator_power_device_get_readable_title (device, title, sizeof(title), false, true); - EXPECT_STREQ (expected_percent ? expected_percent : "", title); + title = indicator_power_device_get_readable_title (device, false, true); + EXPECT_STREQ (expected_percent, title); + g_free (title); - indicator_power_device_get_readable_title (device, title, sizeof(title), false, false); - EXPECT_STREQ ("", title); + title = indicator_power_device_get_readable_title (device, false, false); + EXPECT_STREQ (NULL, title); + g_free (title); - indicator_power_device_get_accessible_title (device, a11y, sizeof(a11y), false, false); - EXPECT_STREQ (expected_a11y ? expected_a11y : "", a11y); + a11y = indicator_power_device_get_accessible_title (device, false, false); + EXPECT_STREQ (expected_a11y, a11y); + g_free (a11y); } }; @@ -524,7 +527,7 @@ TEST_F(DeviceTest, Labels) NULL); check_label (device, "Battery"); check_header (device, "(50%)", - "", + NULL, "(50%)", "Battery"); @@ -536,7 +539,7 @@ TEST_F(DeviceTest, Labels) NULL); check_label (device, "Battery (charged)"); check_header (device, "(100%)", - "", + NULL, "(100%)", "Battery (charged)"); @@ -559,7 +562,7 @@ TEST_F(DeviceTest, Labels) INDICATOR_POWER_DEVICE_TIME, guint64(0), NULL); check_label (device, "Battery"); - check_header (device, "", "", "", "Battery"); + check_header (device, NULL, NULL, NULL, "Battery"); // power line g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_LINE_POWER, @@ -568,7 +571,7 @@ TEST_F(DeviceTest, Labels) INDICATOR_POWER_DEVICE_TIME, guint64(0), NULL); check_label (device, "AC Adapter"); - check_header (device, "", "", "", "AC Adapter"); + check_header (device, NULL, NULL, NULL, "AC Adapter"); // cleanup g_object_unref(o); @@ -634,7 +637,7 @@ TEST_F(DeviceTest, Inestimable___this_takes_80_seconds) { check_label (device, "Battery"); check_header (device, "(50%)", - "", + NULL, "(50%)", "Battery"); } -- cgit v1.2.3 From b1f0d4011ca8ff5658e5b8807350f583d41af21b Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Thu, 13 Mar 2014 10:32:04 -0500 Subject: when expecting a NULL string, use EXPECT_EQ(NULL, str) --- tests/test-device.cc | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'tests') diff --git a/tests/test-device.cc b/tests/test-device.cc index dee0aa6..4d4a89f 100644 --- a/tests/test-device.cc +++ b/tests/test-device.cc @@ -87,23 +87,35 @@ class DeviceTest : public ::testing::Test char * title = NULL; title = indicator_power_device_get_readable_title (device, true, true); - EXPECT_STREQ (expected_time_and_percent, title); + if (expected_time_and_percent) + EXPECT_STREQ (expected_time_and_percent, title); + else + EXPECT_EQ(NULL, title); g_free (title); title = indicator_power_device_get_readable_title (device, true, false); - EXPECT_STREQ (expected_time, title); + if (expected_time) + EXPECT_STREQ (expected_time, title); + else + EXPECT_EQ(NULL, title); g_free (title); title = indicator_power_device_get_readable_title (device, false, true); - EXPECT_STREQ (expected_percent, title); + if (expected_percent) + EXPECT_STREQ (expected_percent, title); + else + EXPECT_EQ(NULL, title); g_free (title); title = indicator_power_device_get_readable_title (device, false, false); - EXPECT_STREQ (NULL, title); + EXPECT_EQ(NULL, title); g_free (title); a11y = indicator_power_device_get_accessible_title (device, false, false); - EXPECT_STREQ (expected_a11y, a11y); + if (expected_a11y) + EXPECT_STREQ (expected_a11y, a11y); + else + EXPECT_EQ(NULL, a11y); g_free (a11y); } }; -- cgit v1.2.3 From b3ec90e07e00f3f28665207987bb9fb73153664b Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 19 Mar 2014 14:15:54 -0500 Subject: when choosing a primary device and more than one battery is found, accumulate their percentages and time-remaining properties as per the spec revisions in bug #880881. --- src/service.c | 130 +++++++++++++++++++++++++++++++++++++++-- tests/test-device.cc | 160 ++++++++++++++++++++++++++++++--------------------- 2 files changed, 220 insertions(+), 70 deletions(-) (limited to 'tests') diff --git a/src/service.c b/src/service.c index 248f953..e042e9e 100644 --- a/src/service.c +++ b/src/service.c @@ -1125,6 +1125,129 @@ indicator_power_service_set_device_provider (IndicatorPowerService * self, } } +/* If a device has multiple batteries and uses only one of them at a time, + they should be presented as separate items inside the battery menu, + but everywhere else they should be aggregated (bug 880881). + Their percentages should be averaged. If any are discharging, + the aggregated time remaining should be the maximum of the times + for all those that are discharging, plus the sum of the times + for all those that are idle. Otherwise, the aggregated time remaining + should be the the maximum of the times for all those that are charging. */ +static IndicatorPowerDevice * +create_totalled_battery_device (const GList * devices) +{ + const GList * l; + guint n_charged = 0; + guint n_charging = 0; + guint n_discharging = 0; + guint n_batteries = 0; + double sum_percent = 0; + time_t max_discharge_time = 0; + time_t max_charge_time = 0; + time_t sum_charged_time = 0; + IndicatorPowerDevice * device = NULL; + + for (l=devices; l!=NULL; l=l->next) + { + const IndicatorPowerDevice * device = INDICATOR_POWER_DEVICE(l->data); + + if (indicator_power_device_get_kind(device) == UP_DEVICE_KIND_BATTERY) + { + const double percent = indicator_power_device_get_percentage (device); + const time_t t = indicator_power_device_get_time (device); + const UpDeviceState state = indicator_power_device_get_state (device); + + ++n_batteries; + + if (percent > 0.01) + sum_percent += percent; + + if (state == UP_DEVICE_STATE_CHARGING) + { + ++n_charging; + max_charge_time = MAX(max_charge_time, t); + } + else if (state == UP_DEVICE_STATE_DISCHARGING) + { + ++n_discharging; + max_discharge_time = MAX(max_discharge_time, t); + } + else if (state == UP_DEVICE_STATE_FULLY_CHARGED) + { + ++n_charged; + sum_charged_time += t; + } + } + } + + if (n_batteries > 1) + { + const double percent = sum_percent / n_batteries; + UpDeviceState state; + time_t time_left; + + if (n_discharging > 0) + { + state = UP_DEVICE_STATE_DISCHARGING; + time_left = max_discharge_time + sum_charged_time; + } + else if (n_charging > 0) + { + state = UP_DEVICE_STATE_CHARGING; + time_left = max_charge_time; + } + else if (n_charged > 0) + { + state = UP_DEVICE_STATE_FULLY_CHARGED; + time_left = 0; + } + else + { + state = UP_DEVICE_STATE_UNKNOWN; + time_left = 0; + } + + device = indicator_power_device_new (NULL, + UP_DEVICE_KIND_BATTERY, + percent, + state, + time_left); + } + + return device; +} + +/** + * If there are multiple UP_DEVICE_KIND_BATTERY devices in the list, + * they're merged into a new 'totalled' device representing the sum of them. + * + * Returns: (element-type IndicatorPowerDevice)(transfer full): a list of devices + */ +static GList* +merge_batteries_together (GList * devices) +{ + GList * ret; + IndicatorPowerDevice * merged_device; + + if ((merged_device = create_totalled_battery_device (devices))) + { + GList * l; + + ret = g_list_append (NULL, merged_device); + + for (l=devices; l!=NULL; l=l->next) + if (indicator_power_device_get_kind(INDICATOR_POWER_DEVICE(l->data)) != UP_DEVICE_KIND_BATTERY) + ret = g_list_append (ret, g_object_ref(l->data)); + } + else /* not enough batteries to merge */ + { + ret = g_list_copy (devices); + g_list_foreach (ret, (GFunc)g_object_ref, NULL); + } + + return ret; +} + IndicatorPowerDevice * indicator_power_service_choose_primary_device (GList * devices) { @@ -1132,13 +1255,10 @@ indicator_power_service_choose_primary_device (GList * devices) if (devices != NULL) { - GList * tmp; - - tmp = g_list_copy (devices); + GList * tmp = merge_batteries_together (devices); tmp = g_list_sort (tmp, device_compare_func); primary = g_object_ref (tmp->data); - - g_list_free (tmp); + g_list_free_full (tmp, (GDestroyNotify)g_object_unref); } return primary; diff --git a/tests/test-device.cc b/tests/test-device.cc index dfbba59..010dd92 100644 --- a/tests/test-device.cc +++ b/tests/test-device.cc @@ -19,6 +19,7 @@ with this program. If not, see . #include #include +#include // ceil() #include "device.h" #include "service.h" @@ -653,77 +654,106 @@ TEST_F(DeviceTest, Inestimable___this_takes_80_seconds) g_free (real_lang); } - -/* The menu title should tell you at a glance what you need to know most: what - device will lose power soonest (and optionally when), or otherwise which - device will take longest to charge (and optionally how long it will take). */ +/* If a device has multiple batteries and uses only one of them at a time, + they should be presented as separate items inside the battery menu, + but everywhere else they should be aggregated (bug 880881). + Their percentages should be averaged. If any are discharging, + the aggregated time remaining should be the maximum of the times + for all those that are discharging, plus the sum of the times + for all those that are idle. Otherwise, the aggregated time remaining + should be the the maximum of the times for all those that are charging. */ TEST_F(DeviceTest, ChoosePrimary) { - GList * device_list; - IndicatorPowerDevice * a; - IndicatorPowerDevice * b; - - a = indicator_power_device_new ("/org/freedesktop/UPower/devices/mouse", - UP_DEVICE_KIND_MOUSE, - 0.0, - UP_DEVICE_STATE_DISCHARGING, - 0); - b = indicator_power_device_new ("/org/freedesktop/UPower/devices/battery", - UP_DEVICE_KIND_BATTERY, - 0.0, - UP_DEVICE_STATE_DISCHARGING, - 0); - - /* device states + time left to {discharge,charge} + % of charge left, - sorted in order of preference wrt the spec's criteria. - So tests[i] should be picked over any test with an index greater than i */ - struct { - int kind; - int state; + struct Description + { + const char * path; + UpDeviceKind kind; + UpDeviceState state; guint64 time; double percentage; - } tests[] = { - { UP_DEVICE_KIND_BATTERY, UP_DEVICE_STATE_DISCHARGING, 49, 50.0 }, - { UP_DEVICE_KIND_BATTERY, UP_DEVICE_STATE_DISCHARGING, 50, 50.0 }, - { UP_DEVICE_KIND_BATTERY, UP_DEVICE_STATE_DISCHARGING, 50, 100.0 }, - { UP_DEVICE_KIND_BATTERY, UP_DEVICE_STATE_DISCHARGING, 51, 50.0 }, - { UP_DEVICE_KIND_BATTERY, UP_DEVICE_STATE_CHARGING, 50, 50.0 }, - { UP_DEVICE_KIND_BATTERY, UP_DEVICE_STATE_CHARGING, 49, 50.0 }, - { UP_DEVICE_KIND_BATTERY, UP_DEVICE_STATE_CHARGING, 49, 100.0 }, - { UP_DEVICE_KIND_BATTERY, UP_DEVICE_STATE_CHARGING, 48, 50.0 }, - { UP_DEVICE_KIND_BATTERY, UP_DEVICE_STATE_FULLY_CHARGED, 0, 50.0 }, - { UP_DEVICE_KIND_KEYBOARD, UP_DEVICE_STATE_FULLY_CHARGED, 0, 50.0 }, - { UP_DEVICE_KIND_LINE_POWER, UP_DEVICE_STATE_UNKNOWN, 0, 0.0 } }; - device_list = NULL; - device_list = g_list_append (device_list, a); - device_list = g_list_append (device_list, b); + const Description descriptions[] = { + { "/some/path/d0", UP_DEVICE_KIND_BATTERY, UP_DEVICE_STATE_DISCHARGING, 10, 60.0 }, // 0 + { "/some/path/d1", UP_DEVICE_KIND_BATTERY, UP_DEVICE_STATE_DISCHARGING, 20, 80.0 }, // 1 + { "/some/path/d2", UP_DEVICE_KIND_BATTERY, UP_DEVICE_STATE_DISCHARGING, 30, 100.0 }, // 2 - for (int i=0, n=G_N_ELEMENTS(tests); i devices; + for(const auto& desc : descriptions) + devices.push_back(indicator_power_device_new(desc.path, desc.kind, desc.percentage, desc.state, desc.time)); + + const struct { + std::vector device_indices; + Description expected; + } tests[] = { + + { { 0 }, descriptions[0] }, // 1 discharging + { { 0, 1 }, { nullptr, UP_DEVICE_KIND_BATTERY, UP_DEVICE_STATE_DISCHARGING, 20, 70.0 } }, // 2 discharging + { { 1, 2 }, { nullptr, UP_DEVICE_KIND_BATTERY, UP_DEVICE_STATE_DISCHARGING, 30, 90.0 } }, // 2 discharging + { { 0, 1, 2 }, { nullptr, UP_DEVICE_KIND_BATTERY, UP_DEVICE_STATE_DISCHARGING, 30, 80.0 } }, // 3 discharging + + { { 3 }, descriptions[3] }, // 1 charging + { { 3, 4 }, { nullptr, UP_DEVICE_KIND_BATTERY, UP_DEVICE_STATE_CHARGING, 20, 70.0 } }, // 2 charging + { { 4, 5 }, { nullptr, UP_DEVICE_KIND_BATTERY, UP_DEVICE_STATE_CHARGING, 30, 90.0 } }, // 2 charging + { { 3, 4, 5 }, { nullptr, UP_DEVICE_KIND_BATTERY, UP_DEVICE_STATE_CHARGING, 30, 80.0 } }, // 3 charging + + { { 6 }, descriptions[6] }, // 1 charged + { { 6, 0 }, { nullptr, UP_DEVICE_KIND_BATTERY, UP_DEVICE_STATE_DISCHARGING, 10, 80.0 } }, // 1 charged, 1 discharging + { { 6, 3 }, { nullptr, UP_DEVICE_KIND_BATTERY, UP_DEVICE_STATE_CHARGING, 10, 80.0 } }, // 1 charged, 1 charging + { { 6, 0, 3 }, { nullptr, UP_DEVICE_KIND_BATTERY, UP_DEVICE_STATE_DISCHARGING, 10, 73.3 } }, // 1 charged, 1 charging, 1 discharging + + { { 0, 7 }, descriptions[0] }, // 1 discharging battery, 1 discharging mouse. pick the one with the least time left. + { { 2, 7 }, descriptions[7] }, // 1 discharging battery, 1 discharging mouse. pick the one with the least time left. + + { { 0, 8 }, descriptions[0] }, // 1 discharging battery, 1 fully-charged mouse. pick the one that's discharging. + { { 6, 7 }, descriptions[7] }, // 1 discharging mouse, 1 fully-charged battery. pick the one that's discharging. + + { { 0, 9 }, descriptions[0] }, // everything comes before power lines + { { 3, 9 }, descriptions[3] }, + { { 7, 9 }, descriptions[7] } + }; + + for(const auto& test : tests) + { + const auto& x = test.expected; + + GList * device_glist = nullptr; + for(const auto& i : test.device_indices) + device_glist = g_list_append(device_glist, devices[i]); + + auto primary = indicator_power_service_choose_primary_device(device_glist); + EXPECT_STREQ(x.path, indicator_power_device_get_object_path(primary)); + EXPECT_EQ(x.kind, indicator_power_device_get_kind(primary)); + EXPECT_EQ(x.state, indicator_power_device_get_state(primary)); + EXPECT_EQ(x.time, indicator_power_device_get_time(primary)); + EXPECT_EQ((int)ceil(x.percentage), (int)ceil(indicator_power_device_get_percentage(primary))); + g_object_unref(primary); + + // reverse the list and repeat the test + // to confirm that list order doesn't matter + device_glist = g_list_reverse (device_glist); + primary = indicator_power_service_choose_primary_device (device_glist); + EXPECT_STREQ(x.path, indicator_power_device_get_object_path(primary)); + EXPECT_EQ(x.kind, indicator_power_device_get_kind(primary)); + EXPECT_EQ(x.state, indicator_power_device_get_state(primary)); + EXPECT_EQ(x.time, indicator_power_device_get_time(primary)); + EXPECT_EQ((int)ceil(x.percentage), (int)ceil(indicator_power_device_get_percentage(primary))); + g_object_unref(primary); + + // cleanup + g_list_free(device_glist); + } + + for (auto& device : devices) + g_object_unref (device); } -- cgit v1.2.3 From 0ea6d3db58a5e795dbe7eaf355b56ef4555e3e9f Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 19 Mar 2014 14:35:12 -0500 Subject: add a courtesy message to let observers know that test-device isn't stuck, it's just slow. --- tests/Makefile.am | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'tests') diff --git a/tests/Makefile.am b/tests/Makefile.am index 47b3e84..483bb8c 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -25,6 +25,13 @@ AM_CXXFLAGS = $(GTEST_CXXFLAGS) ### tests: indicator-power-device ### +dear-reader-please-note-the-next-test-takes-90-seconds: + @echo "#!/bin/bash" > $@ + @echo "exit 0" >> $@ + @chmod +x $@ +TESTS += dear-reader-please-note-the-next-test-takes-90-seconds +CLEANFILES += dear-reader-please-note-the-next-test-takes-90-seconds + TEST_LIBS = $(COVERAGE_LDFLAGS) libgtest.a -lpthread TEST_CPPFLAGS = $(SERVICE_DEPS_CFLAGS) $(AM_CPPFLAGS) -- cgit v1.2.3 From 8c874cb5a9f58ab9d1885dabb24e548afaa9b711 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 5 May 2014 10:21:42 -0500 Subject: prefer the 'battery-020-charging' icon to the 'battery-low-charging' one because the former is more precise so its icon is more likely to be close to the actual actual battery level. --- src/device.c | 3 ++- tests/test-device.cc | 15 ++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) (limited to 'tests') diff --git a/src/device.c b/src/device.c index e3b655a..8780d72 100644 --- a/src/device.c +++ b/src/device.c @@ -416,8 +416,9 @@ indicator_power_device_get_icon_names (const IndicatorPowerDevice * device) case UP_DEVICE_STATE_CHARGING: suffix_str = get_device_icon_suffix (percentage); index_str = get_device_icon_index (percentage); - g_ptr_array_add (names, g_strdup_printf ("%s-%s-charging-symbolic", kind_str, suffix_str)); + g_ptr_array_add (names, g_strdup_printf ("%s-%s-charging", kind_str, index_str)); g_ptr_array_add (names, g_strdup_printf ("gpm-%s-%s-charging", kind_str, index_str)); + g_ptr_array_add (names, g_strdup_printf ("%s-%s-charging-symbolic", kind_str, suffix_str)); g_ptr_array_add (names, g_strdup_printf ("%s-%s-charging", kind_str, suffix_str)); break; diff --git a/tests/test-device.cc b/tests/test-device.cc index 96bea80..7d54816 100644 --- a/tests/test-device.cc +++ b/tests/test-device.cc @@ -324,8 +324,9 @@ TEST_F(DeviceTest, IconNames) INDICATOR_POWER_DEVICE_PERCENTAGE, 95.0, NULL); - g_string_append_printf (expected, "%s-full-charging-symbolic;", kind_str); + g_string_append_printf (expected, "%s-100-charging;", kind_str); g_string_append_printf (expected, "gpm-%s-100-charging;", kind_str); + g_string_append_printf (expected, "%s-full-charging-symbolic;", kind_str); g_string_append_printf (expected, "%s-full-charging", kind_str); check_icon_names (device, expected->str); g_string_truncate (expected, 0); @@ -335,8 +336,9 @@ TEST_F(DeviceTest, IconNames) INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_CHARGING, INDICATOR_POWER_DEVICE_PERCENTAGE, 85.0, NULL); - g_string_append_printf (expected, "%s-full-charging-symbolic;", kind_str); + g_string_append_printf (expected, "%s-080-charging;", kind_str); g_string_append_printf (expected, "gpm-%s-080-charging;", kind_str); + g_string_append_printf (expected, "%s-full-charging-symbolic;", kind_str); g_string_append_printf (expected, "%s-full-charging", kind_str); check_icon_names (device, expected->str); g_string_truncate (expected, 0); @@ -346,8 +348,9 @@ TEST_F(DeviceTest, IconNames) INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_CHARGING, INDICATOR_POWER_DEVICE_PERCENTAGE, 50.0, NULL); - g_string_append_printf (expected, "%s-good-charging-symbolic;", kind_str); + g_string_append_printf (expected, "%s-060-charging;", kind_str); g_string_append_printf (expected, "gpm-%s-060-charging;", kind_str); + g_string_append_printf (expected, "%s-good-charging-symbolic;", kind_str); g_string_append_printf (expected, "%s-good-charging", kind_str); check_icon_names (device, expected->str); g_string_truncate (expected, 0); @@ -357,8 +360,9 @@ TEST_F(DeviceTest, IconNames) INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_CHARGING, INDICATOR_POWER_DEVICE_PERCENTAGE, 25.0, NULL); - g_string_append_printf (expected, "%s-low-charging-symbolic;", kind_str); + g_string_append_printf (expected, "%s-020-charging;", kind_str); g_string_append_printf (expected, "gpm-%s-020-charging;", kind_str); + g_string_append_printf (expected, "%s-low-charging-symbolic;", kind_str); g_string_append_printf (expected, "%s-low-charging", kind_str); check_icon_names (device, expected->str); g_string_truncate (expected, 0); @@ -368,8 +372,9 @@ TEST_F(DeviceTest, IconNames) INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_CHARGING, INDICATOR_POWER_DEVICE_PERCENTAGE, 5.0, NULL); - g_string_append_printf (expected, "%s-caution-charging-symbolic;", kind_str); + g_string_append_printf (expected, "%s-000-charging;", kind_str); g_string_append_printf (expected, "gpm-%s-000-charging;", kind_str); + g_string_append_printf (expected, "%s-caution-charging-symbolic;", kind_str); g_string_append_printf (expected, "%s-caution-charging", kind_str); check_icon_names (device, expected->str); g_string_truncate (expected, 0); -- cgit v1.2.3 From 3f29c1a35113bfd2461dca76235f1812c8dfd6ef Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Sun, 13 Jul 2014 23:33:16 -0500 Subject: fix some compiler warnings generated by clang static analyzer --- src/device-provider-upower.c | 10 ++++------ src/device-provider.c | 2 +- src/device.c | 18 ++++++++---------- src/ib-brightness-control.c | 6 +++--- src/main.c | 2 -- src/service.c | 33 +++++++++------------------------ tests/test-device.cc | 4 ++-- 7 files changed, 27 insertions(+), 48 deletions(-) (limited to 'tests') diff --git a/src/device-provider-upower.c b/src/device-provider-upower.c index 7c12beb..400a060 100644 --- a/src/device-provider-upower.c +++ b/src/device-provider-upower.c @@ -17,8 +17,6 @@ * with this program. If not, see . */ -#include "config.h" - #include "dbus-upower.h" #include "device.h" #include "device-provider.h" @@ -60,7 +58,7 @@ G_DEFINE_TYPE_WITH_CODE ( indicator_power_device_provider_upower, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (INDICATOR_TYPE_POWER_DEVICE_PROVIDER, - indicator_power_device_provider_interface_init)); + indicator_power_device_provider_interface_init)) /*** **** UPOWER DBUS @@ -102,7 +100,7 @@ on_device_properties_ready (GObject * o, GAsyncResult * res, gpointer gdata) gdouble percentage = 0; gint64 time_to_empty = 0; gint64 time_to_full = 0; - time_t time; + gint64 time; IndicatorPowerDevice * device; IndicatorPowerDeviceProviderUPowerPriv * p = data->self->priv; GVariant * dict = g_variant_get_child_value (response, 0); @@ -120,7 +118,7 @@ on_device_properties_ready (GObject * o, GAsyncResult * res, gpointer gdata) INDICATOR_POWER_DEVICE_STATE, (gint)state, INDICATOR_POWER_DEVICE_OBJECT_PATH, data->path, INDICATOR_POWER_DEVICE_PERCENTAGE, percentage, - INDICATOR_POWER_DEVICE_TIME, (guint64)time, + INDICATOR_POWER_DEVICE_TIME, time, NULL); } else @@ -129,7 +127,7 @@ on_device_properties_ready (GObject * o, GAsyncResult * res, gpointer gdata) kind, percentage, state, - time); + (time_t)time); g_hash_table_insert (p->devices, g_strdup (data->path), diff --git a/src/device-provider.c b/src/device-provider.c index 81a8eec..46fcfad 100644 --- a/src/device-provider.c +++ b/src/device-provider.c @@ -29,7 +29,7 @@ static guint signals[SIGNAL_LAST] = { 0 }; G_DEFINE_INTERFACE (IndicatorPowerDeviceProvider, indicator_power_device_provider, - 0); + 0) static void indicator_power_device_provider_default_init (IndicatorPowerDeviceProviderInterface * klass) diff --git a/src/device.c b/src/device.c index 8780d72..f37aa7d 100644 --- a/src/device.c +++ b/src/device.c @@ -44,8 +44,6 @@ struct _IndicatorPowerDevicePrivate GTimer * inestimable; }; -#define INDICATOR_POWER_DEVICE_GET_PRIVATE(o) (INDICATOR_POWER_DEVICE(o)->priv) - /* Properties */ /* Enum for the properties so that they can be quickly found and looked up. */ enum { @@ -69,7 +67,7 @@ static void set_property (GObject*, guint prop_id, const GValue*, GParamSpec* ); static void get_property (GObject*, guint prop_id, GValue*, GParamSpec* ); /* LCOV_EXCL_START */ -G_DEFINE_TYPE (IndicatorPowerDevice, indicator_power_device, G_TYPE_OBJECT); +G_DEFINE_TYPE (IndicatorPowerDevice, indicator_power_device, G_TYPE_OBJECT) /* LCOV_EXCL_STOP */ static void @@ -189,7 +187,7 @@ get_property (GObject * o, guint prop_id, GValue * value, GParamSpec * pspec) break; case PROP_TIME: - g_value_set_uint64 (value, priv->time); + g_value_set_uint64 (value, (guint64)priv->time); break; default: @@ -207,11 +205,11 @@ set_property (GObject * o, guint prop_id, const GValue * value, GParamSpec * psp switch (prop_id) { case PROP_KIND: - p->kind = g_value_get_int (value); + p->kind = (UpDeviceKind) g_value_get_int (value); break; case PROP_STATE: - p->state = g_value_get_int (value); + p->state = (UpDeviceState) g_value_get_int (value); break; case PROP_OBJECT_PATH: @@ -224,7 +222,7 @@ set_property (GObject * o, guint prop_id, const GValue * value, GParamSpec * psp break; case PROP_TIME: - p->time = g_value_get_uint64(value); + p->time = (time_t) g_value_get_uint64(value); break; default: @@ -627,8 +625,8 @@ get_accessible_time_remaining (const IndicatorPowerDevice * device) if (p->time && ((p->state == UP_DEVICE_STATE_CHARGING) || (p->state == UP_DEVICE_STATE_DISCHARGING))) { - int minutes = p->time / 60; - const int hours = minutes / 60; + guint minutes = (guint)p->time / 60u; + const guint hours = minutes / 60u; minutes %= 60; if (p->state == UP_DEVICE_STATE_CHARGING) @@ -889,5 +887,5 @@ indicator_power_device_new_from_variant (GVariant * v) kind, percentage, state, - time); + (time_t)time); } diff --git a/src/ib-brightness-control.c b/src/ib-brightness-control.c index 4fb6bc5..67da10c 100644 --- a/src/ib-brightness-control.c +++ b/src/ib-brightness-control.c @@ -76,7 +76,7 @@ ib_brightness_control_set_value (IbBrightnessControl* self, gint value) gint fd; gchar *filename; gchar *svalue; - gint length; + size_t length; gint err; if (self->path == NULL) @@ -95,7 +95,7 @@ ib_brightness_control_set_value (IbBrightnessControl* self, gint value) err = errno; errno = 0; - if (write (fd, svalue, length) != length) { + if (write (fd, svalue, length) != (ssize_t)length) { g_warning ("Fail to write brightness information: %s", g_strerror(errno)); } errno = err; @@ -105,7 +105,7 @@ ib_brightness_control_set_value (IbBrightnessControl* self, gint value) g_free (filename); } -gint +static gint ib_brightness_control_get_value_from_file (IbBrightnessControl *self, const gchar *file) { GError *error; diff --git a/src/main.c b/src/main.c index ef615dc..7363284 100644 --- a/src/main.c +++ b/src/main.c @@ -17,8 +17,6 @@ * with this program. If not, see . */ -#include "config.h" - #include #include /* exit() */ diff --git a/src/service.c b/src/service.c index 6438c9a..7478d0f 100644 --- a/src/service.c +++ b/src/service.c @@ -18,8 +18,6 @@ * with this program. If not, see . */ -#include "config.h" - #include #include #include @@ -471,7 +469,7 @@ get_brightness_range (IndicatorPowerService * self, gint * low, gint * high) { max = ib_brightness_uscreen_control_get_max_value (self->priv->brightness_uscreen_control); } - *low = max * 0.05; /* 5% minimum -- don't let the screen go completely dark */ + *low = (gint)(max * 0.05); /* 5% minimum -- don't let the screen go completely dark */ *high = max; } @@ -621,18 +619,6 @@ rebuild_header_now (IndicatorPowerService * self) rebuild_now (self, SECTION_HEADER); } -static inline void -rebuild_devices_section_now (IndicatorPowerService * self) -{ - rebuild_now (self, SECTION_DEVICES); -} - -static inline void -rebuild_settings_section_now (IndicatorPowerService * self) -{ - rebuild_now (self, SECTION_SETTINGS); -} - static void create_menu (IndicatorPowerService * self, int profile) { @@ -938,7 +924,7 @@ on_devices_changed (IndicatorPowerService * self) if (p->primary_device == NULL) battery_level = 0; else - battery_level = (int)(indicator_power_device_get_percentage (p->primary_device) + 0.5); + battery_level = (guint32)(indicator_power_device_get_percentage (p->primary_device) + 0.5); g_simple_action_set_state (p->battery_level_action, g_variant_new_uint32 (battery_level)); rebuild_now (self, SECTION_HEADER | SECTION_DEVICES); @@ -1131,9 +1117,8 @@ indicator_power_service_set_device_provider (IndicatorPowerService * self, if (p->device_provider != NULL) { - g_signal_handlers_disconnect_by_func (p->device_provider, - G_CALLBACK(on_devices_changed), - self); + g_signal_handlers_disconnect_by_data (p->device_provider, self); + g_clear_object (&p->device_provider); g_clear_object (&p->primary_device); @@ -1177,13 +1162,13 @@ create_totalled_battery_device (const GList * devices) for (l=devices; l!=NULL; l=l->next) { - const IndicatorPowerDevice * device = INDICATOR_POWER_DEVICE(l->data); + const IndicatorPowerDevice * walk = INDICATOR_POWER_DEVICE(l->data); - if (indicator_power_device_get_kind(device) == UP_DEVICE_KIND_BATTERY) + if (indicator_power_device_get_kind(walk) == UP_DEVICE_KIND_BATTERY) { - const double percent = indicator_power_device_get_percentage (device); - const time_t t = indicator_power_device_get_time (device); - const UpDeviceState state = indicator_power_device_get_state (device); + const double percent = indicator_power_device_get_percentage (walk); + const time_t t = indicator_power_device_get_time (walk); + const UpDeviceState state = indicator_power_device_get_state (walk); ++n_batteries; diff --git a/tests/test-device.cc b/tests/test-device.cc index 7d54816..1d10b5b 100644 --- a/tests/test-device.cc +++ b/tests/test-device.cc @@ -710,10 +710,10 @@ TEST_F(DeviceTest, ChoosePrimary) std::vector devices; for(const auto& desc : descriptions) - devices.push_back(indicator_power_device_new(desc.path, desc.kind, desc.percentage, desc.state, desc.time)); + devices.push_back(indicator_power_device_new(desc.path, desc.kind, desc.percentage, desc.state, (time_t)desc.time)); const struct { - std::vector device_indices; + std::vector device_indices; Description expected; } tests[] = { -- cgit v1.2.3 From 35a8b1720631a6b700bf9a234d0444c3457ce197 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Sun, 13 Jul 2014 23:43:41 -0500 Subject: replace autoconf/automake with cmake --- CMakeLists.txt | 96 ++++++++++++++++++++++++++++++ Makefile.am | 43 -------------- Makefile.am.coverage | 48 --------------- autogen.sh | 27 --------- cmake/GCov.cmake | 51 ++++++++++++++++ cmake/GdbusCodegen.cmake | 36 +++++++++++ cmake/Translations.cmake | 41 +++++++++++++ cmake/UseGSettings.cmake | 23 ++++++++ configure.ac | 138 ------------------------------------------- data/CMakeLists.txt | 69 ++++++++++++++++++++++ data/Makefile.am | 58 ------------------ m4/gcov.m4 | 86 --------------------------- m4/gtest.m4 | 63 -------------------- src/CMakeLists.txt | 45 ++++++++++++++ src/Makefile.am | 83 -------------------------- src/device-provider-upower.h | 2 + tests/CMakeLists.txt | 46 +++++++++++++++ tests/Makefile.am | 71 ---------------------- 18 files changed, 409 insertions(+), 617 deletions(-) create mode 100644 CMakeLists.txt delete mode 100644 Makefile.am delete mode 100644 Makefile.am.coverage delete mode 100755 autogen.sh create mode 100644 cmake/GCov.cmake create mode 100644 cmake/GdbusCodegen.cmake create mode 100644 cmake/Translations.cmake create mode 100644 cmake/UseGSettings.cmake delete mode 100644 configure.ac create mode 100644 data/CMakeLists.txt delete mode 100644 data/Makefile.am delete mode 100644 m4/gcov.m4 delete mode 100644 m4/gtest.m4 create mode 100644 src/CMakeLists.txt delete mode 100644 src/Makefile.am create mode 100644 tests/CMakeLists.txt delete mode 100644 tests/Makefile.am (limited to 'tests') diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..9f80294 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,96 @@ +project(indicator-power C CXX) +cmake_minimum_required(VERSION 2.8.9) + +list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) + +set(PROJECT_VERSION "14.10.0") +set(PACKAGE ${CMAKE_PROJECT_NAME}) +set(GETTEXT_PACKAGE "indicator-power") +add_definitions (-DGETTEXT_PACKAGE="${GETTEXT_PACKAGE}" + -DGNOMELOCALEDIR="${CMAKE_INSTALL_FULL_LOCALEDIR}") + +option (enable_tests "Build the package's automatic tests." ON) +option (enable_lcov "Generate lcov code coverage reports." ON) + +## +## GNU standard installation directories +## + +include (GNUInstallDirs) +if (EXISTS "/etc/debian_version") # Workaround for libexecdir on debian + set (CMAKE_INSTALL_LIBEXECDIR "${CMAKE_INSTALL_LIBDIR}") + set (CMAKE_INSTALL_FULL_LIBEXECDIR "${CMAKE_INSTALL_FULL_LIBDIR}") +endif () +set (CMAKE_INSTALL_PKGLIBEXECDIR "${CMAKE_INSTALL_LIBEXECDIR}/${CMAKE_PROJECT_NAME}") +set (CMAKE_INSTALL_FULL_PKGLIBEXECDIR "${CMAKE_INSTALL_FULL_LIBEXECDIR}/${CMAKE_PROJECT_NAME}") + +## +## Check for prerequisites +## + +find_package (PkgConfig REQUIRED) +include (CheckIncludeFile) +include (FindPkgConfig) + +pkg_check_modules(SERVICE_DEPS REQUIRED + glib-2.0>=2.36 + gio-2.0>=2.36 + gio-unix-2.0>=2.36 + gudev-1.0>=204 + url-dispatcher-1>=1) + +include_directories (SYSTEM ${SERVICE_DEPS_INCLUDE_DIRS}) + +## +## custom targets +## + +set (ARCHIVE_NAME ${CMAKE_PROJECT_NAME}-${PROJECT_VERSION}) +add_custom_target (dist + COMMAND bzr export --root=${ARCHIVE_NAME} ${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar.gz + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + +add_custom_target (clean-coverage + COMMAND find ${CMAKE_BINARY_DIR} -name '*.gcda' | xargs rm -f) + +add_custom_target (cppcheck COMMAND cppcheck --enable=all -q --error-exitcode=2 --inline-suppr + ${CMAKE_SOURCE_DIR}/src + ${CMAKE_SOURCE_DIR}/tests) + +## +## Actual building +## + +# those GActionEntry structs tickle -Wmissing-field-initializers +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + set(C_WARNING_ARGS "${C_WARNING_ARGS} -Weverything -Wno-c++98-compat") + set(C_WARNING_ARGS "${C_WARNING_ARGS} -Wno-documentation") # gtk-doc != doxygen +else() + set(C_WARNING_ARGS "${C_WARNING_ARGS} -Wall -Wextra -Wpedantic -Wformat=2") +endif() +set(C_WARNING_ARGS "${C_WARNING_ARGS} -Wno-missing-field-initializers") # GActionEntry + + +include_directories (${CMAKE_CURRENT_SOURCE_DIR}/include) +include_directories (${CMAKE_CURRENT_BINARY_DIR}/include) + +# testing & coverage +if (${enable_tests}) + pkg_check_modules (DBUSTEST REQUIRED dbustest-1>=14.04.0) + set (GTEST_SOURCE_DIR /usr/src/gtest/src) + set (GTEST_INCLUDE_DIR ${GTEST_SOURCE_DIR}/..) + set (GTEST_LIBS -lpthread) + enable_testing () + if (${enable_lcov}) + include(GCov) + endif () +endif () + +# actually build things +add_subdirectory(src) +add_subdirectory(data) +add_subdirectory(po) +if (${enable_tests}) + add_subdirectory(tests) +endif () + diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index fbf05ca..0000000 --- a/Makefile.am +++ /dev/null @@ -1,43 +0,0 @@ -SUBDIRS = po data src - -if BUILD_TESTS -SUBDIRS += tests -# build src first -tests: src -endif - - -############################################################ - -dist_noinst_SCRIPTS = \ - autogen.sh - -############################################################ - -dist-hook: - @if test -d "$(top_srcdir)/.bzr"; \ - then \ - echo Creating ChangeLog && \ - ( cd "$(top_srcdir)" && \ - echo '# Generated by Makefile. Do not edit.'; echo; \ - $(top_srcdir)/build-aux/missing --run bzr log --gnu-changelog ) > ChangeLog.tmp \ - && mv -f ChangeLog.tmp $(top_distdir)/ChangeLog \ - || (rm -f ChangeLog.tmp; \ - echo Failed to generate ChangeLog >&2 ); \ - else \ - echo Failed to generate ChangeLog: not a branch >&2; \ - fi - @if test -d "$(top_srcdir)/.bzr"; \ - then \ - echo Creating AUTHORS && \ - ( cd "$(top_srcdir)" && \ - echo '# Generated by Makefile. Do not edit.'; echo; \ - $(top_srcdir)/build-aux/missing --run bzr log --long --levels=0 | grep -e "^\s*author:" -e "^\s*committer:" | cut -d ":" -f 2 | cut -d "<" -f 1 | sort -u) > AUTHORS.tmp \ - && mv -f AUTHORS.tmp $(top_distdir)/AUTHORS \ - || (rm -f AUTHORS.tmp; \ - echo Failed to generate AUTHORS >&2 ); \ - else \ - echo Failed to generate AUTHORS: not a branch >&2; \ - fi - -include $(top_srcdir)/Makefile.am.coverage diff --git a/Makefile.am.coverage b/Makefile.am.coverage deleted file mode 100644 index fb97747..0000000 --- a/Makefile.am.coverage +++ /dev/null @@ -1,48 +0,0 @@ - -# Coverage targets - -.PHONY: clean-gcno clean-gcda \ - coverage-html generate-coverage-html clean-coverage-html \ - coverage-gcovr generate-coverage-gcovr clean-coverage-gcovr - -clean-local: clean-gcno clean-coverage-html clean-coverage-gcovr - -if HAVE_GCOV - -clean-gcno: - @echo Removing old coverage instrumentation - -find -name '*.gcno' -print | xargs -r rm - -clean-gcda: - @echo Removing old coverage results - -find -name '*.gcda' -print | xargs -r rm - -coverage-html: clean-gcda - -$(MAKE) $(AM_MAKEFLAGS) -k check - $(MAKE) $(AM_MAKEFLAGS) generate-coverage-html - -generate-coverage-html: - @echo Collecting coverage data - $(LCOV) --directory $(top_builddir) --capture --output-file coverage.info --no-checksum --compat-libtool - LANG=C $(GENHTML) --prefix $(top_builddir) --output-directory coveragereport --title "Code Coverage" --legend --show-details coverage.info - -clean-coverage-html: clean-gcda - -$(LCOV) --directory $(top_builddir) -z - -rm -rf coverage.info coveragereport - -if HAVE_GCOVR - -coverage-gcovr: clean-gcda - -$(MAKE) $(AM_MAKEFLAGS) -k check - $(MAKE) $(AM_MAKEFLAGS) generate-coverage-gcovr - -generate-coverage-gcovr: - @echo Generating coverage GCOVR report - $(GCOVR) -x -r $(top_builddir) -o $(top_builddir)/coverage.xml - -clean-coverage-gcovr: clean-gcda - -rm -rf $(top_builddir)/coverage.xml - -endif # HAVE_GCOVR - -endif # HAVE_GCOV diff --git a/autogen.sh b/autogen.sh deleted file mode 100755 index 1912c87..0000000 --- a/autogen.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh - -test -n "$srcdir" || srcdir=`dirname "$0"` -test -n "$srcdir" || srcdir=. - -olddir=`pwd` -cd $srcdir - -AUTORECONF=`which autoreconf` -if test -z $AUTORECONF; then - echo "*** No autoreconf found, please intall it ***" - exit 1 -fi - -INTLTOOLIZE=`which intltoolize` -if test -z $INTLTOOLIZE; then - echo "*** No intltoolize found, please install the intltool package ***" - exit 1 -fi - -mkdir -p build-aux - -autopoint --force -AUTOPOINT='intltoolize --automake --copy' autoreconf --force --install --verbose - -cd $olddir -test -n "$NOCONFIGURE" || "$srcdir/configure" "$@" diff --git a/cmake/GCov.cmake b/cmake/GCov.cmake new file mode 100644 index 0000000..81c0c40 --- /dev/null +++ b/cmake/GCov.cmake @@ -0,0 +1,51 @@ +if (CMAKE_BUILD_TYPE MATCHES coverage) + set(GCOV_FLAGS "${GCOV_FLAGS} --coverage") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GCOV_FLAGS}") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${GCOV_FLAGS}") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${GCOV_FLAGS}") + set(GCOV_LIBS ${GCOV_LIBS} gcov) + + find_program(GCOVR_EXECUTABLE gcovr HINTS ${GCOVR_ROOT} "${GCOVR_ROOT}/bin") + if (NOT GCOVR_EXECUTABLE) + message(STATUS "Gcovr binary was not found, can not generate XML coverage info.") + else () + message(STATUS "Gcovr found, can generate XML coverage info.") + add_custom_target (coverage-xml + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMAND "${GCOVR_EXECUTABLE}" --exclude="test.*" -x -r "${CMAKE_SOURCE_DIR}" + --object-directory=${CMAKE_BINARY_DIR} -o coverage.xml) + endif() + + find_program(LCOV_EXECUTABLE lcov HINTS ${LCOV_ROOT} "${GCOVR_ROOT}/bin") + find_program(GENHTML_EXECUTABLE genhtml HINTS ${GENHTML_ROOT}) + if (NOT LCOV_EXECUTABLE) + message(STATUS "Lcov binary was not found, can not generate HTML coverage info.") + else () + if(NOT GENHTML_EXECUTABLE) + message(STATUS "Genthml binary not found, can not generate HTML coverage info.") + else() + message(STATUS "Lcov and genhtml found, can generate HTML coverage info.") + add_custom_target (coverage-html + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMAND "${CMAKE_CTEST_COMMAND}" --force-new-ctest-process --verbose + COMMAND "${LCOV_EXECUTABLE}" --directory ${CMAKE_BINARY_DIR} --capture | ${CMAKE_SOURCE_DIR}/trim-lcov.py > dconf-lcov.info + COMMAND "${LCOV_EXECUTABLE}" -r dconf-lcov.info /usr/include/\\* -o nosys-lcov.info + COMMAND LANG=C "${GENHTML_EXECUTABLE}" --prefix ${CMAKE_BINARY_DIR} --output-directory lcov-html --legend --show-details nosys-lcov.info + COMMAND ${CMAKE_COMMAND} -E echo "" + COMMAND ${CMAKE_COMMAND} -E echo "file://${CMAKE_BINARY_DIR}/lcov-html/index.html" + COMMAND ${CMAKE_COMMAND} -E echo "") + #COMMAND "${LCOV_EXECUTABLE}" --directory ${CMAKE_BINARY_DIR} --capture --output-file coverage.info --no-checksum + #COMMAND "${GENHTML_EXECUTABLE}" --prefix ${CMAKE_BINARY_DIR} --output-directory coveragereport --title "Code Coverage" --legend --show-details coverage.info + #COMMAND ${CMAKE_COMMAND} -E echo "\\#define foo \\\"bar\\\"" + #) + endif() + endif() +endif() + + + #$(MAKE) $(AM_MAKEFLAGS) check + #lcov --directory $(top_builddir) --capture --test-name dconf | $(top_srcdir)/trim-lcov.py > dconf-lcov.info + #LANG=C genhtml --prefix $(top_builddir) --output-directory lcov-html --legend --show-details dconf-lcov.info + #@echo + #@echo " file://$(abs_top_builddir)/lcov-html/index.html" + #@echo diff --git a/cmake/GdbusCodegen.cmake b/cmake/GdbusCodegen.cmake new file mode 100644 index 0000000..ddb2995 --- /dev/null +++ b/cmake/GdbusCodegen.cmake @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 2.6) +if(POLICY CMP0011) + cmake_policy(SET CMP0011 NEW) +endif(POLICY CMP0011) + +find_program(GDBUS_CODEGEN NAMES gdbus-codegen DOC "gdbus-codegen executable") +if(NOT GDBUS_CODEGEN) + message(FATAL_ERROR "Excutable gdbus-codegen not found") +endif() + +macro(add_gdbus_codegen outfiles name prefix service_xml) + add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${name}.h" "${CMAKE_CURRENT_BINARY_DIR}/${name}.c" + COMMAND "${GDBUS_CODEGEN}" + --interface-prefix "${prefix}" + --generate-c-code "${name}" + "${service_xml}" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${ARGN} "${service_xml}" + ) + list(APPEND ${outfiles} "${CMAKE_CURRENT_BINARY_DIR}/${name}.c") +endmacro(add_gdbus_codegen) + +macro(add_gdbus_codegen_with_namespace outfiles name prefix namespace service_xml) + add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${name}.h" "${CMAKE_CURRENT_BINARY_DIR}/${name}.c" + COMMAND "${GDBUS_CODEGEN}" + --interface-prefix "${prefix}" + --generate-c-code "${name}" + --c-namespace "${namespace}" + "${service_xml}" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${ARGN} "${service_xml}" + ) + list(APPEND ${outfiles} "${CMAKE_CURRENT_BINARY_DIR}/${name}.c") +endmacro(add_gdbus_codegen_with_namespace) diff --git a/cmake/Translations.cmake b/cmake/Translations.cmake new file mode 100644 index 0000000..d41f04e --- /dev/null +++ b/cmake/Translations.cmake @@ -0,0 +1,41 @@ +# Translations.cmake, CMake macros written for Marlin, feel free to re-use them + +macro(add_translations_directory NLS_PACKAGE) + add_custom_target (i18n ALL) + find_program (MSGFMT_EXECUTABLE msgfmt) + file (GLOB PO_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.po) + foreach (PO_INPUT ${PO_FILES}) + get_filename_component (PO_INPUT_BASE ${PO_INPUT} NAME_WE) + set (MO_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${PO_INPUT_BASE}.mo) + add_custom_command (TARGET i18n COMMAND ${MSGFMT_EXECUTABLE} -o ${MO_OUTPUT} ${PO_INPUT}) + + install (FILES ${MO_OUTPUT} DESTINATION + ${CMAKE_INSTALL_LOCALEDIR}/${PO_INPUT_BASE}/LC_MESSAGES + RENAME ${NLS_PACKAGE}.mo) + endforeach (PO_INPUT ${PO_FILES}) +endmacro(add_translations_directory) + + +macro(add_translations_catalog NLS_PACKAGE) + add_custom_target (pot COMMENT “Building translation catalog.”) + find_program (XGETTEXT_EXECUTABLE xgettext) + + + set(C_SOURCE "") + + foreach(FILES_INPUT ${ARGN}) + file (GLOB_RECURSE SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/${FILES_INPUT}/*.c) + foreach(C_FILE ${SOURCE_FILES}) + set(C_SOURCE ${C_SOURCE} ${C_FILE}) + endforeach() + file (GLOB_RECURSE SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/${FILES_INPUT}/*.vala) + foreach(C_FILE ${SOURCE_FILES}) + set(C_SOURCE ${C_SOURCE} ${C_FILE}) + endforeach() + endforeach() + + add_custom_command (TARGET pot COMMAND + ${XGETTEXT_EXECUTABLE} -d ${NLS_PACKAGE} -o ${CMAKE_CURRENT_SOURCE_DIR}/${NLS_PACKAGE}.pot + ${VALA_SOURCE} ${C_SOURCE} --keyword="_" --keyword="N_" --from-code=UTF-8 + ) +endmacro() diff --git a/cmake/UseGSettings.cmake b/cmake/UseGSettings.cmake new file mode 100644 index 0000000..3b61523 --- /dev/null +++ b/cmake/UseGSettings.cmake @@ -0,0 +1,23 @@ +# GSettings.cmake, CMake macros written for Marlin, feel free to re-use them. + +macro(add_schema SCHEMA_NAME) + + set(PKG_CONFIG_EXECUTABLE pkg-config) + set(GSETTINGS_DIR "${CMAKE_INSTALL_FULL_DATAROOTDIR}/glib-2.0/schemas") + + # Run the validator and error if it fails + execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} gio-2.0 --variable glib_compile_schemas OUTPUT_VARIABLE _glib_compile_schemas OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process (COMMAND ${_glib_compile_schemas} --dry-run --schema-file=${SCHEMA_NAME} ERROR_VARIABLE _schemas_invalid OUTPUT_STRIP_TRAILING_WHITESPACE) + + if (_schemas_invalid) + message (SEND_ERROR "Schema validation error: ${_schemas_invalid}") + endif (_schemas_invalid) + + # Actually install and recomple schemas + message (STATUS "${GSETTINGS_DIR} is the GSettings install dir") + install (FILES ${SCHEMA_NAME} DESTINATION ${GSETTINGS_DIR} OPTIONAL) + + install (CODE "message (STATUS \"Compiling GSettings schemas\")") + install (CODE "execute_process (COMMAND ${_glib_compile_schemas} ${GSETTINGS_DIR})") +endmacro() + diff --git a/configure.ac b/configure.ac deleted file mode 100644 index ca7e793..0000000 --- a/configure.ac +++ /dev/null @@ -1,138 +0,0 @@ -AC_INIT([indicator-power], - [13.10.0], - [http://bugs.launchpad.net/indicator-power], - [indicator-power], - [http://launchpad.net/indicator-power]) -AC_COPYRIGHT([Copyright 2011-2013 Canonical]) - -AC_PREREQ([2.64]) - -AC_CONFIG_HEADERS([config.h]) -AC_CONFIG_SRCDIR([src/device.c]) -AC_CONFIG_MACRO_DIR([m4]) -AC_CONFIG_AUX_DIR([build-aux]) - -AM_INIT_AUTOMAKE([1.11 -Wall foreign dist-xz check-news]) -AM_MAINTAINER_MODE([enable]) - -AM_SILENT_RULES([yes]) - -# Check for programs -AC_PROG_CC -AM_PROG_CC_C_O -AC_PROG_CXX -AM_PROG_AR - -# Initialize libtool -LT_PREREQ([2.2.6]) -LT_INIT - - -########################### -# Dependencies -########################### - -GLIB_REQUIRED_VERSION=2.35.4 -GIO_REQUIRED_VERSION=2.26 -GIO_UNIX_REQUIRED_VERSION=2.26 -GUDEV_REQUIRED_VERSION=204 - -PKG_CHECK_MODULES([SERVICE_DEPS],[glib-2.0 >= $GLIB_REQUIRED_VERSION - gio-2.0 >= $GIO_REQUIRED_VERSION - gio-unix-2.0 >= $GIO_UNIX_REQUIRED_VERSION - gudev-1.0 >= $GUDEV_REQUIRED_VERSION - url-dispatcher-1]) - -########################### -# GSETTINGS -########################### - -GLIB_GSETTINGS - -########################### -# Google Test framework -########################### - -AC_ARG_ENABLE([tests], - [AS_HELP_STRING([--disable-tests], [Disable test scripts and tools (default=auto)])], - [enable_tests=${enableval}], - [enable_tests=auto]) -if test "x$enable_tests" != "xno"; then - m4_include([m4/gtest.m4]) - CHECK_GTEST - if test "x$enable_tests" = "xauto"; then - enable_tests=${have_gtest} - elif test "x$enable_tests" = "xyes" && test "x$have_gtest" != "xyes"; then - AC_MSG_ERROR([tests were requested but gtest is not installed.]) - fi -fi -AM_CONDITIONAL([BUILD_TESTS],[test "x$enable_tests" = "xyes"]) - -########################### -# gcov coverage reporting -########################### - -m4_include([m4/gcov.m4]) -AC_TDD_GCOV -AM_CONDITIONAL([HAVE_GCOV], [test "x$ac_cv_check_gcov" = xyes]) -AM_CONDITIONAL([HAVE_LCOV], [test "x$ac_cv_check_lcov" = xyes]) -AM_CONDITIONAL([HAVE_GCOVR], [test "x$ac_cv_check_gcovr" = xyes]) -AC_SUBST(COVERAGE_CFLAGS) -AC_SUBST(COVERAGE_CXXFLAGS) -AC_SUBST(COVERAGE_LDFLAGS) - -############################## -# Custom Junk -############################## - -AC_DEFUN([AC_DEFINE_PATH], [ - test "x$prefix" = xNONE && prefix="$ac_default_prefix" - test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' - ac_define_path=`eval echo [$]$2` - ac_define_path=`eval echo [$]ac_define_path` - $1="$ac_define_path" - AC_SUBST($1) - ifelse($3, , - AC_DEFINE_UNQUOTED($1, "$ac_define_path"), - AC_DEFINE_UNQUOTED($1, "$ac_define_path", $3)) -]) - -########################### -# Internationalization -########################### - -IT_PROG_INTLTOOL([0.50.0]) - -AM_GNU_GETTEXT([external]) -AM_GNU_GETTEXT_VERSION([0.17]) - -AC_SUBST([GETTEXT_PACKAGE],[${PACKAGE_TARNAME}]) -AC_DEFINE([GETTEXT_PACKAGE],[PACKAGE_TARNAME],[Define to the gettext package name.]) -AC_DEFINE_PATH([GNOMELOCALEDIR],"${datadir}/locale",[locale directory]) - -########################### -# Files -########################### - -AC_CONFIG_FILES([ -Makefile -po/Makefile.in -data/Makefile -src/Makefile -tests/Makefile -]) -AC_OUTPUT - -########################### -# Results -########################### - -AC_MSG_NOTICE([ - -Power Indicator Configuration: - - Prefix: $prefix - Unit Tests: $enable_tests - gcov: $use_gcov - -]) diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt new file mode 100644 index 0000000..51fc415 --- /dev/null +++ b/data/CMakeLists.txt @@ -0,0 +1,69 @@ +## +## GSettings schema +## + +include (UseGSettings) +set (SCHEMA_NAME "com.canonical.indicator.power.gschema.xml") +set (SCHEMA_FILE "${CMAKE_CURRENT_BINARY_DIR}/${SCHEMA_NAME}") +set (SCHEMA_FILE_IN "${CMAKE_CURRENT_SOURCE_DIR}/${SCHEMA_NAME}.in") + +# generate the .xml file using intltool +set (ENV{LC_ALL} "C") +execute_process (COMMAND intltool-merge -quiet --xml-style --utf8 --no-translations "${SCHEMA_FILE_IN}" "${SCHEMA_FILE}") + +# let UseGSettings do the rest +add_schema (${SCHEMA_FILE}) + +## +## Upstart Job File +## + +# where to install +set (UPSTART_JOB_DIR "${CMAKE_INSTALL_FULL_DATADIR}/upstart/sessions") +message (STATUS "${UPSTART_JOB_DIR} is the Upstart Job File install dir") + +set (UPSTART_JOB_NAME "${CMAKE_PROJECT_NAME}.conf") +set (UPSTART_JOB_FILE "${CMAKE_CURRENT_BINARY_DIR}/${UPSTART_JOB_NAME}") +set (UPSTART_JOB_FILE_IN "${CMAKE_CURRENT_SOURCE_DIR}/${UPSTART_JOB_NAME}.in") + +# build it +set (pkglibexecdir "${CMAKE_INSTALL_FULL_PKGLIBEXECDIR}") +configure_file ("${UPSTART_JOB_FILE_IN}" "${UPSTART_JOB_FILE}") + +# install it +install (FILES "${UPSTART_JOB_FILE}" + DESTINATION "${UPSTART_JOB_DIR}") + +## +## XDG Autostart File +## + +# where to install +set (XDG_AUTOSTART_DIR "/etc/xdg/autostart") +message (STATUS "${XDG_AUTOSTART_DIR} is the DBus Service File install dir") + +set (XDG_AUTOSTART_NAME "${CMAKE_PROJECT_NAME}.desktop") +set (XDG_AUTOSTART_FILE "${CMAKE_CURRENT_BINARY_DIR}/${XDG_AUTOSTART_NAME}") +set (XDG_AUTOSTART_FILE_IN "${CMAKE_CURRENT_SOURCE_DIR}/${XDG_AUTOSTART_NAME}.in") + +# build it +set (pkglibexecdir "${CMAKE_INSTALL_FULL_PKGLIBEXECDIR}") +configure_file ("${XDG_AUTOSTART_FILE_IN}" "${XDG_AUTOSTART_FILE}") + +# install it +install (FILES "${XDG_AUTOSTART_FILE}" + DESTINATION "${XDG_AUTOSTART_DIR}") + +## +## Unity Indicator File +## + +# where to install +set (UNITY_INDICATOR_DIR "${CMAKE_INSTALL_FULL_DATAROOTDIR}/unity/indicators") +message (STATUS "${UNITY_INDICATOR_DIR} is the Unity Indicator install dir") + +set (UNITY_INDICATOR_NAME "com.canonical.indicator.power") +set (UNITY_INDICATOR_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${UNITY_INDICATOR_NAME}") + +install (FILES "${UNITY_INDICATOR_FILE}" + DESTINATION "${UNITY_INDICATOR_DIR}") diff --git a/data/Makefile.am b/data/Makefile.am deleted file mode 100644 index 9a4caca..0000000 --- a/data/Makefile.am +++ /dev/null @@ -1,58 +0,0 @@ -BUILT_SOURCES= -CLEANFILES= -EXTRA_DIST= - -# -# the indicator bus file -# - -indicatorsdir = $(prefix)/share/unity/indicators -dist_indicators_DATA = com.canonical.indicator.power - -# -# the upstart job file -# - -upstart_jobsdir = $(datadir)/upstart/sessions -upstart_jobs_DATA = indicator-power.conf -upstart_jobs_in = $(upstart_jobs_DATA:.conf=.conf.in) -$(upstart_jobs_DATA): $(upstart_jobs_in) - $(AM_V_GEN) $(SED) -e "s|\@pkglibexecdir\@|$(pkglibexecdir)|" $< > $@ -BUILT_SOURCES += $(upstart_jobs_DATA) -CLEANFILES += $(upstart_jobs_DATA) -EXTRA_DIST += $(upstart_jobs_in) - -# -# the xdg autostart job file -# - -xdg_autostartdir = /etc/xdg/autostart -xdg_autostart_DATA = indicator-power.desktop -xdg_autostart_in = $(xdg_autostart_DATA:.desktop=.desktop.in) -$(xdg_autostart_DATA): $(xdg_autostart_in) - $(AM_V_GEN) $(SED) -e "s|\@pkglibexecdir\@|$(pkglibexecdir)|" $< > $@ -BUILT_SOURCES += $(xdg_autostart_DATA) -CLEANFILES += $(xdg_autostart_DATA) -EXTRA_DIST += $(xdg_autostart_in) - -# -# the gettings -# - -gsettings_in_file = com.canonical.indicator.power.gschema.xml.in -gsettings_SCHEMAS = $(gsettings_in_file:.xml.in=.xml) -CLEANFILES += $(gsettings_SCHEMAS) - -@INTLTOOL_XML_NOMERGE_RULE@ - -@GSETTINGS_RULES@ - -dist_noinst_DATA = \ - com.canonical.indicator.power.gschema.xml \ - $(gsettings_in_file) - -CLEANFILES += \ - $(gsettings_SCHEMAS) - -MAINTAINERCLEANFILES = \ - $(gsettings_SCHEMAS:.xml=.valid) diff --git a/m4/gcov.m4 b/m4/gcov.m4 deleted file mode 100644 index bd96386..0000000 --- a/m4/gcov.m4 +++ /dev/null @@ -1,86 +0,0 @@ -# Checks for existence of coverage tools: -# * gcov -# * lcov -# * genhtml -# * gcovr -# -# Sets ac_cv_check_gcov to yes if tooling is present -# and reports the executables to the variables LCOV, GCOVR and GENHTML. -AC_DEFUN([AC_TDD_GCOV], -[ - AC_ARG_ENABLE(gcov, - AS_HELP_STRING([--enable-gcov], - [enable coverage testing with gcov]), - [use_gcov=$enableval], [use_gcov=no]) - - if test "x$use_gcov" = "xyes"; then - # we need gcc: - if test "$GCC" != "yes"; then - AC_MSG_ERROR([GCC is required for --enable-gcov]) - fi - - # Check if ccache is being used - AC_CHECK_PROG(SHTOOL, shtool, shtool) - case `$SHTOOL path $CC` in - *ccache*[)] gcc_ccache=yes;; - *[)] gcc_ccache=no;; - esac - - if test "$gcc_ccache" = "yes" && (test -z "$CCACHE_DISABLE" || test "$CCACHE_DISABLE" != "1"); then - AC_MSG_ERROR([ccache must be disabled when --enable-gcov option is used. You can disable ccache by setting environment variable CCACHE_DISABLE=1.]) - fi - - lcov_version_list="1.6 1.7 1.8 1.9 1.10 1.11" - AC_CHECK_PROG(LCOV, lcov, lcov) - AC_CHECK_PROG(GENHTML, genhtml, genhtml) - - if test "$LCOV"; then - AC_CACHE_CHECK([for lcov version], glib_cv_lcov_version, [ - glib_cv_lcov_version=invalid - lcov_version=`$LCOV -v 2>/dev/null | $SED -e 's/^.* //'` - for lcov_check_version in $lcov_version_list; do - if test "$lcov_version" = "$lcov_check_version"; then - glib_cv_lcov_version="$lcov_check_version (ok)" - fi - done - ]) - else - lcov_msg="To enable code coverage reporting you must have one of the following lcov versions installed: $lcov_version_list" - AC_MSG_ERROR([$lcov_msg]) - fi - - case $glib_cv_lcov_version in - ""|invalid[)] - lcov_msg="You must have one of the following versions of lcov: $lcov_version_list (found: $lcov_version)." - AC_MSG_ERROR([$lcov_msg]) - LCOV="exit 0;" - ;; - esac - - if test -z "$GENHTML"; then - AC_MSG_ERROR([Could not find genhtml from the lcov package]) - fi - - ac_cv_check_gcov=yes - ac_cv_check_lcov=yes - - # Remove all optimization flags from CFLAGS - changequote({,}) - CFLAGS=`echo "$CFLAGS" | $SED -e 's/-O[0-9]*//g'` - changequote([,]) - - # Add the special gcc flags - COVERAGE_CFLAGS="-O0 -fprofile-arcs -ftest-coverage" - COVERAGE_CXXFLAGS="-O0 -fprofile-arcs -ftest-coverage" - COVERAGE_LDFLAGS="-lgcov" - - # Check availability of gcovr - AC_CHECK_PROG(GCOVR, gcovr, gcovr) - if test -z "$GCOVR"; then - ac_cv_check_gcovr=no - else - ac_cv_check_gcovr=yes - fi - -fi -]) # AC_TDD_GCOV diff --git a/m4/gtest.m4 b/m4/gtest.m4 deleted file mode 100644 index 2de334c..0000000 --- a/m4/gtest.m4 +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (C) 2012 Canonical, Ltd. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice (including the next -# paragraph) shall be included in all copies or substantial portions of the -# Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -# Checks whether the gtest source is available on the system. Allows for -# adjusting the include and source path. Sets have_gtest=yes if the source is -# present. Sets GTEST_CPPFLAGS and GTEST_SOURCE to the preprocessor flags and -# source location respectively. -AC_DEFUN([CHECK_GTEST], -[ - AC_ARG_WITH([gtest-include-path], - [AS_HELP_STRING([--with-gtest-include-path], - [location of the Google test headers])], - [GTEST_CPPFLAGS="-I$withval"]) - - AC_ARG_WITH([gtest-source-path], - [AS_HELP_STRING([--with-gtest-source-path], - [location of the Google test sources, defaults to /usr/src/gtest])], - [GTEST_SOURCE="$withval"], - [GTEST_SOURCE="/usr/src/gtest"]) - - GTEST_CPPFLAGS="$GTEST_CPPFLAGS -I$GTEST_SOURCE" - - AC_LANG_PUSH([C++]) - - tmp_CPPFLAGS="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $GTEST_CPPFLAGS" - - AC_CHECK_HEADER([gtest/gtest.h]) - - CPPFLAGS="$tmp_CPPFLAGS" - - AC_LANG_POP - - AC_CHECK_FILES([$GTEST_SOURCE/src/gtest-all.cc] - [$GTEST_SOURCE/src/gtest_main.cc], - [have_gtest_source=yes], - [have_gtest_source=no]) - - AS_IF([test "x$ac_cv_header_gtest_gtest_h" = xyes -a \ - "x$have_gtest_source" = xyes], - [have_gtest=yes] - [AC_SUBST(GTEST_CPPFLAGS)] - [AC_SUBST(GTEST_SOURCE)], - [have_gtest=no]) -]) # CHECK_GTEST diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..a39b945 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,45 @@ +set (SERVICE_LIB "indicatorpowerservice") +set (SERVICE_EXEC "indicator-power-service") + +add_definitions(-DG_LOG_DOMAIN="Indicator-Power") + +# handwritten sources +set(SERVICE_MANUAL_SOURCES + device-provider-upower.c + ib-brightness-control.c + ib-brightness-uscreen-control.c + device-provider.c + device.c + service.c) + +# generated sources +include(GdbusCodegen) +set(SERVICE_GENERATED_SOURCES) +add_gdbus_codegen_with_namespace(SERVICE_GENERATED_SOURCES dbus-upower + org.freedesktop + Dbus + ${CMAKE_CURRENT_SOURCE_DIR}/org.freedesktop.UPower.xml) +# add the bin dir to our include path so the code can find the generated header files +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + + +# add warnings/coverage info on handwritten files +# but not the autogenerated ones... +set(C_WARNING_ARGS "${C_WARNING_ARGS} -Wno-bad-function-cast") # g_clear_object() +set(C_WARNING_ARGS "${C_WARNING_ARGS} -Wno-disabled-macro-expansion") # G_DEFINE_TYPE +set(C_WARNING_ARGS "${C_WARNING_ARGS} -Wno-assign-enum") # GParamFlags +set(C_WARNING_ARGS "${C_WARNING_ARGS} -Wno-switch-enum") +set_source_files_properties(${SERVICE_MANUAL_SOURCES} + PROPERTIES COMPILE_FLAGS "${C_WARNING_ARGS} ${GCOV_FLAGS} -g -std=c99") + +# the service library for tests to link against (basically, everything except main()) +add_library(${SERVICE_LIB} STATIC ${SERVICE_MANUAL_SOURCES} ${SERVICE_GENERATED_SOURCES}) +include_directories(${CMAKE_SOURCE_DIR}) +link_directories(${SERVICE_DEPS_LIBRARY_DIRS}) + +# the executable: lib + main() +add_executable (${SERVICE_EXEC} main.c) +set_source_files_properties(${SERVICE_SOURCES} main.c PROPERTIES COMPILE_FLAGS "${C_WARNING_ARGS} -g -std=c99") +target_link_libraries (${SERVICE_EXEC} ${SERVICE_LIB} ${SERVICE_DEPS_LIBRARIES} ${GCOV_LIBS}) +install (TARGETS ${SERVICE_EXEC} RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_PKGLIBEXECDIR}) + diff --git a/src/Makefile.am b/src/Makefile.am deleted file mode 100644 index 3f71b60..0000000 --- a/src/Makefile.am +++ /dev/null @@ -1,83 +0,0 @@ -BUILT_SOURCES = -EXTRA_DIST = -CLEANFILES = - -SHARED_CFLAGS = \ - -Wall -Wextra -Werror \ - $(SERVICE_DEPS_CFLAGS) \ - -DG_LOG_DOMAIN=\"Indicator-Power\" - -### -### - -upower_dbus_sources = \ - dbus-upower.c \ - dbus-upower.h - -$(upower_dbus_sources): org.freedesktop.UPower.xml - $(AM_V_GEN) gdbus-codegen \ - --c-namespace Dbus \ - --interface-prefix org.freedesktop \ - --generate-c-code dbus-upower \ - $^ - -BUILT_SOURCES += $(upower_dbus_sources) -CLEANFILES += $(upower_dbus_sources) -EXTRA_DIST += org.freedesktop.UPower.xml - -### -### -### - -noinst_LIBRARIES = libindicatorpower-upower.a libindicatorpower-service.a - -libindicatorpower_upower_a_SOURCES = \ - $(upower_dbus_sources) \ - device-provider-upower.c \ - device-provider-upower.h - -libindicatorpower_upower_a_CFLAGS = \ - $(SHARED_CFLAGS) \ - -Wno-unused-parameter \ - $(COVERAGE_CFLAGS) - -libindciatorpower_upower_a_LDFLAGS = $(COVERAGE_LDFLAGS) - -libindicatorpower_service_a_SOURCES = \ - ib-brightness-control.c \ - ib-brightness-control.h \ - ib-brightness-uscreen-control.c \ - ib-brightness-uscreen-control.h \ - device-provider.c \ - device-provider.h \ - device.c \ - device.h \ - service.c \ - service.h - -libindicatorpower_service_a_CFLAGS = \ - $(SHARED_CFLAGS) \ - -Wno-missing-field-initializers \ - $(COVERAGE_CFLAGS) - -libindicatorpower_service_a_LDFLAGS = $(COVERAGE_LDFLAGS) - -### -### -### - -pkglibexec_PROGRAMS = indicator-power-service - -indicator_power_service_SOURCES = main.c - -indicator_power_service_CFLAGS = \ - $(SHARED_CFLAGS) \ - $(COVERAGE_CFLAGS) - -indicator_power_service_LDADD = \ - libindicatorpower-upower.a \ - libindicatorpower-service.a \ - $(SERVICE_DEPS_LIBS) - -indicator_power_service_LDFLAGS = \ - $(COVERAGE_LDFLAGS) diff --git a/src/device-provider-upower.h b/src/device-provider-upower.h index 7bdd5d5..7bfecd9 100644 --- a/src/device-provider-upower.h +++ b/src/device-provider-upower.h @@ -65,6 +65,8 @@ struct _IndicatorPowerDeviceProviderUPowerClass GObjectClass parent_class; }; +GType indicator_power_device_provider_upower_get_type (void); + IndicatorPowerDeviceProvider * indicator_power_device_provider_upower_new (void); G_END_DECLS diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..c5ad09d --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,46 @@ +# build libgtest +add_library (gtest STATIC + ${GTEST_SOURCE_DIR}/gtest-all.cc + ${GTEST_SOURCE_DIR}/gtest_main.cc) +set_target_properties (gtest PROPERTIES INCLUDE_DIRECTORIES ${INCLUDE_DIRECTORIES} ${GTEST_INCLUDE_DIR}) +set_target_properties (gtest PROPERTIES COMPILE_FLAGS ${COMPILE_FLAGS} -w) + +# add warnings +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g ${C_WARNING_ARGS}") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-weak-vtables -Wno-global-constructors") # Google Test + +# build the necessary schemas +set_directory_properties (PROPERTIES + ADDITIONAL_MAKE_CLEAN_FILES gschemas.compiled) +set_source_files_properties (gschemas.compiled GENERATED) + +# GSettings: +# compile the indicator-power schema into a gschemas.compiled file in this directory, +# and help the tests to find that file by setting -DSCHEMA_DIR +set (SCHEMA_DIR ${CMAKE_CURRENT_BINARY_DIR}) +add_definitions(-DSCHEMA_DIR="${SCHEMA_DIR}") +execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} gio-2.0 --variable glib_compile_schemas + OUTPUT_VARIABLE COMPILE_SCHEMA_EXECUTABLE + OUTPUT_STRIP_TRAILING_WHITESPACE) +add_custom_command (OUTPUT gschemas.compiled + DEPENDS ${CMAKE_BINARY_DIR}/data/com.canonical.indicator.power.gschema.xml + COMMAND cp -f ${CMAKE_BINARY_DIR}/data/*gschema.xml ${SCHEMA_DIR} + COMMAND ${COMPILE_SCHEMA_EXECUTABLE} ${SCHEMA_DIR}) + +# look for headers in our src dir, and also in the directories where we autogenerate files... +include_directories (${CMAKE_SOURCE_DIR}/src) +include_directories (${CMAKE_BINARY_DIR}/src) +include_directories (${CMAKE_CURRENT_BINARY_DIR}) + +### +### + +function(add_test_by_name name) + set (TEST_NAME ${name}) + add_executable (${TEST_NAME} ${TEST_NAME}.cc gschemas.compiled) + add_test (${TEST_NAME} ${TEST_NAME}) + add_dependencies (${TEST_NAME} libindicatorpowerservice) + target_link_libraries (${TEST_NAME} indicatorpowerservice gtest ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS}) +endfunction() +add_test_by_name(test-device) + diff --git a/tests/Makefile.am b/tests/Makefile.am deleted file mode 100644 index 483bb8c..0000000 --- a/tests/Makefile.am +++ /dev/null @@ -1,71 +0,0 @@ -TESTS = -CLEANFILES = -BUILT_SOURCES = -check_PROGRAMS = - -### -### tests: stock tests on user-visible strings -### - -include $(srcdir)/Makefile.am.strings - -### -### gtest library -### - -check_LIBRARIES = libgtest.a -nodist_libgtest_a_SOURCES = \ - $(GTEST_SOURCE)/src/gtest-all.cc \ - $(GTEST_SOURCE)/src/gtest_main.cc - -AM_CPPFLAGS = $(GTEST_CPPFLAGS) -I${top_srcdir}/src -Wall -Werror -std=c++11 -AM_CXXFLAGS = $(GTEST_CXXFLAGS) - -### -### tests: indicator-power-device -### - -dear-reader-please-note-the-next-test-takes-90-seconds: - @echo "#!/bin/bash" > $@ - @echo "exit 0" >> $@ - @chmod +x $@ -TESTS += dear-reader-please-note-the-next-test-takes-90-seconds -CLEANFILES += dear-reader-please-note-the-next-test-takes-90-seconds - -TEST_LIBS = $(COVERAGE_LDFLAGS) libgtest.a -lpthread -TEST_CPPFLAGS = $(SERVICE_DEPS_CFLAGS) $(AM_CPPFLAGS) - -TESTS += test-device -check_PROGRAMS += test-device -test_device_SOURCES = test-device.cc -test_device_CPPFLAGS = $(TEST_CPPFLAGS) -Wall -Werror -Wextra -test_device_LDADD = \ - $(top_builddir)/src/libindicatorpower-service.a \ - $(SERVICE_DEPS_LIBS) \ - $(TEST_LIBS) - - -# (FIXME: incomplete) -# -### -### tests: indicator-power-service -### -# -# build a local copy of the GSettings schemas -#BUILT_SOURCES += gschemas.compiled -#CLEANFILES += gschemas.compiled -#gschemas.compiled: Makefile -# @glib-compile-schemas --targetdir=$(abs_builddir) $(top_builddir)/data -# -#TESTS += test-service -#check_PROGRAMS += test-service -#test_service_SOURCES = test-service.cc -#test_service_LDADD = $(TEST_LIBS) -#test_service_CPPFLAGS = $(TEST_CPPFLAGS) -DSCHEMA_DIR="\"$(top_builddir)/tests/\"" -# -#TESTS += test-dbus-listener -#check_PROGRAMS += test-dbus-listener -#test_dbus_listener_SOURCES = test-dbus-listener.cc -#test_dbus_listener_LDADD = $(TEST_LIBS) -#test_dbus_listener_CPPFLAGS = $(TEST_CPPFLAGS) -# -- cgit v1.2.3 From 6ea2db56307d04ac8dba4bcf929cd716f4840359 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 16 Jul 2014 01:08:54 -0500 Subject: add first draft of low battery notifications --- src/CMakeLists.txt | 1 + src/main.c | 12 +- src/notifier.c | 336 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/notifier.h | 68 +++++++++++ tests/CMakeLists.txt | 2 + tests/test-notify.cc | 59 +++++++++ 6 files changed, 474 insertions(+), 4 deletions(-) create mode 100644 src/notifier.c create mode 100644 src/notifier.h create mode 100644 tests/test-notify.cc (limited to 'tests') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a39b945..4747b12 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,6 +10,7 @@ set(SERVICE_MANUAL_SOURCES ib-brightness-uscreen-control.c device-provider.c device.c + notifier.c service.c) # generated sources diff --git a/src/main.c b/src/main.c index 7363284..70b7f2a 100644 --- a/src/main.c +++ b/src/main.c @@ -25,6 +25,7 @@ #include "device.h" #include "device-provider-upower.h" +#include "notifier.h" #include "service.h" /*** @@ -41,9 +42,10 @@ on_name_lost (gpointer instance G_GNUC_UNUSED, gpointer loop) int main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) { - GMainLoop * loop; - IndicatorPowerService * service; IndicatorPowerDeviceProvider * device_provider; + IndicatorPowerNotifier * notifier; + IndicatorPowerService * service; + GMainLoop * loop; /* boilerplate i18n */ setlocale (LC_ALL, ""); @@ -52,6 +54,7 @@ main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) /* run */ device_provider = indicator_power_device_provider_upower_new (); + notifier = indicator_power_notifier_new (device_provider); service = indicator_power_service_new (device_provider); loop = g_main_loop_new (NULL, FALSE); g_signal_connect (service, INDICATOR_POWER_SERVICE_SIGNAL_NAME_LOST, @@ -59,8 +62,9 @@ main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) g_main_loop_run (loop); /* cleanup */ - g_clear_object (&device_provider); - g_clear_object (&service); g_main_loop_unref (loop); + g_clear_object (&service); + g_clear_object (¬ifier); + g_clear_object (&device_provider); return 0; } diff --git a/src/notifier.c b/src/notifier.c new file mode 100644 index 0000000..79ea4cc --- /dev/null +++ b/src/notifier.c @@ -0,0 +1,336 @@ +/* + * Copyright 2014 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + * + * Authors: + * Charles Kerr + */ + +#include "device.h" +#include "device-provider.h" +#include "notifier.h" +#include "service.h" + +#include + +#include +#include + +G_DEFINE_TYPE(IndicatorPowerNotifier, + indicator_power_notifier, + G_TYPE_OBJECT) + +enum +{ + PROP_0, + PROP_DEVICE_PROVIDER, + LAST_PROP +}; + +static GParamSpec * properties[LAST_PROP]; + +static int n_notifiers = 0; + +struct _IndicatorPowerNotifierPrivate +{ + IndicatorPowerDeviceProvider * device_provider; + IndicatorPowerDevice * primary_device; + gdouble battery_level; + time_t time_remaining; + NotifyNotification* notify_notification; +}; + +typedef IndicatorPowerNotifierPrivate priv_t; + +/*** +**** +***/ + +static void +emit_critical_signal(IndicatorPowerNotifier * self G_GNUC_UNUSED) +{ + g_message("FIXME %s %s", G_STRFUNC, G_STRLOC); +} + +static void +emit_hide_signal(IndicatorPowerNotifier * self G_GNUC_UNUSED) +{ + g_message("FIXME %s %s", G_STRFUNC, G_STRLOC); +} + +static void +emit_show_signal(IndicatorPowerNotifier * self G_GNUC_UNUSED) +{ + g_message("FIXME %s %s", G_STRFUNC, G_STRLOC); +} + +static void +notification_clear(IndicatorPowerNotifier * self) +{ + priv_t * p = self->priv; + + if (p->notify_notification != NULL) + { + notify_notification_clear_actions(p->notify_notification); + g_signal_handlers_disconnect_by_data(p->notify_notification, self); + g_clear_object(&p->notify_notification); + emit_hide_signal(self); + } +} + +static void +on_notification_clicked(NotifyNotification * notify_notification G_GNUC_UNUSED, + char * action G_GNUC_UNUSED, + gpointer gself G_GNUC_UNUSED) +{ + /* no-op */ +} + +static void +notification_show(IndicatorPowerNotifier * self, + IndicatorPowerDevice * device) + +{ + priv_t * p = self->priv; + char * body; + NotifyNotification * nn; + + // if there's already a notification, tear it down + if (p->notify_notification != NULL) + { + notification_clear (self); + } + + // create the notification + body = g_strdup_printf(_("%d%% charge remaining"), (int)indicator_power_device_get_percentage(device)); + p->notify_notification = nn = notify_notification_new(_("Battery Low"), body, NULL); + notify_notification_set_hint(nn, "x-canonical-snap-decisions", g_variant_new_boolean(TRUE)); + notify_notification_set_hint(nn, "x-canonical-private-button-tint", g_variant_new_boolean(TRUE)); + notify_notification_add_action(nn, "OK", _("OK"), on_notification_clicked, self, NULL); + g_signal_connect_swapped(nn, "closed", G_CALLBACK(notification_clear), self); + + // show the notification + GError* error = NULL; + notify_notification_show(nn, &error); + if (error != NULL) + { + g_critical("Unable to show snap decision for '%s': %s", body, error->message); + g_error_free(error); + } + else + { + emit_show_signal(self); + } + + g_free (body); +} + +static void +on_battery_level_changed(IndicatorPowerNotifier * self G_GNUC_UNUSED, + IndicatorPowerDevice * device, + gdouble old_value, + gdouble new_value) +{ + static const double critical_level = 2.0; + static const double very_low_level = 5.0; + static const double low_level = 48.0; + + if (indicator_power_device_get_state(device) != UP_DEVICE_STATE_DISCHARGING) + return; + +g_message ("%s - %s - %f - %f", G_STRFUNC, indicator_power_device_get_object_path(device), old_value, new_value); + + if ((old_value > critical_level) && (new_value <= critical_level)) + { + emit_critical_signal(self); + } + else if ((old_value > very_low_level) && (new_value <= very_low_level)) + { + notification_show(self, device); + } + else if ((old_value > low_level) && (new_value <= low_level)) + { + notification_show(self, device); + } +} + +static void +on_devices_changed(IndicatorPowerNotifier * self) +{ + priv_t * p = self->priv; + GList * devices; + + // find the primary device + devices = indicator_power_device_provider_get_devices(p->device_provider); + g_clear_object(&p->primary_device); + p->primary_device = indicator_power_service_choose_primary_device (devices); + g_list_free_full (devices, (GDestroyNotify)g_object_unref); + + if (p->primary_device != NULL) + { + // test for battery level change + const gdouble old_level = (int)(p->battery_level*1000) ? p->battery_level : 100.0; + const gdouble new_level = indicator_power_device_get_percentage(p->primary_device); + if ((int)(old_level*1000) != (int)(new_level*1000)) + on_battery_level_changed (self, p->primary_device, old_level, new_level); + + p->battery_level = new_level; + p->time_remaining = indicator_power_device_get_time (p->primary_device); + } +} + +/*** +**** GObject virtual functions +***/ + +static void +my_get_property (GObject * o, + guint property_id, + GValue * value, + GParamSpec * pspec) +{ + IndicatorPowerNotifier * self = INDICATOR_POWER_NOTIFIER (o); + priv_t * p = self->priv; + + switch (property_id) + { + case PROP_DEVICE_PROVIDER: + g_value_set_object (value, p->device_provider); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); + } +} + +static void +my_set_property (GObject * o, + guint property_id, + const GValue * value, + GParamSpec * pspec) +{ + IndicatorPowerNotifier * self = INDICATOR_POWER_NOTIFIER (o); + + switch (property_id) + { + case PROP_DEVICE_PROVIDER: + indicator_power_notifier_set_device_provider (self, g_value_get_object (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); + } +} + +static void +my_dispose (GObject * o) +{ + IndicatorPowerNotifier * self = INDICATOR_POWER_NOTIFIER(o); + + indicator_power_notifier_set_device_provider(self, NULL); + notification_clear(self); + + G_OBJECT_CLASS (indicator_power_notifier_parent_class)->dispose (o); +} + +static void +my_finalize (GObject * o G_GNUC_UNUSED) +{ + if (!--n_notifiers) + notify_uninit(); +} + +/*** +**** Instantiation +***/ + +static void +indicator_power_notifier_init (IndicatorPowerNotifier * self) +{ + priv_t * p = G_TYPE_INSTANCE_GET_PRIVATE (self, + INDICATOR_TYPE_POWER_NOTIFIER, + IndicatorPowerNotifierPrivate); + self->priv = p; + + //p->battery_levels = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_variant_unref); + + if (!n_notifiers++ && !notify_init("indicator-power-service")) + g_critical("Unable to initialize libnotify! Notifications might not be shown."); +} + +static void +indicator_power_notifier_class_init (IndicatorPowerNotifierClass * klass) +{ + GObjectClass * object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = my_dispose; + object_class->finalize = my_finalize; + object_class->get_property = my_get_property; + object_class->set_property = my_set_property; + + g_type_class_add_private (klass, sizeof (IndicatorPowerNotifierPrivate)); + + properties[PROP_0] = NULL; + + properties[PROP_DEVICE_PROVIDER] = g_param_spec_object ( + "device-provider", + "Device Provider", + "Source for power devices", + G_TYPE_OBJECT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, LAST_PROP, properties); +} + +/*** +**** Public API +***/ + +IndicatorPowerNotifier * +indicator_power_notifier_new (IndicatorPowerDeviceProvider * device_provider) +{ + GObject * o = g_object_new (INDICATOR_TYPE_POWER_NOTIFIER, + "device-provider", device_provider, + NULL); + + return INDICATOR_POWER_NOTIFIER (o); +} + +void +indicator_power_notifier_set_device_provider(IndicatorPowerNotifier * self, + IndicatorPowerDeviceProvider * dp) +{ + priv_t * p; + + g_return_if_fail(INDICATOR_IS_POWER_NOTIFIER(self)); + g_return_if_fail(!dp || INDICATOR_IS_POWER_DEVICE_PROVIDER(dp)); + p = self->priv; + + if (p->device_provider != NULL) + { + g_signal_handlers_disconnect_by_data(p->device_provider, self); + g_clear_object(&p->device_provider); + g_clear_object(&p->primary_device); + } + + if (dp != NULL) + { + p->device_provider = g_object_ref(dp); + + g_signal_connect_swapped(p->device_provider, "devices-changed", + G_CALLBACK(on_devices_changed), self); + + on_devices_changed(self); + } +} diff --git a/src/notifier.h b/src/notifier.h new file mode 100644 index 0000000..e8dfaab --- /dev/null +++ b/src/notifier.h @@ -0,0 +1,68 @@ +/* + * Copyright 2014 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + * + * Authors: + * Charles Kerr + */ + +#ifndef __INDICATOR_POWER_NOTIFIER_H__ +#define __INDICATOR_POWER_NOTIFIER_H__ + +#include +#include + +#include "device-provider.h" + +G_BEGIN_DECLS + +/* standard GObject macros */ +#define INDICATOR_POWER_NOTIFIER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_POWER_NOTIFIER, IndicatorPowerNotifier)) +#define INDICATOR_TYPE_POWER_NOTIFIER (indicator_power_notifier_get_type()) +#define INDICATOR_IS_POWER_NOTIFIER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_POWER_NOTIFIER)) + +typedef struct _IndicatorPowerNotifier IndicatorPowerNotifier; +typedef struct _IndicatorPowerNotifierClass IndicatorPowerNotifierClass; +typedef struct _IndicatorPowerNotifierPrivate IndicatorPowerNotifierPrivate; + +/** + * The Indicator Power Notifier. + */ +struct _IndicatorPowerNotifier +{ + /*< private >*/ + GObject parent; + IndicatorPowerNotifierPrivate * priv; +}; + +struct _IndicatorPowerNotifierClass +{ + GObjectClass parent_class; +}; + +/*** +**** +***/ + +GType indicator_power_notifier_get_type (void); + +IndicatorPowerNotifier * indicator_power_notifier_new (IndicatorPowerDeviceProvider * provider); + +void indicator_power_notifier_set_device_provider (IndicatorPowerNotifier * self, + IndicatorPowerDeviceProvider * provider); + + +G_END_DECLS + +#endif /* __INDICATOR_POWER_NOTIFIER_H__ */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c5ad09d..4489bdc 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -42,5 +42,7 @@ function(add_test_by_name name) add_dependencies (${TEST_NAME} libindicatorpowerservice) target_link_libraries (${TEST_NAME} indicatorpowerservice gtest ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS}) endfunction() +add_test_by_name(test-notify) +add_test(NAME dear-reader-the-next-test-takes-80-seconds COMMAND true) add_test_by_name(test-device) diff --git a/tests/test-notify.cc b/tests/test-notify.cc new file mode 100644 index 0000000..0b75177 --- /dev/null +++ b/tests/test-notify.cc @@ -0,0 +1,59 @@ +/* + * Copyright 2014 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + * + * Authors: + * Charles Kerr + */ + +#include "device.h" +#include "service.h" + +#include + +#include + +class NotifyTest : public ::testing::Test +{ + private: + + typedef ::testing::Test super; + + protected: + + virtual void SetUp() + { + super::SetUp(); + } + + virtual void TearDown() + { + super::TearDown(); + } +}; + +/*** +**** +***/ + +// mock device provider + +// send notifications of a device going down from 50% to 3% by 1% increments + +// popup should appear exactly twice: once at 10%, once at 5% + +TEST_F(NotifyTest, HelloWorld) +{ +} + -- cgit v1.2.3 From 9f1ebe8f6c412ab18bdf32bf949fc00152d9671b Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Thu, 17 Jul 2014 14:46:23 -0500 Subject: replace 'std::vector' with 'std::vector' for readability --- tests/test-device.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/test-device.cc b/tests/test-device.cc index 1d10b5b..81e8a22 100644 --- a/tests/test-device.cc +++ b/tests/test-device.cc @@ -713,7 +713,7 @@ TEST_F(DeviceTest, ChoosePrimary) devices.push_back(indicator_power_device_new(desc.path, desc.kind, desc.percentage, desc.state, (time_t)desc.time)); const struct { - std::vector device_indices; + std::vector device_indices; Description expected; } tests[] = { -- cgit v1.2.3 From d5b42752328be0a217c1271656523399b8056f58 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 21 Jul 2014 12:21:54 -0500 Subject: add dbus-test-runner as a build dependency for tests --- debian/control | 11 +++++++---- tests/CMakeLists.txt | 7 ++++++- 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'tests') diff --git a/debian/control b/debian/control index 4571741..487a244 100644 --- a/debian/control +++ b/debian/control @@ -3,15 +3,18 @@ Section: gnome Priority: optional Maintainer: Ubuntu Core Developers Build-Depends: cmake, - debhelper (>= 9), - dh-translations, - intltool, libnotify-dev (>= 0.7.6), - libgtest-dev, libglib2.0-dev (>= 2.36), libgudev-1.0-dev, liburl-dispatcher1-dev, python:any, +# for packaging + debhelper (>= 9), + dh-translations, + intltool, +# for tests + libgtest-dev, + dbus-test-runner, Standards-Version: 3.9.2 Homepage: https://launchpad.net/indicator-power # If you aren't a member of ~indicator-applet-developers but need to upload diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 4489bdc..64b8ed8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,6 +5,11 @@ add_library (gtest STATIC set_target_properties (gtest PROPERTIES INCLUDE_DIRECTORIES ${INCLUDE_DIRECTORIES} ${GTEST_INCLUDE_DIR}) set_target_properties (gtest PROPERTIES COMPILE_FLAGS ${COMPILE_FLAGS} -w) +# dbustest +pkg_check_modules(DBUSTEST REQUIRED + dbustest-1>=14.04.0) +include_directories (SYSTEM ${DBUSTEST_INCLUDE_DIRS}) + # add warnings set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g ${C_WARNING_ARGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-weak-vtables -Wno-global-constructors") # Google Test @@ -40,7 +45,7 @@ function(add_test_by_name name) add_executable (${TEST_NAME} ${TEST_NAME}.cc gschemas.compiled) add_test (${TEST_NAME} ${TEST_NAME}) add_dependencies (${TEST_NAME} libindicatorpowerservice) - target_link_libraries (${TEST_NAME} indicatorpowerservice gtest ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS}) + target_link_libraries (${TEST_NAME} indicatorpowerservice gtest ${DBUSTEST_LIBRARIES} ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS}) endfunction() add_test_by_name(test-notify) add_test(NAME dear-reader-the-next-test-takes-80-seconds COMMAND true) -- cgit v1.2.3 From 125f6f6d02e195a668704ac8f8c7ca87940432b9 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 21 Jul 2014 12:32:49 -0500 Subject: copy the dbus-test-runner/dbusmock scaffolding for freedesktop Notifications from the indicator-datetime tests --- tests/glib-fixture.h | 138 ++++++++++++++++++++++++++++++++++++ tests/test-notify.cc | 192 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 316 insertions(+), 14 deletions(-) create mode 100644 tests/glib-fixture.h (limited to 'tests') diff --git a/tests/glib-fixture.h b/tests/glib-fixture.h new file mode 100644 index 0000000..46b9640 --- /dev/null +++ b/tests/glib-fixture.h @@ -0,0 +1,138 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include + +#include +#include +#include + +#include + +#include // setlocale() + +class GlibFixture : public ::testing::Test +{ + private: + + //GLogFunc realLogHandler; + + protected: + + std::map logCounts; + + void testLogCount(GLogLevelFlags log_level, int /*expected*/) + { +#if 0 + EXPECT_EQ(expected, logCounts[log_level]); +#endif + + logCounts.erase(log_level); + } + + private: + + static void default_log_handler(const gchar * log_domain, + GLogLevelFlags log_level, + const gchar * message, + gpointer self) + { + g_print("%s - %d - %s\n", log_domain, (int)log_level, message); + static_cast(self)->logCounts[log_level]++; + } + + protected: + + virtual void SetUp() + { + setlocale(LC_ALL, "C.UTF-8"); + + loop = g_main_loop_new(nullptr, false); + + //g_log_set_default_handler(default_log_handler, this); + + // only use local, temporary settings + g_assert(g_setenv("GSETTINGS_SCHEMA_DIR", SCHEMA_DIR, true)); + g_assert(g_setenv("GSETTINGS_BACKEND", "memory", true)); + g_debug("SCHEMA_DIR is %s", SCHEMA_DIR); + + g_unsetenv("DISPLAY"); + + } + + virtual void TearDown() + { +#if 0 + // confirm there aren't any unexpected log messages + EXPECT_EQ(0, logCounts[G_LOG_LEVEL_ERROR]); + EXPECT_EQ(0, logCounts[G_LOG_LEVEL_CRITICAL]); + EXPECT_EQ(0, logCounts[G_LOG_LEVEL_WARNING]); + EXPECT_EQ(0, logCounts[G_LOG_LEVEL_MESSAGE]); + EXPECT_EQ(0, logCounts[G_LOG_LEVEL_INFO]); +#endif + + // revert to glib's log handler + //g_log_set_default_handler(realLogHandler, this); + + g_clear_pointer(&loop, g_main_loop_unref); + } + + private: + + static gboolean + wait_for_signal__timeout(gpointer name) + { + g_error("%s: timed out waiting for signal '%s'", G_STRLOC, (char*)name); + return G_SOURCE_REMOVE; + } + + static gboolean + wait_msec__timeout(gpointer loop) + { + g_main_loop_quit(static_cast(loop)); + return G_SOURCE_CONTINUE; + } + + protected: + + /* convenience func to loop while waiting for a GObject's signal */ + void wait_for_signal(gpointer o, const gchar * signal, unsigned int timeout_seconds=5u) + { + // wait for the signal or for timeout, whichever comes first + const auto handler_id = g_signal_connect_swapped(o, signal, + G_CALLBACK(g_main_loop_quit), + loop); + const auto timeout_id = g_timeout_add_seconds(timeout_seconds, + wait_for_signal__timeout, + loop); + g_main_loop_run(loop); + g_source_remove(timeout_id); + g_signal_handler_disconnect(o, handler_id); + } + + /* convenience func to loop for N msec */ + void wait_msec(unsigned int msec=50u) + { + const auto id = g_timeout_add(msec, wait_msec__timeout, loop); + g_main_loop_run(loop); + g_source_remove(id); + } + + GMainLoop * loop; +}; diff --git a/tests/test-notify.cc b/tests/test-notify.cc index 0b75177..6ac3d82 100644 --- a/tests/test-notify.cc +++ b/tests/test-notify.cc @@ -17,30 +17,119 @@ * Charles Kerr */ + +#include "glib-fixture.h" + #include "device.h" -#include "service.h" +#include "notifier.h" #include +#include + +#include + +#include #include -class NotifyTest : public ::testing::Test +/*** +**** +***/ + +class NotifyFixture: public GlibFixture { - private: +private: + + typedef GlibFixture super; + + static constexpr char const * NOTIFY_BUSNAME {"org.freedesktop.Notifications"}; + static constexpr char const * NOTIFY_INTERFACE {"org.freedesktop.Notifications"}; + static constexpr char const * NOTIFY_PATH {"/org/freedesktop/Notifications"}; + + DbusTestService * service = nullptr; + DbusTestDbusMock * mock = nullptr; + DbusTestDbusMockObject * obj = nullptr; + GDBusConnection * bus = nullptr; + +protected: + + static constexpr int NOTIFY_ID {1234}; + + static constexpr int NOTIFICATION_CLOSED_EXPIRED {1}; + static constexpr int NOTIFICATION_CLOSED_DISMISSED {2}; + static constexpr int NOTIFICATION_CLOSED_API {3}; + static constexpr int NOTIFICATION_CLOSED_UNDEFINED {4}; + + static constexpr char const * APP_NAME {"indicator-power-service"}; + + static constexpr char const * METHOD_NOTIFY {"Notify"}; + static constexpr char const * METHOD_GET_CAPS {"GetCapabilities"}; + static constexpr char const * METHOD_GET_INFO {"GetServerInformation"}; + + static constexpr char const * HINT_TIMEOUT {"x-canonical-snap-decisions-timeout"}; + +protected: + + void SetUp() + { + super::SetUp(); + + // init DBusMock / dbus-test-runner + + service = dbus_test_service_new(NULL); + + GError * error = NULL; + mock = dbus_test_dbus_mock_new(NOTIFY_BUSNAME); + obj = dbus_test_dbus_mock_get_object(mock, NOTIFY_PATH, NOTIFY_INTERFACE, &error); + g_assert_no_error (error); + + dbus_test_dbus_mock_object_add_method(mock, obj, METHOD_GET_INFO, + NULL, + G_VARIANT_TYPE("(ssss)"), + "ret = ('mock-notify', 'test vendor', '1.0', '1.1')", // python + &error); + g_assert_no_error (error); + + auto python_str = g_strdup_printf ("ret = %d", NOTIFY_ID); + dbus_test_dbus_mock_object_add_method(mock, obj, METHOD_NOTIFY, + G_VARIANT_TYPE("(susssasa{sv}i)"), + G_VARIANT_TYPE_UINT32, + python_str, + &error); + g_free (python_str); + g_assert_no_error (error); + + dbus_test_service_add_task(service, DBUS_TEST_TASK(mock)); + dbus_test_service_start_tasks(service); + + bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); + g_dbus_connection_set_exit_on_close(bus, FALSE); + g_object_add_weak_pointer(G_OBJECT(bus), (gpointer *)&bus); - typedef ::testing::Test super; + notify_init(APP_NAME); + } - protected: + virtual void TearDown() + { + notify_uninit(); - virtual void SetUp() - { - super::SetUp(); - } + g_clear_object(&mock); + g_clear_object(&service); + g_object_unref(bus); - virtual void TearDown() - { - super::TearDown(); - } + // wait a little while for the scaffolding to shut down, + // but don't block on it forever... + unsigned int cleartry = 0; + while ((bus != NULL) && (cleartry < 50)) + { + g_usleep(100000); + while (g_main_pending()) + g_main_iteration(true); + cleartry++; + } + + super::TearDown(); + } }; /*** @@ -53,7 +142,82 @@ class NotifyTest : public ::testing::Test // popup should appear exactly twice: once at 10%, once at 5% -TEST_F(NotifyTest, HelloWorld) +TEST_F(NotifyFixture, HelloWorld) { } +#if 0 +using namespace unity::indicator::datetime; + +/*** +**** +***/ + +using namespace unity::indicator::datetime; + +class SnapFixture: public GlibFixture +{ + +/*** +**** +***/ + +namespace +{ + gboolean quit_idle (gpointer gloop) + { + g_main_loop_quit(static_cast(gloop)); + return G_SOURCE_REMOVE; + }; +} + +TEST_F(SnapFixture, InteractiveDuration) +{ + static constexpr int duration_minutes = 120; + auto settings = std::make_shared(); + settings->alarm_duration.set(duration_minutes); + auto timezones = std::make_shared(); + auto clock = std::make_shared(timezones); + Snap snap (clock, settings); + + // GetCapabilities returns an array containing 'actions', + // so our snap decision will be interactive. + // For this test, it means we should get a timeout Notify Hint + // that matches duration_minutes + GError * error = nullptr; + dbus_test_dbus_mock_object_add_method(mock, obj, METHOD_GET_CAPS, nullptr, G_VARIANT_TYPE_STRING_ARRAY, "ret = ['actions', 'body']", &error); + g_assert_no_error (error); + + // call the Snap Decision + auto func = [this](const Appointment&){g_idle_add(quit_idle, loop);}; + snap(appt, func, func); + + // confirm that Notify got called once + guint len = 0; + auto calls = dbus_test_dbus_mock_object_get_method_calls (mock, obj, METHOD_NOTIFY, &len, &error); + g_assert_no_error(error); + ASSERT_EQ(1, len); + + // confirm that the app_name passed to Notify was APP_NAME + const auto& params = calls[0].params; + ASSERT_EQ(8, g_variant_n_children(params)); + const char * str = nullptr; + g_variant_get_child (params, 0, "&s", &str); + ASSERT_STREQ(APP_NAME, str); + + // confirm that the icon passed to Notify was "alarm-clock" + g_variant_get_child (params, 2, "&s", &str); + ASSERT_STREQ("alarm-clock", str); + + // confirm that the hints passed to Notify included a timeout matching duration_minutes + int32_t i32; + bool b; + auto hints = g_variant_get_child_value (params, 6); + b = g_variant_lookup (hints, HINT_TIMEOUT, "i", &i32); + EXPECT_TRUE(b); + const auto duration = std::chrono::minutes(duration_minutes); + EXPECT_EQ(std::chrono::duration_cast(duration).count(), i32); + g_variant_unref(hints); +} +#endif + -- cgit v1.2.3 From 2cb851b018c5e7a0278dab75f73bb031c7c42422 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 21 Jul 2014 16:08:29 -0500 Subject: add tests to confirm that the DBus object's PowerLevel property changes at the right times (and only at the right times) when the battery is draining --- CMakeLists.txt | 3 +- src/notifier.c | 92 ++++++++++++++--------- src/notifier.h | 1 + tests/test-notify.cc | 208 ++++++++++++++++++++++++++++++++------------------- 4 files changed, 189 insertions(+), 115 deletions(-) (limited to 'tests') diff --git a/CMakeLists.txt b/CMakeLists.txt index d5d6a82..569100d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,7 +63,8 @@ add_custom_target (cppcheck COMMAND cppcheck --enable=all -q --error-exitcode=2 ## if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - set(C_WARNING_ARGS "${C_WARNING_ARGS} -Weverything -Wno-c++98-compat") + set(C_WARNING_ARGS "${C_WARNING_ARGS} -Weverything") + set(C_WARNING_ARGS "${C_WARNING_ARGS} -Wno-c++98-compat -Wno-padded") # these are annoying set(C_WARNING_ARGS "${C_WARNING_ARGS} -Wno-documentation") # gtk-doc != doxygen else() set(C_WARNING_ARGS "${C_WARNING_ARGS} -Wall -Wextra -Wpedantic -Wformat=2") diff --git a/src/notifier.c b/src/notifier.c index 9dd7550..c805413 100644 --- a/src/notifier.c +++ b/src/notifier.c @@ -153,28 +153,34 @@ notification_show(IndicatorPowerNotifier * self) **** ***/ -static PowerLevel -get_power_level (const IndicatorPowerDevice * device) +static void +on_battery_property_changed (IndicatorPowerNotifier * self) { - static const double percent_critical = 2.0; - static const double percent_very_low = 5.0; - static const double percent_low = 10.0; + priv_t * p; + PowerLevel power_level; - const gdouble p = indicator_power_device_get_percentage(device); - PowerLevel ret; + g_return_if_fail(INDICATOR_IS_POWER_NOTIFIER(self)); + g_return_if_fail(INDICATOR_IS_POWER_DEVICE(self->priv->battery)); - if (p <= percent_critical) - ret = POWER_LEVEL_CRITICAL; - else if (p <= percent_very_low) - ret = POWER_LEVEL_VERY_LOW; - else if (p <= percent_low) - ret = POWER_LEVEL_LOW; - else - ret = POWER_LEVEL_OK; + p = self->priv; - return ret; + power_level = indicator_power_notifier_get_power_level (p->battery); + + if (p->power_level != power_level) + { + set_power_level_property (self, power_level); + + if ((power_level == POWER_LEVEL_OK) || + (indicator_power_device_get_state(p->battery) != UP_DEVICE_STATE_DISCHARGING)) + { + notification_clear (self); + } + else + { + notification_show (self); + } + } } - /*** **** GObject virtual functions @@ -263,10 +269,10 @@ my_dispose (GObject * o) indicator_power_notifier_set_bus (self, NULL); notification_clear (self); - indicator_power_notifier_set_battery (self, NULL); g_clear_pointer (&p->power_level_binding, g_binding_unbind); g_clear_pointer (&p->is_warning_binding, g_binding_unbind); g_clear_object (&p->dbus_battery); + indicator_power_notifier_set_battery (self, NULL); G_OBJECT_CLASS (indicator_power_notifier_parent_class)->dispose (o); } @@ -327,7 +333,6 @@ indicator_power_notifier_init (IndicatorPowerNotifier * self) for (l=caps; l!=NULL && !klass->interactive; l=l->next) if (!g_strcmp0 ("actions", (const char*)l->data)) klass->interactive = TRUE; - g_message ("%s klass->interactive is %d", G_STRLOC, (int)klass->interactive); g_list_free_full (caps, g_free); } } @@ -400,8 +405,12 @@ indicator_power_notifier_set_battery (IndicatorPowerNotifier * self, p = self->priv; + if (p->battery == battery) + return; + if (p->battery != NULL) { + g_signal_handlers_disconnect_by_data (p->battery, self); g_clear_object (&p->battery); set_power_level_property (self, POWER_LEVEL_OK); notification_clear (self); @@ -409,24 +418,12 @@ indicator_power_notifier_set_battery (IndicatorPowerNotifier * self, if (battery != NULL) { - const PowerLevel power_level = get_power_level (battery); - - p->battery = g_object_ref(battery); - - if (p->power_level != power_level) - { - set_power_level_property (self, power_level); - - if ((power_level == POWER_LEVEL_OK) || - (indicator_power_device_get_state(battery) != UP_DEVICE_STATE_DISCHARGING)) - { - notification_clear (self); - } - else - { - notification_show (self); - } - } + p->battery = g_object_ref (battery); + g_signal_connect_swapped (p->battery, "notify::"INDICATOR_POWER_DEVICE_PERCENTAGE, + G_CALLBACK(on_battery_property_changed), self); + g_signal_connect_swapped (p->battery, "notify::"INDICATOR_POWER_DEVICE_STATE, + G_CALLBACK(on_battery_property_changed), self); + on_battery_property_changed (self); } } @@ -474,7 +471,28 @@ indicator_power_notifier_set_bus (IndicatorPowerNotifier * self, } } +PowerLevel +indicator_power_notifier_get_power_level (IndicatorPowerDevice * battery) +{ + static const double percent_critical = 2.0; + static const double percent_very_low = 5.0; + static const double percent_low = 10.0; + gdouble p; + PowerLevel ret; + g_return_val_if_fail(battery != NULL, POWER_LEVEL_OK); + g_return_val_if_fail(indicator_power_device_get_kind(battery) == UP_DEVICE_KIND_BATTERY, POWER_LEVEL_OK); + p = indicator_power_device_get_percentage(battery); + if (p <= percent_critical) + ret = POWER_LEVEL_CRITICAL; + else if (p <= percent_very_low) + ret = POWER_LEVEL_VERY_LOW; + else if (p <= percent_low) + ret = POWER_LEVEL_LOW; + else + ret = POWER_LEVEL_OK; + return ret; +} diff --git a/src/notifier.h b/src/notifier.h index cab053f..0e3ad99 100644 --- a/src/notifier.h +++ b/src/notifier.h @@ -80,6 +80,7 @@ void indicator_power_notifier_set_bus (IndicatorPowerNotifier * self, void indicator_power_notifier_set_battery (IndicatorPowerNotifier * self, IndicatorPowerDevice * battery); +PowerLevel indicator_power_notifier_get_power_level (IndicatorPowerDevice * battery); G_END_DECLS diff --git a/tests/test-notify.cc b/tests/test-notify.cc index 6ac3d82..cf1f9d3 100644 --- a/tests/test-notify.cc +++ b/tests/test-notify.cc @@ -20,6 +20,7 @@ #include "glib-fixture.h" +#include "dbus-shared.h" #include "device.h" #include "notifier.h" @@ -49,10 +50,11 @@ private: DbusTestService * service = nullptr; DbusTestDbusMock * mock = nullptr; DbusTestDbusMockObject * obj = nullptr; - GDBusConnection * bus = nullptr; protected: + GDBusConnection * bus = nullptr; + static constexpr int NOTIFY_ID {1234}; static constexpr int NOTIFICATION_CLOSED_EXPIRED {1}; @@ -76,15 +78,15 @@ protected: // init DBusMock / dbus-test-runner - service = dbus_test_service_new(NULL); + service = dbus_test_service_new(nullptr); - GError * error = NULL; + GError * error = nullptr; mock = dbus_test_dbus_mock_new(NOTIFY_BUSNAME); obj = dbus_test_dbus_mock_get_object(mock, NOTIFY_PATH, NOTIFY_INTERFACE, &error); g_assert_no_error (error); dbus_test_dbus_mock_object_add_method(mock, obj, METHOD_GET_INFO, - NULL, + nullptr, G_VARIANT_TYPE("(ssss)"), "ret = ('mock-notify', 'test vendor', '1.0', '1.1')", // python &error); @@ -102,7 +104,7 @@ protected: dbus_test_service_add_task(service, DBUS_TEST_TASK(mock)); dbus_test_service_start_tasks(service); - bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); + bus = g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, nullptr); g_dbus_connection_set_exit_on_close(bus, FALSE); g_object_add_weak_pointer(G_OBJECT(bus), (gpointer *)&bus); @@ -120,7 +122,7 @@ protected: // wait a little while for the scaffolding to shut down, // but don't block on it forever... unsigned int cleartry = 0; - while ((bus != NULL) && (cleartry < 50)) + while ((bus != nullptr) && (cleartry < 50)) { g_usleep(100000); while (g_main_pending()) @@ -136,88 +138,140 @@ protected: **** ***/ -// mock device provider - -// send notifications of a device going down from 50% to 3% by 1% increments - -// popup should appear exactly twice: once at 10%, once at 5% - +// simple test to confirm the NotifyFixture plumbing all works TEST_F(NotifyFixture, HelloWorld) { } -#if 0 -using namespace unity::indicator::datetime; - -/*** -**** -***/ - -using namespace unity::indicator::datetime; - -class SnapFixture: public GlibFixture -{ - -/*** -**** -***/ +// scaffolding to listen for PropertyChanged signals and remember them namespace { - gboolean quit_idle (gpointer gloop) + enum { - g_main_loop_quit(static_cast(gloop)); - return G_SOURCE_REMOVE; + FIELD_POWER_LEVEL = (1<<0), + FIELD_IS_WARNING = (1<<1) }; + + struct ChangedParams + { + int32_t power_level = POWER_LEVEL_OK; + bool is_warning = false; + uint32_t fields = 0; + }; + + void on_battery_property_changed (GDBusConnection *connection G_GNUC_UNUSED, + const gchar *sender_name G_GNUC_UNUSED, + const gchar *object_path G_GNUC_UNUSED, + const gchar *interface_name G_GNUC_UNUSED, + const gchar *signal_name G_GNUC_UNUSED, + GVariant *parameters, + gpointer gchanged_params) + { + g_return_if_fail (g_variant_n_children (parameters) == 3); + auto changed_properties = g_variant_get_child_value (parameters, 1); + g_return_if_fail (g_variant_is_of_type (changed_properties, G_VARIANT_TYPE_DICTIONARY)); + auto changed_params = static_cast(gchanged_params); + + gint32 power_level; + if (g_variant_lookup (changed_properties, "PowerLevel", "i", &power_level, nullptr)) + { + changed_params->power_level = power_level; + changed_params->fields |= FIELD_POWER_LEVEL; + } + + gboolean is_warning; + if (g_variant_lookup (changed_properties, "IsWarning", "b", &is_warning, nullptr)) + { + changed_params->is_warning = is_warning; + changed_params->fields |= FIELD_IS_WARNING; + } + + g_variant_unref (changed_properties); + } +} + +TEST_F(NotifyFixture, PercentageToLevel) +{ + auto battery = indicator_power_device_new ("/object/path", + UP_DEVICE_KIND_BATTERY, + 50.0, + UP_DEVICE_STATE_DISCHARGING, + 30); + + // confirm that the power levels trigger at the right percentages + for (int i=100; i>=0; --i) + { + g_object_set (battery, INDICATOR_POWER_DEVICE_PERCENTAGE, (gdouble)i, nullptr); + const auto level = indicator_power_notifier_get_power_level(battery); + + if (i <= 2) + EXPECT_EQ (POWER_LEVEL_CRITICAL, level); + else if (i <= 5) + EXPECT_EQ (POWER_LEVEL_VERY_LOW, level); + else if (i <= 10) + EXPECT_EQ (POWER_LEVEL_LOW, level); + else + EXPECT_EQ (POWER_LEVEL_OK, level); + } + + g_object_unref (battery); } -TEST_F(SnapFixture, InteractiveDuration) + +TEST_F(NotifyFixture, LevelsDuringBatteryDrain) { - static constexpr int duration_minutes = 120; - auto settings = std::make_shared(); - settings->alarm_duration.set(duration_minutes); - auto timezones = std::make_shared(); - auto clock = std::make_shared(timezones); - Snap snap (clock, settings); - - // GetCapabilities returns an array containing 'actions', - // so our snap decision will be interactive. - // For this test, it means we should get a timeout Notify Hint - // that matches duration_minutes - GError * error = nullptr; - dbus_test_dbus_mock_object_add_method(mock, obj, METHOD_GET_CAPS, nullptr, G_VARIANT_TYPE_STRING_ARRAY, "ret = ['actions', 'body']", &error); - g_assert_no_error (error); - - // call the Snap Decision - auto func = [this](const Appointment&){g_idle_add(quit_idle, loop);}; - snap(appt, func, func); - - // confirm that Notify got called once - guint len = 0; - auto calls = dbus_test_dbus_mock_object_get_method_calls (mock, obj, METHOD_NOTIFY, &len, &error); - g_assert_no_error(error); - ASSERT_EQ(1, len); - - // confirm that the app_name passed to Notify was APP_NAME - const auto& params = calls[0].params; - ASSERT_EQ(8, g_variant_n_children(params)); - const char * str = nullptr; - g_variant_get_child (params, 0, "&s", &str); - ASSERT_STREQ(APP_NAME, str); - - // confirm that the icon passed to Notify was "alarm-clock" - g_variant_get_child (params, 2, "&s", &str); - ASSERT_STREQ("alarm-clock", str); - - // confirm that the hints passed to Notify included a timeout matching duration_minutes - int32_t i32; - bool b; - auto hints = g_variant_get_child_value (params, 6); - b = g_variant_lookup (hints, HINT_TIMEOUT, "i", &i32); - EXPECT_TRUE(b); - const auto duration = std::chrono::minutes(duration_minutes); - EXPECT_EQ(std::chrono::duration_cast(duration).count(), i32); - g_variant_unref(hints); + auto battery = indicator_power_device_new ("/object/path", + UP_DEVICE_KIND_BATTERY, + 50.0, + UP_DEVICE_STATE_DISCHARGING, + 30); + + // set up a notifier and give it the battery so changing the battery's + // charge should show up on the bus. + auto notifier = indicator_power_notifier_new (); + indicator_power_notifier_set_battery (notifier, battery); + indicator_power_notifier_set_bus (notifier, bus); + wait_msec(); + + ChangedParams changed_params; + auto subscription_tag = g_dbus_connection_signal_subscribe (bus, + nullptr, + "org.freedesktop.DBus.Properties", + "PropertiesChanged", + BUS_PATH"/Battery", + nullptr, + G_DBUS_SIGNAL_FLAGS_NONE, + on_battery_property_changed, + &changed_params, + nullptr); + + // confirm that draining the battery puts + // the power_level change through its paces + for (int i=100; i>=0; --i) + { + changed_params = ChangedParams(); + EXPECT_TRUE (changed_params.fields == 0); + + const auto old_level = indicator_power_notifier_get_power_level(battery); + g_object_set (battery, INDICATOR_POWER_DEVICE_PERCENTAGE, (gdouble)i, nullptr); + const auto new_level = indicator_power_notifier_get_power_level(battery); + wait_msec(); + + if (old_level == new_level) + { + EXPECT_EQ (0, changed_params.fields); + } + else + { + EXPECT_EQ (FIELD_POWER_LEVEL, changed_params.fields); + EXPECT_EQ (new_level, changed_params.power_level); + } + } + + // cleanup + g_dbus_connection_signal_unsubscribe (bus, subscription_tag); + g_object_unref (notifier); + g_object_unref (battery); } -#endif -- cgit v1.2.3 From 1bd1b700892a786fd01410a4b81b2f2cc93a89c1 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 21 Jul 2014 17:13:15 -0500 Subject: add tests for events that change whether or not a 'low battery' notification is being shown --- src/notifier.c | 23 +++++-------- tests/test-notify.cc | 97 ++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 100 insertions(+), 20 deletions(-) (limited to 'tests') diff --git a/src/notifier.c b/src/notifier.c index c805413..fc54e62 100644 --- a/src/notifier.c +++ b/src/notifier.c @@ -157,28 +157,23 @@ static void on_battery_property_changed (IndicatorPowerNotifier * self) { priv_t * p; - PowerLevel power_level; g_return_if_fail(INDICATOR_IS_POWER_NOTIFIER(self)); g_return_if_fail(INDICATOR_IS_POWER_DEVICE(self->priv->battery)); p = self->priv; - power_level = indicator_power_notifier_get_power_level (p->battery); + set_power_level_property (self, + indicator_power_notifier_get_power_level (p->battery)); - if (p->power_level != power_level) + if ((indicator_power_device_get_state(p->battery) == UP_DEVICE_STATE_DISCHARGING) && + (p->power_level != POWER_LEVEL_OK)) { - set_power_level_property (self, power_level); - - if ((power_level == POWER_LEVEL_OK) || - (indicator_power_device_get_state(p->battery) != UP_DEVICE_STATE_DISCHARGING)) - { - notification_clear (self); - } - else - { - notification_show (self); - } + notification_show (self); + } + else + { + notification_clear (self); } } diff --git a/tests/test-notify.cc b/tests/test-notify.cc index cf1f9d3..d5d7e9f 100644 --- a/tests/test-notify.cc +++ b/tests/test-notify.cc @@ -47,12 +47,11 @@ private: static constexpr char const * NOTIFY_INTERFACE {"org.freedesktop.Notifications"}; static constexpr char const * NOTIFY_PATH {"/org/freedesktop/Notifications"}; +protected: + DbusTestService * service = nullptr; DbusTestDbusMock * mock = nullptr; DbusTestDbusMockObject * obj = nullptr; - -protected: - GDBusConnection * bus = nullptr; static constexpr int NOTIFY_ID {1234}; @@ -189,6 +188,10 @@ namespace g_variant_unref (changed_properties); } + + static const double percent_critical = 2.0; + static const double percent_very_low = 5.0; + static const double percent_low = 10.0; } TEST_F(NotifyFixture, PercentageToLevel) @@ -205,11 +208,11 @@ TEST_F(NotifyFixture, PercentageToLevel) g_object_set (battery, INDICATOR_POWER_DEVICE_PERCENTAGE, (gdouble)i, nullptr); const auto level = indicator_power_notifier_get_power_level(battery); - if (i <= 2) + if (i <= percent_critical) EXPECT_EQ (POWER_LEVEL_CRITICAL, level); - else if (i <= 5) + else if (i <= percent_very_low) EXPECT_EQ (POWER_LEVEL_VERY_LOW, level); - else if (i <= 10) + else if (i <= percent_low) EXPECT_EQ (POWER_LEVEL_LOW, level); else EXPECT_EQ (POWER_LEVEL_OK, level); @@ -275,3 +278,85 @@ TEST_F(NotifyFixture, LevelsDuringBatteryDrain) g_object_unref (battery); } + +// confirm that notifications pop up +// when a discharging battery's power level drops +TEST_F(NotifyFixture, EventsThatChangeNotifications) +{ + // GetCapabilities returns an array containing 'actions', so that we'll + // get snap decisions and the 'IsWarning' property + GError * error = nullptr; + dbus_test_dbus_mock_object_add_method(mock, obj, METHOD_GET_CAPS, nullptr, G_VARIANT_TYPE_STRING_ARRAY, "ret = ['actions', 'body']", &error); + g_assert_no_error (error); + + auto battery = indicator_power_device_new ("/object/path", + UP_DEVICE_KIND_BATTERY, + percent_low + 1.0, + UP_DEVICE_STATE_DISCHARGING, + 30); + + // set up a notifier and give it the battery so changing the battery's + // charge should show up on the bus. + auto notifier = indicator_power_notifier_new (); + indicator_power_notifier_set_battery (notifier, battery); + indicator_power_notifier_set_bus (notifier, bus); + ChangedParams changed_params; + auto subscription_tag = g_dbus_connection_signal_subscribe (bus, + nullptr, + "org.freedesktop.DBus.Properties", + "PropertiesChanged", + BUS_PATH"/Battery", + nullptr, + G_DBUS_SIGNAL_FLAGS_NONE, + on_battery_property_changed, + &changed_params, + nullptr); + + // test setup case + wait_msec(); + EXPECT_EQ (0, changed_params.power_level); + + // change the percent past the 'low' threshold and confirm that + // a) the power level changes + // b) we get a notification + changed_params = ChangedParams(); + g_object_set (battery, INDICATOR_POWER_DEVICE_PERCENTAGE, (gdouble)percent_low, nullptr); + wait_msec(); + EXPECT_EQ (FIELD_POWER_LEVEL|FIELD_IS_WARNING, changed_params.fields); + EXPECT_EQ (indicator_power_notifier_get_power_level(battery), changed_params.power_level); + EXPECT_TRUE (changed_params.is_warning); + + // now test that the warning changes if the level goes down even lower... + changed_params = ChangedParams(); + g_object_set (battery, INDICATOR_POWER_DEVICE_PERCENTAGE, (gdouble)percent_very_low, nullptr); + wait_msec(); + EXPECT_EQ (FIELD_POWER_LEVEL, changed_params.fields); + EXPECT_EQ (POWER_LEVEL_VERY_LOW, changed_params.power_level); + + // ...and that the warning is taken down if the battery is plugged back in... + changed_params = ChangedParams(); + g_object_set (battery, INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_CHARGING, nullptr); + wait_msec(); + EXPECT_EQ (FIELD_IS_WARNING, changed_params.fields); + EXPECT_FALSE (changed_params.is_warning); + + // ...and that it comes back if we unplug again... + changed_params = ChangedParams(); + g_object_set (battery, INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING, nullptr); + wait_msec(); + EXPECT_EQ (FIELD_IS_WARNING, changed_params.fields); + EXPECT_TRUE (changed_params.is_warning); + + // ...and that it's taken down if the power level is OK + changed_params = ChangedParams(); + g_object_set (battery, INDICATOR_POWER_DEVICE_PERCENTAGE, (gdouble)percent_low+1, nullptr); + wait_msec(); + EXPECT_EQ (FIELD_POWER_LEVEL|FIELD_IS_WARNING, changed_params.fields); + EXPECT_EQ (POWER_LEVEL_OK, changed_params.power_level); + EXPECT_FALSE (changed_params.is_warning); + + // cleanup + g_dbus_connection_signal_unsubscribe (bus, subscription_tag); + g_object_unref (notifier); + g_object_unref (battery); +} -- cgit v1.2.3 From 9c3d863d5e0ebe35ae69dedb5219519f0ced9339 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 22 Jul 2014 09:53:53 -0500 Subject: copyediting: code cleanup --- src/notifier.c | 18 ++++-- tests/test-notify.cc | 163 +++++++++++++++++++++++++++++---------------------- 2 files changed, 106 insertions(+), 75 deletions(-) (limited to 'tests') diff --git a/src/notifier.c b/src/notifier.c index 80db10d..bf52739 100644 --- a/src/notifier.c +++ b/src/notifier.c @@ -73,8 +73,11 @@ struct _IndicatorPowerNotifierPrivate typedef IndicatorPowerNotifierPrivate priv_t; -static void set_is_warning_property (IndicatorPowerNotifier*, gboolean is_warning); -static void set_power_level_property (IndicatorPowerNotifier*, PowerLevel power_level); +static void set_is_warning_property (IndicatorPowerNotifier*, + gboolean is_warning); + +static void set_power_level_property (IndicatorPowerNotifier*, + PowerLevel power_level); /*** **** Notifications @@ -101,7 +104,7 @@ on_notification_clicked(NotifyNotification * notify_notification G_GNUC_UNUSED, char * action G_GNUC_UNUSED, gpointer gself G_GNUC_UNUSED) { - /* no-op; notify_notification_add_action() doesn't like NULL callbacks */ + /* no-op: notify_notification_add_action() doesn't like NULL callbacks */ } static void @@ -183,9 +186,9 @@ on_battery_property_changed (IndicatorPowerNotifier * self) static void my_get_property (GObject * o, - guint property_id, - GValue * value, - GParamSpec * pspec) + guint property_id, + GValue * value, + GParamSpec * pspec) { IndicatorPowerNotifier * self = INDICATOR_POWER_NOTIFIER (o); priv_t * p = self->priv; @@ -296,6 +299,8 @@ indicator_power_notifier_init (IndicatorPowerNotifier * self) IndicatorPowerNotifierPrivate); self->priv = p; + /* bind the read-only properties so they'll get pushed to the bus */ + p->dbus_battery = dbus_battery_skeleton_new (); p->is_warning_binding = g_object_bind_property (self, @@ -330,6 +335,7 @@ indicator_power_notifier_init (IndicatorPowerNotifier * self) klass->interactive = TRUE; g_list_free_full (caps, g_free); } + g_debug ("Will show popups on low battery: %d", (int)klass->interactive); } } diff --git a/tests/test-notify.cc b/tests/test-notify.cc index d5d7e9f..74a08dc 100644 --- a/tests/test-notify.cc +++ b/tests/test-notify.cc @@ -81,13 +81,16 @@ protected: GError * error = nullptr; mock = dbus_test_dbus_mock_new(NOTIFY_BUSNAME); - obj = dbus_test_dbus_mock_get_object(mock, NOTIFY_PATH, NOTIFY_INTERFACE, &error); + obj = dbus_test_dbus_mock_get_object(mock, + NOTIFY_PATH, + NOTIFY_INTERFACE, + &error); g_assert_no_error (error); dbus_test_dbus_mock_object_add_method(mock, obj, METHOD_GET_INFO, nullptr, G_VARIANT_TYPE("(ssss)"), - "ret = ('mock-notify', 'test vendor', '1.0', '1.1')", // python + "ret = ('mock-notify', 'test vendor', '1.0', '1.1')", &error); g_assert_no_error (error); @@ -142,8 +145,55 @@ TEST_F(NotifyFixture, HelloWorld) { } +/*** +**** +***/ + + +namespace +{ + static constexpr double percent_critical {2.0}; + static constexpr double percent_very_low {5.0}; + static constexpr double percent_low {10.0}; + + void set_battery_percentage (IndicatorPowerDevice * battery, gdouble p) + { + g_object_set (battery, INDICATOR_POWER_DEVICE_PERCENTAGE, p, nullptr); + } +} + +TEST_F(NotifyFixture, PercentageToLevel) +{ + auto battery = indicator_power_device_new ("/object/path", + UP_DEVICE_KIND_BATTERY, + 50.0, + UP_DEVICE_STATE_DISCHARGING, + 30); + + // confirm that the power levels trigger at the right percentages + for (int i=100; i>=0; --i) + { + set_battery_percentage (battery, i); + const auto level = indicator_power_notifier_get_power_level(battery); + + if (i <= percent_critical) + EXPECT_EQ (POWER_LEVEL_CRITICAL, level); + else if (i <= percent_very_low) + EXPECT_EQ (POWER_LEVEL_VERY_LOW, level); + else if (i <= percent_low) + EXPECT_EQ (POWER_LEVEL_LOW, level); + else + EXPECT_EQ (POWER_LEVEL_OK, level); + } + + g_object_unref (battery); +} + +/*** +**** +***/ -// scaffolding to listen for PropertyChanged signals and remember them +// scaffolding to monitor PropertyChanged signals namespace { enum @@ -168,60 +218,28 @@ namespace gpointer gchanged_params) { g_return_if_fail (g_variant_n_children (parameters) == 3); - auto changed_properties = g_variant_get_child_value (parameters, 1); - g_return_if_fail (g_variant_is_of_type (changed_properties, G_VARIANT_TYPE_DICTIONARY)); + auto dict = g_variant_get_child_value (parameters, 1); + g_return_if_fail (g_variant_is_of_type (dict, G_VARIANT_TYPE_DICTIONARY)); auto changed_params = static_cast(gchanged_params); gint32 power_level; - if (g_variant_lookup (changed_properties, "PowerLevel", "i", &power_level, nullptr)) + if (g_variant_lookup (dict, "PowerLevel", "i", &power_level, nullptr)) { changed_params->power_level = power_level; changed_params->fields |= FIELD_POWER_LEVEL; } gboolean is_warning; - if (g_variant_lookup (changed_properties, "IsWarning", "b", &is_warning, nullptr)) + if (g_variant_lookup (dict, "IsWarning", "b", &is_warning, nullptr)) { changed_params->is_warning = is_warning; changed_params->fields |= FIELD_IS_WARNING; } - g_variant_unref (changed_properties); + g_variant_unref (dict); } - - static const double percent_critical = 2.0; - static const double percent_very_low = 5.0; - static const double percent_low = 10.0; -} - -TEST_F(NotifyFixture, PercentageToLevel) -{ - auto battery = indicator_power_device_new ("/object/path", - UP_DEVICE_KIND_BATTERY, - 50.0, - UP_DEVICE_STATE_DISCHARGING, - 30); - - // confirm that the power levels trigger at the right percentages - for (int i=100; i>=0; --i) - { - g_object_set (battery, INDICATOR_POWER_DEVICE_PERCENTAGE, (gdouble)i, nullptr); - const auto level = indicator_power_notifier_get_power_level(battery); - - if (i <= percent_critical) - EXPECT_EQ (POWER_LEVEL_CRITICAL, level); - else if (i <= percent_very_low) - EXPECT_EQ (POWER_LEVEL_VERY_LOW, level); - else if (i <= percent_low) - EXPECT_EQ (POWER_LEVEL_LOW, level); - else - EXPECT_EQ (POWER_LEVEL_OK, level); - } - - g_object_unref (battery); } - TEST_F(NotifyFixture, LevelsDuringBatteryDrain) { auto battery = indicator_power_device_new ("/object/path", @@ -238,16 +256,16 @@ TEST_F(NotifyFixture, LevelsDuringBatteryDrain) wait_msec(); ChangedParams changed_params; - auto subscription_tag = g_dbus_connection_signal_subscribe (bus, - nullptr, - "org.freedesktop.DBus.Properties", - "PropertiesChanged", - BUS_PATH"/Battery", - nullptr, - G_DBUS_SIGNAL_FLAGS_NONE, - on_battery_property_changed, - &changed_params, - nullptr); + auto sub_tag = g_dbus_connection_signal_subscribe (bus, + nullptr, + "org.freedesktop.DBus.Properties", + "PropertiesChanged", + BUS_PATH"/Battery", + nullptr, + G_DBUS_SIGNAL_FLAGS_NONE, + on_battery_property_changed, + &changed_params, + nullptr); // confirm that draining the battery puts // the power_level change through its paces @@ -257,7 +275,7 @@ TEST_F(NotifyFixture, LevelsDuringBatteryDrain) EXPECT_TRUE (changed_params.fields == 0); const auto old_level = indicator_power_notifier_get_power_level(battery); - g_object_set (battery, INDICATOR_POWER_DEVICE_PERCENTAGE, (gdouble)i, nullptr); + set_battery_percentage (battery, i); const auto new_level = indicator_power_notifier_get_power_level(battery); wait_msec(); @@ -273,20 +291,27 @@ TEST_F(NotifyFixture, LevelsDuringBatteryDrain) } // cleanup - g_dbus_connection_signal_unsubscribe (bus, subscription_tag); + g_dbus_connection_signal_unsubscribe (bus, sub_tag); g_object_unref (notifier); g_object_unref (battery); } +/*** +**** +***/ -// confirm that notifications pop up -// when a discharging battery's power level drops TEST_F(NotifyFixture, EventsThatChangeNotifications) { // GetCapabilities returns an array containing 'actions', so that we'll // get snap decisions and the 'IsWarning' property GError * error = nullptr; - dbus_test_dbus_mock_object_add_method(mock, obj, METHOD_GET_CAPS, nullptr, G_VARIANT_TYPE_STRING_ARRAY, "ret = ['actions', 'body']", &error); + dbus_test_dbus_mock_object_add_method (mock, + obj, + METHOD_GET_CAPS, + nullptr, + G_VARIANT_TYPE_STRING_ARRAY, + "ret = ['actions', 'body']", + &error); g_assert_no_error (error); auto battery = indicator_power_device_new ("/object/path", @@ -301,16 +326,16 @@ TEST_F(NotifyFixture, EventsThatChangeNotifications) indicator_power_notifier_set_battery (notifier, battery); indicator_power_notifier_set_bus (notifier, bus); ChangedParams changed_params; - auto subscription_tag = g_dbus_connection_signal_subscribe (bus, - nullptr, - "org.freedesktop.DBus.Properties", - "PropertiesChanged", - BUS_PATH"/Battery", - nullptr, - G_DBUS_SIGNAL_FLAGS_NONE, - on_battery_property_changed, - &changed_params, - nullptr); + auto sub_tag = g_dbus_connection_signal_subscribe (bus, + nullptr, + "org.freedesktop.DBus.Properties", + "PropertiesChanged", + BUS_PATH"/Battery", + nullptr, + G_DBUS_SIGNAL_FLAGS_NONE, + on_battery_property_changed, + &changed_params, + nullptr); // test setup case wait_msec(); @@ -320,7 +345,7 @@ TEST_F(NotifyFixture, EventsThatChangeNotifications) // a) the power level changes // b) we get a notification changed_params = ChangedParams(); - g_object_set (battery, INDICATOR_POWER_DEVICE_PERCENTAGE, (gdouble)percent_low, nullptr); + set_battery_percentage (battery, percent_low); wait_msec(); EXPECT_EQ (FIELD_POWER_LEVEL|FIELD_IS_WARNING, changed_params.fields); EXPECT_EQ (indicator_power_notifier_get_power_level(battery), changed_params.power_level); @@ -328,7 +353,7 @@ TEST_F(NotifyFixture, EventsThatChangeNotifications) // now test that the warning changes if the level goes down even lower... changed_params = ChangedParams(); - g_object_set (battery, INDICATOR_POWER_DEVICE_PERCENTAGE, (gdouble)percent_very_low, nullptr); + set_battery_percentage (battery, percent_very_low); wait_msec(); EXPECT_EQ (FIELD_POWER_LEVEL, changed_params.fields); EXPECT_EQ (POWER_LEVEL_VERY_LOW, changed_params.power_level); @@ -349,14 +374,14 @@ TEST_F(NotifyFixture, EventsThatChangeNotifications) // ...and that it's taken down if the power level is OK changed_params = ChangedParams(); - g_object_set (battery, INDICATOR_POWER_DEVICE_PERCENTAGE, (gdouble)percent_low+1, nullptr); + set_battery_percentage (battery, percent_low+1); wait_msec(); EXPECT_EQ (FIELD_POWER_LEVEL|FIELD_IS_WARNING, changed_params.fields); EXPECT_EQ (POWER_LEVEL_OK, changed_params.power_level); EXPECT_FALSE (changed_params.is_warning); // cleanup - g_dbus_connection_signal_unsubscribe (bus, subscription_tag); + g_dbus_connection_signal_unsubscribe (bus, sub_tag); g_object_unref (notifier); g_object_unref (battery); } -- cgit v1.2.3 From 399eab24252eb7c83042de726ebbc4cf9fbb7637 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 22 Jul 2014 09:58:29 -0500 Subject: add indicator-power-service-cmdline-battery, a manual test utility to test the indicator's behavior when a battery's state changes --- tests/CMakeLists.txt | 8 ++ tests/device-provider-mock.c | 107 +++++++++++++++++++ tests/device-provider-mock.h | 79 +++++++++++++++ tests/indicator-power-service-cmdline-battery.cc | 124 +++++++++++++++++++++++ 4 files changed, 318 insertions(+) create mode 100644 tests/device-provider-mock.c create mode 100644 tests/device-provider-mock.h create mode 100644 tests/indicator-power-service-cmdline-battery.cc (limited to 'tests') diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 64b8ed8..a0d24af 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -51,3 +51,11 @@ add_test_by_name(test-notify) add_test(NAME dear-reader-the-next-test-takes-80-seconds COMMAND true) add_test_by_name(test-device) +### +### + +set (APP_NAME indicator-power-service-cmdline-battery) +add_executable (${APP_NAME} ${APP_NAME}.cc device-provider-mock.c) +add_dependencies (${APP_NAME} libindicatorpowerservice) +target_link_libraries (${APP_NAME} indicatorpowerservice ${SERVICE_DEPS_LIBRARIES}) + diff --git a/tests/device-provider-mock.c b/tests/device-provider-mock.c new file mode 100644 index 0000000..afca178 --- /dev/null +++ b/tests/device-provider-mock.c @@ -0,0 +1,107 @@ +/* + * Copyright 2014 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + * + * Authors: + * Charles Kerr + */ + +#include "device.h" +#include "device-provider.h" +#include "device-provider-mock.h" + +/*** +**** GObject boilerplate +***/ + +static void indicator_power_device_provider_interface_init ( + IndicatorPowerDeviceProviderInterface * iface); + +G_DEFINE_TYPE_WITH_CODE ( + IndicatorPowerDeviceProviderMock, + indicator_power_device_provider_mock, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (INDICATOR_TYPE_POWER_DEVICE_PROVIDER, + indicator_power_device_provider_interface_init)) + +/*** +**** IndicatorPowerDeviceProvider virtual functions +***/ + +static GList * +my_get_devices (IndicatorPowerDeviceProvider * provider) +{ + IndicatorPowerDeviceProviderMock * self = INDICATOR_POWER_DEVICE_PROVIDER_MOCK(provider); + + return g_list_copy_deep (self->devices, (GCopyFunc)g_object_ref, NULL); +} + +/*** +**** GObject virtual functions +***/ + +static void +my_dispose (GObject * o) +{ + IndicatorPowerDeviceProviderMock * self = INDICATOR_POWER_DEVICE_PROVIDER_MOCK(o); + + g_list_free_full (self->devices, g_object_unref); + + G_OBJECT_CLASS (indicator_power_device_provider_mock_parent_class)->dispose (o); +} + +/*** +**** Instantiation +***/ + +static void +indicator_power_device_provider_mock_class_init (IndicatorPowerDeviceProviderMockClass * klass) +{ + GObjectClass * object_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->dispose = my_dispose; +} + +static void +indicator_power_device_provider_interface_init (IndicatorPowerDeviceProviderInterface * iface) +{ + iface->get_devices = my_get_devices; +} + +static void +indicator_power_device_provider_mock_init (IndicatorPowerDeviceProviderMock * self) +{ +} + +/*** +**** Public API +***/ + +IndicatorPowerDeviceProvider * +indicator_power_device_provider_mock_new (void) +{ + gpointer o = g_object_new (INDICATOR_TYPE_POWER_DEVICE_PROVIDER_MOCK, NULL); + + return INDICATOR_POWER_DEVICE_PROVIDER (o); +} + +void +indicator_power_device_provider_add_device (IndicatorPowerDeviceProviderMock * provider, + IndicatorPowerDevice * device) +{ + provider->devices = g_list_append (provider->devices, g_object_ref(device)); + + g_signal_connect_swapped (device, "notify", G_CALLBACK(indicator_power_device_provider_emit_devices_changed), provider); +} diff --git a/tests/device-provider-mock.h b/tests/device-provider-mock.h new file mode 100644 index 0000000..4d06924 --- /dev/null +++ b/tests/device-provider-mock.h @@ -0,0 +1,79 @@ +/* + * Copyright 2014 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + * + * Authors: + * Charles Kerr + */ + +#ifndef __INDICATOR_POWER_DEVICE_PROVIDER_MOCK__H__ +#define __INDICATOR_POWER_DEVICE_PROVIDER_MOCK__H__ + +#include /* parent class */ + +#include "device.h" +#include "device-provider.h" + +G_BEGIN_DECLS + +#define INDICATOR_TYPE_POWER_DEVICE_PROVIDER_MOCK \ + (indicator_power_device_provider_mock_get_type()) + +#define INDICATOR_POWER_DEVICE_PROVIDER_MOCK(o) \ + (G_TYPE_CHECK_INSTANCE_CAST ((o), \ + INDICATOR_TYPE_POWER_DEVICE_PROVIDER_MOCK, \ + IndicatorPowerDeviceProviderMock)) + +#define INDICATOR_POWER_DEVICE_PROVIDER_MOCK_GET_CLASS(o) \ + (G_TYPE_INSTANCE_GET_CLASS ((o), \ + INDICATOR_TYPE_POWER_DEVICE_PROVIDER_MOCK, \ + IndicatorPowerDeviceProviderMockClass)) + +#define INDICATOR_IS_POWER_DEVICE_PROVIDER_MOCK(o) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((o), \ + INDICATOR_TYPE_POWER_DEVICE_PROVIDER_MOCK)) + +typedef struct _IndicatorPowerDeviceProviderMock + IndicatorPowerDeviceProviderMock; +typedef struct _IndicatorPowerDeviceProviderMockPriv + IndicatorPowerDeviceProviderMockPriv; +typedef struct _IndicatorPowerDeviceProviderMockClass + IndicatorPowerDeviceProviderMockClass; + +/** + * An IndicatorPowerDeviceProvider which gets its devices from Mock. + */ +struct _IndicatorPowerDeviceProviderMock +{ + GObject parent_instance; + + /*< private >*/ + GList * devices; +}; + +struct _IndicatorPowerDeviceProviderMockClass +{ + GObjectClass parent_class; +}; + +GType indicator_power_device_provider_mock_get_type (void); + +IndicatorPowerDeviceProvider * indicator_power_device_provider_mock_new (void); + +void indicator_power_device_provider_add_device (IndicatorPowerDeviceProviderMock * provider, + IndicatorPowerDevice * device); + +G_END_DECLS + +#endif /* __INDICATOR_POWER_DEVICE_PROVIDER_MOCK__H__ */ diff --git a/tests/indicator-power-service-cmdline-battery.cc b/tests/indicator-power-service-cmdline-battery.cc new file mode 100644 index 0000000..a7a86a1 --- /dev/null +++ b/tests/indicator-power-service-cmdline-battery.cc @@ -0,0 +1,124 @@ +/* + * Copyright 2014 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + * + * Authors: + * Charles Kerr + */ + +#include + +#include // setlocale() +#include // bindtextdomain() +#include // STDIN_FILENO + +#include + +#include "device-provider-mock.h" + +#include "service.h" + +/*** +**** +***/ + +static void +on_name_lost (gpointer instance G_GNUC_UNUSED, gpointer loop) +{ + g_message ("exiting: service couldn't acquire or lost ownership of busname"); + g_main_loop_quit ((GMainLoop*)loop); +} + +static IndicatorPowerDevice * battery = nullptr; + +static GMainLoop * loop = nullptr; + +static gboolean on_command_stream_available (GIOChannel *source, + GIOCondition /*condition*/, + gpointer /*user_data*/) +{ + gchar * str = nullptr; + GError * error = nullptr; + auto status = g_io_channel_read_line (source, &str, nullptr, nullptr, &error); + g_assert_no_error (error); + + if (status == G_IO_STATUS_NORMAL) + { + g_strstrip (str); + + if (!g_strcmp0 (str, "charging")) + { + g_object_set (battery, INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_CHARGING, nullptr); + } + else if (!g_strcmp0 (str, "discharging")) + { + g_object_set (battery, INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING, nullptr); + } + else + { + g_object_set (battery, INDICATOR_POWER_DEVICE_PERCENTAGE, atof(str), nullptr); + } + } + else if (status == G_IO_STATUS_EOF) + { + g_main_loop_quit (loop); + } + + g_free (str); + return G_SOURCE_CONTINUE; +} + +/* this is basically indicator-power-service with a custom provider */ +int +main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) +{ + g_message ("This app is basically the same as indicator-power-service but,\n" + "instead of the system's real devices, sees a single fake battery\n" + "which can be manipulated by typing commands:\n" + "'charging', 'discharging', a charge percentage, or ctrl-c."); + + IndicatorPowerDeviceProvider * device_provider; + IndicatorPowerService * service; + + g_assert(g_setenv("GSETTINGS_SCHEMA_DIR", SCHEMA_DIR, true)); + g_assert(g_setenv("GSETTINGS_BACKEND", "memory", true)); + + /* boilerplate i18n */ + setlocale (LC_ALL, ""); + bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); + textdomain (GETTEXT_PACKAGE); + + /* read lines from the command line */ + auto channel = g_io_channel_unix_new (STDIN_FILENO); + auto watch_tag = g_io_add_watch (channel, G_IO_IN, on_command_stream_available, nullptr); + + /* run */ + battery = indicator_power_device_new ("/some/path", UP_DEVICE_KIND_BATTERY, 50.0, UP_DEVICE_STATE_DISCHARGING, 30*60); + device_provider = indicator_power_device_provider_mock_new (); + indicator_power_device_provider_add_device (INDICATOR_POWER_DEVICE_PROVIDER_MOCK(device_provider), battery); + service = indicator_power_service_new (device_provider); + loop = g_main_loop_new (NULL, FALSE); + g_signal_connect (service, INDICATOR_POWER_SERVICE_SIGNAL_NAME_LOST, + G_CALLBACK(on_name_lost), loop); + g_main_loop_run (loop); + + /* cleanup */ + g_main_loop_unref (loop); + g_source_remove (watch_tag); + g_io_channel_unref (channel); + g_clear_object (&service); + g_clear_object (&device_provider); + g_clear_object (&battery); + return 0; +} -- cgit v1.2.3 From 584aa80f415597a2970bfd29fa0d48b9a8842086 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 22 Jul 2014 11:59:03 -0500 Subject: Make the when-does-power-level-change tests work whether or not Ephemeral notifications are being used. --- tests/test-notify.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/test-notify.cc b/tests/test-notify.cc index 74a08dc..1fc843e 100644 --- a/tests/test-notify.cc +++ b/tests/test-notify.cc @@ -281,11 +281,11 @@ TEST_F(NotifyFixture, LevelsDuringBatteryDrain) if (old_level == new_level) { - EXPECT_EQ (0, changed_params.fields); + EXPECT_EQ (0, (changed_params.fields & FIELD_POWER_LEVEL)); } else { - EXPECT_EQ (FIELD_POWER_LEVEL, changed_params.fields); + EXPECT_EQ (FIELD_POWER_LEVEL, (changed_params.fields & FIELD_POWER_LEVEL)); EXPECT_EQ (new_level, changed_params.power_level); } } -- cgit v1.2.3 From dd322344959c31ebbda939bf74547ed85e3233f9 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 22 Jul 2014 12:01:45 -0500 Subject: add manual test case for using the indicator-power-service-cmdline-battery test utility --- tests/manual | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'tests') diff --git a/tests/manual b/tests/manual index d3a22e1..a542cac 100644 --- a/tests/manual +++ b/tests/manual @@ -22,3 +22,20 @@ Test-case indicator-power/unity8-items-check
The menu is populated with items
+Test-case indicator-power/low-battery-popups +
+
Open a terminal
+
Stop the currently-running power indicator: "stop indicator-power"
+
Start the fake battery harness in the tests/build/ directory: "indicator-power-service-cmdline-battery"
+
Battery indicator should update, showing a discharging battery with a 50% charge
+
Type: "10" (no quotes) and press Enter
+
A popup should appear saying 'Battery low - 10% charge remaining'
+
Battery indicator's icon should show a low charge
+
Battery indicator's "Charge level" menuitem should show a 10% charge
+
Type: "9" (no quotes) and press Enter
+
The 'Battery low' popup should NOT appear, since we've already been notified
+
Battery indicator's "Charge level" menuitem should show a 9% charge
+
Type: "5" (no quotes) and press Enter
+
No 'Battery low' popup SHOULD appear, since 5% is the next warning threshold
+
Battery indicator's "Charge level" menuitem should show a 5% charge
+
-- cgit v1.2.3 From 8b9a80174263c601952d6c31cbcd344c85d096dd Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Thu, 24 Jul 2014 09:20:35 -0500 Subject: in tests/glib-fixture.h, sync with the glib-fixture.h from indicator-transfer, it's got less '#if 0' cruft --- tests/glib-fixture.h | 77 +++++++++++++++++++++++++++------------------------- 1 file changed, 40 insertions(+), 37 deletions(-) (limited to 'tests') diff --git a/tests/glib-fixture.h b/tests/glib-fixture.h index 46b9640..4c53244 100644 --- a/tests/glib-fixture.h +++ b/tests/glib-fixture.h @@ -1,8 +1,5 @@ /* - * Copyright 2013 Canonical Ltd. - * - * Authors: - * Charles Kerr + * Copyright 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published @@ -15,6 +12,9 @@ * * You should have received a copy of the GNU General Public License along * with this program. If not, see . + * + * Authors: + * Charles Kerr */ #include @@ -31,64 +31,67 @@ class GlibFixture : public ::testing::Test { private: - //GLogFunc realLogHandler; - - protected: + GLogFunc realLogHandler; - std::map logCounts; + std::map expected_log; + std::map> log; - void testLogCount(GLogLevelFlags log_level, int /*expected*/) + void test_log_counts() { -#if 0 - EXPECT_EQ(expected, logCounts[log_level]); -#endif + const GLogLevelFlags levels_to_test[] = { G_LOG_LEVEL_ERROR, + G_LOG_LEVEL_CRITICAL, + G_LOG_LEVEL_MESSAGE, + G_LOG_LEVEL_WARNING }; - logCounts.erase(log_level); - } + for(const auto& level : levels_to_test) + { + const auto& v = log[level]; + const auto n = v.size(); - private: + EXPECT_EQ(expected_log[level], n); + + if (expected_log[level] != n) + for (size_t i=0; i(self)->logCounts[log_level]++; + auto tmp = g_strdup_printf ("%s:%d \"%s\"", log_domain, (int)log_level, message); + static_cast(self)->log[log_level].push_back(tmp); + g_free(tmp); } protected: + void increment_expected_errors(GLogLevelFlags level, size_t n=1) + { + expected_log[level] += n; + } + virtual void SetUp() { setlocale(LC_ALL, "C.UTF-8"); loop = g_main_loop_new(nullptr, false); - //g_log_set_default_handler(default_log_handler, this); - - // only use local, temporary settings - g_assert(g_setenv("GSETTINGS_SCHEMA_DIR", SCHEMA_DIR, true)); - g_assert(g_setenv("GSETTINGS_BACKEND", "memory", true)); - g_debug("SCHEMA_DIR is %s", SCHEMA_DIR); + g_log_set_default_handler(default_log_handler, this); g_unsetenv("DISPLAY"); - } virtual void TearDown() { -#if 0 - // confirm there aren't any unexpected log messages - EXPECT_EQ(0, logCounts[G_LOG_LEVEL_ERROR]); - EXPECT_EQ(0, logCounts[G_LOG_LEVEL_CRITICAL]); - EXPECT_EQ(0, logCounts[G_LOG_LEVEL_WARNING]); - EXPECT_EQ(0, logCounts[G_LOG_LEVEL_MESSAGE]); - EXPECT_EQ(0, logCounts[G_LOG_LEVEL_INFO]); -#endif - - // revert to glib's log handler - //g_log_set_default_handler(realLogHandler, this); + test_log_counts(); + + g_log_set_default_handler(realLogHandler, this); g_clear_pointer(&loop, g_main_loop_unref); } @@ -112,7 +115,7 @@ class GlibFixture : public ::testing::Test protected: /* convenience func to loop while waiting for a GObject's signal */ - void wait_for_signal(gpointer o, const gchar * signal, unsigned int timeout_seconds=5u) + void wait_for_signal(gpointer o, const gchar * signal, const guint timeout_seconds=5) { // wait for the signal or for timeout, whichever comes first const auto handler_id = g_signal_connect_swapped(o, signal, @@ -127,7 +130,7 @@ class GlibFixture : public ::testing::Test } /* convenience func to loop for N msec */ - void wait_msec(unsigned int msec=50u) + void wait_msec(guint msec=50) { const auto id = g_timeout_add(msec, wait_msec__timeout, loop); g_main_loop_run(loop); -- cgit v1.2.3 From f7f949eb2d04e8dd4493cbd8e55f34c896efd9ea Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Thu, 24 Jul 2014 16:25:32 -0500 Subject: d'oh --- tests/glib-fixture.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/glib-fixture.h b/tests/glib-fixture.h index 4c53244..d333ab2 100644 --- a/tests/glib-fixture.h +++ b/tests/glib-fixture.h @@ -52,7 +52,7 @@ class GlibFixture : public ::testing::Test if (expected_log[level] != n) for (size_t i=0; i Date: Thu, 24 Jul 2014 22:51:03 -0500 Subject: in notifier.c, fix potential callchain loop when closing a notification --- src/notifier.c | 68 ++++++++++++++++++++++++++++++++-------------------- tests/test-notify.cc | 33 +++++++++++++++++++++---- 2 files changed, 70 insertions(+), 31 deletions(-) (limited to 'tests') diff --git a/src/notifier.c b/src/notifier.c index 1ac7e32..dc3a186 100644 --- a/src/notifier.c +++ b/src/notifier.c @@ -89,56 +89,72 @@ static void set_power_level_property (IndicatorPowerNotifier*, **** Notifications ***/ +static void +on_notify_notification_finalized (gpointer gself, GObject * dead) +{ + IndicatorPowerNotifier * const self = INDICATOR_POWER_NOTIFIER(gself); + priv_t * const p = get_priv(self); + g_return_if_fail ((void*)(p->notify_notification) == (void*)dead); + p->notify_notification = NULL; + set_is_warning_property (self, FALSE); +} + static void notification_clear (IndicatorPowerNotifier * self) { priv_t * const p = get_priv(self); + NotifyNotification * nn; - if (p->notify_notification != NULL) + if ((nn = p->notify_notification)) { - set_is_warning_property (self, FALSE); + GError * error = NULL; + + g_object_weak_unref(G_OBJECT(nn), on_notify_notification_finalized, self); - notify_notification_clear_actions(p->notify_notification); - g_signal_handlers_disconnect_by_data(p->notify_notification, self); - g_clear_object(&p->notify_notification); + if (!notify_notification_close(nn, &error)) + { + g_warning("Unable to close notification: %s", error->message); + g_error_free(error); + } + + p->notify_notification = NULL; + set_is_warning_property(self, FALSE); } } static void notification_show(IndicatorPowerNotifier * self) { - priv_t * p; + priv_t * const p = get_priv(self); + gdouble pct; char * body; + NotifyNotification * nn; GError * error; - notification_clear (self); - - p = get_priv (self); + notification_clear(self); /* create the notification */ - body = g_strdup_printf(_("%.0f%% charge remaining"), - indicator_power_device_get_percentage(p->battery)); - p->notify_notification = notify_notification_new(_("Battery Low"), body, NULL); - notify_notification_set_hint(p->notify_notification, - HINT_INTERACTIVE, - g_variant_new_boolean(TRUE)); - g_signal_connect_swapped(p->notify_notification, "closed", - G_CALLBACK(notification_clear), self); - - /* show the notification */ + pct = indicator_power_device_get_percentage(p->battery); + body = g_strdup_printf(_("%.0f%% charge remaining"), pct); + nn = notify_notification_new(_("Battery Low"), body, NULL); + g_free (body); + notify_notification_set_hint(nn, HINT_INTERACTIVE, g_variant_new_boolean(TRUE)); + + /* if we can show it, keep it */ error = NULL; - notify_notification_show(p->notify_notification, &error); - if (error != NULL) + if (notify_notification_show(nn, &error)) { - g_critical("Unable to show snap decision for '%s': %s", body, error->message); - g_error_free(error); + p->notify_notification = nn; + g_signal_connect(nn, "closed", G_CALLBACK(g_object_unref), NULL); + g_object_weak_ref(G_OBJECT(nn), on_notify_notification_finalized, self); + set_is_warning_property(self, TRUE); } else { - set_is_warning_property (self, TRUE); + g_critical("Unable to show snap decision for '%s': %s", body, error->message); + g_error_free(error); + g_object_unref(nn); } - - g_free (body); } /*** diff --git a/tests/test-notify.cc b/tests/test-notify.cc index 1fc843e..a8d66d3 100644 --- a/tests/test-notify.cc +++ b/tests/test-notify.cc @@ -54,7 +54,7 @@ protected: DbusTestDbusMockObject * obj = nullptr; GDBusConnection * bus = nullptr; - static constexpr int NOTIFY_ID {1234}; + static constexpr int FIRST_NOTIFY_ID {1234}; static constexpr int NOTIFICATION_CLOSED_EXPIRED {1}; static constexpr int NOTIFICATION_CLOSED_DISMISSED {2}; @@ -63,9 +63,11 @@ protected: static constexpr char const * APP_NAME {"indicator-power-service"}; + static constexpr char const * METHOD_CLOSE {"CloseNotification"}; static constexpr char const * METHOD_NOTIFY {"Notify"}; static constexpr char const * METHOD_GET_CAPS {"GetCapabilities"}; static constexpr char const * METHOD_GET_INFO {"GetServerInformation"}; + static constexpr char const * SIGNAL_CLOSED {"NotificationClosed"}; static constexpr char const * HINT_TIMEOUT {"x-canonical-snap-decisions-timeout"}; @@ -86,7 +88,8 @@ protected: NOTIFY_INTERFACE, &error); g_assert_no_error (error); - + + // METHOD_GET_INFO dbus_test_dbus_mock_object_add_method(mock, obj, METHOD_GET_INFO, nullptr, G_VARIANT_TYPE("(ssss)"), @@ -94,14 +97,34 @@ protected: &error); g_assert_no_error (error); - auto python_str = g_strdup_printf ("ret = %d", NOTIFY_ID); + // METHOD_NOTIFY + auto str = g_strdup_printf("try:\n" + " self.NextNotifyId\n" + "except AttributeError:\n" + " self.NextNotifyId = %d\n" + "ret = self.NextNotifyId\n" + "self.NextNotifyId += 1\n", + FIRST_NOTIFY_ID); dbus_test_dbus_mock_object_add_method(mock, obj, METHOD_NOTIFY, G_VARIANT_TYPE("(susssasa{sv}i)"), G_VARIANT_TYPE_UINT32, - python_str, + str, &error); - g_free (python_str); g_assert_no_error (error); + g_free (str); + + // METHOD_CLOSE + str = g_strdup_printf("self.EmitSignal('%s', '%s', 'uu', [ args[0], %d ])", + NOTIFY_INTERFACE, + SIGNAL_CLOSED, + NOTIFICATION_CLOSED_API); + dbus_test_dbus_mock_object_add_method(mock, obj, METHOD_CLOSE, + G_VARIANT_TYPE("(u)"), + nullptr, + str, + &error); + g_assert_no_error (error); + g_free (str); dbus_test_service_add_task(service, DBUS_TEST_TASK(mock)); dbus_test_service_start_tasks(service); -- cgit v1.2.3 From f15482d3f189c378d4e4cf2dfc69eefa522b30aa Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Thu, 24 Jul 2014 23:31:11 -0500 Subject: on the bus, publish the battery's power_level as strings rather than ints --- data/com.canonical.indicator.power.Battery.xml | 4 +- src/notifier.c | 81 ++++++++++++++++++-------- src/notifier.h | 15 ++--- tests/test-notify.cc | 20 +++---- 4 files changed, 73 insertions(+), 47 deletions(-) (limited to 'tests') diff --git a/data/com.canonical.indicator.power.Battery.xml b/data/com.canonical.indicator.power.Battery.xml index d2c8a2d..eca4524 100644 --- a/data/com.canonical.indicator.power.Battery.xml +++ b/data/com.canonical.indicator.power.Battery.xml @@ -3,10 +3,10 @@ - + - The battery's power level. 0==No Low Battery, 1==Low, 2==Very Low, 3==Critical + The battery's power level. Possible values: 'ok', 'low', 'very_low', 'critical' diff --git a/src/notifier.c b/src/notifier.c index 60799f9..7add139 100644 --- a/src/notifier.c +++ b/src/notifier.c @@ -27,6 +27,15 @@ #define HINT_INTERACTIVE "x-canonical-switch-to-application" +typedef enum +{ + POWER_LEVEL_OK, + POWER_LEVEL_LOW, + POWER_LEVEL_VERY_LOW, + POWER_LEVEL_CRITICAL +} +PowerLevel; + /** *** GObject Properties **/ @@ -74,6 +83,48 @@ G_DEFINE_TYPE_WITH_PRIVATE(IndicatorPowerNotifier, #define get_priv(o) ((priv_t*)indicator_power_notifier_get_instance_private(o)) +/*** +**** +***/ + +static const char * +power_level_to_dbus_string (const PowerLevel power_level) +{ + switch (power_level) + { + case POWER_LEVEL_LOW: return "low"; + case POWER_LEVEL_VERY_LOW: return "very_low"; + case POWER_LEVEL_CRITICAL: return "critical"; + default: return "ok"; + } +} + +PowerLevel +get_battery_power_level (IndicatorPowerDevice * battery) +{ + static const double percent_critical = 2.0; + static const double percent_very_low = 5.0; + static const double percent_low = 10.0; + gdouble p; + PowerLevel ret; + + g_return_val_if_fail(battery != NULL, POWER_LEVEL_OK); + g_return_val_if_fail(indicator_power_device_get_kind(battery) == UP_DEVICE_KIND_BATTERY, POWER_LEVEL_OK); + + p = indicator_power_device_get_percentage(battery); + + if (p <= percent_critical) + ret = POWER_LEVEL_CRITICAL; + else if (p <= percent_very_low) + ret = POWER_LEVEL_VERY_LOW; + else if (p <= percent_low) + ret = POWER_LEVEL_LOW; + else + ret = POWER_LEVEL_OK; + + return ret; +} + /*** **** Notifications ***/ @@ -164,7 +215,7 @@ on_battery_property_changed (IndicatorPowerNotifier * self) g_return_if_fail(INDICATOR_IS_POWER_DEVICE(p->battery)); old_power_level = p->power_level; - new_power_level = indicator_power_notifier_get_power_level (p->battery); + new_power_level = get_battery_power_level (p->battery); old_discharging = p->discharging; new_discharging = indicator_power_device_get_state(p->battery) == UP_DEVICE_STATE_DISCHARGING; @@ -182,7 +233,7 @@ on_battery_property_changed (IndicatorPowerNotifier * self) notification_clear (self); } - dbus_battery_set_power_level (p->dbus_battery, new_power_level); + dbus_battery_set_power_level (p->dbus_battery, power_level_to_dbus_string (new_power_level)); p->discharging = new_discharging; } @@ -326,7 +377,7 @@ indicator_power_notifier_set_battery (IndicatorPowerNotifier * self, { g_signal_handlers_disconnect_by_data (p->battery, self); g_clear_object (&p->battery); - dbus_battery_set_power_level (p->dbus_battery, POWER_LEVEL_OK); + dbus_battery_set_power_level (p->dbus_battery, power_level_to_dbus_string (POWER_LEVEL_OK)); notification_clear (self); } @@ -384,28 +435,8 @@ indicator_power_notifier_set_bus (IndicatorPowerNotifier * self, } } -PowerLevel +const char * indicator_power_notifier_get_power_level (IndicatorPowerDevice * battery) { - static const double percent_critical = 2.0; - static const double percent_very_low = 5.0; - static const double percent_low = 10.0; - gdouble p; - PowerLevel ret; - - g_return_val_if_fail(battery != NULL, POWER_LEVEL_OK); - g_return_val_if_fail(indicator_power_device_get_kind(battery) == UP_DEVICE_KIND_BATTERY, POWER_LEVEL_OK); - - p = indicator_power_device_get_percentage(battery); - - if (p <= percent_critical) - ret = POWER_LEVEL_CRITICAL; - else if (p <= percent_very_low) - ret = POWER_LEVEL_VERY_LOW; - else if (p <= percent_low) - ret = POWER_LEVEL_LOW; - else - ret = POWER_LEVEL_OK; - - return ret; + return power_level_to_dbus_string (get_battery_power_level (battery)); } diff --git a/src/notifier.h b/src/notifier.h index c23c585..18e25d7 100644 --- a/src/notifier.h +++ b/src/notifier.h @@ -35,15 +35,6 @@ G_BEGIN_DECLS typedef struct _IndicatorPowerNotifier IndicatorPowerNotifier; typedef struct _IndicatorPowerNotifierClass IndicatorPowerNotifierClass; -typedef enum -{ - POWER_LEVEL_OK, - POWER_LEVEL_LOW, - POWER_LEVEL_VERY_LOW, - POWER_LEVEL_CRITICAL -} -PowerLevel; - /** * The Indicator Power Notifier. */ @@ -72,7 +63,11 @@ void indicator_power_notifier_set_bus (IndicatorPowerNotifier * self, void indicator_power_notifier_set_battery (IndicatorPowerNotifier * self, IndicatorPowerDevice * battery); -PowerLevel indicator_power_notifier_get_power_level (IndicatorPowerDevice * battery); +#define POWER_LEVEL_STR_OK "ok" +#define POWER_LEVEL_STR_LOW "low" +#define POWER_LEVEL_STR_VERY_LOW "very_low" +#define POWER_LEVEL_STR_CRITICAL "critical" +const char * indicator_power_notifier_get_power_level (IndicatorPowerDevice * battery); G_END_DECLS diff --git a/tests/test-notify.cc b/tests/test-notify.cc index a8d66d3..b5166a0 100644 --- a/tests/test-notify.cc +++ b/tests/test-notify.cc @@ -200,13 +200,13 @@ TEST_F(NotifyFixture, PercentageToLevel) const auto level = indicator_power_notifier_get_power_level(battery); if (i <= percent_critical) - EXPECT_EQ (POWER_LEVEL_CRITICAL, level); + EXPECT_STREQ (POWER_LEVEL_STR_CRITICAL, level); else if (i <= percent_very_low) - EXPECT_EQ (POWER_LEVEL_VERY_LOW, level); + EXPECT_STREQ (POWER_LEVEL_STR_VERY_LOW, level); else if (i <= percent_low) - EXPECT_EQ (POWER_LEVEL_LOW, level); + EXPECT_STREQ (POWER_LEVEL_STR_LOW, level); else - EXPECT_EQ (POWER_LEVEL_OK, level); + EXPECT_STREQ (POWER_LEVEL_STR_OK, level); } g_object_unref (battery); @@ -227,7 +227,7 @@ namespace struct ChangedParams { - int32_t power_level = POWER_LEVEL_OK; + std::string power_level = POWER_LEVEL_STR_OK; bool is_warning = false; uint32_t fields = 0; }; @@ -245,8 +245,8 @@ namespace g_return_if_fail (g_variant_is_of_type (dict, G_VARIANT_TYPE_DICTIONARY)); auto changed_params = static_cast(gchanged_params); - gint32 power_level; - if (g_variant_lookup (dict, "PowerLevel", "i", &power_level, nullptr)) + const char * power_level; + if (g_variant_lookup (dict, "PowerLevel", "&s", &power_level, nullptr)) { changed_params->power_level = power_level; changed_params->fields |= FIELD_POWER_LEVEL; @@ -362,7 +362,7 @@ TEST_F(NotifyFixture, EventsThatChangeNotifications) // test setup case wait_msec(); - EXPECT_EQ (0, changed_params.power_level); + EXPECT_STREQ (POWER_LEVEL_STR_OK, changed_params.power_level.c_str()); // change the percent past the 'low' threshold and confirm that // a) the power level changes @@ -379,7 +379,7 @@ TEST_F(NotifyFixture, EventsThatChangeNotifications) set_battery_percentage (battery, percent_very_low); wait_msec(); EXPECT_EQ (FIELD_POWER_LEVEL, changed_params.fields); - EXPECT_EQ (POWER_LEVEL_VERY_LOW, changed_params.power_level); + EXPECT_STREQ (POWER_LEVEL_STR_VERY_LOW, changed_params.power_level.c_str()); // ...and that the warning is taken down if the battery is plugged back in... changed_params = ChangedParams(); @@ -400,7 +400,7 @@ TEST_F(NotifyFixture, EventsThatChangeNotifications) set_battery_percentage (battery, percent_low+1); wait_msec(); EXPECT_EQ (FIELD_POWER_LEVEL|FIELD_IS_WARNING, changed_params.fields); - EXPECT_EQ (POWER_LEVEL_OK, changed_params.power_level); + EXPECT_STREQ (POWER_LEVEL_STR_OK, changed_params.power_level.c_str()); EXPECT_FALSE (changed_params.is_warning); // cleanup -- cgit v1.2.3 From a402b61b0acc81a808f9cb353e0df81bb9b14de0 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 29 Jul 2014 10:05:20 -0500 Subject: sync unit tests. --- tests/test-device.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'tests') diff --git a/tests/test-device.cc b/tests/test-device.cc index 81e8a22..85ba237 100644 --- a/tests/test-device.cc +++ b/tests/test-device.cc @@ -422,10 +422,10 @@ TEST_F(DeviceTest, IconNames) INDICATOR_POWER_DEVICE_PERCENTAGE, 25.0, INDICATOR_POWER_DEVICE_TIME, (guint64)(60*60), NULL); - g_string_append_printf (expected, "%s-040;", kind_str); - g_string_append_printf (expected, "gpm-%s-040;", kind_str); - g_string_append_printf (expected, "%s-good-symbolic;", kind_str); - g_string_append_printf (expected, "%s-good", kind_str); + g_string_append_printf (expected, "%s-020;", kind_str); + g_string_append_printf (expected, "gpm-%s-020;", kind_str); + g_string_append_printf (expected, "%s-low-symbolic;", kind_str); + g_string_append_printf (expected, "%s-low", kind_str); check_icon_names (device, expected->str); g_string_truncate (expected, 0); @@ -448,10 +448,10 @@ TEST_F(DeviceTest, IconNames) INDICATOR_POWER_DEVICE_PERCENTAGE, 5.0, INDICATOR_POWER_DEVICE_TIME, (guint64)(60*60), NULL); - g_string_append_printf (expected, "%s-040;", kind_str); - g_string_append_printf (expected, "gpm-%s-040;", kind_str); - g_string_append_printf (expected, "%s-good-symbolic;", kind_str); - g_string_append_printf (expected, "%s-good", kind_str); + g_string_append_printf (expected, "%s-000;", kind_str); + g_string_append_printf (expected, "gpm-%s-000;", kind_str); + g_string_append_printf (expected, "%s-caution-symbolic;", kind_str); + g_string_append_printf (expected, "%s-caution", kind_str); check_icon_names (device, expected->str); g_string_truncate (expected, 0); -- cgit v1.2.3