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 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 134 test_vim_snprintf(void) 135 { 136 int n; 137 size_t bsize; 138 int bsize_int; 139 void *ptr = (void *)0x87654321; 140 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 178 n = vim_snprintf(buf, bsize, fmt_06b, (uvarnumber_T)12); 179 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. 252 // 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 262 n = vim_snprintf(buf, bsize, "%p", ptr); 263 assert(n == 8 + PREFIX_LEN); 264 assert(bsize == 0 265 || STRNCMP(buf, PREFIX_STR1 "87654321", bsize_int) == 0); 266 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); 267 268 n = vim_snprintf(buf, bsize, fmt_012p, ptr); 269 assert(n == 12); 270 assert(bsize == 0 271 || STRNCMP(buf, PREFIX_STR2 "0087654321", bsize_int) == 0); 272 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); 273 274 free(buf); 275 } 276 } 277 278 int 279 main(int argc, char **argv) 280 { 281 CLEAR_FIELD(params); 282 params.argc = argc; 283 params.argv = argv; 284 common_init(¶ms); 285 286 set_option_value((char_u *)"encoding", 0, (char_u *)"utf-8", 0); 287 init_chartab(); 288 test_trunc_string(); 289 test_vim_snprintf(); 290 291 set_option_value((char_u *)"encoding", 0, (char_u *)"latin1", 0); 292 init_chartab(); 293 test_trunc_string(); 294 test_vim_snprintf(); 295 296 return 0; 297 } 298