[Spice-devel] [spice-common v2 13/13] quic: Add test case for compression/decompression
Christophe Fergeau
cfergeau at redhat.com
Wed Aug 2 08:15:10 UTC 2017
This only adds a basic test relying on gdk-pixbuf.
The main limitation is that gdk-pixbuf does not handle 16bpp images,
nor 32bpp/no alpha images. I should have picked something else instead ;)
This allows at least to exercise the QUIC_IMAGE_TYPE_RGB24 and
QUIC_IMAGE_TYPE_RGBA codepaths.
Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>
---
configure.ac | 1 +
m4/spice-deps.m4 | 15 ++++
tests/Makefile.am | 22 +++++
tests/test-quic.c | 235 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 273 insertions(+)
create mode 100644 tests/test-quic.c
diff --git a/configure.ac b/configure.ac
index 3542161..1f2ecc0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -47,6 +47,7 @@ SPICE_CHECK_CELT051
SPICE_CHECK_GLIB2
SPICE_CHECK_OPUS
SPICE_CHECK_OPENSSL
+SPICE_CHECK_GDK_PIXBUF
SPICE_COMMON_CFLAGS='$(PIXMAN_CFLAGS) $(SMARTCARD_CFLAGS) $(CELT051_CFLAGS) $(GLIB2_CFLAGS) $(OPUS_CFLAGS) $(OPENSSL_CFLAGS)'
SPICE_COMMON_CFLAGS="$SPICE_COMMON_CFLAGS -DG_LOG_DOMAIN=\\\"Spice\\\""
diff --git a/m4/spice-deps.m4 b/m4/spice-deps.m4
index 68e3091..3fe4a5b 100644
--- a/m4/spice-deps.m4
+++ b/m4/spice-deps.m4
@@ -147,6 +147,21 @@ AC_DEFUN([SPICE_CHECK_GLIB2], [
PKG_CHECK_MODULES(GLIB2, glib-2.0 >= 2.22 gio-2.0 >= 2.22 gthread-2.0 >= 2.22)
])
+# SPICE_CHECK_GDK_PIXBUF
+# ----------------------
+# Check for the availability of gdk-pixbuf. If found, it will return the flags to use
+# in the GDK_PIXBUF_CFLAGS and GDK_PIXBUF_LIBS variables, and it will define a
+# HAVE_GDK_PIXBUF preprocessor symbol as well as a HAVE_GDK_PIXBUF Makefile conditional.
+# ----------------
+AC_DEFUN([SPICE_CHECK_GDK_PIXBUF], [
+ PKG_CHECK_MODULES([GDK_PIXBUF], [gdk-pixbuf-2.0], [have_gdk_pixbuf=yes], [have_gdk_pixbuf=no])
+
+ AM_CONDITIONAL([HAVE_GDK_PIXBUF], [test "x$have_gdk_pixbuf" = "xyes"])
+ if test "x$have_gdk_pixbuf" = "xyes" ; then
+ AC_DEFINE([HAVE_GDK_PIXBUF], [1], [Define if gdk-pixbuf was found])
+ fi
+])
+
# SPICE_CHECK_PYTHON_MODULES()
# --------------------------
# Adds a --enable-python-checks configure flags as well as checks for the
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 10033c0..02f679d 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,6 +1,9 @@
NULL =
TESTS = test_logging test_marshallers
+if HAVE_GDK_PIXBUF
+TESTS += test_quic
+endif
noinst_PROGRAMS = $(TESTS)
test_logging_SOURCES = test-logging.c
@@ -33,6 +36,25 @@ test_marshallers_LDADD = \
$(GLIB2_LIBS) \
$(NULL)
+
+if HAVE_GDK_PIXBUF
+test_quic_SOURCES = \
+ test-quic.c \
+ $(NULL)
+test_quic_CFLAGS = \
+ -I$(top_srcdir) \
+ $(GLIB2_CFLAGS) \
+ $(GDK_PIXBUF_CFLAGS) \
+ $(PROTOCOL_CFLAGS) \
+ $(NULL)
+test_quic_LDADD = \
+ $(top_builddir)/common/libspice-common.la \
+ $(GLIB2_LIBS) \
+ $(GDK_PIXBUF_LIBS) \
+ $(NULL)
+endif
+
+
# Avoid need for python(pyparsing) by end users
TEST_MARSHALLERS = \
generated_test_marshallers.c \
diff --git a/tests/test-quic.c b/tests/test-quic.c
new file mode 100644
index 0000000..b45794f
--- /dev/null
+++ b/tests/test-quic.c
@@ -0,0 +1,235 @@
+#include "common/quic.h"
+#include <glib.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+typedef struct {
+ QuicUsrContext usr;
+ GByteArray *dest;
+} QuicData;
+
+static SPICE_GNUC_NORETURN SPICE_GNUC_PRINTF(2, 3) void
+quic_usr_error(QuicUsrContext *usr, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, fmt, ap);
+ va_end(ap);
+
+ g_assert_not_reached();
+}
+
+static SPICE_GNUC_PRINTF(2, 3) void
+quic_usr_warn(QuicUsrContext *usr, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, fmt, ap);
+ va_end(ap);
+}
+
+static void *quic_usr_malloc(QuicUsrContext *usr, int size)
+{
+ return g_malloc(size);
+}
+
+
+static void quic_usr_free(QuicUsrContext *usr, void *ptr)
+{
+ g_free(ptr);
+}
+
+static int quic_usr_more_space(QuicUsrContext *usr, uint32_t **io_ptr, int rows_completed)
+{
+ QuicData *quic_data = (QuicData *)usr;
+ int initial_len = quic_data->dest->len;
+
+ g_byte_array_set_size(quic_data->dest, quic_data->dest->len*2);
+
+ *io_ptr = (uint32_t *)(quic_data->dest->data + initial_len);
+ return (quic_data->dest->len - initial_len)/4;
+}
+
+
+static int quic_usr_more_lines(QuicUsrContext *usr, uint8_t **lines)
+{
+ g_return_val_if_reached(0);
+}
+
+
+static void init_quic_data(QuicData *quic_data)
+{
+ quic_data->usr.error = quic_usr_error;
+ quic_data->usr.warn = quic_usr_warn;
+ quic_data->usr.info = quic_usr_warn;
+ quic_data->usr.malloc = quic_usr_malloc;
+ quic_data->usr.free = quic_usr_free;
+ quic_data->usr.more_space = quic_usr_more_space;
+ quic_data->usr.more_lines = quic_usr_more_lines;
+ quic_data->dest = g_byte_array_new();
+}
+
+static GByteArray *quic_encode_from_pixbuf(GdkPixbuf *pixbuf)
+{
+ QuicData quic_data;
+ QuicContext *quic;
+ int encoded_size;
+ QuicImageType quic_type;
+
+ init_quic_data(&quic_data);
+ g_byte_array_set_size(quic_data.dest, 1024);
+
+ quic = quic_create(&quic_data.usr);
+ g_assert(quic != NULL);
+ switch (gdk_pixbuf_get_n_channels(pixbuf)) {
+ case 3:
+ quic_type = QUIC_IMAGE_TYPE_RGB24;
+ break;
+ case 4:
+ quic_type = QUIC_IMAGE_TYPE_RGBA;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ encoded_size = quic_encode(quic, quic_type,
+ gdk_pixbuf_get_width(pixbuf),
+ gdk_pixbuf_get_height(pixbuf),
+ gdk_pixbuf_get_pixels(pixbuf),
+ gdk_pixbuf_get_height(pixbuf),
+ gdk_pixbuf_get_rowstride(pixbuf),
+ (uint32_t *)quic_data.dest->data,
+ quic_data.dest->len/sizeof(uint32_t));
+ encoded_size *= 4;
+ g_byte_array_set_size(quic_data.dest, encoded_size);
+ quic_destroy(quic);
+
+ return quic_data.dest;
+}
+
+static GdkPixbuf *quic_decode_to_pixbuf(GByteArray *compressed_data)
+{
+ QuicData quic_data;
+ QuicContext *quic;
+ int encoded_size;
+ QuicImageType quic_type;
+ GdkPixbuf *pixbuf;
+ QuicImageType type;
+ int width;
+ int height;
+ int status;
+
+ init_quic_data(&quic_data);
+ g_byte_array_free(quic_data.dest, TRUE);
+ quic_data.dest = NULL;
+
+ quic = quic_create(&quic_data.usr);
+ g_assert(quic != NULL);
+
+ status = quic_decode_begin(quic,
+ (uint32_t *)compressed_data->data, compressed_data->len/4,
+ &type, &width, &height);
+ g_assert(status == QUIC_OK);
+
+ pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
+ (type == QUIC_IMAGE_TYPE_RGBA), 8,
+ width, height);
+ status = quic_decode(quic, type,
+ gdk_pixbuf_get_pixels(pixbuf),
+ gdk_pixbuf_get_rowstride(pixbuf));
+ g_assert(status == QUIC_OK);
+ quic_destroy(quic);
+
+ return pixbuf;
+}
+
+static void gdk_pixbuf_compare(GdkPixbuf *pixbuf_a, GdkPixbuf *pixbuf_b)
+{
+ int width = gdk_pixbuf_get_width(pixbuf_a);
+ int height = gdk_pixbuf_get_height(pixbuf_a);
+ int n_channels = gdk_pixbuf_get_n_channels (pixbuf_a);
+ int x;
+ int y;
+ guint8 *pixels_a = gdk_pixbuf_get_pixels(pixbuf_a);
+ guint8 *pixels_b = gdk_pixbuf_get_pixels(pixbuf_a);
+
+ g_assert(width == gdk_pixbuf_get_width(pixbuf_b));
+ g_assert(height == gdk_pixbuf_get_height(pixbuf_b));
+ g_assert(n_channels == gdk_pixbuf_get_n_channels (pixbuf_b));
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ guint8 *p_a = pixels_a + y*gdk_pixbuf_get_rowstride(pixbuf_a) + x*n_channels;
+ guint8 *p_b = pixels_b + y*gdk_pixbuf_get_rowstride(pixbuf_b) + x*n_channels;
+
+ g_assert(p_a[0] == p_b[0]);
+ g_assert(p_a[1] == p_b[1]);
+ g_assert(p_a[2] == p_b[2]);
+ if (gdk_pixbuf_get_has_alpha(pixbuf_a)) {
+ g_assert(p_a[3] == p_b[3]);
+ }
+ }
+ }
+}
+
+static GdkPixbuf *gdk_pixbuf_new_random(void)
+{
+ gboolean has_alpha = g_random_boolean();
+ gint n_channels = g_random_int_range(3, 5);
+ gint width = g_random_int_range(100, 2000);
+ gint height = g_random_int_range(100, 2000);
+ GdkPixbuf *random_pixbuf;
+ gint i;
+ guint8 *pixels;
+
+ random_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, has_alpha, 8, width, height);
+ pixels = gdk_pixbuf_get_pixels(random_pixbuf);
+ for (i = 0; i < gdk_pixbuf_get_byte_length(random_pixbuf); i++) {
+ pixels[i] = g_random_int_range(0, 256);
+ }
+
+ return random_pixbuf;
+}
+
+static void test_pixbuf(GdkPixbuf *pixbuf)
+{
+ GdkPixbuf *uncompressed_pixbuf;
+ GByteArray *compressed_data;
+ g_assert(pixbuf != NULL);
+ g_assert (gdk_pixbuf_get_colorspace(pixbuf) == GDK_COLORSPACE_RGB);
+ g_assert (gdk_pixbuf_get_bits_per_sample(pixbuf) == 8);
+
+ compressed_data = quic_encode_from_pixbuf(pixbuf);
+
+ uncompressed_pixbuf = quic_decode_to_pixbuf(compressed_data);
+
+ g_assert(gdk_pixbuf_get_byte_length(pixbuf) == gdk_pixbuf_get_byte_length(uncompressed_pixbuf));
+ //g_assert(memcmp(gdk_pixbuf_get_pixels(pixbuf), gdk_pixbuf_get_pixels(uncompressed_pixbuf), gdk_pixbuf_get_byte_length(uncompressed_pixbuf)));
+ gdk_pixbuf_compare(pixbuf, uncompressed_pixbuf);
+
+ g_byte_array_free(compressed_data, TRUE);
+ g_object_unref(uncompressed_pixbuf);
+
+}
+
+int main(int argc, char **argv)
+{
+ if (argc == 2) {
+ GdkPixbuf *source_pixbuf;
+
+ source_pixbuf = gdk_pixbuf_new_from_file(argv[1], NULL);
+ test_pixbuf(source_pixbuf);
+ g_object_unref(source_pixbuf);
+ } else if (argc == 1) {
+ unsigned int count;
+
+ for (count = 0; count < 50; count++) {
+ GdkPixbuf *pixbuf = gdk_pixbuf_new_random();
+ test_pixbuf(pixbuf);
+ g_object_unref(pixbuf);
+ }
+ } else {
+ g_assert_not_reached();
+ }
+
+ return 0;
+}
--
2.13.3
More information about the Spice-devel
mailing list