tests: Move clutter-test-utils.[ch] to src/tests

And add the necessary glue so those initialize a X11 clutter backend.
This should get Clutter tests that are dependent on windowing to work
again, thus they were enabled back again.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/672
This commit is contained in:
Carlos Garnacho
2019-07-03 13:43:25 +02:00
committed by Jonas Ådahl
parent cfb8f18cef
commit cc7e843c44
29 changed files with 86 additions and 23 deletions

View File

@ -0,0 +1,458 @@
#include "clutter-test-utils.h"
#include <stdlib.h>
#include <glib-object.h>
#include <clutter/clutter.h>
typedef struct {
ClutterActor *stage;
guint no_display : 1;
} ClutterTestEnvironment;
static ClutterTestEnvironment *test_environ = NULL;
/*
* clutter_test_init:
* @argc: (inout): number of arguments in @argv
* @argv: (inout) (array length=argc) (nullable): array of arguments
*
* Initializes the Clutter test environment.
*
* Since: 1.18
*/
void
clutter_test_init (int *argc,
char ***argv)
{
gboolean no_display = FALSE;
if (G_UNLIKELY (test_environ != NULL))
g_error ("Attempting to initialize the test suite more than once, "
"aborting...\n");
#ifdef CLUTTER_WINDOWING_X11
/* on X11 backends we need the DISPLAY environment set.
*
* check_windowing_backend() will pre-initialize the Clutter
* backend object.
*/
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_X11))
{
const char *display = g_getenv ("DISPLAY");
if (display == NULL || *display == '\0')
{
g_test_message ("No DISPLAY environment variable found, but we require a "
"DISPLAY set in order to run the conformance test suite.\n"
"Skipping all tests.\n");
no_display = TRUE;
goto out;
}
}
#endif
/* we explicitly disable the synchronisation to the vertical refresh
* rate, and run the master clock using a 60 fps timer instead.
*/
_clutter_set_sync_to_vblank (FALSE);
/* perform the actual initialization */
g_assert (clutter_init (NULL, NULL) == CLUTTER_INIT_SUCCESS);
out:
g_test_init (argc, argv, NULL);
g_test_bug_base ("https://bugzilla.gnome.org/show_bug.cgi?id=%s");
/* our global state, accessible from each test unit */
test_environ = g_new0 (ClutterTestEnvironment, 1);
test_environ->no_display = no_display;
}
/**
* clutter_test_get_stage:
*
* Retrieves the #ClutterStage used for testing.
*
* Return value: (transfer none): the stage used for testing
*
* Since: 1.18
*/
ClutterActor *
clutter_test_get_stage (void)
{
g_assert (test_environ != NULL);
if (test_environ->stage == NULL)
{
/* create a stage, and ensure that it goes away at the end */
test_environ->stage = clutter_stage_new ();
clutter_actor_set_name (test_environ->stage, "Test Stage");
g_object_add_weak_pointer (G_OBJECT (test_environ->stage),
(gpointer *) &test_environ->stage);
}
return test_environ->stage;
}
typedef struct {
gpointer test_func;
gpointer test_data;
GDestroyNotify test_notify;
} ClutterTestData;
static void
clutter_test_func_wrapper (gconstpointer data_)
{
const ClutterTestData *data = data_;
/* ensure that the previous test state has been cleaned up */
g_assert_null (test_environ->stage);
if (test_environ->no_display)
{
g_test_skip ("No DISPLAY set");
goto out;
}
if (data->test_data != NULL)
{
GTestDataFunc test_func = data->test_func;
test_func (data->test_data);
}
else
{
GTestFunc test_func = data->test_func;
test_func ();
}
out:
if (data->test_notify != NULL)
data->test_notify (data->test_data);
if (test_environ->stage != NULL)
{
clutter_actor_destroy (test_environ->stage);
g_assert_null (test_environ->stage);
}
}
/**
* clutter_test_add: (skip)
* @test_path: unique path for identifying the test
* @test_func: function containing the test
*
* Adds a test unit to the Clutter test environment.
*
* See also: g_test_add()
*
* Since: 1.18
*/
void
clutter_test_add (const char *test_path,
GTestFunc test_func)
{
clutter_test_add_data_full (test_path, (GTestDataFunc) test_func, NULL, NULL);
}
/**
* clutter_test_add_data: (skip)
* @test_path: unique path for identifying the test
* @test_func: function containing the test
* @test_data: data to pass to the test function
*
* Adds a test unit to the Clutter test environment.
*
* See also: g_test_add_data_func()
*
* Since: 1.18
*/
void
clutter_test_add_data (const char *test_path,
GTestDataFunc test_func,
gpointer test_data)
{
clutter_test_add_data_full (test_path, test_func, test_data, NULL);
}
/**
* clutter_test_add_data_full:
* @test_path: unique path for identifying the test
* @test_func: (scope notified): function containing the test
* @test_data: (closure): data to pass to the test function
* @test_notify: function called when the test function ends
*
* Adds a test unit to the Clutter test environment.
*
* See also: g_test_add_data_func_full()
*
* Since: 1.18
*/
void
clutter_test_add_data_full (const char *test_path,
GTestDataFunc test_func,
gpointer test_data,
GDestroyNotify test_notify)
{
ClutterTestData *data;
g_return_if_fail (test_path != NULL);
g_return_if_fail (test_func != NULL);
g_assert (test_environ != NULL);
data = g_new (ClutterTestData, 1);
data->test_func = test_func;
data->test_data = test_data;
data->test_notify = test_notify;
g_test_add_data_func_full (test_path, data,
clutter_test_func_wrapper,
g_free);
}
/**
* clutter_test_run:
*
* Runs the test suite using the units added by calling
* clutter_test_add().
*
* The typical test suite is composed of a list of functions
* called by clutter_test_run(), for instance:
*
* |[
* static void unit_foo (void) { ... }
*
* static void unit_bar (void) { ... }
*
* static void unit_baz (void) { ... }
*
* int
* main (int argc, char *argv[])
* {
* clutter_test_init (&argc, &argv);
*
* clutter_test_add ("/unit/foo", unit_foo);
* clutter_test_add ("/unit/bar", unit_bar);
* clutter_test_add ("/unit/baz", unit_baz);
*
* return clutter_test_run ();
* }
* ]|
*
* Return value: the exit code for the test suite
*
* Since: 1.18
*/
int
clutter_test_run (void)
{
int res;
g_assert (test_environ != NULL);
res = g_test_run ();
g_free (test_environ);
return res;
}
typedef struct {
ClutterActor *stage;
ClutterPoint point;
gpointer result;
guint check_actor : 1;
guint check_color : 1;
guint was_painted : 1;
} ValidateData;
static gboolean
validate_stage (gpointer data_)
{
ValidateData *data = data_;
if (data->check_actor)
{
data->result =
clutter_stage_get_actor_at_pos (CLUTTER_STAGE (data->stage),
CLUTTER_PICK_ALL,
data->point.x,
data->point.y);
}
if (data->check_color)
{
data->result =
clutter_stage_read_pixels (CLUTTER_STAGE (data->stage),
data->point.x,
data->point.y,
1, 1);
}
if (!g_test_verbose ())
{
clutter_actor_hide (data->stage);
data->was_painted = TRUE;
}
return G_SOURCE_REMOVE;
}
static gboolean
on_key_press_event (ClutterActor *stage,
ClutterEvent *event,
gpointer data_)
{
ValidateData *data = data_;
if (data->stage == stage &&
clutter_event_get_key_symbol (event) == CLUTTER_KEY_Escape)
{
clutter_actor_hide (stage);
data->was_painted = TRUE;
}
return CLUTTER_EVENT_PROPAGATE;
}
/**
* clutter_test_check_actor_at_point:
* @stage: a #ClutterStage
* @point: coordinates to check
* @actor: the expected actor at the given coordinates
* @result: (out) (nullable): actor at the coordinates
*
* Checks the given coordinates of the @stage and compares the
* actor found there with the given @actor.
*
* Returns: %TRUE if the actor at the given coordinates matches
*
* Since: 1.18
*/
gboolean
clutter_test_check_actor_at_point (ClutterActor *stage,
const ClutterPoint *point,
ClutterActor *actor,
ClutterActor **result)
{
ValidateData *data;
guint press_id = 0;
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
g_return_val_if_fail (point != NULL, FALSE);
g_return_val_if_fail (CLUTTER_IS_ACTOR (stage), FALSE);
g_return_val_if_fail (result != NULL, FALSE);
data = g_new0 (ValidateData, 1);
data->stage = stage;
data->point = *point;
data->check_actor = TRUE;
if (g_test_verbose ())
{
g_printerr ("Press ESC to close the stage and resume the test\n");
press_id = g_signal_connect (stage, "key-press-event",
G_CALLBACK (on_key_press_event),
data);
}
clutter_actor_show (stage);
clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_POST_PAINT,
validate_stage,
data,
NULL);
while (!data->was_painted)
g_main_context_iteration (NULL, TRUE);
*result = data->result;
if (press_id != 0)
g_signal_handler_disconnect (stage, press_id);
g_free (data);
return *result == actor;
}
/**
* clutter_test_check_color_at_point:
* @stage: a #ClutterStage
* @point: coordinates to check
* @color: expected color
* @result: (out caller-allocates): color at the given coordinates
*
* Checks the color at the given coordinates on @stage, and matches
* it with the red, green, and blue channels of @color. The alpha
* component of @color and @result is ignored.
*
* Returns: %TRUE if the colors match
*
* Since: 1.18
*/
gboolean
clutter_test_check_color_at_point (ClutterActor *stage,
const ClutterPoint *point,
const ClutterColor *color,
ClutterColor *result)
{
ValidateData *data;
gboolean retval;
guint8 *buffer;
guint press_id = 0;
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
g_return_val_if_fail (point != NULL, FALSE);
g_return_val_if_fail (color != NULL, FALSE);
g_return_val_if_fail (result != NULL, FALSE);
data = g_new0 (ValidateData, 1);
data->stage = stage;
data->point = *point;
data->check_color = TRUE;
if (g_test_verbose ())
{
g_printerr ("Press ESC to close the stage and resume the test\n");
press_id = g_signal_connect (stage, "key-press-event",
G_CALLBACK (on_key_press_event),
data);
}
clutter_actor_show (stage);
clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_POST_PAINT,
validate_stage,
data,
NULL);
while (!data->was_painted)
g_main_context_iteration (NULL, TRUE);
if (press_id != 0)
g_signal_handler_disconnect (stage, press_id);
buffer = data->result;
clutter_color_init (result, buffer[0], buffer[1], buffer[2], 255);
/* we only check the color channels, so we can't use clutter_color_equal() */
retval = buffer[0] == color->red &&
buffer[1] == color->green &&
buffer[2] == color->blue;
g_free (data->result);
g_free (data);
return retval;
}

