1/* 2 * Copyright (c) 2023, Oracle and/or its affiliates. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24#include <glib.h> 25 26#include <errno.h> 27#include <limits.h> 28#include <setjmp.h> 29#include <signal.h> 30#include <stdlib.h> 31#include <unistd.h> 32 33#include "config.h" 34 35/* g_pattern_spec_match_string is available in glib 2.70 and later, 36 to replace the deprecated g_pattern_match_string */ 37#ifdef HAVE_G_PATTERN_SPEC_MATCH_STRING 38#define g_pattern_match_string g_pattern_spec_match_string 39#endif 40 41#define DEFAULT_TIMEOUT 10 /* maximum seconds for each file */ 42 43static sigjmp_buf jump_env; 44 45static void sigalrm (int sig) 46{ 47 siglongjmp(jump_env, 1); 48} 49 50typedef int (*testfilefunc)(const gchar *filepath); 51 52/* 53 * Test all files in a given subdir of either the build or source directory 54 */ 55static void 56TestAllFilesByType(GTestFileType file_type, gboolean compressed, 57 const char *subdir, int expected, testfilefunc testfunc) 58{ 59 const gchar *datadir_path, *filename; 60 GDir *datadir; 61 GError *err = NULL; 62 int timeout = DEFAULT_TIMEOUT; 63 char *timeout_env; 64 65 GPatternSpec *xpm_pattern = g_pattern_spec_new("*.xpm"); 66#ifndef NO_ZPIPE 67 GPatternSpec *z_pattern = compressed ? g_pattern_spec_new("*.xpm.Z") : NULL; 68 GPatternSpec *gz_pattern = compressed ? g_pattern_spec_new("*.xpm.gz") : NULL; 69#endif 70 71 /* Allow override when debugging tests */ 72 timeout_env = getenv("XPM_TEST_TIMEOUT"); 73 if (timeout_env != NULL) { 74 int from_env = atoi(timeout_env); 75 76 if (from_env >= 0) 77 timeout = from_env; 78 } 79 80 datadir_path = g_test_get_filename(file_type, "pixmaps", subdir, 81 (file_type == G_TEST_BUILT) ? "generated" : NULL, NULL); 82 g_assert_nonnull(datadir_path); 83 g_test_message("Reading files from %s", datadir_path); 84 85 datadir = g_dir_open(datadir_path, 0, &err); 86 g_assert_no_error(err); 87 88 errno = 0; 89 while ((filename = g_dir_read_name(datadir)) != NULL) { 90 91 if (!g_pattern_match_string(xpm_pattern, filename)) { 92#ifndef NO_ZPIPE 93 if (!compressed || 94 (!g_pattern_match_string(z_pattern, filename) && 95 !g_pattern_match_string(gz_pattern, filename))) 96#endif 97 { 98 g_test_message("skipping \"%s\"", filename); 99 continue; 100 } 101 } 102 103 /* 104 * Assumes the test function should complete in less than "timeout" 105 * seconds and fails if they don't, in order to catch runaway loops. 106 */ 107 if (timeout > 0) { 108 struct sigaction sa = { 109 .sa_handler = sigalrm, 110 .sa_flags = SA_RESTART 111 }; 112 sigemptyset (&sa.sa_mask); 113 sigaction(SIGALRM, &sa, NULL); 114 } 115 116 if (sigsetjmp(jump_env, 1) == 0) { 117 int status; 118 gchar *filepath; 119 120 filepath = g_build_filename(datadir_path, filename, NULL); 121 122 g_test_message("testing \"%s\", should return %d", 123 filename, expected); 124 if (timeout > 0) 125 alarm(timeout); 126 status = testfunc(filepath); 127 g_assert_cmpint(status, ==, expected); 128 129 if (timeout > 0) { 130 status = alarm(0); /* cancel alarm */ 131 g_test_message("%d seconds left on %d second timer", 132 status, timeout); 133 } 134 135 g_free(filepath); 136 } 137 else { 138 g_test_message("timed out reading %s", filename); 139 g_assertion_message(G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, 140 "test timed out"); 141 } 142 143 errno = 0; 144 } 145 // g_assert_cmpint(errno, ==, 0); - not sure why this sometimes fails 146 147 g_dir_close(datadir); 148} 149 150/* 151 * Test all non-compressed files in a given subdir 152 */ 153static void 154TestAllNormalFiles(const char *subdir, int expected, testfilefunc testfunc) 155{ 156 TestAllFilesByType(G_TEST_DIST, FALSE, subdir, expected, testfunc); 157} 158 159/* 160 * Test all compressed files in a given subdir 161 */ 162static void 163TestAllCompressedFiles(const char *subdir, int expected, testfilefunc testfunc) 164{ 165#ifdef NO_ZPIPE 166 g_test_message("compression disabled, skipping compressed file tests"); 167#else 168 TestAllFilesByType(G_TEST_BUILT, TRUE, subdir, expected, testfunc); 169#endif 170} 171