Mercurial > paster
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-database.c Wed Feb 12 12:50:00 2020 +0100 @@ -0,0 +1,491 @@ +/* + * test-database.c -- test database functions + * + * Copyright (c) 2020 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdio.h> +#include <unistd.h> + +#define GREATEST_USE_ABBREVS 0 +#include <greatest.h> + +#include "database.h" +#include "paste.h" +#include "util.h" + +#define TEST_DATABASE "test.db" + +static void +setup(void *data) +{ + remove(TEST_DATABASE); + + if (!database_open(TEST_DATABASE)) + die("abort: could not open database"); + + (void)data; +} + +static void +finish(void *data) +{ + database_finish(); + + (void)data; +} + +GREATEST_TEST +recents_empty(void) +{ + struct paste pastes[10]; + size_t max = 10; + + if (!database_recents(pastes, &max)) + GREATEST_FAIL(); + + GREATEST_ASSERT_EQ(max, 0); + GREATEST_PASS(); +} + +GREATEST_TEST +recents_one(void) +{ + struct paste pastes[10]; + size_t max = 10; + struct paste one = { + .title = estrdup("test 1"), + .author = estrdup("unit test"), + .language = estrdup("cpp"), + .code = estrdup("int main() {}"), + .duration = PASTE_HOUR, + .visible = true + }; + + if (!database_insert(&one)) + GREATEST_FAIL(); + if (!database_recents(pastes, &max)) + GREATEST_FAIL(); + + GREATEST_ASSERT_EQ(max, 1); + GREATEST_ASSERT(pastes[0].uuid); + GREATEST_ASSERT_STR_EQ(pastes[0].title, "test 1"); + GREATEST_ASSERT_STR_EQ(pastes[0].author, "unit test"); + GREATEST_ASSERT_STR_EQ(pastes[0].language, "cpp"); + GREATEST_ASSERT_STR_EQ(pastes[0].code, "int main() {}"); + GREATEST_ASSERT_EQ(pastes[0].duration, PASTE_HOUR); + GREATEST_ASSERT(pastes[0].visible); + GREATEST_PASS(); +} + + +GREATEST_TEST +recents_hidden(void) +{ + struct paste pastes[10]; + size_t max = 10; + struct paste one = { + .title = estrdup("test 1"), + .author = estrdup("unit test"), + .language = estrdup("cpp"), + .code = estrdup("int main() {}"), + .duration = PASTE_HOUR, + .visible = false + }; + + if (!database_insert(&one)) + GREATEST_FAIL(); + if (!database_recents(pastes, &max)) + GREATEST_FAIL(); + + GREATEST_ASSERT_EQ(max, 0); + GREATEST_PASS(); +} + +GREATEST_TEST +recents_many(void) +{ + static const int expected[] = { 2, 1, 0 }; + struct paste pastes[3]; + size_t max = 3; + struct paste pastie = { + .duration = PASTE_HOUR, + .visible = true + }; + + for (int i = 0; i < 3; ++i) { + pastie.title = estrdup(bprintf("test %d", i)); + pastie.author = estrdup(bprintf("unit test %d", i)); + pastie.language = estrdup("cpp"); + pastie.code = estrdup(bprintf("int main() { return %d; }", i)); + + if (!database_insert(&pastie)) + GREATEST_FAIL(); + + /* Sleep a little bit to avoid same timestamp. */ + sleep(2); + }; + + if (!database_recents(pastes, &max)) + GREATEST_FAIL(); + + GREATEST_ASSERT_EQ(max, 3U); + + for (int i = 0; i < 3; ++i) { + /* Selected in most recents first. */ + GREATEST_ASSERT(pastes[i].uuid); + GREATEST_ASSERT_STR_EQ(pastes[i].title, + bprintf("test %d", expected[i])); + GREATEST_ASSERT_STR_EQ(pastes[i].author, + bprintf("unit test %d", expected[i])); + GREATEST_ASSERT_STR_EQ(pastes[i].language, "cpp"); + GREATEST_ASSERT_STR_EQ(pastes[i].code, + bprintf("int main() { return %d; }", expected[i])); + GREATEST_ASSERT_EQ(pastes[i].duration, PASTE_HOUR); + GREATEST_ASSERT(pastes[i].visible); + }; + + GREATEST_PASS(); +} + +GREATEST_TEST +recents_limits(void) +{ + static const int expected[] = { 19, 18, 17 }; + struct paste pastes[3]; + size_t max = 3; + struct paste pastie = { + .duration = PASTE_HOUR, + .visible = true + }; + + for (int i = 0; i < 20; ++i) { + pastie.title = estrdup(bprintf("test %d", i)); + pastie.author = estrdup(bprintf("unit test %d", i)); + pastie.language = estrdup("cpp"); + pastie.code = estrdup(bprintf("int main() { return %d; }", i)); + + if (!database_insert(&pastie)) + GREATEST_FAIL(); + + /* Sleep a little bit to avoid same timestamp. */ + sleep(2); + }; + + if (!database_recents(pastes, &max)) + GREATEST_FAIL(); + + GREATEST_ASSERT_EQ(max, 3U); + + for (int i = 0; i < 3; ++i) { + /* Selected in most recents first. */ + GREATEST_ASSERT(pastes[i].uuid); + GREATEST_ASSERT_STR_EQ(pastes[i].title, + bprintf("test %d", expected[i])); + GREATEST_ASSERT_STR_EQ(pastes[i].author, + bprintf("unit test %d", expected[i])); + GREATEST_ASSERT_STR_EQ(pastes[i].language, "cpp"); + GREATEST_ASSERT_STR_EQ(pastes[i].code, + bprintf("int main() { return %d; }", expected[i])); + GREATEST_ASSERT_EQ(pastes[i].duration, PASTE_HOUR); + GREATEST_ASSERT(pastes[i].visible); + }; + + GREATEST_PASS(); +} + +GREATEST_SUITE(recents) +{ + GREATEST_SET_SETUP_CB(setup, NULL); + GREATEST_SET_TEARDOWN_CB(finish, NULL); + GREATEST_RUN_TEST(recents_empty); + GREATEST_RUN_TEST(recents_one); + GREATEST_RUN_TEST(recents_hidden); + GREATEST_RUN_TEST(recents_many); + GREATEST_RUN_TEST(recents_limits); +} + +GREATEST_TEST +get_basic(void) +{ + struct paste original = { + .title = estrdup("test 1"), + .author = estrdup("unit test"), + .language = estrdup("cpp"), + .code = estrdup("int main() {}"), + .duration = PASTE_HOUR, + .visible = false + }; + struct paste new = { 0 }; + + if (!database_insert(&original)) + GREATEST_FAIL(); + if (!database_get(&new, original.uuid)) + GREATEST_FAIL(); + + GREATEST_ASSERT_STR_EQ(new.uuid, original.uuid); + GREATEST_ASSERT_STR_EQ(new.title, original.title); + GREATEST_ASSERT_STR_EQ(new.author, original.author); + GREATEST_ASSERT_STR_EQ(new.language, original.language); + GREATEST_ASSERT_STR_EQ(new.code, original.code); + GREATEST_ASSERT_EQ(new.visible, original.visible); + GREATEST_PASS(); +} + +GREATEST_TEST +get_nonexistent(void) +{ + struct paste new = { 0 }; + + if (!database_get(&new, "unknown")) + GREATEST_FAIL(); + + GREATEST_ASSERT(!new.uuid); + GREATEST_ASSERT(!new.title); + GREATEST_ASSERT(!new.author); + GREATEST_ASSERT(!new.language); + GREATEST_ASSERT(!new.code); + GREATEST_PASS(); +} + +GREATEST_SUITE(get) +{ + GREATEST_SET_SETUP_CB(setup, NULL); + GREATEST_SET_TEARDOWN_CB(finish, NULL); + GREATEST_RUN_TEST(get_basic); + GREATEST_RUN_TEST(get_nonexistent); +} + +GREATEST_TEST +search_basic(void) +{ + struct paste searched[3] = { 0 }; + struct paste originals[] = { + { + .title = estrdup("This is in C"), + .author = estrdup("markand"), + .language = estrdup("cpp"), + .code = estrdup("int main(void) {}"), + .duration = PASTE_HOUR, + .visible = true + }, + { + .title = estrdup("This is in shell"), + .author = estrdup("markand"), + .language = estrdup("shell"), + .code = estrdup("f() {}"), + .duration = PASTE_HOUR, + .visible = true + }, + { + .title = estrdup("This is in python"), + .author = estrdup("NiReaS"), + .language = estrdup("python"), + .code = estrdup("f: pass"), + .duration = PASTE_HOUR, + .visible = true + }, + }; + size_t max = 3; + + for (int i = 0; i < 3; ++i) + if (!database_insert(&originals[i])) + GREATEST_FAIL(); + + /* + * Search: + * + * title = <any> + * author = markand, + * language = cpp + */ + if (!database_search(searched, &max, NULL, "markand", "cpp")) + GREATEST_FAIL(); + + GREATEST_ASSERT_EQ(max, 1); + GREATEST_ASSERT(searched[0].uuid); + GREATEST_ASSERT_STR_EQ(searched[0].title, "This is in C"); + GREATEST_ASSERT_STR_EQ(searched[0].author, "markand"); + GREATEST_ASSERT_STR_EQ(searched[0].language, "cpp"); + GREATEST_ASSERT_STR_EQ(searched[0].code, "int main(void) {}"); + GREATEST_ASSERT_EQ(searched[0].duration, PASTE_HOUR); + GREATEST_ASSERT(searched[0].visible); + GREATEST_PASS(); +} + +GREATEST_TEST +search_notfound(void) +{ + struct paste searched = { 0 }; + struct paste original = { + .title = estrdup("This is in C"), + .author = estrdup("markand"), + .language = estrdup("cpp"), + .code = estrdup("int main(void) {}"), + .duration = PASTE_HOUR, + .visible = true + }; + size_t max = 1; + + if (!database_insert(&original)) + GREATEST_FAIL(); + + /* + * Search: + * + * title = <any> + * author = jean, + * language = <any> + */ + if (!database_search(&searched, &max, NULL, "jean", NULL)) + GREATEST_FAIL(); + + GREATEST_ASSERT_EQ(max, 0); + GREATEST_ASSERT(!searched.uuid); + GREATEST_ASSERT(!searched.title); + GREATEST_ASSERT(!searched.author); + GREATEST_ASSERT(!searched.language); + GREATEST_ASSERT(!searched.code); + GREATEST_PASS(); +} + +GREATEST_TEST +search_private(void) +{ + struct paste searched = { 0 }; + struct paste original = { + .title = estrdup("This is secret"), + .author = estrdup("anonymous"), + .language = estrdup("nohighlight"), + .code = estrdup("I love you, honey"), + .duration = PASTE_HOUR, + .visible = false + }; + size_t max = 1; + + if (!database_insert(&original)) + GREATEST_FAIL(); + + /* + * Search: + * + * title = <any> + * author = <any> + * language = <any> + */ + if (!database_search(&searched, &max, NULL, NULL, NULL)) + GREATEST_FAIL(); + + GREATEST_ASSERT_EQ(max, 0); + GREATEST_ASSERT(!searched.uuid); + GREATEST_ASSERT(!searched.title); + GREATEST_ASSERT(!searched.author); + GREATEST_ASSERT(!searched.language); + GREATEST_ASSERT(!searched.code); + GREATEST_PASS(); +} + +GREATEST_SUITE(search) +{ + GREATEST_SET_SETUP_CB(setup, NULL); + GREATEST_SET_TEARDOWN_CB(finish, NULL); + GREATEST_RUN_TEST(search_basic); + GREATEST_RUN_TEST(search_notfound); + GREATEST_RUN_TEST(search_private); +} + +GREATEST_TEST +clear_run(void) +{ + struct paste searched = { 0 }; + struct paste originals[] = { + /* Will be deleted */ + { + .title = estrdup("This is in C"), + .author = estrdup("markand"), + .language = estrdup("cpp"), + .code = estrdup("int main(void) {}"), + .duration = 1, + .visible = true + }, + /* Will be deleted */ + { + .title = estrdup("This is in shell"), + .author = estrdup("markand"), + .language = estrdup("shell"), + .code = estrdup("f() {}"), + .duration = 1, + .visible = true + }, + /* Will be kept */ + { + .title = estrdup("This is in python"), + .author = estrdup("NiReaS"), + .language = estrdup("python"), + .code = estrdup("f: pass"), + .duration = PASTE_HOUR, + .visible = true + }, + }; + size_t max = 1; + + for (int i = 0; i < 3; ++i) + if (!database_insert(&originals[i])) + GREATEST_FAIL(); + + /* Sleep 2 seconds to exceed the lifetime of C and shell pastes. */ + sleep(2); + database_clear(); + + /* + * Search: + * + * title = <any> + * author = <any> + * language = <any> + */ + if (!database_search(&searched, &max, NULL, NULL, NULL)) + GREATEST_FAIL(); + + GREATEST_ASSERT_EQ(max, 1); + GREATEST_ASSERT(searched.uuid); + GREATEST_ASSERT_STR_EQ(searched.title, "This is in python"); + GREATEST_ASSERT_STR_EQ(searched.author, "NiReaS"); + GREATEST_ASSERT_STR_EQ(searched.language, "python"); + GREATEST_ASSERT_STR_EQ(searched.code, "f: pass"); + GREATEST_ASSERT_EQ(searched.duration, PASTE_HOUR); + GREATEST_ASSERT(searched.visible); + GREATEST_PASS(); +} + +GREATEST_SUITE(clear) +{ + GREATEST_SET_SETUP_CB(setup, NULL); + GREATEST_SET_TEARDOWN_CB(finish, NULL); + GREATEST_RUN_TEST(clear_run); +} + +GREATEST_MAIN_DEFS(); + +int +main(int argc, char **argv) +{ + GREATEST_MAIN_BEGIN(); + GREATEST_RUN_SUITE(recents); + GREATEST_RUN_SUITE(get); + GREATEST_RUN_SUITE(search); + GREATEST_RUN_SUITE(clear); + GREATEST_MAIN_END(); +}