2 * Helper application to test internal library error reporting.
3 * Copyright © 2023-2024 Nick Bowler
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
25 #include "cdecl-internal.h"
31 * Function called from output.c but not needed for error messaging.
33 const char *cdecl__token_name(unsigned token)
35 tap_bail_out("stub cdecl__token_name called");
38 static char *fmt_char(int c, char *buf)
43 case '\a': escape = 'a'; break;
44 case '\b': escape = 'b'; break;
45 case '\t': escape = 't'; break;
46 case '\n': escape = 'n'; break;
47 case '\v': escape = 'v'; break;
48 case '\f': escape = 'f'; break;
49 case '\r': escape = 'r'; break;
50 case '\\': escape = '\\'; break;
51 case '\'': escape = '\''; break;
55 sprintf(buf, "'\\%c'", escape);
56 else if (isprint((unsigned char)c))
57 sprintf(buf, "'%c'", c);
59 sprintf(buf, "'\\%.3o'", c & 0777u);
64 static void check_code(const struct cdecl_error *err, unsigned expect)
66 if (!tap_result(err->code == expect, "returned error code")) {
67 tap_diag("Failed, unexpected result");
68 tap_diag(" Received: %u", err->code);
69 tap_diag(" Expected: %u", expect);
73 static void check_fixed_string(size_t len)
75 const struct cdecl_error *err;
80 work1 = calloc(2, len);
85 memset(work1, 'X', len - 1);
86 memset(work2, 'X', len - 1);
88 tap_diag("cdecl__err w/ %lu-byte string", (unsigned long)len);
89 cdecl__err(work1, "XX");
90 memset(work1, 0, len);
91 err = cdecl_get_error();
93 check_code(err, CDECL_ENOPARSE);
95 errlen = strlen(err->str);
96 if (!tap_result(errlen == len-1, "returned string length")) {
97 tap_diag("Failed, unexpected result");
98 tap_diag(" Received: %lu", (unsigned long)errlen);
99 tap_diag(" Expected: %lu", (unsigned long)len);
102 if (!tap_result(!memcmp(err->str, work2, len), "returned string")) {
106 n = strspn(err->str, "X");
110 tap_diag("Failed, first incorrect character at offset %lu",
112 tap_diag(" Received: %s", fmt_char(err->str[n], buf));
113 tap_diag(" Expected: %s", fmt_char(work2[n], buf));
119 static void check_format_string(const char *fmt, const char *arg)
121 size_t sz = strlen(fmt) + strlen(arg);
122 const struct cdecl_error *err;
125 work = malloc(sz + 1);
128 sprintf(work, fmt, arg);
130 cdecl__err(fmt, arg);
131 err = cdecl_get_error();
133 tap_diag("cdecl__err(\"%s\", \"%s\")", fmt, arg);
134 check_code(err, CDECL_ENOPARSE);
136 if (!tap_result(!strcmp(err->str, work), "returned string")) {
137 tap_diag("Failed, unexpected result");
138 tap_diag(" Received: %.*s", (int)sz, err->str);
139 tap_diag(" Expected: %s", work);
145 static void check_enomem()
147 const char expmsg[] = "failed to allocate memory";
148 const struct cdecl_error *err;
150 tap_diag("cdecl__errmsg(CDECL__ENOMEM)");
151 cdecl__errmsg(CDECL__ENOMEM);
152 err = cdecl_get_error();
154 check_code(err, CDECL_ENOMEM);
155 if (!tap_result(!strcmp(err->str, "failed to allocate memory"),
160 for (i = 0; i < sizeof expmsg; i++) {
161 if (err->str[i] != expmsg[i])
165 tap_diag("Failed, first incorrect character at offset %u", i);
166 tap_diag(" Received: %.*s", (int)sizeof expmsg, err->str);
167 tap_diag(" Expected: %s", expmsg);
171 #define IFNLS(a, b) (ENABLE_NLS ? (a) : (b))
175 tap_plan(3*3 + 2 + 2);
177 check_fixed_string(50);
178 check_fixed_string(500);
179 check_fixed_string(5000);
182 * When NLS is disabled, for implementation simplicity only format
183 * strings ending with %s are supported as this is sufficient.
184 * Otherwise, %s may appear anywhere.
186 check_format_string(IFNLS("hello %s world", "hello world %s"), "za");