View File

@ -0,0 +1,181 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2013 Emmanuele Bassi <ebassi@gnome.org>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#ifndef __CLUTTER_TEST_UTILS_H__
#define __CLUTTER_TEST_UTILS_H__
#define __CLUTTER_H_INSIDE__
#include "clutter/clutter-types.h"
#include "clutter/clutter-actor.h"
#include "clutter/clutter-color.h"
#include "clutter/clutter-private.h"
#include "core/main-private.h"
#include "meta/common.h"
#include "meta/main.h"
#include "backends/x11/nested/meta-backend-x11-nested.h"
#include "wayland/meta-wayland.h"
#include "wayland/meta-xwayland.h"
G_BEGIN_DECLS
/**
* CLUTTER_TEST_UNIT:
* @path: the GTest path for the test function
* @func: the GTestFunc function
*
* Adds @func at the given @path in the test suite.
*
* Since: 1.18
*/
#define CLUTTER_TEST_UNIT(path,func) \
clutter_test_add (path, func);
/**
* CLUTTER_TEST_SUITE:
* @units: a list of %CLUTTER_TEST_UNIT definitions
*
* Defines the entry point and initializes a Clutter test unit, e.g.:
*
* |[
* CLUTTER_TEST_SUITE (
* CLUTTER_TEST_UNIT ("/foobarize", foobarize)
* CLUTTER_TEST_UNIT ("/bar-enabled", bar_enabled)
* )
* ]|
*
* Expands to:
*
* |[
* int
* main (int argc,
* char *argv[])
* {
* clutter_test_init (&argc, &argv);
*
* clutter_test_add ("/foobarize", foobarize);
* clutter_test_add ("/bar-enabled", bar_enabled);
*
* return clutter_test_run ();
* }
* ]|
*
* Since: 1.18
*/
#define CLUTTER_TEST_SUITE(units) \
int \
main (int argc, char *argv[]) \
{ \
char *display_name = g_strdup ("mutter-test-display-XXXXXX");\
int fd = g_mkstemp (display_name);\
meta_wayland_override_display_name (display_name);\
meta_override_compositor_configuration (META_COMPOSITOR_TYPE_WAYLAND,\
META_TYPE_BACKEND_X11_NESTED);\
\
meta_init ();\
\
clutter_test_init (&argc, &argv); \
\
{ \
units \
} \
\
close (fd);\
g_free (display_name);\
return clutter_test_run (); \
}
CLUTTER_EXPORT
void clutter_test_init (int *argc,
char ***argv);
CLUTTER_EXPORT
int clutter_test_run (void);
CLUTTER_EXPORT
void clutter_test_add (const char *test_path,
GTestFunc test_func);
CLUTTER_EXPORT
void clutter_test_add_data (const char *test_path,
GTestDataFunc test_func,
gpointer test_data);
CLUTTER_EXPORT
void clutter_test_add_data_full (const char *test_path,
GTestDataFunc test_func,
gpointer test_data,
GDestroyNotify test_notify);
CLUTTER_EXPORT
ClutterActor * clutter_test_get_stage (void);
#define clutter_test_assert_actor_at_point(stage,point,actor) \
G_STMT_START { \
const ClutterPoint *__p = (point); \
ClutterActor *__actor = (actor); \
ClutterActor *__stage = (stage); \
ClutterActor *__res; \
if (clutter_test_check_actor_at_point (__stage, __p, actor, &__res)) ; else { \
const char *__str1 = clutter_actor_get_name (__actor) != NULL \
? clutter_actor_get_name (__actor) \
: G_OBJECT_TYPE_NAME (__actor); \
const char *__str2 = clutter_actor_get_name (__res) != NULL \
? clutter_actor_get_name (__res) \
: G_OBJECT_TYPE_NAME (__res); \
char *__msg = g_strdup_printf ("assertion failed (actor %s at %.2f,%.2f): found actor %s", \
__str1, __p->x, __p->y, __str2); \
g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, __msg); \
g_free (__msg); \
} \
} G_STMT_END
#define clutter_test_assert_color_at_point(stage,point,color) \
G_STMT_START { \
const ClutterPoint *__p = (point); \
const ClutterColor *__c = (color); \
ClutterActor *__stage = (stage); \
ClutterColor __res; \
if (clutter_test_check_color_at_point (__stage, __p, __c, &__res)) ; else { \
char *__str1 = clutter_color_to_string (__c); \
char *__str2 = clutter_color_to_string (&__res); \
char *__msg = g_strdup_printf ("assertion failed (color %s at %.2f,%.2f): found color %s", \
__str1, __p->x, __p->y, __str2); \
g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, __msg); \
g_free (__msg); \
g_free (__str1); \
g_free (__str2); \
} \
} G_STMT_END
CLUTTER_EXPORT
gboolean clutter_test_check_actor_at_point (ClutterActor *stage,
const ClutterPoint *point,
ClutterActor *actor,
ClutterActor **result);
CLUTTER_EXPORT
gboolean clutter_test_check_color_at_point (ClutterActor *stage,
const ClutterPoint *point,
const ClutterColor *color,
ClutterColor *result);
G_END_DECLS
#endif /* __CLUTTER_TEST_UTILS_H__ */

