blob: 88335de26cb3bd93fe2f0f548f048440556ab051 [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 Moolenaar62818152021-02-14 15:37:30 +010052 // Should not write anything to destination if buflen is 0.
53 trunc_string((char_u *)"", NULL, 1, 0);
54
55 // Truncating an empty string does nothing.
56 buf = alloc(1);
57 trunc_string((char_u *)"", buf, 1, 1);
58 assert(buf[0] == NUL);
59 vim_free(buf);
60
Bram Moolenaar85a20022019-12-21 18:25:54 +010061 // in place
Bram Moolenaarb9644432016-07-19 12:33:44 +020062 buf = alloc(40);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020063 STRCPY(buf, "text");
64 trunc_string(buf, buf, 20, 40);
65 assert(STRCMP(buf, "text") == 0);
Bram Moolenaarb9644432016-07-19 12:33:44 +020066 vim_free(buf);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020067
Bram Moolenaarb9644432016-07-19 12:33:44 +020068 buf = alloc(40);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020069 STRCPY(buf, "a short text");
70 trunc_string(buf, buf, 20, 40);
71 assert(STRCMP(buf, "a short text") == 0);
Bram Moolenaarb9644432016-07-19 12:33:44 +020072 vim_free(buf);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020073
Bram Moolenaarb9644432016-07-19 12:33:44 +020074 buf = alloc(40);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020075 STRCPY(buf, "a text tha just fits");
76 trunc_string(buf, buf, 20, 40);
77 assert(STRCMP(buf, "a text tha just fits") == 0);
Bram Moolenaarb9644432016-07-19 12:33:44 +020078 vim_free(buf);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020079
Bram Moolenaarb9644432016-07-19 12:33:44 +020080 buf = alloc(40);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020081 STRCPY(buf, "a text that nott fits");
82 trunc_string(buf, buf, 20, 40);
83 assert(STRCMP(buf, "a text t...nott fits") == 0);
Bram Moolenaarb9644432016-07-19 12:33:44 +020084 vim_free(buf);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020085
Bram Moolenaar85a20022019-12-21 18:25:54 +010086 // copy from string to buf
Bram Moolenaarb9644432016-07-19 12:33:44 +020087 buf = alloc(40);
88 s = vim_strsave((char_u *)"text");
89 trunc_string(s, buf, 20, 40);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020090 assert(STRCMP(buf, "text") == 0);
Bram Moolenaarb9644432016-07-19 12:33:44 +020091 vim_free(buf);
92 vim_free(s);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +020093
Bram Moolenaarb9644432016-07-19 12:33:44 +020094 buf = alloc(40);
95 s = vim_strsave((char_u *)"a text that fits");
96 trunc_string(s, buf, 34, 40);
97 assert(STRCMP(buf, "a text that fits") == 0);
98 vim_free(buf);
99 vim_free(s);
100
101 buf = alloc(40);
102 s = vim_strsave((char_u *)"a short text");
103 trunc_string(s, buf, 20, 40);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +0200104 assert(STRCMP(buf, "a short text") == 0);
Bram Moolenaarb9644432016-07-19 12:33:44 +0200105 vim_free(buf);
106 vim_free(s);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +0200107
Bram Moolenaarb9644432016-07-19 12:33:44 +0200108 buf = alloc(40);
109 s = vim_strsave((char_u *)"a text tha just fits");
110 trunc_string(s, buf, 20, 40);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +0200111 assert(STRCMP(buf, "a text tha just fits") == 0);
Bram Moolenaarb9644432016-07-19 12:33:44 +0200112 vim_free(buf);
113 vim_free(s);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +0200114
Bram Moolenaarb9644432016-07-19 12:33:44 +0200115 buf = alloc(40);
116 s = vim_strsave((char_u *)"a text that nott fits");
117 trunc_string(s, buf, 20, 40);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +0200118 assert(STRCMP(buf, "a text t...nott fits") == 0);
Bram Moolenaarb9644432016-07-19 12:33:44 +0200119 vim_free(buf);
120 vim_free(s);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +0200121}
122
Bram Moolenaard2c946b2019-12-31 19:24:51 +0100123/*
124 * Test vim_snprintf() with a focus on checking that truncation is
125 * correct when buffer is small, since it cannot be tested from
126 * vim scrip tests. Check that:
127 * - no buffer overflows happens (with valgrind or asan)
128 * - output string is always NUL terminated.
129 *
130 * Not all formats of vim_snprintf() are checked here. They are
131 * checked more exhaustively in Test_printf*() vim script tests.
132 */
133 static void
134test_vim_snprintf(void)
135{
136 int n;
137 size_t bsize;
138 int bsize_int;
Bram Moolenaar4da6df42020-04-20 16:12:09 +0200139 void *ptr = (void *)0x87654321;
Bram Moolenaard2c946b2019-12-31 19:24:51 +0100140
141 // Loop on various buffer sizes to make sure that truncation of
142 // vim_snprintf() is correct.
143 for (bsize = 0; bsize < 15; ++bsize)
144 {
145 bsize_int = (int)bsize - 1;
146
147 // buf is the heap rather than in the stack
148 // so valgrind can detect buffer overflows if any.
149 // Use malloc() rather than alloc() as test checks with 0-size
150 // buffer and its content should then never be used.
151 char *buf = malloc(bsize);
152
153 n = vim_snprintf(buf, bsize, "%d", 1234567);
154 assert(n == 7);
155 assert(bsize == 0 || STRNCMP(buf, "1234567", bsize_int) == 0);
156 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
157
158 n = vim_snprintf(buf, bsize, "%ld", 1234567L);
159 assert(n == 7);
160 assert(bsize == 0 || STRNCMP(buf, "1234567", bsize_int) == 0);
161 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
162
163 n = vim_snprintf(buf, bsize, "%9ld", 1234567L);
164 assert(n == 9);
165 assert(bsize == 0 || STRNCMP(buf, " 1234567", bsize_int) == 0);
166 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
167
168 n = vim_snprintf(buf, bsize, "%-9ld", 1234567L);
169 assert(n == 9);
170 assert(bsize == 0 || STRNCMP(buf, "1234567 ", bsize_int) == 0);
171 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
172
173 n = vim_snprintf(buf, bsize, "%x", 0xdeadbeef);
174 assert(n == 8);
175 assert(bsize == 0 || STRNCMP(buf, "deadbeef", bsize_int) == 0);
176 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
177
Bram Moolenaar1470dc32020-01-14 22:02:14 +0100178 n = vim_snprintf(buf, bsize, fmt_06b, (uvarnumber_T)12);
Bram Moolenaard2c946b2019-12-31 19:24:51 +0100179 assert(n == 6);
180 assert(bsize == 0 || STRNCMP(buf, "001100", bsize_int) == 0);
181 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
182
183#ifdef FEAT_FLOAT
184 n = vim_snprintf(buf, bsize, "%f", 1.234);
185 assert(n == 8);
186 assert(bsize == 0 || STRNCMP(buf, "1.234000", bsize_int) == 0);
187 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
188
189 n = vim_snprintf(buf, bsize, "%e", 1.234);
190 assert(n == 12);
191 assert(bsize == 0 || STRNCMP(buf, "1.234000e+00", bsize_int) == 0);
192 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
193
194 n = vim_snprintf(buf, bsize, "%f", 0.0/0.0);
195 assert(n == 3);
196 assert(bsize == 0 || STRNCMP(buf, "nan", bsize_int) == 0);
197 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
198
199 n = vim_snprintf(buf, bsize, "%f", 1.0/0.0);
200 assert(n == 3);
201 assert(bsize == 0 || STRNCMP(buf, "inf", bsize_int) == 0);
202 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
203
204 n = vim_snprintf(buf, bsize, "%f", -1.0/0.0);
205 assert(n == 4);
206 assert(bsize == 0 || STRNCMP(buf, "-inf", bsize_int) == 0);
207 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
208
209 n = vim_snprintf(buf, bsize, "%f", -0.0);
210 assert(n == 9);
211 assert(bsize == 0 || STRNCMP(buf, "-0.000000", bsize_int) == 0);
212 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
213#endif
214
215 n = vim_snprintf(buf, bsize, "%s", "漢語");
216 assert(n == 6);
217 assert(bsize == 0 || STRNCMP(buf, "漢語", bsize_int) == 0);
218 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
219
220 n = vim_snprintf(buf, bsize, "%8s", "漢語");
221 assert(n == 8);
222 assert(bsize == 0 || STRNCMP(buf, " 漢語", bsize_int) == 0);
223 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
224
225 n = vim_snprintf(buf, bsize, "%-8s", "漢語");
226 assert(n == 8);
227 assert(bsize == 0 || STRNCMP(buf, "漢語 ", bsize_int) == 0);
228 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
229
230 n = vim_snprintf(buf, bsize, "%.3s", "漢語");
231 assert(n == 3);
232 assert(bsize == 0 || STRNCMP(buf, "漢", bsize_int) == 0);
233 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
234
235 n = vim_snprintf(buf, bsize, fmt_5S, "foo");
236 assert(n == 5);
237 assert(bsize == 0 || STRNCMP(buf, " foo", bsize_int) == 0);
238 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
239
240 n = vim_snprintf(buf, bsize, "%%%%%%");
241 assert(n == 3);
242 assert(bsize == 0 || STRNCMP(buf, "%%%", bsize_int) == 0);
243 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
244
245 n = vim_snprintf(buf, bsize, "%c%c", 1, 2);
246 assert(n == 2);
247 assert(bsize == 0 || STRNCMP(buf, "\x01\x02", bsize_int) == 0);
248 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
249
250 // %p format is not tested in vim script tests Test_printf*()
251 // as it only makes sense in C code.
Bram Moolenaard5b99142020-02-08 17:14:46 +0100252 // NOTE: SunOS libc doesn't use the prefix "0x" on %p.
253#ifdef SUN_SYSTEM
254# define PREFIX_LEN 0
255# define PREFIX_STR1 ""
256# define PREFIX_STR2 "00"
257#else
258# define PREFIX_LEN 2
259# define PREFIX_STR1 "0x"
260# define PREFIX_STR2 "0x"
261#endif
Bram Moolenaard2c946b2019-12-31 19:24:51 +0100262 n = vim_snprintf(buf, bsize, "%p", ptr);
Bram Moolenaard5b99142020-02-08 17:14:46 +0100263 assert(n == 8 + PREFIX_LEN);
264 assert(bsize == 0
265 || STRNCMP(buf, PREFIX_STR1 "87654321", bsize_int) == 0);
Bram Moolenaard2c946b2019-12-31 19:24:51 +0100266 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
267
268 n = vim_snprintf(buf, bsize, fmt_012p, ptr);
269 assert(n == 12);
Bram Moolenaard5b99142020-02-08 17:14:46 +0100270 assert(bsize == 0
271 || STRNCMP(buf, PREFIX_STR2 "0087654321", bsize_int) == 0);
Bram Moolenaard2c946b2019-12-31 19:24:51 +0100272 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
273
274 free(buf);
275 }
276}
277
Bram Moolenaar502ae4b2016-07-16 19:50:13 +0200278 int
279main(int argc, char **argv)
280{
Bram Moolenaara80faa82020-04-12 19:37:17 +0200281 CLEAR_FIELD(params);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +0200282 params.argc = argc;
283 params.argv = argv;
284 common_init(&params);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +0200285
Bram Moolenaard0337e32019-12-30 17:55:34 +0100286 set_option_value((char_u *)"encoding", 0, (char_u *)"utf-8", 0);
287 init_chartab();
Bram Moolenaar502ae4b2016-07-16 19:50:13 +0200288 test_trunc_string();
Bram Moolenaard2c946b2019-12-31 19:24:51 +0100289 test_vim_snprintf();
Bram Moolenaard0337e32019-12-30 17:55:34 +0100290
291 set_option_value((char_u *)"encoding", 0, (char_u *)"latin1", 0);
292 init_chartab();
293 test_trunc_string();
Bram Moolenaard2c946b2019-12-31 19:24:51 +0100294 test_vim_snprintf();
Bram Moolenaard0337e32019-12-30 17:55:34 +0100295
Bram Moolenaar502ae4b2016-07-16 19:50:13 +0200296 return 0;
297}