xref: /vim-8.2.3635/src/message_test.c (revision ceb56ddb)
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
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 
17 // Must include main.c because it contains much more than just main()
18 #define NO_VIM_MAIN
19 #include "main.c"
20 
21 // This file has to be included because some of the tested functions are
22 // static.
23 #include "message.c"
24 
25 #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.
39 char *fmt_012p = "%012p";
40 char *fmt_5S   = "%5S";
41 char *fmt_06b  = "%06b";
42 
43 /*
44  * Test trunc_string().
45  */
46     static void
47 test_trunc_string(void)
48 {
49     char_u  *buf; /*allocated every time to find uninit errors */
50     char_u  *s;
51 
52     // in place
53     buf = alloc(40);
54     STRCPY(buf, "text");
55     trunc_string(buf, buf, 20, 40);
56     assert(STRCMP(buf, "text") == 0);
57     vim_free(buf);
58 
59     buf = alloc(40);
60     STRCPY(buf, "a short text");
61     trunc_string(buf, buf, 20, 40);
62     assert(STRCMP(buf, "a short text") == 0);
63     vim_free(buf);
64 
65     buf = alloc(40);
66     STRCPY(buf, "a text tha just fits");
67     trunc_string(buf, buf, 20, 40);
68     assert(STRCMP(buf, "a text tha just fits") == 0);
69     vim_free(buf);
70 
71     buf = alloc(40);
72     STRCPY(buf, "a text that nott fits");
73     trunc_string(buf, buf, 20, 40);
74     assert(STRCMP(buf, "a text t...nott fits") == 0);
75     vim_free(buf);
76 
77     // copy from string to buf
78     buf = alloc(40);
79     s = vim_strsave((char_u *)"text");
80     trunc_string(s, buf, 20, 40);
81     assert(STRCMP(buf, "text") == 0);
82     vim_free(buf);
83     vim_free(s);
84 
85     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);
95     assert(STRCMP(buf, "a short text") == 0);
96     vim_free(buf);
97     vim_free(s);
98 
99     buf = alloc(40);
100     s = vim_strsave((char_u *)"a text tha just fits");
101     trunc_string(s, buf, 20, 40);
102     assert(STRCMP(buf, "a text tha just fits") == 0);
103     vim_free(buf);
104     vim_free(s);
105 
106     buf = alloc(40);
107     s = vim_strsave((char_u *)"a text that nott fits");
108     trunc_string(s, buf, 20, 40);
109     assert(STRCMP(buf, "a text t...nott fits") == 0);
110     vim_free(buf);
111     vim_free(s);
112 }
113 
114 /*
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
125 test_vim_snprintf(void)
126 {
127     int		n;
128     size_t	bsize;
129     int		bsize_int;
130     void	*ptr = (void *)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, (uvarnumber_T)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 	// 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
253 	n = vim_snprintf(buf, bsize, "%p", ptr);
254 	assert(n == 8 + PREFIX_LEN);
255 	assert(bsize == 0
256 		     || STRNCMP(buf, PREFIX_STR1 "87654321", bsize_int) == 0);
257 	assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
258 
259 	n = vim_snprintf(buf, bsize, fmt_012p, ptr);
260 	assert(n == 12);
261 	assert(bsize == 0
262 		   || STRNCMP(buf, PREFIX_STR2 "0087654321", bsize_int) == 0);
263 	assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
264 
265 	free(buf);
266     }
267 }
268 
269     int
270 main(int argc, char **argv)
271 {
272     CLEAR_FIELD(params);
273     params.argc = argc;
274     params.argv = argv;
275     common_init(&params);
276 
277     set_option_value((char_u *)"encoding", 0, (char_u *)"utf-8", 0);
278     init_chartab();
279     test_trunc_string();
280     test_vim_snprintf();
281 
282     set_option_value((char_u *)"encoding", 0, (char_u *)"latin1", 0);
283     init_chartab();
284     test_trunc_string();
285     test_vim_snprintf();
286 
287     return 0;
288 }
289