run tests in current dir after setting up the logging directory, so their

2007-12-05 18:59:59  Tim Janik  <timj@imendio.com>

        * gtk+/Makefile.decl: run tests in current dir after setting up the
        logging directory, so their results get properly merged into the
        resulting test log.

        * gtk+/gtk/gtktestutils.[hc]: added gtk_test_list_all_types() for
        tests to loop over registered Gdk/Gtk+ types.

        * gtk+/tests/objecttests.c: new test program, implements automated
        property tests. several properties are blacklisted because they
        seem to trigger Gdk/Gtk+ bugs. ./objecttests -m thorough --verbose
        can be used to test blacklisted properties and see which proprty failed.



svn path=/trunk/; revision=19115
This commit is contained in:
18:59:59 Tim Janik 2007-12-05 16:58:44 +00:00 committed by Tim Janik
parent 4a82f84a28
commit 9ba5da2f36
8 changed files with 424 additions and 18 deletions

View File

@ -1,3 +1,17 @@
2007-12-05 18:59:59 Tim Janik <timj@imendio.com>
* gtk+/Makefile.decl: run tests in current dir after setting up the
logging directory, so their results get properly merged into the
resulting test log.
* gtk+/gtk/gtktestutils.[hc]: added gtk_test_list_all_types() for
tests to loop over registered Gdk/Gtk+ types.
* gtk+/tests/objecttests.c: new test program, implements automated
property tests. several properties are blacklisted because they
seem to trigger Gdk/Gtk+ bugs. ./objecttests -m thorough --verbose
can be used to test blacklisted properties and see which proprty failed.
2007-12-04 Richard Hult <richard@imendio.com>
* gdk/quartz/gdkwindow-quartz.c: (_gdk_windowing_window_init):

View File

