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 // 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 61 // in place 62 buf = alloc(40); 63 STRCPY(buf, "text"); 64 trunc_string(buf, buf, 20, 40); 65 assert(STRCMP(buf, "text") == 0); 66 vim_free(buf); 67 68 buf = alloc(40); 69 STRCPY(buf, "a short text"); 70 trunc_string(buf, buf, 20, 40); 71 assert(STRCMP(buf, "a short text") == 0); 72 vim_free(buf); 73 74 buf = alloc(40); 75 STRCPY(buf, "a text tha just fits"); 76 trunc_string(buf, buf, 20, 40); 77 assert(STRCMP(buf, "a text tha just fits") == 0); 78 vim_free(buf); 79 80 buf = alloc(40); 81 STRCPY(buf, "a text that nott fits"); 82 trunc_string(buf, buf, 20, 40); 83 assert(STRCMP(buf, "a text t...nott fits") == 0); 84 vim_free(buf); 85 86 // copy from string to buf 87 buf = alloc(40); 88 s = vim_strsave((char_u *)"text"); 89 trunc_string(s, buf, 20, 40); 90 assert(STRCMP(buf, "text") == 0); 91 vim_free(buf); 92 vim_free(s); 93 94 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); 104 assert(STRCMP(buf, "a short text") == 0); 105 vim_free(buf); 106 vim_free(s); 107 108 buf = alloc(40); 109 s = vim_strsave((char_u *)"a text tha just fits"); 110 trunc_string(s, buf, 20, 40); 111 assert(STRCMP(buf, "a text tha just fits") == 0); 112 vim_free(buf); 113 vim_free(s); 114 115 buf = alloc(40); 116 s = vim_strsave((char_u *)"a text that nott fits"); 117 trunc_string(s, buf, 20, 40); 118 assert(STRCMP(buf, "a text t...nott fits") == 0); 119 vim_free(buf); 120 vim_free(s); 121 } 122 123 /* 124 * Test trunc_string() with mbyte chars. 125 */ 126 static void 127 test_trunc_string_mbyte(void) 128 { 129 char_u *buf; // allocated every time to find uninit errors 130 char_u *s; 131 132 buf = alloc(40); 133 s = vim_strsave((char_u *)"Ä text tha just fits"); 134 trunc_string(s, buf, 20, 40); 135 assert(STRCMP(buf, "Ä text tha just fits") == 0); 136 vim_free(buf); 137 vim_free(s); 138 139 buf = alloc(40); 140 s = vim_strsave((char_u *)"a text ÄÖÜä nott fits"); 141 trunc_string(s, buf, 20, 40); 142 assert(STRCMP(buf, "a text Ä...nott fits") == 0); 143 vim_free(buf); 144 vim_free(s); 145 146 buf = alloc(40); 147 s = vim_strsave((char_u *)"a text that not fitsÄ"); 148 trunc_string(s, buf, 20, 40); 149 assert(STRCMP(buf, "a text t...not fitsÄ") == 0); 150 vim_free(buf); 151 vim_free(s); 152 } 153 154 /* 155 * Test vim_snprintf() with a focus on checking that truncation is 156 * correct when buffer is small, since it cannot be tested from 157 * vim scrip tests. Check that: 158 * - no buffer overflows happens (with valgrind or asan) 159 * - output string is always NUL terminated. 160 * 161 * Not all formats of vim_snprintf() are checked here. They are 162 * checked more exhaustively in Test_printf*() vim script tests. 163 */ 164 static void 165 test_vim_snprintf(void) 166 { 167 int n; 168 size_t bsize; 169 int bsize_int; 170 void *ptr = (void *)0x87654321; 171 172 // Loop on various buffer sizes to make sure that truncation of 173 // vim_snprintf() is correct. 174 for (bsize = 0; bsize < 15; ++bsize) 175 { 176 bsize_int = (int)bsize - 1; 177 178 // buf is the heap rather than in the stack 179 // so valgrind can detect buffer overflows if any. 180 // Use malloc() rather than alloc() as test checks with 0-size 181 // buffer and its content should then never be used. 182 char *buf = malloc(bsize); 183 184 n = vim_snprintf(buf, bsize, "%d", 1234567); 185 assert(n == 7); 186 assert(bsize == 0 || STRNCMP(buf, "1234567", bsize_int) == 0); 187 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); 188 189 n = vim_snprintf(buf, bsize, "%ld", 1234567L); 190 assert(n == 7); 191 assert(bsize == 0 || STRNCMP(buf, "1234567", bsize_int) == 0); 192 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); 193 194 n = vim_snprintf(buf, bsize, "%9ld", 1234567L); 195 assert(n == 9); 196 assert(bsize == 0 || STRNCMP(buf, " 1234567", bsize_int) == 0); 197 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); 198 199 n = vim_snprintf(buf, bsize, "%-9ld", 1234567L); 200 assert(n == 9); 201 assert(bsize == 0 || STRNCMP(buf, "1234567 ", bsize_int) == 0); 202 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); 203 204 n = vim_snprintf(buf, bsize, "%x", 0xdeadbeef); 205 assert(n == 8); 206 assert(bsize == 0 || STRNCMP(buf, "deadbeef", bsize_int) == 0); 207 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); 208 209 n = vim_snprintf(buf, bsize, fmt_06b, (uvarnumber_T)12); 210 assert(n == 6); 211 assert(bsize == 0 || STRNCMP(buf, "001100", bsize_int) == 0); 212 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); 213 214 #ifdef FEAT_FLOAT 215 n = vim_snprintf(buf, bsize, "%f", 1.234); 216 assert(n == 8); 217 assert(bsize == 0 || STRNCMP(buf, "1.234000", bsize_int) == 0); 218 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); 219 220 n = vim_snprintf(buf, bsize, "%e", 1.234); 221 assert(n == 12); 222 assert(bsize == 0 || STRNCMP(buf, "1.234000e+00", bsize_int) == 0); 223 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); 224 225 n = vim_snprintf(buf, bsize, "%f", 0.0/0.0); 226 assert(n == 3); 227 assert(bsize == 0 || STRNCMP(buf, "nan", bsize_int) == 0); 228 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); 229 230 n = vim_snprintf(buf, bsize, "%f", 1.0/0.0); 231 assert(n == 3); 232 assert(bsize == 0 || STRNCMP(buf, "inf", bsize_int) == 0); 233 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); 234 235 n = vim_snprintf(buf, bsize, "%f", -1.0/0.0); 236 assert(n == 4); 237 assert(bsize == 0 || STRNCMP(buf, "-inf", bsize_int) == 0); 238 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); 239 240 n = vim_snprintf(buf, bsize, "%f", -0.0); 241 assert(n == 9); 242 assert(bsize == 0 || STRNCMP(buf, "-0.000000", bsize_int) == 0); 243 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); 244 #endif 245 246 n = vim_snprintf(buf, bsize, "%s", "漢語"); 247 assert(n == 6); 248 assert(bsize == 0 || STRNCMP(buf, "漢語", bsize_int) == 0); 249 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); 250 251 n = vim_snprintf(buf, bsize, "%8s", "漢語"); 252 assert(n == 8); 253 assert(bsize == 0 || STRNCMP(buf, " 漢語", bsize_int) == 0); 254 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); 255 256 n = vim_snprintf(buf, bsize, "%-8s", "漢語"); 257 assert(n == 8); 258 assert(bsize == 0 || STRNCMP(buf, "漢語 ", bsize_int) == 0); 259 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); 260 261 n = vim_snprintf(buf, bsize, "%.3s", "漢語"); 262 assert(n == 3); 263 assert(bsize == 0 || STRNCMP(buf, "漢", bsize_int) == 0); 264 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); 265 266 n = vim_snprintf(buf, bsize, fmt_5S, "foo"); 267 assert(n == 5); 268 assert(bsize == 0 || STRNCMP(buf, " foo", bsize_int) == 0); 269 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); 270 271 n = vim_snprintf(buf, bsize, "%%%%%%"); 272 assert(n == 3); 273 assert(bsize == 0 || STRNCMP(buf, "%%%", bsize_int) == 0); 274 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); 275 276 n = vim_snprintf(buf, bsize, "%c%c", 1, 2); 277 assert(n == 2); 278 assert(bsize == 0 || STRNCMP(buf, "\x01\x02", bsize_int) == 0); 279 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); 280 281 // %p format is not tested in vim script tests Test_printf*() 282 // as it only makes sense in C code. 283 // NOTE: SunOS libc doesn't use the prefix "0x" on %p. 284 #ifdef SUN_SYSTEM 285 # define PREFIX_LEN 0 286 # define PREFIX_STR1 "" 287 # define PREFIX_STR2 "00" 288 #else 289 # define PREFIX_LEN 2 290 # define PREFIX_STR1 "0x" 291 # define PREFIX_STR2 "0x" 292 #endif 293 n = vim_snprintf(buf, bsize, "%p", ptr); 294 assert(n == 8 + PREFIX_LEN); 295 assert(bsize == 0 296 || STRNCMP(buf, PREFIX_STR1 "87654321", bsize_int) == 0); 297 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); 298 299 n = vim_snprintf(buf, bsize, fmt_012p, ptr); 300 assert(n == 12); 301 assert(bsize == 0 302 || STRNCMP(buf, PREFIX_STR2 "0087654321", bsize_int) == 0); 303 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); 304 305 free(buf); 306 } 307 } 308 309 int 310 main(int argc, char **argv) 311 { 312 CLEAR_FIELD(params); 313 params.argc = argc; 314 params.argv = argv; 315 common_init(¶ms); 316 317 set_option_value((char_u *)"encoding", 0, (char_u *)"utf-8", 0); 318 init_chartab(); 319 test_trunc_string(); 320 test_trunc_string_mbyte(); 321 test_vim_snprintf(); 322 323 set_option_value((char_u *)"encoding", 0, (char_u *)"latin1", 0); 324 init_chartab(); 325 test_trunc_string(); 326 test_vim_snprintf(); 327 328 return 0; 329 } 330