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