Bram Moolenaar | edf3f97 | 2016-08-29 22:49:24 +0200 | [diff] [blame] | 1 | /* vi:set ts=8 sts=4 sw=4 noet: |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 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 | |
Bram Moolenaar | 85a2002 | 2019-12-21 18:25:54 +0100 | [diff] [blame] | 17 | // Must include main.c because it contains much more than just main() |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 18 | #define NO_VIM_MAIN |
| 19 | #include "main.c" |
| 20 | |
Bram Moolenaar | 85a2002 | 2019-12-21 18:25:54 +0100 | [diff] [blame] | 21 | // This file has to be included because some of the tested functions are |
| 22 | // static. |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 23 | #include "message.c" |
| 24 | |
Bram Moolenaar | d2c946b | 2019-12-31 19:24:51 +0100 | [diff] [blame] | 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 | |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 43 | /* |
| 44 | * Test trunc_string(). |
| 45 | */ |
| 46 | static void |
| 47 | test_trunc_string(void) |
| 48 | { |
Bram Moolenaar | b964443 | 2016-07-19 12:33:44 +0200 | [diff] [blame] | 49 | char_u *buf; /*allocated every time to find uninit errors */ |
| 50 | char_u *s; |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 51 | |
Bram Moolenaar | 85a2002 | 2019-12-21 18:25:54 +0100 | [diff] [blame] | 52 | // in place |
Bram Moolenaar | b964443 | 2016-07-19 12:33:44 +0200 | [diff] [blame] | 53 | buf = alloc(40); |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 54 | STRCPY(buf, "text"); |
| 55 | trunc_string(buf, buf, 20, 40); |
| 56 | assert(STRCMP(buf, "text") == 0); |
Bram Moolenaar | b964443 | 2016-07-19 12:33:44 +0200 | [diff] [blame] | 57 | vim_free(buf); |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 58 | |
Bram Moolenaar | b964443 | 2016-07-19 12:33:44 +0200 | [diff] [blame] | 59 | buf = alloc(40); |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 60 | STRCPY(buf, "a short text"); |
| 61 | trunc_string(buf, buf, 20, 40); |
| 62 | assert(STRCMP(buf, "a short text") == 0); |
Bram Moolenaar | b964443 | 2016-07-19 12:33:44 +0200 | [diff] [blame] | 63 | vim_free(buf); |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 64 | |
Bram Moolenaar | b964443 | 2016-07-19 12:33:44 +0200 | [diff] [blame] | 65 | buf = alloc(40); |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 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); |
Bram Moolenaar | b964443 | 2016-07-19 12:33:44 +0200 | [diff] [blame] | 69 | vim_free(buf); |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 70 | |
Bram Moolenaar | b964443 | 2016-07-19 12:33:44 +0200 | [diff] [blame] | 71 | buf = alloc(40); |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 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); |
Bram Moolenaar | b964443 | 2016-07-19 12:33:44 +0200 | [diff] [blame] | 75 | vim_free(buf); |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 76 | |
Bram Moolenaar | 85a2002 | 2019-12-21 18:25:54 +0100 | [diff] [blame] | 77 | // copy from string to buf |
Bram Moolenaar | b964443 | 2016-07-19 12:33:44 +0200 | [diff] [blame] | 78 | buf = alloc(40); |
| 79 | s = vim_strsave((char_u *)"text"); |
| 80 | trunc_string(s, buf, 20, 40); |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 81 | assert(STRCMP(buf, "text") == 0); |
Bram Moolenaar | b964443 | 2016-07-19 12:33:44 +0200 | [diff] [blame] | 82 | vim_free(buf); |
| 83 | vim_free(s); |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 84 | |
Bram Moolenaar | b964443 | 2016-07-19 12:33:44 +0200 | [diff] [blame] | 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); |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 95 | assert(STRCMP(buf, "a short text") == 0); |
Bram Moolenaar | b964443 | 2016-07-19 12:33:44 +0200 | [diff] [blame] | 96 | vim_free(buf); |
| 97 | vim_free(s); |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 98 | |
Bram Moolenaar | b964443 | 2016-07-19 12:33:44 +0200 | [diff] [blame] | 99 | buf = alloc(40); |
| 100 | s = vim_strsave((char_u *)"a text tha just fits"); |
| 101 | trunc_string(s, buf, 20, 40); |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 102 | assert(STRCMP(buf, "a text tha just fits") == 0); |
Bram Moolenaar | b964443 | 2016-07-19 12:33:44 +0200 | [diff] [blame] | 103 | vim_free(buf); |
| 104 | vim_free(s); |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 105 | |
Bram Moolenaar | b964443 | 2016-07-19 12:33:44 +0200 | [diff] [blame] | 106 | buf = alloc(40); |
| 107 | s = vim_strsave((char_u *)"a text that nott fits"); |
| 108 | trunc_string(s, buf, 20, 40); |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 109 | assert(STRCMP(buf, "a text t...nott fits") == 0); |
Bram Moolenaar | b964443 | 2016-07-19 12:33:44 +0200 | [diff] [blame] | 110 | vim_free(buf); |
| 111 | vim_free(s); |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 112 | } |
| 113 | |
Bram Moolenaar | d2c946b | 2019-12-31 19:24:51 +0100 | [diff] [blame] | 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; |
Bram Moolenaar | 4da6df4 | 2020-04-20 16:12:09 +0200 | [diff] [blame] | 130 | void *ptr = (void *)0x87654321; |
Bram Moolenaar | d2c946b | 2019-12-31 19:24:51 +0100 | [diff] [blame] | 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 | |
Bram Moolenaar | 1470dc3 | 2020-01-14 22:02:14 +0100 | [diff] [blame] | 169 | n = vim_snprintf(buf, bsize, fmt_06b, (uvarnumber_T)12); |
Bram Moolenaar | d2c946b | 2019-12-31 19:24:51 +0100 | [diff] [blame] | 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. |
Bram Moolenaar | d5b9914 | 2020-02-08 17:14:46 +0100 | [diff] [blame] | 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 |
Bram Moolenaar | d2c946b | 2019-12-31 19:24:51 +0100 | [diff] [blame] | 253 | n = vim_snprintf(buf, bsize, "%p", ptr); |
Bram Moolenaar | d5b9914 | 2020-02-08 17:14:46 +0100 | [diff] [blame] | 254 | assert(n == 8 + PREFIX_LEN); |
| 255 | assert(bsize == 0 |
| 256 | || STRNCMP(buf, PREFIX_STR1 "87654321", bsize_int) == 0); |
Bram Moolenaar | d2c946b | 2019-12-31 19:24:51 +0100 | [diff] [blame] | 257 | assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); |
| 258 | |
| 259 | n = vim_snprintf(buf, bsize, fmt_012p, ptr); |
| 260 | assert(n == 12); |
Bram Moolenaar | d5b9914 | 2020-02-08 17:14:46 +0100 | [diff] [blame] | 261 | assert(bsize == 0 |
| 262 | || STRNCMP(buf, PREFIX_STR2 "0087654321", bsize_int) == 0); |
Bram Moolenaar | d2c946b | 2019-12-31 19:24:51 +0100 | [diff] [blame] | 263 | assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); |
| 264 | |
| 265 | free(buf); |
| 266 | } |
| 267 | } |
| 268 | |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 269 | int |
| 270 | main(int argc, char **argv) |
| 271 | { |
Bram Moolenaar | a80faa8 | 2020-04-12 19:37:17 +0200 | [diff] [blame] | 272 | CLEAR_FIELD(params); |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 273 | params.argc = argc; |
| 274 | params.argv = argv; |
| 275 | common_init(¶ms); |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 276 | |
Bram Moolenaar | d0337e3 | 2019-12-30 17:55:34 +0100 | [diff] [blame] | 277 | set_option_value((char_u *)"encoding", 0, (char_u *)"utf-8", 0); |
| 278 | init_chartab(); |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 279 | test_trunc_string(); |
Bram Moolenaar | d2c946b | 2019-12-31 19:24:51 +0100 | [diff] [blame] | 280 | test_vim_snprintf(); |
Bram Moolenaar | d0337e3 | 2019-12-30 17:55:34 +0100 | [diff] [blame] | 281 | |
| 282 | set_option_value((char_u *)"encoding", 0, (char_u *)"latin1", 0); |
| 283 | init_chartab(); |
| 284 | test_trunc_string(); |
Bram Moolenaar | d2c946b | 2019-12-31 19:24:51 +0100 | [diff] [blame] | 285 | test_vim_snprintf(); |
Bram Moolenaar | d0337e3 | 2019-12-30 17:55:34 +0100 | [diff] [blame] | 286 | |
Bram Moolenaar | 502ae4b | 2016-07-16 19:50:13 +0200 | [diff] [blame] | 287 | return 0; |
| 288 | } |