summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-07-14 08:49:12 +0300
committerPaul Buetow <paul@buetow.org>2026-07-14 08:49:12 +0300
commit12be1b9ae52829292d13cc2fcc6ff7571d050d62 (patch)
tree674aafaeb3485bb38dd1e2ecc3d62f77e3584366 /tests
parent484fbca06312dbe0f381109763f701671f22e602 (diff)
progressive: libjpeg-turbo two-phase JPEG backend (st0)
M6: progressive low-res preview via libjpeg-turbo. - jpeg.c: two-phase decode (1/8 low-res via progress_cb, full via GdkPixbuf with EXIF orientation). Feature-gated. - loader.h/c: LoaderProgressCb + load_progressive on backend struct; loader_load_async accepts progress params; JPEG special-cased in task thread. - window.c: _load_progress_cb marshals partial to main thread. - tests: test_loader_jpeg (progress + dims), test_progressive_jpeg (sample). 16/16 green, ASan clean.
Diffstat (limited to 'tests')
-rw-r--r--tests/meson.build23
-rw-r--r--tests/test_loader_jpeg.c97
-rw-r--r--tests/test_progressive_jpeg.c94
3 files changed, 214 insertions, 0 deletions
diff --git a/tests/meson.build b/tests/meson.build
index 86eee1d..dbe21f2 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -67,6 +67,18 @@ test_loader_pixbuf = executable(
)
test('loader_pixbuf', test_loader_pixbuf, suite : 'unit', env : fixtures_env)
+if libjpeg_dep.found()
+ test_loader_jpeg = executable(
+ 'test_loader_jpeg',
+ ['test_loader_jpeg.c', ggaze_conf_h],
+ include_directories : [inc, src_inc],
+ dependencies : [gdkpixbuf_dep, gtk4_dep, glib_dep, gio_dep],
+ link_with : ggaze_lib,
+ install : false,
+ )
+ test('loader_jpeg', test_loader_jpeg, suite : 'unit', env : fixtures_env)
+endif
+
test_navigator = executable(
'test_navigator',
['test_navigator.c', ggaze_conf_h],
@@ -172,4 +184,15 @@ test_grid_cull = executable(
)
test('grid_cull', test_grid_cull, suite : 'integration', env : fixtures_env)
+test_progressive_jpeg = executable(
+ 'test_progressive_jpeg',
+ ['test_progressive_jpeg.c', ggaze_conf_h],
+ include_directories : [inc, src_inc],
+ dependencies : ggaze_deps,
+ link_with : ggaze_lib,
+ install : false,
+)
+test('progressive_jpeg', test_progressive_jpeg,
+ suite : 'integration', env : fixtures_env)
+
subdir('integration') \ No newline at end of file
diff --git a/tests/test_loader_jpeg.c b/tests/test_loader_jpeg.c
new file mode 100644
index 0000000..6a2e0e5
--- /dev/null
+++ b/tests/test_loader_jpeg.c
@@ -0,0 +1,97 @@
+/*:*
+ * ggaze — libjpeg-turbo progressive loader unit test (feature-gated)
+ *
+ * Tests the progressive JPEG path: loader_load_async with a progress callback
+ * fires the callback (low-res partial) and returns the full texture. Only
+ * compiled when libjpeg-turbo is found (HAVE_JPEG).
+ *
+ * Copyright (c) 2026 ggaze contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *:*/
+
+#include "loader/loader.h"
+
+#include <gdk/gdk.h>
+#include <gio/gio.h>
+#include <glib.h>
+
+static volatile int g_progress_fired = 0;
+static GMainLoop *g_loop = NULL;
+static GdkTexture *g_result = NULL;
+
+static void
+progress_cb(GdkTexture *p_partial, gpointer p_data) {
+ (void)p_partial;
+ (void)p_data;
+ g_atomic_int_set(&g_progress_fired, 1);
+}
+
+static void
+finish_cb(GObject *p_src, GAsyncResult *p_res, gpointer p_data) {
+ (void)p_src;
+ (void)p_data;
+ GError *p_err = NULL;
+ g_result = loader_load_finish(p_res, &p_err);
+ g_assert_no_error(p_err);
+ g_main_loop_quit(g_loop);
+}
+
+static void
+test_progressive_jpeg(void) {
+ const char *c_dir = g_getenv("GGAZE_FIXTURES_DIR");
+ g_assert_nonnull(c_dir);
+ char *c_path = g_build_filename(c_dir, "plain.jpg", NULL);
+ GFile *p_file = g_file_new_for_path(c_path);
+ g_free(c_path);
+
+ g_progress_fired = 0;
+ g_result = NULL;
+ g_loop = g_main_loop_new(NULL, FALSE);
+ loader_load_async(p_file, NULL, progress_cb, NULL, finish_cb, NULL);
+ g_main_loop_run(g_loop);
+ g_main_loop_unref(g_loop);
+ g_loop = NULL;
+
+ g_assert_nonnull(g_result);
+ g_assert_cmpint(gdk_texture_get_width(g_result), ==, 6);
+ g_assert_cmpint(gdk_texture_get_height(g_result), ==, 3);
+ g_assert_cmpint(g_atomic_int_get(&g_progress_fired), ==, 1);
+ g_object_unref(g_result);
+ g_object_unref(p_file);
+}
+
+static void
+test_progressive_rotated(void) {
+ const char *c_dir = g_getenv("GGAZE_FIXTURES_DIR");
+ g_assert_nonnull(c_dir);
+ char *c_path = g_build_filename(c_dir, "rot6.jpg", NULL);
+ GFile *p_file = g_file_new_for_path(c_path);
+ g_free(c_path);
+
+ g_progress_fired = 0;
+ g_result = NULL;
+ g_loop = g_main_loop_new(NULL, FALSE);
+ loader_load_async(p_file, NULL, progress_cb, NULL, finish_cb, NULL);
+ g_main_loop_run(g_loop);
+ g_main_loop_unref(g_loop);
+
+ /* Full result via GdkPixbuf applies EXIF orientation → 4x8. */
+ g_assert_nonnull(g_result);
+ g_assert_cmpint(gdk_texture_get_width(g_result), ==, 4);
+ g_assert_cmpint(gdk_texture_get_height(g_result), ==, 8);
+ g_object_unref(g_result);
+ g_object_unref(p_file);
+}
+
+int
+main(int i_argc, char **c_argv) {
+ g_test_init(&i_argc, &c_argv, NULL);
+ if (g_getenv("GGAZE_FIXTURES_DIR") == NULL) {
+ g_test_skip("GGAZE_FIXTURES_DIR unset");
+ return (g_test_run());
+ }
+ g_test_add_func("/loader/jpeg/progressive", test_progressive_jpeg);
+ g_test_add_func("/loader/jpeg/progressive_rotated",
+ test_progressive_rotated);
+ return (g_test_run());
+} \ No newline at end of file
diff --git a/tests/test_progressive_jpeg.c b/tests/test_progressive_jpeg.c
new file mode 100644
index 0000000..8fc8f19
--- /dev/null
+++ b/tests/test_progressive_jpeg.c
@@ -0,0 +1,94 @@
+/*:*
+ * ggaze — progressive JPEG integration test
+ *
+ * Opens a large sample JPEG via the window (async + progressive path) and
+ * asserts the viewer shows a texture. The progressive low-res partial fires
+ * first (via the loader's progress callback), then the full result replaces
+ * it. Skip-if-absent (./sample-images not in CI). Needs a display.
+ *
+ * Copyright (c) 2026 ggaze contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *:*/
+
+#include "viewer.h"
+#include "window.h"
+
+#include <gdk/gdk.h>
+#include <gio/gio.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+
+static GgazeWindow *
+new_window(void) {
+ return (GGAZE_WINDOW(g_object_new(GGAZE_TYPE_WINDOW, NULL)));
+}
+
+static GdkTexture *
+viewer_texture(GgazeWindow *p_win) {
+ GtkStack *p_stack = ggaze_window_get_stack(p_win);
+ GtkWidget *p_large = gtk_stack_get_child_by_name(p_stack, "large");
+ return (ggaze_viewer_get_texture(GGAZE_VIEWER(p_large)));
+}
+
+static void
+drain_main(guint u_ms) {
+ for (guint u = 0; u < u_ms; u++) {
+ g_main_context_iteration(g_main_context_default(), FALSE);
+ g_usleep(1000);
+ }
+}
+
+static void
+test_progressive_sample(void) {
+ const gchar *c_dir = g_getenv("GGAZE_SAMPLE_DIR");
+ if (c_dir == NULL || *c_dir == '\0' ||
+ !g_file_test(c_dir, G_FILE_TEST_IS_DIR)) {
+ g_test_skip("GGAZE_SAMPLE_DIR unset/absent (./sample-images)");
+ return;
+ }
+ GDir *p_d = g_dir_open(c_dir, 0, NULL);
+ g_assert_nonnull(p_d);
+ const gchar *c_name;
+ while ((c_name = g_dir_read_name(p_d)) != NULL) {
+ if (g_str_has_suffix(c_name, ".jpg") ||
+ g_str_has_suffix(c_name, ".JPG")) {
+ break;
+ }
+ }
+ char *c_path =
+ (c_name != NULL) ? g_build_filename(c_dir, c_name, NULL) : NULL;
+ g_dir_close(p_d);
+ if (c_path == NULL) {
+ g_test_skip("no JPEG sample found");
+ return;
+ }
+
+ GgazeWindow *p_win = new_window();
+ GFile *p_file = g_file_new_for_path(c_path);
+ ggaze_window_open(p_win, p_file);
+ g_object_unref(p_file);
+ g_free(c_path);
+
+ /* Pump until the viewer shows a texture (the progressive partial or the
+ * full result). */
+ for (guint u = 0; u < 3000 && viewer_texture(p_win) == NULL; u++) {
+ g_main_context_iteration(g_main_context_default(), FALSE);
+ g_usleep(1000);
+ }
+ g_assert_nonnull(viewer_texture(p_win));
+
+ g_object_unref(p_win);
+ drain_main(500);
+}
+
+int
+main(int i_argc, char **c_argv) {
+ g_test_init(&i_argc, &c_argv, NULL);
+ g_log_set_always_fatal(G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
+ if (!gtk_init_check()) {
+ g_test_skip("no display available (run under xvfb)");
+ return (g_test_run());
+ }
+ g_test_add_func("/progressive/sample", test_progressive_sample);
+ return (g_test_run());
+} \ No newline at end of file