summaryrefslogtreecommitdiff
path: root/gobject
diff options
context:
space:
mode:
Diffstat (limited to 'gobject')
-rw-r--r--gobject/gbinding.c95
-rw-r--r--gobject/gboxed.c6
-rw-r--r--gobject/gobject.c127
-rw-r--r--gobject/gobject.h19
-rw-r--r--gobject/gobject_trace.h4
-rw-r--r--gobject/gparam.c81
-rw-r--r--gobject/gparam.h2
-rw-r--r--gobject/gparamspecs.c17
-rw-r--r--gobject/gparamspecs.h2
-rw-r--r--gobject/gsignal.c199
-rw-r--r--gobject/gsignal.h4
-rw-r--r--gobject/gtype-private.h4
-rw-r--r--gobject/gtype.c4
-rw-r--r--gobject/gtype.h22
-rw-r--r--gobject/gvalue.c4
-rw-r--r--gobject/tests/autoptr.c30
-rw-r--r--gobject/tests/binding.c152
-rw-r--r--gobject/tests/meson.build1
-rw-r--r--gobject/tests/param.c97
-rw-r--r--gobject/tests/reference.c30
-rw-r--r--gobject/tests/signals.c213
-rw-r--r--gobject/tests/testing.c71
22 files changed, 949 insertions, 235 deletions
diff --git a/gobject/gbinding.c b/gobject/gbinding.c
index 16942c221..12475bcdd 100644
--- a/gobject/gbinding.c
+++ b/gobject/gbinding.c
@@ -423,6 +423,53 @@ g_binding_finalize (GObject *gobject)
G_OBJECT_CLASS (g_binding_parent_class)->finalize (gobject);
}
+/* @key must have already been validated with is_valid()
+ * Modifies @key in place. */
+static void
+canonicalize_key (gchar *key)
+{
+ gchar *p;
+
+ for (p = key; *p != 0; p++)
+ {
+ gchar c = *p;
+
+ if (c == '_')
+ *p = '-';
+ }
+}
+
+/* @key must have already been validated with is_valid() */
+static gboolean
+is_canonical (const gchar *key)
+{
+ return (strchr (key, '_') == NULL);
+}
+
+static gboolean
+is_valid_property_name (const gchar *key)
+{
+ const gchar *p;
+
+ /* First character must be a letter. */
+ if ((key[0] < 'A' || key[0] > 'Z') &&
+ (key[0] < 'a' || key[0] > 'z'))
+ return FALSE;
+
+ for (p = key; *p != 0; p++)
+ {
+ const gchar c = *p;
+
+ if (c != '-' && c != '_' &&
+ (c < '0' || c > '9') &&
+ (c < 'A' || c > 'Z') &&
+ (c < 'a' || c > 'z'))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static void
g_binding_set_property (GObject *gobject,
guint prop_id,
@@ -437,17 +484,35 @@ g_binding_set_property (GObject *gobject,
binding->source = g_value_get_object (value);
break;
- case PROP_SOURCE_PROPERTY:
- binding->source_property = g_intern_string (g_value_get_string (value));
- break;
-
case PROP_TARGET:
binding->target = g_value_get_object (value);
break;
+ case PROP_SOURCE_PROPERTY:
case PROP_TARGET_PROPERTY:
- binding->target_property = g_intern_string (g_value_get_string (value));
- break;
+ {
+ gchar *name_copy = NULL;
+ const gchar *name = g_value_get_string (value);
+ const gchar **dest;
+
+ /* Ensure the name we intern is canonical. */
+ if (!is_canonical (name))
+ {
+ name_copy = g_value_dup_string (value);
+ canonicalize_key (name_copy);
+ name = name_copy;
+ }
+
+ if (prop_id == PROP_SOURCE_PROPERTY)
+ dest = &binding->source_property;
+ else
+ dest = &binding->target_property;
+
+ *dest = g_intern_string (name);
+
+ g_free (name_copy);
+ break;
+ }
case PROP_FLAGS:
binding->flags = g_value_get_flags (value);
@@ -474,7 +539,8 @@ g_binding_get_property (GObject *gobject,
break;
case PROP_SOURCE_PROPERTY:
- g_value_set_string (value, binding->source_property);
+ /* @source_property is interned, so we don’t need to take a copy */
+ g_value_set_static_string (value, binding->source_property);
break;
case PROP_TARGET:
@@ -482,7 +548,8 @@ g_binding_get_property (GObject *gobject,
break;
case PROP_TARGET_PROPERTY:
- g_value_set_string (value, binding->target_property);
+ /* @target_property is interned, so we don’t need to take a copy */
+ g_value_set_static_string (value, binding->target_property);
break;
case PROP_FLAGS:
@@ -606,7 +673,10 @@ g_binding_class_init (GBindingClass *klass)
* GBinding:source-property:
*
* The name of the property of #GBinding:source that should be used
- * as the source of the binding
+ * as the source of the binding.
+ *
+ * This should be in [canonical form][canonical-parameter-names] to get the
+ * best performance.
*
* Since: 2.26
*/
@@ -622,7 +692,10 @@ g_binding_class_init (GBindingClass *klass)
* GBinding:target-property:
*
* The name of the property of #GBinding:target that should be used
- * as the target of the binding
+ * as the target of the binding.
+ *
+ * This should be in [canonical form][canonical-parameter-names] to get the
+ * best performance.
*
* Since: 2.26
*/
@@ -835,8 +908,10 @@ g_object_bind_property_full (gpointer source,
g_return_val_if_fail (G_IS_OBJECT (source), NULL);
g_return_val_if_fail (source_property != NULL, NULL);
+ g_return_val_if_fail (is_valid_property_name (source_property), NULL);
g_return_val_if_fail (G_IS_OBJECT (target), NULL);
g_return_val_if_fail (target_property != NULL, NULL);
+ g_return_val_if_fail (is_valid_property_name (target_property), NULL);
if (source == target && g_strcmp0 (source_property, target_property) == 0)
{
diff --git a/gobject/gboxed.c b/gobject/gboxed.c
index 4404de3d6..87cc5d2c2 100644
--- a/gobject/gboxed.c
+++ b/gobject/gboxed.c
@@ -346,8 +346,7 @@ g_boxed_copy (GType boxed_type,
g_return_val_if_fail (src_boxed != NULL, NULL);
value_table = g_type_value_table_peek (boxed_type);
- if (!value_table)
- g_return_val_if_fail (G_TYPE_IS_VALUE_TYPE (boxed_type), NULL);
+ g_assert (value_table != NULL);
/* check if our proxying implementation is used, we can short-cut here */
if (value_table->value_copy == boxed_proxy_value_copy)
@@ -404,8 +403,7 @@ g_boxed_free (GType boxed_type,
g_return_if_fail (boxed != NULL);
value_table = g_type_value_table_peek (boxed_type);
- if (!value_table)
- g_return_if_fail (G_TYPE_IS_VALUE_TYPE (boxed_type));
+ g_assert (value_table != NULL);
/* check if our proxying implementation is used, we can short-cut here */
if (value_table->value_free == boxed_proxy_value_free)
diff --git a/gobject/gobject.c b/gobject/gobject.c
index df27c36f7..07752cf25 100644
--- a/gobject/gobject.c
+++ b/gobject/gobject.c
@@ -162,6 +162,29 @@ enum {
PROP_NONE
};
+#define OPTIONAL_FLAG_IN_CONSTRUCTION 1<<0
+#define OPTIONAL_FLAG_HAS_SIGNAL_HANDLER 1<<1 /* Set if object ever had a signal handler */
+
+#if SIZEOF_INT == 4 && GLIB_SIZEOF_VOID_P == 8
+#define HAVE_OPTIONAL_FLAGS
+#endif
+
+typedef struct
+{
+ GTypeInstance g_type_instance;
+
+ /*< private >*/
+ volatile guint ref_count;
+#ifdef HAVE_OPTIONAL_FLAGS
+ volatile guint optional_flags;
+#endif
+ GData *qdata;
+} GObjectReal;
+
+G_STATIC_ASSERT(sizeof(GObject) == sizeof(GObjectReal));
+G_STATIC_ASSERT(G_STRUCT_OFFSET(GObject, ref_count) == G_STRUCT_OFFSET(GObjectReal, ref_count));
+G_STATIC_ASSERT(G_STRUCT_OFFSET(GObject, qdata) == G_STRUCT_OFFSET(GObjectReal, qdata));
+
/* --- prototypes --- */
static void g_object_base_class_init (GObjectClass *class);
@@ -1008,10 +1031,83 @@ g_object_interface_list_properties (gpointer g_iface,
return pspecs;
}
+static inline guint
+object_get_optional_flags (GObject *object)
+{
+#ifdef HAVE_OPTIONAL_FLAGS
+ GObjectReal *real = (GObjectReal *)object;
+ return (guint)g_atomic_int_get (&real->optional_flags);
+#else
+ return 0;
+#endif
+}
+
+static inline void
+object_set_optional_flags (GObject *object,
+ guint flags)
+{
+#ifdef HAVE_OPTIONAL_FLAGS
+ GObjectReal *real = (GObjectReal *)object;
+ g_atomic_int_or (&real->optional_flags, flags);
+#endif
+}
+
+static inline void
+object_unset_optional_flags (GObject *object,
+ guint flags)
+{
+#ifdef HAVE_OPTIONAL_FLAGS
+ GObjectReal *real = (GObjectReal *)object;
+ g_atomic_int_and (&real->optional_flags, ~flags);
+#endif
+}
+
+gboolean
+_g_object_has_signal_handler (GObject *object)
+{
+#ifdef HAVE_OPTIONAL_FLAGS
+ return (object_get_optional_flags (object) & OPTIONAL_FLAG_HAS_SIGNAL_HANDLER) != 0;
+#else
+ return TRUE;
+#endif
+}
+
+void
+_g_object_set_has_signal_handler (GObject *object)
+{
+#ifdef HAVE_OPTIONAL_FLAGS
+ object_set_optional_flags (object, OPTIONAL_FLAG_HAS_SIGNAL_HANDLER);
+#endif
+}
+
static inline gboolean
object_in_construction (GObject *object)
{
+#ifdef HAVE_OPTIONAL_FLAGS
+ return (object_get_optional_flags (object) & OPTIONAL_FLAG_IN_CONSTRUCTION) != 0;
+#else
return g_datalist_id_get_data (&object->qdata, quark_in_construction) != NULL;
+#endif
+}
+
+static inline void
+set_object_in_construction (GObject *object)
+{
+#ifdef HAVE_OPTIONAL_FLAGS
+ object_set_optional_flags (object, OPTIONAL_FLAG_IN_CONSTRUCTION);
+#else
+ g_datalist_id_set_data (&object->qdata, quark_in_construction, object);
+#endif
+}
+
+static inline void
+unset_object_in_construction (GObject *object)
+{
+#ifdef HAVE_OPTIONAL_FLAGS
+ object_unset_optional_flags (object, OPTIONAL_FLAG_IN_CONSTRUCTION);
+#else
+ g_datalist_id_set_data (&object->qdata, quark_in_construction, NULL);
+#endif
}
static void
@@ -1030,7 +1126,7 @@ g_object_init (GObject *object,
if (CLASS_HAS_CUSTOM_CONSTRUCTOR (class))
{
/* mark object in-construction for notify_queue_thaw() and to allow construct-only properties */
- g_datalist_id_set_data (&object->qdata, quark_in_construction, object);
+ set_object_in_construction (object);
}
GOBJECT_IF_DEBUG (OBJECTS,
@@ -1521,7 +1617,7 @@ object_interface_check_properties (gpointer check_data,
/* We do a number of checks on the properties of an interface to
* make sure that all classes implementing the interface are
- * overriding the properties in a sane way.
+ * overriding the properties correctly.
*
* We do the checks in order of importance so that we can give
* more useful error messages first.
@@ -1651,6 +1747,20 @@ g_object_get_type (void)
* Construction parameters (see #G_PARAM_CONSTRUCT, #G_PARAM_CONSTRUCT_ONLY)
* which are not explicitly specified are set to their default values.
*
+ * Note that in C, small integer types in variable argument lists are promoted
+ * up to #gint or #guint as appropriate, and read back accordingly. #gint is 32
+ * bits on every platform on which GLib is currently supported. This means that
+ * you can use C expressions of type #gint with g_object_new() and properties of
+ * type #gint or #guint or smaller. Specifically, you can use integer literals
+ * with these property types.
+ *
+ * When using property types of #gint64 or #guint64, you must ensure that the
+ * value that you provide is 64 bit. This means that you should use a cast or
+ * make use of the %G_GINT64_CONSTANT or %G_GUINT64_CONSTANT macros.
+ *
+ * Similarly, #gfloat is promoted to #gdouble, so you must ensure that the value
+ * you provide is a #gdouble, even for a property of type #gfloat.
+ *
* Returns: (transfer full) (type GObject.Object): a new instance of
* @object_type
*/
@@ -1766,7 +1876,7 @@ g_object_new_with_custom_constructor (GObjectClass *class,
*/
newly_constructed = object_in_construction (object);
if (newly_constructed)
- g_datalist_id_set_data (&object->qdata, quark_in_construction, NULL);
+ unset_object_in_construction (object);
if (CLASS_HAS_PROPS (class))
{
@@ -2479,6 +2589,11 @@ g_object_get_valist (GObject *object,
*
* Sets properties on an object.
*
+ * The same caveats about passing integer literals as varargs apply as with
+ * g_object_new(). In particular, any integer literals set as the values for
+ * properties of type #gint64 or #guint64 must be 64 bits wide, using the
+ * %G_GINT64_CONSTANT or %G_GUINT64_CONSTANT macros.
+ *
* Note that the "notify" signals are queued and only emitted (in
* reverse order) after all properties have been set. See
* g_object_freeze_notify().
@@ -2515,20 +2630,22 @@ g_object_set (gpointer _object,
* of three properties: an integer, a string and an object:
* |[<!-- language="C" -->
* gint intval;
+ * guint64 uint64val;
* gchar *strval;
* GObject *objval;
*
* g_object_get (my_object,
* "int-property", &intval,
+ * "uint64-property", &uint64val,
* "str-property", &strval,
* "obj-property", &objval,
* NULL);
*
- * // Do something with intval, strval, objval
+ * // Do something with intval, uint64val, strval, objval
*
* g_free (strval);
* g_object_unref (objval);
- * ]|
+ * ]|
*/
void
g_object_get (gpointer _object,
diff --git a/gobject/gobject.h b/gobject/gobject.h
index 91b9f6328..2e07fa724 100644
--- a/gobject/gobject.h
+++ b/gobject/gobject.h
@@ -738,12 +738,31 @@ static inline gboolean
return TRUE;
}
+/* We need GCC for __extension__, which we need to sort out strict aliasing of @object_ptr */
+#if defined(__GNUC__)
+
+#define g_set_object(object_ptr, new_object) \
+ (G_GNUC_EXTENSION ({ \
+ G_STATIC_ASSERT (sizeof *(object_ptr) == sizeof (new_object)); \
+ /* Only one access, please; work around type aliasing */ \
+ union { char *in; GObject **out; } _object_ptr; \
+ _object_ptr.in = (char *) (object_ptr); \
+ /* Check types match */ \
+ (void) (0 ? *(object_ptr) = (new_object), FALSE : FALSE); \
+ (g_set_object) (_object_ptr.out, (GObject *) new_object); \
+ })) \
+ GLIB_AVAILABLE_MACRO_IN_2_44
+
+#else /* if !defined(__GNUC__) */
+
#define g_set_object(object_ptr, new_object) \
(/* Check types match. */ \
0 ? *(object_ptr) = (new_object), FALSE : \
(g_set_object) ((GObject **) (object_ptr), (GObject *) (new_object)) \
)
+#endif /* !defined(__GNUC__) */
+
/**
* g_assert_finalize_object: (skip)
* @object: (transfer full) (type GObject.Object): an object
diff --git a/gobject/gobject_trace.h b/gobject/gobject_trace.h
index 30ef2fb5b..261fdac07 100644
--- a/gobject/gobject_trace.h
+++ b/gobject/gobject_trace.h
@@ -25,7 +25,9 @@
#error "config.h must be included prior to gobject_trace.h"
#endif
-#ifdef HAVE_DTRACE
+/* Ignore probes when doing static analysis, as they do weird things which
+ * confuses the analyser. */
+#if defined(HAVE_DTRACE) && !defined(__clang_analyzer__)
/* include the generated probes header and put markers in code */
#include "gobject_probes.h"
diff --git a/gobject/gparam.c b/gobject/gparam.c
index 5aa54c02c..b336125e4 100644
--- a/gobject/gparam.c
+++ b/gobject/gparam.c
@@ -41,11 +41,14 @@
*
* ## Parameter names # {#canonical-parameter-names}
*
- * Parameter names need to start with a letter (a-z or A-Z).
- * Subsequent characters can be letters, numbers or a '-'.
- * All other characters are replaced by a '-' during construction.
- * The result of this replacement is called the canonical name of
- * the parameter.
+ * A property name consists of segments consisting of ASCII letters and
+ * digits, separated by either the `-` or `_` character. The first
+ * character of a property name must be a letter. These are the same rules as
+ * for signal naming (see g_signal_new()).
+ *
+ * When creating and looking up a #GParamSpec, either separator can be
+ * used, but they cannot be mixed. Using `-` is considerably more
+ * efficient, and is the ‘canonical form’. Using `_` is discouraged.
*/
@@ -355,6 +358,8 @@ g_param_spec_get_blurb (GParamSpec *pspec)
return NULL;
}
+/* @key must have already been validated with is_valid()
+ * Modifies @key in place. */
static void
canonicalize_key (gchar *key)
{
@@ -364,28 +369,37 @@ canonicalize_key (gchar *key)
{
gchar c = *p;
- if (c != '-' &&
- (c < '0' || c > '9') &&
- (c < 'A' || c > 'Z') &&
- (c < 'a' || c > 'z'))
- *p = '-';
+ if (c == '_')
+ *p = '-';
}
}
+/* @key must have already been validated with is_valid() */
static gboolean
is_canonical (const gchar *key)
{
+ return (strchr (key, '_') == NULL);
+}
+
+static gboolean
+is_valid_property_name (const gchar *key)
+{
const gchar *p;
+ /* First character must be a letter. */
+ if ((key[0] < 'A' || key[0] > 'Z') &&
+ (key[0] < 'a' || key[0] > 'z'))
+ return FALSE;
+
for (p = key; *p != 0; p++)
{
- gchar c = *p;
+ const gchar c = *p;
- if (c != '-' &&
- (c < '0' || c > '9') &&
- (c < 'A' || c > 'Z') &&
- (c < 'a' || c > 'z'))
- return FALSE;
+ if (c != '-' && c != '_' &&
+ (c < '0' || c > '9') &&
+ (c < 'A' || c > 'Z') &&
+ (c < 'a' || c > 'z'))
+ return FALSE;
}
return TRUE;
@@ -401,15 +415,9 @@ is_canonical (const gchar *key)
*
* Creates a new #GParamSpec instance.
*
- * A property name consists of segments consisting of ASCII letters and
- * digits, separated by either the '-' or '_' character. The first
- * character of a property name must be a letter. Names which violate these
- * rules lead to undefined behaviour.
- *
- * When creating and looking up a #GParamSpec, either separator can be
- * used, but they cannot be mixed. Using '-' is considerably more
- * efficient and in fact required when using property names as detail
- * strings for signals.
+ * See [canonical parameter names][canonical-parameter-names] for details of
+ * the rules for @name. Names which violate these rules lead to undefined
+ * behaviour.
*
* Beyond the name, #GParamSpecs have two more descriptive
* strings associated with them, the @nick, which should be suitable
@@ -431,7 +439,7 @@ g_param_spec_internal (GType param_type,
g_return_val_if_fail (G_TYPE_IS_PARAM (param_type) && param_type != G_TYPE_PARAM, NULL);
g_return_val_if_fail (name != NULL, NULL);
- g_return_val_if_fail ((name[0] >= 'A' && name[0] <= 'Z') || (name[0] >= 'a' && name[0] <= 'z'), NULL);
+ g_return_val_if_fail (is_valid_property_name (name), NULL);
g_return_val_if_fail (!(flags & G_PARAM_STATIC_NAME) || is_canonical (name), NULL);
pspec = (gpointer) g_type_create_instance (param_type);
@@ -595,7 +603,8 @@ g_param_spec_get_redirect_target (GParamSpec *pspec)
/**
* g_param_value_set_default:
* @pspec: a valid #GParamSpec
- * @value: a #GValue of correct type for @pspec
+ * @value: a #GValue of correct type for @pspec; since 2.64, you
+ * can also pass an empty #GValue, initialized with %G_VALUE_INIT
*
* Sets @value to its default value as specified in @pspec.
*/
@@ -604,10 +613,18 @@ g_param_value_set_default (GParamSpec *pspec,
GValue *value)
{
g_return_if_fail (G_IS_PARAM_SPEC (pspec));
- g_return_if_fail (G_IS_VALUE (value));
- g_return_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value));
- g_value_reset (value);
+ if (G_VALUE_TYPE (value) == G_TYPE_INVALID)
+ {
+ g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+ }
+ else
+ {
+ g_return_if_fail (G_IS_VALUE (value));
+ g_return_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value));
+ g_value_reset (value);
+ }
+
G_PARAM_SPEC_GET_CLASS (pspec)->value_set_default (pspec, value);
}
@@ -621,8 +638,8 @@ g_param_value_set_default (GParamSpec *pspec,
* Returns: whether @value contains the canonical default for this @pspec
*/
gboolean
-g_param_value_defaults (GParamSpec *pspec,
- GValue *value)
+g_param_value_defaults (GParamSpec *pspec,
+ const GValue *value)
{
GValue dflt_value = G_VALUE_INIT;
gboolean defaults;
diff --git a/gobject/gparam.h b/gobject/gparam.h
index 33f95f0c5..b6a554653 100644
--- a/gobject/gparam.h
+++ b/gobject/gparam.h
@@ -307,7 +307,7 @@ void g_param_value_set_default (GParamSpec *pspec,
GValue *value);
GLIB_AVAILABLE_IN_ALL
gboolean g_param_value_defaults (GParamSpec *pspec,
- GValue *value);
+ const GValue *value);
GLIB_AVAILABLE_IN_ALL
gboolean g_param_value_validate (GParamSpec *pspec,
GValue *value);
diff --git a/gobject/gparamspecs.c b/gobject/gparamspecs.c
index 5d15c26e1..c45ebc548 100644
--- a/gobject/gparamspecs.c
+++ b/gobject/gparamspecs.c
@@ -912,8 +912,11 @@ param_value_array_validate (GParamSpec *pspec,
g_param_value_set_default (element_spec, element);
changed++;
}
- /* validate array value against element_spec */
- changed += g_param_value_validate (element_spec, element);
+ else
+ {
+ /* validate array value against element_spec */
+ changed += g_param_value_validate (element_spec, element);
+ }
}
}
}
@@ -2092,7 +2095,10 @@ g_param_spec_enum (const gchar *name,
blurb,
flags);
if (espec == NULL)
- return NULL;
+ {
+ g_type_class_unref (enum_class);
+ return NULL;
+ }
espec->enum_class = enum_class;
espec->default_value = default_value;
@@ -2140,7 +2146,10 @@ g_param_spec_flags (const gchar *name,
blurb,
flags);
if (fspec == NULL)
- return NULL;
+ {
+ g_type_class_unref (flags_class);
+ return NULL;
+ }
fspec->flags_class = flags_class;
fspec->default_value = default_value;
diff --git a/gobject/gparamspecs.h b/gobject/gparamspecs.h
index 0309f9bb3..d0e4d5953 100644
--- a/gobject/gparamspecs.h
+++ b/gobject/gparamspecs.h
@@ -1150,7 +1150,7 @@ GParamSpec* g_param_spec_variant (const gchar *name,
# else /* !GOBJECT_STATIC_COMPILATION */
# ifdef GOBJECT_COMPILATION
# ifdef DLL_EXPORT
-# define GOBJECT_VAR __declspec(dllexport)
+# define GOBJECT_VAR extern __declspec(dllexport)
# else /* !DLL_EXPORT */
# define GOBJECT_VAR extern
# endif /* !DLL_EXPORT */
diff --git a/gobject/gsignal.c b/gobject/gsignal.c
index 77d8f211e..45effa92d 100644
--- a/gobject/gsignal.c
+++ b/gobject/gsignal.c
@@ -98,6 +98,10 @@
* detail part of the signal specification upon connection) serves as a
* wildcard and matches any detail argument passed in to emission.
*
+ * While the @detail argument is typically used to pass an object property name
+ * (as with #GObject::notify), no specific format is mandated for the detail
+ * string, other than that it must be non-empty.
+ *
* ## Memory management of signal handlers # {#signal-memory-management}
*
* If you are connecting handlers to signals and using a #GObject instance as
@@ -145,8 +149,8 @@ typedef enum
/* --- prototypes --- */
-static inline guint signal_id_lookup (GQuark quark,
- GType itype);
+static inline guint signal_id_lookup (const gchar *name,
+ GType itype);
static void signal_destroy_R (SignalNode *signal_node);
static inline HandlerList* handler_list_ensure (guint signal_id,
gpointer instance);
@@ -340,14 +344,68 @@ LOOKUP_SIGNAL_NODE (guint signal_id)
/* --- functions --- */
+/* @key must have already been validated with is_valid()
+ * Modifies @key in place. */
+static void
+canonicalize_key (gchar *key)
+{
+ gchar *p;
+
+ for (p = key; *p != 0; p++)
+ {
+ gchar c = *p;
+
+ if (c == '_')
+ *p = '-';
+ }
+}
+
+/* @key must have already been validated with is_valid() */
+static gboolean
+is_canonical (const gchar *key)
+{
+ return (strchr (key, '_') == NULL);
+}
+
+static gboolean
+is_valid_signal_name (const gchar *key)
+{
+ const gchar *p;
+
+ /* FIXME: We allow this, against our own documentation (the leading `-` is
+ * invalid), because GTK has historically used this. */
+ if (g_str_equal (key, "-gtk-private-changed"))
+ return TRUE;
+
+ /* First character must be a letter. */
+ if ((key[0] < 'A' || key[0] > 'Z') &&
+ (key[0] < 'a' || key[0] > 'z'))
+ return FALSE;
+
+ for (p = key; *p != 0; p++)
+ {
+ const gchar c = *p;
+
+ if (c != '-' && c != '_' &&
+ (c < '0' || c > '9') &&
+ (c < 'A' || c > 'Z') &&
+ (c < 'a' || c > 'z'))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static inline guint
-signal_id_lookup (GQuark quark,
- GType itype)
+signal_id_lookup (const gchar *name,
+ GType itype)
{
+ GQuark quark;
GType *ifaces, type = itype;
SignalKey key;
guint n_ifaces;
+ quark = g_quark_try_string (name);
key.quark = quark;
/* try looking up signals for this type and its ancestors */
@@ -381,7 +439,22 @@ signal_id_lookup (GQuark quark,
}
}
g_free (ifaces);
-
+
+ /* If the @name is non-canonical, try again. This is the slow path — people
+ * should use canonical names in their queries if they want performance. */
+ if (!is_canonical (name))
+ {
+ guint signal_id;
+ gchar *name_copy = g_strdup (name);
+ canonicalize_key (name_copy);
+
+ signal_id = signal_id_lookup (name_copy, itype);
+
+ g_free (name_copy);
+
+ return signal_id;
+ }
+
return 0;
}
@@ -711,7 +784,7 @@ handler_insert (guint signal_id,
HandlerList *hlist;
g_assert (handler->prev == NULL && handler->next == NULL); /* paranoid */
-
+
hlist = handler_list_ensure (signal_id, instance);
if (!hlist->handlers)
{
@@ -1080,7 +1153,7 @@ signal_parse_name (const gchar *name,
if (!colon)
{
- signal_id = signal_id_lookup (g_quark_try_string (name), itype);
+ signal_id = signal_id_lookup (name, itype);
if (signal_id && detail_p)
*detail_p = 0;
}
@@ -1089,11 +1162,14 @@ signal_parse_name (const gchar *name,
gchar buffer[32];
guint l = colon - name;
+ if (colon[2] == '\0')
+ return 0;
+
if (l < 32)
{
memcpy (buffer, name, l);
buffer[l] = 0;
- signal_id = signal_id_lookup (g_quark_try_string (buffer), itype);
+ signal_id = signal_id_lookup (buffer, itype);
}
else
{
@@ -1101,12 +1177,12 @@ signal_parse_name (const gchar *name,
memcpy (signal, name, l);
signal[l] = 0;
- signal_id = signal_id_lookup (g_quark_try_string (signal), itype);
+ signal_id = signal_id_lookup (signal, itype);
g_free (signal);
}
if (signal_id && detail_p)
- *detail_p = colon[2] ? (force_quark ? g_quark_from_string : g_quark_try_string) (colon + 2) : 0;
+ *detail_p = (force_quark ? g_quark_from_string : g_quark_try_string) (colon + 2);
}
else
signal_id = 0;
@@ -1224,6 +1300,10 @@ g_signal_stop_emission_by_name (gpointer instance,
*
* Also tries the ancestors of the given type.
*
+ * The type class passed as @itype must already have been instantiated (for
+ * example, using g_type_class_ref()) for this function to work, as signals are
+ * always installed during class initialization.
+ *
* See g_signal_new() for details on allowed signal names.
*
* Returns: the signal's identifying number, or 0 if no signal was found.
@@ -1237,7 +1317,7 @@ g_signal_lookup (const gchar *name,
g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (itype) || G_TYPE_IS_INTERFACE (itype), 0);
SIGNAL_LOCK ();
- signal_id = signal_id_lookup (g_quark_try_string (name), itype);
+ signal_id = signal_id_lookup (name, itype);
SIGNAL_UNLOCK ();
if (!signal_id)
{
@@ -1245,12 +1325,9 @@ g_signal_lookup (const gchar *name,
if (!g_type_name (itype))
g_warning (G_STRLOC ": unable to look up signal \"%s\" for invalid type id '%"G_GSIZE_FORMAT"'",
name, itype);
- else if (!G_TYPE_IS_INSTANTIATABLE (itype))
- g_warning (G_STRLOC ": unable to look up signal \"%s\" for non instantiatable type '%s'",
- name, g_type_name (itype));
- else if (!g_type_class_peek (itype))
- g_warning (G_STRLOC ": unable to look up signal \"%s\" of unloaded type '%s'",
- name, g_type_name (itype));
+ else if (!is_valid_signal_name (name))
+ g_warning (G_STRLOC ": unable to look up invalid signal name \"%s\" on type '%s'",
+ name, g_type_name (itype));
}
return signal_id;
@@ -1287,13 +1364,7 @@ g_signal_list_ids (GType itype,
for (i = 0; i < n_nodes; i++)
if (keys[i].itype == itype)
{
- const gchar *name = g_quark_to_string (keys[i].quark);
-
- /* Signal names with "_" in them are aliases to the same
- * name with "-" instead of "_".
- */
- if (!strchr (name, '_'))
- g_array_append_val (result, keys[i].signal_id);
+ g_array_append_val (result, keys[i].signal_id);
}
*n_ids = result->len;
SIGNAL_UNLOCK ();
@@ -1399,12 +1470,14 @@ g_signal_query (guint signal_id,
* Creates a new signal. (This is usually done in the class initializer.)
*
* A signal name consists of segments consisting of ASCII letters and
- * digits, separated by either the '-' or '_' character. The first
+ * digits, separated by either the `-` or `_` character. The first
* character of a signal name must be a letter. Names which violate these
- * rules lead to undefined behaviour of the GSignal system.
+ * rules lead to undefined behaviour. These are the same rules as for property
+ * naming (see g_param_spec_internal()).
*
* When registering a signal and looking up a signal, either separator can
- * be used, but they cannot be mixed.
+ * be used, but they cannot be mixed. Using `-` is considerably more efficient.
+ * Using `_` is discouraged.
*
* If 0 is used for @class_offset subclasses cannot override the class handler
* in their class_init method by doing super_class->signal_handler = my_signal_handler.
@@ -1630,7 +1703,8 @@ g_signal_newv (const gchar *signal_name,
guint n_params,
GType *param_types)
{
- gchar *name;
+ const gchar *name;
+ gchar *signal_name_copy = NULL;
guint signal_id, i;
SignalNode *node;
GSignalCMarshaller builtin_c_marshaller;
@@ -1638,6 +1712,7 @@ g_signal_newv (const gchar *signal_name,
GSignalCVaMarshaller va_marshaller;
g_return_val_if_fail (signal_name != NULL, 0);
+ g_return_val_if_fail (is_valid_signal_name (signal_name), 0);
g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (itype) || G_TYPE_IS_INTERFACE (itype), 0);
if (n_params)
g_return_val_if_fail (param_types != NULL, 0);
@@ -1647,12 +1722,20 @@ g_signal_newv (const gchar *signal_name,
if (!accumulator)
g_return_val_if_fail (accu_data == NULL, 0);
- name = g_strdup (signal_name);
- g_strdelimit (name, G_STR_DELIMITERS ":^", '_'); /* FIXME do character checks like for types */
+ if (!is_canonical (signal_name))
+ {
+ signal_name_copy = g_strdup (signal_name);
+ canonicalize_key (signal_name_copy);
+ name = signal_name_copy;
+ }
+ else
+ {
+ name = signal_name;
+ }
SIGNAL_LOCK ();
- signal_id = signal_id_lookup (g_quark_try_string (name), itype);
+ signal_id = signal_id_lookup (name, itype);
node = LOOKUP_SIGNAL_NODE (signal_id);
if (node && !node->destroyed)
{
@@ -1660,7 +1743,7 @@ g_signal_newv (const gchar *signal_name,
name,
type_debug_name (node->itype),
G_TYPE_IS_INTERFACE (node->itype) ? "interface" : "class ancestry");
- g_free (name);
+ g_free (signal_name_copy);
SIGNAL_UNLOCK ();
return 0;
}
@@ -1670,7 +1753,7 @@ g_signal_newv (const gchar *signal_name,
name,
type_debug_name (itype),
type_debug_name (node->itype));
- g_free (name);
+ g_free (signal_name_copy);
SIGNAL_UNLOCK ();
return 0;
}
@@ -1679,7 +1762,7 @@ g_signal_newv (const gchar *signal_name,
{
g_warning (G_STRLOC ": parameter %d of type '%s' for signal \"%s::%s\" is not a value type",
i + 1, type_debug_name (param_types[i]), type_debug_name (itype), name);
- g_free (name);
+ g_free (signal_name_copy);
SIGNAL_UNLOCK ();
return 0;
}
@@ -1687,7 +1770,7 @@ g_signal_newv (const gchar *signal_name,
{
g_warning (G_STRLOC ": return value of type '%s' for signal \"%s::%s\" is not a value type",
type_debug_name (return_type), type_debug_name (itype), name);
- g_free (name);
+ g_free (signal_name_copy);
SIGNAL_UNLOCK ();
return 0;
}
@@ -1696,7 +1779,7 @@ g_signal_newv (const gchar *signal_name,
{
g_warning (G_STRLOC ": signal \"%s::%s\" has return type '%s' and is only G_SIGNAL_RUN_FIRST",
type_debug_name (itype), name, type_debug_name (return_type));
- g_free (name);
+ g_free (signal_name_copy);
SIGNAL_UNLOCK ();
return 0;
}
@@ -1712,12 +1795,8 @@ g_signal_newv (const gchar *signal_name,
g_signal_nodes = g_renew (SignalNode*, g_signal_nodes, g_n_signal_nodes);
g_signal_nodes[signal_id] = node;
node->itype = itype;
- node->name = name;
key.itype = itype;
- key.quark = g_quark_from_string (node->name);
key.signal_id = signal_id;
- g_signal_key_bsa = g_bsearch_array_insert (g_signal_key_bsa, &g_signal_key_bconfig, &key);
- g_strdelimit (name, "_", '-');
node->name = g_intern_string (name);
key.quark = g_quark_from_string (name);
g_signal_key_bsa = g_bsearch_array_insert (g_signal_key_bsa, &g_signal_key_bconfig, &key);
@@ -1805,7 +1884,7 @@ g_signal_newv (const gchar *signal_name,
SIGNAL_UNLOCK ();
- g_free (name);
+ g_free (signal_name_copy);
return signal_id;
}
@@ -2212,7 +2291,7 @@ g_signal_chain_from_overridden_handler (gpointer instance,
g_free (error);
/* we purposely leak the value here, it might not be
- * in a sane state if an error condition occoured
+ * in a correct state if an error condition occurred
*/
while (i--)
g_value_unset (param_values + i);
@@ -2268,7 +2347,7 @@ g_signal_chain_from_overridden_handler (gpointer instance,
g_free (error);
/* we purposely leak the value here, it might not be
- * in a sane state if an error condition occurred
+ * in a correct state if an error condition occurred
*/
}
}
@@ -2345,7 +2424,10 @@ g_signal_connect_closure_by_id (gpointer instance,
else
{
Handler *handler = handler_new (signal_id, instance, after);
-
+
+ if (G_TYPE_IS_OBJECT (node->itype))
+ _g_object_set_has_signal_handler ((GObject *)instance);
+
handler_seq_no = handler->sequential_number;
handler->detail = detail;
handler->closure = g_closure_ref (closure);
@@ -2410,6 +2492,9 @@ g_signal_connect_closure (gpointer instance,
{
Handler *handler = handler_new (signal_id, instance, after);
+ if (G_TYPE_IS_OBJECT (node->itype))
+ _g_object_set_has_signal_handler ((GObject *)instance);
+
handler_seq_no = handler->sequential_number;
handler->detail = detail;
handler->closure = g_closure_ref (closure);
@@ -2511,6 +2596,9 @@ g_signal_connect_data (gpointer instance,
{
Handler *handler = handler_new (signal_id, instance, after);
+ if (G_TYPE_IS_OBJECT (node->itype))
+ _g_object_set_has_signal_handler ((GObject *)instance);
+
handler_seq_no = handler->sequential_number;
handler->detail = detail;
handler->closure = g_closure_ref ((swapped ? g_cclosure_new_swap : g_cclosure_new) (c_handler, data, destroy_data));
@@ -3121,7 +3209,14 @@ g_signal_emitv (const GValue *instance_and_params,
(node->single_va_closure == SINGLE_VA_CLOSURE_EMPTY_MAGIC ||
_g_closure_is_void (node->single_va_closure, instance)))
{
- HandlerList* hlist = handler_list_lookup (node->signal_id, instance);
+ HandlerList* hlist;
+
+ /* single_va_closure is only true for GObjects, so fast path if no handler ever connected to the signal */
+ if (_g_object_has_signal_handler ((GObject *)instance))
+ hlist = handler_list_lookup (node->signal_id, instance);
+ else
+ hlist = NULL;
+
if (hlist == NULL || hlist->handlers == NULL)
{
/* nothing to do to emit this signal */
@@ -3204,7 +3299,7 @@ g_signal_emit_valist (gpointer instance,
if (node->single_va_closure != NULL)
{
- HandlerList* hlist = handler_list_lookup (node->signal_id, instance);
+ HandlerList* hlist;
Handler *fastpath_handler = NULL;
Handler *l;
GClosure *closure = NULL;
@@ -3226,6 +3321,12 @@ g_signal_emit_valist (gpointer instance,
fastpath = FALSE;
}
+ /* single_va_closure is only true for GObjects, so fast path if no handler ever connected to the signal */
+ if (_g_object_has_signal_handler ((GObject *)instance))
+ hlist = handler_list_lookup (node->signal_id, instance);
+ else
+ hlist = NULL;
+
for (l = hlist ? hlist->handlers : NULL; fastpath && l != NULL; l = l->next)
{
if (!l->block_count &&
@@ -3345,7 +3446,7 @@ g_signal_emit_valist (gpointer instance,
g_warning ("%s: %s", G_STRLOC, error);
g_free (error);
/* we purposely leak the value here, it might not be
- * in a sane state if an error condition occurred
+ * in a correct state if an error condition occurred
*/
}
}
@@ -3382,7 +3483,7 @@ g_signal_emit_valist (gpointer instance,
g_free (error);
/* we purposely leak the value here, it might not be
- * in a sane state if an error condition occoured
+ * in a correct state if an error condition occurred
*/
while (i--)
g_value_unset (param_values + i);
@@ -3418,7 +3519,7 @@ g_signal_emit_valist (gpointer instance,
g_free (error);
/* we purposely leak the value here, it might not be
- * in a sane state if an error condition occurred
+ * in a correct state if an error condition occurred
*/
}
}
diff --git a/gobject/gsignal.h b/gobject/gsignal.h
index a79b9f662..59f94d59a 100644
--- a/gobject/gsignal.h
+++ b/gobject/gsignal.h
@@ -160,11 +160,11 @@ typedef enum
/**
* GSignalMatchType:
* @G_SIGNAL_MATCH_ID: The signal id must be equal.
- * @G_SIGNAL_MATCH_DETAIL: The signal detail be equal.
+ * @G_SIGNAL_MATCH_DETAIL: The signal detail must be equal.
* @G_SIGNAL_MATCH_CLOSURE: The closure must be the same.
* @G_SIGNAL_MATCH_FUNC: The C closure callback must be the same.
* @G_SIGNAL_MATCH_DATA: The closure data must be the same.
- * @G_SIGNAL_MATCH_UNBLOCKED: Only unblocked signals may matched.
+ * @G_SIGNAL_MATCH_UNBLOCKED: Only unblocked signals may be matched.
*
* The match types specify what g_signal_handlers_block_matched(),
* g_signal_handlers_unblock_matched() and g_signal_handlers_disconnect_matched()
diff --git a/gobject/gtype-private.h b/gobject/gtype-private.h
index 230dba03a..2e0afdd5d 100644
--- a/gobject/gtype-private.h
+++ b/gobject/gtype-private.h
@@ -23,6 +23,7 @@
#include "gboxed.h"
#include "gclosure.h"
+#include "gobject.h"
/*< private >
* GOBJECT_IF_DEBUG:
@@ -92,6 +93,9 @@ void _g_closure_invoke_va (GClosure *closure,
int n_params,
GType *param_types);
+gboolean _g_object_has_signal_handler (GObject *object);
+void _g_object_set_has_signal_handler (GObject *object);
+
/**
* _G_DEFINE_TYPE_EXTENDED_WITH_PRELUDE:
*
diff --git a/gobject/gtype.c b/gobject/gtype.c
index 7d3789400..b5ef2d11e 100644
--- a/gobject/gtype.c
+++ b/gobject/gtype.c
@@ -2825,7 +2825,7 @@ g_type_register_dynamic (GType parent_type,
* @info: #GInterfaceInfo structure for this
* (@instance_type, @interface_type) combination
*
- * Adds the static @interface_type to @instantiable_type.
+ * Adds @interface_type to the static @instantiable_type.
* The information contained in the #GInterfaceInfo structure
* pointed to by @info is used to manage the relationship.
*/
@@ -2861,7 +2861,7 @@ g_type_add_interface_static (GType instance_type,
* @interface_type: #GType value of an interface type
* @plugin: #GTypePlugin structure to retrieve the #GInterfaceInfo from
*
- * Adds the dynamic @interface_type to @instantiable_type. The information
+ * Adds @interface_type to the dynamic @instantiable_type. The information
* contained in the #GTypePlugin structure pointed to by @plugin
* is used to manage the relationship.
*/
diff --git a/gobject/gtype.h b/gobject/gtype.h
index d9e5d110c..479b405e9 100644
--- a/gobject/gtype.h
+++ b/gobject/gtype.h
@@ -1406,10 +1406,11 @@ guint g_type_get_type_registration_serial (void);
typedef struct { ParentName##Class parent_class; } ModuleObjName##Class; \
\
_GLIB_DEFINE_AUTOPTR_CHAINUP (ModuleObjName, ParentName) \
+ G_DEFINE_AUTOPTR_CLEANUP_FUNC (ModuleObjName##Class, g_type_class_unref) \
\
- static inline ModuleObjName * MODULE##_##OBJ_NAME (gpointer ptr) { \
+ G_GNUC_UNUSED static inline ModuleObjName * MODULE##_##OBJ_NAME (gpointer ptr) { \
return G_TYPE_CHECK_INSTANCE_CAST (ptr, module_obj_name##_get_type (), ModuleObjName); } \
- static inline gboolean MODULE##_IS_##OBJ_NAME (gpointer ptr) { \
+ G_GNUC_UNUSED static inline gboolean MODULE##_IS_##OBJ_NAME (gpointer ptr) { \
return G_TYPE_CHECK_INSTANCE_TYPE (ptr, module_obj_name##_get_type ()); } \
G_GNUC_END_IGNORE_DEPRECATIONS
@@ -1497,16 +1498,17 @@ guint g_type_get_type_registration_serial (void);
struct _##ModuleObjName { ParentName parent_instance; }; \
\
_GLIB_DEFINE_AUTOPTR_CHAINUP (ModuleObjName, ParentName) \
+ G_DEFINE_AUTOPTR_CLEANUP_FUNC (ModuleObjName##Class, g_type_class_unref) \
\
- static inline ModuleObjName * MODULE##_##OBJ_NAME (gpointer ptr) { \
+ G_GNUC_UNUSED static inline ModuleObjName * MODULE##_##OBJ_NAME (gpointer ptr) { \
return G_TYPE_CHECK_INSTANCE_CAST (ptr, module_obj_name##_get_type (), ModuleObjName); } \
- static inline ModuleObjName##Class * MODULE##_##OBJ_NAME##_CLASS (gpointer ptr) { \
+ G_GNUC_UNUSED static inline ModuleObjName##Class * MODULE##_##OBJ_NAME##_CLASS (gpointer ptr) { \
return G_TYPE_CHECK_CLASS_CAST (ptr, module_obj_name##_get_type (), ModuleObjName##Class); } \
- static inline gboolean MODULE##_IS_##OBJ_NAME (gpointer ptr) { \
+ G_GNUC_UNUSED static inline gboolean MODULE##_IS_##OBJ_NAME (gpointer ptr) { \
return G_TYPE_CHECK_INSTANCE_TYPE (ptr, module_obj_name##_get_type ()); } \
- static inline gboolean MODULE##_IS_##OBJ_NAME##_CLASS (gpointer ptr) { \
+ G_GNUC_UNUSED static inline gboolean MODULE##_IS_##OBJ_NAME##_CLASS (gpointer ptr) { \
return G_TYPE_CHECK_CLASS_TYPE (ptr, module_obj_name##_get_type ()); } \
- static inline ModuleObjName##Class * MODULE##_##OBJ_NAME##_GET_CLASS (gpointer ptr) { \
+ G_GNUC_UNUSED static inline ModuleObjName##Class * MODULE##_##OBJ_NAME##_GET_CLASS (gpointer ptr) { \
return G_TYPE_INSTANCE_GET_CLASS (ptr, module_obj_name##_get_type (), ModuleObjName##Class); } \
G_GNUC_END_IGNORE_DEPRECATIONS
@@ -1576,11 +1578,11 @@ guint g_type_get_type_registration_serial (void);
\
_GLIB_DEFINE_AUTOPTR_CHAINUP (ModuleObjName, PrerequisiteName) \
\
- static inline ModuleObjName * MODULE##_##OBJ_NAME (gpointer ptr) { \
+ G_GNUC_UNUSED static inline ModuleObjName * MODULE##_##OBJ_NAME (gpointer ptr) { \
return G_TYPE_CHECK_INSTANCE_CAST (ptr, module_obj_name##_get_type (), ModuleObjName); } \
- static inline gboolean MODULE##_IS_##OBJ_NAME (gpointer ptr) { \
+ G_GNUC_UNUSED static inline gboolean MODULE##_IS_##OBJ_NAME (gpointer ptr) { \
return G_TYPE_CHECK_INSTANCE_TYPE (ptr, module_obj_name##_get_type ()); } \
- static inline ModuleObjName##Interface * MODULE##_##OBJ_NAME##_GET_IFACE (gpointer ptr) { \
+ G_GNUC_UNUSED static inline ModuleObjName##Interface * MODULE##_##OBJ_NAME##_GET_IFACE (gpointer ptr) { \
return G_TYPE_INSTANCE_GET_INTERFACE (ptr, module_obj_name##_get_type (), ModuleObjName##Interface); } \
G_GNUC_END_IGNORE_DEPRECATIONS
diff --git a/gobject/gvalue.c b/gobject/gvalue.c
index 6d10f61a2..468da2e7d 100644
--- a/gobject/gvalue.c
+++ b/gobject/gvalue.c
@@ -376,7 +376,7 @@ g_value_set_instance (GValue *value,
g_free (error_msg);
/* we purposely leak the value here, it might not be
- * in a sane state if an error condition occoured
+ * in a correct state if an error condition occurred
*/
value_meminit (value, g_type);
value_table->value_init (value);
@@ -440,7 +440,7 @@ g_value_init_from_instance (GValue *value,
g_free (error_msg);
/* we purposely leak the value here, it might not be
- * in a sane state if an error condition occoured
+ * in a correct state if an error condition occurred
*/
value_meminit (value, g_type);
value_table->value_init (value);
diff --git a/gobject/tests/autoptr.c b/gobject/tests/autoptr.c
index cf7687d84..ec3c89ebc 100644
--- a/gobject/tests/autoptr.c
+++ b/gobject/tests/autoptr.c
@@ -29,6 +29,18 @@ struct _TestAutoCleanupBaseClass {
GObjectClass parent_class;
};
+G_DEFINE_TYPE (TestAutoCleanupBase, test_base_auto_cleanup, G_TYPE_OBJECT)
+
+static void
+test_base_auto_cleanup_class_init (TestAutoCleanupBaseClass *class)
+{
+}
+
+static void
+test_base_auto_cleanup_init (TestAutoCleanupBase *tac)
+{
+}
+
G_DECLARE_FINAL_TYPE (TestAutoCleanup, test_auto_cleanup, TEST, AUTO_CLEANUP, TestAutoCleanupBase)
struct _TestAutoCleanup
@@ -65,6 +77,7 @@ test_autoptr (void)
{
g_autoptr (TestAutoCleanup) tac = tac_ptr;
+ g_assert_nonnull (tac);
}
#ifdef __GNUC__
g_assert_null (tac_ptr);
@@ -113,6 +126,9 @@ test_autolist (void)
l = g_list_prepend (l, tac1);
l = g_list_prepend (l, tac2);
+
+ /* Squash warnings about dead stores */
+ (void) l;
}
/* Only assert if autoptr works */
@@ -192,6 +208,19 @@ test_autoqueue (void)
g_assert_null (tac3);
}
+static void
+test_autoclass (void)
+{
+ g_autoptr (TestAutoCleanupBaseClass) base_class_ptr = NULL;
+ g_autoptr (TestAutoCleanupClass) class_ptr = NULL;
+
+ base_class_ptr = g_type_class_ref (test_base_auto_cleanup_get_type ());
+ class_ptr = g_type_class_ref (test_auto_cleanup_get_type ());
+
+ g_assert_nonnull (base_class_ptr);
+ g_assert_nonnull (class_ptr);
+}
+
int
main (int argc, gchar *argv[])
{
@@ -202,6 +231,7 @@ main (int argc, gchar *argv[])
g_test_add_func ("/autoptr/autolist", test_autolist);
g_test_add_func ("/autoptr/autoslist", test_autoslist);
g_test_add_func ("/autoptr/autoqueue", test_autoqueue);
+ g_test_add_func ("/autoptr/autoclass", test_autoclass);
return g_test_run ();
}
diff --git a/gobject/tests/binding.c b/gobject/tests/binding.c
index 019fb280e..1d3ead481 100644
--- a/gobject/tests/binding.c
+++ b/gobject/tests/binding.c
@@ -8,7 +8,7 @@ typedef struct _BindingSource
gint foo;
gint bar;
- gdouble value;
+ gdouble double_value;
gboolean toggle;
} BindingSource;
@@ -23,7 +23,7 @@ enum
PROP_SOURCE_FOO,
PROP_SOURCE_BAR,
- PROP_SOURCE_VALUE,
+ PROP_SOURCE_DOUBLE_VALUE,
PROP_SOURCE_TOGGLE
};
@@ -48,8 +48,8 @@ binding_source_set_property (GObject *gobject,
source->bar = g_value_get_int (value);
break;
- case PROP_SOURCE_VALUE:
- source->value = g_value_get_double (value);
+ case PROP_SOURCE_DOUBLE_VALUE:
+ source->double_value = g_value_get_double (value);
break;
case PROP_SOURCE_TOGGLE:
@@ -79,8 +79,8 @@ binding_source_get_property (GObject *gobject,
g_value_set_int (value, source->bar);
break;
- case PROP_SOURCE_VALUE:
- g_value_set_double (value, source->value);
+ case PROP_SOURCE_DOUBLE_VALUE:
+ g_value_set_double (value, source->double_value);
break;
case PROP_SOURCE_TOGGLE:
@@ -110,8 +110,8 @@ binding_source_class_init (BindingSourceClass *klass)
-1, 100,
0,
G_PARAM_READWRITE));
- g_object_class_install_property (gobject_class, PROP_SOURCE_VALUE,
- g_param_spec_double ("value", "Value", "Value",
+ g_object_class_install_property (gobject_class, PROP_SOURCE_DOUBLE_VALUE,
+ g_param_spec_double ("double-value", "Value", "Value",
-100.0, 200.0,
0.0,
G_PARAM_READWRITE));
@@ -131,7 +131,7 @@ typedef struct _BindingTarget
GObject parent_instance;
gint bar;
- gdouble value;
+ gdouble double_value;
gboolean toggle;
} BindingTarget;
@@ -145,7 +145,7 @@ enum
PROP_TARGET_0,
PROP_TARGET_BAR,
- PROP_TARGET_VALUE,
+ PROP_TARGET_DOUBLE_VALUE,
PROP_TARGET_TOGGLE
};
@@ -166,8 +166,8 @@ binding_target_set_property (GObject *gobject,
target->bar = g_value_get_int (value);
break;
- case PROP_TARGET_VALUE:
- target->value = g_value_get_double (value);
+ case PROP_TARGET_DOUBLE_VALUE:
+ target->double_value = g_value_get_double (value);
break;
case PROP_TARGET_TOGGLE:
@@ -193,8 +193,8 @@ binding_target_get_property (GObject *gobject,
g_value_set_int (value, target->bar);
break;
- case PROP_TARGET_VALUE:
- g_value_set_double (value, target->value);
+ case PROP_TARGET_DOUBLE_VALUE:
+ g_value_set_double (value, target->double_value);
break;
case PROP_TARGET_TOGGLE:
@@ -219,8 +219,8 @@ binding_target_class_init (BindingTargetClass *klass)
-1, 100,
0,
G_PARAM_READWRITE));
- g_object_class_install_property (gobject_class, PROP_TARGET_VALUE,
- g_param_spec_double ("value", "Value", "Value",
+ g_object_class_install_property (gobject_class, PROP_TARGET_DOUBLE_VALUE,
+ g_param_spec_double ("double-value", "Value", "Value",
-100.0, 200.0,
0.0,
G_PARAM_READWRITE));
@@ -243,8 +243,8 @@ celsius_to_fahrenheit (GBinding *binding,
{
gdouble celsius, fahrenheit;
- g_assert (G_VALUE_HOLDS (from_value, G_TYPE_DOUBLE));
- g_assert (G_VALUE_HOLDS (to_value, G_TYPE_DOUBLE));
+ g_assert_true (G_VALUE_HOLDS (from_value, G_TYPE_DOUBLE));
+ g_assert_true (G_VALUE_HOLDS (to_value, G_TYPE_DOUBLE));
celsius = g_value_get_double (from_value);
fahrenheit = (9 * celsius / 5) + 32.0;
@@ -265,8 +265,8 @@ fahrenheit_to_celsius (GBinding *binding,
{
gdouble celsius, fahrenheit;
- g_assert (G_VALUE_HOLDS (from_value, G_TYPE_DOUBLE));
- g_assert (G_VALUE_HOLDS (to_value, G_TYPE_DOUBLE));
+ g_assert_true (G_VALUE_HOLDS (from_value, G_TYPE_DOUBLE));
+ g_assert_true (G_VALUE_HOLDS (to_value, G_TYPE_DOUBLE));
fahrenheit = g_value_get_double (from_value);
celsius = 5 * (fahrenheit - 32.0) / 9;
@@ -291,8 +291,8 @@ binding_default (void)
G_BINDING_DEFAULT);
g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding);
- g_assert ((BindingSource *) g_binding_get_source (binding) == source);
- g_assert ((BindingTarget *) g_binding_get_target (binding) == target);
+ g_assert_true ((BindingSource *) g_binding_get_source (binding) == source);
+ g_assert_true ((BindingTarget *) g_binding_get_target (binding) == target);
g_assert_cmpstr (g_binding_get_source_property (binding), ==, "foo");
g_assert_cmpstr (g_binding_get_target_property (binding), ==, "bar");
g_assert_cmpint (g_binding_get_flags (binding), ==, G_BINDING_DEFAULT);
@@ -310,7 +310,38 @@ binding_default (void)
g_object_unref (source);
g_object_unref (target);
- g_assert (binding == NULL);
+ g_assert_null (binding);
+}
+
+static void
+binding_canonicalisation (void)
+{
+ BindingSource *source = g_object_new (binding_source_get_type (), NULL);
+ BindingTarget *target = g_object_new (binding_target_get_type (), NULL);
+ GBinding *binding;
+
+ g_test_summary ("Test that bindings set up with non-canonical property names work");
+
+ binding = g_object_bind_property (source, "double_value",
+ target, "double_value",
+ G_BINDING_DEFAULT);
+
+ g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding);
+ g_assert_true ((BindingSource *) g_binding_get_source (binding) == source);
+ g_assert_true ((BindingTarget *) g_binding_get_target (binding) == target);
+ g_assert_cmpstr (g_binding_get_source_property (binding), ==, "double-value");
+ g_assert_cmpstr (g_binding_get_target_property (binding), ==, "double-value");
+ g_assert_cmpint (g_binding_get_flags (binding), ==, G_BINDING_DEFAULT);
+
+ g_object_set (source, "double-value", 24.0, NULL);
+ g_assert_cmpfloat (target->double_value, ==, source->double_value);
+
+ g_object_set (target, "double-value", 69.0, NULL);
+ g_assert_cmpfloat (source->double_value, !=, target->double_value);
+
+ g_object_unref (target);
+ g_object_unref (source);
+ g_assert_null (binding);
}
static void
@@ -338,7 +369,7 @@ binding_bidirectional (void)
g_object_unref (source);
g_object_unref (target);
- g_assert (binding == NULL);
+ g_assert_null (binding);
}
static void
@@ -360,7 +391,7 @@ binding_transform_default (void)
GBindingFlags flags;
binding = g_object_bind_property (source, "foo",
- target, "value",
+ target, "double-value",
G_BINDING_BIDIRECTIONAL);
g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding);
@@ -372,10 +403,10 @@ binding_transform_default (void)
"target-property", &trg_prop,
"flags", &flags,
NULL);
- g_assert (src == source);
- g_assert (trg == target);
+ g_assert_true (src == source);
+ g_assert_true (trg == target);
g_assert_cmpstr (src_prop, ==, "foo");
- g_assert_cmpstr (trg_prop, ==, "value");
+ g_assert_cmpstr (trg_prop, ==, "double-value");
g_assert_cmpint (flags, ==, G_BINDING_BIDIRECTIONAL);
g_object_unref (src);
g_object_unref (trg);
@@ -383,14 +414,14 @@ binding_transform_default (void)
g_free (trg_prop);
g_object_set (source, "foo", 24, NULL);
- g_assert_cmpfloat (target->value, ==, 24.0);
+ g_assert_cmpfloat (target->double_value, ==, 24.0);
- g_object_set (target, "value", 69.0, NULL);
+ g_object_set (target, "double-value", 69.0, NULL);
g_assert_cmpint (source->foo, ==, 69);
g_object_unref (target);
g_object_unref (source);
- g_assert (binding == NULL);
+ g_assert_null (binding);
}
static void
@@ -401,23 +432,23 @@ binding_transform (void)
GBinding *binding G_GNUC_UNUSED;
gboolean unused_data = FALSE;
- binding = g_object_bind_property_full (source, "value",
- target, "value",
+ binding = g_object_bind_property_full (source, "double-value",
+ target, "double-value",
G_BINDING_BIDIRECTIONAL,
celsius_to_fahrenheit,
fahrenheit_to_celsius,
&unused_data, data_free);
- g_object_set (source, "value", 24.0, NULL);
- g_assert_cmpfloat (target->value, ==, ((9 * 24.0 / 5) + 32.0));
+ g_object_set (source, "double-value", 24.0, NULL);
+ g_assert_cmpfloat (target->double_value, ==, ((9 * 24.0 / 5) + 32.0));
- g_object_set (target, "value", 69.0, NULL);
- g_assert_cmpfloat (source->value, ==, (5 * (69.0 - 32.0) / 9));
+ g_object_set (target, "double-value", 69.0, NULL);
+ g_assert_cmpfloat (source->double_value, ==, (5 * (69.0 - 32.0) / 9));
g_object_unref (source);
g_object_unref (target);
- g_assert (unused_data);
+ g_assert_true (unused_data);
}
static void
@@ -433,23 +464,23 @@ binding_transform_closure (void)
f2c_clos = g_cclosure_new (G_CALLBACK (fahrenheit_to_celsius), &unused_data_2, (GClosureNotify) data_free);
- binding = g_object_bind_property_with_closures (source, "value",
- target, "value",
+ binding = g_object_bind_property_with_closures (source, "double-value",
+ target, "double-value",
G_BINDING_BIDIRECTIONAL,
c2f_clos,
f2c_clos);
- g_object_set (source, "value", 24.0, NULL);
- g_assert_cmpfloat (target->value, ==, ((9 * 24.0 / 5) + 32.0));
+ g_object_set (source, "double-value", 24.0, NULL);
+ g_assert_cmpfloat (target->double_value, ==, ((9 * 24.0 / 5) + 32.0));
- g_object_set (target, "value", 69.0, NULL);
- g_assert_cmpfloat (source->value, ==, (5 * (69.0 - 32.0) / 9));
+ g_object_set (target, "double-value", 69.0, NULL);
+ g_assert_cmpfloat (source->double_value, ==, (5 * (69.0 - 32.0) / 9));
g_object_unref (source);
g_object_unref (target);
- g_assert (unused_data_1);
- g_assert (unused_data_2);
+ g_assert_true (unused_data_1);
+ g_assert_true (unused_data_2);
}
static void
@@ -477,9 +508,9 @@ binding_chain (void)
/* unbind A -> B and B -> C */
g_object_unref (binding_1);
- g_assert (binding_1 == NULL);
+ g_assert_null (binding_1);
g_object_unref (binding_2);
- g_assert (binding_2 == NULL);
+ g_assert_null (binding_2);
/* bind A -> C directly */
binding_2 = g_object_bind_property (a, "foo", c, "foo", G_BINDING_BIDIRECTIONAL);
@@ -544,16 +575,16 @@ binding_invert_boolean (void)
target, "toggle",
G_BINDING_BIDIRECTIONAL | G_BINDING_INVERT_BOOLEAN);
- g_assert (source->toggle);
- g_assert (!target->toggle);
+ g_assert_true (source->toggle);
+ g_assert_false (target->toggle);
g_object_set (source, "toggle", FALSE, NULL);
- g_assert (!source->toggle);
- g_assert (target->toggle);
+ g_assert_false (source->toggle);
+ g_assert_true (target->toggle);
g_object_set (target, "toggle", FALSE, NULL);
- g_assert (source->toggle);
- g_assert (!target->toggle);
+ g_assert_true (source->toggle);
+ g_assert_false (target->toggle);
g_object_unref (binding);
g_object_unref (source);
@@ -582,7 +613,7 @@ binding_same_object (void)
g_assert_cmpint (source->bar, ==, 30);
g_object_unref (source);
- g_assert (binding == NULL);
+ g_assert_null (binding);
}
static void
@@ -604,7 +635,7 @@ binding_unbind (void)
g_assert_cmpint (source->foo, !=, target->bar);
g_binding_unbind (binding);
- g_assert (binding == NULL);
+ g_assert_null (binding);
g_object_set (source, "foo", 0, NULL);
g_assert_cmpint (source->foo, !=, target->bar);
@@ -621,7 +652,7 @@ binding_unbind (void)
g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding);
g_binding_unbind (binding);
- g_assert (binding == NULL);
+ g_assert_null (binding);
g_object_unref (source);
}
@@ -711,19 +742,19 @@ binding_fail (void)
GBinding *binding;
/* double -> boolean is not supported */
- binding = g_object_bind_property (source, "value",
+ binding = g_object_bind_property (source, "double-value",
target, "toggle",
G_BINDING_DEFAULT);
g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding);
g_test_expect_message ("GLib-GObject", G_LOG_LEVEL_WARNING,
"*Unable to convert*double*boolean*");
- g_object_set (source, "value", 1.0, NULL);
+ g_object_set (source, "double-value", 1.0, NULL);
g_test_assert_expected_messages ();
g_object_unref (source);
g_object_unref (target);
- g_assert (binding == NULL);
+ g_assert_null (binding);
}
int
@@ -734,6 +765,7 @@ main (int argc, char *argv[])
g_test_bug_base ("https://gitlab.gnome.org/GNOME/glib/issues/");
g_test_add_func ("/binding/default", binding_default);
+ g_test_add_func ("/binding/canonicalisation", binding_canonicalisation);
g_test_add_func ("/binding/bidirectional", binding_bidirectional);
g_test_add_func ("/binding/transform", binding_transform);
g_test_add_func ("/binding/transform-default", binding_transform_default);
diff --git a/gobject/tests/meson.build b/gobject/tests/meson.build
index 9c6a6e034..1d0ef4a53 100644
--- a/gobject/tests/meson.build
+++ b/gobject/tests/meson.build
@@ -50,6 +50,7 @@ gobject_tests = {
'signals' : {
'source' : ['signals.c', marshalers_h, marshalers_c],
},
+ 'testing' : {},
}
if cc.get_id() != 'msvc'
diff --git a/gobject/tests/param.c b/gobject/tests/param.c
index 758289bf8..93c3f4b94 100644
--- a/gobject/tests/param.c
+++ b/gobject/tests/param.c
@@ -10,19 +10,19 @@ test_param_value (void)
GValue value = G_VALUE_INIT;
g_value_init (&value, G_TYPE_PARAM);
- g_assert (G_VALUE_HOLDS_PARAM (&value));
+ g_assert_true (G_VALUE_HOLDS_PARAM (&value));
p = g_param_spec_int ("my-int", "My Int", "Blurb", 0, 20, 10, G_PARAM_READWRITE);
g_value_take_param (&value, p);
p2 = g_value_get_param (&value);
- g_assert (p2 == p);
+ g_assert_true (p2 == p);
pp = g_param_spec_uint ("my-uint", "My UInt", "Blurb", 0, 10, 5, G_PARAM_READWRITE);
g_value_set_param (&value, pp);
p2 = g_value_dup_param (&value);
- g_assert (p2 == pp); /* param specs use ref/unref for copy/free */
+ g_assert_true (p2 == pp); /* param specs use ref/unref for copy/free */
g_param_spec_unref (p2);
g_value_unset (&value);
@@ -57,7 +57,7 @@ test_param_qdata (void)
g_assert_cmpint (destroy_count, ==, 1);
g_assert_cmpstr (g_param_spec_steal_qdata (p, q), ==, "blabla");
g_assert_cmpint (destroy_count, ==, 1);
- g_assert (g_param_spec_get_qdata (p, q) == NULL);
+ g_assert_null (g_param_spec_get_qdata (p, q));
g_param_spec_ref_sink (p);
@@ -74,12 +74,12 @@ test_param_validate (void)
g_value_init (&value, G_TYPE_INT);
g_value_set_int (&value, 100);
- g_assert (!g_param_value_defaults (p, &value));
- g_assert (g_param_value_validate (p, &value));
+ g_assert_false (g_param_value_defaults (p, &value));
+ g_assert_true (g_param_value_validate (p, &value));
g_assert_cmpint (g_value_get_int (&value), ==, 20);
g_param_value_set_default (p, &value);
- g_assert (g_param_value_defaults (p, &value));
+ g_assert_true (g_param_value_defaults (p, &value));
g_assert_cmpint (g_value_get_int (&value), ==, 10);
g_param_spec_unref (p);
@@ -91,9 +91,9 @@ test_param_strings (void)
GParamSpec *p;
/* test canonicalization */
- p = g_param_spec_int ("my_int:bla", "My Int", "Blurb", 0, 20, 10, G_PARAM_READWRITE);
+ p = g_param_spec_int ("my_int", "My Int", "Blurb", 0, 20, 10, G_PARAM_READWRITE);
- g_assert_cmpstr (g_param_spec_get_name (p), ==, "my-int-bla");
+ g_assert_cmpstr (g_param_spec_get_name (p), ==, "my-int");
g_assert_cmpstr (g_param_spec_get_nick (p), ==, "My Int");
g_assert_cmpstr (g_param_spec_get_blurb (p), ==, "Blurb");
@@ -104,12 +104,32 @@ test_param_strings (void)
g_assert_cmpstr (g_param_spec_get_name (p), ==, "my-int");
g_assert_cmpstr (g_param_spec_get_nick (p), ==, "my-int");
- g_assert (g_param_spec_get_blurb (p) == NULL);
+ g_assert_null (g_param_spec_get_blurb (p));
g_param_spec_unref (p);
}
static void
+test_param_invalid_name (gconstpointer test_data)
+{
+ const gchar *invalid_name = test_data;
+
+ g_test_summary ("Test that properties cannot be created with invalid names");
+
+ if (g_test_subprocess ())
+ {
+ GParamSpec *p;
+ p = g_param_spec_int (invalid_name, "My Int", "Blurb", 0, 20, 10, G_PARAM_READWRITE);
+ g_param_spec_unref (p);
+ return;
+ }
+
+ g_test_trap_subprocess (NULL, 0, 0);
+ g_test_trap_assert_failed ();
+ g_test_trap_assert_stderr ("*CRITICAL*is_valid_property_name (name)*");
+}
+
+static void
test_param_convert (void)
{
GParamSpec *p;
@@ -123,10 +143,10 @@ test_param_convert (void)
g_value_init (&v2, G_TYPE_INT);
g_value_set_int (&v2, -4);
- g_assert (!g_param_value_convert (p, &v1, &v2, TRUE));
+ g_assert_false (g_param_value_convert (p, &v1, &v2, TRUE));
g_assert_cmpint (g_value_get_int (&v2), ==, -4);
- g_assert (g_param_value_convert (p, &v1, &v2, FALSE));
+ g_assert_true (g_param_value_convert (p, &v1, &v2, FALSE));
g_assert_cmpint (g_value_get_int (&v2), ==, 20);
g_param_spec_unref (p);
@@ -139,11 +159,11 @@ test_value_transform (void)
GValue dest = G_VALUE_INIT;
#define CHECK_INT_CONVERSION(type, getter, value) \
- g_assert (g_value_type_transformable (G_TYPE_INT, type)); \
+ g_assert_true (g_value_type_transformable (G_TYPE_INT, type)); \
g_value_init (&src, G_TYPE_INT); \
g_value_init (&dest, type); \
g_value_set_int (&src, value); \
- g_assert (g_value_transform (&src, &dest)); \
+ g_assert_true (g_value_transform (&src, &dest)); \
g_assert_cmpint (g_value_get_##getter (&dest), ==, value); \
g_value_unset (&src); \
g_value_unset (&dest);
@@ -171,11 +191,11 @@ test_value_transform (void)
CHECK_INT_CONVERSION(G_TYPE_DOUBLE, double, 12345678)
#define CHECK_UINT_CONVERSION(type, getter, value) \
- g_assert (g_value_type_transformable (G_TYPE_UINT, type)); \
+ g_assert_true (g_value_type_transformable (G_TYPE_UINT, type)); \
g_value_init (&src, G_TYPE_UINT); \
g_value_init (&dest, type); \
g_value_set_uint (&src, value); \
- g_assert (g_value_transform (&src, &dest)); \
+ g_assert_true (g_value_transform (&src, &dest)); \
g_assert_cmpuint (g_value_get_##getter (&dest), ==, value); \
g_value_unset (&src); \
g_value_unset (&dest);
@@ -196,11 +216,11 @@ test_value_transform (void)
CHECK_UINT_CONVERSION(G_TYPE_DOUBLE, double, 12345678)
#define CHECK_LONG_CONVERSION(type, getter, value) \
- g_assert (g_value_type_transformable (G_TYPE_LONG, type)); \
+ g_assert_true (g_value_type_transformable (G_TYPE_LONG, type)); \
g_value_init (&src, G_TYPE_LONG); \
g_value_init (&dest, type); \
g_value_set_long (&src, value); \
- g_assert (g_value_transform (&src, &dest)); \
+ g_assert_true (g_value_transform (&src, &dest)); \
g_assert_cmpint (g_value_get_##getter (&dest), ==, value); \
g_value_unset (&src); \
g_value_unset (&dest);
@@ -221,11 +241,11 @@ test_value_transform (void)
CHECK_LONG_CONVERSION(G_TYPE_DOUBLE, double, 12345678)
#define CHECK_ULONG_CONVERSION(type, getter, value) \
- g_assert (g_value_type_transformable (G_TYPE_ULONG, type)); \
+ g_assert_true (g_value_type_transformable (G_TYPE_ULONG, type)); \
g_value_init (&src, G_TYPE_ULONG); \
g_value_init (&dest, type); \
g_value_set_ulong (&src, value); \
- g_assert (g_value_transform (&src, &dest)); \
+ g_assert_true (g_value_transform (&src, &dest)); \
g_assert_cmpuint (g_value_get_##getter (&dest), ==, value); \
g_value_unset (&src); \
g_value_unset (&dest);
@@ -246,11 +266,11 @@ test_value_transform (void)
CHECK_ULONG_CONVERSION(G_TYPE_DOUBLE, double, 12345678)
#define CHECK_INT64_CONVERSION(type, getter, value) \
- g_assert (g_value_type_transformable (G_TYPE_INT64, type)); \
+ g_assert_true (g_value_type_transformable (G_TYPE_INT64, type)); \
g_value_init (&src, G_TYPE_INT64); \
g_value_init (&dest, type); \
g_value_set_int64 (&src, value); \
- g_assert (g_value_transform (&src, &dest)); \
+ g_assert_true (g_value_transform (&src, &dest)); \
g_assert_cmpint (g_value_get_##getter (&dest), ==, value); \
g_value_unset (&src); \
g_value_unset (&dest);
@@ -271,11 +291,11 @@ test_value_transform (void)
CHECK_INT64_CONVERSION(G_TYPE_DOUBLE, double, 12345678)
#define CHECK_UINT64_CONVERSION(type, getter, value) \
- g_assert (g_value_type_transformable (G_TYPE_UINT64, type)); \
+ g_assert_true (g_value_type_transformable (G_TYPE_UINT64, type)); \
g_value_init (&src, G_TYPE_UINT64); \
g_value_init (&dest, type); \
g_value_set_uint64 (&src, value); \
- g_assert (g_value_transform (&src, &dest)); \
+ g_assert_true (g_value_transform (&src, &dest)); \
g_assert_cmpuint (g_value_get_##getter (&dest), ==, value); \
g_value_unset (&src); \
g_value_unset (&dest);
@@ -296,11 +316,11 @@ test_value_transform (void)
CHECK_UINT64_CONVERSION(G_TYPE_DOUBLE, double, 12345678)
#define CHECK_FLOAT_CONVERSION(type, getter, value) \
- g_assert (g_value_type_transformable (G_TYPE_FLOAT, type)); \
+ g_assert_true (g_value_type_transformable (G_TYPE_FLOAT, type)); \
g_value_init (&src, G_TYPE_FLOAT); \
g_value_init (&dest, type); \
g_value_set_float (&src, value); \
- g_assert (g_value_transform (&src, &dest)); \
+ g_assert_true (g_value_transform (&src, &dest)); \
g_assert_cmpfloat (g_value_get_##getter (&dest), ==, value); \
g_value_unset (&src); \
g_value_unset (&dest);
@@ -321,11 +341,11 @@ test_value_transform (void)
CHECK_FLOAT_CONVERSION(G_TYPE_DOUBLE, double, 12345678)
#define CHECK_DOUBLE_CONVERSION(type, getter, value) \
- g_assert (g_value_type_transformable (G_TYPE_DOUBLE, type)); \
+ g_assert_true (g_value_type_transformable (G_TYPE_DOUBLE, type)); \
g_value_init (&src, G_TYPE_DOUBLE); \
g_value_init (&dest, type); \
g_value_set_double (&src, value); \
- g_assert (g_value_transform (&src, &dest)); \
+ g_assert_true (g_value_transform (&src, &dest)); \
g_assert_cmpfloat (g_value_get_##getter (&dest), ==, value); \
g_value_unset (&src); \
g_value_unset (&dest);
@@ -346,14 +366,14 @@ test_value_transform (void)
CHECK_DOUBLE_CONVERSION(G_TYPE_DOUBLE, double, 12345678)
#define CHECK_BOOLEAN_CONVERSION(type, setter, value) \
- g_assert (g_value_type_transformable (type, G_TYPE_BOOLEAN)); \
+ g_assert_true (g_value_type_transformable (type, G_TYPE_BOOLEAN)); \
g_value_init (&src, type); \
g_value_init (&dest, G_TYPE_BOOLEAN); \
g_value_set_##setter (&src, value); \
- g_assert (g_value_transform (&src, &dest)); \
+ g_assert_true (g_value_transform (&src, &dest)); \
g_assert_cmpint (g_value_get_boolean (&dest), ==, TRUE); \
g_value_set_##setter (&src, 0); \
- g_assert (g_value_transform (&src, &dest)); \
+ g_assert_true (g_value_transform (&src, &dest)); \
g_assert_cmpint (g_value_get_boolean (&dest), ==, FALSE); \
g_value_unset (&src); \
g_value_unset (&dest);
@@ -366,11 +386,11 @@ test_value_transform (void)
CHECK_BOOLEAN_CONVERSION(G_TYPE_UINT64, uint64, 12345678)
#define CHECK_STRING_CONVERSION(int_type, setter, int_value) \
- g_assert (g_value_type_transformable (int_type, G_TYPE_STRING)); \
+ g_assert_true (g_value_type_transformable (int_type, G_TYPE_STRING)); \
g_value_init (&src, int_type); \
g_value_init (&dest, G_TYPE_STRING); \
g_value_set_##setter (&src, int_value); \
- g_assert (g_value_transform (&src, &dest)); \
+ g_assert_true (g_value_transform (&src, &dest)); \
g_assert_cmpstr (g_value_get_string (&dest), ==, #int_value); \
g_value_unset (&src); \
g_value_unset (&dest);
@@ -384,12 +404,12 @@ test_value_transform (void)
CHECK_STRING_CONVERSION(G_TYPE_FLOAT, float, 0.500000)
CHECK_STRING_CONVERSION(G_TYPE_DOUBLE, double, -1.234567)
- g_assert (!g_value_type_transformable (G_TYPE_STRING, G_TYPE_CHAR));
+ g_assert_false (g_value_type_transformable (G_TYPE_STRING, G_TYPE_CHAR));
g_value_init (&src, G_TYPE_STRING);
g_value_init (&dest, G_TYPE_CHAR);
g_value_set_static_string (&src, "bla");
g_value_set_schar (&dest, 'c');
- g_assert (!g_value_transform (&src, &dest));
+ g_assert_false (g_value_transform (&src, &dest));
g_assert_cmpint (g_value_get_schar (&dest), ==, 'c');
g_value_unset (&src);
g_value_unset (&dest);
@@ -757,7 +777,7 @@ test_param_implement (void)
{
case 0:
/* make sure the other table agrees */
- g_assert (valid_impl_types[change_this_type * 16 + change_this_flag][use_this_type] == 0);
+ g_assert_cmpint (valid_impl_types[change_this_type * 16 + change_this_flag][use_this_type], ==, 0);
g_test_trap_assert_failed ();
g_test_trap_assert_stderr ("*Interface property does not exist*");
continue;
@@ -820,7 +840,7 @@ test_param_default (void)
param = g_param_spec_int ("my-int", "My Int", "Blurb", 0, 20, 10, G_PARAM_READWRITE);
def = g_param_spec_get_default_value (param);
- g_assert (G_VALUE_HOLDS (def, G_TYPE_INT));
+ g_assert_true (G_VALUE_HOLDS (def, G_TYPE_INT));
g_assert_cmpint (g_value_get_int (def), ==, 10);
g_param_spec_unref (param);
@@ -836,6 +856,9 @@ main (int argc, char *argv[])
g_test_add_func ("/param/value", test_param_value);
g_test_add_func ("/param/strings", test_param_strings);
+ g_test_add_data_func ("/param/invalid-name/colon", "my_int:hello", test_param_invalid_name);
+ g_test_add_data_func ("/param/invalid-name/first-char", "7zip", test_param_invalid_name);
+ g_test_add_data_func ("/param/invalid-name/empty", "", test_param_invalid_name);
g_test_add_func ("/param/qdata", test_param_qdata);
g_test_add_func ("/param/validate", test_param_validate);
g_test_add_func ("/param/convert", test_param_convert);
diff --git a/gobject/tests/reference.c b/gobject/tests/reference.c
index 9508ee741..c6f4d5127 100644
--- a/gobject/tests/reference.c
+++ b/gobject/tests/reference.c
@@ -218,6 +218,35 @@ test_set_function (void)
}
static void
+test_set_derived_type (void)
+{
+ GBinding *obj = NULL;
+ GObject *o = NULL;
+ GBinding *b = NULL;
+
+ g_test_summary ("Check that g_set_object() doesn’t give strict aliasing "
+ "warnings when used on types derived from GObject");
+
+ g_assert_false (g_set_object (&o, NULL));
+ g_assert_null (o);
+
+ g_assert_false (g_set_object (&b, NULL));
+ g_assert_null (b);
+
+ obj = g_object_new (my_object_get_type (), NULL);
+
+ g_assert_true (g_set_object (&o, G_OBJECT (obj)));
+ g_assert_true (o == G_OBJECT (obj));
+
+ g_assert_true (g_set_object (&b, obj));
+ g_assert_true (b == obj);
+
+ g_object_unref (obj);
+ g_clear_object (&b);
+ g_clear_object (&o);
+}
+
+static void
toggle_cb (gpointer data, GObject *obj, gboolean is_last)
{
gboolean *b = data;
@@ -774,6 +803,7 @@ main (int argc, char **argv)
g_test_add_func ("/object/clear-function", test_clear_function);
g_test_add_func ("/object/set", test_set);
g_test_add_func ("/object/set-function", test_set_function);
+ g_test_add_func ("/object/set/derived-type", test_set_derived_type);
g_test_add_func ("/object/value", test_object_value);
g_test_add_func ("/object/initially-unowned", test_initially_unowned);
g_test_add_func ("/object/weak-pointer", test_weak_pointer);
diff --git a/gobject/tests/signals.c b/gobject/tests/signals.c
index 44e3f6217..ae8bd9dc2 100644
--- a/gobject/tests/signals.c
+++ b/gobject/tests/signals.c
@@ -180,7 +180,16 @@ test_class_init (TestClass *klass)
NULL,
G_TYPE_NONE,
0);
- simple2_id = g_signal_new ("simple-2",
+ g_signal_new ("simple-detailed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE,
+ 0);
+ /* Deliberately install this one in non-canonical form to check that’s handled correctly: */
+ simple2_id = g_signal_new ("simple_2",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
0,
@@ -455,16 +464,16 @@ test_variant_signal (void)
v = g_variant_new_boolean (TRUE);
g_variant_ref (v);
- g_assert (g_variant_is_floating (v));
+ g_assert_true (g_variant_is_floating (v));
g_signal_emit_by_name (test, "variant-changed-no-slot", v);
- g_assert (!g_variant_is_floating (v));
+ g_assert_false (g_variant_is_floating (v));
g_variant_unref (v);
v = g_variant_new_boolean (TRUE);
g_variant_ref (v);
- g_assert (g_variant_is_floating (v));
+ g_assert_true (g_variant_is_floating (v));
g_signal_emit_by_name (test, "variant-changed", v);
- g_assert (!g_variant_is_floating (v));
+ g_assert_false (g_variant_is_floating (v));
g_variant_unref (v);
g_object_unref (test);
@@ -485,7 +494,7 @@ on_generic_marshaller_1 (Test *obj,
g_assert_cmpint (v_uchar, ==, 43);
g_assert_cmpint (v_int, ==, 4096);
g_assert_cmpint (v_long, ==, 8192);
- g_assert (v_pointer == NULL);
+ g_assert_null (v_pointer);
g_assert_cmpfloat (v_double, >, 0.0);
g_assert_cmpfloat (v_double, <, 1.0);
g_assert_cmpfloat (v_float, >, 5.0);
@@ -754,7 +763,7 @@ custom_marshaller_callback (Test *test,
{
GSignalInvocationHint *ihint;
- g_assert (hint != &dont_use_this);
+ g_assert_true (hint != &dont_use_this);
ihint = g_signal_get_invocation_hint (test);
@@ -801,7 +810,7 @@ all_types_handler (Test *test, int i, gboolean b, char c, guchar uc, guint ui, g
g_assert_cmpstr (str, ==, "Test");
g_assert_cmpstr (g_param_spec_get_nick (param), ==, "nick");
g_assert_cmpstr (g_bytes_get_data (bytes, NULL), ==, "Blah");
- g_assert (ptr == &enum_type);
+ g_assert_true (ptr == &enum_type);
g_assert_cmpuint (g_variant_get_uint16 (var), == , 99);
g_assert_cmpint (i64, ==, G_MAXINT64 - 1234);
g_assert_cmpuint (ui64, ==, G_MAXUINT64 - 123456);
@@ -810,7 +819,7 @@ all_types_handler (Test *test, int i, gboolean b, char c, guchar uc, guint ui, g
static void
all_types_handler_cb (Test *test, int i, gboolean b, char c, guchar uc, guint ui, glong l, gulong ul, MyEnum e, guint f, float fl, double db, char *str, GParamSpec *param, GBytes *bytes, gpointer ptr, Test *obj, GVariant *var, gint64 i64, guint64 ui64, gpointer user_data)
{
- g_assert (user_data == &flags_type);
+ g_assert_true (user_data == &flags_type);
all_types_handler (test, i, b, c, uc, ui, l, ul, e, f, fl, db, str, param, bytes, ptr, obj, var, i64, ui64);
}
@@ -1064,6 +1073,7 @@ test_introspection (void)
gint i;
const gchar *names[] = {
"simple",
+ "simple-detailed",
"simple-2",
"generic-marshaller-1",
"generic-marshaller-2",
@@ -1091,15 +1101,15 @@ test_introspection (void)
for (i = 0; i < n_ids; i++)
{
name = g_signal_name (ids[i]);
- g_assert (in_set (name, names));
+ g_assert_true (in_set (name, names));
}
g_signal_query (simple_id, &query);
g_assert_cmpuint (query.signal_id, ==, simple_id);
g_assert_cmpstr (query.signal_name, ==, "simple");
- g_assert (query.itype == test_get_type ());
- g_assert (query.signal_flags == G_SIGNAL_RUN_LAST);
- g_assert (query.return_type == G_TYPE_NONE);
+ g_assert_true (query.itype == test_get_type ());
+ g_assert_cmpint (query.signal_flags, ==, G_SIGNAL_RUN_LAST);
+ g_assert_cmpint (query.return_type, ==, G_TYPE_NONE);
g_assert_cmpuint (query.n_params, ==, 0);
g_free (ids);
@@ -1129,7 +1139,7 @@ test_block_handler (void)
handler = g_signal_handler_find (test1, G_SIGNAL_MATCH_ID, simple_id, 0, NULL, NULL, NULL);
- g_assert (handler == handler1);
+ g_assert_true (handler == handler1);
g_assert_cmpint (count1, ==, 0);
g_assert_cmpint (count2, ==, 0);
@@ -1238,7 +1248,7 @@ test_signal_disconnect_wrong_object (void)
g_test_assert_expected_messages ();
/* it's still connected */
- g_assert (g_signal_handler_is_connected (object, signal_id));
+ g_assert_true (g_signal_handler_is_connected (object, signal_id));
g_object_unref (object);
g_object_unref (object2);
@@ -1276,6 +1286,172 @@ test_clear_signal_handler (void)
g_object_unref (test_obj);
}
+static void
+test_lookup (void)
+{
+ GTypeClass *test_class;
+ guint signal_id, saved_signal_id;
+
+ g_test_summary ("Test that g_signal_lookup() works with a variety of inputs.");
+
+ test_class = g_type_class_ref (test_get_type ());
+
+ signal_id = g_signal_lookup ("all-types", test_get_type ());
+ g_assert_cmpint (signal_id, !=, 0);
+
+ saved_signal_id = signal_id;
+
+ /* Try with a non-canonical name. */
+ signal_id = g_signal_lookup ("all_types", test_get_type ());
+ g_assert_cmpint (signal_id, ==, saved_signal_id);
+
+ /* Looking up a non-existent signal should return nothing. */
+ g_assert_cmpint (g_signal_lookup ("nope", test_get_type ()), ==, 0);
+
+ g_type_class_unref (test_class);
+}
+
+static void
+test_lookup_invalid (void)
+{
+ g_test_summary ("Test that g_signal_lookup() emits a warning if looking up an invalid signal name.");
+
+ if (g_test_subprocess ())
+ {
+ GTypeClass *test_class;
+ guint signal_id;
+
+ test_class = g_type_class_ref (test_get_type ());
+
+ signal_id = g_signal_lookup ("", test_get_type ());
+ g_assert_cmpint (signal_id, ==, 0);
+
+ g_type_class_unref (test_class);
+ return;
+ }
+
+ g_test_trap_subprocess (NULL, 0, 0);
+ g_test_trap_assert_failed ();
+ g_test_trap_assert_stderr ("*WARNING*unable to look up invalid signal name*");
+}
+
+static void
+test_parse_name (void)
+{
+ GTypeClass *test_class;
+ guint signal_id, saved_signal_id;
+ gboolean retval;
+ GQuark detail, saved_detail;
+
+ g_test_summary ("Test that g_signal_parse_name() works with a variety of inputs.");
+
+ test_class = g_type_class_ref (test_get_type ());
+
+ /* Simple test. */
+ retval = g_signal_parse_name ("simple-detailed", test_get_type (), &signal_id, &detail, TRUE);
+ g_assert_true (retval);
+ g_assert_cmpint (signal_id, !=, 0);
+ g_assert_cmpint (detail, ==, 0);
+
+ saved_signal_id = signal_id;
+
+ /* Simple test with detail. */
+ retval = g_signal_parse_name ("simple-detailed::a-detail", test_get_type (), &signal_id, &detail, TRUE);
+ g_assert_true (retval);
+ g_assert_cmpint (signal_id, ==, saved_signal_id);
+ g_assert_cmpint (detail, !=, 0);
+
+ saved_detail = detail;
+
+ /* Simple test with the same detail again. */
+ retval = g_signal_parse_name ("simple-detailed::a-detail", test_get_type (), &signal_id, &detail, FALSE);
+ g_assert_true (retval);
+ g_assert_cmpint (signal_id, ==, saved_signal_id);
+ g_assert_cmpint (detail, ==, saved_detail);
+
+ /* Simple test with a new detail. */
+ retval = g_signal_parse_name ("simple-detailed::another-detail", test_get_type (), &signal_id, &detail, FALSE);
+ g_assert_true (retval);
+ g_assert_cmpint (signal_id, ==, saved_signal_id);
+ g_assert_cmpint (detail, ==, 0); /* we didn’t force the quark */
+
+ /* Canonicalisation shouldn’t affect the results. */
+ retval = g_signal_parse_name ("simple_detailed::a-detail", test_get_type (), &signal_id, &detail, FALSE);
+ g_assert_true (retval);
+ g_assert_cmpint (signal_id, ==, saved_signal_id);
+ g_assert_cmpint (detail, ==, saved_detail);
+
+ /* Details don’t have to look like property names. */
+ retval = g_signal_parse_name ("simple-detailed::hello::world", test_get_type (), &signal_id, &detail, TRUE);
+ g_assert_true (retval);
+ g_assert_cmpint (signal_id, ==, saved_signal_id);
+ g_assert_cmpint (detail, !=, 0);
+
+ /* Trying to parse a detail for a signal which isn’t %G_SIGNAL_DETAILED should fail. */
+ retval = g_signal_parse_name ("all-types::a-detail", test_get_type (), &signal_id, &detail, FALSE);
+ g_assert_false (retval);
+
+ g_type_class_unref (test_class);
+}
+
+static void
+test_parse_name_invalid (void)
+{
+ GTypeClass *test_class;
+ gsize i;
+ guint signal_id;
+ GQuark detail;
+ const gchar *vectors[] =
+ {
+ "",
+ "7zip",
+ "invalid:signal",
+ "simple-detailed::",
+ "simple-detailed:",
+ ":",
+ "::",
+ ":valid-detail",
+ "::valid-detail",
+ };
+
+ g_test_summary ("Test that g_signal_parse_name() ignores a variety of invalid inputs.");
+
+ test_class = g_type_class_ref (test_get_type ());
+
+ for (i = 0; i < G_N_ELEMENTS (vectors); i++)
+ {
+ g_test_message ("Parser input: %s", vectors[i]);
+ g_assert_false (g_signal_parse_name (vectors[i], test_get_type (), &signal_id, &detail, TRUE));
+ }
+
+ g_type_class_unref (test_class);
+}
+
+static void
+test_signals_invalid_name (gconstpointer test_data)
+{
+ const gchar *signal_name = test_data;
+
+ g_test_summary ("Check that g_signal_new() rejects invalid signal names.");
+
+ if (g_test_subprocess ())
+ {
+ g_signal_new (signal_name,
+ test_get_type (),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE,
+ 0);
+ return;
+ }
+
+ g_test_trap_subprocess (NULL, 0, 0);
+ g_test_trap_assert_failed ();
+ g_test_trap_assert_stderr ("*CRITICAL*is_valid_signal_name (signal_name)*");
+}
+
/* --- */
int
@@ -1302,6 +1478,13 @@ main (int argc,
g_test_add_func ("/gobject/signals/invocation-hint", test_invocation_hint);
g_test_add_func ("/gobject/signals/test-disconnection-wrong-object", test_signal_disconnect_wrong_object);
g_test_add_func ("/gobject/signals/clear-signal-handler", test_clear_signal_handler);
+ g_test_add_func ("/gobject/signals/lookup", test_lookup);
+ g_test_add_func ("/gobject/signals/lookup/invalid", test_lookup_invalid);
+ g_test_add_func ("/gobject/signals/parse-name", test_parse_name);
+ g_test_add_func ("/gobject/signals/parse-name/invalid", test_parse_name_invalid);
+ g_test_add_data_func ("/gobject/signals/invalid-name/colon", "my_int:hello", test_signals_invalid_name);
+ g_test_add_data_func ("/gobject/signals/invalid-name/first-char", "7zip", test_signals_invalid_name);
+ g_test_add_data_func ("/gobject/signals/invalid-name/empty", "", test_signals_invalid_name);
return g_test_run ();
}
diff --git a/gobject/tests/testing.c b/gobject/tests/testing.c
new file mode 100644
index 000000000..5c7e663bf
--- /dev/null
+++ b/gobject/tests/testing.c
@@ -0,0 +1,71 @@
+/* GLib testing framework examples and tests
+ *
+ * Copyright © 2019 Endless Mobile, Inc.
+ *
+ * This library 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.
+ *
+ * This library 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 this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Philip Withnall <withnall@endlessm.com>
+ */
+
+#include "config.h"
+
+/* We want to distinguish between messages originating from libglib
+ * and messages originating from this program.
+ */
+#undef G_LOG_DOMAIN
+#define G_LOG_DOMAIN "testing"
+
+#include <glib.h>
+#include <glib-object.h>
+#include <locale.h>
+#include <stdlib.h>
+
+static void
+test_assert_finalize_object_subprocess_bad (void)
+{
+ GObject *obj = g_object_new (G_TYPE_OBJECT, NULL);
+ g_object_ref (obj);
+
+ /* This should emit an assertion failure. */
+ g_assert_finalize_object (obj);
+
+ g_object_unref (obj);
+
+ exit (0);
+}
+
+static void
+test_assert_finalize_object (void)
+{
+ GObject *obj = g_object_new (G_TYPE_OBJECT, NULL);
+
+ g_assert_finalize_object (obj);
+
+ g_test_trap_subprocess ("/assert/finalize_object/subprocess/bad", 0, 0);
+ g_test_trap_assert_failed ();
+ g_test_trap_assert_stderr ("*g_assert_finalize_object:*'weak_pointer' should be NULL*");
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/assert/finalize_object", test_assert_finalize_object);
+ g_test_add_func ("/assert/finalize_object/subprocess/bad",
+ test_assert_finalize_object_subprocess_bad);
+
+ return g_test_run ();
+}