@ -32,20 +32,6 @@ test: ${TEST_PROGS}
# perf-report: run tests in subdirs with -m perf and generate report
# full-report: like test-report: with -m perf and -m slow
test-report perf-report full-report: ${TEST_PROGS}
@test -z "${TEST_PROGS}" || { \
case $@ in \
test-report) test_options="-k";; \
perf-report) test_options="-k -m=perf";; \
full-report) test_options="-k -m=perf -m=slow";; \
esac ; \
$(XVFB_START) && { \
if test -z "$$GTESTER_LOGDIR" ; then \
${GTESTER} --verbose $$test_options -o test-report.xml ${TEST_PROGS} ; \
elif test -n "${TEST_PROGS}" ; then \
${GTESTER} --verbose $$test_options -o `mktemp "$$GTESTER_LOGDIR/log-XXXXXX"` ${TEST_PROGS} ; \
fi ; \
} \
}
@ ignore_logdir=true ; \
if test -z "$$GTESTER_LOGDIR" ; then \
GTESTER_LOGDIR=`mktemp -d "\`pwd\`/.testlogs-XXXXXX"`; export GTESTER_LOGDIR ; \
@ -55,6 +41,20 @@ test-report perf-report full-report: ${TEST_PROGS}
test "$$subdir" = "." -o "$$subdir" = "po" -o "$$subdir" = "po-properties" || \
( cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $? ; \
done ; \
test -z "${TEST_PROGS}" || { \
case $@ in \
test-report) test_options="-k";; \
perf-report) test_options="-k -m=perf";; \
full-report) test_options="-k -m=perf -m=slow";; \
esac ; \
$(XVFB_START) && { \
if test -z "$$GTESTER_LOGDIR" ; then \
${GTESTER} --verbose $$test_options -o test-report.xml ${TEST_PROGS} ; \
elif test -n "${TEST_PROGS}" ; then \
${GTESTER} --verbose $$test_options -o `mktemp "$$GTESTER_LOGDIR/log-XXXXXX"` ${TEST_PROGS} ; \
fi ; \
}; \
}; \
$$ignore_logdir || { \
echo '<?xml version="1.0"?>' > $@.xml ; \
echo '<report-collection>' >> $@.xml ; \

View File

@ -817,7 +817,7 @@ gtktypefuncs.c: @REBUILD@ $(top_srcdir)/gtk/*.h $(top_srcdir)/gdk/*.h Makefile
${CPP} $(DEFS) $(INCLUDES) -DGTK_ENABLE_BROKEN $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) xgen-gtfsrc.c | \
grep -o '\bg[td]k_[a-zA-Z0-9_]*_get_type\b' | \
sort | uniq | \
sed '{ s/^/vgt=/; s/$$/();/; }' > xgen-gtf \
sed '{ s/^/*tp++ = /; s/$$/();/; }' > xgen-gtf \
&& cp xgen-gtf $@ && rm -f xgen-gtf
gtktestutils.c: gtktypefuncs.c

View File

@ -3263,6 +3263,7 @@ gtk_test_find_sibling
gtk_test_find_widget
gtk_test_init
gtk_test_register_all_types
gtk_test_list_all_types
gtk_test_slider_get_value
gtk_test_slider_set_perc
gtk_test_spin_button_click

View File

@ -60,7 +60,6 @@ gtk_test_init (int *argcp,
* FUTURE TODO:
* - this function could install a mock object around GtkSettings
*/
// FIXME: g_test_init (argcp, argvp, NULL);
g_setenv ("GTK_MODULES", "", TRUE);
g_setenv ("GTK2_RC_FILES", "/dev/null", TRUE);
gtk_disable_setlocale();
@ -570,6 +569,25 @@ gtk_test_create_simple_window (const gchar *window_title,
return window;
}
static GType *all_registered_types = NULL;
static guint n_all_registered_types = 0;
/**
* gtk_test_list_all_types
* @n_types: location to store number of types
* @returns: 0-terminated array of type ids
*
* Return the type ids that have been registered after
* calling gtk_test_register_all_types().
**/
const GType*
gtk_test_list_all_types (guint *n_types)
{
if (n_types)
*n_types = n_all_registered_types;
return all_registered_types;
}
/**
* gtk_test_register_all_types
*
@ -580,8 +598,17 @@ gtk_test_create_simple_window (const gchar *window_title,
void
gtk_test_register_all_types (void)
{
volatile GType vgt;
if (!all_registered_types)
{
const guint max_gtk_types = 999;
GType *tp;
all_registered_types = g_new0 (GType, max_gtk_types);
tp = all_registered_types;
#include "gtktypefuncs.c"
n_all_registered_types = tp - all_registered_types;
g_assert (n_all_registered_types + 1 < max_gtk_types);
*tp = 0;
}
}
#define __GTK_TEST_UTILS_C__

View File

@ -30,6 +30,7 @@ void gtk_test_init (int *argcp,
char ***argvp,
...);
void gtk_test_register_all_types (void);
const GType* gtk_test_list_all_types (guint *n_types);
GtkWidget* gtk_test_find_widget (GtkWidget *widget,
const gchar *label_pattern,
GType widget_type);

View File

@ -25,9 +25,16 @@ if USE_X11
testsocket_programs = testsocket testsocket_child
endif
TEST_PROGS += objecttests
objecttests_SOURCES = objecttests.c
objecttests_LDADD = $(LDADDS)
objecttests_DEPENDENCIES = $(TEST_DEPS)
TESTS = floatingtest buildertest
noinst_PROGRAMS = \
noinst_PROGRAMS = $(TEST_PROGS) \
autotestfilechooser \
autotestkeywords \
floatingtest \

356
tests/objecttests.c Normal file
View File

@ -0,0 +1,356 @@
/* Gtk+ object tests
* Copyright (C) 2007 Imendio AB
* Authors: Tim Janik
*
* 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 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, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <gtk/gtk.h>
#include <string.h>
/* --- helper macros for property value generation --- */
/* dvalue=+0: generate minimum value
* dvalue=.x: generate value within value range proportional to x.
* dvalue=+1: generate maximum value
* dvalue=-1: generate random value within value range
* dvalue=+2: initialize value from default_value
*/
#define ASSIGN_VALUE(__g_value_set_func, __value, PSPECTYPE, __pspec, __default_value, __minimum, __maximum, __dvalue) do { \
PSPECTYPE __p = (PSPECTYPE) __pspec; \
__g_value_set_func (__value, SELECT_VALUE (__dvalue, __p->__default_value, __p->__minimum, __p->__maximum)); \
} while (0)
#define SELECT_VALUE(__dvalue, __default_value, __minimum, __maximum) ( \
__dvalue >= 0 && __dvalue <= 1 ? __minimum * (1 - __dvalue) + __dvalue * __maximum : \
__dvalue <= -1 ? g_test_rand_double_range (__minimum, __maximum) : \
__default_value)
#define SELECT_NAME(__dvalue) ( \
__dvalue == 0 ? "minimum" : \
__dvalue == 1 ? "maximum" : \
__dvalue >= +2 ? "default" : \
__dvalue == 0.5 ? "medium" : \
__dvalue > 0 && __dvalue < 1 ? "fractional" : \
"random")
#define MATCH_ANY_VALUE ((void*) 0xf1874c23)
/* --- variables --- */
static const char * const the_empty_string = ""; // use this constant to allow pointer comparisons of ""
/* --- property blacklists --- */
typedef struct {
const char *type_name;
const char *name;
gconstpointer value;
} IgnoreProperty;
static const IgnoreProperty*
list_ignore_properties (gboolean buglist)
{
/* currently untestable properties */
static const IgnoreProperty ignore_properties[] = {
{ "GtkContainer", "child", NULL, }, /* needs working child widget */
{ "GtkRadioMenuItem", "group", NULL, }, /* needs working sibling */
{ "GtkWidget", "parent", NULL, }, /* needs working parent widget */
{ "GtkCList", "selection-mode", (void*) GTK_SELECTION_NONE, },
{ "GtkWidget", "has-default", (void*) TRUE, }, /* conflicts with toplevel-less widgets */
{ "GtkWidget", "screen", NULL, },
{ "GtkWindow", "type-hint", (void*) GDK_WINDOW_TYPE_HINT_DND, }, /* conflicts with ::visible=TRUE */
{ "GtkCellView", "background", (void*) the_empty_string, }, /* "" is not a valid background color */
{ "GtkColorButton", "color", (void*) NULL, }, /* not a valid boxed color */
{ "GtkInputDialog", "has-separator", (void*) MATCH_ANY_VALUE, }, /* property disabled */
{ "GtkMessageDialog", "has-separator", (void*) MATCH_ANY_VALUE, }, /* property disabled */
{ "GtkFontSelectionDialog", "has-separator", (void*) MATCH_ANY_VALUE, }, /* property disabled */
{ "GtkColorSelectionDialog","has-separator", (void*) MATCH_ANY_VALUE, }, /* property disabled */
{ "GtkColorSelection", "child", NULL, },
{ "GtkColorSelection", "current-color", (void*) NULL, }, /* not a valid boxed color */
{ "GtkComboBox", "row-span-column", (void*) MATCH_ANY_VALUE }, /* GtkComboBoxEntry needs a tree model for this */
{ "GtkComboBox", "column-span-column", (void*) MATCH_ANY_VALUE }, /* GtkComboBoxEntry needs a tree model for this */
{ "GtkComboBoxEntry", "text-column", (void*) MATCH_ANY_VALUE }, /* GtkComboBoxEntry needs a tree model for this */
{ "GtkFileChooserButton", "select-multiple", (void*) MATCH_ANY_VALUE }, /* property disabled */
{ "GtkFileChooserButton", "action", (void*) GTK_FILE_CHOOSER_ACTION_SAVE },
{ "GtkFileChooserButton", "action", (void*) GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER },
{ "GtkFileChooserWidget", "select-multiple", (void*) 0x1 }, /* property conflicts */
{ "GtkFileChooserDialog", "select-multiple", (void*) MATCH_ANY_VALUE }, /* property disabled */
{ "GtkRecentChooserMenu", "select-multiple", (void*) MATCH_ANY_VALUE }, /* property disabled */
{ "GtkTextView", "overwrite", (void*) MATCH_ANY_VALUE }, /* needs text buffer */
{ "GtkToolbar", "icon-size", (void*) GTK_ICON_SIZE_INVALID },
{ NULL, NULL, NULL }
};
/* properties suspected to be Gdk/Gtk+ bugs */
static const IgnoreProperty bug_properties[] = {
{ "GtkMessageDialog", "image", NULL, }, /* FIXME: should accept NULL images */
{ "GtkOptionMenu", "menu", NULL, }, /* FIXME: should accept NULL menus */
{ "GtkComboBox", "active", (void*) MATCH_ANY_VALUE }, /* FIXME: triggers NULL model bug */
{ "GtkComboBoxEntry", "text-column", (void*) 0xffffffff }, /* FIXME: triggers signedness bug */
{ "GtkCTree", "indent", (void*) MATCH_ANY_VALUE }, /* FIXME: triggers signedness bug */
{ "GtkCTree", "spacing", (void*) MATCH_ANY_VALUE }, /* FIXME: triggers signedness bug */
{ "GtkCurve", "curve-type", (void*) MATCH_ANY_VALUE }, /* FIXME: triggers OOM */
{ "GtkCurve", "min-x", (void*) 0x80000000 }, /* FIXME: triggers coordinate OOB */
{ "GtkCurve", "min-y", (void*) 0x80000000 }, /* FIXME: triggers coordinate OOB */
{ "GtkCurve", "max-x", (void*) 0x80000000 }, /* FIXME: triggers coordinate OOB */
{ "GtkCurve", "max-y", (void*) 0x80000000 }, /* FIXME: triggers coordinate OOB */
{ "GtkFileChooserButton", "local-only", (void*) MATCH_ANY_VALUE }, /* FIXME: triggers NULL path assertion */
{ "GtkFileChooserDialog", "local-only", (void*) MATCH_ANY_VALUE }, /* FIXME: triggers NULL path assertion */
{ "GtkFileChooserDialog", "action", (void*) MATCH_ANY_VALUE }, /* FIXME: triggers closure->ref_count assertion */
{ "GtkFileChooserDialog", "visible", (void*) TRUE }, /* FIXME: triggers gtk_window_resize assertion */
{ "GtkFileChooserWidget", "local-only", (void*) MATCH_ANY_VALUE }, /* FIXME: triggers NULL path assertion */
{ "GtkFontSelection", "font-name", (void*) MATCH_ANY_VALUE }, /* FIXME: requires non-NULL GdkScreen */
{ "GtkInvisible", "has-focus", (void*) TRUE }, /* FIXME: triggers invalid window cast */
{ "GtkInvisible", "is-focus", (void*) TRUE }, /* FIXME: triggers invalid window cast */
{ "GtkMenu", "tearoff-state", (void*) MATCH_ANY_VALUE }, /* FIXME: triggers NULL widget cast */
{ "GtkProgress", "activity-mode", (void*) TRUE }, /* FIXME: segfaults */
{ "GtkScaleButton", "adjustment", NULL, }, /* FIXME: should accept NULL adjustments */
{ "GtkStatusbar", "sensitive", (void*) FALSE }, /* FIXME: check if widget is realize */
{ "GtkTable", "n-rows", (void*) MATCH_ANY_VALUE }, /* FIXME: fix property minimum/maximum */
{ "GtkTable", "n-columns", (void*) MATCH_ANY_VALUE }, /* FIXME: fix property minimum/maximum */
{ "GtkText", "text-position", (void*) MATCH_ANY_VALUE }, /* FIXME: segfaults, fix property minimum/maximum */
{ NULL, NULL, NULL }
};
if (buglist)
return bug_properties;
else
return ignore_properties;
}
/* --- test functions --- */
static void
pspec_select_value (GParamSpec *pspec,
GValue *value,
double dvalue)
{
/* generate a value suitable for pspec */
if (G_IS_PARAM_SPEC_CHAR (pspec))
ASSIGN_VALUE (g_value_set_char, value, GParamSpecChar*, pspec, default_value, minimum, maximum, dvalue);
else if (G_IS_PARAM_SPEC_UCHAR (pspec))
ASSIGN_VALUE (g_value_set_uchar, value, GParamSpecUChar*, pspec, default_value, minimum, maximum, dvalue);
else if (G_IS_PARAM_SPEC_INT (pspec))
ASSIGN_VALUE (g_value_set_int, value, GParamSpecInt*, pspec, default_value, minimum, maximum, dvalue);
else if (G_IS_PARAM_SPEC_UINT (pspec))
ASSIGN_VALUE (g_value_set_uint, value, GParamSpecUInt*, pspec, default_value, minimum, maximum, dvalue);
else if (G_IS_PARAM_SPEC_LONG (pspec))
ASSIGN_VALUE (g_value_set_long, value, GParamSpecLong*, pspec, default_value, minimum, maximum, dvalue);
else if (G_IS_PARAM_SPEC_ULONG (pspec))
ASSIGN_VALUE (g_value_set_ulong, value, GParamSpecULong*, pspec, default_value, minimum, maximum, dvalue);
else if (G_IS_PARAM_SPEC_INT64 (pspec))
ASSIGN_VALUE (g_value_set_int64, value, GParamSpecInt64*, pspec, default_value, minimum, maximum, dvalue);
else if (G_IS_PARAM_SPEC_UINT64 (pspec))
ASSIGN_VALUE (g_value_set_uint64, value, GParamSpecUInt64*, pspec, default_value, minimum, maximum, dvalue);
else if (G_IS_PARAM_SPEC_FLOAT (pspec))
ASSIGN_VALUE (g_value_set_float, value, GParamSpecFloat*, pspec, default_value, minimum, maximum, dvalue);
else if (G_IS_PARAM_SPEC_DOUBLE (pspec))
ASSIGN_VALUE (g_value_set_double, value, GParamSpecDouble*, pspec, default_value, minimum, maximum, dvalue);
else if (G_IS_PARAM_SPEC_BOOLEAN (pspec))
g_value_set_boolean (value, SELECT_VALUE (dvalue, ((GParamSpecBoolean*) pspec)->default_value, FALSE, TRUE));
else if (G_IS_PARAM_SPEC_UNICHAR (pspec))
g_value_set_uint (value, SELECT_VALUE (dvalue, ((GParamSpecUnichar*) pspec)->default_value, FALSE, TRUE));
else if (G_IS_PARAM_SPEC_GTYPE (pspec))
g_value_set_gtype (value, SELECT_VALUE ((int) dvalue, ((GParamSpecGType*) pspec)->is_a_type, 0, GTK_TYPE_WIDGET));
else if (G_IS_PARAM_SPEC_STRING (pspec))
{
GParamSpecString *sspec = (GParamSpecString*) pspec;
if (dvalue >= +2)
g_value_set_string (value, sspec->default_value);
if (dvalue > 0 && sspec->cset_first && sspec->cset_nth)
g_value_take_string (value, g_strdup_printf ("%c%c", sspec->cset_first[0], sspec->cset_nth[0]));
else /* if (sspec->ensure_non_null) */
g_value_set_string (value, "");
if (g_value_get_string (value) && strcmp (g_value_get_string (value), the_empty_string) == 0)
g_value_set_static_string (value, the_empty_string); // allow pointer comparisons of ""
}
else if (G_IS_PARAM_SPEC_ENUM (pspec))
{
GParamSpecEnum *espec = (GParamSpecEnum*) pspec;
if (dvalue >= +2)
g_value_set_enum (value, espec->default_value);
if (dvalue >= 0 && dvalue <= 1)
g_value_set_enum (value, espec->enum_class->values[(int) ((espec->enum_class->n_values - 1) * dvalue)].value);
else if (dvalue <= -1)
g_value_set_enum (value, espec->enum_class->values[g_test_rand_int_range (0, espec->enum_class->n_values)].value);
}
else if (G_IS_PARAM_SPEC_FLAGS (pspec))
{
GParamSpecFlags *fspec = (GParamSpecFlags*) pspec;
if (dvalue >= +2)
g_value_set_flags (value, fspec->default_value);
if (dvalue >= 0 && dvalue <= 1)
g_value_set_flags (value, fspec->flags_class->values[(int) ((fspec->flags_class->n_values - 1) * dvalue)].value);
else if (dvalue <= -1)
g_value_set_flags (value, fspec->flags_class->values[g_test_rand_int_range (0, fspec->flags_class->n_values)].value);
}
/* unimplemented:
* G_IS_PARAM_SPEC_PARAM
* G_IS_PARAM_SPEC_BOXED
* G_IS_PARAM_SPEC_POINTER
* G_IS_PARAM_SPEC_VALUE_ARRAY
* G_IS_PARAM_SPEC_OBJECT
*/
}
static gpointer
value_as_pointer (GValue *value)
{
if (g_value_fits_pointer (value))
return g_value_peek_pointer (value);
if (G_VALUE_HOLDS_BOOLEAN (value))
return (void*) g_value_get_boolean (value);
if (G_VALUE_HOLDS_CHAR (value))
return (void*) (gssize) g_value_get_char (value);
if (G_VALUE_HOLDS_UCHAR (value))
return (void*) (gsize) g_value_get_uchar (value);
if (G_VALUE_HOLDS_INT (value))
return (void*) g_value_get_int (value);
if (G_VALUE_HOLDS_UINT (value))
return (void*) g_value_get_uint (value);
if (G_VALUE_HOLDS_LONG (value))
return (void*) g_value_get_long (value);
if (G_VALUE_HOLDS_ULONG (value))
return (void*) g_value_get_ulong (value);
if (G_VALUE_HOLDS_FLOAT (value))
return (void*) (gssize) g_value_get_float (value);
if (G_VALUE_HOLDS_DOUBLE (value))
return (void*) (gssize) g_value_get_double (value);
if (G_VALUE_HOLDS_ENUM (value))
return (void*) (gssize) g_value_get_enum (value);
if (G_VALUE_HOLDS_FLAGS (value))
return (void*) (gsize) g_value_get_flags (value);
return (void*) 0x1373babe;
}
static void
object_test_property (GObject *object,
GParamSpec *pspec,
double dvalue)
{
/* test setting of a normal writable property */
if (pspec->flags & G_PARAM_WRITABLE &&
!(pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)))
{
GValue value = { 0, };
guint i;
const IgnoreProperty *ignore_properties;
/* select value to set */
g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
pspec_select_value (pspec, &value, dvalue);
/* ignore untestable properties */
ignore_properties = list_ignore_properties (FALSE);
for (i = 0; ignore_properties[i].name; i++)
if (g_type_is_a (G_OBJECT_TYPE (object), g_type_from_name (ignore_properties[i].type_name)) &&
strcmp (pspec->name, ignore_properties[i].name) == 0 &&
(MATCH_ANY_VALUE == ignore_properties[i].value ||
value_as_pointer (&value) == ignore_properties[i].value))
break;
/* ignore known property bugs if not testing thoroughly */
if (ignore_properties[i].name == NULL && !g_test_thorough())
{
ignore_properties = list_ignore_properties (TRUE);
for (i = 0; ignore_properties[i].name; i++)
if (g_type_is_a (G_OBJECT_TYPE (object), g_type_from_name (ignore_properties[i].type_name)) &&
strcmp (pspec->name, ignore_properties[i].name) == 0 &&
(MATCH_ANY_VALUE == ignore_properties[i].value ||
value_as_pointer (&value) == ignore_properties[i].value))
break;
}
/* assign unignored properties */
if (ignore_properties[i].name == NULL)
{
if (g_test_verbose())
g_print ("PropertyTest: %s::%s := (%s value (%s): %p)\n",
g_type_name (G_OBJECT_TYPE (object)), pspec->name,
SELECT_NAME (dvalue), g_type_name (G_VALUE_TYPE (&value)),
value_as_pointer (&value));
g_object_set_property (object, pspec->name, &value);
}
/* cleanups */
g_value_unset (&value);
}
}
static void
widget_test_properties (GtkWidget *widget,
double dvalue)
{
/* try setting all possible properties, according to dvalue */
guint i, n_pspecs = 0;
GParamSpec **pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (widget), &n_pspecs);
for (i = 0; i < n_pspecs; i++)
{
GParamSpec *pspec = pspecs[i];
if (pspec->flags & G_PARAM_WRITABLE &&
!(pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)))
object_test_property (G_OBJECT (widget), pspecs[i], dvalue);
}
g_free (pspecs);
}
static void
widget_fixups (GtkWidget *widget)
{
/* post-constructor for widgets that need additional settings to work correctly */
if (GTK_IS_COMBO_BOX_ENTRY (widget))
{
GtkListStore *store = gtk_list_store_new (1, G_TYPE_STRING);
g_object_set (widget, "model", store, "text-column", 0, NULL);
g_object_unref (store);
gtk_combo_box_append_text (GTK_COMBO_BOX (widget), "test text");
}
else if (GTK_IS_COMBO_BOX (widget))
{
GtkListStore *store = gtk_list_store_new (1, G_TYPE_STRING);
g_object_set (widget, "model", store, NULL);
g_object_unref (store);
gtk_combo_box_append_text (GTK_COMBO_BOX (widget), "test text");
}
}
static void
widget_property_tests (gconstpointer test_data)
{
GType wtype = (GType) test_data;
/* create widget */
GtkWidget *widget = gtk_widget_new (wtype, NULL);
g_object_ref_sink (widget);
widget_fixups (widget);
/* test property values */
widget_test_properties (widget, +2); /* test default_value */
widget_test_properties (widget, 0); /* test minimum */
widget_test_properties (widget, 0.5); /* test medium */
widget_test_properties (widget, 1); /* test maximum */
widget_test_properties (widget, -1); /* test random value */
/* cleanup */
gtk_widget_destroy (widget);
g_object_unref (widget);
}
/* --- main test program --- */
int
main (int argc,
char *argv[])
{
const GType *otypes;
guint i;
/* initialize test program */
gtk_test_init (&argc, &argv);
gtk_test_register_all_types();
/* install a property test for each widget type */
otypes = gtk_test_list_all_types (NULL);
for (i = 0; otypes[i]; i++)
if (g_type_is_a (otypes[i], GTK_TYPE_WIDGET) &&
G_TYPE_IS_OBJECT (otypes[i]) &&
!G_TYPE_IS_ABSTRACT (otypes[i]))
{
gchar *testpath = g_strdup_printf ("/properties/%s", g_type_name (otypes[i]));
g_test_add_data_func (testpath, (void*) otypes[i], widget_property_tests);
g_free (testpath);
}
return g_test_run();
}