/* * This file is part of Cockpit. * * Copyright (C) 2016 Red Hat, Inc. * * Cockpit is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * Cockpit is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Cockpit; If not, see . */ #include "config.h" #include "cockpitdbusmeta.h" #include "common/cockpitjson.h" #include "common/cockpittest.h" #include typedef struct { const GDBusInterfaceInfo *iface; const gchar *result; } BuildFixture; static const GDBusArgInfo janitor_method_say_what = { -1, (gchar *)"what", "s" }; static const GDBusArgInfo janitor_method_say_how = { -1, (gchar *)"how", "i", }; static const GDBusArgInfo *janitor_method_say_in[] = { &janitor_method_say_what, &janitor_method_say_how, NULL, }; static const GDBusArgInfo janitor_method_say_said = { -1, (gchar *)"said", "a{sv}", }; static const GDBusArgInfo *janitor_method_say_out[] = { &janitor_method_say_said, NULL, }; static const GDBusMethodInfo janitor_method_say = { -1, (gchar *)"Say", (GDBusArgInfo **) &janitor_method_say_in, (GDBusArgInfo **) &janitor_method_say_out, }; static const GDBusArgInfo janitor_method_mop_mess = { -1, (gchar *)"mess", "sa{sa{sv}}a{sv}a{sv}a{sv}a{sv}a{sv}a{sv}ssa{sv}a{sv}b" }; static const GDBusArgInfo *janitor_method_mop_out[] = { &janitor_method_mop_mess, NULL, }; static const GDBusMethodInfo janitor_method_mop = { -1, (gchar *)"Mop", (GDBusArgInfo **) NULL, (GDBusArgInfo **) &janitor_method_mop_out, }; static const GDBusMethodInfo *janitor_methods[] = { &janitor_method_say, &janitor_method_mop, NULL }; static const GDBusArgInfo janitor_signal_oh_oh = { -1, (gchar *)"oh", "v", }; static const GDBusArgInfo janitor_signal_oh_marmalade = { -1, (gchar *)"marmalade", "v" }; static const GDBusArgInfo *janitor_signal_oh_args[] = { &janitor_signal_oh_oh, &janitor_signal_oh_marmalade, NULL, }; static const GDBusSignalInfo janitor_signal_oh = { -1, (gchar *)"Oh", (GDBusArgInfo **)&janitor_signal_oh_args }; static const GDBusSignalInfo janitor_signal_boom = { -1, (gchar *)"Oh", (GDBusArgInfo **)&janitor_signal_oh_args }; static const GDBusSignalInfo *janitor_signals[] = { &janitor_signal_oh, &janitor_signal_boom, NULL }; static const GDBusPropertyInfo janitor_property_name = { -1, (gchar *)"Name", "s", G_DBUS_PROPERTY_INFO_FLAGS_READABLE }; static const GDBusPropertyInfo janitor_property_habit = { -1, (gchar *)"Habit", "a{sv}", G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE }; static const GDBusPropertyInfo janitor_property_hidden = { -1, (gchar *)"Hidden", "b", G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE }; static const GDBusPropertyInfo *janitor_properties[] = { &janitor_property_name, &janitor_property_habit, &janitor_property_hidden, NULL }; static const GDBusInterfaceInfo janitor_interface = { -1, "planet.express.Janitor", (GDBusMethodInfo **) &janitor_methods, (GDBusSignalInfo **) &janitor_signals, (GDBusPropertyInfo **) &janitor_properties, NULL }; static const gchar janitor_json[] = "{" "\"methods\": {" "\"Say\": {" "\"in\": [\"s\",\"i\"]," "\"out\":[\"a{sv}\"]" "}," "\"Mop\": {" "\"out\":[\"sa{sa{sv}}a{sv}a{sv}a{sv}a{sv}a{sv}a{sv}ssa{sv}a{sv}b\"]" "}" "}," "\"properties\": {" "\"Name\": {" "\"flags\": \"r\"," "\"type\": \"s\"" "}," "\"Habit\": {" "\"flags\": \"rw\"," "\"type\": \"a{sv}\"" "}," "\"Hidden\": {" "\"flags\": \"w\"," "\"type\": \"b\"" "}" "}," "\"signals\": {" "\"Oh\": {" "\"in\": [\"v\",\"v\"]" "}" "}" "}"; static const GDBusInterfaceInfo no_methods_interface = { -1, "planet.express.NoMethods", (GDBusMethodInfo **) NULL, (GDBusSignalInfo **) &janitor_signals, (GDBusPropertyInfo **) &janitor_properties, NULL }; static const gchar no_methods_json[] = "{" "\"properties\": {" "\"Name\": {" "\"flags\": \"r\"," "\"type\": \"s\"" "}," "\"Habit\": {" "\"flags\": \"rw\"," "\"type\": \"a{sv}\"" "}," "\"Hidden\": {" "\"flags\": \"w\"," "\"type\": \"b\"" "}" "}," "\"signals\": {" "\"Oh\": {" "\"in\": [\"v\",\"v\"]" "}" "}" "}"; static const GDBusInterfaceInfo no_signals_interface = { -1, "planet.express.NoSignals", (GDBusMethodInfo **) &janitor_methods, (GDBusSignalInfo **) NULL, (GDBusPropertyInfo **) &janitor_properties, NULL }; static const gchar no_signals_json[] = "{" "\"methods\": {" "\"Say\": {" "\"in\": [\"s\",\"i\"]," "\"out\":[\"a{sv}\"]" "}," "\"Mop\": {" "\"out\":[\"sa{sa{sv}}a{sv}a{sv}a{sv}a{sv}a{sv}a{sv}ssa{sv}a{sv}b\"]" "}" "}," "\"properties\": {" "\"Name\": {" "\"flags\": \"r\"," "\"type\": \"s\"" "}," "\"Habit\": {" "\"flags\": \"rw\"," "\"type\": \"a{sv}\"" "}," "\"Hidden\": {" "\"flags\": \"w\"," "\"type\": \"b\"" "}" "}" "}"; static const GDBusInterfaceInfo no_properties_interface = { -1, "planet.express.NoProperties", (GDBusMethodInfo **) &janitor_methods, (GDBusSignalInfo **) &janitor_signals, (GDBusPropertyInfo **) NULL, NULL }; static const gchar no_properties_json[] = "{" "\"methods\": {" "\"Say\": {" "\"in\": [\"s\",\"i\"]," "\"out\":[\"a{sv}\"]" "}," "\"Mop\": {" "\"out\":[\"sa{sa{sv}}a{sv}a{sv}a{sv}a{sv}a{sv}a{sv}ssa{sv}a{sv}b\"]" "}" "}," "\"signals\": {" "\"Oh\": {" "\"in\": [\"v\",\"v\"]" "}" "}" "}"; static const BuildFixture build_janitor_fixture = { &janitor_interface, janitor_json }; static const BuildFixture build_no_methods_fixture = { &no_methods_interface, no_methods_json }; static const BuildFixture build_no_signals_fixture = { &no_signals_interface, no_signals_json }; static const BuildFixture build_no_properties_fixture = { &no_properties_interface, no_properties_json }; static void test_build (gconstpointer data) { const BuildFixture *fixture = data; JsonObject *object; object = cockpit_dbus_meta_build ((GDBusInterfaceInfo *)fixture->iface); cockpit_assert_json_eq (object, fixture->result); json_object_unref (object); } static void assert_equal_arg (GDBusArgInfo *one, GDBusArgInfo *two) { g_assert (one != NULL); g_assert (two != NULL); g_assert_cmpstr (one->signature, ==, two->signature); } static void assert_equal_args (GDBusArgInfo **one, GDBusArgInfo **two) { if (one == NULL || two == NULL) { g_assert (one == NULL && two == NULL); return; } while (*one != NULL && *two != NULL) { assert_equal_arg (*one, *two); one++; two++; } } static void assert_equal_method (GDBusMethodInfo *one, GDBusMethodInfo *two) { g_assert (one != NULL); g_assert (two != NULL); g_assert_cmpstr (one->name, ==, two->name); assert_equal_args (one->in_args, two->in_args); assert_equal_args (one->out_args, two->out_args); } static void assert_equal_methods (GDBusMethodInfo **one, GDBusMethodInfo **two) { if (one == NULL || two == NULL) { g_assert (one == NULL && two == NULL); return; } while (*one != NULL && *two != NULL) { assert_equal_method (*one, *two); one++; two++; } } static void assert_equal_signal (GDBusSignalInfo *one, GDBusSignalInfo *two) { g_assert (one != NULL); g_assert (two != NULL); g_assert_cmpstr (one->name, ==, two->name); assert_equal_args (one->args, two->args); } static void assert_equal_signals (GDBusSignalInfo **one, GDBusSignalInfo **two) { if (one == NULL || two == NULL) { g_assert (one == NULL && two == NULL); return; } while (*one != NULL && *two != NULL) { assert_equal_signal (*one, *two); one++; two++; } } static void assert_equal_property (GDBusPropertyInfo *one, GDBusPropertyInfo *two) { g_assert (one != NULL); g_assert (two != NULL); g_assert_cmpstr (one->name, ==, two->name); g_assert_cmpstr (one->signature, ==, two->signature); g_assert_cmpuint (one->flags, ==, two->flags); } static void assert_equal_properties (GDBusPropertyInfo **one, GDBusPropertyInfo **two) { if (one == NULL || two == NULL) { g_assert (one == NULL && two == NULL); return; } while (*one != NULL && *two != NULL) { assert_equal_property (*one, *two); one++; two++; } } static void assert_equal_interface (GDBusInterfaceInfo *one, GDBusInterfaceInfo *two) { g_assert (one != NULL); g_assert (two != NULL); g_assert_cmpstr (one->name, ==, two->name); assert_equal_methods (one->methods, two->methods); assert_equal_signals (one->signals, two->signals); assert_equal_properties (one->properties, two->properties); } typedef struct { const gchar *name; const gchar *input; const GDBusInterfaceInfo *iface; } ParseFixture; static const ParseFixture parse_janitor_fixture = { "planet.express.Janitor", janitor_json, &janitor_interface }; static const ParseFixture parse_no_methods_fixture = { "planet.express.NoMethods", no_methods_json, &no_methods_interface }; static const ParseFixture parse_no_signals_fixture = { "planet.express.NoSignals", no_signals_json, &no_signals_interface }; static const ParseFixture parse_no_properties_fixture = { "planet.express.NoProperties", no_properties_json, &no_properties_interface }; static void test_parse (gconstpointer data) { const ParseFixture *fixture = data; GDBusInterfaceInfo *iface; GError *error = NULL; JsonObject *object; object = cockpit_json_parse_object (fixture->input, -1, &error); g_assert_no_error (error); iface = cockpit_dbus_meta_parse (fixture->name, object, &error); g_assert_no_error (error); assert_equal_interface (iface, (GDBusInterfaceInfo *)fixture->iface); g_dbus_interface_info_unref (iface); json_object_unref (object); } typedef struct { const gchar *input; const gchar *message; } ErrorFixture; static const gchar invalid_in_argument_json[] = "{" "\"methods\": {" "\"BrokenMethod\": {" "\"in\": [ true ]" "}" "}" "}"; static const ErrorFixture error_invalid_in_argument = { invalid_in_argument_json, "invalid argument in dbus meta field" }; static const gchar invalid_out_argument_json[] = "{" "\"methods\": {" "\"BrokenMethod\": {" "\"out\": [ true ]" "}" "}" "}"; static const ErrorFixture error_invalid_out_argument = { invalid_out_argument_json, "invalid argument in dbus meta field" }; static const gchar invalid_signal_argument_json[] = "{" "\"signals\": {" "\"BrokenSignal\": {" "\"in\": [ true ]" "}" "}" "}"; static const ErrorFixture error_invalid_signal_argument = { invalid_signal_argument_json, "invalid argument in dbus meta field" }; static const gchar invalid_signature_argument_json[] = "{" "\"methods\": {" "\"BrokenMethod\": {" "\"in\": [\"s\",\"!!!\"]" "}" "}" "}"; static const ErrorFixture error_signature_argument = { invalid_signature_argument_json, "argument in dbus meta field has invalid signature: !!!" }; static const gchar invalid_in_method_json[] = "{" "\"methods\": {" "\"BrokenMethod\": {" "\"in\": true," "\"out\":[\"a{sv}\"]" "}" "}" "}"; static const ErrorFixture error_invalid_in_method = { invalid_in_method_json, "invalid \"in\" field in dbus meta method: BrokenMethod" }; static const gchar invalid_out_method_json[] = "{" "\"methods\": {" "\"BrokenMethod\": {" "\"in\":[\"a{sv}\"]," "\"out\": 5" "}" "}" "}"; static const ErrorFixture error_invalid_out_method = { invalid_out_method_json, "invalid \"out\" field in dbus meta method: BrokenMethod" }; static const gchar invalid_in_signal_json[] = "{" "\"signals\": {" "\"BrokenSignal\": {" "\"in\": { }" "}" "}" "}"; static const ErrorFixture error_in_signal_fixture = { invalid_in_signal_json, "invalid \"in\" field in dbus meta signal: BrokenSignal" }; static const gchar invalid_flags_property_json[] = "{" "\"properties\": {" "\"BrokenProperty\": {" "\"flags\": [ ]," "\"type\": \"s\"" "}" "}" "}"; static const ErrorFixture error_flags_property_fixture = { invalid_flags_property_json, "invalid \"flags\" field in dbus property: BrokenProperty" }; static const gchar invalid_type_property_json[] = "{" "\"properties\": {" "\"BrokenProperty\": {" "\"flags\": \"r\"," "\"type\": 555" "}" "}" "}"; static const ErrorFixture error_type_property_fixture = { invalid_type_property_json, "invalid \"type\" field in dbus property: BrokenProperty" }; static const gchar missing_type_property_json[] = "{" "\"properties\": {" "\"BrokenProperty\": {" "\"flags\": \"r\"" "}" "}" "}"; static const ErrorFixture error_type_missing_fixture = { missing_type_property_json, "missing \"type\" field in dbus property: BrokenProperty" }; static const gchar invalid_signature_property_json[] = "{" "\"properties\": {" "\"BrokenProperty\": {" "\"flags\": \"r\"," "\"type\": \"???\"" "}" "}" "}"; static const ErrorFixture error_signature_property_fixture = { invalid_signature_property_json, "the \"type\" field in dbus property is not a dbus signature: ???" }; static const gchar invalid_methods_json[] = "{" "\"methods\": [ ]" "}"; static const ErrorFixture error_methods_fixture = { invalid_methods_json, "invalid \"methods\" field in dbus meta structure" }; static const gchar invalid_method_json[] = "{" "\"methods\": {" "\"BadMethod\": [ ]" "}" "}"; static const ErrorFixture error_method_json = { invalid_method_json, "invalid method field in dbus meta structure: BadMethod", }; static const gchar invalid_signals_json[] = "{" "\"signals\": 555" "}"; static const ErrorFixture error_signals_json = { invalid_signals_json, "invalid \"signals\" field in dbus meta structure" }; static const gchar invalid_signal_json[] = "{" "\"signals\": {" "\"BadSignal\": true" "}" "}"; static const ErrorFixture error_signal_json = { invalid_signal_json, "invalid signal field in dbus meta structure: BadSignal", }; static const gchar invalid_properties_json[] = "{" "\"properties\": [ ]" "}"; static const ErrorFixture error_properties_json = { invalid_properties_json, "invalid \"properties\" field in dbus meta structure" }; static const gchar invalid_property_json[] = "{" "\"properties\": {" "\"BadProperty\": true" "}" "}"; static const ErrorFixture error_property_json = { invalid_property_json, "invalid property field in dbus meta structure: BadProperty", }; static void test_error (gconstpointer data) { const ErrorFixture *fixture = data; GDBusInterfaceInfo *iface; GError *error = NULL; JsonObject *object; object = cockpit_json_parse_object (fixture->input, -1, &error); g_assert_no_error (error); iface = cockpit_dbus_meta_parse ("name.not.Important", object, &error); g_assert (iface == NULL); g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS); g_assert_cmpstr (error->message, ==, fixture->message); g_error_free (error); json_object_unref (object); } int main (int argc, char *argv[]) { cockpit_test_init (&argc, &argv); g_test_add_data_func ("/dbus-meta/build/basic", &build_janitor_fixture, test_build); g_test_add_data_func ("/dbus-meta/build/no-methods", &build_no_methods_fixture, test_build); g_test_add_data_func ("/dbus-meta/build/no-signals", &build_no_signals_fixture, test_build); g_test_add_data_func ("/dbus-meta/build/no-properties", &build_no_properties_fixture, test_build); g_test_add_data_func ("/dbus-meta/parse/basic", &parse_janitor_fixture, test_parse); g_test_add_data_func ("/dbus-meta/parse/no-methods", &parse_no_methods_fixture, test_parse); g_test_add_data_func ("/dbus-meta/parse/no-signals", &parse_no_signals_fixture, test_parse); g_test_add_data_func ("/dbus-meta/parse/no-properties", &parse_no_properties_fixture, test_parse); g_test_add_data_func ("/dbus-meta/parse/invalid-in-argument", &error_invalid_in_argument, test_error); g_test_add_data_func ("/dbus-meta/parse/invalid-out-argument", &error_invalid_out_argument, test_error); g_test_add_data_func ("/dbus-meta/parse/invalid-signal-argument", &error_invalid_signal_argument, test_error); g_test_add_data_func ("/dbus-meta/parse/invalid-signature-argument", &error_signature_argument, test_error); g_test_add_data_func ("/dbus-meta/parse/invalid-in-arguments", &error_invalid_in_method, test_error); g_test_add_data_func ("/dbus-meta/parse/invalid-out-arguments", &error_invalid_out_method, test_error); g_test_add_data_func ("/dbus-meta/parse/invalid-signal-arguments", &error_in_signal_fixture, test_error); g_test_add_data_func ("/dbus-meta/parse/invalid-property-flags", &error_flags_property_fixture, test_error); g_test_add_data_func ("/dbus-meta/parse/invalid-property-type", &error_type_property_fixture, test_error); g_test_add_data_func ("/dbus-meta/parse/missing-property-type", &error_type_missing_fixture, test_error); g_test_add_data_func ("/dbus-meta/parse/invalid-property-signature", &error_signature_property_fixture, test_error); g_test_add_data_func ("/dbus-meta/parse/invalid-methods", &error_methods_fixture, test_error); g_test_add_data_func ("/dbus-meta/parse/invalid-method", &error_method_json, test_error); g_test_add_data_func ("/dbus-meta/parse/invalid-signals", &error_signals_json, test_error); g_test_add_data_func ("/dbus-meta/parse/invalid-signal", &error_signal_json, test_error); g_test_add_data_func ("/dbus-meta/parse/invalid-properties", &error_properties_json, test_error); g_test_add_data_func ("/dbus-meta/parse/invalid-property", &error_property_json, test_error); return g_test_run (); }