(root)/
glib-2.79.0/
gio/
tests/
gdbus-introspection.c
       1  /* GLib testing framework examples and tests
       2   *
       3   * Copyright (C) 2008-2010 Red Hat, Inc.
       4   *
       5   * SPDX-License-Identifier: LGPL-2.1-or-later
       6   *
       7   * This library is free software; you can redistribute it and/or
       8   * modify it under the terms of the GNU Lesser General Public
       9   * License as published by the Free Software Foundation; either
      10   * version 2.1 of the License, or (at your option) any later version.
      11   *
      12   * This library is distributed in the hope that it will be useful,
      13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15   * Lesser General Public License for more details.
      16   *
      17   * You should have received a copy of the GNU Lesser General
      18   * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
      19   *
      20   * Author: David Zeuthen <davidz@redhat.com>
      21   */
      22  
      23  #include <gio/gio.h>
      24  #include <unistd.h>
      25  #include <string.h>
      26  
      27  #include "gdbus-tests.h"
      28  
      29  /* all tests rely on a shared mainloop */
      30  static GMainLoop *loop = NULL;
      31  
      32  /* ---------------------------------------------------------------------------------------------------- */
      33  /* Test introspection parser */
      34  /* ---------------------------------------------------------------------------------------------------- */
      35  
      36  static void
      37  test_introspection (GDBusProxy *proxy)
      38  {
      39    GError *error;
      40    const gchar *xml_data;
      41    GDBusNodeInfo *node_info;
      42    GDBusInterfaceInfo *interface_info;
      43    GDBusMethodInfo *method_info;
      44    GDBusSignalInfo *signal_info;
      45    GVariant *result;
      46  
      47    error = NULL;
      48  
      49    /*
      50     * Invoke Introspect(), then parse the output.
      51     */
      52    result = g_dbus_proxy_call_sync (proxy,
      53                                     "org.freedesktop.DBus.Introspectable.Introspect",
      54                                     NULL,
      55                                     G_DBUS_CALL_FLAGS_NONE,
      56                                     -1,
      57                                     NULL,
      58                                     &error);
      59    g_assert_no_error (error);
      60    g_assert (result != NULL);
      61    g_variant_get (result, "(&s)", &xml_data);
      62  
      63    node_info = g_dbus_node_info_new_for_xml (xml_data, &error);
      64    g_assert_no_error (error);
      65    g_assert (node_info != NULL);
      66  
      67    /* for now we only check a couple of things. TODO: check more things */
      68  
      69    interface_info = g_dbus_node_info_lookup_interface (node_info, "com.example.NonExistantInterface");
      70    g_assert (interface_info == NULL);
      71  
      72    interface_info = g_dbus_node_info_lookup_interface (node_info, "org.freedesktop.DBus.Introspectable");
      73    g_assert (interface_info != NULL);
      74    method_info = g_dbus_interface_info_lookup_method (interface_info, "NonExistantMethod");
      75    g_assert (method_info == NULL);
      76    method_info = g_dbus_interface_info_lookup_method (interface_info, "Introspect");
      77    g_assert (method_info != NULL);
      78    g_assert (method_info->in_args != NULL);
      79    g_assert (method_info->in_args[0] == NULL);
      80    g_assert (method_info->out_args != NULL);
      81    g_assert (method_info->out_args[0] != NULL);
      82    g_assert (method_info->out_args[1] == NULL);
      83    g_assert_cmpstr (method_info->out_args[0]->signature, ==, "s");
      84  
      85    interface_info = g_dbus_node_info_lookup_interface (node_info, "com.example.Frob");
      86    g_assert (interface_info != NULL);
      87    signal_info = g_dbus_interface_info_lookup_signal (interface_info, "TestSignal");
      88    g_assert (signal_info != NULL);
      89    g_assert (signal_info->args != NULL);
      90    g_assert (signal_info->args[0] != NULL);
      91    g_assert_cmpstr (signal_info->args[0]->signature, ==, "s");
      92    g_assert (signal_info->args[1] != NULL);
      93    g_assert_cmpstr (signal_info->args[1]->signature, ==, "o");
      94    g_assert (signal_info->args[2] != NULL);
      95    g_assert_cmpstr (signal_info->args[2]->signature, ==, "v");
      96    g_assert (signal_info->args[3] == NULL);
      97  
      98    g_dbus_node_info_unref (node_info);
      99    g_variant_unref (result);
     100  
     101    g_main_loop_quit (loop);
     102  }
     103  
     104  static void
     105  test_introspection_parser (void)
     106  {
     107    GDBusProxy *proxy;
     108    GDBusConnection *connection;
     109    GError *error;
     110  
     111    error = NULL;
     112    connection = g_bus_get_sync (G_BUS_TYPE_SESSION,
     113                                 NULL,
     114                                 &error);
     115    g_assert_no_error (error);
     116    error = NULL;
     117    proxy = g_dbus_proxy_new_sync (connection,
     118                                   G_DBUS_PROXY_FLAGS_NONE,
     119                                   NULL,                      /* GDBusInterfaceInfo */
     120                                   "com.example.TestService", /* name */
     121                                   "/com/example/TestObject", /* object path */
     122                                   "com.example.Frob",        /* interface */
     123                                   NULL, /* GCancellable */
     124                                   &error);
     125    g_assert_no_error (error);
     126  
     127    /* this is safe; testserver will exit once the bus goes away */
     128    g_assert (g_spawn_command_line_async (g_test_get_filename (G_TEST_BUILT, "gdbus-testserver", NULL), NULL));
     129  
     130    _g_assert_property_notify (proxy, "g-name-owner");
     131  
     132    test_introspection (proxy);
     133  
     134    g_object_unref (proxy);
     135    g_object_unref (connection);
     136  }
     137  
     138  /* check that a parse-generate roundtrip produces identical results
     139   */
     140  static void
     141  test_generate (void)
     142  {
     143    GDBusNodeInfo *info;
     144    GDBusNodeInfo *info2;
     145    GDBusInterfaceInfo *iinfo;
     146    GDBusMethodInfo *minfo;
     147    GDBusSignalInfo *sinfo;
     148    GDBusArgInfo *arginfo;
     149    GDBusPropertyInfo *pinfo;
     150    GDBusAnnotationInfo *aninfo;
     151    const gchar *data =
     152    "  <node>"
     153    "    <interface name='com.example.Frob'>"
     154    "      <annotation name='foo' value='bar'/>"
     155    "      <method name='PairReturn'>"
     156    "        <annotation name='org.freedesktop.DBus.GLib.Async' value=''/>"
     157    "        <arg type='u' name='somenumber' direction='in'/>"
     158    "        <arg type='s' name='somestring' direction='out'/>"
     159    "      </method>"
     160    "      <signal name='HelloWorld'>"
     161    "        <arg type='s' name='greeting' direction='out'/>"
     162    "      </signal>"
     163    "      <method name='Sleep'>"
     164    "        <arg type='i' name='timeout' direction='in'/>"
     165    "      </method>"
     166    "      <property name='y' type='y' access='readwrite'>"
     167    "        <annotation name='needs-escaping' value='bar&lt;&gt;&apos;&quot;'/>"
     168    "      </property>"
     169    "    </interface>"
     170    "  </node>";
     171  
     172    GString *string;
     173    GString *string2;
     174    GError *error;
     175  
     176    error = NULL;
     177    info = g_dbus_node_info_new_for_xml (data, &error);
     178    g_assert_no_error (error);
     179  
     180    iinfo = g_dbus_node_info_lookup_interface (info, "com.example.Frob");
     181    aninfo = iinfo->annotations[0];
     182    g_assert_cmpstr (aninfo->key, ==, "foo");
     183    g_assert_cmpstr (aninfo->value, ==, "bar");
     184    g_assert (iinfo->annotations[1] == NULL);
     185    minfo = g_dbus_interface_info_lookup_method (iinfo, "PairReturn");
     186    g_assert_cmpstr (g_dbus_annotation_info_lookup (minfo->annotations, "org.freedesktop.DBus.GLib.Async"), ==, "");
     187    arginfo = minfo->in_args[0];
     188    g_assert_cmpstr (arginfo->name, ==, "somenumber");
     189    g_assert_cmpstr (arginfo->signature, ==, "u");
     190    g_assert (minfo->in_args[1] == NULL);
     191    arginfo = minfo->out_args[0];
     192    g_assert_cmpstr (arginfo->name, ==, "somestring");
     193    g_assert_cmpstr (arginfo->signature, ==, "s");
     194    g_assert (minfo->out_args[1] == NULL);
     195    sinfo = g_dbus_interface_info_lookup_signal (iinfo, "HelloWorld");
     196    arginfo = sinfo->args[0];
     197    g_assert_cmpstr (arginfo->name, ==, "greeting");
     198    g_assert_cmpstr (arginfo->signature, ==, "s");
     199    g_assert (sinfo->args[1] == NULL);
     200    pinfo = g_dbus_interface_info_lookup_property (iinfo, "y");
     201    g_assert_cmpstr (pinfo->signature, ==, "y");
     202    g_assert_cmpint (pinfo->flags, ==, G_DBUS_PROPERTY_INFO_FLAGS_READABLE |
     203                                       G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE);
     204  
     205    string = g_string_new ("");
     206    g_dbus_node_info_generate_xml (info, 2, string);
     207  
     208    info2 = g_dbus_node_info_new_for_xml (string->str, &error);
     209    string2 = g_string_new ("");
     210    g_dbus_node_info_generate_xml (info2, 2, string2);
     211  
     212    g_assert_cmpstr (string->str, ==, string2->str);
     213    g_string_free (string, TRUE);
     214    g_string_free (string2, TRUE);
     215  
     216    g_dbus_node_info_unref (info);
     217    g_dbus_node_info_unref (info2);
     218  }
     219  
     220  /* test that omitted direction attributes default to 'out' for signals,
     221   * and 'in' for methods.
     222   */
     223  static void
     224  test_default_direction (void)
     225  {
     226    GDBusNodeInfo *info;
     227    GDBusInterfaceInfo *iinfo;
     228    GDBusMethodInfo *minfo;
     229    GDBusSignalInfo *sinfo;
     230    GDBusArgInfo *arginfo;
     231    const gchar *data =
     232    "  <node>"
     233    "    <interface name='com.example.Frob'>"
     234    "      <signal name='HelloWorld'>"
     235    "        <arg type='s' name='greeting'/>"
     236    "      </signal>"
     237    "      <method name='Sleep'>"
     238    "        <arg type='i' name='timeout'/>"
     239    "      </method>"
     240    "    </interface>"
     241    "  </node>";
     242  
     243    GError *error;
     244  
     245    error = NULL;
     246    info = g_dbus_node_info_new_for_xml (data, &error);
     247    g_assert_no_error (error);
     248  
     249    iinfo = g_dbus_node_info_lookup_interface (info, "com.example.Frob");
     250    sinfo = g_dbus_interface_info_lookup_signal (iinfo, "HelloWorld");
     251    g_assert (sinfo->args != NULL);
     252    arginfo = sinfo->args[0];
     253    g_assert_cmpstr (arginfo->name, ==, "greeting");
     254    g_assert (sinfo->args[1] == NULL);
     255    minfo = g_dbus_interface_info_lookup_method (iinfo, "Sleep");
     256    g_assert (minfo->in_args != NULL);
     257    arginfo = minfo->in_args[0];
     258    g_assert_cmpstr (arginfo->name, ==, "timeout");
     259    g_assert (minfo->in_args[1] == NULL);
     260  
     261    g_dbus_node_info_unref (info);
     262  }
     263  
     264  static void
     265  test_extra_data (void)
     266  {
     267    GDBusNodeInfo *info;
     268    const gchar *data =
     269    "  <node>"
     270    "    <interface name='com.example.Frob' version='1.0'>"
     271    "      <doc:doc><doc:description><doc:para>Blah blah</doc:para></doc:description></doc:doc>"
     272    "      <method name='DownloadPackages'>"
     273    "        <arg type='u' name='somenumber' direction='in'>"
     274    "          <doc:doc><doc:summary><doc:para>"
     275    "            See <doc:ulink url='http:///example.com'>example</doc:ulink>"
     276    "          </doc:para></doc:summary></doc:doc>"
     277    "        </arg>"
     278    "        <arg type='s' name='somestring' direction='out'>"
     279    "          <doc:doc><doc:summary><doc:para>"
     280    "            More docs"
     281    "          </doc:para></doc:summary></doc:doc>"
     282    "        </arg>"
     283    "      </method>"
     284    "      <signal name='HelloWorld'>"
     285    "        <arg type='s' name='somestring'/>"
     286    "      </signal>"
     287    "      <method name='Sleep'>"
     288    "        <arg type='i' name='timeout' direction='in'/>"
     289    "      </method>"
     290    "      <property name='y' type='y' access='readwrite'/>"
     291    "    </interface>"
     292    "  </node>";
     293    GError *error;
     294  
     295    error = NULL;
     296    info = g_dbus_node_info_new_for_xml (data, &error);
     297    g_assert_no_error (error);
     298  
     299    g_dbus_node_info_unref (info);
     300  }
     301  
     302  /* ---------------------------------------------------------------------------------------------------- */
     303  
     304  int
     305  main (int   argc,
     306        char *argv[])
     307  {
     308    gint ret;
     309  
     310    g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
     311  
     312    /* all the tests rely on a shared main loop */
     313    loop = g_main_loop_new (NULL, FALSE);
     314  
     315    g_test_add_func ("/gdbus/introspection-parser", test_introspection_parser);
     316    g_test_add_func ("/gdbus/introspection-generate", test_generate);
     317    g_test_add_func ("/gdbus/introspection-default-direction", test_default_direction);
     318    g_test_add_func ("/gdbus/introspection-extra-data", test_extra_data);
     319  
     320    ret = session_bus_run ();
     321  
     322    while (g_main_context_iteration (NULL, FALSE));
     323    g_main_loop_unref (loop);
     324  
     325    return ret;
     326  }