/* Copyright 2012 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 "gtest-dbus-fixture.h" #include "service.h" #include "backend-mock.h" #include "backend-mock-users.h" #include "backend-mock-guest.h" #include "backend-mock-actions.h" /*** **** ***/ #if 0 namespace { void dump_menu_model (GMenuModel * model, int depth) { GString * indent = g_string_new_len (" ", (depth*4)); const int n = g_menu_model_get_n_items (model); g_message ("%s depth[%d] menu model[%p] has %d items", indent->str, depth, (void*)model, n); for (int i=0; istr, depth, (void*)model, i, name, str); g_free (str); g_variant_unref (attribute_value); } g_clear_object (&attribute_iter); GMenuLinkIter * link_iter = g_menu_model_iterate_item_links (model, i); while (g_menu_link_iter_get_next (link_iter, &name, &link_value)) { g_message ("%s depth[%d] menu model[%p] item[%d] attribute key[%s] model[%p]", indent->str, depth, (void*)model, i, name, (void*)link_value); dump_menu_model (link_value, depth+1); g_object_unref (link_value); } g_clear_object (&link_iter); } g_string_free (indent, TRUE); } } #endif /* cppcheck-suppress noConstructor */ class ServiceTest: public GTestDBusFixture { typedef GTestDBusFixture super; enum { TIME_LIMIT_SEC = 10 }; private: static void on_name_appeared (GDBusConnection * connection G_GNUC_UNUSED, const gchar * name G_GNUC_UNUSED, const gchar * name_owner G_GNUC_UNUSED, gpointer gself) { g_main_loop_quit (static_cast(gself)->loop); } GSList * menu_references; gboolean any_item_changed; static void on_items_changed (GMenuModel * model G_GNUC_UNUSED, gint position G_GNUC_UNUSED, gint removed G_GNUC_UNUSED, gint added G_GNUC_UNUSED, gpointer any_item_changed) { *((gboolean*)any_item_changed) = true; } protected: void activate_subtree (GMenuModel * model) { // query the GDBusMenuModel for information to activate it int n = g_menu_model_get_n_items (model); if (!n) { // give the model a moment to populate its info wait_msec (100); n = g_menu_model_get_n_items (model); } // keep a ref so that it stays activated menu_references = g_slist_prepend (menu_references, g_object_ref(model)); g_signal_connect (model, "items-changed", G_CALLBACK(on_items_changed), &any_item_changed); // recurse for (int i=0; i= TIME_LIMIT_SEC; } void wait_for_has_action (const char * name) { while (!g_action_group_has_action (G_ACTION_GROUP(action_group), name) && !times_up()) wait_msec (50); ASSERT_FALSE (times_up()); ASSERT_TRUE (g_action_group_has_action (G_ACTION_GROUP(action_group), name)); } void wait_for_menu_resync (void) { any_item_changed = false; while (!times_up() && !any_item_changed) wait_msec (50); g_warn_if_fail (any_item_changed); sync_menu (); } protected: void check_last_command_is (const char * expected) { char * str = g_settings_get_string (mock_settings, "last-command"); ASSERT_STREQ (expected, str); g_free (str); } void test_simple_action (const char * action_name) { wait_for_has_action (action_name); g_action_group_activate_action (G_ACTION_GROUP (action_group), action_name, NULL); wait_for_signal (mock_settings, "changed::last-command"); check_last_command_is (action_name); } protected: bool find_menu_item_for_action (const char * action_key, GMenuModel ** setme, int * item_index) { bool success = false; for (GSList * l=menu_references; !success && (l!=NULL); l=l->next) { GMenuModel * mm = G_MENU_MODEL (l->data); const int n = g_menu_model_get_n_items (mm); for (int i=0; !success && iis_current_user = false; u->is_logged_in = false; u->uid = account_info[i].uid; u->login_frequency = account_info[i].login_frequency; u->user_name = g_strdup (account_info[i].user_name); u->real_name = g_strdup (account_info[i].real_name); indicator_session_users_mock_add_user (INDICATOR_SESSION_USERS_MOCK(mock_users), u); users[i] = u; } wait_for_menu_resync (); // now there should be 7 menuitems: greeter + guest + the five doctors ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-screensaver", &switch_menu, &pos)); ASSERT_EQ (0, pos); ASSERT_EQ (7, g_menu_model_get_n_items (switch_menu)); // confirm that the doctor names are sorted check_label ("Fifth Doctor", switch_menu, 2); check_label ("First Doctor", switch_menu, 3); check_label ("Fourth Doctor", switch_menu, 4); check_label ("Second Doctor", switch_menu, 5); check_label ("Third Doctor", switch_menu, 6); g_clear_object (&switch_menu); // now remove a couple of 'em indicator_session_users_mock_remove_user (INDICATOR_SESSION_USERS_MOCK(mock_users), account_info[3].uid); indicator_session_users_mock_remove_user (INDICATOR_SESSION_USERS_MOCK(mock_users), account_info[4].uid); wait_for_menu_resync (); // now there should be 5 menuitems: greeter + guest + the three doctors ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-screensaver", &switch_menu, &pos)); ASSERT_EQ (0, pos); ASSERT_EQ (5, g_menu_model_get_n_items (switch_menu)); // confirm that the doctor names are sorted check_label ("First Doctor", switch_menu, 2); check_label ("Second Doctor", switch_menu, 3); check_label ("Third Doctor", switch_menu, 4); g_clear_object (&switch_menu); // now let's have the third one be the current user users[2]->is_current_user = true; users[2]->is_logged_in = true; indicator_session_users_changed (mock_users, users[2]->uid); wait_for_menu_resync (); // now there should be 5 menuitems: greeter + guest + the three doctors ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-screensaver", &switch_menu, &pos)); ASSERT_EQ (0, pos); ASSERT_EQ (5, g_menu_model_get_n_items (switch_menu)); g_clear_object (&switch_menu); // oh hey, while we've got an active user let's check the header ASSERT_FALSE (g_settings_get_boolean (indicator_settings, show_name_key)); ASSERT_FALSE (g_settings_get_boolean (mock_settings, error_key)); check_header ("", "system-devices-panel", "System"); g_settings_set_boolean (indicator_settings, show_name_key, true); wait_for_signal (action_group, "action-state-changed"); check_header ("Third Doctor", "system-devices-panel", "System, Third Doctor"); g_settings_set_boolean (mock_settings, error_key, true); wait_for_signal (action_group, "action-state-changed"); check_header ("Third Doctor", "system-devices-panel-alert", "System, Third Doctor (Attention Required)"); g_settings_reset (mock_settings, error_key); g_settings_reset (indicator_settings, show_name_key); wait_for_menu_resync (); // try setting the max user count to 2... // since troughton has the fewest logins, he should get culled g_object_set (service, "max-users", 2, NULL); guint max_users; g_object_get (service, "max-users", &max_users, NULL); ASSERT_EQ (2, max_users); wait_for_menu_resync (); ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-screensaver", &switch_menu, &pos)); ASSERT_EQ (0, pos); ASSERT_EQ (4, g_menu_model_get_n_items (switch_menu)); check_label ("First Doctor", switch_menu, 2); check_label ("Third Doctor", switch_menu, 3); g_clear_object (&switch_menu); // add some more, test sorting and culling. // add in all the doctors, but only show 7, and make msmith the current session g_object_set (service, "max-users", 7, NULL); g_object_get (service, "max-users", &max_users, NULL); ASSERT_EQ (7, max_users); for (int i=3; i<12; ++i) { IndicatorSessionUser * u = g_new0 (IndicatorSessionUser, 1); u->is_current_user = false; u->is_logged_in = false; u->uid = 101 + i; u->login_frequency = account_info[i].login_frequency; u->user_name = g_strdup (account_info[i].user_name); u->real_name = g_strdup (account_info[i].real_name); indicator_session_users_mock_add_user (INDICATOR_SESSION_USERS_MOCK(mock_users), u); users[i] = u; } users[2]->is_current_user = false; indicator_session_users_changed (mock_users, users[2]->uid); users[10]->is_current_user = true; users[10]->is_logged_in = true; indicator_session_users_changed (mock_users, users[10]->uid); wait_for_menu_resync (); ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-screensaver", &switch_menu, &pos)); ASSERT_EQ (0, pos); ASSERT_EQ (9, g_menu_model_get_n_items (switch_menu)); check_label ("Eleventh Doctor", switch_menu, 2); check_label ("Fifth Doctor", switch_menu, 3); check_label ("First Doctor", switch_menu, 4); check_label ("Fourth Doctor", switch_menu, 5); check_label ("Second Doctor", switch_menu, 6); check_label ("Tenth Doctor", switch_menu, 7); check_label ("Third Doctor", switch_menu, 8); g_clear_object (&switch_menu); // now switch to one of the doctors g_action_group_activate_action (G_ACTION_GROUP(action_group), "switch-to-user", g_variant_new_string("tbaker")); wait_for_signal (mock_settings, "changed::last-command"); check_last_command_is ("switch-to-user::tbaker"); } TEST_F (ServiceTest, UserLabels) { int pos = 0; GMenuModel * switch_menu = 0; // Check label uses username when real name is blank IndicatorSessionUser * u = g_new0 (IndicatorSessionUser, 1); u->uid = 100; u->user_name = g_strdup ("blank"); u->real_name = g_strdup (""); indicator_session_users_mock_add_user (INDICATOR_SESSION_USERS_MOCK(mock_users), u); wait_for_menu_resync (); ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-screensaver", &switch_menu, &pos)); check_label ("blank", switch_menu, 2); g_clear_object (&switch_menu); indicator_session_users_mock_remove_user (INDICATOR_SESSION_USERS_MOCK(mock_users), 100); // Check label uses username when real name is all whitespace u = g_new0 (IndicatorSessionUser, 1); u->uid = 100; u->user_name = g_strdup ("whitespace"); u->real_name = g_strdup (" "); indicator_session_users_mock_add_user (INDICATOR_SESSION_USERS_MOCK(mock_users), u); wait_for_menu_resync (); ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-screensaver", &switch_menu, &pos)); check_label ("whitespace", switch_menu, 2); g_clear_object (&switch_menu); indicator_session_users_mock_remove_user (INDICATOR_SESSION_USERS_MOCK(mock_users), 100); }