const int LONG_TIMEOUT = 1; const int SHORT_TIMEOUT = 1000; [DBus (name = "com.canonical.indicator.keyboard.test")] public class Service : Object { [DBus (visible = false)] private string? _command; [DBus (visible = false)] public string? command { get { return _command; } } public void execute (string command) { this._command = command; var pspec = this.get_class ().find_property ("command"); if (pspec != null) { this.notify["command"] ((!) pspec); } } } struct Fixture { TestDBus? bus; uint service_name; DBusConnection? connection; Service? service; uint object_name; } static void start_service (Fixture *fixture) { if (fixture.connection != null) { try { fixture.service = new Service (); fixture.object_name = ((!) fixture.connection).register_object ("/com/canonical/indicator/keyboard/test", fixture.service); } catch (IOError error) { fixture.connection = null; fixture.service = null; fixture.object_name = 0; Test.message ("error: %s", error.message); Test.fail (); } } } static void begin_test (void *data) { var fixture = (Fixture *) data; fixture.bus = new TestDBus (TestDBusFlags.NONE); ((!) fixture.bus).add_service_dir (SERVICE_DIR); ((!) fixture.bus).up (); var loop = new MainLoop (null, false); fixture.service_name = Bus.own_name (BusType.SESSION, "com.canonical.indicator.keyboard.test", BusNameOwnerFlags.ALLOW_REPLACEMENT | BusNameOwnerFlags.REPLACE, (connection, name) => { if (loop.is_running ()) { fixture.connection = connection; start_service (fixture); loop.quit (); } }, null, (connection, name) => { if (loop.is_running ()) { fixture.connection = null; fixture.service = null; fixture.object_name = 0; loop.quit (); } }); loop.run (); if (fixture.connection == null) { Test.message ("Unable to connect to 'com.canonical.indicator.keyboard.test'."); Test.fail (); } } static void end_test (void *data) { var fixture = (Fixture *) data; if (fixture.object_name != 0) { ((!) fixture.connection).unregister_object (fixture.object_name); fixture.object_name = 0; } if (fixture.service_name != 0) { Bus.unown_name (fixture.service_name); fixture.service_name = 0; } fixture.service = null; fixture.connection = null; if (fixture.bus != null) { ((!) fixture.bus).down (); fixture.bus = null; } } static void test_activate_input_source (void *data) { var fixture = (Fixture *) data; if (fixture.object_name == 0) { Test.message ("Invalid test fixture."); Test.fail (); return; } try { var current = 0; var sources = "[('xkb', 'us'), ('xkb', 'ca+eng'), ('xkb', 'epo'), ('ibus', 'pinyin')]"; Process.spawn_command_line_sync (@"gsettings set org.gnome.desktop.input-sources current $current"); Process.spawn_command_line_sync (@"gsettings set org.gnome.desktop.input-sources sources \"$sources\""); } catch (SpawnError error) { Test.message ("error: %s", error.message); Test.fail (); return; } var cancellable = new Cancellable (); DBusProxy action_proxy; DBusProxy menu_proxy; var source = Timeout.add_seconds (LONG_TIMEOUT, () => { cancellable.cancel (); return false; }); try { action_proxy = new DBusProxy.for_bus_sync (BusType.SESSION, DBusProxyFlags.NONE, null, "com.canonical.indicator.keyboard", "/com/canonical/indicator/keyboard", "org.gtk.Actions", cancellable); } catch (Error error) { Test.message ("error: %s", error.message); Test.fail (); return; } Source.remove (source); if (cancellable.is_cancelled ()) { Test.message ("Unable to connect to 'com.canonical.indicator.keyboard'.\n"); Test.fail (); return; } source = Timeout.add_seconds (LONG_TIMEOUT, () => { cancellable.cancel (); return false; }); try { menu_proxy = new DBusProxy.for_bus_sync (BusType.SESSION, DBusProxyFlags.NONE, null, "com.canonical.indicator.keyboard", "/com/canonical/indicator/keyboard/desktop", "org.gtk.Menus", cancellable); } catch (Error error) { Test.message ("error: %s", error.message); Test.fail (); return; } Source.remove (source); if (cancellable.is_cancelled ()) { Test.message ("Unable to connect to 'com.canonical.indicator.keyboard'.\n"); Test.fail (); return; } try { var builder = new VariantBuilder (new VariantType ("(sava{sv})")); builder.add ("s", "current"); builder.add_value (new Variant.parsed ("[<@u 2>]")); builder.add_value (new Variant.parsed ("@a{sv} {}")); action_proxy.call_sync ("Activate", builder.end (), DBusCallFlags.NONE, SHORT_TIMEOUT); } catch (Error error) { Test.message ("error: %s", error.message); Test.fail (); return; } try { string current; Process.spawn_command_line_sync ("gsettings get org.gnome.desktop.input-sources current", out current); assert (strcmp (current, "uint32 2\n") == 0); } catch (SpawnError error) { Test.message ("error: %s", error.message); Test.fail (); return; } } static void test_activate_character_map (void *data) { var fixture = (Fixture *) data; if (fixture.object_name == 0) { Test.message ("Invalid test fixture."); Test.fail (); return; } var cancellable = new Cancellable (); DBusProxy action_proxy; DBusProxy menu_proxy; var source = Timeout.add_seconds (LONG_TIMEOUT, () => { cancellable.cancel (); return false; }); try { action_proxy = new DBusProxy.for_bus_sync (BusType.SESSION, DBusProxyFlags.NONE, null, "com.canonical.indicator.keyboard", "/com/canonical/indicator/keyboard", "org.gtk.Actions", cancellable); } catch (Error error) { Test.message ("error: %s", error.message); Test.fail (); return; } Source.remove (source); if (cancellable.is_cancelled ()) { Test.message ("Unable to connect to 'com.canonical.indicator.keyboard'.\n"); Test.fail (); return; } source = Timeout.add_seconds (LONG_TIMEOUT, () => { cancellable.cancel (); return false; }); try { menu_proxy = new DBusProxy.for_bus_sync (BusType.SESSION, DBusProxyFlags.NONE, null, "com.canonical.indicator.keyboard", "/com/canonical/indicator/keyboard/desktop", "org.gtk.Menus", cancellable); } catch (Error error) { Test.message ("error: %s", error.message); Test.fail (); return; } Source.remove (source); if (cancellable.is_cancelled ()) { Test.message ("Unable to connect to 'com.canonical.indicator.keyboard'.\n"); Test.fail (); return; } var loop = new MainLoop (null, false); var signal_name = ((!) fixture.service).notify["command"].connect ((pspec) => { loop.quit (); }); try { var builder = new VariantBuilder (new VariantType ("(sava{sv})")); builder.add ("s", "map"); builder.add_value (new Variant.parsed ("@av []")); builder.add_value (new Variant.parsed ("@a{sv} {}")); action_proxy.call_sync ("Activate", builder.end (), DBusCallFlags.NONE, SHORT_TIMEOUT); } catch (Error error) { Test.message ("error: %s", error.message); Test.fail (); return; } source = Timeout.add_seconds (LONG_TIMEOUT, () => { loop.quit (); return false; }); loop.run (); Source.remove (source); ((!) fixture.service).disconnect (signal_name); assert (strcmp ((!) ((!) fixture.service).command, "'gucharmap '") == 0); } static void test_activate_keyboard_layout_chart (void *data) { var fixture = (Fixture *) data; if (fixture.object_name == 0) { Test.message ("Invalid test fixture."); Test.fail (); return; } try { var current = 1; var sources = "[('xkb', 'us'), ('xkb', 'ca+eng'), ('xkb', 'epo'), ('ibus', 'pinyin')]"; Process.spawn_command_line_sync (@"gsettings set org.gnome.desktop.input-sources current $current"); Process.spawn_command_line_sync (@"gsettings set org.gnome.desktop.input-sources sources \"$sources\""); } catch (SpawnError error) { Test.message ("error: %s", error.message); Test.fail (); return; } var cancellable = new Cancellable (); DBusProxy action_proxy; DBusProxy menu_proxy; var source = Timeout.add_seconds (LONG_TIMEOUT, () => { cancellable.cancel (); return false; }); try { action_proxy = new DBusProxy.for_bus_sync (BusType.SESSION, DBusProxyFlags.NONE, null, "com.canonical.indicator.keyboard", "/com/canonical/indicator/keyboard", "org.gtk.Actions", cancellable); } catch (Error error) { Test.message ("error: %s", error.message); Test.fail (); return; } Source.remove (source); if (cancellable.is_cancelled ()) { Test.message ("Unable to connect to 'com.canonical.indicator.keyboard'.\n"); Test.fail (); return; } source = Timeout.add_seconds (LONG_TIMEOUT, () => { cancellable.cancel (); return false; }); try { menu_proxy = new DBusProxy.for_bus_sync (BusType.SESSION, DBusProxyFlags.NONE, null, "com.canonical.indicator.keyboard", "/com/canonical/indicator/keyboard/desktop", "org.gtk.Menus", cancellable); } catch (Error error) { Test.message ("error: %s", error.message); Test.fail (); return; } Source.remove (source); if (cancellable.is_cancelled ()) { Test.message ("Unable to connect to 'com.canonical.indicator.keyboard'.\n"); Test.fail (); return; } var loop = new MainLoop (null, false); var signal_name = ((!) fixture.service).notify["command"].connect ((pspec) => { loop.quit (); }); try { var builder = new VariantBuilder (new VariantType ("(sava{sv})")); builder.add ("s", "chart"); builder.add_value (new Variant.parsed ("@av []")); builder.add_value (new Variant.parsed ("@a{sv} {}")); action_proxy.call_sync ("Activate", builder.end (), DBusCallFlags.NONE, SHORT_TIMEOUT); } catch (Error error) { Test.message ("error: %s", error.message); Test.fail (); return; } source = Timeout.add_seconds (LONG_TIMEOUT, () => { loop.quit (); return false; }); loop.run (); Source.remove (source); ((!) fixture.service).disconnect (signal_name); assert (strcmp ((!) ((!) fixture.service).command, "'gkbd-keyboard-display -l ca\teng'") == 0); } static void test_activate_text_entry_settings (void *data) { var fixture = (Fixture *) data; if (fixture.object_name == 0) { Test.message ("Invalid test fixture."); Test.fail (); return; } var cancellable = new Cancellable (); DBusProxy action_proxy; DBusProxy menu_proxy; var source = Timeout.add_seconds (LONG_TIMEOUT, () => { cancellable.cancel (); return false; }); try { action_proxy = new DBusProxy.for_bus_sync (BusType.SESSION, DBusProxyFlags.NONE, null, "com.canonical.indicator.keyboard", "/com/canonical/indicator/keyboard", "org.gtk.Actions", cancellable); } catch (Error error) { Test.message ("error: %s", error.message); Test.fail (); return; } Source.remove (source); if (cancellable.is_cancelled ()) { Test.message ("Unable to connect to 'com.canonical.indicator.keyboard'.\n"); Test.fail (); return; } source = Timeout.add_seconds (LONG_TIMEOUT, () => { cancellable.cancel (); return false; }); try { menu_proxy = new DBusProxy.for_bus_sync (BusType.SESSION, DBusProxyFlags.NONE, null, "com.canonical.indicator.keyboard", "/com/canonical/indicator/keyboard/desktop", "org.gtk.Menus", cancellable); } catch (Error error) { Test.message ("error: %s", error.message); Test.fail (); return; } Source.remove (source); if (cancellable.is_cancelled ()) { Test.message ("Unable to connect to 'com.canonical.indicator.keyboard'.\n"); Test.fail (); return; } var loop = new MainLoop (null, false); var signal_name = ((!) fixture.service).notify["command"].connect ((pspec) => { loop.quit (); }); try { var builder = new VariantBuilder (new VariantType ("(sava{sv})")); builder.add ("s", "settings"); builder.add_value (new Variant.parsed ("@av []")); builder.add_value (new Variant.parsed ("@a{sv} {}")); action_proxy.call_sync ("Activate", builder.end (), DBusCallFlags.NONE, SHORT_TIMEOUT); } catch (Error error) { Test.message ("error: %s", error.message); Test.fail (); return; } source = Timeout.add_seconds (LONG_TIMEOUT, () => { loop.quit (); return false; }); loop.run (); Source.remove (source); ((!) fixture.service).disconnect (signal_name); assert (strcmp ((!) ((!) fixture.service).command, "'gnome-control-center region layouts'") == 0); } static void test_migration (void *data) { } static void test_update_visible (void *data) { } static void test_update_input_source (void *data) { } static void test_update_input_sources (void *data) { } public int main (string[] args) { Environment.set_variable ("DCONF_PROFILE", DCONF_PROFILE, true); Test.init (ref args, null); var suite = new TestSuite ("indicator-keyboard"); suite.add (new TestCase ("activate-input-source", begin_test, test_activate_input_source, end_test, sizeof (Fixture))); suite.add (new TestCase ("activate-character-map", begin_test, test_activate_character_map, end_test, sizeof (Fixture))); suite.add (new TestCase ("activate-keyboard-layout-chart", begin_test, test_activate_keyboard_layout_chart, end_test, sizeof (Fixture))); suite.add (new TestCase ("activate-text-entry-settings", begin_test, test_activate_text_entry_settings, end_test, sizeof (Fixture))); suite.add (new TestCase ("migration", begin_test, test_migration, end_test, sizeof (Fixture))); suite.add (new TestCase ("update-visible", begin_test, test_update_visible, end_test, sizeof (Fixture))); suite.add (new TestCase ("update-input-source", begin_test, test_update_input_source, end_test, sizeof (Fixture))); suite.add (new TestCase ("update-input-sources", begin_test, test_update_input_sources, end_test, sizeof (Fixture))); TestSuite.get_root ().add_suite (suite); return Test.run (); }