comparison tests/test-database.c @ 34:030efbd7340f

tests: create unit tests, closes #1696 @2h
author David Demelier <markand@malikania.fr>
date Wed, 12 Feb 2020 12:50:00 +0100
parents
children 48834441dc86
comparison
equal deleted inserted replaced
33:511e2e865e15 34:030efbd7340f
1 /*
2 * test-database.c -- test database functions
3 *
4 * Copyright (c) 2020 David Demelier <markand@malikania.fr>
5 *
6 * Permission to use, copy, modify, and/or distribute this software 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 * THE SOFTWARE IS 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
19 #include <stdio.h>
20 #include <unistd.h>
21
22 #define GREATEST_USE_ABBREVS 0
23 #include <greatest.h>
24
25 #include "database.h"
26 #include "paste.h"
27 #include "util.h"
28
29 #define TEST_DATABASE "test.db"
30
31 static void
32 setup(void *data)
33 {
34 remove(TEST_DATABASE);
35
36 if (!database_open(TEST_DATABASE))
37 die("abort: could not open database");
38
39 (void)data;
40 }
41
42 static void
43 finish(void *data)
44 {
45 database_finish();
46
47 (void)data;
48 }
49
50 GREATEST_TEST
51 recents_empty(void)
52 {
53 struct paste pastes[10];
54 size_t max = 10;
55
56 if (!database_recents(pastes, &max))
57 GREATEST_FAIL();
58
59 GREATEST_ASSERT_EQ(max, 0);
60 GREATEST_PASS();
61 }
62
63 GREATEST_TEST
64 recents_one(void)
65 {
66 struct paste pastes[10];
67 size_t max = 10;
68 struct paste one = {
69 .title = estrdup("test 1"),
70 .author = estrdup("unit test"),
71 .language = estrdup("cpp"),
72 .code = estrdup("int main() {}"),
73 .duration = PASTE_HOUR,
74 .visible = true
75 };
76
77 if (!database_insert(&one))
78 GREATEST_FAIL();
79 if (!database_recents(pastes, &max))
80 GREATEST_FAIL();
81
82 GREATEST_ASSERT_EQ(max, 1);
83 GREATEST_ASSERT(pastes[0].uuid);
84 GREATEST_ASSERT_STR_EQ(pastes[0].title, "test 1");
85 GREATEST_ASSERT_STR_EQ(pastes[0].author, "unit test");
86 GREATEST_ASSERT_STR_EQ(pastes[0].language, "cpp");
87 GREATEST_ASSERT_STR_EQ(pastes[0].code, "int main() {}");
88 GREATEST_ASSERT_EQ(pastes[0].duration, PASTE_HOUR);
89 GREATEST_ASSERT(pastes[0].visible);
90 GREATEST_PASS();
91 }
92
93
94 GREATEST_TEST
95 recents_hidden(void)
96 {
97 struct paste pastes[10];
98 size_t max = 10;
99 struct paste one = {
100 .title = estrdup("test 1"),
101 .author = estrdup("unit test"),
102 .language = estrdup("cpp"),
103 .code = estrdup("int main() {}"),
104 .duration = PASTE_HOUR,
105 .visible = false
106 };
107
108 if (!database_insert(&one))
109 GREATEST_FAIL();
110 if (!database_recents(pastes, &max))
111 GREATEST_FAIL();
112
113 GREATEST_ASSERT_EQ(max, 0);
114 GREATEST_PASS();
115 }
116
117 GREATEST_TEST
118 recents_many(void)
119 {
120 static const int expected[] = { 2, 1, 0 };
121 struct paste pastes[3];
122 size_t max = 3;
123 struct paste pastie = {
124 .duration = PASTE_HOUR,
125 .visible = true
126 };
127
128 for (int i = 0; i < 3; ++i) {
129 pastie.title = estrdup(bprintf("test %d", i));
130 pastie.author = estrdup(bprintf("unit test %d", i));
131 pastie.language = estrdup("cpp");
132 pastie.code = estrdup(bprintf("int main() { return %d; }", i));
133
134 if (!database_insert(&pastie))
135 GREATEST_FAIL();
136
137 /* Sleep a little bit to avoid same timestamp. */
138 sleep(2);
139 };
140
141 if (!database_recents(pastes, &max))
142 GREATEST_FAIL();
143
144 GREATEST_ASSERT_EQ(max, 3U);
145
146 for (int i = 0; i < 3; ++i) {
147 /* Selected in most recents first. */
148 GREATEST_ASSERT(pastes[i].uuid);
149 GREATEST_ASSERT_STR_EQ(pastes[i].title,
150 bprintf("test %d", expected[i]));
151 GREATEST_ASSERT_STR_EQ(pastes[i].author,
152 bprintf("unit test %d", expected[i]));
153 GREATEST_ASSERT_STR_EQ(pastes[i].language, "cpp");
154 GREATEST_ASSERT_STR_EQ(pastes[i].code,
155 bprintf("int main() { return %d; }", expected[i]));
156 GREATEST_ASSERT_EQ(pastes[i].duration, PASTE_HOUR);
157 GREATEST_ASSERT(pastes[i].visible);
158 };
159
160 GREATEST_PASS();
161 }
162
163 GREATEST_TEST
164 recents_limits(void)
165 {
166 static const int expected[] = { 19, 18, 17 };
167 struct paste pastes[3];
168 size_t max = 3;
169 struct paste pastie = {
170 .duration = PASTE_HOUR,
171 .visible = true
172 };
173
174 for (int i = 0; i < 20; ++i) {
175 pastie.title = estrdup(bprintf("test %d", i));
176 pastie.author = estrdup(bprintf("unit test %d", i));
177 pastie.language = estrdup("cpp");
178 pastie.code = estrdup(bprintf("int main() { return %d; }", i));
179
180 if (!database_insert(&pastie))
181 GREATEST_FAIL();
182
183 /* Sleep a little bit to avoid same timestamp. */
184 sleep(2);
185 };
186
187 if (!database_recents(pastes, &max))
188 GREATEST_FAIL();
189
190 GREATEST_ASSERT_EQ(max, 3U);
191
192 for (int i = 0; i < 3; ++i) {
193 /* Selected in most recents first. */
194 GREATEST_ASSERT(pastes[i].uuid);
195 GREATEST_ASSERT_STR_EQ(pastes[i].title,
196 bprintf("test %d", expected[i]));
197 GREATEST_ASSERT_STR_EQ(pastes[i].author,
198 bprintf("unit test %d", expected[i]));
199 GREATEST_ASSERT_STR_EQ(pastes[i].language, "cpp");
200 GREATEST_ASSERT_STR_EQ(pastes[i].code,
201 bprintf("int main() { return %d; }", expected[i]));
202 GREATEST_ASSERT_EQ(pastes[i].duration, PASTE_HOUR);
203 GREATEST_ASSERT(pastes[i].visible);
204 };
205
206 GREATEST_PASS();
207 }
208
209 GREATEST_SUITE(recents)
210 {
211 GREATEST_SET_SETUP_CB(setup, NULL);
212 GREATEST_SET_TEARDOWN_CB(finish, NULL);
213 GREATEST_RUN_TEST(recents_empty);
214 GREATEST_RUN_TEST(recents_one);
215 GREATEST_RUN_TEST(recents_hidden);
216 GREATEST_RUN_TEST(recents_many);
217 GREATEST_RUN_TEST(recents_limits);
218 }
219
220 GREATEST_TEST
221 get_basic(void)
222 {
223 struct paste original = {
224 .title = estrdup("test 1"),
225 .author = estrdup("unit test"),
226 .language = estrdup("cpp"),
227 .code = estrdup("int main() {}"),
228 .duration = PASTE_HOUR,
229 .visible = false
230 };
231 struct paste new = { 0 };
232
233 if (!database_insert(&original))
234 GREATEST_FAIL();
235 if (!database_get(&new, original.uuid))
236 GREATEST_FAIL();
237
238 GREATEST_ASSERT_STR_EQ(new.uuid, original.uuid);
239 GREATEST_ASSERT_STR_EQ(new.title, original.title);
240 GREATEST_ASSERT_STR_EQ(new.author, original.author);
241 GREATEST_ASSERT_STR_EQ(new.language, original.language);
242 GREATEST_ASSERT_STR_EQ(new.code, original.code);
243 GREATEST_ASSERT_EQ(new.visible, original.visible);
244 GREATEST_PASS();
245 }
246
247 GREATEST_TEST
248 get_nonexistent(void)
249 {
250 struct paste new = { 0 };
251
252 if (!database_get(&new, "unknown"))
253 GREATEST_FAIL();
254
255 GREATEST_ASSERT(!new.uuid);
256 GREATEST_ASSERT(!new.title);
257 GREATEST_ASSERT(!new.author);
258 GREATEST_ASSERT(!new.language);
259 GREATEST_ASSERT(!new.code);
260 GREATEST_PASS();
261 }
262
263 GREATEST_SUITE(get)
264 {
265 GREATEST_SET_SETUP_CB(setup, NULL);
266 GREATEST_SET_TEARDOWN_CB(finish, NULL);
267 GREATEST_RUN_TEST(get_basic);
268 GREATEST_RUN_TEST(get_nonexistent);
269 }
270
271 GREATEST_TEST
272 search_basic(void)
273 {
274 struct paste searched[3] = { 0 };
275 struct paste originals[] = {
276 {
277 .title = estrdup("This is in C"),
278 .author = estrdup("markand"),
279 .language = estrdup("cpp"),
280 .code = estrdup("int main(void) {}"),
281 .duration = PASTE_HOUR,
282 .visible = true
283 },
284 {
285 .title = estrdup("This is in shell"),
286 .author = estrdup("markand"),
287 .language = estrdup("shell"),
288 .code = estrdup("f() {}"),
289 .duration = PASTE_HOUR,
290 .visible = true
291 },
292 {
293 .title = estrdup("This is in python"),
294 .author = estrdup("NiReaS"),
295 .language = estrdup("python"),
296 .code = estrdup("f: pass"),
297 .duration = PASTE_HOUR,
298 .visible = true
299 },
300 };
301 size_t max = 3;
302
303 for (int i = 0; i < 3; ++i)
304 if (!database_insert(&originals[i]))
305 GREATEST_FAIL();
306
307 /*
308 * Search:
309 *
310 * title = <any>
311 * author = markand,
312 * language = cpp
313 */
314 if (!database_search(searched, &max, NULL, "markand", "cpp"))
315 GREATEST_FAIL();
316
317 GREATEST_ASSERT_EQ(max, 1);
318 GREATEST_ASSERT(searched[0].uuid);
319 GREATEST_ASSERT_STR_EQ(searched[0].title, "This is in C");
320 GREATEST_ASSERT_STR_EQ(searched[0].author, "markand");
321 GREATEST_ASSERT_STR_EQ(searched[0].language, "cpp");
322 GREATEST_ASSERT_STR_EQ(searched[0].code, "int main(void) {}");
323 GREATEST_ASSERT_EQ(searched[0].duration, PASTE_HOUR);
324 GREATEST_ASSERT(searched[0].visible);
325 GREATEST_PASS();
326 }
327
328 GREATEST_TEST
329 search_notfound(void)
330 {
331 struct paste searched = { 0 };
332 struct paste original = {
333 .title = estrdup("This is in C"),
334 .author = estrdup("markand"),
335 .language = estrdup("cpp"),
336 .code = estrdup("int main(void) {}"),
337 .duration = PASTE_HOUR,
338 .visible = true
339 };
340 size_t max = 1;
341
342 if (!database_insert(&original))
343 GREATEST_FAIL();
344
345 /*
346 * Search:
347 *
348 * title = <any>
349 * author = jean,
350 * language = <any>
351 */
352 if (!database_search(&searched, &max, NULL, "jean", NULL))
353 GREATEST_FAIL();
354
355 GREATEST_ASSERT_EQ(max, 0);
356 GREATEST_ASSERT(!searched.uuid);
357 GREATEST_ASSERT(!searched.title);
358 GREATEST_ASSERT(!searched.author);
359 GREATEST_ASSERT(!searched.language);
360 GREATEST_ASSERT(!searched.code);
361 GREATEST_PASS();
362 }
363
364 GREATEST_TEST
365 search_private(void)
366 {
367 struct paste searched = { 0 };
368 struct paste original = {
369 .title = estrdup("This is secret"),
370 .author = estrdup("anonymous"),
371 .language = estrdup("nohighlight"),
372 .code = estrdup("I love you, honey"),
373 .duration = PASTE_HOUR,
374 .visible = false
375 };
376 size_t max = 1;
377
378 if (!database_insert(&original))
379 GREATEST_FAIL();
380
381 /*
382 * Search:
383 *
384 * title = <any>
385 * author = <any>
386 * language = <any>
387 */
388 if (!database_search(&searched, &max, NULL, NULL, NULL))
389 GREATEST_FAIL();
390
391 GREATEST_ASSERT_EQ(max, 0);
392 GREATEST_ASSERT(!searched.uuid);
393 GREATEST_ASSERT(!searched.title);
394 GREATEST_ASSERT(!searched.author);
395 GREATEST_ASSERT(!searched.language);
396 GREATEST_ASSERT(!searched.code);
397 GREATEST_PASS();
398 }
399
400 GREATEST_SUITE(search)
401 {
402 GREATEST_SET_SETUP_CB(setup, NULL);
403 GREATEST_SET_TEARDOWN_CB(finish, NULL);
404 GREATEST_RUN_TEST(search_basic);
405 GREATEST_RUN_TEST(search_notfound);
406 GREATEST_RUN_TEST(search_private);
407 }
408
409 GREATEST_TEST
410 clear_run(void)
411 {
412 struct paste searched = { 0 };
413 struct paste originals[] = {
414 /* Will be deleted */
415 {
416 .title = estrdup("This is in C"),
417 .author = estrdup("markand"),
418 .language = estrdup("cpp"),
419 .code = estrdup("int main(void) {}"),
420 .duration = 1,
421 .visible = true
422 },
423 /* Will be deleted */
424 {
425 .title = estrdup("This is in shell"),
426 .author = estrdup("markand"),
427 .language = estrdup("shell"),
428 .code = estrdup("f() {}"),
429 .duration = 1,
430 .visible = true
431 },
432 /* Will be kept */
433 {
434 .title = estrdup("This is in python"),
435 .author = estrdup("NiReaS"),
436 .language = estrdup("python"),
437 .code = estrdup("f: pass"),
438 .duration = PASTE_HOUR,
439 .visible = true
440 },
441 };
442 size_t max = 1;
443
444 for (int i = 0; i < 3; ++i)
445 if (!database_insert(&originals[i]))
446 GREATEST_FAIL();
447
448 /* Sleep 2 seconds to exceed the lifetime of C and shell pastes. */
449 sleep(2);
450 database_clear();
451
452 /*
453 * Search:
454 *
455 * title = <any>
456 * author = <any>
457 * language = <any>
458 */
459 if (!database_search(&searched, &max, NULL, NULL, NULL))
460 GREATEST_FAIL();
461
462 GREATEST_ASSERT_EQ(max, 1);
463 GREATEST_ASSERT(searched.uuid);
464 GREATEST_ASSERT_STR_EQ(searched.title, "This is in python");
465 GREATEST_ASSERT_STR_EQ(searched.author, "NiReaS");
466 GREATEST_ASSERT_STR_EQ(searched.language, "python");
467 GREATEST_ASSERT_STR_EQ(searched.code, "f: pass");
468 GREATEST_ASSERT_EQ(searched.duration, PASTE_HOUR);
469 GREATEST_ASSERT(searched.visible);
470 GREATEST_PASS();
471 }
472
473 GREATEST_SUITE(clear)
474 {
475 GREATEST_SET_SETUP_CB(setup, NULL);
476 GREATEST_SET_TEARDOWN_CB(finish, NULL);
477 GREATEST_RUN_TEST(clear_run);
478 }
479
480 GREATEST_MAIN_DEFS();
481
482 int
483 main(int argc, char **argv)
484 {
485 GREATEST_MAIN_BEGIN();
486 GREATEST_RUN_SUITE(recents);
487 GREATEST_RUN_SUITE(get);
488 GREATEST_RUN_SUITE(search);
489 GREATEST_RUN_SUITE(clear);
490 GREATEST_MAIN_END();
491 }