From 59dff46f643fd2a11ddfba88c93704df9adda8f2 Mon Sep 17 00:00:00 2001
From: Simon McVittie <[EMAIL REDACTED]>
Date: Tue, 17 May 2022 20:58:20 +0100
Subject: [PATCH] Add a simple automated test
This loads and saves various supported formats, and asserts that the
same pixels (or close enough) end up in the output files.
For a distribution that knows it intends to support particular formats,
if an environment variable like SVG_IMAGE_TEST_REQUIRE_LOAD_JPG or
SVG_IMAGE_TEST_REQUIRE_SAVE_JPG is set, the test will fail if the given
format is not available.
Signed-off-by: Simon McVittie <smcv@debian.org>
---
CMakeLists.txt | 7 +
Makefile.am | 6 +
configure.ac | 10 +
test/.gitignore | 5 +
test/CMakeLists.txt | 75 ++++
test/Makefile.am | 69 +++
test/main.c | 976 ++++++++++++++++++++++++++++++++++++++++++
test/palette.bmp | Bin 0 -> 1242 bytes
test/palette.gif | Bin 0 -> 568 bytes
test/sample.avif | Bin 0 -> 322 bytes
test/sample.bmp | Bin 0 -> 3162 bytes
test/sample.cur | Bin 0 -> 3254 bytes
test/sample.ico | Bin 0 -> 3254 bytes
test/sample.jpg | Bin 0 -> 578 bytes
test/sample.jxl | Bin 0 -> 163 bytes
test/sample.png | Bin 0 -> 850 bytes
test/sample.pnm | 28 ++
test/sample.qoi | Bin 0 -> 1480 bytes
test/sample.tif | Bin 0 -> 3143 bytes
test/sample.webp | Bin 0 -> 668 bytes
test/sample.xcf | Bin 0 -> 3511 bytes
test/sample.xpm | 546 +++++++++++++++++++++++
test/svg.bmp | Bin 0 -> 4218 bytes
test/svg.svg | 24 ++
test/svg64.bmp | Bin 0 -> 16506 bytes
test/template.test.in | 3 +
26 files changed, 1749 insertions(+)
create mode 100644 test/.gitignore
create mode 100644 test/CMakeLists.txt
create mode 100644 test/Makefile.am
create mode 100644 test/main.c
create mode 100644 test/palette.bmp
create mode 100644 test/palette.gif
create mode 100644 test/sample.avif
create mode 100644 test/sample.bmp
create mode 100644 test/sample.cur
create mode 100644 test/sample.ico
create mode 100644 test/sample.jpg
create mode 100644 test/sample.jxl
create mode 100644 test/sample.png
create mode 100644 test/sample.pnm
create mode 100644 test/sample.qoi
create mode 100644 test/sample.tif
create mode 100644 test/sample.webp
create mode 100644 test/sample.xcf
create mode 100644 test/sample.xpm
create mode 100644 test/svg.bmp
create mode 100644 test/svg.svg
create mode 100644 test/svg64.bmp
create mode 100644 test/template.test.in
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9f54397..24978ec 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -239,6 +239,8 @@ include(CMakeDependentOption)
include(CMakePackageConfigHelpers)
include(GNUInstallDirs)
+option(BUILD_TESTS "Build unit tests?" OFF)
+cmake_dependent_option(INSTALL_TESTS "Install unit tests?" OFF BUILD_TESTS OFF)
option(VENDORED_DEFAULT "Default value for *_VENDORED options. Can be overridden for each library. Is only used in the first configure run." ON)
option(SDL2_IMAGE_DISABLE_INSTALL "Disable installing SDL2_image" OFF)
@@ -767,3 +769,8 @@ if (BUILD_SAMPLES)
endif()
endforeach()
endif()
+
+if (BUILD_TESTS)
+ include(CTest)
+ add_subdirectory(test)
+endif()
diff --git a/Makefile.am b/Makefile.am
index 8c864a2..b47d071 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -74,6 +74,12 @@ noinst_PROGRAMS = showimage showanim
showimage_LDADD = libSDL2_image.la
showanim_LDADD = libSDL2_image.la
+SUBDIRS = .
+
+if BUILD_TESTS
+SUBDIRS += test
+endif
+
# Rule to build tar-gzipped distribution package
$(PACKAGE)-$(VERSION).tar.gz: distcheck
diff --git a/configure.ac b/configure.ac
index e5b76cb..d76cdfe 100644
--- a/configure.ac
+++ b/configure.ac
@@ -250,6 +250,12 @@ AC_ARG_ENABLE([webp-shared], [AS_HELP_STRING([--enable-webp-shared], [dynamicall
[], [enable_webp_shared=yes])
AC_ARG_ENABLE([qoi], [AS_HELP_STRING([--enable-qoi], [support loading QOI images [default=yes]])],
[], [enable_qoi=yes])
+AC_ARG_ENABLE([tests],
+ [AS_HELP_STRING([--enable-tests], [build tests [default=no]])],
+ [], [enable_tests=no])
+AC_ARG_ENABLE([installed-tests],
+ [AS_HELP_STRING([--enable-installed-tests], [install tests [default=no]])],
+ [], [enable_installed_tests=no])
dnl Check for SDL
SDL_VERSION=2.0.8
@@ -665,6 +671,9 @@ AC_SUBST([IMG_LIBS])
AC_SUBST([PC_LIBS])
AC_SUBST([PC_REQUIRES])
+AM_CONDITIONAL([BUILD_TESTS], [test "x$enable_tests" = xyes])
+AM_CONDITIONAL([INSTALL_TESTS], [test "x$enable_installed_tests" = xyes])
+
dnl check for GCC warning options
CheckWarnAll
@@ -678,5 +687,6 @@ AC_CONFIG_FILES([
Makefile
SDL2_image.spec
SDL2_image.pc
+test/Makefile
])
AC_OUTPUT
diff --git a/test/.gitignore b/test/.gitignore
new file mode 100644
index 0000000..185ec1c
--- /dev/null
+++ b/test/.gitignore
@@ -0,0 +1,5 @@
+/*.test
+/CompareSurfaces*.bmp
+/save-*.bmp
+/save.*
+/testimage
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644
index 0000000..1b6594f
--- /dev/null
+++ b/test/CMakeLists.txt
@@ -0,0 +1,75 @@
+add_executable(testimage main.c)
+
+set(ALL_TESTS
+ testimage
+)
+set(RESOURCE_FILES
+ palette.bmp
+ palette.gif
+ sample.avif
+ sample.bmp
+ sample.cur
+ sample.ico
+ sample.jpg
+ sample.jxl
+ sample.png
+ sample.pnm
+ sample.qoi
+ sample.tif
+ sample.webp
+ sample.xcf
+ sample.xpm
+ svg.bmp
+ svg.svg
+ svg64.bmp
+)
+
+set(TESTS_ENVIRONMENT
+ "SDL_TEST_SRCDIR=${CMAKE_CURRENT_SOURCE_DIR}"
+ "SDL_TEST_BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}"
+ "SDL_VIDEODRIVER=dummy"
+)
+
+foreach(prog ${ALL_TESTS})
+ target_compile_definitions(${prog} PRIVATE $<TARGET_PROPERTY:SDL2_image,COMPILE_DEFINITIONS>)
+ target_link_libraries(${prog} PRIVATE SDL2_image::${sdl2_image_export_name})
+ if (TARGET SDL2::SDL2main)
+ target_link_libraries(${prog} PRIVATE SDL2::SDL2main)
+ endif()
+ target_link_libraries(${prog} PRIVATE SDL2_test)
+ if (BUILD_SHARED_LIBS)
+ target_link_libraries(${prog} PRIVATE SDL2::SDL2)
+ else()
+ target_link_libraries(${prog} PRIVATE SDL2::SDL2-static)
+ endif()
+
+ add_test(
+ NAME ${prog}
+ COMMAND ${prog}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ )
+ set_tests_properties(
+ ${prog}
+ PROPERTIES ENVIRONMENT "${TESTS_ENVIRONMENT}"
+ )
+ if(INSTALL_TESTS)
+ set(exe ${prog})
+ set(installedtestsdir "${CMAKE_INSTALL_FULL_LIBEXECDIR}/installed-tests/${CMAKE_PROJECT_NAME}")
+ configure_file(template.test.in "${exe}.test" @ONLY)
+ install(
+ FILES "${CMAKE_CURRENT_BINARY_DIR}/${exe}.test"
+ DESTINATION "${CMAKE_INSTALL_DATADIR}/installed-tests/${CMAKE_PROJECT_NAME}"
+ )
+ endif()
+endforeach()
+
+if(INSTALL_TESTS)
+ install(
+ TARGETS ${ALL_TESTS}
+ DESTINATION "${CMAKE_INSTALL_LIBEXECDIR}/installed-tests/${CMAKE_PROJECT_NAME}"
+ )
+ install(
+ FILES ${RESOURCE_FILES}
+ DESTINATION "${CMAKE_INSTALL_LIBEXECDIR}/installed-tests/${CMAKE_PROJECT_NAME}"
+ )
+endif()
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644
index 0000000..4ed70ed
--- /dev/null
+++ b/test/Makefile.am
@@ -0,0 +1,69 @@
+testmetadir = $(datadir)/installed-tests/$(PACKAGE_TARNAME)
+testexecdir = $(libexecdir)/installed-tests/$(PACKAGE_TARNAME)
+
+test_programs = \
+ testimage \
+ $(NULL)
+
+testimage_CPPFLAGS = -I$(top_srcdir)
+testimage_SOURCES = main.c
+testimage_LDADD = \
+ ../libSDL2_image.la \
+ $(SDL_LIBS) \
+ -lSDL2_test \
+ $(NULL)
+
+AM_TESTS_ENVIRONMENT = \
+ SDL_TEST_SRCDIR=$(abs_srcdir) \
+ SDL_TEST_BUILDDIR=$(abs_builddir) \
+ SDL_VIDEODRIVER=dummy \
+ $(NULL)
+
+if INSTALL_TESTS
+testexec_PROGRAMS = $(test_programs)
+else
+noinst_PROGRAMS = $(test_programs)
+endif
+
+TESTS = $(test_programs)
+
+if INSTALL_TESTS
+dist_testexec_DATA = \
+ palette.bmp \
+ palette.gif \
+ sample.avif \
+ sample.bmp \
+ sample.cur \
+ sample.ico \
+ sample.jpg \
+ sample.jxl \
+ sample.png \
+ sample.pnm \
+ sample.qoi \
+ sample.tif \
+ sample.webp \
+ sample.xcf \
+ sample.xpm \
+ svg.bmp \
+ svg.svg \
+ svg64.bmp \
+ $(NULL)
+
+all-local: generatetestmeta
+generatetestmeta:
+ rm -f *.test
+ set -e; for exe in $(test_programs); do \
+ sed \
+ -e 's#@installedtestsdir@#$(testexecdir)#g' \
+ -e "s#@exe@#$$exe#g" \
+ < $(srcdir)/template.test.in > $$exe.test; \
+ done
+
+install-data-hook: installtestmeta
+installtestmeta: generatetestmeta
+ install -m644 -D -t $(DESTDIR)$(testmetadir) *.test
+
+clean-local:
+ rm -f *.test
+ rm -f save.jpg save.bmp CompareSurfaces*.bmp
+endif
diff --git a/test/main.c b/test/main.c
new file mode 100644
index 0000000..56a34ea
--- /dev/null
+++ b/test/main.c
@@ -0,0 +1,976 @@
+/*
+ Copyright 1997-2022 Sam Lantinga
+ Copyright 2022 Collabora Ltd.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely.
+*/
+
+#include "SDL_image.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+#include "SDL.h"
+#include "SDL_test.h"
+
+#if defined(SDL_FILESYSTEM_OS2) || defined(SDL_FILESYSTEM_WINDOWS)
+static const char pathsep[] = "\\";
+#elif defined(SDL_FILESYSTEM_RISCOS)
+static const char pathsep[] = ".";
+#else
+static const char pathsep[] = "/";
+#endif
+
+/* TODO: https://github.com/libsdl-org/SDL_image/issues/243 */
+#ifndef SDL_IMAGE_SAVE_JPG
+# define SDL_IMAGE_SAVE_JPG 0
+#endif
+#ifndef SDL_IMAGE_SAVE_PNG
+# define SDL_IMAGE_SAVE_PNG 0
+#endif
+
+typedef enum
+{
+ TEST_FILE_DIST,
+ TEST_FILE_BUILT
+} TestFileType;
+
+static SDL_bool
+GetStringBoolean(const char *value, SDL_bool default_value)
+{
+ if (!value || !*value) {
+ return default_value;
+ }
+ if (*value == '0' || SDL_strcasecmp(value, "false") == 0) {
+ return SDL_FALSE;
+ }
+ return SDL_TRUE;
+}
+
+/*
+ * Return the absolute path to a resource file, similar to GLib's
+ * g_test_build_filename().
+ *
+ * If type is TEST_FILE_DIST, look for it in $SDL_TEST_SRCDIR or next
+ * to the executable.
+ *
+ * If type is TEST_FILE_BUILT, look for it in $SDL_TEST_BUILDDIR or next
+ * to the executable.
+ *
+ * Fails and returns NULL if out of memory.
+ */
+static char *
+GetTestFilename(TestFileType type, const char *file)
+{
+ const char *env;
+ char *base = NULL;
+ char *path = NULL;
+ SDL_bool needPathSep = SDL_TRUE;
+
+ if (type == TEST_FILE_DIST) {
+ env = SDL_getenv("SDL_TEST_SRCDIR");
+ } else {
+ env = SDL_getenv("SDL_TEST_BUILDDIR");
+ }
+
+ if (env != NULL) {
+ base = SDL_strdup(env);
+ if (base == NULL) {
+ SDL_OutOfMemory();
+ return NULL;
+ }
+ }
+
+ if (base == NULL) {
+ base = SDL_GetBasePath();
+ /* SDL_GetBasePath() guarantees a trailing path separator */
+ needPathSep = SDL_FALSE;
+ }
+
+ if (base != NULL) {
+ size_t len = SDL_strlen(base) + SDL_strlen(pathsep) + SDL_strlen(file) + 1;
+
+ path = SDL_malloc(len);
+
+ if (path == NULL) {
+ SDL_OutOfMemory();
+ return NULL;
+ }
+
+ if (needPathSep) {
+ SDL_snprintf(path, len, "%s%s%s", base, pathsep, file);
+ } else {
+ SDL_snprintf(path, len, "%s%s", base, file);
+ }
+
+ SDL_free(base);
+ } else {
+ path = SDL_strdup(file);
+ if (path == NULL) {
+ SDL_OutOfMemory();
+ return NULL;
+ }
+ }
+
+ return path;
+}
+
+static SDLTest_CommonState *state;
+
+typedef struct
+{
+ const char *name;
+ const char *sample;
+ const char *reference;
+ int w;
+ int h;
+ int tolerance;
+ int initFlag;
+ SDL_bool canLoad;
+ SDL_bool canSave;
+ int (SDLCALL * checkFunction)(SDL_RWops *src);
+ SDL_Surface *(SDLCALL * loadFunction)(SDL_RWops *src);
+} Format;
+
+static const Format formats[] =
+{
+ {
+ "AVIF",
+ "sample.avif",
+ "sample.bmp",
+ 23,
+ 42,
+ 0, /* lossless */
+ IMG_INIT_AVIF,
+#ifdef LOAD_AVIF
+ SDL_TRUE,
+#else
+ SDL_FALSE,
+#endif
+ SDL_FALSE, /* can save */
+ IMG_isAVIF,
+ IMG_LoadAVIF_RW,
+ },
+ {
+ "BMP",
+ "sample.bmp",
+ "sample.png",
+ 23,
+ 42,
+ 0, /* lossless */
+ 0, /* no initialization */
+#ifdef LOAD_BMP
+ SDL_TRUE,
+#else
+ SDL_FALSE,
+#endif
+ SDL_FALSE, /* can save */
+ IMG_isBMP,
+ IMG_LoadBMP_RW,
+ },
+ {
+ "CUR",
+ "sample.cur",
+ "sample.bmp",
+ 23,
+ 42,
+ 0, /* lossless */
+ 0, /* no initialization */
+#ifdef LOAD_BMP
+ SDL_TRUE,
+#else
+ SDL_FALSE,
+#endif
+ SDL_FALSE, /* can save */
+ IMG_isCUR,
+ IMG_LoadCUR_RW,
+ },
+ {
+ "GIF",
+ "palette.gif",
+ "palette.bmp",
+ 23,
+ 42,
+ 0, /* lossless */
+ 0, /* no initialization */
+#ifdef LOAD_GIF
+ SDL_TRUE,
+#else
+ SDL_FALSE,
+#endif
+ SDL_FALSE, /* can save */
+ IMG_isGIF,
+ IMG_LoadGIF_RW,
+ },
+ {
+ "ICO",
+ "sample.ico",
+ "sample.bmp",
+ 23,
+ 42,
+ 0, /* lossless */
+ 0, /* no initialization */
+#ifdef LOAD_BMP
+ SDL_TRUE,
+#else
+ SDL_FALSE,
+#endif
+ SDL_FALSE, /* can save */
+ IMG_isICO,
+ IMG_LoadICO_RW,
+ },
+ {
+ "JPG",
+ "sample.jpg",
+ "sample.bmp",
+ 23,
+ 42,
+ 100,
+ IMG_INIT_JPG,
+#ifdef LOAD_JPG
+ SDL_TRUE,
+#else
+ SDL_FALSE,
+#endif
+ SDL_IMAGE_SAVE_JPG,
+ IMG_isJPG,
+ IMG_LoadJPG_RW,
+ },
+ {
+ "JXL",
+ "sample.jxl",
+ "sample.bmp",
+ 23,
+ 42,
+ 100,
+ IMG_INIT_JXL,
+#ifdef LOAD_JXL
+ SDL_TRUE,
+#else
+ SDL_FALSE,
+#endif
+ SDL_FALSE, /* can save */
+ IMG_isJXL,
+ IMG_LoadJXL_RW,
+ },
+#if 0
+ {
+ "LBM",
+ "sample.lbm",
+ "sample.bmp",
+ 23,
+ 42,
+ 0, /* lossless? */
+ 0, /* no initialization */
+#ifdef LOAD_LBM
+ SDL_TRUE,
+#else
+ SDL_FALSE,
+#endif
+ SDL_FALSE, /* can save */
+ IMG_isLBM,
+ IMG_LoadLBM_RW,
+ },
+#endif
+#if 0
+ {
+ "PCX",
+ "sample.pcx",
+ "sample.bmp",
+ 23,
+ 42,
+ 0, /* lossless? */
+ 0, /* no initialization */
+#ifdef LOAD_PCX
+ SDL_TRUE,
+#else
+ SDL_FALSE,
+#endif
+ SDL_FALSE, /* can save */
+ IMG_isPCX,
+ IMG_LoadPCX_RW,
+ },
+#endif
+ {
+ "PNG",
+ "sample.png",
+ "sample.bmp",
+ 23,
+ 42,
+ 0, /* lossless */
+ IMG_INIT_PNG,
+#ifdef LOAD_PNM
+ SDL_TRUE,
+#else
+ SDL_FALSE,
+#endif
+ SDL_IMAGE_SAVE_PNG,
+ IMG_isPNG,
+ IMG_LoadPNG_RW,
+ },
+ {
+ "PNM",
+ "sample.pnm",
+ "sample.bmp",
+ 23,
+ 42,
+ 0, /* lossless */
+ 0, /* no initialization */
+#ifdef LOAD_PNM
+ SDL_TRUE,
+#else
+ SDL_FALSE,
+#endif
+ SDL_FALSE, /* can save */
+ IMG_isPNM,
+ IMG_LoadPNM_RW,
+ },
+ {
+ "QOI",
+ "sample.qoi",
+ "sample.bmp",
+ 23,
+ 42,
+ 0, /* lossless */
+ 0, /* no initialization */
+#ifdef LOAD_QOI
+ SDL_TRUE,
+#else
+ SDL_FALSE,
+#endif
+ SDL_FALSE, /* can save */
+ IMG_isQOI,
+ IMG_LoadQOI_RW,
+ },
+ {
+ "SVG",
+ "svg.svg",
+ "svg.bmp",
+ 32,
+ 32,
+ 100,
+ 0, /* no initialization */
+#ifdef LOAD_SVG
+ SDL_TRUE,
+#else
+ SDL_FALSE,
+#endif
+ SDL_FALSE, /* can save */
+ IMG_isSVG,
+ IMG_LoadSVG_RW,
+ },
+ {
+ "SVG-sized",
+ "svg.svg",
+ "svg64.bmp",
+ 64,
+ 64,
+ 100,
+ 0, /* no initialization */
+#ifdef LOAD_SVG
+ SDL_TRUE,
+#else
+ SDL_FALSE,
+#endif
+ SDL_FALSE, /* can save */
+ IMG_isSVG,
+ IMG_LoadSVG_RW,
+ },
+#if 0
+ {
+ "TGA",
+ "sample.tga",
+ "sample.bmp",
+ 23,
+ 42,
+ 0, /* lossless? */
+ 0, /* no initialization */
+#ifdef LOAD_TGA
+ SDL_TRUE,
+#else
+ SDL_FALSE,
+#endif
+ SDL_FALSE, /* can save */
+ NULL,
+ IMG_LoadTGA_RW,
+ },
+#endif
+ {
+ "TIF",
+ "sample.tif",
+ "sample.bmp",
+ 23,
+ 42,
+ 0, /* lossless */
+ IMG_INIT_TIF,
+#ifdef LOAD_TIF
+ SDL_TRUE,
+#else
+ SDL_FALSE,
+#endif
+ SDL_FALSE, /* can save */
+ IMG_isTIF,
+ IMG_LoadTIF_RW,
+ },
+ {
+ "WEBP",
+ "sample.webp",
+ "sample.bmp",
+ 23,
+ 42,
+ 0, /* lossless */
+ IMG_INIT_WEBP,
+#ifdef LOAD_WEBP
+ SDL_TRUE,
+#else
+ SDL_FALSE,
+#endif
+ SDL_FALSE, /* can save */
+ IMG_isWEBP,
+ IMG_LoadWEBP_RW,
+ },
+ {
+ "XCF",
+ "sample.xcf",
+ "sample.bmp",
+ 23,
+ 42,
+ 0, /* lossless */
+ 0, /* no initialization */
+#ifdef LOAD_XCF
+ SDL_TRUE,
+#else
+ SDL_FALSE,
+#endif
+ SDL_FALSE, /* can save */
+ IMG_isXCF,
+ IMG_LoadXCF_RW,
+ },
+ {
+ "XPM",
+ "sample.xpm",
+ "sample.bmp",
+ 23,
+ 42,
+ 0, /* lossless */
+ 0, /* no initialization */
+#ifdef LOAD_XPM
+ SDL_TRUE,
+#else
+ SDL_FALSE,
+#endif
+ SDL_FALSE, /* can save */
+ IMG_isXPM,
+ IMG_LoadXPM_RW,
+ },
+#if 0
+ {
+ "XV",
+ "sample.xv",
+ "sample.bmp",
+ 23,
+ 42,
+ 0, /* lossless? */
+ 0, /* no initialization */
+#ifdef LOAD_XV
+ SDL_TRUE,
+#else
+ SDL_FALSE,
+#endif
+ SDL_FALSE, /* can save */
+ IMG_isXV,
+ IMG_LoadXV_RW,
+ },
+#endif
+};
+
+static SDL_bool
+StrHasSuffix(const char *str, const char *suffix)
+{
+ size_t str_len = strlen(str);
+ size_t suffix_len = strlen(suffix);
+
+ return (str_len >= suffix_len
+ && strcmp(str + (str_len - suffix_len), suffix) == 0);
+}
+
+typedef enum
+{
+ LOAD_CONVENIENCE = 0,
+ LOAD_RW,
+ LOAD_TYPED_RW,
+ LOAD_FORMAT_SPECIFIC,
+ LOAD_SIZED
+} LoadMode;
+
+/* Convert to RGBA for comparison, if necessary */
+static SDL_bool
+ConvertToRgba32(SDL_Surface **surface_p)
+{
+ if ((*surface_p)->format->format != SDL_PIXELFORMAT_RGBA32) {
+ SDL_Surface *temp;
+
+ temp = SDL_ConvertSurfaceFormat(*surface_p, SDL_PIXELFORMAT_RGBA32, 0);
+ SDLTest_AssertCheck(temp != NULL,
+ "Converting to RGBA should succeed (%s)",
+ SDL_GetError());
+ if (temp != NULL) {
+ return SDL_FALSE;
+ }
+ SDL_FreeSurface(*surface_p);
+ *surface_p = temp;
+ }
+ return SDL_TRUE;
+}
+
+static void
+FormatLoadTest(const Format *format,
+ LoadMode mode)
+{
+ SDL_Surface *reference = NULL;
+ SDL_Surface *surface = NULL;
+ SDL_RWops *src = NULL;
+ char *filename = GetTestFilename(TEST_FILE_DIST, format->sample);
+ char *refFilename = GetTestFilename(TEST_FILE_DIST, format->reference);
+ int initResult = 0;
+ int diff;
+
+ if (!SDLTest_AssertCheck(filename != NULL,
+ "Building filename should succeed (%s)",
+ SDL_GetError())) {
+ goto out;
+ }
+ if (!SDLTest_AssertCheck(refFilename != NULL,
+ "Building ref filename should succeed (%s)",
+ SDL_GetError())) {
+ goto out;
+ }
+
+ if (StrHasSuffix(format->reference, ".bmp")) {
+ reference = SDL_LoadBMP(refFilename);
+ if (!SDLTest_AssertCheck(reference != NULL,
+ "Loading reference should succeed (%s)",
+ SDL_GetError())) {
+ goto out;
+ }
+ }
+ else if (StrHasSuffix (format->reference, ".png")) {
+#ifdef LOAD_PNG
+ reference = IMG_Load(refFilename);
+ if (!SDLTest_AssertCheck(reference != NULL,
+ "Loading reference should succeed (%s)",
+ SDL_GetError())) {
+ goto out;
+ }
+#endif
+ }
+
+ if (format->initFlag) {
+ initResult = IMG_Init(format->initFlag);
+ if (!SDLTest_AssertCheck(initResult != 0,
+ "Initialization should succeed (%s)",
+ SDL_GetError())) {
+ goto out;
+ }
+ SDLTest_AssertCheck(initResult & format->initFlag,
+ "Expected at least bit 0x%x set, got 0x%x",
+ format->initFlag, initResult);
+ }
+
+ if (mode != LOAD_CONVENIENCE) {
+ src = SDL_RWFromFile(filename, "rb");
+ SDLTest_AssertCheck(src != NULL,
+ "Opening %s should succeed (%s)",
+ filename, SDL_GetError());
+ if (src == NULL)
+ goto out;
+ }
+
+ switch (mode) {
+ case LOAD_CONVENIENCE:
+ surface = IMG_Load(filename);
+ break;
+
+ case LOAD_RW:
+ if (format->checkFunction != NULL) {
+ SDL_RWops *ref_src;
+ int check;
+
+ ref_src = SDL_RWFromFile(refFilename, "rb");
+ SDLTest_AssertCheck(ref_src != NULL,
+ "Opening %s should succeed (%s)",
+ refFilename, SDL_GetError());
+ if (ref_src != NULL) {
+ check = format->checkFunction(ref_src);
+ SDLTest_AssertCheck(!check,
+ "Should not detect %s as %s -> %d",
+ refFilename, format->name, check);
+ SDL_RWclose(ref_src);
+ }
+ }
+
+ if (format->checkFunction != NULL) {
+ int check = format->checkFunction(src);
+
+ SDLTest_AssertCheck(check,
+ "Should detect %s as %s -> %d",
+ filename, format->name, check);
+ }
+
+ surface = IMG_Load_RW(src, SDL_TRUE);
+ src = NULL; /* ownership taken */
+ break;
+
+ case LOAD_TYPED_RW:
+ surface = IMG_LoadTyped_RW(src, SDL_TRUE, format->name);
+ src = NULL; /* ownership taken */
+ break;
+
+ case LOAD_FORMAT_SPECIFIC:
+ surface = format->loadFunction(src);
+ break;
+
+ case LOAD_SIZED:
+ if (strcmp(format->name, "SVG-sized") == 0) {
+ surface = IMG_LoadSizedSVG_RW(src, 64, 64);
+ }
+ break;
+ }
+
+ if (!SDLTest_AssertCheck(surface != NULL,
+ "Load %s (%s)", filename, SDL_GetError())) {
+ goto out;
+ }
+
+ SDLTest_AssertCheck(surface->w == format->w,
+ "Expected width %d px, got %d",
+ format->w, surface->w);
+ SDLTest_AssertCheck(surface->h == format->h,
+ "Expected height %d px, got %d",
+ format->h, surface->h);
+
+ if (reference != NULL) {
+ ConvertToRgba32(&reference);
+ ConvertToRgba32(&surface);
+ diff = SDLTest_CompareSurfaces(surface, reference, format->tolerance);
+ SDLTest_AssertCheck(diff == 0,
+ "Surface differed from reference by at least %d in %d pixels",
+ format->tolerance, diff);
+ }
+
+out:
+ if (surface != NULL) {
+ SDL_FreeSurface(surface);
+ }
+ if (reference != NULL) {
+ SDL_FreeSurface(reference);
+ }
+ if (src != NULL) {
+ SDL_RWclose(src);
+ }
+ if (refFilename != NULL) {
+ SDL_free(refFilename);
+ }
+ if (filename != NULL) {
+ SDL_free(filename);
+ }
+ if (initResult) {
+ IMG_Quit();
+ }
+}
+
+static void
+FormatSaveTest(const Format *format,
+ SDL_bool rw)
+{
+ char *refFilename = GetTestFilename(TEST_FILE_DIST, "sample.bmp");
+ const char *filename;
+ SDL_Surface *reference = NULL;
+ SDL_Surface *surface = NULL;
+ SDL_RWops *dest = NULL;
+ int initResult = 0;
+ int diff;
+ int result;
+
+ if (!SDLTest_AssertCheck(refFilename != NULL,
+ "Building ref filename should succeed (%s)",
+ SDL_GetError())) {
+ goto out;
+ }
+
+ reference = SDL_LoadBMP(refFilename);
+ if (!SDLTest_AssertCheck(reference != NULL,
+ "Loading reference should succeed (%s)",
+ SDL_GetError())) {
+ goto out;
+ }
+
+ if (format->initFlag) {
+ initResult = IMG_Init(format->initFlag);
+ if (!SDLTest_AssertCheck(initResult != 0,
+ "Initialization should succeed (%s)",
+ SDL_GetError())) {
+ goto out;
+ }
+ SDLTest_AssertCheck(initResult & format->initFlag,
+ "Expected at least bit 0x%x set, got 0x%x",
+ format->initFlag, initResult);
+ }
+
+ if (strcmp (format->name, "PNG") == 0) {
+ filename = "save.png";
+
+ if (rw) {
+ dest = SDL_RWFromFile(filename, "wb");
+ result = IMG_SavePNG_RW(reference, dest, SDL_FALSE);
+ SDL_RWclose(dest);
+ } else {
+ result = IMG_SavePNG(reference, filename);
+ }
+ } else if (strcmp(format->name, "JPG") == 0) {
+ filename = "save.jpg";
+
+ if (rw) {
+ dest = SDL_RWFromFile(filename, "wb");
+ result = IMG_SaveJPG_RW(reference, dest, SDL_FALSE, 90);
+ SDL_RWclose(dest);
+ } else {
+ result = IMG_SaveJPG(reference, "save.jpg", 90);
+ }
+ } else {
+ SDLTest_AssertCheck(SDL_FALSE, "How do I save %s?", format->name);
+ goto out;
+ }
+
+ SDLTest_AssertCheck(result == 0, "Save %s (%s)", filename, SDL_GetError());
+
+ if (format->canLoad) {
+ if (strcmp (format->name, "PNG") == 0) {
+ surface = IMG_Load("save.png");
+ } else if (strcmp (format->name, "JPG") == 0) {
+ surface = IMG_Load("save.jpg");
+ }
+
+ if (!SDLTest_AssertCheck(surface != NULL,
+ "Load %s (%s)", "saved file", SDL_GetError())) {
+ goto out;
+ }
+
+ SDLTest_AssertCheck(surface->w == format->w,
+ "Expected width %d px, got %d",
+ format->w, surface->w);
+ SDLTest_AssertCheck(surface->h == format->h,
+ "Expected height %d px, got %d",
+ format->h, surface->h);
+
+ diff = SDLTest_CompareSurfaces(surface, reference, format->tolerance);
+ SDLTest_AssertCheck(diff == 0,
+ "Surface differed from reference by at least %d in %d pixels",
+ format->tolerance, diff);
+ }
+
+out:
+ if (surface != NULL) {
+ SDL_FreeSurface(surface);
+ }
+ if (reference != NULL) {
+ SDL_FreeSurface(reference);
+ }
+ if (refFilename != NULL) {
+ SDL_free(refFilename);
+ }
+ if (initResult) {
+ IMG_Quit();
+ }
+}
+
+static void
+FormatTest(const Format *format)
+{
+ SDL_bool forced;
+ char envVar[64] = { 0 };
+
+ SDL_snprintf(envVar, sizeof(envVar), "SDL_IMAGE_TEST_REQUIRE_LOAD_%s",
+ format->name);
+
+ forced = GetStringBoolean(SDL_getenv(envVar), SDL_FALSE);
+ if (forced) {
+ SDLTest_AssertCheck(format->canLoad,
+ "%s loading should be enabled", format->name);
+ }
+
+ if (format->canLoad || forced) {
+ SDLTest_Log("Testing ability to load format %s", format->name);
+
+ if (strcmp(format->name, "SVG-sized") == 0) {
+ FormatLoadTest(format, LOAD_SIZED);
+ } else {
+ FormatLoadTest(format, LOAD_CONVENIENCE);
+ FormatLoadTest(format, LOAD_RW);
+ FormatLoadTest(format, LOAD_TYPED_RW);
+
+ if (format->loadFunction != NULL) {
+ FormatLoadTest(format, LOAD_FORMAT_SPECIFIC);
+ }
+ }
+ } else {
+ SDLTest_Log("Format %s is not supported", format->name);
+ }
+
+ SDL_snprintf(envVar, sizeof(envVar), "SDL_IMAGE_TEST_REQUIRE_SAVE_%s",
+ format->name);
+
+ forced = GetStringBoolean(SDL_getenv(envVar), SDL_FALSE);
+ if (forced) {
+ SDLTest_AssertCheck(format->canSave,
+ "%s saving should be enabled", format->name);
+ }
+
+ if (format->canSave || forced) {
+ SDLTest_Log("Testing ability to save format %s", format->name);
+ FormatSaveTest(format, SDL_FALSE);
+ FormatSaveTest(format, SDL_TRUE);
+ } else {
+ SDLTest_Log("Saving format %s is not supported", format->name);
+ }
+}
+
+static int
+TestFormats(void *arg)
+{
+ size_t i;
+
+ for (i = 0; i < SDL_arraysize(formats); i++) {
+ FormatTest(&formats[i]);
+ }
+
+ return TEST_COMPLETED;
+}
+
+static const SDLTest_TestCaseReference formatsTestCase = {
+ TestFormats, "Images", "Load and save various image formats", TEST_ENABLED
+};
+
+static const SDLTest_TestCaseReference *testCases[] = {
+ &formatsTestCase,
+ NULL
+};
+static SDLTest_TestSuiteReference testSuite = {
+ "img",
+ NULL,
+ testCases,
+ NULL
+};
+static SDLTest_TestSuiteReference *testSuites[] = {
+ &testSuite,
+ NULL
+};
+
+/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
+static void
+quit(int rc)
+{
+ SDLTest_CommonQuit(state);
+ exit(rc);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int result;
+ int testIterations = 1;
+ Uint64 userExecKey = 0;
+ char *userRunSeed = NULL;
+ char *filter = NULL;
+ int i, done;
+ SDL_Event event;
+
+ /* Initialize test framework */
+ state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
+ if (!state) {
+ return 1;
+ }
+
+ /* Parse commandline */
+ for (i = 1; i < argc;) {
+ int consumed;
+
+ consumed = SDLTest_CommonArg(state, i);
+ if (consumed == 0) {
+
(Patch may be truncated, please check the link at the top of this post.)