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