1 /*
2 test.c UNIT tests main for HSTR shell history completion utility
3
4 Copyright (C) 2014-2020 Martin Dvorak <martin.dvorak@mindforger.com>
5
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17 */
18
19 #define HSTR_TESTS_UNIT 1
20
21 #include <string.h>
22 #include <regex.h>
23 #include <stdio.h>
24 #include <stdbool.h>
25 #include <getopt.h>
26
27 // HSTR uses Unity C test framework: https://github.com/ThrowTheSwitch/Unity
28 #include "unity/src/c/unity.h"
29
30 #include "../../src/include/hashset.h"
31 #include "../../src/include/hstr_utils.h"
32 #include "../../src/include/hstr_history.h"
33 #include "../../src/include/hstr_favorites.h"
34 #include "../../src/include/hstr.h"
35
36 /*
37 * IMPORTANT: make sure to run TEST RUNNER GENERATOR script after any change to this file!
38 *
39 */
40
setUp(void)41 void setUp(void)
42 {
43 }
44
tearDown(void)45 void tearDown(void)
46 {
47 }
48
test_args(void)49 void test_args(void)
50 {
51 const unsigned LINELNG = 500;
52 int argc = 3;
53 char* argv[argc];
54 argv[0] = "hstr";
55 argv[1] = "-o";
56 argv[2] = "_args";
57
58 if(argc>0) {
59 int i;
60 char line[LINELNG];
61 line[0]=0;
62 for(i=0; i<argc; i++) {
63 if((strlen(line)+strlen(argv[i])*2) > LINELNG) break;
64 printf("%d %s\n", i, argv[i]);
65 if(strstr(argv[i], " ")) {
66 strcat(line, "\"");
67 }
68 strcat(line, argv[i]);
69 if(strstr(argv[i], " ")) {
70 strcat(line, "\"");
71 }
72 strcat(line, " ");
73 }
74
75 printf("#%s#\n", line);
76 TEST_ASSERT_EQUAL_STRING("hstr -o _args ", line);
77 } else {
78 TEST_FAIL_MESSAGE("There must be an argument");
79 }
80 }
81
test_getopt(void)82 void test_getopt(void)
83 {
84 int argc = 3;
85 char* argv[argc];
86 argv[0] = "hstr";
87 argv[1] = "--create";
88 argv[2] = "_getopt";
89
90 int c;
91 int digit_optind = 0;
92
93 while (1) {
94 int this_option_optind = optind ? optind : 1;
95 int option_index = 0;
96 static struct option long_options[] = {
97 {"add", required_argument, 0, 0 },
98 {"append", no_argument, 0, 0 },
99 {"delete", required_argument, 0, 0 },
100 {"verbose", no_argument, 0, 0 },
101 {"create", required_argument, 0, 'c'},
102 {"file", required_argument, 0, 0 },
103 {0, 0, 0, 0 }
104 };
105
106 c = getopt_long(argc, argv, "abc:d:012", long_options, &option_index);
107 if (c == -1)
108 break;
109
110
111 switch (c) {
112 case 0:
113 printf("option %s", long_options[option_index].name);
114 if (optarg)
115 printf(" with arg %s", optarg);
116 printf("\n");
117 break;
118
119 case '0':
120 case '1':
121 case '2':
122 if (digit_optind != 0 && digit_optind != this_option_optind)
123 printf("digits occur in two different argv-elements.\n");
124 digit_optind = this_option_optind;
125 printf("option %c\n", c);
126 break;
127
128 case 'a':
129 printf("option a\n");
130 break;
131
132 case 'b':
133 printf("option b\n");
134 break;
135
136 case 'c':
137 printf("option c with value '%s'\n", optarg);
138 break;
139
140 case 'd':
141 printf("option d with value '%s'\n", optarg);
142 break;
143
144 case '?':
145
146 break;
147
148 default:
149 printf("?? getopt returned character code 0%o ??\n", c);
150 }
151
152 TEST_ASSERT_EQUAL('c', c);
153 }
154
155 if(optind < argc) {
156 printf("non-option ARGV-elements: ");
157 while (optind < argc) {
158 printf("%s ", argv[optind++]);
159 }
160 printf("\n");
161 TEST_FAIL_MESSAGE("Thist unit test is supposed to succeed with 'c' option");
162 }
163 }
164
test_locate_char_in_string_overflow(void)165 void test_locate_char_in_string_overflow(void)
166 {
167 TEST_ASSERT_EQUAL_STRING(0, strchr("a\nb",1));
168
169 printf("%s\n",strchr("a\nb",98));
170 TEST_ASSERT_EQUAL_STRING("b", strchr("a\nb",98));
171
172 printf("%s\n",strchr("a\nb",10));
173 TEST_ASSERT_EQUAL_STRING("\nb", strchr("a\nb",10));
174 }
175
test_favorites(void)176 void test_favorites(void)
177 {
178 FavoriteItems favoriteItems;
179
180 favorites_init(&favoriteItems);
181 favorites_get(&favoriteItems);
182
183 char* favorite = "UNIT-TEST-ENTRY";
184 unsigned count = favoriteItems.count;
185
186 TEST_ASSERT_EQUAL(count, favoriteItems.count);
187 favorites_add(&favoriteItems, favorite);
188 TEST_ASSERT_EQUAL(count+1, favoriteItems.count);
189
190 favorites_choose(&favoriteItems, favorite);
191 TEST_ASSERT_EQUAL_STRING(favorite, favoriteItems.items[0]);
192
193 favorites_remove(&favoriteItems, favorite);
194 TEST_ASSERT_EQUAL(count, favoriteItems.count);
195
196 favorites_choose(&favoriteItems, favorite);
197 TEST_ASSERT_NOT_EQUAL(favorite, favoriteItems.items[0]);
198 }
199
test_hashset_blacklist()200 void test_hashset_blacklist()
201 {
202 const char* commandBlacklist[] = { "a","b","c","d","e" };
203 HashSet blacklist;
204 int i;
205 hashset_init(&blacklist);
206 for (i = 0; i < 5; i++) {
207 TEST_ASSERT_TRUE(hashset_add(&blacklist, commandBlacklist[i]));
208 }
209 for (i = 0; i < 5; i++) {
210 printf("match %d\n", hashset_contains(&blacklist, hstr_strdup(commandBlacklist[i])));
211 TEST_ASSERT_TRUE(hashset_contains(&blacklist, hstr_strdup(commandBlacklist[i])));
212 }
213 }
214
test_hashset_get_keys()215 void test_hashset_get_keys()
216 {
217 const char* commandBlacklist[] = { "a","b","c","d","e" };
218 HashSet blacklist;
219 int i;
220 hashset_init(&blacklist);
221 for (i = 0; i < 5; i++) {
222 TEST_ASSERT_TRUE(hashset_add(&blacklist, commandBlacklist[i]));
223 }
224
225 char **keys=hashset_keys(&blacklist);
226 if(keys) {
227 for(i=0; i<hashset_size(&blacklist); i++) {
228 printf("Key: %s\n", keys[i]);
229 TEST_ASSERT_NOT_EQUAL(NULL, keys[i]);
230 }
231 } else {
232 TEST_FAIL_MESSAGE("Inserted keys are missing in hashset");
233 }
234 }
235
test_regexp(void)236 void test_regexp(void)
237 {
238 unsigned REGEXP_MATCH_BUFFER_SIZE = 10;
239
240 bool caseSensitive=false;
241
242 char *regexp="^b";
243 char *text="This is a command that I want to match: go.sh there";
244
245 regex_t precompiled;
246 int compilationFlags=(caseSensitive?0:REG_ICASE);
247 printf("Regular expressions matching:\n '%s'\n '%s'",text,regexp);
248 int compilationStatus=regcomp(&precompiled, regexp, compilationFlags);
249 printf("\nCompilation: %d",compilationStatus);
250 TEST_ASSERT_FALSE(compilationStatus);
251
252 int matches=REGEXP_MATCH_BUFFER_SIZE;
253 regmatch_t matchPtr[REGEXP_MATCH_BUFFER_SIZE];
254 int matchingFlags=0;
255 int matchingStatus=regexec(&precompiled, text, matches, matchPtr, matchingFlags);
256 printf("\nMatching (status/matches): %s %d",(!matchingStatus?"match":"no-match"), matches);
257 TEST_ASSERT_EQUAL(10, matches);
258
259 if(!matchingStatus) {
260 unsigned i;
261 for(i=0; i<REGEXP_MATCH_BUFFER_SIZE; i++) {
262 printf("\n %d %d",matchPtr[i].rm_so, matchPtr[i].rm_eo);
263 if(matchPtr[i].rm_so != -1) {
264 printf("\n* %d %d",matchPtr[i].rm_so,matchPtr[i].rm_eo);
265 }
266 }
267 } else {
268 char message[100];
269 regerror(matchingStatus, &precompiled, message, 100);
270 printf("\nRegexp failed with %s\n", message);
271 }
272
273 printf("\n");
274 }
275
test_help_long(void)276 void test_help_long(void)
277 {
278 TEST_IGNORE_MESSAGE("Tests exits the program");
279
280 char* ARG_HSTR = "hstr";
281 char* ARG_HELP = "--help";
282 int argc = 1+1;
283 char* argv[argc];
284 argv[0] = ARG_HSTR;
285 argv[1] = ARG_HELP;
286 int s;
287
288 s = hstr_main(argc, argv);
289 TEST_ASSERT_FALSE(s);
290 }
291
test_help_short(void)292 void test_help_short(void)
293 {
294 TEST_IGNORE_MESSAGE("Tests exits the program");
295
296 char* ARG_HSTR = "hstr";
297 char* ARG_H = "-h";
298 int argc = 1+1;
299 char* argv[argc];
300 argv[0] = ARG_HSTR;
301 argv[1] = ARG_H;
302 int s;
303
304 s = hstr_main(argc, argv);
305 TEST_ASSERT_FALSE(s);
306 }
307
test_string_elide()308 void test_string_elide()
309 {
310 char buffer[1000];
311
312 // do nothing - string fits to screen
313 hstr_strelide(buffer, "0123456789", 20);
314 printf("%s\n", buffer);
315 TEST_ASSERT_EQUAL_STRING("0123456789", buffer);
316
317 // do nothing - string too short
318 hstr_strelide(buffer, "012", 1);
319 printf("%s\n", buffer);
320 TEST_ASSERT_EQUAL_STRING("012", buffer);
321
322 hstr_strelide(buffer, "0123456789", 6);
323 printf("%s\n", buffer);
324 TEST_ASSERT_EQUAL_STRING("01...9", buffer);
325
326
327 hstr_strelide(buffer, "0123456789", 10);
328 TEST_ASSERT_EQUAL_STRING("0123456789", buffer);
329 printf("%s\n", buffer);
330
331 hstr_strelide(buffer, "0123456789", 9);
332 TEST_ASSERT_EQUAL_STRING("012...789", buffer);
333 printf("%s\n", buffer);
334
335 hstr_strelide(buffer, "0123456789", 8);
336 TEST_ASSERT_EQUAL_STRING("012...89", buffer);
337 printf("%s\n", buffer);
338 }
339
test_parse_history_line()340 void test_parse_history_line()
341 {
342 TEST_ASSERT_EQUAL(NULL, parse_history_line(NULL));
343
344 TEST_ASSERT_EQUAL_STRING("ls", parse_history_line("ls"));
345 TEST_ASSERT_EQUAL_STRING(":::", parse_history_line(":::"));
346
347 TEST_ASSERT_EQUAL_STRING(":vspman epoll_ctl", parse_history_line(": 1592444398:0;:vspman epoll_ctl"));
348 TEST_ASSERT_EQUAL_STRING("scan-view work/scans/2020-07-30-114451-3063582-1", parse_history_line(": 1596135828:6109;scan-view work/scans/2020-07-30-114451-3063582-1"));
349 TEST_ASSERT_EQUAL_STRING(":wq", parse_history_line(": 1592444398:0;:wq"));
350 TEST_ASSERT_EQUAL_STRING(":wq", parse_history_line(":wq"));
351
352 TEST_ASSERT_EQUAL_STRING(": 159244439:0;:wq", parse_history_line(": 159244439:0;:wq"));
353 TEST_ASSERT_EQUAL_STRING(": 1592444398:;:wq", parse_history_line(": 1592444398:;:wq"));
354 TEST_ASSERT_EQUAL_STRING(": 1592444398:0:wq", parse_history_line(": 1592444398:0:wq"));
355 TEST_ASSERT_EQUAL_STRING(":1592444398:0;:vspman epoll_ctl", parse_history_line(":1592444398:0;:vspman epoll_ctl"));
356 }
357