2 * Helper application to test internal library error reporting.
3 * Copyright © 2023 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"
30 const char *cdecl__token_name(unsigned token)
35 static char *fmt_char(int c, char *buf)
40 case '\a': escape = 'a'; break;
41 case '\b': escape = 'b'; break;
42 case '\t': escape = 't'; break;
43 case '\n': escape = 'n'; break;
44 case '\v': escape = 'v'; break;
45 case '\f': escape = 'f'; break;
46 case '\r': escape = 'r'; break;
47 case '\\': escape = '\\'; break;
48 case '\'': escape = '\''; break;
52 sprintf(buf, "'\\%c'", escape);
53 else if (isprint((unsigned char)c))
54 sprintf(buf, "'%c'", c);
56 sprintf(buf, "'\\%.3o'", c & 0777u);
61 static void check_code(const struct cdecl_error *err, unsigned expect)
63 if (!tap_result(err->code == expect, "returned error code")) {
64 tap_diag("Failed, unexpected result");
65 tap_diag(" Received: %u", err->code);
66 tap_diag(" Expected: %u", expect);
70 static void check_fixed_string(size_t len)
72 const struct cdecl_error *err;
77 work1 = calloc(2, len);
82 memset(work1, 'X', len - 1);
83 memset(work2, 'X', len - 1);
85 tap_diag("cdecl__err w/ %lu-byte string", (unsigned long)len);
86 cdecl__err(1234, work1, "XX");
87 memset(work1, 0, len);
88 err = cdecl_get_error();
90 check_code(err, 1234);
92 errlen = strlen(err->str);
93 if (!tap_result(errlen == len-1, "returned string length")) {
94 tap_diag("Failed, unexpected result");
95 tap_diag(" Received: %lu", (unsigned long)errlen);
96 tap_diag(" Expected: %lu", (unsigned long)len);
99 if (!tap_result(!memcmp(err->str, work2, len), "returned string")) {
103 n = strspn(err->str, "X");
107 tap_diag("Failed, first incorrect character at offset %lu",
109 tap_diag(" Received: %s", fmt_char(err->str[n], buf));
110 tap_diag(" Expected: %s", fmt_char(work2[n], buf));
116 static void check_format_string(const char *fmt, const char *arg)
118 size_t sz = strlen(fmt) + strlen(arg);
119 const struct cdecl_error *err;
122 work = malloc(sz + 1);
125 sprintf(work, fmt, arg);
127 cdecl__err(5432, fmt, arg);
128 err = cdecl_get_error();
130 tap_diag("cdecl__err(\"%s\", \"%s\")", fmt, arg);
131 check_code(err, 5432);
133 if (!tap_result(!strcmp(err->str, work), "returned string")) {
134 tap_diag("Failed, unexpected result");
135 tap_diag(" Received: %.*s", (int)sz, err->str);
136 tap_diag(" Expected: %s", work);
142 static void check_enomem()
144 const char expmsg[] = "failed to allocate memory";
145 const struct cdecl_error *err;
147 tap_diag("cdecl__errmsg(CDECL__ENOMEM)");
148 cdecl__errmsg(CDECL__ENOMEM);
149 err = cdecl_get_error();
151 check_code(err, CDECL_ENOMEM);
152 if (!tap_result(!strcmp(err->str, "failed to allocate memory"),
157 for (i = 0; i < sizeof expmsg; i++) {
158 if (err->str[i] != expmsg[i])
162 tap_diag("Failed, first incorrect character at offset %u", i);
163 tap_diag(" Received: %.*s", (int)sizeof expmsg, err->str);
164 tap_diag(" Expected: %s", expmsg);
168 #define IFNLS(a, b) (ENABLE_NLS ? (a) : (b))
172 tap_plan(3*3 + 2 + 2);
174 check_fixed_string(50);
175 check_fixed_string(500);
176 check_fixed_string(5000);
179 * When NLS is disabled, for implementation simplicity only format
180 * strings ending with %s are supported as this is sufficient.
181 * Otherwise, %s may appear anywhere.
183 check_format_string(IFNLS("hello %s world", "hello world %s"), "za");