]> git.draconx.ca Git - cdecl99.git/blob - t/cdeclerr.c
Fix library error state allocation.
[cdecl99.git] / t / cdeclerr.c
1 /*
2  * Helper application to test internal library error reporting.
3  * Copyright © 2023 Nick Bowler
4  *
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.
9  *
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.
14  *
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/>.
17  */
18
19 #include <config.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <assert.h>
23 #include <ctype.h>
24
25 #include "cdecl-internal.h"
26 #include "cdecl.h"
27 #include "tap.h"
28
29 #if ENABLE_NLS
30 void cdecl__init_i18n(void) { }
31 #endif
32
33 static char *fmt_char(int c, char *buf)
34 {
35         int escape = 0;
36
37         switch (c) {
38         case '\a': escape = 'a';  break;
39         case '\b': escape = 'b';  break;
40         case '\t': escape = 't';  break;
41         case '\n': escape = 'n';  break;
42         case '\v': escape = 'v';  break;
43         case '\f': escape = 'f';  break;
44         case '\r': escape = 'r';  break;
45         case '\\': escape = '\\'; break;
46         case '\'': escape = '\''; break;
47         }
48
49         if (escape)
50                 sprintf(buf, "'\\%c'", escape);
51         else if (isprint((unsigned char)c))
52                 sprintf(buf, "'%c'", c);
53         else
54                 sprintf(buf, "'\\%.3o'", c & 0777u);
55
56         return buf;
57 }
58
59 static void check_fixed_string(size_t len)
60 {
61         const struct cdecl_error *err;
62         char *work1, *work2;
63         size_t errlen;
64
65         assert(len > 0);
66         work1 = calloc(2, len);
67         if (!work1)
68                 abort();
69
70         work2 = work1 + len;
71         memset(work1, 'X', len - 1);
72         memset(work2, 'X', len - 1);
73
74         tap_diag("cdecl__err w/ %lu-byte string", (unsigned long)len);
75         cdecl__err(1234, work1);
76         memset(work1, 0, len);
77         err = cdecl_get_error();
78
79         if (!tap_result(err->code == 1234, "returned error code")) {
80                 tap_diag("Failed, unexpected result");
81                 tap_diag("   Received: %u", err->code);
82                 tap_diag("   Expected: 1234");
83         }
84
85         errlen = strlen(err->str);
86         if (!tap_result(errlen == len-1, "returned string length")) {
87                 tap_diag("Failed, unexpected result");
88                 tap_diag("   Received: %lu", (unsigned long)errlen);
89                 tap_diag("   Expected: %lu", (unsigned long)len);
90         }
91
92         if (!tap_result(!memcmp(err->str, work2, len), "returned string")) {
93                 char buf[8];
94                 size_t n;
95
96                 n = strspn(err->str, "X");
97                 if (n >= len)
98                         n = len;
99
100                 tap_diag("Failed, first incorrect character at offset %lu",
101                          (unsigned long)n);
102                 tap_diag("   Received: %s", fmt_char(err->str[n], buf));
103                 tap_diag("   Expected: %s", fmt_char(work2[n], buf));
104         }
105
106         free(work1);
107 }
108
109 static void check_enomem()
110 {
111         const char expmsg[] = "failed to allocate memory";
112         const struct cdecl_error *err;
113
114         tap_diag("cdecl__err(CDECL_ENOMEM)");
115         cdecl__err(CDECL_ENOMEM);
116         err = cdecl_get_error();
117
118         if (!tap_result(err->code == CDECL_ENOMEM, "returned error code")) {
119                 tap_diag("Failed, unexpected result");
120                 tap_diag("   Received: %u", err->code);
121                 tap_diag("   Expected: %d", CDECL_ENOMEM);
122         }
123
124         if (!tap_result(!strcmp(err->str, "failed to allocate memory"),
125                         "returned string"))
126         {
127                 unsigned i;
128
129                 for (i = 0; i < sizeof expmsg; i++) {
130                         if (err->str[i] != expmsg[i])
131                                 break;
132                 }
133
134                 tap_diag("Failed, first incorrect character at offset %u", i);
135                 tap_diag("   Received: %.*s", (int)sizeof expmsg, err->str);
136                 tap_diag("   Expected: %s", expmsg);
137         }
138 }
139
140 int main(void)
141 {
142         tap_plan(3*3 + 2);
143
144         check_fixed_string(50);
145         check_fixed_string(500);
146         check_fixed_string(5000);
147
148         check_enomem();
149
150         tap_done();
151 }