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 char *ptr = (char *)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, 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 n = vim_snprintf(buf, bsize, "%p", ptr); 244 assert(n == 10); 245 assert(bsize == 0 || STRNCMP(buf, "0x87654321", bsize_int) == 0); 246 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); 247 248 n = vim_snprintf(buf, bsize, fmt_012p, ptr); 249 assert(n == 12); 250 assert(bsize == 0 || STRNCMP(buf, "0x0087654321", bsize_int) == 0); 251 assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); 252 253 free(buf); 254 } 255 } 256 257 int 258 main(int argc, char **argv) 259 { 260 vim_memset(¶ms, 0, sizeof(params)); 261 params.argc = argc; 262 params.argv = argv; 263 common_init(¶ms); 264 265 set_option_value((char_u *)"encoding", 0, (char_u *)"utf-8", 0); 266 init_chartab(); 267 test_trunc_string(); 268 test_vim_snprintf(); 269 270 set_option_value((char_u *)"encoding", 0, (char_u *)"latin1", 0); 271 init_chartab(); 272 test_trunc_string(); 273 test_vim_snprintf(); 274 275 return 0; 276 } 277