[Spice-devel] [spice-common v2 13/13] quic: Add test case for compression/decompression

Frediano Ziglio fziglio at redhat.com
Wed Aug 2 09:32:04 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

I would put these with other lines

>  noinst_PROGRAMS = $(TESTS)
>  
>  test_logging_SOURCES = test-logging.c
> @@ -33,6 +36,25 @@ test_marshallers_LDADD =				\
>  	$(GLIB2_LIBS)			\
>  	$(NULL)
>  
> +
> +if HAVE_GDK_PIXBUF

so here

TESTS += test_quic

> +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
> +
> +

Maybe you want also to add test-quic.c to EXTRA_DIST in order to be
able to build a proper package if gdk-pixbuf is missing.

>  # 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 @@

I would put a license.

> +#include "common/quic.h"

shouldn't you include config.h (or syntax checks would fail) ?

> +#include <glib.h>
> +#include <gdk-pixbuf/gdk-pixbuf.h>

I would include these first.

> +
> +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;
> +}

Frediano


More information about the Spice-devel mailing list