/* * Copyright 2012-2016 Canonical Ltd. * Copyright 2022-2023 Robert Tari * * 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 * Robert Tari */ #include "device.h" #include "service.h" #include #include #include #include #include // ceil() #include class DeviceTest : public ::testing::Test { private: guint log_handler_id; int log_count_ipower_actual; static void log_count_func (const gchar * log_domain G_GNUC_UNUSED, GLogLevelFlags log_level G_GNUC_UNUSED, const gchar * message G_GNUC_UNUSED, gpointer gself) { reinterpret_cast(gself)->log_count_ipower_actual++; } protected: int log_count_ipower_expected; protected: virtual void SetUp() { const GLogLevelFlags flags = GLogLevelFlags(G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING); log_handler_id = g_log_set_handler(G_LOG_DOMAIN, flags, log_count_func, this); log_count_ipower_expected = 0; log_count_ipower_actual = 0; } virtual void TearDown() { ASSERT_EQ (log_count_ipower_expected, log_count_ipower_actual); g_log_remove_handler (G_LOG_DOMAIN, log_handler_id); } protected: static std::string get_icon_names_from_device(const IndicatorPowerDevice* device) { std::string ret; char ** names = indicator_power_device_get_icon_names (device, TRUE); char * str = g_strjoinv (";", names); if (str != nullptr) ret = str; g_free (str); g_strfreev (names); return ret; } void check_label (const IndicatorPowerDevice * device, const char * expected_label) { char * label = indicator_power_device_get_readable_text (device, FALSE); EXPECT_STREQ (expected_label, label); g_free (label); } void check_header (const IndicatorPowerDevice * device, const char * expected_time_and_percent, const char * expected_time, const char * expected_percent, const char * expected_a11y) { char * a11y = NULL; char * title = NULL; title = indicator_power_device_get_readable_title (device, true, true); 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); 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); 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_EQ(NULL, title); g_free (title); a11y = indicator_power_device_get_accessible_title (device, false, false); if (expected_a11y) EXPECT_STREQ (expected_a11y, a11y); else EXPECT_EQ(NULL, a11y); g_free (a11y); } }; #define EXPECT_ICON_NAMES_EQ(expected_in,device_in) \ do { \ const std::string tmp_expected {expected_in}; \ const std::string tmp_actual {get_icon_names_from_device(device_in)}; \ EXPECT_EQ(tmp_expected, tmp_actual); \ } while(0) /*** **** ***/ TEST_F(DeviceTest, GObjectNew) { GObject * o = G_OBJECT (g_object_new (INDICATOR_POWER_DEVICE_TYPE, NULL)); ASSERT_TRUE (o != NULL); ASSERT_TRUE (INDICATOR_IS_POWER_DEVICE(o)); g_object_run_dispose (o); // used to get coverage of both branches in the object's dispose func's g_clear_*() calls g_object_unref (o); } TEST_F(DeviceTest, Properties) { int i; gdouble d; GObject * o; gchar * str; guint64 u64; const gchar * key; o = G_OBJECT (g_object_new (INDICATOR_POWER_DEVICE_TYPE, NULL)); ASSERT_TRUE (o != NULL); ASSERT_TRUE (INDICATOR_IS_POWER_DEVICE(o)); // Test getting & setting a Device's properties. // KIND key = INDICATOR_POWER_DEVICE_KIND; g_object_set (o, key, UP_DEVICE_KIND_BATTERY, NULL); g_object_get (o, key, &i, NULL); ASSERT_EQ (i, UP_DEVICE_KIND_BATTERY); // STATE key = INDICATOR_POWER_DEVICE_STATE; g_object_set (o, key, UP_DEVICE_STATE_CHARGING, NULL); g_object_get (o, key, &i, NULL); ASSERT_EQ (i, UP_DEVICE_STATE_CHARGING); // OBJECT_PATH key = INDICATOR_POWER_DEVICE_OBJECT_PATH; g_object_set (o, key, "/object/path", NULL); g_object_get (o, key, &str, NULL); ASSERT_STREQ (str, "/object/path"); g_free (str); // PERCENTAGE key = INDICATOR_POWER_DEVICE_PERCENTAGE; g_object_set (o, key, 50.0, NULL); g_object_get (o, key, &d, NULL); ASSERT_EQ(int(d), 50); // TIME key = INDICATOR_POWER_DEVICE_TIME; g_object_set (o, key, guint64(30), NULL); g_object_get (o, key, &u64, NULL); ASSERT_EQ(u64, 30); // cleanup g_object_unref (o); } TEST_F(DeviceTest, New) { IndicatorPowerDevice * device = indicator_power_device_new ("/object/path", UP_DEVICE_KIND_BATTERY, "Some Model", 50.0, UP_DEVICE_STATE_CHARGING, 30, TRUE); ASSERT_TRUE (device != NULL); ASSERT_TRUE (INDICATOR_IS_POWER_DEVICE(device)); ASSERT_EQ (UP_DEVICE_KIND_BATTERY, indicator_power_device_get_kind(device)); ASSERT_STREQ ("Some Model", indicator_power_device_get_model(device)); ASSERT_EQ (UP_DEVICE_STATE_CHARGING, indicator_power_device_get_state(device)); ASSERT_STREQ ("/object/path", indicator_power_device_get_object_path(device)); ASSERT_EQ (50, int(indicator_power_device_get_percentage(device))); ASSERT_EQ (30, indicator_power_device_get_time(device)); ASSERT_TRUE (indicator_power_device_get_power_supply(device)); // cleanup g_object_unref (device); } TEST_F(DeviceTest, NewFromVariant) { auto variant = g_variant_new("(sussdutb)", "/object/path", guint32(UP_DEVICE_KIND_BATTERY), "Some Model", "icon", 50.0, guint32(UP_DEVICE_STATE_CHARGING), guint64(30), TRUE); IndicatorPowerDevice * device = indicator_power_device_new_from_variant (variant); ASSERT_TRUE (variant != NULL); ASSERT_TRUE (device != NULL); ASSERT_TRUE (INDICATOR_IS_POWER_DEVICE(device)); ASSERT_EQ (UP_DEVICE_KIND_BATTERY, indicator_power_device_get_kind(device)); ASSERT_STREQ ("Some Model", indicator_power_device_get_model(device)); ASSERT_EQ (UP_DEVICE_STATE_CHARGING, indicator_power_device_get_state(device)); ASSERT_STREQ ("/object/path", indicator_power_device_get_object_path(device)); ASSERT_EQ (50, int(indicator_power_device_get_percentage(device))); ASSERT_EQ (30, indicator_power_device_get_time(device)); ASSERT_TRUE (indicator_power_device_get_power_supply(device)); // cleanup g_object_unref (device); g_variant_unref (variant); } TEST_F(DeviceTest, BadAccessors) { // test that these functions can handle being passed NULL pointers IndicatorPowerDevice * device = NULL; indicator_power_device_get_kind (device); indicator_power_device_get_time (device); indicator_power_device_get_state (device); indicator_power_device_get_percentage (device); indicator_power_device_get_object_path (device); log_count_ipower_expected += 5; // test that these functions can handle being passed non-device GObjects device = reinterpret_cast(g_cancellable_new ()); indicator_power_device_get_kind (device); indicator_power_device_get_time (device); indicator_power_device_get_state (device); indicator_power_device_get_percentage (device); indicator_power_device_get_object_path (device); log_count_ipower_expected += 5; g_object_unref (device); } /*** **** ***/ TEST_F(DeviceTest, IconNames) { IndicatorPowerDevice * device = INDICATOR_POWER_DEVICE (g_object_new (INDICATOR_POWER_DEVICE_TYPE, NULL)); GObject * o = G_OBJECT(device); // bad arguments log_count_ipower_expected++; ASSERT_TRUE (indicator_power_device_get_icon_names (NULL, TRUE) == NULL); // power g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_LINE_POWER, NULL); EXPECT_ICON_NAMES_EQ("ac-adapter-panel;" "ac-adapter", device); // monitor g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_MONITOR, NULL); EXPECT_ICON_NAMES_EQ("gpm-monitor-panel;" "gpm-monitor", device); // devices that hold a charge struct { int kind; const gchar * kind_str; } devices[] = { { UP_DEVICE_KIND_BATTERY, "battery" }, { UP_DEVICE_KIND_UPS, "ups" }, { UP_DEVICE_KIND_MOUSE, "mouse" }, { UP_DEVICE_KIND_KEYBOARD, "keyboard" }, { UP_DEVICE_KIND_PHONE, "phone" } }; GString * expected = g_string_new (NULL); for (int i=0, n=G_N_ELEMENTS(devices); istr, device); g_string_truncate (expected, 0); // charged g_object_set (o, INDICATOR_POWER_DEVICE_KIND, kind, INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_FULLY_CHARGED, NULL); g_string_append_printf (expected, "%s-full-charged-panel;", kind_str); g_string_append_printf (expected, "gpm-%s-full;", kind_str); g_string_append_printf (expected, "gpm-%s-100;", kind_str); g_string_append_printf (expected, "%s-full-charged;", kind_str); g_string_append_printf (expected, "%s-full-charging", kind_str); EXPECT_ICON_NAMES_EQ(expected->str, device); g_string_truncate (expected, 0); // charging, 95% g_object_set (o, INDICATOR_POWER_DEVICE_KIND, kind, INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_CHARGING, INDICATOR_POWER_DEVICE_PERCENTAGE, 95.0, NULL); g_string_append_printf (expected, "%s-100-charging-panel;", 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-panel;", kind_str); g_string_append_printf (expected, "%s-full-charging;", kind_str); g_string_append_printf (expected, "%s-100-panel;", kind_str); g_string_append_printf (expected, "%s-100;", kind_str); g_string_append_printf (expected, "gpm-%s-100;", kind_str); g_string_append_printf (expected, "%s-full-panel;", kind_str); g_string_append_printf (expected, "%s-full", kind_str); EXPECT_ICON_NAMES_EQ(expected->str, device); g_string_truncate (expected, 0); // charging, 85% g_object_set (o, INDICATOR_POWER_DEVICE_KIND, kind, INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_CHARGING, INDICATOR_POWER_DEVICE_PERCENTAGE, 85.0, NULL); g_string_append_printf (expected, "%s-090-charging-panel;", kind_str); g_string_append_printf (expected, "%s-090-charging;", kind_str); g_string_append_printf (expected, "gpm-%s-090-charging;", kind_str); g_string_append_printf (expected, "%s-080-charging-panel;", 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-panel;", kind_str); g_string_append_printf (expected, "%s-full-charging;", kind_str); g_string_append_printf (expected, "%s-090-panel;", kind_str); g_string_append_printf (expected, "%s-090;", kind_str); g_string_append_printf (expected, "gpm-%s-090;", kind_str); g_string_append_printf (expected, "%s-080-panel;", kind_str); g_string_append_printf (expected, "%s-080;", kind_str); g_string_append_printf (expected, "gpm-%s-080;", kind_str); g_string_append_printf (expected, "%s-full-panel;", kind_str); g_string_append_printf (expected, "%s-full", kind_str); EXPECT_ICON_NAMES_EQ(expected->str, device); g_string_truncate (expected, 0); // charging, 50% g_object_set (o, INDICATOR_POWER_DEVICE_KIND, kind, INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_CHARGING, INDICATOR_POWER_DEVICE_PERCENTAGE, 50.0, NULL); g_string_append_printf (expected, "%s-050-charging-panel;", kind_str); g_string_append_printf (expected, "%s-050-charging;", kind_str); g_string_append_printf (expected, "gpm-%s-050-charging;", kind_str); g_string_append_printf (expected, "%s-060-charging-panel;", 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-panel;", kind_str); g_string_append_printf (expected, "%s-good-charging;", kind_str); g_string_append_printf (expected, "%s-050-panel;", kind_str); g_string_append_printf (expected, "%s-050;", kind_str); g_string_append_printf (expected, "gpm-%s-050;", kind_str); g_string_append_printf (expected, "%s-060-panel;", kind_str); g_string_append_printf (expected, "%s-060;", kind_str); g_string_append_printf (expected, "gpm-%s-060;", kind_str); g_string_append_printf (expected, "%s-good-panel;", kind_str); g_string_append_printf (expected, "%s-good", kind_str); EXPECT_ICON_NAMES_EQ(expected->str, device); g_string_truncate (expected, 0); // charging, 25% g_object_set (o, INDICATOR_POWER_DEVICE_KIND, kind, INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_CHARGING, INDICATOR_POWER_DEVICE_PERCENTAGE, 25.0, NULL); g_string_append_printf (expected, "%s-030-charging-panel;", kind_str); g_string_append_printf (expected, "%s-030-charging;", kind_str); g_string_append_printf (expected, "gpm-%s-030-charging;", kind_str); g_string_append_printf (expected, "%s-040-charging-panel;", kind_str); g_string_append_printf (expected, "%s-040-charging;", kind_str); g_string_append_printf (expected, "gpm-%s-040-charging;", kind_str); g_string_append_printf (expected, "%s-low-charging-panel;", kind_str); g_string_append_printf (expected, "%s-low-charging;", kind_str); g_string_append_printf (expected, "%s-030-panel;", kind_str); g_string_append_printf (expected, "%s-030;", kind_str); g_string_append_printf (expected, "gpm-%s-030;", kind_str); g_string_append_printf (expected, "%s-040-panel;", kind_str); 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-low-panel;", kind_str); g_string_append_printf (expected, "%s-low", kind_str); EXPECT_ICON_NAMES_EQ(expected->str, device); g_string_truncate (expected, 0); // charging, 5% g_object_set (o, INDICATOR_POWER_DEVICE_KIND, kind, INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_CHARGING, INDICATOR_POWER_DEVICE_PERCENTAGE, 5.0, NULL); g_string_append_printf (expected, "%s-010-charging-panel;", kind_str); g_string_append_printf (expected, "%s-010-charging;", kind_str); g_string_append_printf (expected, "gpm-%s-010-charging;", kind_str); g_string_append_printf (expected, "%s-000-charging-panel;", 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-panel;", kind_str); g_string_append_printf (expected, "%s-caution-charging;", kind_str); g_string_append_printf (expected, "%s-010-panel;", kind_str); g_string_append_printf (expected, "%s-010;", kind_str); g_string_append_printf (expected, "gpm-%s-010;", kind_str); g_string_append_printf (expected, "%s-000-panel;", 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-panel;", kind_str); g_string_append_printf (expected, "%s-caution", kind_str); EXPECT_ICON_NAMES_EQ(expected->str, device); g_string_truncate (expected, 0); // discharging, 95% g_object_set (o, INDICATOR_POWER_DEVICE_KIND, kind, INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING, INDICATOR_POWER_DEVICE_PERCENTAGE, 95.0, NULL); g_string_append_printf (expected, "%s-100-panel;", kind_str); g_string_append_printf (expected, "%s-100;", kind_str); g_string_append_printf (expected, "gpm-%s-100;", kind_str); g_string_append_printf (expected, "%s-full-panel;", kind_str); g_string_append_printf (expected, "%s-full", kind_str); EXPECT_ICON_NAMES_EQ(expected->str, device); g_string_truncate (expected, 0); // discharging, 85% g_object_set (o, INDICATOR_POWER_DEVICE_KIND, kind, INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING, INDICATOR_POWER_DEVICE_PERCENTAGE, 85.0, NULL); g_string_append_printf (expected, "%s-090-panel;", kind_str); g_string_append_printf (expected, "%s-090;", kind_str); g_string_append_printf (expected, "gpm-%s-090;", kind_str); g_string_append_printf (expected, "%s-080-panel;", kind_str); g_string_append_printf (expected, "%s-080;", kind_str); g_string_append_printf (expected, "gpm-%s-080;", kind_str); g_string_append_printf (expected, "%s-full-panel;", kind_str); g_string_append_printf (expected, "%s-full", kind_str); EXPECT_ICON_NAMES_EQ(expected->str, device); g_string_truncate (expected, 0); // discharging, 50% -- 1 hour left g_object_set (o, INDICATOR_POWER_DEVICE_KIND, kind, INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING, INDICATOR_POWER_DEVICE_PERCENTAGE, 50.0, INDICATOR_POWER_DEVICE_TIME, guint64(60*60), NULL); g_string_append_printf (expected, "%s-050-panel;", kind_str); g_string_append_printf (expected, "%s-050;", kind_str); g_string_append_printf (expected, "gpm-%s-050;", kind_str); g_string_append_printf (expected, "%s-060-panel;", kind_str); g_string_append_printf (expected, "%s-060;", kind_str); g_string_append_printf (expected, "gpm-%s-060;", kind_str); g_string_append_printf (expected, "%s-good-panel;", kind_str); g_string_append_printf (expected, "%s-good", kind_str); EXPECT_ICON_NAMES_EQ(expected->str, device); g_string_truncate (expected, 0); // discharging, 25% -- 1 hour left g_object_set (o, INDICATOR_POWER_DEVICE_KIND, kind, INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING, INDICATOR_POWER_DEVICE_PERCENTAGE, 25.0, INDICATOR_POWER_DEVICE_TIME, guint64(60*60), NULL); g_string_append_printf (expected, "%s-030-panel;", kind_str); g_string_append_printf (expected, "%s-030;", kind_str); g_string_append_printf (expected, "gpm-%s-030;", kind_str); g_string_append_printf (expected, "%s-040-panel;", kind_str); 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-low-panel;", kind_str); g_string_append_printf (expected, "%s-low", kind_str); EXPECT_ICON_NAMES_EQ(expected->str, device); g_string_truncate (expected, 0); // discharging, 25% -- 15 minutes left g_object_set (o, INDICATOR_POWER_DEVICE_KIND, kind, INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING, INDICATOR_POWER_DEVICE_PERCENTAGE, 25.0, INDICATOR_POWER_DEVICE_TIME, guint64(60*15), NULL); g_string_append_printf (expected, "%s-030-panel;", kind_str); g_string_append_printf (expected, "%s-030;", kind_str); g_string_append_printf (expected, "gpm-%s-030;", kind_str); g_string_append_printf (expected, "%s-040-panel;", kind_str); 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-low-panel;", kind_str); g_string_append_printf (expected, "%s-low", kind_str); EXPECT_ICON_NAMES_EQ(expected->str, device); g_string_truncate (expected, 0); // discharging, 5% -- 1 hour left g_object_set (o, INDICATOR_POWER_DEVICE_KIND, kind, INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING, INDICATOR_POWER_DEVICE_PERCENTAGE, 5.0, INDICATOR_POWER_DEVICE_TIME, guint64(60*60), NULL); g_string_append_printf (expected, "%s-010-panel;", kind_str); g_string_append_printf (expected, "%s-010;", kind_str); g_string_append_printf (expected, "gpm-%s-010;", kind_str); g_string_append_printf (expected, "%s-000-panel;", 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-panel;", kind_str); g_string_append_printf (expected, "%s-caution", kind_str); EXPECT_ICON_NAMES_EQ(expected->str, device); g_string_truncate (expected, 0); // discharging, 5% -- 15 minutes left g_object_set (o, INDICATOR_POWER_DEVICE_KIND, kind, INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING, INDICATOR_POWER_DEVICE_PERCENTAGE, 5.0, INDICATOR_POWER_DEVICE_TIME, guint64(60*15), NULL); g_string_append_printf (expected, "%s-010-panel;", kind_str); g_string_append_printf (expected, "%s-010;", kind_str); g_string_append_printf (expected, "gpm-%s-010;", kind_str); g_string_append_printf (expected, "%s-000-panel;", 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-panel;", kind_str); g_string_append_printf (expected, "%s-caution", kind_str); EXPECT_ICON_NAMES_EQ(expected->str, device); // if we know the charge level, but not that it’s charging, // then we should use the same icons as when it’s discharging. // https://wiki.ubuntu.com/Power?action=diff&rev2=78&rev1=77 // https://bugs.launchpad.net/ubuntu/+source/indicator-power/+bug/1470080 g_object_set (o, INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_UNKNOWN, NULL); EXPECT_ICON_NAMES_EQ(expected->str, device); g_string_truncate (expected, 0); } g_string_free (expected, TRUE); // cleanup g_object_unref(o); } TEST_F(DeviceTest, Labels) { // set our language so that i18n won't break these tests char * real_lang = g_strdup(g_getenv ("LANG")); g_setenv ("LANG", "en_US.UTF-8", TRUE); // bad args: NULL device log_count_ipower_expected++; check_label (NULL, NULL); log_count_ipower_expected += 5; check_header (nullptr, nullptr, nullptr, nullptr, nullptr); // bad args: a GObject that isn't a device GObject * o = G_OBJECT(g_cancellable_new()); log_count_ipower_expected++; check_label (INDICATOR_POWER_DEVICE(o), nullptr); log_count_ipower_expected += 5; check_header (NULL, NULL, NULL, NULL, NULL); g_object_unref (o); /** *** **/ IndicatorPowerDevice * device = INDICATOR_POWER_DEVICE (g_object_new (INDICATOR_POWER_DEVICE_TYPE, NULL)); o = G_OBJECT(device); // charging g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY, INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_CHARGING, INDICATOR_POWER_DEVICE_PERCENTAGE, 50.0, INDICATOR_POWER_DEVICE_TIME, guint64(60*61), NULL); check_label (device, "Battery (1:01 to charge)"); check_header (device, "(1:01, 50%)", "(1:01)", "(50%)", "Battery (1 hour 1 minute to charge)"); // discharging, < 12 hours left 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(60*61), NULL); check_label (device, "Battery (1:01 left)"); check_header (device, "(1:01, 50%)", "(1:01)", "(50%)", "Battery (1 hour 1 minute left)"); // discharging, > 24 hours left // we don't show the clock time when > 24 hours discharging 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(60*60*25), NULL); check_label (device, "Battery"); check_header (device, "(50%)", NULL, "(50%)", "Battery"); // fully charged g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY, INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_FULLY_CHARGED, INDICATOR_POWER_DEVICE_PERCENTAGE, 100.0, INDICATOR_POWER_DEVICE_TIME, guint64(0), NULL); check_label (device, "Battery (charged)"); check_header (device, "(100%)", NULL, "(100%)", "Battery (charged)"); // percentage but no time estimate 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), NULL); check_label (device, "Battery (estimating…)"); check_header (device, "(estimating…, 50%)", "(estimating…)", "(50%)", "Battery (estimating…)"); // no percentage, no time estimate g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY, INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING, INDICATOR_POWER_DEVICE_PERCENTAGE, 0.0, INDICATOR_POWER_DEVICE_TIME, guint64(0), NULL); check_label (device, "Battery"); check_header (device, NULL, NULL, NULL, "Battery"); // power line g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_LINE_POWER, INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_UNKNOWN, INDICATOR_POWER_DEVICE_PERCENTAGE, 0.0, INDICATOR_POWER_DEVICE_TIME, guint64(0), NULL); check_label (device, "AC Adapter"); check_header (device, NULL, NULL, NULL, "AC Adapter"); // cleanup g_object_unref(o); g_setenv ("LANG", real_lang, TRUE); 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%)", NULL, "(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); } namespace { const std::array,UP_DEVICE_KIND_LAST> kinds = { std::make_pair("unknown", UP_DEVICE_KIND_UNKNOWN), std::make_pair("line-power", UP_DEVICE_KIND_LINE_POWER), std::make_pair("battery", UP_DEVICE_KIND_BATTERY), std::make_pair("ups", UP_DEVICE_KIND_UPS), std::make_pair("monitor", UP_DEVICE_KIND_MONITOR), std::make_pair("mouse", UP_DEVICE_KIND_MOUSE), std::make_pair("keyboard", UP_DEVICE_KIND_KEYBOARD), std::make_pair("pda", UP_DEVICE_KIND_PDA), std::make_pair("phone", UP_DEVICE_KIND_PHONE), std::make_pair("media-player", UP_DEVICE_KIND_MEDIA_PLAYER), std::make_pair("tablet", UP_DEVICE_KIND_TABLET), std::make_pair("computer", UP_DEVICE_KIND_COMPUTER) }; const std::string& kind2str(UpDeviceKind kind) { return std::find_if( kinds.begin(), kinds.end(), [kind](decltype(kinds[0])& i){return i.second==kind;} )->first; } UpDeviceKind str2kind(const std::string& str) { return std::find_if( kinds.begin(), kinds.end(), [str](decltype(kinds[0])& i){return i.first==str;} )->second; } /** **/ const std::array,UP_DEVICE_STATE_LAST> states = { std::make_pair("unknown", UP_DEVICE_STATE_UNKNOWN), std::make_pair("charging", UP_DEVICE_STATE_CHARGING), std::make_pair("discharging", UP_DEVICE_STATE_DISCHARGING), std::make_pair("empty", UP_DEVICE_STATE_EMPTY), std::make_pair("charged", UP_DEVICE_STATE_FULLY_CHARGED), std::make_pair("pending-charge", UP_DEVICE_STATE_PENDING_CHARGE), std::make_pair("pending-discharge", UP_DEVICE_STATE_PENDING_DISCHARGE) }; const std::string& state2str(UpDeviceState state) { return std::find_if( states.begin(), states.end(), [state](decltype(states[0])& i){return i.second==state;} )->first; } UpDeviceState str2state(const std::string& str) { return std::find_if( states.begin(), states.end(), [str](decltype(states[0])& i){return i.first==str;} )->second; } /** **/ std::string device2str(IndicatorPowerDevice* device) { std::ostringstream o; const auto path = indicator_power_device_get_object_path(device); const gchar *model = indicator_power_device_get_model(device); o << kind2str(indicator_power_device_get_kind(device)) << ' ' << (model ? model : "noname") << ' ' << state2str(indicator_power_device_get_state(device)) << ' ' << indicator_power_device_get_time(device)<<'m' << ' ' << int(ceil(indicator_power_device_get_percentage(device)))<<'%' << ' ' << (path ? path : "nopath") << ' ' << (indicator_power_device_get_power_supply(device) ? "1" : "0"); return o.str(); } IndicatorPowerDevice* str2device(const std::string& str) { auto tokens = g_strsplit(str.c_str(), " ", 0); g_assert(7u == g_strv_length(tokens)); const auto kind = str2kind(tokens[0]); const char* model = !g_strcmp0(tokens[1],"noname") ? nullptr : tokens[1]; const auto state = str2state(tokens[2]); const time_t time = atoi(tokens[3]); const double pct = strtod(tokens[4],nullptr); const char* path = !g_strcmp0(tokens[5],"nopath") ? nullptr : tokens[5]; const gboolean power_supply = atoi(tokens[6]); auto ret = indicator_power_device_new(path, kind, model, pct, state, time, power_supply); g_strfreev(tokens); return ret; } } /* 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) { const struct { std::string description; std::string expected; std::vector devices; } tests[] = { { "one discharging battery", "battery noname discharging 10m 60% bat01 1", { "battery noname discharging 10m 60% bat01 1" } }, { "merge two discharging batteries", "battery noname discharging 20m 70% nopath 1", { "battery noname discharging 10m 60% bat01 1", "battery noname discharging 20m 80% bat02 1" } }, { "merge two other discharging batteries", "battery noname discharging 30m 90% nopath 1", { "battery noname discharging 20m 80% bat01 1", "battery noname discharging 30m 100% bat02 1" } }, { "merge three discharging batteries", "battery noname discharging 30m 80% nopath 1", { "battery noname discharging 10m 60% bat01 1", "battery noname discharging 20m 80% bat02 1", "battery noname discharging 30m 100% bat03 1" } }, { "one charging battery", "battery noname charging 10m 60% bat01 1", { "battery noname charging 10m 60% bat01 1" } }, { "merge two charging batteries", "battery noname charging 20m 70% nopath 1", { "battery noname charging 10m 60% bat01 1", "battery noname charging 20m 80% bat02 1" } }, { "merge two other charging batteries", "battery noname charging 30m 90% nopath 1", { "battery noname charging 20m 80% bat01 1", "battery noname charging 30m 100% bat02 1" } }, { "merge three charging batteries", "battery noname charging 30m 80% nopath 1", { "battery noname charging 10m 60% bat01 1", "battery noname charging 20m 80% bat02 1", "battery noname charging 30m 100% bat03 1" } }, { "one charged battery", "battery noname charged 0m 100% bat01 1", { "battery noname charged 0m 100% bat01 1" } }, { "merge one charged, one discharging", "battery noname discharging 10m 80% nopath 1", { "battery noname charged 0m 100% bat01 1", "battery noname discharging 10m 60% bat02 1" } }, { "merged one charged, one charging", "battery noname charging 10m 80% nopath 1", { "battery noname charged 0m 100% bat01 1", "battery noname charging 10m 60% bat02 1" } }, { "merged one charged, one charging, one discharging", "battery noname discharging 10m 74% nopath 1", { "battery noname charged 0m 100% bat01 1", "battery noname charging 10m 60% bat02 1", "battery noname discharging 10m 60% bat03 1" } }, { "one discharging mouse and one discharging battery. ignore mouse because it doesn't supply the power", "battery noname discharging 10m 60% bat01 1", { "battery noname discharging 10m 60% bat01 1", "mouse noname discharging 20m 80% mouse01 0" } }, { "one discharging mouse and a different discharging battery. ignore mouse because it doesn't supply the power", "battery noname discharging 30m 100% bat01 1", { "battery noname discharging 30m 100% bat01 1", "mouse noname discharging 20m 80% mouse01 0" } }, { "everything comes before power lines #1", "battery noname discharging 10m 60% bat01 1", { "battery noname discharging 10m 60% bat01 1", "line-power noname unknown 0m 0% lp01 1" } }, { "everything comes before power lines #2", "battery noname charging 10m 60% bat01 1", { "battery noname charging 10m 60% bat01 1", "line-power noname unknown 0m 0% lp01 1" } }, { "everything comes before power lines #3 except that the mouse doesn't supply the power", "line-power noname unknown 0m 0% lp01 1", { "mouse noname discharging 20m 80% mouse01 0", "line-power noname unknown 0m 0% lp01 1" } }, { // https://bugs.launchpad.net/ubuntu/+source/indicator-power/+bug/1470080/comments/10 "don't select a device with unknown state when we have another device with a known state...", "battery noname charged 0m 100% bat01 1", { "battery noname charged 0m 100% bat01 1", "phone noname unknown 0m 61% phone01 1" } }, { // https://bugs.launchpad.net/ubuntu/+source/indicator-power/+bug/1470080/comments/10 "...but do select the unknown state device if nothing else is available", "phone noname unknown 0m 61% phone01 1", { "phone noname unknown 0m 61% phone01 1" } } }; for(const auto& test : tests) { // build the device list GList* device_glist {}; for (const auto& description : test.devices) device_glist = g_list_append(device_glist, str2device(description)); // run the test auto primary = indicator_power_service_choose_primary_device(device_glist); EXPECT_EQ(test.expected, device2str(primary)); g_clear_object(&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_EQ(test.expected, device2str(primary)); g_clear_object(&primary); // cleanup g_list_free_full(device_glist, g_object_unref); } }