From 83a2d26df3081fff5e14a92daf132400353fddf0 Mon Sep 17 00:00:00 2001 From: hujianwei Date: Fri, 4 Nov 2022 02:41:19 +0000 Subject: [PATCH] Check in tests * tests/Imakefile: * tests/README * tests/basic_test_card.png: * tests/blue.png: * tests/simple_test.c: * tests/simple_test.dump: * tests/svnignore.txt: * tests/test_harness.c: * tests/test_harness.h: New files. --- tests/Imakefile | 37 ++ tests/README | 6 + tests/basic_test_card.png | Bin 0 -> 8347 bytes tests/blue.png | Bin 0 -> 1530 bytes tests/simple_test.c | 171 +++++++++ tests/simple_test.dump | Bin 0 -> 35720 bytes tests/svnignore.txt | 5 + tests/test_harness.c | 753 ++++++++++++++++++++++++++++++++++++++ tests/test_harness.h | 91 +++++ 9 files changed, 1063 insertions(+) create mode 100644 tests/Imakefile create mode 100644 tests/README create mode 100644 tests/basic_test_card.png create mode 100644 tests/blue.png create mode 100644 tests/simple_test.c create mode 100644 tests/simple_test.dump create mode 100644 tests/svnignore.txt create mode 100644 tests/test_harness.c create mode 100644 tests/test_harness.h diff --git a/tests/Imakefile b/tests/Imakefile new file mode 100644 index 0000000..2fb7655 --- /dev/null +++ b/tests/Imakefile @@ -0,0 +1,37 @@ +#include "../12to11.conf" + + 12TO11ROOT = .. + DEPLIBS = $(DEPXLIB) +LOCAL_LIBRARIES = $(WAYLAND_CLIENT) $(XLIB) $(PNG) + COMMONOBJS = test_harness.o + COMMONSRCS = test_harness.c + HEADER = test_harness.h + EXTRA_DEFINES := -D_GNU_SOURCE -U_BSD_SOURCE -U_SVID_SOURCE + +#define ScannerTarget(name) @@\ +name.h: $(12TO11ROOT)/name.xml @@\ + $(WAYLAND_SCANNER) client-header $< $@ @@\ + @@\ +name.c: $(12TO11ROOT)/name.xml name.h @@\ + $(WAYLAND_SCANNER) private-code $< $@ @@\ + @@\ + COMMONOBJS := $(COMMONOBJS) name.o @@\ + COMMONSRCS := $(COMMONSRCS) name.c @@\ + HEADER := $(HEADER) name.h @@\ + +ScannerTarget(12to11-test) + + SRCS1 = $(COMMONSRCS) simple_test.c + OBJS1 = $(COMMONOBJS) simple_test.o + PROGRAMS = simple_test + +/* Make all objects depend on HEADER. */ +$(OBJS1): $(HEADER) + +/* And depend on all sources and headers. */ +depend:: $(HEADER) $(SRCS1) + +NormalProgramTarget(simple_test,$(OBJS1),NullParameter,$(LOCAL_LIBRARIES),NullParameter) +DependTarget3($(SRCS1),NullParameter,NullParameter) + +all:: $(PROGRAMS) diff --git a/tests/README b/tests/README new file mode 100644 index 0000000..b236882 --- /dev/null +++ b/tests/README @@ -0,0 +1,6 @@ +This directory holds some work-in-progress code for testing the +protocol translator. At present, there is only a simple smoke test of +limited utility. + +Each test must be individually run on a system with an a8r8g8b8 +visual, GLOBAL_SCALE and OUTPUT_SCALE set to 1. diff --git a/tests/basic_test_card.png b/tests/basic_test_card.png new file mode 100644 index 0000000000000000000000000000000000000000..027ca852e94d2c58ce735e6a042515a6171b1fe3 GIT binary patch literal 8347 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 G3;P%Myjjfv literal 0 HcmV?d00001 diff --git a/tests/blue.png b/tests/blue.png new file mode 100644 index 0000000000000000000000000000000000000000..c650f7e690a93953f1bda9a7f8fc4d2df3555460 GIT binary patch literal 1530 zcmeAS@N?(olHy`uVBq!ia0y~yV4MKL985qF{<{lj134|3&dvdz&dv%2Mfqu&IjIZ` z8WU?L+Ik!g5NY+l?A0A6^G4y(goRd-0=kb@glago254`2mGJ2ox3APB5pnl}TOT|) zpLF%$(a3Q2a7TeZjD;mdK_wG~-g|TDChhr9A^-etam9N(hm5e9S!`+yp__Y3j1<#~ zS0{ZCt>rk-ZsBBP{MFLa>)_^n?^aHJrFU%ep5Oo0{Hr;b(%`Q$FLhUs{*IMd3%;zzseeiyyg z7*T^Fods;7n;x_OZ@$0Tv^#imUXTUjmpwPW9oG=J!y3hV`=8ymx7Roy)U&PI(zpK_ zOPZZ$e#w>>f(9FSV`9opQu%k>VQiaMa&v<0Nq=t*vBvMlzm~}uRB(S;x3f5V{^Ku< zCoZfBGCy!o(I9Nmo6`RB_Fd1v<@;CH+3Ttnb)^mS!_#?8WLqRZ`Lcm^mWS>hT|;+&tGo0?a`;9QiNSdyBeP@Y+mq2TW68xY>e zC(gjY{KV76F{I+w+bf2=3=AAB8`=NQb7W=q)PC5uI)&+jqc?+uSVJOX8*4%YLmMlY zEg=SGCqw|niIXH+Azmv+O#ucsmY^R-;gS#`1WW=Xq%7mdKI;Vst0NW(fOaK4? literal 0 HcmV?d00001 diff --git a/tests/simple_test.c b/tests/simple_test.c new file mode 100644 index 0000000..b3a732f --- /dev/null +++ b/tests/simple_test.c @@ -0,0 +1,171 @@ +/* Tests for the Wayland compositor running on the X server. + +Copyright (C) 2022 to various contributors. + +This file is part of 12to11. + +12to11 is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation, either version 3 of the License, or (at your +option) any later version. + +12to11 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 General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with 12to11. If not, see . */ + +#include "test_harness.h" + +enum test_kind + { + MAP_WINDOW_KIND, + BASIC_TEST_CARD_IMAGE_KIND, + }; + +/* The display. */ +static struct test_display *display; + +/* Test interfaces. */ +static struct test_interface test_interfaces[] = + { + /* No interfaces yet. */ + }; + +/* The test surface window. */ +static Window test_surface_window; + +/* The test surface and Wayland surface. */ +static struct test_surface *test_surface; +static struct wl_surface *wayland_surface; + + + +/* Forward declarations. */ +static void submit_frame_callback (struct wl_surface *, enum test_kind); + + + +static void +verify_single_step (enum test_kind kind) +{ + verify_image_data (display, test_surface_window, "simple_test.dump"); +} + +static void +test_single_step (enum test_kind kind) +{ + struct wl_buffer *buffer; + + switch (kind) + { + case MAP_WINDOW_KIND: + buffer = load_png_image (display, "blue.png"); + + if (!buffer) + report_test_failure ("failed to load blue.png"); + + wl_surface_attach (wayland_surface, buffer, 0, 0); + wl_surface_commit (wayland_surface); + wl_buffer_destroy (buffer); + break; + + case BASIC_TEST_CARD_IMAGE_KIND: + buffer = load_png_image (display, "basic_test_card.png"); + + if (!buffer) + report_test_failure ("failed to load basic_test_card.png"); + + wl_surface_attach (wayland_surface, buffer, 0, 0); + submit_frame_callback (wayland_surface, kind); + wl_surface_commit (wayland_surface); + wl_buffer_destroy (buffer); + break; + } +} + + + +static void +handle_test_surface_mapped (void *data, struct test_surface *surface, + uint32_t xid, const char *display_string) +{ + /* Sleep for 1 second to ensure that the window is exposed and + redirected. */ + sleep (1); + + /* Start the test. */ + test_surface_window = xid; + + /* Run the test again. */ + test_single_step (BASIC_TEST_CARD_IMAGE_KIND); +} + +static const struct test_surface_listener test_surface_listener = + { + handle_test_surface_mapped, + }; + + + +static void +handle_wl_callback_done (void *data, struct wl_callback *callback, + uint32_t callback_data) +{ + enum test_kind kind; + + kind = (intptr_t) data; + wl_callback_destroy (callback); + verify_single_step (kind); +} + +static const struct wl_callback_listener wl_callback_listener = + { + handle_wl_callback_done, + }; + + + +static void +submit_frame_callback (struct wl_surface *surface, enum test_kind kind) +{ + struct wl_callback *callback; + + callback = wl_surface_frame (surface); + wl_callback_set_user_data (callback, (void *) (intptr_t) kind); + wl_callback_add_listener (callback, &wl_callback_listener, + NULL); +} + +static void +run_test (void) +{ + if (!make_test_surface (display, &wayland_surface, + &test_surface)) + report_test_failure ("failed to create test surface"); + + test_surface_add_listener (test_surface, &test_surface_listener, + NULL); + test_single_step (MAP_WINDOW_KIND); + + while (true) + { + if (wl_display_dispatch (display->display) == -1) + die ("wl_display_dispatch"); + } +} + +int +main (void) +{ + test_init (); + display = open_test_display (test_interfaces, + ARRAYELTS (test_interfaces)); + + if (!display) + report_test_failure ("failed to open display"); + + run_test (); +} diff --git a/tests/simple_test.dump b/tests/simple_test.dump new file mode 100644 index 0000000000000000000000000000000000000000..17aa3d15cf0d70df7898289025dc8b1c4cb05131 GIT binary patch literal 35720 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 AQ2+n{ literal 0 HcmV?d00001 diff --git a/tests/svnignore.txt b/tests/svnignore.txt new file mode 100644 index 0000000..ccbcac7 --- /dev/null +++ b/tests/svnignore.txt @@ -0,0 +1,5 @@ +*-*.h +*-*.c +vgcore* +simple_test +Makefile diff --git a/tests/test_harness.c b/tests/test_harness.c new file mode 100644 index 0000000..826e62c --- /dev/null +++ b/tests/test_harness.c @@ -0,0 +1,753 @@ +/* Tests for the Wayland compositor running on the X server. + +Copyright (C) 2022 to various contributors. + +This file is part of 12to11. + +12to11 is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation, either version 3 of the License, or (at your +option) any later version. + +12to11 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 General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with 12to11. If not, see . */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include "test_harness.h" + +#define BIG_ENDIAN_BYTE_ORDER (1 << 8) + +struct image_data_header +{ + /* Currently 1. High bit is byte order. */ + unsigned char version; + + /* The data format. Currently always 0. */ + unsigned char format; + + /* The width and height. */ + unsigned short width, height; + + /* The stride. */ + unsigned int stride; +}; + +enum image_data_format + { + /* Little-endian ARGB8888. */ + IMAGE_DATA_ARGB8888_LE, + /* Little-endian XRGB8888. */ + IMAGE_DATA_XRGB8888_LE, + }; + +#if PNG_LIBPNG_VER < 10500 +#define PNG_JMPBUF(ptr) ((ptr)->jmpbuf) +# else +#define PNG_JMPBUF(ptr) \ + (*png_set_longjmp_fn (ptr, longjmp, sizeof (jmp_buf))) +#endif + +/* Whether or not to write image data instead of verifying it. */ +static bool write_image_data_instead; + +static void +handle_test_manager_display_string (void *data, struct test_manager *manager, + const char *display_string) +{ + struct test_display *display; + + display = data; + display->x_display = XOpenDisplay (display_string); + display->pixmap_formats + = XListPixmapFormats (display->x_display, + &display->num_pixmap_formats); +} + +static const struct test_manager_listener test_manager_listener = + { + handle_test_manager_display_string, + }; + +static bool +test_manager_check (struct test_display *display) +{ + return (display->x_display != NULL + && display->num_pixmap_formats + && display->pixmap_formats); +} + + + +static void +handle_registry_global (void *data, struct wl_registry *registry, + uint32_t id, const char *interface, + uint32_t version) +{ + struct test_display *display; + int i; + + display = data; + + if (!strcmp (interface, "wl_compositor") && version >= 5) + display->compositor + = wl_registry_bind (registry, id, &wl_compositor_interface, + 5); + if (!strcmp (interface, "wl_shm") && version >= 1) + display->shm = wl_registry_bind (registry, id, &wl_shm_interface, 1); + else if (!strcmp (interface, "test_manager")) + display->test_manager + = wl_registry_bind (registry, id, &test_manager_interface, 1); + else + { + /* Look through the user specified list of interfaces. */ + for (i = 0; i < display->num_test_interfaces; ++i) + { + if (!strcmp (interface, display->interfaces[i].interface) + && display->interfaces[i].version >= version) + /* Bind to it. */ + *((void **) display->interfaces[i].data) + = wl_registry_bind (registry, id, + display->interfaces[i].c_interface, + display->interfaces[i].version); + } + } +} + +static void +handle_registry_global_remove (void *data, struct wl_registry *registry, + uint32_t name) +{ + return; +} + +static const struct wl_registry_listener registry_listener = + { + handle_registry_global, + handle_registry_global_remove, + }; + +/* Check whether or not all required globals were found and bound + to. */ + +static bool +registry_listener_check (struct test_display *display) +{ + int i; + + if (!display->compositor) + return false; + + if (!display->shm) + return false; + + if (!display->test_manager) + return false; + + for (i = 0; i < display->num_test_interfaces; ++i) + { + if (!*((void **) display->interfaces[i].interface)) + return false; + } + + return true; +} + +void __attribute__ ((noreturn)) +die (const char *reason) +{ + perror (reason); + exit (1); +} + +struct test_display * +open_test_display (struct test_interface *interfaces, int num_interfaces) +{ + struct test_display *display; + + display = malloc (sizeof *display); + + if (!display) + return NULL; + + display->display = wl_display_connect (NULL); + + if (!display->display) + goto error_1; + + display->registry = wl_display_get_registry (display->display); + + if (!display->registry) + goto error_2; + + display->interfaces = interfaces; + display->num_test_interfaces = num_interfaces; + wl_registry_add_listener (display->registry, ®istry_listener, + display); + wl_display_roundtrip (display->display); + + if (!registry_listener_check (display)) + goto error_2; + + /* Now establish the connection to the X display. */ + test_manager_add_listener (display->test_manager, + &test_manager_listener, display); + wl_display_roundtrip (display->display); + + if (!test_manager_check (display)) + goto error_3; + + return display; + + error_3: + if (display->x_display) + XCloseDisplay (display->x_display); + error_2: + wl_display_disconnect (display->display); + error_1: + free (display); + return NULL; +} + +int +get_shm_file_descriptor (void) +{ + char name[sizeof "test_driver_buffer_XXXXXXXX"]; + int fd; + uint32_t i; + + i = 0; + + while (i <= 0xffffffff) + { + sprintf (name, "test_driver_buffer_%"PRIu32, i); + fd = shm_open (name, O_RDWR | O_CREAT | O_EXCL, 0600); + + if (fd >= 0) + { + shm_unlink (name); + return fd; + } + + if (errno == EEXIST) + ++i; + else + return -1; + } + + return -1; +} + +#define IMAGE_PAD(nbytes, pad) ((((nbytes) + ((pad) - 1)) / (pad)) * ((pad) >> 3)) + +size_t +get_image_stride (struct test_display *display, int depth, int width) +{ + int bpp, scanline_pad, i; + size_t stride; + + for (i = 0; i < display->num_pixmap_formats; ++i) + { + if (display->pixmap_formats[i].depth == depth) + { + bpp = display->pixmap_formats[i].bits_per_pixel; + scanline_pad = display->pixmap_formats[i].bits_per_pixel; + stride = IMAGE_PAD (width * bpp, scanline_pad); + + return stride; + } + } + + return 0; +} + +struct wl_buffer * +upload_image_data (struct test_display *display, const char *data, + int width, int height, int depth) +{ + size_t stride; + int fd; + void *mapping; + struct wl_shm_pool *pool; + struct wl_buffer *buffer; + + if (depth != 32 && depth != 24) + return NULL; + + stride = get_image_stride (display, depth, width); + + if (!stride) + return NULL; + + fd = get_shm_file_descriptor (); + + if (fd < 0) + return NULL; + + if (ftruncate (fd, stride * height) < 0) + return NULL; + + mapping = mmap (NULL, stride * height, PROT_WRITE, MAP_SHARED, + fd, 0); + + if (mapping == (void *) -1) + { + perror ("mmap"); + close (fd); + return NULL; + } + + memcpy (mapping, data, stride * height); + + if (munmap (mapping, stride * height) < 0) + die ("munmap"); + + pool = wl_shm_create_pool (display->shm, fd, stride * height); + + if (!pool) + { + close (fd); + return NULL; + } + + close (fd); + buffer = wl_shm_pool_create_buffer (pool, 0, width, height, stride, + (depth == 32 + ? WL_SHM_FORMAT_ARGB8888 + : WL_SHM_FORMAT_XRGB8888)); + wl_shm_pool_destroy (pool); + + return buffer; +} + +void __attribute__ ((noreturn, format (gnu_printf, 1, 2))) +report_test_failure (const char *format, ...) +{ + va_list ap; + + va_start (ap, format); + fputs ("failure: ", stderr); + vfprintf (stderr, format, ap); + fputs ("\n", stderr); + va_end (ap); + + exit (1); +} + +void __attribute__ ((format (gnu_printf, 1, 2))) +test_log (const char *format, ...) +{ + va_list ap; + + va_start (ap, format); + fputs ("note: ", stderr); + vfprintf (stderr, format, ap); + fputs ("\n", stderr); + va_end (ap); +} + +bool +make_test_surface (struct test_display *display, + struct wl_surface **surface_return, + struct test_surface **test_surface_return) +{ + struct wl_surface *surface; + struct test_surface *test_surface; + + surface = wl_compositor_create_surface (display->compositor); + + if (!surface) + return false; + + test_surface + = test_manager_get_test_surface (display->test_manager, + surface); + + if (!test_surface) + { + wl_surface_destroy (surface); + return false; + } + + *surface_return = surface; + *test_surface_return = test_surface; + return true; +} + +/* Swizzle the big-endian data in ROW_DATA to the little-endian format + Wayland mandates. */ + +static void +swizzle_png_row (unsigned char *row_data, int width) +{ + int i; + unsigned char byte_1, byte_2, byte_3, byte_4; + + for (i = 0; i < width; ++i) + { + byte_1 = row_data[i * 4 + 0]; + byte_2 = row_data[i * 4 + 1]; + byte_3 = row_data[i * 4 + 2]; + byte_4 = row_data[i * 4 + 3]; + + row_data[i * 4 + 0] = byte_3; + row_data[i * 4 + 1] = byte_2; + row_data[i * 4 + 2] = byte_1; + row_data[i * 4 + 3] = byte_4; + } +} + +/* Load a PNG image into a wl_buffer. The image must be either + PNG_COLOR_TYPE_RGB or PNG_COLOR_TYPE_RGB_ALPHA. The image + background is ignored. */ + +struct wl_buffer * +load_png_image (struct test_display *display, const char *filename) +{ + FILE *file; + unsigned char signature[8]; + png_structp png_ptr; + png_infop info_ptr; + png_uint_32 width, height; + int bit_depth, color_type, depth; + png_uint_32 i, rowbytes; + png_bytep *row_pointers; + unsigned char *image_data; + struct wl_buffer *buffer; + + image_data = NULL; + file = fopen (filename, "r"); + + if (!file) + return NULL; + + if (fread (signature, 1, 8, file) != 8) + goto error_1; + + if (!png_check_sig (signature, 8)) + goto error_1; + + png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, + NULL); + + if (!png_ptr) + goto error_1; + + info_ptr = png_create_info_struct (png_ptr); + + if (!info_ptr) + goto error_2; + + if (setjmp (PNG_JMPBUF (png_ptr))) + goto error_3; + + png_init_io (png_ptr, file); + png_set_sig_bytes (png_ptr, 8); + png_read_info (png_ptr, info_ptr); + png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, + &color_type, NULL, NULL, NULL); + + if (color_type != PNG_COLOR_TYPE_RGB + && color_type != PNG_COLOR_TYPE_RGB_ALPHA) + goto error_3; + + /* Get data as ARGB. */ + if (color_type == PNG_COLOR_TYPE_RGB) + png_set_filler (png_ptr, 0, PNG_FILLER_AFTER); + + /* Start reading the PNG data. Get the stride and depth. */ + depth = (color_type == PNG_COLOR_TYPE_RGB_ALPHA + ? 32 : 24); + + png_read_update_info (png_ptr, info_ptr); + rowbytes = get_image_stride (display, depth, width); + + /* Allocate a buffer for the image data. */ + image_data = malloc (rowbytes * height); + + if (!image_data) + goto error_3; + + /* Allocate the array of row pointers. */ + row_pointers = alloca (sizeof *row_pointers * height); + + for (i = 0; i < height; ++i) + row_pointers[i] = image_data + i * rowbytes; + + /* Read the data. */ + png_read_image (png_ptr, row_pointers); + png_read_end (png_ptr, NULL); + + for (i = 0; i < height; ++i) + /* Swizzle the big-endian data. */ + swizzle_png_row (row_pointers[i], width); + + /* Now, destroy the read struct and close the file. */ + png_destroy_read_struct (&png_ptr, &info_ptr, NULL); + fclose (file); + + /* Upload the image data. */ + buffer = upload_image_data (display, (const char *) image_data, + width, height, depth); + + /* Free the image data. */ + free (image_data); + + return buffer; + + error_3: + if (image_data) + free (image_data); + + /* This looks silly... */ + if (true) + png_destroy_read_struct (&png_ptr, &info_ptr, NULL); + else + error_2: + png_destroy_read_struct (&png_ptr, NULL, NULL); + error_1: + fclose (file); + return NULL; +} + +static unsigned short +bytes_per_pixel_for_format (enum image_data_format format) +{ + switch (format) + { + case IMAGE_DATA_ARGB8888_LE: + case IMAGE_DATA_XRGB8888_LE: + return 4; + + default: + return 0; + } +} + +static int +byte_order_for_format (enum image_data_format format) +{ + switch (format) + { + case IMAGE_DATA_ARGB8888_LE: + case IMAGE_DATA_XRGB8888_LE: + return LSBFirst; + + default: + return 0; + } +} + +/* Load image data from a file. */ + +static unsigned char * +load_image_data (const char *filename, struct image_data_header *header) +{ + int fd; + struct iovec iov; + unsigned char *buffer; + unsigned short bpp; + + fd = open (filename, O_RDONLY); + + if (fd < 0) + return NULL; + + iov.iov_base = header; + iov.iov_len = sizeof *header; + + if (readv (fd, &iov, 1) != iov.iov_len) + goto error_1; + +#ifdef __BIG_ENDIAN__ + if (!(header->version & BIG_ENDIAN_BYTE_ORDER)) + goto error_1; +#endif + + if ((header->version & ~BIG_ENDIAN_BYTE_ORDER) != 1) + goto error_1; + + bpp = bytes_per_pixel_for_format (header->format); + + if (!bpp || header->stride < header->height * bpp) + goto error_1; + + buffer = malloc (header->stride * header->height); + + if (!buffer) + goto error_1; + + iov.iov_base = buffer; + iov.iov_len = header->stride * header->height; + + if (readv (fd, &iov, 1) != iov.iov_len) + goto error_2; + + close (fd); + return buffer; + + error_2: + free (buffer); + error_1: + close (fd); + return NULL; +} + +static void +compare_single_row (unsigned char *data, int row_no, + struct image_data_header *header, XImage *image) +{ + char *xdata; + unsigned short bytes_per_pixel; + + bytes_per_pixel = bytes_per_pixel_for_format (header->format); + data = data + header->stride * row_no; + xdata = image->data + image->bytes_per_line * row_no; + + if (memcmp (data, xdata, bytes_per_pixel * header->width)) + report_test_failure ("row %d differs", row_no); +} + +static void +write_image_data (struct test_display *display, Window window, + const char *filename) +{ + struct image_data_header header; + XImage *image; + struct iovec iovecs[2]; + int fd; + XWindowAttributes attrs; + + test_log ("writing contents of drawable to reference %s", filename); + + XGetWindowAttributes (display->x_display, window, &attrs); + image = XGetImage (display->x_display, window, 0, 0, attrs.width, + attrs.height, ~0, ZPixmap); + + if (!image) + report_test_failure ("failed to load from drawable 0x%lx", window); + + memset (&header, 0, sizeof header); + header.version = 1; +#ifdef __BIG_ENDIAN__ + header.version |= BIG_ENDIAN_BYTE_ORDER; +#endif + + if ((image->depth != 24 && image->depth != 32) + || image->bits_per_pixel != 32) + report_test_failure ("don't know how to save image of depth %d (bpp %d)", + image->depth, image->bits_per_pixel); + + if (image->byte_order != LSBFirst) + report_test_failure ("don't know how to save big-endian image"); + + /* TODO: determine the image format based on the visual of the + window. */ + header.format = (image->depth == 24 + ? IMAGE_DATA_XRGB8888_LE + : IMAGE_DATA_ARGB8888_LE); + header.width = image->width; + header.height = image->height; + header.stride = image->bytes_per_line; + + /* Open the output file and write the data. */ + fd = open (filename, O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + + if (fd < 0) + report_test_failure ("failed to open output file %s", filename); + + iovecs[0].iov_base = &header; + iovecs[0].iov_len = sizeof header; + iovecs[1].iov_base = image->data; + iovecs[1].iov_len = image->bytes_per_line * image->height; + + if (writev (fd, iovecs, 2) != iovecs[0].iov_len + iovecs[1].iov_len) + report_test_failure ("failed to write to output file %s", filename); + + close (fd); + XDestroyImage (image); + + test_log ("image data written to %s", filename); +} + +/* Verify the image data against a file. */ + +void +verify_image_data (struct test_display *display, Window window, + const char *filename) +{ + XImage *image; + XWindowAttributes attrs; + unsigned char *data; + struct image_data_header header; + unsigned short data_bpp, i; + int byte_order; + + if (write_image_data_instead) + write_image_data (display, window, filename); + + data = load_image_data (filename, &header); + + if (!data) + report_test_failure ("failed to load input file: %s", filename); + + XGetWindowAttributes (display->x_display, window, &attrs); + image = XGetImage (display->x_display, window, 0, 0, attrs.width, + attrs.height, ~0, ZPixmap); + + if (!image) + report_test_failure ("failed to load from drawable 0x%lx", window); + + /* Check if the image data is compatible. */ + data_bpp = bytes_per_pixel_for_format (header.format); + byte_order = byte_order_for_format (header.format); + + if (byte_order != image->byte_order) + report_test_failure ("image data has wrong byte order"); + + if (data_bpp * 8 != image->bits_per_pixel) + report_test_failure ("image data has %d bits per pixel, but reference" + " data has %hd * 8", image->bits_per_pixel, data_bpp); + + if (image->width != header.width + || image->height != header.height) + report_test_failure ("image data is %d by %d, but reference data is" + " %hd by %hd", image->width, image->height, + header.width, header.height); + + /* Now compare the actual image data. Make sure this is done with + the same visual as the reference data was saved in! */ + + for (i = 0; i < header.height; ++i) + compare_single_row (data, i, &header, image); + + /* Destroy the images. */ + free (data); + XDestroyImage (image); + + test_log ("verified image data"); +} + +void +test_init (void) +{ + write_image_data_instead + = getenv ("TEST_WRITE_REFERENCE") != NULL; +} diff --git a/tests/test_harness.h b/tests/test_harness.h new file mode 100644 index 0000000..0e97f40 --- /dev/null +++ b/tests/test_harness.h @@ -0,0 +1,91 @@ +/* Tests for the Wayland compositor running on the X server. + +Copyright (C) 2022 to various contributors. + +This file is part of 12to11. + +12to11 is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation, either version 3 of the License, or (at your +option) any later version. + +12to11 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 General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with 12to11. If not, see . */ + +#include +#include +#include + +#include + +#include +#include + +#include "12to11-test.h" + +struct test_display +{ + /* The wayland display. */ + struct wl_display *display; + + /* The X display. */ + Display *x_display; + + /* List of pixmap formats. */ + XPixmapFormatValues *pixmap_formats; + + /* Number of pixmap formats. */ + int num_pixmap_formats; + + /* The registry and various Wayland interfaces. */ + struct wl_registry *registry; + struct wl_compositor *compositor; + struct wl_shm *shm; + struct test_manager *test_manager; + + /* Test interfaces. */ + struct test_interface *interfaces; + + /* The number of such interfaces. */ + int num_test_interfaces; +}; + +struct test_interface +{ + /* The name of the interface. */ + const char *interface; + + /* Pointer to the interface data. */ + void *data; + + /* Pointer to the interface. */ + struct wl_interface *c_interface; + + /* The wanted version. */ + uint32_t version; +}; + +extern void die (const char *); +extern struct test_display *open_test_display (struct test_interface *, int); +extern int get_shm_file_descriptor (void); +extern size_t get_image_stride (struct test_display *, int, int); +extern struct wl_buffer *upload_image_data (struct test_display *, + const char *, int, int, + int); +extern void report_test_failure (const char *, ...) + __attribute__ ((noreturn, format (gnu_printf, 1, 2))); +extern void test_log (const char *, ...) + __attribute__ ((format (gnu_printf, 1, 2))); + +extern bool make_test_surface (struct test_display *, struct wl_surface **, + struct test_surface **); +extern struct wl_buffer *load_png_image (struct test_display *, const char *); +extern void verify_image_data (struct test_display *, Window, const char *); +extern void test_init (void); + +#define ARRAYELTS(arr) (sizeof (arr) / sizeof (arr)[0])