Bug 1162 - Re-works the tests/ to use the glib-2.16 unit testing
framework * configure.ac: * tests/*: The tests have been reorganised into different categories: conformance, interactive and micro benchmarks. - conformance tests can be run as part of automated tests - interactive tests are basically all the existing tests - micro benchmarks focus on a single performance metric I converted the timeline tests to conformance tests and also added some tests from Neil Roberts and Ebassi. Note: currently only the conformance tests use the glib test APIs, though the micro benchmarks should too. The other change is to make the unit tests link into monolithic binaries which makes the build time for unit tests considerably faster. To deal with the extra complexity this adds to debugging individual tests I have added some sugar to the makefiles so all the tests can be run directly via a symlink and when an individual test is run this way, then a note is printed to the terminal explaining exactly how that test may be debugged using GDB. There is a convenience make rule: 'make test-report', that will run all the conformance tests and hopefully even open the results in your web browser. It skips some of the slower timeline tests, but you can run those using 'make full-report'
This commit is contained in:
31
tests/conform/ADDING_NEW_TESTS
Normal file
31
tests/conform/ADDING_NEW_TESTS
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
How:
|
||||
----
|
||||
|
||||
You should including the following at the top of your new unit test:
|
||||
#include "test-conform-common.h"
|
||||
|
||||
Instead of a main () function add an entry point with a prototype as follows:
|
||||
|
||||
void
|
||||
test_blah (TestConformSimpleFixture *fixture,
|
||||
gconstpointer data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Add a TEST_CONFORM_SIMPLE() entry in test-conform-main.c
|
||||
|
||||
|
||||
Notes:
|
||||
------
|
||||
|
||||
NB: A test fails if it exists. (regardless of the exist status)
|
||||
|
||||
Don't call clutter_init since that is handled in test-conform-common.c
|
||||
|
||||
Make sure you clean up *everything* you create. Noteable things you might miss
|
||||
include timelines, behaviours, and all actors you add to the stage. This is important because otherwise you can cause cascading failures in other tests.
|
||||
|
||||
Use stage = clutter_stage_new () with a corresponding clutter_actor_destroy instead of clutter_stage_get_default ().
|
||||
|
52
tests/conform/Makefile.am
Normal file
52
tests/conform/Makefile.am
Normal file
@@ -0,0 +1,52 @@
|
||||
noinst_PROGRAMS = test-conformance
|
||||
|
||||
test_conformance_SOURCES = \
|
||||
test-conform-main.c \
|
||||
test-conform-common.c \
|
||||
test-conform-common.h \
|
||||
\
|
||||
test-timeline-dup-frames.c \
|
||||
test-timeline-interpolate.c \
|
||||
test-timeline-rewind.c \
|
||||
test-timeline-smoothness.c \
|
||||
test-timeline.c \
|
||||
test-pick.c \
|
||||
test-label-cache.c \
|
||||
test-clutter-entry.c \
|
||||
test-clutter-rectangle.c \
|
||||
test-clutter-fixed.c
|
||||
|
||||
# For convenience, this provides a way to easily run individual unit tests:
|
||||
.PHONY: wrappers
|
||||
wrappers: test-conformance
|
||||
for i in `./test-conformance -l`; \
|
||||
do \
|
||||
ln -sf $(top_srcdir)/tests/conform/wrapper.sh `basename $$i`; \
|
||||
done
|
||||
# NB: BUILT_SOURCES here a misnomer. We aren't building source, just inserting
|
||||
# a phony rule that will generate symlink scripts for running individual tests
|
||||
BUILT_SOURCES = wrappers
|
||||
|
||||
test_conformance_CFLAGS = \
|
||||
-I$(top_srcdir)/ \
|
||||
-I$(top_srcdir)/clutter \
|
||||
-I$(top_builddir)/clutter \
|
||||
$(CLUTTER_CFLAGS)
|
||||
test_conformance_LDADD = $(top_builddir)/clutter/libclutter-@CLUTTER_FLAVOUR@-@CLUTTER_MAJORMINOR@.la
|
||||
|
||||
.PHONY: test test-report full-report
|
||||
test:
|
||||
gtester -o=test-conformance-results.xml ./test-conformance
|
||||
|
||||
test-report:
|
||||
gtester -o=test-conformance-results.xml -k ./test-conformance \
|
||||
&& gtester-report test-conformance-results.xml > test-conformance-results.html \
|
||||
&& gnome-open ./test-conformance-results.html
|
||||
|
||||
full-report:
|
||||
gtester -o=test-conformance-results.xml -k -m=slow ./test-conformance \
|
||||
&& gtester-report test-conformance-results.xml > test-conformance-results.html \
|
||||
&& gnome-open ./test-conformance-results.html
|
||||
|
||||
EXTRA_DIST = ADDING_NEW_TESTS
|
||||
|
370
tests/conform/test-clutter-entry.c
Normal file
370
tests/conform/test-clutter-entry.c
Normal file
@@ -0,0 +1,370 @@
|
||||
#include <glib.h>
|
||||
#include <clutter/clutter.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "test-conform-common.h"
|
||||
|
||||
typedef struct {
|
||||
gunichar unichar;
|
||||
const char bytes[6];
|
||||
gint nbytes;
|
||||
} TestData;
|
||||
|
||||
const TestData
|
||||
test_data[] = {
|
||||
{ 0xe4, "\xc3\xa4", 2 }, /* LATIN SMALL LETTER A WITH DIAERESIS */
|
||||
{ 0x2665, "\xe2\x99\xa5", 3 } /* BLACK HEART SUIT */
|
||||
};
|
||||
|
||||
void
|
||||
test_entry_utf8_validation (TestConformSimpleFixture *fixture,
|
||||
gconstpointer data)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (test_data); i++)
|
||||
{
|
||||
const TestData *t = &test_data[i];
|
||||
gunichar unichar;
|
||||
char bytes[6];
|
||||
int nbytes;
|
||||
|
||||
g_assert (g_unichar_validate (t->unichar));
|
||||
|
||||
nbytes = g_unichar_to_utf8 (t->unichar, bytes);
|
||||
bytes[nbytes] = '\0';
|
||||
g_assert (nbytes == t->nbytes);
|
||||
g_assert (memcmp (t->bytes, bytes, nbytes) == 0);
|
||||
|
||||
unichar = g_utf8_get_char_validated (bytes, nbytes);
|
||||
g_assert (unichar == t->unichar);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
get_nbytes (ClutterEntry *entry)
|
||||
{
|
||||
const char *s = clutter_entry_get_text (entry);
|
||||
return strlen (s);
|
||||
}
|
||||
|
||||
static int
|
||||
get_nchars (ClutterEntry *entry)
|
||||
{
|
||||
const char *s = clutter_entry_get_text (entry);
|
||||
g_assert (g_utf8_validate (s, -1, NULL));
|
||||
return g_utf8_strlen (s, -1);
|
||||
}
|
||||
|
||||
#define DONT_MOVE_CURSOR (-2)
|
||||
|
||||
static void
|
||||
insert_unichar (ClutterEntry *entry, gunichar unichar, int position)
|
||||
{
|
||||
if (position > DONT_MOVE_CURSOR)
|
||||
{
|
||||
clutter_entry_set_cursor_position (entry, position);
|
||||
g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, position);
|
||||
}
|
||||
|
||||
clutter_entry_insert_unichar (entry, unichar);
|
||||
}
|
||||
|
||||
void
|
||||
test_entry_empty (TestConformSimpleFixture *fixture,
|
||||
gconstpointer data)
|
||||
{
|
||||
ClutterEntry *entry = CLUTTER_ENTRY (clutter_entry_new ());
|
||||
|
||||
g_assert (clutter_entry_get_text (entry) == NULL);
|
||||
g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, -1);
|
||||
|
||||
clutter_actor_destroy (CLUTTER_ACTOR (entry));
|
||||
}
|
||||
|
||||
void
|
||||
test_entry_set_empty (TestConformSimpleFixture *fixture,
|
||||
gconstpointer data)
|
||||
{
|
||||
ClutterEntry *entry = CLUTTER_ENTRY (clutter_entry_new ());
|
||||
|
||||
/* annoyingly slightly different from initially empty */
|
||||
clutter_entry_set_text (entry, "");
|
||||
g_assert_cmpint (get_nchars (entry), ==, 0);
|
||||
g_assert_cmpint (get_nbytes (entry), ==, 0);
|
||||
g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, -1);
|
||||
|
||||
clutter_actor_destroy (CLUTTER_ACTOR (entry));
|
||||
}
|
||||
|
||||
void
|
||||
test_entry_set_text (TestConformSimpleFixture *fixture,
|
||||
gconstpointer data)
|
||||
{
|
||||
ClutterEntry *entry = CLUTTER_ENTRY (clutter_entry_new ());
|
||||
|
||||
clutter_entry_set_text (entry, "abcdef");
|
||||
g_assert_cmpint (get_nchars (entry), ==, 6);
|
||||
g_assert_cmpint (get_nbytes (entry), ==, 6);
|
||||
g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, -1);
|
||||
|
||||
clutter_entry_set_cursor_position (entry, 5);
|
||||
g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, 5);
|
||||
|
||||
clutter_entry_set_text (entry, "");
|
||||
/* FIXME: cursor position should be -1?
|
||||
g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, -1);
|
||||
*/
|
||||
|
||||
clutter_actor_destroy (CLUTTER_ACTOR (entry));
|
||||
}
|
||||
|
||||
void
|
||||
test_entry_append_some (TestConformSimpleFixture *fixture,
|
||||
gconstpointer data)
|
||||
{
|
||||
ClutterEntry *entry = CLUTTER_ENTRY (clutter_entry_new ());
|
||||
int i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (test_data); i++)
|
||||
{
|
||||
const TestData *t = &test_data[i];
|
||||
int j;
|
||||
|
||||
for (j = 1; j <= 4; j++)
|
||||
{
|
||||
insert_unichar (entry, t->unichar, DONT_MOVE_CURSOR);
|
||||
g_assert_cmpint (get_nchars (entry), ==, j);
|
||||
g_assert_cmpint (get_nbytes (entry), ==, j * t->nbytes);
|
||||
g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, -1);
|
||||
}
|
||||
|
||||
clutter_entry_set_text (entry, "");
|
||||
}
|
||||
|
||||
clutter_actor_destroy (CLUTTER_ACTOR (entry));
|
||||
}
|
||||
|
||||
void
|
||||
test_entry_prepend_some (TestConformSimpleFixture *fixture,
|
||||
gconstpointer data)
|
||||
{
|
||||
ClutterEntry *entry = CLUTTER_ENTRY (clutter_entry_new ());
|
||||
int i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (test_data); i++)
|
||||
{
|
||||
const TestData *t = &test_data[i];
|
||||
int j;
|
||||
|
||||
clutter_entry_insert_unichar (entry, t->unichar);
|
||||
g_assert_cmpint (get_nchars (entry), ==, 1);
|
||||
g_assert_cmpint (get_nbytes (entry), ==, 1 * t->nbytes);
|
||||
g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, -1);
|
||||
|
||||
for (j = 2; j <= 4; j++)
|
||||
{
|
||||
insert_unichar (entry, t->unichar, 0);
|
||||
g_assert_cmpint (get_nchars (entry), ==, j);
|
||||
g_assert_cmpint (get_nbytes (entry), ==, j * t->nbytes);
|
||||
g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, 1);
|
||||
}
|
||||
|
||||
clutter_entry_set_text (entry, "");
|
||||
}
|
||||
|
||||
clutter_actor_destroy (CLUTTER_ACTOR (entry));
|
||||
}
|
||||
|
||||
void
|
||||
test_entry_insert (TestConformSimpleFixture *fixture,
|
||||
gconstpointer data)
|
||||
{
|
||||
ClutterEntry *entry = CLUTTER_ENTRY (clutter_entry_new ());
|
||||
int i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (test_data); i++)
|
||||
{
|
||||
const TestData *t = &test_data[i];
|
||||
|
||||
clutter_entry_insert_unichar (entry, t->unichar);
|
||||
clutter_entry_insert_unichar (entry, t->unichar);
|
||||
|
||||
insert_unichar (entry, t->unichar, 1);
|
||||
g_assert_cmpint (get_nchars (entry), ==, 3);
|
||||
g_assert_cmpint (get_nbytes (entry), ==, 3 * t->nbytes);
|
||||
g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, 2);
|
||||
|
||||
clutter_entry_set_text (entry, "");
|
||||
}
|
||||
|
||||
clutter_actor_destroy (CLUTTER_ACTOR (entry));
|
||||
}
|
||||
|
||||
void
|
||||
test_entry_delete_chars (TestConformSimpleFixture *fixture,
|
||||
gconstpointer data)
|
||||
{
|
||||
ClutterEntry *entry = CLUTTER_ENTRY (clutter_entry_new ());
|
||||
int i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (test_data); i++)
|
||||
{
|
||||
const TestData *t = &test_data[i];
|
||||
int j;
|
||||
|
||||
for (j = 0; j < 4; j++)
|
||||
clutter_entry_insert_unichar (entry, t->unichar);
|
||||
|
||||
clutter_entry_set_cursor_position (entry, 2);
|
||||
clutter_entry_delete_chars (entry, 1);
|
||||
g_assert_cmpint (get_nchars (entry), ==, 3);
|
||||
g_assert_cmpint (get_nbytes (entry), ==, 3 * t->nbytes);
|
||||
g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, 1);
|
||||
|
||||
clutter_entry_set_cursor_position (entry, 2);
|
||||
clutter_entry_delete_chars (entry, 1);
|
||||
g_assert_cmpint (get_nchars (entry), ==, 2);
|
||||
g_assert_cmpint (get_nbytes (entry), ==, 2 * t->nbytes);
|
||||
g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, 1);
|
||||
|
||||
clutter_entry_set_text (entry, "");
|
||||
}
|
||||
|
||||
clutter_actor_destroy (CLUTTER_ACTOR (entry));
|
||||
}
|
||||
|
||||
void
|
||||
test_entry_delete_text (TestConformSimpleFixture *fixture,
|
||||
gconstpointer data)
|
||||
{
|
||||
ClutterEntry *entry = CLUTTER_ENTRY (clutter_entry_new ());
|
||||
int i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (test_data); i++)
|
||||
{
|
||||
const TestData *t = &test_data[i];
|
||||
int j;
|
||||
|
||||
for (j = 0; j < 4; j++)
|
||||
clutter_entry_insert_unichar (entry, t->unichar);
|
||||
|
||||
clutter_entry_set_cursor_position (entry, 3);
|
||||
clutter_entry_delete_text (entry, 2, 4);
|
||||
|
||||
g_assert_cmpint (get_nchars (entry), ==, 2);
|
||||
g_assert_cmpint (get_nbytes (entry), ==, 2 * t->nbytes);
|
||||
|
||||
/* FIXME: cursor position should be -1?
|
||||
g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, -1);
|
||||
*/
|
||||
|
||||
clutter_entry_set_text (entry, "");
|
||||
}
|
||||
|
||||
clutter_actor_destroy (CLUTTER_ACTOR (entry));
|
||||
}
|
||||
|
||||
static void
|
||||
init_event (ClutterKeyEvent *event)
|
||||
{
|
||||
event->type = CLUTTER_KEY_PRESS;
|
||||
event->time = 0; /* not needed */
|
||||
event->flags = CLUTTER_EVENT_FLAG_SYNTHETIC;
|
||||
event->stage = NULL; /* not needed */
|
||||
event->source = NULL; /* not needed */
|
||||
event->modifier_state = 0;
|
||||
event->hardware_keycode = 0; /* not needed */
|
||||
}
|
||||
|
||||
static void
|
||||
send_keyval (ClutterEntry *entry, int keyval)
|
||||
{
|
||||
ClutterKeyEvent event;
|
||||
|
||||
init_event (&event);
|
||||
event.keyval = keyval;
|
||||
event.unicode_value = 0; /* should be ignored for cursor keys etc. */
|
||||
|
||||
clutter_entry_handle_key_event (entry, &event);
|
||||
}
|
||||
|
||||
static inline void
|
||||
send_unichar (ClutterEntry *entry, gunichar unichar)
|
||||
{
|
||||
ClutterKeyEvent event;
|
||||
|
||||
init_event (&event);
|
||||
event.keyval = 0; /* should be ignored for printable characters */
|
||||
event.unicode_value = unichar;
|
||||
|
||||
clutter_entry_handle_key_event (entry, &event);
|
||||
}
|
||||
|
||||
void
|
||||
test_entry_cursor (TestConformSimpleFixture *fixture,
|
||||
gconstpointer data)
|
||||
{
|
||||
ClutterEntry *entry = CLUTTER_ENTRY (clutter_entry_new ());
|
||||
int i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (test_data); i++)
|
||||
{
|
||||
const TestData *t = &test_data[i];
|
||||
int j;
|
||||
|
||||
for (j = 0; j < 4; ++j)
|
||||
clutter_entry_insert_unichar (entry, t->unichar);
|
||||
|
||||
clutter_entry_set_cursor_position (entry, 2);
|
||||
|
||||
/* test cursor moves and is clamped */
|
||||
send_keyval (entry, CLUTTER_Left);
|
||||
g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, 1);
|
||||
|
||||
send_keyval (entry, CLUTTER_Left);
|
||||
g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, 0);
|
||||
|
||||
send_keyval (entry, CLUTTER_Left);
|
||||
g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, 0);
|
||||
|
||||
/* delete text containing the cursor */
|
||||
clutter_entry_set_cursor_position (entry, 3);
|
||||
g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, 3);
|
||||
|
||||
clutter_entry_delete_text (entry, 2, 4);
|
||||
send_keyval (entry, CLUTTER_Left);
|
||||
|
||||
/* FIXME: cursor position should be -1?
|
||||
g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, -1);
|
||||
*/
|
||||
|
||||
clutter_entry_set_text (entry, "");
|
||||
}
|
||||
|
||||
clutter_actor_destroy (CLUTTER_ACTOR (entry));
|
||||
}
|
||||
|
||||
void
|
||||
test_entry_event (TestConformSimpleFixture *fixture,
|
||||
gconstpointer data)
|
||||
{
|
||||
ClutterEntry *entry = CLUTTER_ENTRY (clutter_entry_new ());
|
||||
int i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (test_data); i++)
|
||||
{
|
||||
const TestData *t = &test_data[i];
|
||||
|
||||
send_unichar (entry, t->unichar);
|
||||
|
||||
g_assert_cmpint (get_nchars (entry), ==, 1);
|
||||
g_assert_cmpint (get_nbytes (entry), ==, 1 * t->nbytes);
|
||||
g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, -1);
|
||||
|
||||
clutter_entry_set_text (entry, "");
|
||||
}
|
||||
|
||||
clutter_actor_destroy (CLUTTER_ACTOR (entry));
|
||||
}
|
||||
|
18
tests/conform/test-clutter-fixed.c
Normal file
18
tests/conform/test-clutter-fixed.c
Normal file
@@ -0,0 +1,18 @@
|
||||
#include <stdio.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include "test-conform-common.h"
|
||||
|
||||
void
|
||||
test_fixed_constants (TestConformSimpleFixture *fixture,
|
||||
gconstpointer data)
|
||||
{
|
||||
g_assert_cmpint (CFX_ONE, ==, CLUTTER_FLOAT_TO_FIXED (1.0));
|
||||
g_assert_cmpint (CFX_ONE, ==, CLUTTER_INT_TO_FIXED (1));
|
||||
|
||||
g_assert_cmpint (CFX_HALF, ==, CLUTTER_FLOAT_TO_FIXED (0.5));
|
||||
|
||||
g_assert_cmpfloat (CLUTTER_FIXED_TO_FLOAT (CFX_ONE), ==, 1.0);
|
||||
g_assert_cmpfloat (CLUTTER_FIXED_TO_FLOAT (CFX_HALF), ==, 0.5);
|
||||
}
|
||||
|
56
tests/conform/test-clutter-rectangle.c
Normal file
56
tests/conform/test-clutter-rectangle.c
Normal file
@@ -0,0 +1,56 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <glib/gtestutils.h>
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include "test-conform-common.h"
|
||||
|
||||
void
|
||||
test_rect_set_size (TestConformSimpleFixture *fixture,
|
||||
gconstpointer data)
|
||||
{
|
||||
ClutterActor *rect = clutter_rectangle_new ();
|
||||
|
||||
/* initial positioning */
|
||||
g_assert_cmpint (clutter_actor_get_x (rect), ==, 0);
|
||||
g_assert_cmpint (clutter_actor_get_y (rect), ==, 0);
|
||||
|
||||
clutter_actor_set_size (rect, 100, 100);
|
||||
|
||||
/* make sure that changing the size does not affect the
|
||||
* rest of the bounding box
|
||||
*/
|
||||
g_assert_cmpint (clutter_actor_get_x (rect), ==, 0);
|
||||
g_assert_cmpint (clutter_actor_get_y (rect), ==, 0);
|
||||
|
||||
g_assert_cmpint (clutter_actor_get_width (rect), ==, 100);
|
||||
g_assert_cmpint (clutter_actor_get_height (rect), ==, 100);
|
||||
|
||||
clutter_actor_destroy (rect);
|
||||
}
|
||||
|
||||
void
|
||||
test_rect_set_color (TestConformSimpleFixture *fixture,
|
||||
gconstpointer data)
|
||||
{
|
||||
ClutterActor *rect = clutter_rectangle_new ();
|
||||
ClutterColor white = { 255, 255, 255, 255 };
|
||||
ClutterColor black = { 0, 0, 0, 255 };
|
||||
ClutterColor check = { 0, };
|
||||
|
||||
clutter_rectangle_set_color (CLUTTER_RECTANGLE (rect), &black);
|
||||
clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &check);
|
||||
g_assert_cmpint (check.blue, ==, black.blue);
|
||||
|
||||
clutter_rectangle_set_color (CLUTTER_RECTANGLE (rect), &white);
|
||||
clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &check);
|
||||
g_assert_cmpint (check.green, ==, white.green);
|
||||
|
||||
g_assert_cmpint (clutter_actor_get_opacity (rect), ==, white.alpha);
|
||||
|
||||
clutter_actor_destroy (rect);
|
||||
}
|
||||
|
29
tests/conform/test-conform-common.c
Normal file
29
tests/conform/test-conform-common.c
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include "test-conform-common.h"
|
||||
|
||||
/**
|
||||
* test_conform_simple_fixture_setup:
|
||||
*
|
||||
* Initialise stuff before each test is run
|
||||
*/
|
||||
void
|
||||
test_conform_simple_fixture_setup (TestConformSimpleFixture *fixture,
|
||||
gconstpointer data)
|
||||
{
|
||||
/* const TestConformSharedState *shared_state = data; */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test_conform_simple_fixture_teardown:
|
||||
*
|
||||
* Cleanup stuff after each test has finished
|
||||
*/
|
||||
void
|
||||
test_conform_simple_fixture_teardown (TestConformSimpleFixture *fixture,
|
||||
gconstpointer data)
|
||||
{
|
||||
/* const TestConformSharedState *shared_state = data; */
|
||||
}
|
||||
|
25
tests/conform/test-conform-common.h
Normal file
25
tests/conform/test-conform-common.h
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
/* Stuff you put in here is setup once in main() and gets passed around to
|
||||
* all test functions and fixture setup/teardown functions in the data
|
||||
* argument */
|
||||
typedef struct _TestConformSharedState
|
||||
{
|
||||
int *argc_addr;
|
||||
char ***argv_addr;
|
||||
} TestConformSharedState;
|
||||
|
||||
|
||||
/* This fixture structure is allocated by glib, and before running each test
|
||||
* the test_conform_simple_fixture_setup func (see below) is called to
|
||||
* initialise it, and test_conform_simple_fixture_teardown is called when
|
||||
* the test is finished. */
|
||||
typedef struct _TestConformSimpleFixture
|
||||
{
|
||||
/**/
|
||||
} TestConformSimpleFixture;
|
||||
|
||||
void test_conform_simple_fixture_setup (TestConformSimpleFixture *fixture,
|
||||
gconstpointer data);
|
||||
void test_conform_simple_fixture_teardown (TestConformSimpleFixture *fixture,
|
||||
gconstpointer data);
|
||||
|
81
tests/conform/test-conform-main.c
Normal file
81
tests/conform/test-conform-main.c
Normal file
@@ -0,0 +1,81 @@
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "test-conform-common.h"
|
||||
|
||||
|
||||
/* This is a bit of sugar for adding new conformance tests:
|
||||
*
|
||||
* - It adds an extern function definition just to save maintaining a header
|
||||
* that lists test entry points.
|
||||
* - It sets up callbacks for a fixture, which lets us share initialization
|
||||
* *code* between tests. (see test-conform-common.c)
|
||||
* - It passes in a shared *data* pointer that is initialised once in main(),
|
||||
* that gets passed to the fixture setup and test functions. (See the
|
||||
* definition in test-conform-common.h)
|
||||
*/
|
||||
#define TEST_CONFORM_SIMPLE(NAMESPACE, FUNC) \
|
||||
extern void FUNC (TestConformSimpleFixture *fixture, gconstpointer data); \
|
||||
g_test_add ("/conform" NAMESPACE "/" #FUNC, \
|
||||
TestConformSimpleFixture, \
|
||||
shared_state, /* data argument for test */ \
|
||||
test_conform_simple_fixture_setup, \
|
||||
FUNC, \
|
||||
test_conform_simple_fixture_teardown);
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
TestConformSharedState *shared_state = g_new0 (TestConformSharedState, 1);
|
||||
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
g_test_bug_base ("http://bugzilla.openedhand.com/show_bug.cgi?id=%s");
|
||||
|
||||
g_assert (clutter_init (shared_state->argc_addr, shared_state->argv_addr)
|
||||
== CLUTTER_INIT_SUCCESS);
|
||||
|
||||
/* Initialise the state you need to share with everything.
|
||||
*/
|
||||
shared_state->argc_addr = &argc;
|
||||
shared_state->argv_addr = &argv;
|
||||
|
||||
if (g_test_slow ())
|
||||
{
|
||||
TEST_CONFORM_SIMPLE ("/timeline", test_timeline_dup_frames);
|
||||
TEST_CONFORM_SIMPLE ("/timeline", test_timeline_interpolate);
|
||||
TEST_CONFORM_SIMPLE ("/timeline", test_timeline_rewind);
|
||||
TEST_CONFORM_SIMPLE ("/timeline", test_timeline_smoothness);
|
||||
}
|
||||
|
||||
TEST_CONFORM_SIMPLE ("/picking", test_pick);
|
||||
|
||||
TEST_CONFORM_SIMPLE ("/label", test_label_cache);
|
||||
|
||||
TEST_CONFORM_SIMPLE ("/entry", test_entry_utf8_validation);
|
||||
TEST_CONFORM_SIMPLE ("/entry", test_entry_empty);
|
||||
TEST_CONFORM_SIMPLE ("/entry", test_entry_set_empty);
|
||||
TEST_CONFORM_SIMPLE ("/entry", test_entry_set_text);
|
||||
|
||||
TEST_CONFORM_SIMPLE ("/entry", test_entry_append_some);
|
||||
TEST_CONFORM_SIMPLE ("/entry", test_entry_prepend_some);
|
||||
TEST_CONFORM_SIMPLE ("/entry", test_entry_insert);
|
||||
|
||||
TEST_CONFORM_SIMPLE ("/entry", test_entry_delete_chars);
|
||||
TEST_CONFORM_SIMPLE ("/entry", test_entry_delete_text);
|
||||
|
||||
TEST_CONFORM_SIMPLE ("/entry", test_entry_cursor);
|
||||
TEST_CONFORM_SIMPLE ("/entry", test_entry_event);
|
||||
|
||||
TEST_CONFORM_SIMPLE ("/rectangle", test_rect_set_size);
|
||||
TEST_CONFORM_SIMPLE ("/rectangle", test_rect_set_color);
|
||||
|
||||
TEST_CONFORM_SIMPLE ("/fixed", test_fixed_constants);
|
||||
|
||||
g_test_run ();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
260
tests/conform/test-label-cache.c
Normal file
260
tests/conform/test-label-cache.c
Normal file
@@ -0,0 +1,260 @@
|
||||
#include <clutter/clutter.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "test-conform-common.h"
|
||||
|
||||
#define TEST_FONT "Sans 10"
|
||||
|
||||
static const char long_text[] =
|
||||
"<b>This</b> <i>is</i> some <span size=\"x-large\">REALLY</span> "
|
||||
"long text that contains markup for testing the <tt>use_markup</tt> "
|
||||
"property and to test word-wrapping, justification and alignment.";
|
||||
|
||||
typedef struct _CallbackData CallbackData;
|
||||
|
||||
struct _CallbackData
|
||||
{
|
||||
ClutterActor *stage;
|
||||
ClutterActor *label;
|
||||
|
||||
PangoLayout *old_layout;
|
||||
gboolean layout_changed;
|
||||
PangoRectangle label_extents;
|
||||
|
||||
PangoLayout *test_layout;
|
||||
|
||||
gboolean test_failed;
|
||||
};
|
||||
|
||||
static void
|
||||
on_paint (ClutterActor *label, CallbackData *data)
|
||||
{
|
||||
PangoLayout *new_layout;
|
||||
|
||||
/* Check whether the layout used for this paint is different from
|
||||
the layout used for the last paint */
|
||||
new_layout = clutter_label_get_layout (CLUTTER_LABEL (data->label));
|
||||
data->layout_changed = data->old_layout != new_layout;
|
||||
|
||||
if (data->old_layout)
|
||||
g_object_unref (data->old_layout);
|
||||
/* Keep a reference to the old layout so we can be sure it won't
|
||||
just reallocate a new layout with the same address */
|
||||
data->old_layout = g_object_ref (new_layout);
|
||||
|
||||
pango_layout_get_extents (new_layout, NULL, &data->label_extents);
|
||||
}
|
||||
|
||||
static void
|
||||
force_redraw (CallbackData *data)
|
||||
{
|
||||
clutter_redraw (CLUTTER_STAGE (clutter_actor_get_stage (data->label)));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
check_result (CallbackData *data, const char *note,
|
||||
gboolean layout_should_change)
|
||||
{
|
||||
PangoRectangle test_extents;
|
||||
gboolean fail = FALSE;
|
||||
|
||||
printf ("%s: ", note);
|
||||
|
||||
/* Force a redraw to get the on_paint handler to run */
|
||||
force_redraw (data);
|
||||
|
||||
/* Compare the extents from the label with the extents from our test
|
||||
layout */
|
||||
pango_layout_get_extents (data->test_layout, NULL, &test_extents);
|
||||
if (memcmp (&test_extents, &data->label_extents, sizeof (PangoRectangle)))
|
||||
{
|
||||
printf ("extents are different, ");
|
||||
fail = TRUE;
|
||||
}
|
||||
else
|
||||
printf ("extents are the same, ");
|
||||
|
||||
if (data->layout_changed)
|
||||
printf ("layout changed, ");
|
||||
else
|
||||
printf ("layout did not change, ");
|
||||
|
||||
if (data->layout_changed != layout_should_change)
|
||||
fail = TRUE;
|
||||
|
||||
if (fail)
|
||||
{
|
||||
printf ("FAIL\n");
|
||||
data->test_failed = TRUE;
|
||||
}
|
||||
else
|
||||
printf ("pass\n");
|
||||
|
||||
return fail;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
do_tests (CallbackData *data)
|
||||
{
|
||||
PangoFontDescription *fd;
|
||||
static const ClutterColor red = { 0xff, 0x00, 0x00, 0xff };
|
||||
PangoAttrList *attr_list, *attr_list_copy;
|
||||
PangoAttribute *attr;
|
||||
|
||||
/* TEST 1: change the text */
|
||||
clutter_label_set_text (CLUTTER_LABEL (data->label), "Counter 0");
|
||||
pango_layout_set_text (data->test_layout, "Counter 0", -1);
|
||||
check_result (data, "Change text", TRUE);
|
||||
|
||||
/* TEST 2: change a single character */
|
||||
clutter_label_set_text (CLUTTER_LABEL (data->label), "Counter 1");
|
||||
pango_layout_set_text (data->test_layout, "Counter 1", -1);
|
||||
check_result (data, "Change a single character", TRUE);
|
||||
|
||||
/* TEST 3: move the label */
|
||||
clutter_actor_set_position (data->label, 10, 0);
|
||||
check_result (data, "Move the label", FALSE);
|
||||
|
||||
/* TEST 4: change the font */
|
||||
clutter_label_set_font_name (CLUTTER_LABEL (data->label), "Serif 15");
|
||||
fd = pango_font_description_from_string ("Serif 15");
|
||||
pango_layout_set_font_description (data->test_layout, fd);
|
||||
pango_font_description_free (fd);
|
||||
check_result (data, "Change the font", TRUE);
|
||||
|
||||
/* TEST 5: change the color */
|
||||
clutter_label_set_color (CLUTTER_LABEL (data->label), &red);
|
||||
check_result (data, "Change the color", FALSE);
|
||||
|
||||
/* TEST 6: change the attributes */
|
||||
attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
|
||||
attr->start_index = 0;
|
||||
attr->end_index = 2;
|
||||
attr_list = pango_attr_list_new ();
|
||||
pango_attr_list_insert (attr_list, attr);
|
||||
attr_list_copy = pango_attr_list_copy (attr_list);
|
||||
clutter_label_set_attributes (CLUTTER_LABEL (data->label), attr_list);
|
||||
pango_layout_set_attributes (data->test_layout, attr_list_copy);
|
||||
pango_attr_list_unref (attr_list_copy);
|
||||
pango_attr_list_unref (attr_list);
|
||||
check_result (data, "Change the attributes", TRUE);
|
||||
|
||||
/* TEST 7: change the text again */
|
||||
clutter_label_set_attributes (CLUTTER_LABEL (data->label), NULL);
|
||||
clutter_label_set_text (CLUTTER_LABEL (data->label), long_text);
|
||||
pango_layout_set_attributes (data->test_layout, NULL);
|
||||
pango_layout_set_text (data->test_layout, long_text, -1);
|
||||
check_result (data, "Change the text again", TRUE);
|
||||
|
||||
/* TEST 8: enable markup */
|
||||
clutter_label_set_use_markup (CLUTTER_LABEL (data->label), TRUE);
|
||||
pango_layout_set_markup (data->test_layout, long_text, -1);
|
||||
check_result (data, "Enable markup", TRUE);
|
||||
|
||||
/* This part can't be a test because Clutter won't restrict the
|
||||
width if wrapping and ellipsizing is disabled so the extents will
|
||||
be different, but we still want to do it for the later tests */
|
||||
clutter_actor_set_width (data->label, 200);
|
||||
pango_layout_set_width (data->test_layout, 200 * PANGO_SCALE);
|
||||
/* Force a redraw so that changing the width won't affect the
|
||||
results */
|
||||
force_redraw (data);
|
||||
|
||||
/* TEST 9: enable ellipsize */
|
||||
clutter_label_set_ellipsize (CLUTTER_LABEL (data->label),
|
||||
PANGO_ELLIPSIZE_END);
|
||||
pango_layout_set_ellipsize (data->test_layout, PANGO_ELLIPSIZE_END);
|
||||
check_result (data, "Enable ellipsize", TRUE);
|
||||
clutter_label_set_ellipsize (CLUTTER_LABEL (data->label),
|
||||
PANGO_ELLIPSIZE_NONE);
|
||||
pango_layout_set_ellipsize (data->test_layout, PANGO_ELLIPSIZE_NONE);
|
||||
force_redraw (data);
|
||||
|
||||
/* TEST 10: enable line wrap */
|
||||
clutter_label_set_line_wrap (CLUTTER_LABEL (data->label), TRUE);
|
||||
pango_layout_set_wrap (data->test_layout, PANGO_WRAP_WORD);
|
||||
check_result (data, "Enable line wrap", TRUE);
|
||||
|
||||
/* TEST 11: change wrap mode */
|
||||
clutter_label_set_line_wrap_mode (CLUTTER_LABEL (data->label),
|
||||
PANGO_WRAP_CHAR);
|
||||
pango_layout_set_wrap (data->test_layout, PANGO_WRAP_CHAR);
|
||||
check_result (data, "Change wrap mode", TRUE);
|
||||
|
||||
/* TEST 12: enable justify */
|
||||
clutter_label_set_justify (CLUTTER_LABEL (data->label), TRUE);
|
||||
pango_layout_set_justify (data->test_layout, TRUE);
|
||||
/* Pango appears to have a bug which means that you can't change the
|
||||
justification after setting the text but this fixes it.
|
||||
See http://bugzilla.gnome.org/show_bug.cgi?id=551865 */
|
||||
pango_layout_context_changed (data->test_layout);
|
||||
check_result (data, "Enable justify", TRUE);
|
||||
|
||||
/* TEST 13: change alignment */
|
||||
clutter_label_set_alignment (CLUTTER_LABEL (data->label), PANGO_ALIGN_RIGHT);
|
||||
pango_layout_set_alignment (data->test_layout, PANGO_ALIGN_RIGHT);
|
||||
check_result (data, "Change alignment", TRUE);
|
||||
|
||||
clutter_main_quit ();
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static PangoLayout *
|
||||
make_layout_like_label (ClutterLabel *label)
|
||||
{
|
||||
PangoLayout *label_layout, *new_layout;
|
||||
PangoContext *context;
|
||||
PangoFontDescription *fd;
|
||||
|
||||
/* Make another layout using the same context as the layout from the
|
||||
label */
|
||||
label_layout = clutter_label_get_layout (label);
|
||||
context = pango_layout_get_context (label_layout);
|
||||
new_layout = pango_layout_new (context);
|
||||
fd = pango_font_description_from_string (TEST_FONT);
|
||||
pango_layout_set_font_description (new_layout, fd);
|
||||
pango_font_description_free (fd);
|
||||
|
||||
return new_layout;
|
||||
}
|
||||
|
||||
void
|
||||
test_label_cache (TestConformSimpleFixture *fixture,
|
||||
gconstpointer _data)
|
||||
{
|
||||
CallbackData data;
|
||||
int ret = 0;
|
||||
|
||||
memset (&data, 0, sizeof (data));
|
||||
|
||||
data.stage = clutter_stage_get_default ();
|
||||
|
||||
data.label = clutter_label_new_with_text (TEST_FONT, "");
|
||||
|
||||
data.test_layout = make_layout_like_label (CLUTTER_LABEL (data.label));
|
||||
|
||||
g_signal_connect (data.label, "paint", G_CALLBACK (on_paint), &data);
|
||||
|
||||
clutter_container_add (CLUTTER_CONTAINER (data.stage), data.label, NULL);
|
||||
|
||||
clutter_actor_show (data.stage);
|
||||
|
||||
clutter_threads_add_idle ((GSourceFunc) do_tests, &data);
|
||||
|
||||
clutter_main ();
|
||||
|
||||
printf ("\nOverall result: ");
|
||||
|
||||
if (data.test_failed)
|
||||
{
|
||||
printf ("FAIL\n");
|
||||
exit (1);
|
||||
}
|
||||
else
|
||||
printf ("pass\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
106
tests/conform/test-pick.c
Normal file
106
tests/conform/test-pick.c
Normal file
@@ -0,0 +1,106 @@
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include "test-conform-common.h"
|
||||
|
||||
#define STAGE_WIDTH 320
|
||||
#define STAGE_HEIGHT 200
|
||||
#define ACTORS_X 12
|
||||
#define ACTORS_Y 16
|
||||
|
||||
typedef struct _State State;
|
||||
|
||||
struct _State
|
||||
{
|
||||
ClutterActor *stage;
|
||||
int y, x;
|
||||
guint32 gids[ACTORS_X * ACTORS_Y];
|
||||
guint actor_width, actor_height;
|
||||
int ret;
|
||||
};
|
||||
|
||||
static gboolean
|
||||
on_timeout (State *state)
|
||||
{
|
||||
int y, x;
|
||||
|
||||
for (y = 0; y < ACTORS_Y; y++)
|
||||
for (x = 0; x < ACTORS_X; x++)
|
||||
{
|
||||
gboolean pass = FALSE;
|
||||
guint32 gid;
|
||||
ClutterActor *actor
|
||||
= clutter_stage_get_actor_at_pos (CLUTTER_STAGE (state->stage),
|
||||
x * state->actor_width
|
||||
+ state->actor_width / 2,
|
||||
y * state->actor_height
|
||||
+ state->actor_height / 2);
|
||||
|
||||
printf ("actor %u -> ", state->gids[y * ACTORS_X + x]);
|
||||
|
||||
if (actor == NULL)
|
||||
printf ("NULL: FAIL\n");
|
||||
else
|
||||
{
|
||||
gid = clutter_actor_get_gid (actor);
|
||||
if (gid == state->gids[y * ACTORS_X + x])
|
||||
pass = TRUE;
|
||||
printf ("% 8i: %s\n", gid, pass ? "pass" : "FAIL");
|
||||
}
|
||||
|
||||
if (!pass)
|
||||
state->ret = 1;
|
||||
}
|
||||
|
||||
clutter_main_quit ();
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
test_pick (TestConformSimpleFixture *fixture,
|
||||
gconstpointer data)
|
||||
{
|
||||
int y, x;
|
||||
State state;
|
||||
|
||||
state.ret = 0;
|
||||
|
||||
state.stage = clutter_stage_new ();
|
||||
|
||||
clutter_actor_set_size (state.stage, STAGE_WIDTH, STAGE_HEIGHT);
|
||||
state.actor_width = STAGE_WIDTH / ACTORS_X;
|
||||
state.actor_height = STAGE_HEIGHT / ACTORS_Y;
|
||||
|
||||
for (y = 0; y < ACTORS_Y; y++)
|
||||
for (x = 0; x < ACTORS_X; x++)
|
||||
{
|
||||
ClutterColor color = { x * 255 / (ACTORS_X - 1),
|
||||
y * 255 / (ACTORS_Y - 1),
|
||||
128, 255 };
|
||||
ClutterGeometry geom = { x * state.actor_width, y * state.actor_height,
|
||||
state.actor_width, state.actor_height };
|
||||
ClutterActor *rect = clutter_rectangle_new_with_color (&color);
|
||||
|
||||
clutter_actor_set_geometry (rect, &geom);
|
||||
|
||||
clutter_container_add (CLUTTER_CONTAINER (state.stage), rect, NULL);
|
||||
|
||||
state.gids[y * ACTORS_X + x] = clutter_actor_get_gid (rect);
|
||||
}
|
||||
|
||||
clutter_actor_show (state.stage);
|
||||
|
||||
g_timeout_add (250, (GSourceFunc) on_timeout, &state);
|
||||
|
||||
clutter_main ();
|
||||
|
||||
clutter_actor_destroy (state.stage);
|
||||
|
||||
printf ("end result: %s\n", state.ret ? "FAIL" : "pass");
|
||||
|
||||
if (state.ret)
|
||||
exit (state.ret);
|
||||
|
||||
return;
|
||||
}
|
||||
|
101
tests/conform/test-timeline-dup-frames.c
Normal file
101
tests/conform/test-timeline-dup-frames.c
Normal file
@@ -0,0 +1,101 @@
|
||||
#include <stdlib.h>
|
||||
#include <glib.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include "test-conform-common.h"
|
||||
|
||||
/* We use a nice slow timeline for this test since we
|
||||
* dont want the timeouts to interpolate the timeline
|
||||
* forward multiple frames */
|
||||
#define TEST_TIMELINE_FPS 10
|
||||
#define TEST_TIMELINE_FRAME_COUNT 20
|
||||
|
||||
typedef struct _TestState {
|
||||
ClutterTimeline *timeline;
|
||||
gint prev_frame;
|
||||
gint completion_count;
|
||||
gint passed;
|
||||
}TestState;
|
||||
|
||||
|
||||
static void
|
||||
new_frame_cb (ClutterTimeline *timeline,
|
||||
gint frame_num,
|
||||
TestState *state)
|
||||
{
|
||||
gint current_frame = clutter_timeline_get_current_frame (state->timeline);
|
||||
|
||||
if (state->prev_frame
|
||||
!= clutter_timeline_get_current_frame (state->timeline))
|
||||
{
|
||||
g_test_message ("timeline previous frame=%-4i "
|
||||
"actual frame=%-4i (OK)\n",
|
||||
state->prev_frame,
|
||||
current_frame);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_test_message ("timeline previous frame=%-4i "
|
||||
"actual frame=%-4i (FAILED)\n",
|
||||
state->prev_frame,
|
||||
current_frame);
|
||||
|
||||
state->passed = FALSE;
|
||||
}
|
||||
|
||||
state->prev_frame = current_frame;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
completed_cb (ClutterTimeline *timeline,
|
||||
TestState *state)
|
||||
{
|
||||
state->completion_count++;
|
||||
|
||||
if (state->completion_count == 2)
|
||||
{
|
||||
if (state->passed)
|
||||
{
|
||||
g_test_message ("Passed\n");
|
||||
clutter_main_quit ();
|
||||
}
|
||||
else
|
||||
{
|
||||
g_test_message ("Failed\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
test_timeline_dup_frames (TestConformSimpleFixture *fixture,
|
||||
gconstpointer data)
|
||||
{
|
||||
TestState state;
|
||||
|
||||
state.timeline =
|
||||
clutter_timeline_new (TEST_TIMELINE_FRAME_COUNT,
|
||||
TEST_TIMELINE_FPS);
|
||||
clutter_timeline_set_loop (state.timeline, TRUE);
|
||||
g_signal_connect (G_OBJECT(state.timeline),
|
||||
"new-frame",
|
||||
G_CALLBACK(new_frame_cb),
|
||||
&state);
|
||||
g_signal_connect (G_OBJECT(state.timeline),
|
||||
"completed",
|
||||
G_CALLBACK(completed_cb),
|
||||
&state);
|
||||
|
||||
state.prev_frame = -1;
|
||||
state.completion_count = 0;
|
||||
state.passed = TRUE;
|
||||
|
||||
clutter_timeline_start (state.timeline);
|
||||
|
||||
clutter_main();
|
||||
|
||||
g_object_unref (state.timeline);
|
||||
}
|
||||
|
165
tests/conform/test-timeline-interpolate.c
Normal file
165
tests/conform/test-timeline-interpolate.c
Normal file
@@ -0,0 +1,165 @@
|
||||
#include <stdlib.h>
|
||||
#include <glib.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include "test-conform-common.h"
|
||||
|
||||
/* We ask for 1 frame per millisecond.
|
||||
* Whenever this rate can't be achieved then the timeline
|
||||
* will interpolate the number frames that should have
|
||||
* passed between timeouts. */
|
||||
#define TEST_TIMELINE_FPS 1000
|
||||
#define TEST_TIMELINE_FRAME_COUNT 5000
|
||||
|
||||
/* We are at the mercy of the system scheduler so this
|
||||
* may not be a very reliable tolerance. */
|
||||
#define TEST_ERROR_TOLERANCE 20
|
||||
|
||||
typedef struct _TestState {
|
||||
ClutterTimeline *timeline;
|
||||
GTimeVal start_time;
|
||||
guint new_frame_counter;
|
||||
gint expected_frame;
|
||||
gint completion_count;
|
||||
gboolean passed;
|
||||
}TestState;
|
||||
|
||||
|
||||
static void
|
||||
new_frame_cb (ClutterTimeline *timeline,
|
||||
gint frame_num,
|
||||
TestState *state)
|
||||
{
|
||||
GTimeVal current_time;
|
||||
gint current_frame;
|
||||
glong msec_diff;
|
||||
gint loop_overflow = 0;
|
||||
static gint step = 1;
|
||||
|
||||
g_get_current_time (¤t_time);
|
||||
|
||||
current_frame = clutter_timeline_get_current_frame (state->timeline);
|
||||
|
||||
msec_diff = (current_time.tv_sec - state->start_time.tv_sec) * 1000;
|
||||
msec_diff += (current_time.tv_usec - state->start_time.tv_usec)/1000;
|
||||
|
||||
/* If we expect to have interpolated past the end of the timeline
|
||||
* we keep track of the overflow so we can determine when
|
||||
* the next timeout will happen. We then clip expected_frames
|
||||
* to TEST_TIMELINE_FRAME_COUNT since clutter-timeline
|
||||
* semantics guaranty this frame is always signaled before
|
||||
* looping */
|
||||
if (state->expected_frame > TEST_TIMELINE_FRAME_COUNT)
|
||||
{
|
||||
loop_overflow = state->expected_frame - TEST_TIMELINE_FRAME_COUNT;
|
||||
state->expected_frame = TEST_TIMELINE_FRAME_COUNT;
|
||||
}
|
||||
|
||||
if (current_frame >= (state->expected_frame-TEST_ERROR_TOLERANCE)
|
||||
&& current_frame <= (state->expected_frame+TEST_ERROR_TOLERANCE))
|
||||
{
|
||||
g_test_message ("\nelapsed milliseconds=%-5li "
|
||||
"expected frame=%-4i actual frame=%-4i (OK)\n",
|
||||
msec_diff,
|
||||
state->expected_frame,
|
||||
current_frame);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_test_message ("\nelapsed milliseconds=%-5li "
|
||||
"expected frame=%-4i actual frame=%-4i (FAILED)\n",
|
||||
msec_diff,
|
||||
state->expected_frame,
|
||||
current_frame);
|
||||
state->passed = FALSE;
|
||||
}
|
||||
|
||||
if (step>0)
|
||||
{
|
||||
state->expected_frame = current_frame + (TEST_TIMELINE_FPS / 4);
|
||||
g_test_message ("Sleeping for 250ms "
|
||||
"so next frame should be (%i + %i) = %i\n",
|
||||
current_frame,
|
||||
(TEST_TIMELINE_FPS / 4),
|
||||
state->expected_frame);
|
||||
g_usleep (250000);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->expected_frame = current_frame + TEST_TIMELINE_FPS;
|
||||
g_test_message ("Sleeping for 1sec "
|
||||
"so next frame should be (%i + %i) = %i\n",
|
||||
current_frame,
|
||||
TEST_TIMELINE_FPS,
|
||||
state->expected_frame);
|
||||
g_usleep (1000000);
|
||||
}
|
||||
|
||||
if (current_frame >= TEST_TIMELINE_FRAME_COUNT)
|
||||
{
|
||||
state->expected_frame += loop_overflow;
|
||||
state->expected_frame -= TEST_TIMELINE_FRAME_COUNT;
|
||||
g_test_message ("End of timeline reached: "
|
||||
"Wrapping expected frame too %i\n",
|
||||
state->expected_frame);
|
||||
}
|
||||
|
||||
state->new_frame_counter++;
|
||||
step = -step;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
completed_cb (ClutterTimeline *timeline,
|
||||
TestState *state)
|
||||
{
|
||||
state->completion_count++;
|
||||
|
||||
if (state->completion_count == 2)
|
||||
{
|
||||
if (state->passed)
|
||||
{
|
||||
g_test_message ("Passed\n");
|
||||
clutter_main_quit ();
|
||||
}
|
||||
else
|
||||
{
|
||||
g_test_message ("Failed\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
test_timeline_interpolate (TestConformSimpleFixture *fixture,
|
||||
gconstpointer data)
|
||||
{
|
||||
TestState state;
|
||||
|
||||
state.timeline =
|
||||
clutter_timeline_new (TEST_TIMELINE_FRAME_COUNT,
|
||||
TEST_TIMELINE_FPS);
|
||||
clutter_timeline_set_loop (state.timeline, TRUE);
|
||||
g_signal_connect (G_OBJECT(state.timeline),
|
||||
"new-frame",
|
||||
G_CALLBACK(new_frame_cb),
|
||||
&state);
|
||||
g_signal_connect (G_OBJECT(state.timeline),
|
||||
"completed",
|
||||
G_CALLBACK(completed_cb),
|
||||
&state);
|
||||
|
||||
state.completion_count = 0;
|
||||
state.new_frame_counter = 0;
|
||||
state.passed = TRUE;
|
||||
state.expected_frame = 0;
|
||||
|
||||
g_get_current_time (&state.start_time);
|
||||
clutter_timeline_start (state.timeline);
|
||||
|
||||
clutter_main();
|
||||
|
||||
g_object_unref (state.timeline);
|
||||
}
|
||||
|
98
tests/conform/test-timeline-rewind.c
Normal file
98
tests/conform/test-timeline-rewind.c
Normal file
@@ -0,0 +1,98 @@
|
||||
#include <stdlib.h>
|
||||
#include <glib.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include "test-conform-common.h"
|
||||
|
||||
#define TEST_TIMELINE_FPS 10
|
||||
#define TEST_TIMELINE_FRAME_COUNT 5
|
||||
#define TEST_WATCHDOG_KICK_IN_SECONDS 10
|
||||
|
||||
typedef struct _TestState {
|
||||
ClutterTimeline *timeline;
|
||||
gint rewind_count;
|
||||
}TestState;
|
||||
|
||||
|
||||
static gboolean
|
||||
watchdog_timeout (TestState *state)
|
||||
{
|
||||
g_test_message ("Watchdog timer kicking in\n");
|
||||
g_test_message ("rewind_count=%i\n", state->rewind_count);
|
||||
if (state->rewind_count <= 3)
|
||||
{
|
||||
/* The test has hung */
|
||||
g_test_message ("Failed (This test shouldn't have hung!)\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_test_message ("Passed\n");
|
||||
clutter_main_quit ();
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
new_frame_cb (ClutterTimeline *timeline,
|
||||
gint frame_num,
|
||||
TestState *state)
|
||||
{
|
||||
gint current_frame = clutter_timeline_get_current_frame (timeline);
|
||||
|
||||
if (current_frame == TEST_TIMELINE_FRAME_COUNT)
|
||||
{
|
||||
g_test_message ("new-frame signal recieved (end of timeline)\n");
|
||||
g_test_message ("Rewinding timeline\n");
|
||||
clutter_timeline_rewind (timeline);
|
||||
state->rewind_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (current_frame == 0)
|
||||
{
|
||||
g_test_message ("new-frame signal recieved (start of timeline)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
g_test_message ("new-frame signal recieved (mid frame)\n");
|
||||
}
|
||||
|
||||
if (state->rewind_count >= 2)
|
||||
{
|
||||
g_test_message ("Sleeping for 1 second\n");
|
||||
g_usleep (1000000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
test_timeline_rewind (TestConformSimpleFixture *fixture,
|
||||
gconstpointer data)
|
||||
{
|
||||
TestState state;
|
||||
|
||||
state.timeline =
|
||||
clutter_timeline_new (TEST_TIMELINE_FRAME_COUNT,
|
||||
TEST_TIMELINE_FPS);
|
||||
g_signal_connect (G_OBJECT(state.timeline),
|
||||
"new-frame",
|
||||
G_CALLBACK(new_frame_cb),
|
||||
&state);
|
||||
g_test_message ("Installing a watchdog timeout "
|
||||
"to determine if this test hangs\n");
|
||||
g_timeout_add (TEST_WATCHDOG_KICK_IN_SECONDS*1000,
|
||||
(GSourceFunc)watchdog_timeout,
|
||||
&state);
|
||||
state.rewind_count = 0;
|
||||
|
||||
clutter_timeline_start (state.timeline);
|
||||
|
||||
clutter_main();
|
||||
|
||||
g_object_unref (state.timeline);
|
||||
}
|
||||
|
115
tests/conform/test-timeline-smoothness.c
Normal file
115
tests/conform/test-timeline-smoothness.c
Normal file
@@ -0,0 +1,115 @@
|
||||
#include <stdlib.h>
|
||||
#include <glib.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include "test-conform-common.h"
|
||||
|
||||
#define TEST_TIMELINE_FPS 10
|
||||
#define TEST_TIMELINE_FRAME_COUNT 20
|
||||
#define TEST_ERROR_TOLERANCE 5
|
||||
|
||||
typedef struct _TestState {
|
||||
ClutterTimeline *timeline;
|
||||
GTimeVal start_time;
|
||||
GTimeVal prev_frame_time;
|
||||
guint frame;
|
||||
gint completion_count;
|
||||
gint passed;
|
||||
}TestState;
|
||||
|
||||
|
||||
static void
|
||||
new_frame_cb (ClutterTimeline *timeline,
|
||||
gint frame_num,
|
||||
TestState *state)
|
||||
{
|
||||
GTimeVal current_time;
|
||||
glong total_elapsed_ms;
|
||||
glong frame_elapsed_ms = 0;
|
||||
gchar *bump = "";
|
||||
|
||||
g_get_current_time (¤t_time);
|
||||
|
||||
total_elapsed_ms = (current_time.tv_sec - state->start_time.tv_sec) * 1000;
|
||||
total_elapsed_ms += (current_time.tv_usec - state->start_time.tv_usec)/1000;
|
||||
|
||||
if (state->frame>0)
|
||||
{
|
||||
frame_elapsed_ms =
|
||||
(current_time.tv_sec - state->prev_frame_time.tv_sec) * 1000;
|
||||
frame_elapsed_ms +=
|
||||
(current_time.tv_usec - state->prev_frame_time.tv_usec)/1000;
|
||||
|
||||
if (ABS(frame_elapsed_ms - (1000/TEST_TIMELINE_FPS))
|
||||
> TEST_ERROR_TOLERANCE)
|
||||
{
|
||||
state->passed = FALSE;
|
||||
bump = " (BUMP)";
|
||||
}
|
||||
}
|
||||
|
||||
g_test_message ("timeline frame=%-2d total elapsed=%-4li(ms) "
|
||||
"since last frame=%-4li(ms)%s\n",
|
||||
clutter_timeline_get_current_frame(state->timeline),
|
||||
total_elapsed_ms,
|
||||
frame_elapsed_ms,
|
||||
bump);
|
||||
|
||||
state->prev_frame_time = current_time;
|
||||
state->frame++;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
completed_cb (ClutterTimeline *timeline,
|
||||
TestState *state)
|
||||
{
|
||||
state->completion_count++;
|
||||
|
||||
if (state->completion_count == 2)
|
||||
{
|
||||
if (state->passed)
|
||||
{
|
||||
g_test_message ("Passed\n");
|
||||
clutter_main_quit ();
|
||||
}
|
||||
else
|
||||
{
|
||||
g_test_message ("Failed\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
test_timeline_smoothness (TestConformSimpleFixture *fixture,
|
||||
gconstpointer data)
|
||||
{
|
||||
TestState state;
|
||||
|
||||
state.timeline =
|
||||
clutter_timeline_new (TEST_TIMELINE_FRAME_COUNT,
|
||||
TEST_TIMELINE_FPS);
|
||||
clutter_timeline_set_loop (state.timeline, TRUE);
|
||||
g_signal_connect (G_OBJECT(state.timeline),
|
||||
"new-frame",
|
||||
G_CALLBACK(new_frame_cb),
|
||||
&state);
|
||||
g_signal_connect (G_OBJECT(state.timeline),
|
||||
"completed",
|
||||
G_CALLBACK(completed_cb),
|
||||
&state);
|
||||
|
||||
state.frame = 0;
|
||||
state.completion_count = 0;
|
||||
state.passed = TRUE;
|
||||
|
||||
g_get_current_time (&state.start_time);
|
||||
clutter_timeline_start (state.timeline);
|
||||
|
||||
clutter_main();
|
||||
|
||||
g_object_unref (state.timeline);
|
||||
}
|
||||
|
140
tests/conform/test-timeline.c
Normal file
140
tests/conform/test-timeline.c
Normal file
@@ -0,0 +1,140 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <gmodule.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
static void
|
||||
timeline_1_complete (ClutterTimeline *timeline)
|
||||
{
|
||||
g_debug ("1: Completed");
|
||||
}
|
||||
|
||||
static void
|
||||
timeline_2_complete (ClutterTimeline *timeline)
|
||||
{
|
||||
g_debug ("2: Completed");
|
||||
}
|
||||
|
||||
static void
|
||||
timeline_3_complete (ClutterTimeline *timeline)
|
||||
{
|
||||
g_debug ("3: Completed");
|
||||
}
|
||||
|
||||
static void
|
||||
timeline_1_new_frame_cb (ClutterTimeline *timeline, gint frame_no)
|
||||
{
|
||||
g_debug ("1: Doing frame %d.", frame_no);
|
||||
}
|
||||
|
||||
static void
|
||||
timeline_2_new_frame_cb (ClutterTimeline *timeline, gint frame_no)
|
||||
{
|
||||
g_debug ("2: Doing frame %d.", frame_no);
|
||||
}
|
||||
|
||||
static void
|
||||
timeline_3_new_frame_cb (ClutterTimeline *timeline, gint frame_no)
|
||||
{
|
||||
g_debug ("3: Doing frame %d.", frame_no);
|
||||
}
|
||||
|
||||
static void
|
||||
timeline_1_marker_reached (ClutterTimeline *timeline,
|
||||
const gchar *marker_name,
|
||||
guint frame_num)
|
||||
{
|
||||
g_print ("1: Marker `%s' (%d) reached\n", marker_name, frame_num);
|
||||
}
|
||||
|
||||
static void
|
||||
timeline_2_marker_reached (ClutterTimeline *timeline,
|
||||
const gchar *marker_name,
|
||||
guint frame_num)
|
||||
{
|
||||
g_print ("2: Marker `%s' (%d) reached\n", marker_name, frame_num);
|
||||
}
|
||||
|
||||
static void
|
||||
timeline_3_marker_reached (ClutterTimeline *timeline,
|
||||
const gchar *marker_name,
|
||||
guint frame_num)
|
||||
{
|
||||
g_print ("3: Marker `%s' (%d) reached\n", marker_name, frame_num);
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT int
|
||||
test_timeline_main (int argc, char **argv)
|
||||
{
|
||||
ClutterTimeline *timeline_1;
|
||||
ClutterTimeline *timeline_2;
|
||||
ClutterTimeline *timeline_3;
|
||||
gchar **markers;
|
||||
gsize n_markers;
|
||||
|
||||
clutter_init (&argc, &argv);
|
||||
|
||||
timeline_1 = clutter_timeline_new (10, 120);
|
||||
clutter_timeline_add_marker_at_frame (timeline_1, "foo", 5);
|
||||
clutter_timeline_add_marker_at_frame (timeline_1, "bar", 5);
|
||||
clutter_timeline_add_marker_at_frame (timeline_1, "baz", 5);
|
||||
markers = clutter_timeline_list_markers (timeline_1, 5, &n_markers);
|
||||
g_assert (markers != NULL);
|
||||
g_assert (n_markers == 3);
|
||||
g_strfreev (markers);
|
||||
|
||||
timeline_2 = clutter_timeline_clone (timeline_1);
|
||||
clutter_timeline_add_marker_at_frame (timeline_2, "bar", 2);
|
||||
markers = clutter_timeline_list_markers (timeline_2, -1, &n_markers);
|
||||
g_assert (markers != NULL);
|
||||
g_assert (n_markers == 1);
|
||||
g_assert (strcmp (markers[0], "bar") == 0);
|
||||
g_strfreev (markers);
|
||||
|
||||
timeline_3 = clutter_timeline_clone (timeline_1);
|
||||
clutter_timeline_set_direction (timeline_3, CLUTTER_TIMELINE_BACKWARD);
|
||||
clutter_timeline_add_marker_at_frame (timeline_3, "baz", 8);
|
||||
|
||||
g_signal_connect (timeline_1,
|
||||
"marker-reached", G_CALLBACK (timeline_1_marker_reached),
|
||||
NULL);
|
||||
g_signal_connect (timeline_1,
|
||||
"new-frame", G_CALLBACK (timeline_1_new_frame_cb),
|
||||
NULL);
|
||||
g_signal_connect (timeline_1,
|
||||
"completed", G_CALLBACK (timeline_1_complete),
|
||||
NULL);
|
||||
|
||||
g_signal_connect (timeline_2,
|
||||
"marker-reached::bar", G_CALLBACK (timeline_2_marker_reached),
|
||||
NULL);
|
||||
g_signal_connect (timeline_2,
|
||||
"new-frame", G_CALLBACK (timeline_2_new_frame_cb),
|
||||
NULL);
|
||||
g_signal_connect (timeline_2,
|
||||
"completed", G_CALLBACK (timeline_2_complete),
|
||||
NULL);
|
||||
|
||||
g_signal_connect (timeline_3,
|
||||
"marker-reached", G_CALLBACK (timeline_3_marker_reached),
|
||||
NULL);
|
||||
g_signal_connect (timeline_3,
|
||||
"new-frame", G_CALLBACK (timeline_3_new_frame_cb),
|
||||
NULL);
|
||||
g_signal_connect (timeline_3,
|
||||
"completed", G_CALLBACK (timeline_3_complete),
|
||||
NULL);
|
||||
|
||||
clutter_timeline_start (timeline_1);
|
||||
clutter_timeline_start (timeline_2);
|
||||
clutter_timeline_start (timeline_3);
|
||||
|
||||
clutter_main ();
|
||||
|
||||
g_object_unref (timeline_1);
|
||||
g_object_unref (timeline_2);
|
||||
g_object_unref (timeline_3);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
15
tests/conform/wrapper.sh
Executable file
15
tests/conform/wrapper.sh
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
|
||||
UNIT_TEST=`basename $0`
|
||||
UNIT_TEST_PATH=`./test-conformance -l |grep $UNIT_TEST`
|
||||
|
||||
echo "Running: gtester -p $UNIT_TEST_PATH ./test-conformance"
|
||||
echo ""
|
||||
gtester -p $UNIT_TEST_PATH ./test-conformance
|
||||
|
||||
echo ""
|
||||
echo "NOTE: For debugging purposes, you can run this single test as follows:"
|
||||
echo "$ libtool --mode=execute \\"
|
||||
echo " gdb --eval-command=\"b $UNIT_TEST\" \\"
|
||||
echo " --args ./test-conformance -p $UNIT_TEST_PATH"
|
||||
|
Reference in New Issue
Block a user