blob: 38e52c5f8a258b23b90a8fbc226e9f9c3d150eb6 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar502ae4b2016-07-16 19:50:13 +02002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * message_test.c: Unittests for message.c
12 */
13
14#undef NDEBUG
15#include <assert.h>
16
Bram Moolenaar85a20022019-12-21 18:25:54 +010017// Must include main.c because it contains much more than just main()
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020018#define NO_VIM_MAIN
19#include "main.c"
20
Bram Moolenaar85a20022019-12-21 18:25:54 +010021// This file has to be included because some of the tested functions are
22// static.
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020023#include "message.c"
24
Bram Moolenaard2c946b2019-12-31 19:24:51 +010025#ifndef MIN
26# define MIN(x,y) ((x) < (y) ? (x) : (y))
27#endif
28
29// These formats are not standard in C printf() function.
30// Use a global variable rather than a literal format to disable
31// -Wformat compiler warnings:
32//
33// - warning: '0' flag used with ‘%p’ gnu_printf format
34// - warning: format ‘%S’ expects argument of type ‘wchar_t *’, but argument 4 has type ‘char *’
35// - warning: unknown conversion type character ‘b’ in format
36//
37// These formats are in practise only used from vim script printf()
38// function and never as literals in C code.
39char *fmt_012p = "%012p";
40char *fmt_5S = "%5S";
41char *fmt_06b = "%06b";
42
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020043/*
44 * Test trunc_string().
45 */
46 static void
47test_trunc_string(void)
48{
Bram Moolenaarb9644432016-07-19 12:33:44 +020049 char_u *buf; /*allocated every time to find uninit errors */
50 char_u *s;
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020051
Bram Moolenaar85a20022019-12-21 18:25:54 +010052 // in place
Bram Moolenaarb9644432016-07-19 12:33:44 +020053 buf = alloc(40);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020054 STRCPY(buf, "text");
55 trunc_string(buf, buf, 20, 40);
56 assert(STRCMP(buf, "text") == 0);
Bram Moolenaarb9644432016-07-19 12:33:44 +020057 vim_free(buf);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020058
Bram Moolenaarb9644432016-07-19 12:33:44 +020059 buf = alloc(40);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020060 STRCPY(buf, "a short text");
61 trunc_string(buf, buf, 20, 40);
62 assert(STRCMP(buf, "a short text") == 0);
Bram Moolenaarb9644432016-07-19 12:33:44 +020063 vim_free(buf);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020064
Bram Moolenaarb9644432016-07-19 12:33:44 +020065 buf = alloc(40);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020066 STRCPY(buf, "a text tha just fits");
67 trunc_string(buf, buf, 20, 40);
68 assert(STRCMP(buf, "a text tha just fits") == 0);
Bram Moolenaarb9644432016-07-19 12:33:44 +020069 vim_free(buf);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020070
Bram Moolenaarb9644432016-07-19 12:33:44 +020071 buf = alloc(40);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020072 STRCPY(buf, "a text that nott fits");
73 trunc_string(buf, buf, 20, 40);
74 assert(STRCMP(buf, "a text t...nott fits") == 0);
Bram Moolenaarb9644432016-07-19 12:33:44 +020075 vim_free(buf);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020076
Bram Moolenaar85a20022019-12-21 18:25:54 +010077 // copy from string to buf
Bram Moolenaarb9644432016-07-19 12:33:44 +020078 buf = alloc(40);
79 s = vim_strsave((char_u *)"text");
80 trunc_string(s, buf, 20, 40);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020081 assert(STRCMP(buf, "text") == 0);
Bram Moolenaarb9644432016-07-19 12:33:44 +020082 vim_free(buf);
83 vim_free(s);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020084
Bram Moolenaarb9644432016-07-19 12:33:44 +020085 buf = alloc(40);
86 s = vim_strsave((char_u *)"a text that fits");
87 trunc_string(s, buf, 34, 40);
88 assert(STRCMP(buf, "a text that fits") == 0);
89 vim_free(buf);
90 vim_free(s);
91
92 buf = alloc(40);
93 s = vim_strsave((char_u *)"a short text");
94 trunc_string(s, buf, 20, 40);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020095 assert(STRCMP(buf, "a short text") == 0);
Bram Moolenaarb9644432016-07-19 12:33:44 +020096 vim_free(buf);
97 vim_free(s);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020098
Bram Moolenaarb9644432016-07-19 12:33:44 +020099 buf = alloc(40);
100 s = vim_strsave((char_u *)"a text tha just fits");
101 trunc_string(s, buf, 20, 40);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +0200102 assert(STRCMP(buf, "a text tha just fits") == 0);
Bram Moolenaarb9644432016-07-19 12:33:44 +0200103 vim_free(buf);
104 vim_free(s);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +0200105
Bram Moolenaarb9644432016-07-19 12:33:44 +0200106 buf = alloc(40);
107 s = vim_strsave((char_u *)"a text that nott fits");
108 trunc_string(s, buf, 20, 40);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +0200109 assert(STRCMP(buf, "a text t...nott fits") == 0);
Bram Moolenaarb9644432016-07-19 12:33:44 +0200110 vim_free(buf);
111 vim_free(s);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +0200112}
113
Bram Moolenaard2c946b2019-12-31 19:24:51 +0100114/*
115 * Test vim_snprintf() with a focus on checking that truncation is
116 * correct when buffer is small, since it cannot be tested from
117 * vim scrip tests. Check that:
118 * - no buffer overflows happens (with valgrind or asan)
119 * - output string is always NUL terminated.
120 *
121 * Not all formats of vim_snprintf() are checked here. They are
122 * checked more exhaustively in Test_printf*() vim script tests.
123 */
124 static void
125test_vim_snprintf(void)
126{
127 int n;
128 size_t bsize;
129 int bsize_int;
130 char *ptr = (char *)0x87654321;
131
132 // Loop on various buffer sizes to make sure that truncation of
133 // vim_snprintf() is correct.
134 for (bsize = 0; bsize < 15; ++bsize)
135 {
136 bsize_int = (int)bsize - 1;
137
138 // buf is the heap rather than in the stack
139 // so valgrind can detect buffer overflows if any.
140 // Use malloc() rather than alloc() as test checks with 0-size
141 // buffer and its content should then never be used.
142 char *buf = malloc(bsize);
143
144 n = vim_snprintf(buf, bsize, "%d", 1234567);
145 assert(n == 7);
146 assert(bsize == 0 || STRNCMP(buf, "1234567", bsize_int) == 0);
147 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
148
149 n = vim_snprintf(buf, bsize, "%ld", 1234567L);
150 assert(n == 7);
151 assert(bsize == 0 || STRNCMP(buf, "1234567", bsize_int) == 0);
152 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
153
154 n = vim_snprintf(buf, bsize, "%9ld", 1234567L);
155 assert(n == 9);
156 assert(bsize == 0 || STRNCMP(buf, " 1234567", bsize_int) == 0);
157 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
158
159 n = vim_snprintf(buf, bsize, "%-9ld", 1234567L);
160 assert(n == 9);
161 assert(bsize == 0 || STRNCMP(buf, "1234567 ", bsize_int) == 0);
162 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
163
164 n = vim_snprintf(buf, bsize, "%x", 0xdeadbeef);
165 assert(n == 8);
166 assert(bsize == 0 || STRNCMP(buf, "deadbeef", bsize_int) == 0);
167 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
168
169 n = vim_snprintf(buf, bsize, fmt_06b, 12);
170 assert(n == 6);
171 assert(bsize == 0 || STRNCMP(buf, "001100", bsize_int) == 0);
172 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
173
174#ifdef FEAT_FLOAT
175 n = vim_snprintf(buf, bsize, "%f", 1.234);
176 assert(n == 8);
177 assert(bsize == 0 || STRNCMP(buf, "1.234000", bsize_int) == 0);
178 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
179
180 n = vim_snprintf(buf, bsize, "%e", 1.234);
181 assert(n == 12);
182 assert(bsize == 0 || STRNCMP(buf, "1.234000e+00", bsize_int) == 0);
183 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
184
185 n = vim_snprintf(buf, bsize, "%f", 0.0/0.0);
186 assert(n == 3);
187 assert(bsize == 0 || STRNCMP(buf, "nan", bsize_int) == 0);
188 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
189
190 n = vim_snprintf(buf, bsize, "%f", 1.0/0.0);
191 assert(n == 3);
192 assert(bsize == 0 || STRNCMP(buf, "inf", bsize_int) == 0);
193 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
194
195 n = vim_snprintf(buf, bsize, "%f", -1.0/0.0);
196 assert(n == 4);
197 assert(bsize == 0 || STRNCMP(buf, "-inf", bsize_int) == 0);
198 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
199
200 n = vim_snprintf(buf, bsize, "%f", -0.0);
201 assert(n == 9);
202 assert(bsize == 0 || STRNCMP(buf, "-0.000000", bsize_int) == 0);
203 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
204#endif
205
206 n = vim_snprintf(buf, bsize, "%s", "漢語");
207 assert(n == 6);
208 assert(bsize == 0 || STRNCMP(buf, "漢語", bsize_int) == 0);
209 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
210
211 n = vim_snprintf(buf, bsize, "%8s", "漢語");
212 assert(n == 8);
213 assert(bsize == 0 || STRNCMP(buf, " 漢語", bsize_int) == 0);
214 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
215
216 n = vim_snprintf(buf, bsize, "%-8s", "漢語");
217 assert(n == 8);
218 assert(bsize == 0 || STRNCMP(buf, "漢語 ", bsize_int) == 0);
219 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
220
221 n = vim_snprintf(buf, bsize, "%.3s", "漢語");
222 assert(n == 3);
223 assert(bsize == 0 || STRNCMP(buf, "漢", bsize_int) == 0);
224 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
225
226 n = vim_snprintf(buf, bsize, fmt_5S, "foo");
227 assert(n == 5);
228 assert(bsize == 0 || STRNCMP(buf, " foo", bsize_int) == 0);
229 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
230
231 n = vim_snprintf(buf, bsize, "%%%%%%");
232 assert(n == 3);
233 assert(bsize == 0 || STRNCMP(buf, "%%%", bsize_int) == 0);
234 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
235
236 n = vim_snprintf(buf, bsize, "%c%c", 1, 2);
237 assert(n == 2);
238 assert(bsize == 0 || STRNCMP(buf, "\x01\x02", bsize_int) == 0);
239 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
240
241 // %p format is not tested in vim script tests Test_printf*()
242 // as it only makes sense in C code.
243 n = vim_snprintf(buf, bsize, "%p", ptr);
244 assert(n == 10);
245 assert(bsize == 0 || STRNCMP(buf, "0x87654321", bsize_int) == 0);
246 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
247
248 n = vim_snprintf(buf, bsize, fmt_012p, ptr);
249 assert(n == 12);
250 assert(bsize == 0 || STRNCMP(buf, "0x0087654321", bsize_int) == 0);
251 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
252
253 free(buf);
254 }
255}
256
Bram Moolenaar502ae4b2016-07-16 19:50:13 +0200257 int
258main(int argc, char **argv)
259{
Bram Moolenaar502ae4b2016-07-16 19:50:13 +0200260 vim_memset(&params, 0, sizeof(params));
261 params.argc = argc;
262 params.argv = argv;
263 common_init(&params);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +0200264
Bram Moolenaard0337e32019-12-30 17:55:34 +0100265 set_option_value((char_u *)"encoding", 0, (char_u *)"utf-8", 0);
266 init_chartab();
Bram Moolenaar502ae4b2016-07-16 19:50:13 +0200267 test_trunc_string();
Bram Moolenaard2c946b2019-12-31 19:24:51 +0100268 test_vim_snprintf();
Bram Moolenaard0337e32019-12-30 17:55:34 +0100269
270 set_option_value((char_u *)"encoding", 0, (char_u *)"latin1", 0);
271 init_chartab();
272 test_trunc_string();
Bram Moolenaard2c946b2019-12-31 19:24:51 +0100273 test_vim_snprintf();
Bram Moolenaard0337e32019-12-30 17:55:34 +0100274
Bram Moolenaar502ae4b2016-07-16 19:50:13 +0200275 return 0;
276}