dbus/test/internals/dbus-marshal-validate-util.c

511 lines
15 KiB
C
Raw Permalink Normal View History

/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* dbus-marshal-validate-util.c Would be in dbus-marshal-validate.c, but only used by tests/bus
*
* Copyright (C) 2005 Red Hat, Inc.
*
* SPDX-License-Identifier: AFL-2.1 OR GPL-2.0-or-later
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <config.h>
#include "misc-internals.h"
#ifdef DBUS_ENABLE_EMBEDDED_TESTS
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#include "dbus/dbus-internals.h"
#include "dbus/dbus-marshal-validate.h"
#include "dbus/dbus-marshal-recursive.h"
#include <dbus/dbus-test-tap.h>
#include "dbus/dbus-test.h"
#include "dbus-marshal-recursive-util.h"
#include <stdio.h>
typedef struct
{
const char *data;
DBusValidity expected;
} ValidityTest;
static void
run_validity_tests (const ValidityTest *tests,
int n_tests,
DBusValidity (* func) (const DBusString*,int,int))
{
int i;
for (i = 0; i < n_tests; i++)
{
DBusString str;
DBusValidity v;
_dbus_string_init_const (&str, tests[i].data);
v = (*func) (&str, 0, _dbus_string_get_length (&str));
if (v != tests[i].expected)
_dbus_test_fatal ("Improper validation result %d for '%s'", v, tests[i].data);
}
}
static const ValidityTest signature_tests[] = {
{ "", DBUS_VALID },
{ "sss", DBUS_VALID },
{ "i", DBUS_VALID },
{ "b", DBUS_VALID },
{ "ai", DBUS_VALID },
{ "(i)", DBUS_VALID },
{ "w", DBUS_INVALID_UNKNOWN_TYPECODE },
{ "a", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE },
{ "aaaaaa", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE },
{ "ii(ii)a", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE },
{ "ia", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE },
/* DBUS_INVALID_SIGNATURE_TOO_LONG, */ /* too hard to test this way */
{ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION },
{ "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((ii))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))",
DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION },
{ ")", DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED },
{ "i)", DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED },
{ "a)", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE },
{ "(", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED },
{ "(i", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED },
{ "(iiiii", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED },
{ "(ai", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED },
{ "()", DBUS_INVALID_STRUCT_HAS_NO_FIELDS },
{ "(())", DBUS_INVALID_STRUCT_HAS_NO_FIELDS },
{ "a()", DBUS_INVALID_STRUCT_HAS_NO_FIELDS },
{ "i()", DBUS_INVALID_STRUCT_HAS_NO_FIELDS },
{ "()i", DBUS_INVALID_STRUCT_HAS_NO_FIELDS },
{ "(a)", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE },
{ "a{ia}", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE },
{ "a{}", DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS },
{ "a{aii}", DBUS_INVALID_DICT_KEY_MUST_BE_BASIC_TYPE },
{ " ", DBUS_INVALID_UNKNOWN_TYPECODE },
{ "not a valid signature", DBUS_INVALID_UNKNOWN_TYPECODE },
{ "123", DBUS_INVALID_UNKNOWN_TYPECODE },
{ ".", DBUS_INVALID_UNKNOWN_TYPECODE },
/* https://bugs.freedesktop.org/show_bug.cgi?id=17803 */
{ "a{(ii)i}", DBUS_INVALID_DICT_KEY_MUST_BE_BASIC_TYPE },
{ "a{i}", DBUS_INVALID_DICT_ENTRY_HAS_ONLY_ONE_FIELD },
{ "{is}", DBUS_INVALID_DICT_ENTRY_NOT_INSIDE_ARRAY },
{ "a{isi}", DBUS_INVALID_DICT_ENTRY_HAS_TOO_MANY_FIELDS },
};
dbus_bool_t
_dbus_marshal_validate_test (const char *test_data_dir _DBUS_GNUC_UNUSED)
{
DBusString str;
int i;
const char *valid_paths[] = {
"/",
"/foo/bar",
"/foo",
"/foo/bar/baz"
};
const char *invalid_paths[] = {
"bar",
"bar/baz",
"/foo/bar/",
"/foo/",
"foo/",
"boo//blah",
"//",
"///",
"foo///blah/",
"Hello World",
"",
" ",
"foo bar"
};
const char *valid_interfaces[] = {
"org.freedesktop.Foo",
"Bar.Baz",
"Blah.Blah.Blah.Blah.Blah",
"a.b",
"a.b.c.d.e.f.g",
"a0.b1.c2.d3.e4.f5.g6",
"abc123.foo27"
};
const char *invalid_interfaces[] = {
".",
"",
"..",
".Foo.Bar",
"..Foo.Bar",
"Foo.Bar.",
"Foo.Bar..",
"Foo",
"9foo.bar.baz",
"foo.bar..baz",
"foo.bar...baz",
"foo.bar.b..blah",
":",
":0-1",
"10",
":11.34324",
"0.0.0",
"0..0",
"foo.Bar.%",
"foo.Bar!!",
"!Foo.bar.bz",
"foo.$.blah",
"",
" ",
"foo bar"
};
const char *valid_unique_names[] = {
":0",
":a",
":",
":.a",
":.1",
":0.1",
":000.2222",
":.blah",
":abce.freedesktop.blah"
};
const char *invalid_unique_names[] = {
* glib/dbus-gvalue.c (marshal_variant): call _dbus_gvalue_marshal instead of marshal basic so we can handle recursive types in a variant * test/glib/test-dbus-glib.c: Add test for marshaling recurive types in variants * test/glib/test-service-glib.c, test-service-glib.xml (my_object_echo_variant [EchoVariant], my_object_process_variant_of_array_of_ints123 [ProcessVariantOfArrayOfInts123]): Add two test methods * python/introspect_parser.py: New module for parsing introspect data. * python/dbus_bindings.pyx: (various places): when throwing errors fix to use errormsg instead of message local variable because Pyrex can get confused with other message variables (initial patch by Robert McQueen <robert.mcqueen at collabora.co.uk>) (MessageIter::parse_signature_block): new method for getting the next block in a signiture. (MessageIter::append_strict): new method for appending values strictly using the passed in signature instead of guessing at the type (MessageItter:: append_dict, append_struct, append_array): use signatures to marshal children if the signature is available * python/exceptions.py (IntrospectionParserException): new exception * python/proxies.py (ProxyMethod::__call__): Marshal args with introspected signatures if available, else we fall back to the old way of doing things. (ProxyObject::_introspect_reply_handler ): parse introspection data * python/service.py (ObjectType::_reflect_on_method): Properly terminate <method> if there are no args in the reflection data * test/python/test-client.py: add tests for talking with the GLib test server. This gives us better coverage for introspection since python to python will always generate arguments as variants. It also allows us to test the robustness of the GLib bindings and interlanguage communications.
2005-10-05 20:43:46 +00:00
//":-",
":!",
* glib/dbus-gvalue.c (marshal_variant): call _dbus_gvalue_marshal instead of marshal basic so we can handle recursive types in a variant * test/glib/test-dbus-glib.c: Add test for marshaling recurive types in variants * test/glib/test-service-glib.c, test-service-glib.xml (my_object_echo_variant [EchoVariant], my_object_process_variant_of_array_of_ints123 [ProcessVariantOfArrayOfInts123]): Add two test methods * python/introspect_parser.py: New module for parsing introspect data. * python/dbus_bindings.pyx: (various places): when throwing errors fix to use errormsg instead of message local variable because Pyrex can get confused with other message variables (initial patch by Robert McQueen <robert.mcqueen at collabora.co.uk>) (MessageIter::parse_signature_block): new method for getting the next block in a signiture. (MessageIter::append_strict): new method for appending values strictly using the passed in signature instead of guessing at the type (MessageItter:: append_dict, append_struct, append_array): use signatures to marshal children if the signature is available * python/exceptions.py (IntrospectionParserException): new exception * python/proxies.py (ProxyMethod::__call__): Marshal args with introspected signatures if available, else we fall back to the old way of doing things. (ProxyObject::_introspect_reply_handler ): parse introspection data * python/service.py (ObjectType::_reflect_on_method): Properly terminate <method> if there are no args in the reflection data * test/python/test-client.py: add tests for talking with the GLib test server. This gives us better coverage for introspection since python to python will always generate arguments as variants. It also allows us to test the robustness of the GLib bindings and interlanguage communications.
2005-10-05 20:43:46 +00:00
//":0-10",
":blah.",
":blah.",
":blah..org",
":blah.org..",
":..blah.org",
"",
" ",
"foo bar"
};
const char *valid_members[] = {
"Hello",
"Bar",
"foobar",
"_foobar",
"foo89"
};
const char *invalid_members[] = {
"9Hello",
"10",
"1",
"foo-bar",
"blah.org",
".blah",
"blah.",
"Hello.",
"!foo",
"",
" ",
"foo bar"
};
/* Signature with reason */
run_validity_tests (signature_tests, _DBUS_N_ELEMENTS (signature_tests),
_dbus_validate_signature_with_reason);
/* Path validation */
i = 0;
while (i < (int) _DBUS_N_ELEMENTS (valid_paths))
{
_dbus_string_init_const (&str, valid_paths[i]);
if (!_dbus_validate_path (&str, 0,
_dbus_string_get_length (&str)))
_dbus_test_fatal ("Path \"%s\" should have been valid", valid_paths[i]);
++i;
}
i = 0;
while (i < (int) _DBUS_N_ELEMENTS (invalid_paths))
{
_dbus_string_init_const (&str, invalid_paths[i]);
if (_dbus_validate_path (&str, 0,
_dbus_string_get_length (&str)))
_dbus_test_fatal ("Path \"%s\" should have been invalid", invalid_paths[i]);
++i;
}
/* Interface validation */
i = 0;
while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces))
{
_dbus_string_init_const (&str, valid_interfaces[i]);
if (!_dbus_validate_interface (&str, 0,
_dbus_string_get_length (&str)))
_dbus_test_fatal ("Interface \"%s\" should have been valid", valid_interfaces[i]);
++i;
}
i = 0;
while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces))
{
_dbus_string_init_const (&str, invalid_interfaces[i]);
if (_dbus_validate_interface (&str, 0,
_dbus_string_get_length (&str)))
_dbus_test_fatal ("Interface \"%s\" should have been invalid", invalid_interfaces[i]);
++i;
}
/* Bus name validation (check that valid interfaces are valid bus names,
* and invalid interfaces are invalid services except if they start with ':')
*/
i = 0;
while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces))
{
_dbus_string_init_const (&str, valid_interfaces[i]);
if (!_dbus_validate_bus_name (&str, 0,
_dbus_string_get_length (&str)))
_dbus_test_fatal ("Bus name \"%s\" should have been valid", valid_interfaces[i]);
++i;
}
i = 0;
while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces))
{
if (invalid_interfaces[i][0] != ':')
{
_dbus_string_init_const (&str, invalid_interfaces[i]);
if (_dbus_validate_bus_name (&str, 0,
_dbus_string_get_length (&str)))
_dbus_test_fatal ("Bus name \"%s\" should have been invalid", invalid_interfaces[i]);
}
++i;
}
/* unique name validation */
i = 0;
while (i < (int) _DBUS_N_ELEMENTS (valid_unique_names))
{
_dbus_string_init_const (&str, valid_unique_names[i]);
if (!_dbus_validate_bus_name (&str, 0,
_dbus_string_get_length (&str)))
_dbus_test_fatal ("Bus name \"%s\" should have been valid", valid_unique_names[i]);
++i;
}
i = 0;
while (i < (int) _DBUS_N_ELEMENTS (invalid_unique_names))
{
_dbus_string_init_const (&str, invalid_unique_names[i]);
if (_dbus_validate_bus_name (&str, 0,
_dbus_string_get_length (&str)))
_dbus_test_fatal ("Bus name \"%s\" should have been invalid", invalid_unique_names[i]);
++i;
}
/* Error name validation (currently identical to interfaces)
*/
i = 0;
while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces))
{
_dbus_string_init_const (&str, valid_interfaces[i]);
if (!_dbus_validate_error_name (&str, 0,
_dbus_string_get_length (&str)))
_dbus_test_fatal ("Error name \"%s\" should have been valid", valid_interfaces[i]);
++i;
}
i = 0;
while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces))
{
if (invalid_interfaces[i][0] != ':')
{
_dbus_string_init_const (&str, invalid_interfaces[i]);
if (_dbus_validate_error_name (&str, 0,
_dbus_string_get_length (&str)))
_dbus_test_fatal ("Error name \"%s\" should have been invalid", invalid_interfaces[i]);
}
++i;
}
/* Member validation */
i = 0;
while (i < (int) _DBUS_N_ELEMENTS (valid_members))
{
_dbus_string_init_const (&str, valid_members[i]);
if (!_dbus_validate_member (&str, 0,
_dbus_string_get_length (&str)))
_dbus_test_fatal ("Member \"%s\" should have been valid", valid_members[i]);
++i;
}
i = 0;
while (i < (int) _DBUS_N_ELEMENTS (invalid_members))
{
_dbus_string_init_const (&str, invalid_members[i]);
if (_dbus_validate_member (&str, 0,
_dbus_string_get_length (&str)))
_dbus_test_fatal ("Member \"%s\" should have been invalid", invalid_members[i]);
++i;
}
/* Validate claimed length longer than real length */
_dbus_string_init_const (&str, "abc.efg");
if (_dbus_validate_bus_name (&str, 0, 8))
_dbus_test_fatal ("validated too-long string");
if (_dbus_validate_interface (&str, 0, 8))
_dbus_test_fatal ("validated too-long string");
if (_dbus_validate_error_name (&str, 0, 8))
_dbus_test_fatal ("validated too-long string");
_dbus_string_init_const (&str, "abc");
if (_dbus_validate_member (&str, 0, 4))
_dbus_test_fatal ("validated too-long string");
/* Validate string exceeding max name length */
if (!_dbus_string_init (&str))
_dbus_test_fatal ("no memory");
while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH)
if (!_dbus_string_append (&str, "abc.def"))
_dbus_test_fatal ("no memory");
if (_dbus_validate_bus_name (&str, 0, _dbus_string_get_length (&str)))
_dbus_test_fatal ("validated overmax string");
if (_dbus_validate_interface (&str, 0, _dbus_string_get_length (&str)))
_dbus_test_fatal ("validated overmax string");
if (_dbus_validate_error_name (&str, 0, _dbus_string_get_length (&str)))
_dbus_test_fatal ("validated overmax string");
/* overlong member */
_dbus_string_set_length (&str, 0);
while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH)
if (!_dbus_string_append (&str, "abc"))
_dbus_test_fatal ("no memory");
if (_dbus_validate_member (&str, 0, _dbus_string_get_length (&str)))
_dbus_test_fatal ("validated overmax string");
/* overlong unique name */
_dbus_string_set_length (&str, 0);
_dbus_string_append (&str, ":");
while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH)
if (!_dbus_string_append (&str, "abc"))
_dbus_test_fatal ("no memory");
if (_dbus_validate_bus_name (&str, 0, _dbus_string_get_length (&str)))
_dbus_test_fatal ("validated overmax string");
_dbus_string_free (&str);
/* Body validation; test basic validation of valid bodies for both endian */
{
int sequence;
DBusString signature;
DBusString body;
if (!_dbus_string_init (&signature) || !_dbus_string_init (&body))
_dbus_test_fatal ("oom");
sequence = 0;
while (_dbus_test_generate_bodies (sequence, DBUS_LITTLE_ENDIAN,
&signature, &body))
{
DBusValidity validity;
validity = _dbus_validate_body_with_reason (&signature, 0,
DBUS_LITTLE_ENDIAN,
NULL, &body, 0,
_dbus_string_get_length (&body));
if (validity != DBUS_VALID)
{
_dbus_warn ("invalid code %d expected valid on sequence %d little endian",
validity, sequence);
_dbus_verbose_bytes_of_string (&signature, 0, _dbus_string_get_length (&signature));
_dbus_verbose_bytes_of_string (&body, 0, _dbus_string_get_length (&body));
_dbus_test_fatal ("test failed");
}
_dbus_string_set_length (&signature, 0);
_dbus_string_set_length (&body, 0);
++sequence;
}
sequence = 0;
while (_dbus_test_generate_bodies (sequence, DBUS_BIG_ENDIAN,
&signature, &body))
{
DBusValidity validity;
validity = _dbus_validate_body_with_reason (&signature, 0,
DBUS_BIG_ENDIAN,
NULL, &body, 0,
_dbus_string_get_length (&body));
if (validity != DBUS_VALID)
{
_dbus_warn ("invalid code %d expected valid on sequence %d big endian",
validity, sequence);
_dbus_verbose_bytes_of_string (&signature, 0, _dbus_string_get_length (&signature));
_dbus_verbose_bytes_of_string (&body, 0, _dbus_string_get_length (&body));
_dbus_test_fatal ("test failed");
}
_dbus_string_set_length (&signature, 0);
_dbus_string_set_length (&body, 0);
++sequence;
}
_dbus_string_free (&signature);
_dbus_string_free (&body);
}
return TRUE;
}
#endif /* !DOXYGEN_SHOULD_SKIP_THIS */
#endif /* DBUS_ENABLE_EMBEDDED_TESTS */