Mercurial > malikania
changeset 126:a8bddc9566b0
Server: make more comprehensive tests
author | David Demelier <markand@malikania.fr> |
---|---|
date | Fri, 22 Sep 2017 13:03:33 +0200 |
parents | e08378afc8f8 |
children | 991f2af682a0 |
files | libserver-test/CMakeLists.txt libserver-test/malikania/server/db/database_fixture.cpp libserver-test/malikania/server/db/database_fixture.hpp libserver-test/malikania/server/db/test_character.cpp libserver-test/malikania/server/db/test_character.hpp libserver-test/malikania/server/db/test_spell.cpp libserver-test/malikania/server/db/test_spell.hpp libserver/malikania/server/db/account.cpp libserver/malikania/server/db/account.hpp libserver/malikania/server/db/character.cpp libserver/malikania/server/db/character.hpp libserver/malikania/server/db/spell.hpp tests/libserver/db/account/main.cpp |
diffstat | 13 files changed, 289 insertions(+), 145 deletions(-) [+] |
line wrap: on
line diff
--- a/libserver-test/CMakeLists.txt Fri Sep 22 13:42:31 2017 +0200 +++ b/libserver-test/CMakeLists.txt Fri Sep 22 13:03:33 2017 +0200 @@ -22,6 +22,7 @@ HEADERS ${libmlk-server-test_SOURCE_DIR}/malikania/server/db/broken_account.hpp ${libmlk-server-test_SOURCE_DIR}/malikania/server/db/broken_character.hpp + ${libmlk-server-test_SOURCE_DIR}/malikania/server/db/database_fixture.hpp ${libmlk-server-test_SOURCE_DIR}/malikania/server/db/test_account.hpp ${libmlk-server-test_SOURCE_DIR}/malikania/server/db/test_character.hpp ${libmlk-server-test_SOURCE_DIR}/malikania/server/db/test_database.hpp @@ -32,6 +33,7 @@ SOURCES ${libmlk-server-test_SOURCE_DIR}/malikania/server/db/broken_account.cpp ${libmlk-server-test_SOURCE_DIR}/malikania/server/db/broken_character.cpp + ${libmlk-server-test_SOURCE_DIR}/malikania/server/db/database_fixture.cpp ${libmlk-server-test_SOURCE_DIR}/malikania/server/db/test_account.cpp ${libmlk-server-test_SOURCE_DIR}/malikania/server/db/test_character.cpp ${libmlk-server-test_SOURCE_DIR}/malikania/server/db/test_database.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libserver-test/malikania/server/db/database_fixture.cpp Fri Sep 22 13:03:33 2017 +0200 @@ -0,0 +1,30 @@ +/* + * database_fixture.cpp -- helper to test all database backends in a row + * + * Copyright (c) 2013-2017 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 <cstdio> + +#include "database_fixture.hpp" + +namespace mlk { + +namespace server { + + +} // !server + +} // !mlk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libserver-test/malikania/server/db/database_fixture.hpp Fri Sep 22 13:03:33 2017 +0200 @@ -0,0 +1,60 @@ +/* + * database_fixture.hpp -- helper to test all database backends in a row + * + * Copyright (c) 2013-2017 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. + */ + +#ifndef MALIKANIA_SERVER_DATABASE_FIXTURE_HPP +#define MALIKANIA_SERVER_DATABASE_FIXTURE_HPP + +#include <memory> + +#include <boost/mpl/list.hpp> + +#include <malikania/server/db/test_database.hpp> + +namespace mlk { + +namespace server { + +/** + * \brief Create a test database fixture. + */ +class test_fixture { +private: + test_database db_; + +public: + /** + * Access the database object. + */ + inline database& db() noexcept + { + return db_; + } +}; + +/** + * \brief List to use with BOOST_AUTO_TEST_CASE_TEMPLATE + */ +using database_types = boost::mpl::list< + test_fixture +>; + +} // !server + +} // !mlk + +#endif // !MALIKANIA_SERVER_DATABASE_FIXTURE_HPP
--- a/libserver-test/malikania/server/db/test_character.cpp Fri Sep 22 13:42:31 2017 +0200 +++ b/libserver-test/malikania/server/db/test_character.cpp Fri Sep 22 13:03:33 2017 +0200 @@ -63,9 +63,9 @@ level_ = json["level"]; } -character_set test_dao::characters_for_account(std::int64_t account_id) +character_list test_dao::characters_for_account(std::int64_t account_id) { - character_set set; + character_list set; for (const auto& pair : characters_) { if (pair.second["account_id"].get<int>() == account_id) { @@ -76,7 +76,7 @@ ); c->unserialize(pair.second); - set.insert(std::move(c)); + set.push_back(std::move(c)); } }
--- a/libserver-test/malikania/server/db/test_character.hpp Fri Sep 22 13:42:31 2017 +0200 +++ b/libserver-test/malikania/server/db/test_character.hpp Fri Sep 22 13:03:33 2017 +0200 @@ -143,7 +143,7 @@ /** * Get the set of characters for the given account. */ - character_set characters_for_account(std::int64_t account_id); + character_list characters_for_account(std::int64_t account_id); /** * Remove all characters for the specified account.
--- a/libserver-test/malikania/server/db/test_spell.cpp Fri Sep 22 13:42:31 2017 +0200 +++ b/libserver-test/malikania/server/db/test_spell.cpp Fri Sep 22 13:03:33 2017 +0200 @@ -43,20 +43,20 @@ level_ = json["level"]; } -spell_set test_dao::spells_for_charater(std::int64_t character_id) +spell_list test_dao::spells_for_charater(std::int64_t character_id) { - spell_set set; + spell_list list; for (const auto& pair : spells_) { if (pair.second["character_id"].get<int>() == character_id) { auto s = std::make_unique<test_spell>(pair.second["classname"], db_); s->unserialize(pair.second); - set.insert(std::move(s)); + list.push_back(std::move(s)); } } - return set; + return list; } void test_dao::remove_all(std::int64_t character_id)
--- a/libserver-test/malikania/server/db/test_spell.hpp Fri Sep 22 13:42:31 2017 +0200 +++ b/libserver-test/malikania/server/db/test_spell.hpp Fri Sep 22 13:03:33 2017 +0200 @@ -119,7 +119,7 @@ /** * Get the set of spells for the given character. */ - spell_set spells_for_charater(std::int64_t character_id); + spell_list spells_for_charater(std::int64_t character_id); /** * Remove all characters for the specified character.
--- a/libserver/malikania/server/db/account.cpp Fri Sep 22 13:42:31 2017 +0200 +++ b/libserver/malikania/server/db/account.cpp Fri Sep 22 13:03:33 2017 +0200 @@ -27,31 +27,33 @@ * account::add_character * ------------------------------------------------------------------ */ -const std::unique_ptr<character>& account::add_character(std::unique_ptr<character> ch) +std::unique_ptr<character>& account::add_character(std::unique_ptr<character> ch) { assert(is_published()); assert(ch && ch->is_draft()); ch->do_save(id_); + characters_.push_back(std::move(ch)); - return *characters_.insert(std::move(ch)).first; + return characters_.back(); } /* * account::remove_character * ------------------------------------------------------------------ */ -void account::remove_character(const std::unique_ptr<character>& ch) +void account::remove_character(std::unique_ptr<character>& ch) { assert(is_published()); assert(ch && ch->is_published()); - auto it = characters_.find(ch); + auto it = std::find(characters_.begin(), characters_.end(), ch); if (it == characters_.end()) return; ch->do_remove(); + ch = nullptr; characters_.erase(it); }
--- a/libserver/malikania/server/db/account.hpp Fri Sep 22 13:42:31 2017 +0200 +++ b/libserver/malikania/server/db/account.hpp Fri Sep 22 13:03:33 2017 +0200 @@ -24,6 +24,8 @@ * \brief Database account object. */ +#include <algorithm> + #include "model.hpp" #include "character.hpp" @@ -44,7 +46,7 @@ std::string email_; //!< raw email std::string firstname_; //!< optional first name std::string lastname_; //!< optional last name - character_set characters_; //!< set of characters + character_list characters_; //!< list of characters /** * Save the account. @@ -248,7 +250,7 @@ * * \return the associated characters. */ - inline const character_set& characters() const noexcept + inline const character_list& characters() const noexcept { return characters_; } @@ -263,15 +265,37 @@ * \return the attached character * \post ch->is_published() */ - const std::unique_ptr<character>& add_character(std::unique_ptr<character> ch); + std::unique_ptr<character>& add_character(std::unique_ptr<character> ch); + + /** + * Find a character by a predicate. + * + * The predicate must be the same as one use in std::find_if, the unique + * value given as argument is the const std::unique_ptr<character>&. + * + * \param pred the unary predicate + * \return the character or null if not found. + */ + template <typename Predicate> + inline std::unique_ptr<character>& find_character(Predicate&& pred) noexcept + { + static std::unique_ptr<character> none; + + auto it = std::find_if(characters_.begin(), characters_.end(), std::forward<Predicate>(pred)); + + if (it != characters_.end()) + return *it; + + return none; + } /** * Remove the character from the account. * * \param ch the character - * \post ch->is_draft() and empty + * \post ch == nullptr */ - void remove_character(const std::unique_ptr<character>& ch); + void remove_character(std::unique_ptr<character>& ch); /** * Save the account, does nothing if is_published().
--- a/libserver/malikania/server/db/character.cpp Fri Sep 22 13:42:31 2017 +0200 +++ b/libserver/malikania/server/db/character.cpp Fri Sep 22 13:03:33 2017 +0200 @@ -26,31 +26,33 @@ * character::add_spell * ------------------------------------------------------------------ */ -const std::unique_ptr<spell>& character::add_spell(std::unique_ptr<spell> sp) +std::unique_ptr<spell>& character::add_spell(std::unique_ptr<spell> sp) { assert(is_published()); assert(sp && sp->is_draft()); sp->do_save(id_); + spells_.push_back(std::move(sp)); - return *spells_.insert(std::move(sp)).first; + return spells_.back(); } /* * character::remove_spell * ------------------------------------------------------------------ */ -void character::remove_spell(const std::unique_ptr<spell>& sp) +void character::remove_spell(std::unique_ptr<spell>& sp) { assert(is_published()); assert(sp && sp->is_published()); - auto it = spells_.find(sp); + auto it = std::find(spells_.begin(), spells_.end(), sp); if (it == spells_.end()) return; sp->do_remove(); + sp = nullptr; spells_.erase(it); }
--- a/libserver/malikania/server/db/character.hpp Fri Sep 22 13:42:31 2017 +0200 +++ b/libserver/malikania/server/db/character.hpp Fri Sep 22 13:03:33 2017 +0200 @@ -24,6 +24,8 @@ * \brief Database character object. */ +#include <algorithm> + #include "model.hpp" #include "spell.hpp" @@ -43,7 +45,7 @@ std::string nickname_; //!< nickname (non null) std::string classname_; //!< class type to instanciate std::uint16_t level_{1}; //!< character level - spell_set spells_; //!< set of spells + spell_list spells_; //!< list of spells /** * Save this character. @@ -132,7 +134,7 @@ * * \return the spells */ - inline const spell_set& spells() const noexcept + inline const spell_list& spells() const noexcept { return spells_; } @@ -146,15 +148,15 @@ * \param sp the spell * \return the attached spell */ - const std::unique_ptr<spell>& add_spell(std::unique_ptr<spell> sp); + std::unique_ptr<spell>& add_spell(std::unique_ptr<spell> sp); /** * Remove the spell from the character. * * \param sp the spell - * \post sp->is_draft() and empty + * \post sp == nullptr */ - void remove_spell(const std::unique_ptr<spell>& sp); + void remove_spell(std::unique_ptr<spell>& sp); /** * Set the account level. @@ -173,7 +175,7 @@ /** * Type for storing characters. */ -using character_set = std::unordered_set<std::unique_ptr<character>>; +using character_list = std::vector<std::unique_ptr<character>>; } // !server
--- a/libserver/malikania/server/db/spell.hpp Fri Sep 22 13:42:31 2017 +0200 +++ b/libserver/malikania/server/db/spell.hpp Fri Sep 22 13:03:33 2017 +0200 @@ -26,7 +26,7 @@ #include <memory> #include <string> -#include <unordered_set> +#include <vector> #include "model.hpp" @@ -122,7 +122,7 @@ /** * Type for storing spells. */ -using spell_set = std::unordered_set<std::unique_ptr<spell>>; +using spell_list = std::vector<std::unique_ptr<spell>>; } // !server
--- a/tests/libserver/db/account/main.cpp Fri Sep 22 13:42:31 2017 +0200 +++ b/tests/libserver/db/account/main.cpp Fri Sep 22 13:03:33 2017 +0200 @@ -22,6 +22,7 @@ #include <malikania/server/db/test_database.hpp> #include <malikania/server/db/broken_account.hpp> #include <malikania/server/db/broken_character.hpp> +#include <malikania/server/db/database_fixture.hpp> namespace mlk { @@ -61,47 +62,7 @@ * Basic suite using test database. * ------------------------------------------------------------------ */ - -BOOST_FIXTURE_TEST_SUITE(basic_suite, account_fixture) - -/* - * account::save. - * ------------------------------------------------------------------ - * - * Verify that database is untouched during all operation on a draft account. - */ -BOOST_AUTO_TEST_CASE(save) -{ - auto acc = db_->account_draft("nanahara", "dummypassword"); - - // Initial creation must be draft. - BOOST_TEST(acc->is_draft()); - - /* - * Set some fields, the database must not be modified at all but fields - * must be set. - */ - acc->set_email("nanahara@malikania.fr"); - acc->set_firstname("Alexis"); - acc->set_lastname("Dörr"); - - BOOST_TEST(acc->is_draft()); - BOOST_TEST(!acc->is_published()); - BOOST_TEST(acc->email() == "nanahara@malikania.fr"); - BOOST_TEST(acc->firstname() == "Alexis"); - BOOST_TEST(acc->lastname() == "Dörr"); - BOOST_TEST(accounts().size() == 0U); - - // Do save, database must be updated and account published. - acc->save(); - - BOOST_TEST(!acc->is_draft()); - BOOST_TEST(acc->is_published()); - BOOST_TEST(acc->email() == "nanahara@malikania.fr"); - BOOST_TEST(acc->firstname() == "Alexis"); - BOOST_TEST(acc->lastname() == "Dörr"); - BOOST_TEST(accounts().size() == 1U); -} +BOOST_FIXTURE_TEST_SUITE(draft_suite, account_fixture) /* * account::set_password. @@ -112,10 +73,8 @@ auto ac = db_->account_draft("markand", "nopassword"); ac->set_password("temporarypassword"); - ac->save(); - ac->set_password("newpassword"); - BOOST_TEST(get(ac->id())["password"].get<std::string>() == "newpassword"); + BOOST_TEST(accounts().empty()); } /* @@ -127,10 +86,8 @@ auto ac = db_->account_draft("markand", "nopassword"); ac->set_email("fake@malikania.fr"); - ac->save(); - ac->set_email("markand@malikania.fr"); - BOOST_TEST(get(ac->id())["email"].get<std::string>() == "markand@malikania.fr"); + BOOST_TEST(accounts().empty()); } /* @@ -142,10 +99,8 @@ auto ac = db_->account_draft("markand", "nopassword"); ac->set_firstname("Jean"); - ac->save(); - ac->set_firstname("David"); - BOOST_TEST(get(ac->id())["firstname"].get<std::string>() == "David"); + BOOST_TEST(accounts().empty()); } /* @@ -157,74 +112,10 @@ auto ac = db_->account_draft("markand", "nopassword"); ac->set_lastname("Bertrand"); - ac->save(); - ac->set_lastname("Demelier"); - BOOST_TEST(get(ac->id())["lastname"].get<std::string>() == "Demelier"); -} - -/* - * account::add_character. - * ------------------------------------------------------------------ - */ -BOOST_AUTO_TEST_CASE(add_character) -{ - auto ac = db_->account_draft("markand", "nopassword"); - - ac->save(); - - auto& ch = ac->add_character(db_->character_draft("erekin", "fire")); - - BOOST_TEST(ch->is_published()); - BOOST_TEST(characters().size() == 1U); + BOOST_TEST(accounts().empty()); } -/* - * account::dao::find_by_login suite. - * ------------------------------------------------------------------ - */ -BOOST_AUTO_TEST_SUITE(find_by_login) - -/* - * Find existing account. - * ------------------------------------------------------------------ - */ -BOOST_AUTO_TEST_CASE(simple) -{ - { - auto ac = db_->account_draft("markand", "nopassword"); - - ac->set_email("markand@malikania.fr"); - ac->set_firstname("David"); - ac->set_lastname("Demelier"); - ac->save(); - ac->add_character(db_->character_draft("erekin", "mage")); - ac->add_character(db_->character_draft("irina", "fairy")); - } - - auto ac = db_->account_dao().find_by_login("markand"); - - BOOST_TEST(ac->is_published()); - BOOST_TEST(ac->login() == "markand"); - BOOST_TEST(ac->email() == "markand@malikania.fr"); - BOOST_TEST(ac->firstname() == "David"); - BOOST_TEST(ac->lastname() == "Demelier"); - BOOST_TEST(ac->characters().size() == 2U); -} - -/* - * Not existing account. - * ------------------------------------------------------------------ - */ -BOOST_AUTO_TEST_CASE(not_found) -{ - auto ac = db_->account_dao().find_by_login("doesnotexist"); - - BOOST_TEST(!ac); -} - -BOOST_AUTO_TEST_SUITE_END() - BOOST_AUTO_TEST_SUITE_END() /* @@ -352,6 +243,137 @@ BOOST_AUTO_TEST_SUITE_END() +/* + * Generic tests using all backends. + * ------------------------------------------------------------------ + */ +BOOST_AUTO_TEST_SUITE(generic) + +void fill(database& db) +{ + auto ac = db.account_draft("markand", "nopassword"); + + ac->set_email("markand@malikania.fr"); + ac->set_firstname("David"); + ac->set_lastname("Demelier"); + ac->save(); + + { + auto ch = db.character_draft("erekin", "blackmage"); + ch->set_level(75); + ac->add_character(std::move(ch)); + } + + { + auto ch = db.character_draft("luna", "fairy"); + ch->set_level(45); + ac->add_character(std::move(ch)); + } +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(load, Database, database_types) +{ + Database db; + + fill(db.db()); + + auto ac = db.db().account_dao().find_by_login("markand"); + + BOOST_TEST(ac->login() == "markand"); + BOOST_TEST(ac->password() == "nopassword"); + BOOST_TEST(ac->email() == "markand@malikania.fr"); + BOOST_TEST(ac->firstname() == "David"); + BOOST_TEST(ac->lastname() == "Demelier"); + BOOST_TEST(ac->characters().size() == 2U); + + auto& erekin = ac->find_character([] (const auto& c) { + return c->nickname() == "erekin"; + }); + + BOOST_TEST(erekin.get()); + BOOST_TEST(erekin->nickname() == "erekin"); + BOOST_TEST(erekin->classname() == "blackmage"); + BOOST_TEST(erekin->level() == 75U); + + auto& luna = ac->find_character([] (const auto& c) { + return c->nickname() == "luna"; + }); + + BOOST_TEST(luna.get()); + BOOST_TEST(luna->nickname() == "luna"); + BOOST_TEST(luna->classname() == "fairy"); + BOOST_TEST(luna->level() == 45U); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(set_password, Database, database_types) +{ + Database db; + + fill(db.db()); + db.db().account_dao().find_by_login("markand")->set_password("hello"); + + BOOST_TEST(db.db().account_dao().find_by_login("markand")->password() == "hello"); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(set_email, Database, database_types) +{ + Database db; + + fill(db.db()); + db.db().account_dao().find_by_login("markand")->set_email("no@spam.org"); + + BOOST_TEST(db.db().account_dao().find_by_login("markand")->email() == "no@spam.org"); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(set_firstname, Database, database_types) +{ + Database db; + + fill(db.db()); + db.db().account_dao().find_by_login("markand")->set_firstname("Francis"); + + BOOST_TEST(db.db().account_dao().find_by_login("markand")->firstname() == "Francis"); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(set_lastname, Database, database_types) +{ + Database db; + + fill(db.db()); + db.db().account_dao().find_by_login("markand")->set_lastname("Lalanne"); + + BOOST_TEST(db.db().account_dao().find_by_login("markand")->lastname() == "Lalanne"); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(remove_character, Database, database_types) +{ + Database db; + + fill(db.db()); + + { + auto ac = db.db().account_dao().find_by_login("markand"); + + ac->remove_character( + ac->find_character([] (const auto& c) { + return c->nickname() == "luna"; + }) + ); + } + + auto ac = db.db().account_dao().find_by_login("markand"); + + BOOST_TEST(ac->characters().size() == 1U); + + auto& luna = ac->find_character([] (const auto& c) { + return c->nickname() == "luna"; + }); + + BOOST_TEST(!luna.get()); +} + +BOOST_AUTO_TEST_SUITE_END() + } // !server } // !mlk