blob: 85a29b4712828a694158352a45a881cf5c6738a1 [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;
Bram Moolenaar4da6df42020-04-20 16:12:09 +0200130 void *ptr = (void *)0x87654321;
Bram Moolenaard2c946b2019-12-31 19:24:51 +0100131
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
Bram Moolenaar1470dc32020-01-14 22:02:14 +0100169 n = vim_snprintf(buf, bsize, fmt_06b, (uvarnumber_T)12);
Bram Moolenaard2c946b2019-12-31 19:24:51 +0100170 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.
Bram Moolenaard5b99142020-02-08 17:14:46 +0100243 // NOTE: SunOS libc doesn't use the prefix "0x" on %p.
244#ifdef SUN_SYSTEM
245# define PREFIX_LEN 0
246# define PREFIX_STR1 ""
247# define PREFIX_STR2 "00"
248#else
249# define PREFIX_LEN 2
250# define PREFIX_STR1 "0x"
251# define PREFIX_STR2 "0x"
252#endif
Bram Moolenaard2c946b2019-12-31 19:24:51 +0100253 n = vim_snprintf(buf, bsize, "%p", ptr);
Bram Moolenaard5b99142020-02-08 17:14:46 +0100254 assert(n == 8 + PREFIX_LEN);
255 assert(bsize == 0
256 || STRNCMP(buf, PREFIX_STR1 "87654321", bsize_int) == 0);
Bram Moolenaard2c946b2019-12-31 19:24:51 +0100257 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
258
259 n = vim_snprintf(buf, bsize, fmt_012p, ptr);
260 assert(n == 12);
Bram Moolenaard5b99142020-02-08 17:14:46 +0100261 assert(bsize == 0
262 || STRNCMP(buf, PREFIX_STR2 "0087654321", bsize_int) == 0);
Bram Moolenaard2c946b2019-12-31 19:24:51 +0100263 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
264
265 free(buf);
266 }
267}
268
Bram Moolenaar502ae4b2016-07-16 19:50:13 +0200269 int
270main(int argc, char **argv)
271{
Bram Moolenaara80faa82020-04-12 19:37:17 +0200272 CLEAR_FIELD(params);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +0200273 params.argc = argc;
274 params.argv = argv;
275 common_init(&params);
Bram Moolenaar502ae4b2016-07-16 19:50:13 +0200276
Bram Moolenaard0337e32019-12-30 17:55:34 +0100277 set_option_value((char_u *)"encoding", 0, (char_u *)"utf-8", 0);
278 init_chartab();
Bram Moolenaar502ae4b2016-07-16 19:50:13 +0200279 test_trunc_string();
Bram Moolenaard2c946b2019-12-31 19:24:51 +0100280 test_vim_snprintf();
Bram Moolenaard0337e32019-12-30 17:55:34 +0100281
282 set_option_value((char_u *)"encoding", 0, (char_u *)"latin1", 0);
283 init_chartab();
284 test_trunc_string();
Bram Moolenaard2c946b2019-12-31 19:24:51 +0100285 test_vim_snprintf();
Bram Moolenaard0337e32019-12-30 17:55:34 +0100286
Bram Moolenaar502ae4b2016-07-16 19:50:13 +0200287 return 0;
288}