1 /* 2 * Copyright (c) 2016 Bastian Maerkisch <bmaerkisch@web.de> 3 * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute these tests for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THESE TESTS ARE PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 #include <err.h> 18 #include <stdarg.h> 19 #include <stdio.h> 20 #include <string.h> 21 22 #ifdef READLINE 23 #include <readline/history.h> 24 #else 25 #include <readline/readline.h> 26 #endif 27 28 29 /* 30 * Test infrastructure function. 31 * At the beginning of each test, call as "msg(__func__);". 32 * Upon failure, call as "msg(fmt, ...);". 33 * At the end of each test, call as "return msg(NULL);". 34 */ 35 int 36 msg(const char *fmt, ...) 37 { 38 static const char *testname = NULL; 39 static int failed = 0; 40 va_list ap; 41 42 if (testname == NULL) { 43 using_history(); 44 unstifle_history(); 45 testname = fmt; 46 return 0; 47 } 48 49 if (fmt == NULL) { 50 clear_history(); 51 unstifle_history(); 52 testname = NULL; 53 if (failed == 0) 54 return 0; 55 failed = 0; 56 return 1; 57 } 58 59 fprintf(stderr, "%s: ", testname); 60 va_start(ap, fmt); 61 vfprintf(stderr, fmt, ap); 62 va_end(ap); 63 fputc('\n', stderr); 64 failed = 1; 65 return 1; 66 } 67 68 void 69 check_current(const char *descr, const char *want) 70 { 71 HIST_ENTRY *he; 72 73 he = current_history(); 74 75 if (want == NULL) { 76 if (he != NULL) 77 msg("Failed to move beyond the newest entry."); 78 return; 79 } 80 81 if (he == NULL) 82 msg("%s is NULL.", descr); 83 else if (strcmp(he->line, want) != 0) 84 msg("%s is \"%s\" instead of \"%s\".", descr, he->line, want); 85 } 86 87 void 88 check_get(int idx, const char *want) 89 { 90 HIST_ENTRY *he; 91 92 if ((he = history_get(history_base + idx)) == NULL) 93 msg("Get %d+%d returned NULL.", history_base, idx); 94 else if (he->line == NULL) 95 msg("Get %d+%d returned line == NULL.", history_base, idx); 96 else if (strcmp(he->line, want) != 0) 97 msg("Get %d+%d returned \"%s\" instead of \"%s\".", 98 history_base, idx, he->line, want); 99 } 100 101 102 /* Fails if previous and next are interchanged. */ 103 int 104 test_movement_direction(void) 105 { 106 msg(__func__); 107 add_history("111"); 108 add_history("222"); 109 110 while (previous_history() != NULL); 111 check_current("Oldest entry", "111"); 112 113 /* 114 * Move to the most recent end of the history. 115 * This moves past the newest entry. 116 */ 117 while (next_history() != NULL); 118 check_current(NULL, NULL); 119 120 return msg(NULL); 121 } 122 123 124 /* Fails if the position is counted from the recent end. */ 125 int 126 test_where(void) 127 { 128 int ret; 129 130 msg(__func__); 131 132 /* 133 * Adding four elements since set_pos(0) doesn't work 134 * for some versions of libedit. 135 */ 136 add_history("111"); 137 add_history("222"); 138 add_history("333"); 139 add_history("444"); 140 141 /* Set the pointer to the element "222". */ 142 history_set_pos(1); 143 if ((ret = where_history()) != 1) 144 msg("Where returned %d instead of 1.", ret); 145 146 return msg(NULL); 147 } 148 149 150 /* 151 * Fails if the argument of history_get() 152 * does not refer to the zero-based index + history_base. 153 */ 154 int 155 test_get(void) 156 { 157 msg(__func__); 158 add_history("111"); 159 add_history("222"); 160 add_history("333"); 161 add_history("444"); 162 163 /* Try to retrieve second element. */ 164 check_get(1, "222"); 165 166 return msg(NULL); 167 } 168 169 170 /* Fails if set_pos returns 0 for success and -1 for failure. */ 171 int 172 test_set_pos_return_values(void) 173 { 174 int ret; 175 176 msg(__func__); 177 add_history("111"); 178 add_history("222"); 179 180 /* This should fail. */ 181 if ((ret = history_set_pos(-1)) != 0) 182 msg("Set_pos(-1) returned %d instead of 0.", ret); 183 184 /* 185 * This should succeed. 186 * Note that we do not use the index 0 here, since that 187 * actually fails for some versions of libedit. 188 */ 189 if ((ret = history_set_pos(1)) != 1) 190 msg("Set_pos(1) returned %d instead of 1.", ret); 191 192 return msg(NULL); 193 } 194 195 196 /* Fails if the index is one-based. */ 197 int 198 test_set_pos_index(void) 199 { 200 msg(__func__); 201 add_history("111"); 202 add_history("222"); 203 204 /* Do not test return value here since that might be broken, too. */ 205 history_set_pos(0); 206 check_current("Entry 0", "111"); 207 208 history_set_pos(1); 209 check_current("Entry 1", "222"); 210 211 return msg(NULL); 212 } 213 214 215 /* Fails if remove does not renumber. */ 216 int 217 test_remove(void) 218 { 219 msg(__func__); 220 add_history("111"); 221 add_history("222"); 222 add_history("333"); 223 add_history("444"); 224 225 /* Remove the second item "222"; the index is zero-based. */ 226 remove_history(1); 227 228 /* 229 * Try to get the new second element using history_get. 230 * The argument of get is based on history_base. 231 */ 232 check_get(1, "333"); 233 234 /* 235 * Try to get the second element using set_pos/current. 236 * The index is zero-based. 237 */ 238 history_set_pos(1); 239 check_current("Entry 1", "333"); 240 241 /* Remove the new second item "333". */ 242 remove_history(1); 243 check_get(1, "444"); 244 245 return msg(NULL); 246 } 247 248 249 /* Fails if stifle doesn't discard existing entries. */ 250 int 251 test_stifle_size(void) 252 { 253 msg(__func__); 254 add_history("111"); 255 add_history("222"); 256 add_history("333"); 257 258 /* Reduce the size of the history. */ 259 stifle_history(2); 260 if (history_length != 2) 261 msg("Length is %d instead of 2.", history_length); 262 263 return msg(NULL); 264 } 265 266 267 /* Fails if add doesn't increase history_base if the history is full. */ 268 int 269 test_stifle_base(void) 270 { 271 msg(__func__); 272 stifle_history(2); 273 274 /* Add one more than the maximum size. */ 275 add_history("111"); 276 add_history("222"); 277 add_history("333"); 278 279 /* The history_base should have changed. */ 280 if (history_base != 2) 281 msg("Base is %d instead of 2.", history_base); 282 283 return msg(NULL); 284 } 285 286 287 int 288 main(void) 289 { 290 int fail = 0; 291 292 fail += test_movement_direction(); 293 fail += test_where(); 294 fail += test_get(); 295 fail += test_set_pos_return_values(); 296 fail += test_set_pos_index(); 297 fail += test_remove(); 298 fail += test_stifle_size(); 299 fail += test_stifle_base(); 300 301 if (fail) 302 errx(1, "%d test(s) failed.", fail); 303 return 0; 304 } 305