View File

@ -4,6 +4,8 @@
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include <clutter/clutter.h>
#include "tests/clutter-test-utils.h"
#define NOTIFY_ANCHOR_X (1 << 0)
#define NOTIFY_ANCHOR_Y (1 << 1)
#define NOTIFY_ANCHOR_GRAVITY (1 << 2)

View File

@ -1,6 +1,8 @@
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include <clutter/clutter.h>
#include "tests/clutter-test-utils.h"
#define TEST_TYPE_DESTROY (test_destroy_get_type ())
#define TEST_DESTROY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_DESTROY, TestDestroy))
#define TEST_IS_DESTROY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_DESTROY))

View File

@ -1,5 +1,7 @@
#include <clutter/clutter.h>
#include "tests/clutter-test-utils.h"
static void
actor_add_child (void)
{

View File

@ -4,6 +4,8 @@
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include <clutter/clutter.h>
#include "tests/clutter-test-utils.h"
static void
actor_initial_state (void)
{

View File

@ -1,6 +1,8 @@
#include <glib.h>
#include <clutter/clutter.h>
#include "tests/clutter-test-utils.h"
static void
actor_iter_traverse_children (void)
{

View File

@ -1,5 +1,7 @@
#include <clutter/clutter.h>
#include "tests/clutter-test-utils.h"
static void
actor_basic_layout (void)
{

View File

@ -3,6 +3,8 @@
#include <clutter/clutter.h>
#include "tests/clutter-test-utils.h"
static void
actor_meta_clear (void)
{

View File

@ -1,6 +1,8 @@
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include <clutter/clutter.h>
#include "tests/clutter-test-utils.h"
typedef struct _FooActor FooActor;
typedef struct _FooActorClass FooActorClass;

View File

@ -1,6 +1,8 @@
#include <clutter/clutter.h>
#include <stdlib.h>
#include "tests/clutter-test-utils.h"
static void
opacity_label (void)
{

View File

@ -1,6 +1,8 @@
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include <clutter/clutter.h>
#include "tests/clutter-test-utils.h"
#define STAGE_WIDTH 640
#define STAGE_HEIGHT 480
#define ACTORS_X 12

View File

@ -2,6 +2,8 @@
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include <clutter/clutter.h>
#include "tests/clutter-test-utils.h"
/****************************************************************
Old style shader effect
This uses clutter_shader_effect_set_source

View File

@ -3,6 +3,8 @@
#include <clutter/clutter.h>
#include "tests/clutter-test-utils.h"
#define TEST_TYPE_ACTOR (test_actor_get_type ())
typedef struct _TestActor TestActor;

View File

@ -1,6 +1,8 @@
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include <clutter/clutter.h>
#include "tests/clutter-test-utils.h"
static void
behaviour_opacity (void)
{
@ -65,6 +67,12 @@ main (int argc, char *argv[])
{
int i;
meta_wayland_override_display_name ("mutter-test-display");
meta_xwayland_override_display_number (512);
meta_override_compositor_configuration (META_COMPOSITOR_TYPE_WAYLAND,
META_TYPE_BACKEND_X11_NESTED);
meta_init ();
clutter_test_init (&argc, &argv);
for (i = 0; i < n_behaviour_tests; i++)

View File

@ -2,6 +2,8 @@
#include <clutter/clutter.h>
#include "tests/clutter-test-utils.h"
#define TYPE_KEY_GROUP (key_group_get_type ())
#define KEY_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_KEY_GROUP, KeyGroup))
#define IS_KEY_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_KEY_GROUP))

View File

@ -1,5 +1,7 @@
#include <clutter/clutter.h>
#include "tests/clutter-test-utils.h"
static void
color_hls_roundtrip (void)
{

View File

@ -1,6 +1,8 @@
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include <clutter/clutter.h>
#include "tests/clutter-test-utils.h"
static void
group_depth_sorting (void)
{

View File

@ -1,5 +1,7 @@
#include <clutter/clutter.h>
#include "tests/clutter-test-utils.h"
static void
interval_initial_state (void)
{

View File

@ -59,6 +59,7 @@ foreach test : clutter_conform_tests
test_executable = executable('@0@'.format(test),
sources: [
'@0@.c'.format(test),
clutter_test_utils,
],
include_directories: clutter_includes,
c_args: clutter_tests_conform_c_args,
@ -66,7 +67,8 @@ foreach test : clutter_conform_tests
dependencies: [
clutter_deps,
libmutter_clutter_dep,
libmutter_cogl_path_dep
libmutter_cogl_path_dep,
libmutter_dep
],
install: false,
)

View File

@ -1,6 +1,8 @@
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include <clutter/clutter.h>
#include "tests/clutter-test-utils.h"
static void
rectangle_set_size (void)
{

View File

@ -4,6 +4,8 @@
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include <clutter/clutter.h>
#include "tests/clutter-test-utils.h"
#define TEST_TYPE_GROUP (test_group_get_type ())
#define TEST_TYPE_GROUP_META (test_group_meta_get_type ())

View File

@ -2,6 +2,8 @@
#include <clutter/clutter.h>
#include <string.h>
#include "tests/clutter-test-utils.h"
typedef struct {
gunichar unichar;
const char bytes[6];

View File

@ -2,6 +2,8 @@
#include <clutter/clutter.h>
#include <string.h>
#include "tests/clutter-test-utils.h"
static CoglHandle
make_texture (void)
{

View File

@ -1,5 +1,7 @@
#include <clutter/clutter.h>
#include "tests/clutter-test-utils.h"
static void
units_cache (void)
{

View File

@ -1,6 +1,11 @@
#if have_clutter_tests
# subdir('clutter')
#endif
clutter_test_utils = files (
'clutter-test-utils.c',
'clutter-test-utils.h',
)
if have_clutter_tests
subdir('clutter')
endif
tests_includepath = mutter_includes
tests_c_args = mutter_c_args