diff options
author | Huynh Tran <nthuynh75@gmail.com> | 2005-06-30 20:46:57 +0000 |
---|---|---|
committer | Huynh Tran <nthuynh75@gmail.com> | 2005-06-30 20:46:57 +0000 |
commit | 38cfcdd2b7681fc32b1464a4905c721246cf6d75 (patch) | |
tree | a4c6aca110f71fe221e66cdf57d4c5b66a8501a4 | |
parent | a5aee1322f498537f8de83123099bbfcb2e3a969 (diff) | |
download | manaserv-38cfcdd2b7681fc32b1464a4905c721246cf6d75.tar.gz manaserv-38cfcdd2b7681fc32b1464a4905c721246cf6d75.tar.bz2 manaserv-38cfcdd2b7681fc32b1464a4905c721246cf6d75.tar.xz manaserv-38cfcdd2b7681fc32b1464a4905c721246cf6d75.zip |
Fixed memory leak, implemented delAccount() + unit tests and now using reference-counted smart pointers to facilitate the memory management.
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/account.cpp | 19 | ||||
-rw-r--r-- | src/account.h | 8 | ||||
-rw-r--r-- | src/being.h | 9 | ||||
-rw-r--r-- | src/dal/mysqldataprovider.cpp | 5 | ||||
-rw-r--r-- | src/dalstorage.cpp | 88 | ||||
-rw-r--r-- | src/dalstorage.h | 17 | ||||
-rw-r--r-- | src/storage.h | 10 | ||||
-rw-r--r-- | src/tests/testaccount.cpp | 55 | ||||
-rw-r--r-- | src/tests/testcipher.cpp | 30 | ||||
-rw-r--r-- | src/tests/testdataprovider.cpp | 17 | ||||
-rw-r--r-- | src/tests/testrecordset.cpp | 45 | ||||
-rw-r--r-- | src/tests/testsmain.cpp | 5 | ||||
-rw-r--r-- | src/tests/teststorage.cpp | 509 | ||||
-rw-r--r-- | src/tests/teststorage.h | 65 | ||||
-rw-r--r-- | src/utils/countedptr.h | 163 |
16 files changed, 696 insertions, 350 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index f15ee464..56003d26 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -45,6 +45,7 @@ tmwserv_SOURCES = main.cpp \ dal/dataproviderfactory.cpp \ dal/recordset.h \ dal/recordset.cpp \ + utils/countedptr.h \ utils/functors.h \ utils/singleton.h \ utils/cipher.h \ diff --git a/src/account.cpp b/src/account.cpp index 97b723a0..c44af2d9 100644 --- a/src/account.cpp +++ b/src/account.cpp @@ -70,15 +70,8 @@ Account::Account(const std::string& name, Account::~Account(void) throw() { - for (Beings::iterator it = mCharacters.begin(); - it != mCharacters.end(); - ++it) - { - if (*it != 0) { - delete (*it); - *it = 0; - } - } + // mCharacters is a list of smart pointers which will take care about + // deallocating the memory so nothing to deallocate here :) } @@ -177,9 +170,9 @@ Account::setCharacters(const Beings& characters) * Add a new character. */ void -Account::addCharacter(Being* character) +Account::addCharacter(BeingPtr character) { - if (character) { + if (character.get() != 0) { mCharacters.push_back(character); } } @@ -204,11 +197,11 @@ Account::getCharacter(const std::string& name) Beings::iterator it = std::find_if(mCharacters.begin(), mCharacters.end(), - std::bind2nd(obj_name_is<Being*>(), name) + std::bind2nd(obj_name_is<BeingPtr>(), name) ); if (it != mCharacters.end()) { - return (*it); + return (*it).get(); } return 0; diff --git a/src/account.h b/src/account.h index 0291b780..7e1322cc 100644 --- a/src/account.h +++ b/src/account.h @@ -174,7 +174,7 @@ class Account * @param character the new character. */ void - addCharacter(Being* character); + addCharacter(BeingPtr character); /** @@ -225,6 +225,12 @@ class Account }; +/** + * Type definition for a smart pointer to Account. + */ +typedef utils::CountedPtr<Account> AccountPtr; + + } // namespace tmwserv diff --git a/src/being.h b/src/being.h index 577ec31e..2ebbd8cf 100644 --- a/src/being.h +++ b/src/being.h @@ -30,6 +30,7 @@ #include "defines.h" #include "object.h" +#include "utils/countedptr.h" namespace tmwserv @@ -285,9 +286,15 @@ class Being: public Object /** + * Type definition for a smart pointer to Being. + */ +typedef utils::CountedPtr<Being> BeingPtr; + + +/** * Type definition for a list of Beings. */ -typedef std::vector<Being*> Beings; +typedef std::vector<BeingPtr> Beings; } // namespace tmwserv diff --git a/src/dal/mysqldataprovider.cpp b/src/dal/mysqldataprovider.cpp index 1813fddd..ca01577f 100644 --- a/src/dal/mysqldataprovider.cpp +++ b/src/dal/mysqldataprovider.cpp @@ -104,7 +104,10 @@ MySqlDataProvider::connect(const std::string& dbName, NULL, // use defaut socket 0)) // client flags { - throw DbConnectionFailure(mysql_error(mDb)); + std::string msg(mysql_error(mDb)); + mysql_close(mDb); + + throw DbConnectionFailure(msg); } mIsConnected = true; diff --git a/src/dalstorage.cpp b/src/dalstorage.cpp index 1970ed75..ca47c3f5 100644 --- a/src/dalstorage.cpp +++ b/src/dalstorage.cpp @@ -57,26 +57,8 @@ DALStorage::~DALStorage() close(); } - // clean up accounts. - for (Accounts::iterator it = mAccounts.begin(); - it != mAccounts.end(); - ++it) - { - if (it->first != 0) { - delete it->first; - } - } - - // clean up characters. - for (Beings::iterator it = mCharacters.begin(); - it != mCharacters.end(); - ++it) - { - if (*it != 0) { - delete (*it); - *it = 0; - } - } + // mAccounts and mCharacters contain smart pointers that will deallocate + // the memory so nothing else to do here :) } @@ -179,7 +161,7 @@ DALStorage::getAccount(const std::string& userName) ); if (it != mAccounts.end()) { - return it->first; + return (it->first).get(); } using namespace dal; @@ -201,9 +183,9 @@ DALStorage::getAccount(const std::string& userName) // create an Account instance // and initialize it with information about the user. - Account* account = new Account(accountInfo(0, 1), + AccountPtr account(new Account(accountInfo(0, 1), accountInfo(0, 2), - accountInfo(0, 3)); + accountInfo(0, 3))); // specialize the string_to functor to convert // a string to an unsigned int. @@ -247,11 +229,11 @@ DALStorage::getAccount(const std::string& userName) Genders gender; switch (value) { - case 0: + case GENDER_MALE: gender = GENDER_MALE; break; - case 1: + case GENDER_FEMALE: gender = GENDER_FEMALE; break; @@ -260,13 +242,13 @@ DALStorage::getAccount(const std::string& userName) break; }; - Being* being = + BeingPtr being( new Being(charInfo(i, 2), // name gender, // gender toUshort(charInfo(i, 4)), // level toUint(charInfo(i, 5)), // money stats - ); + )); mCharacters.push_back(being); beings.push_back(being); @@ -275,7 +257,7 @@ DALStorage::getAccount(const std::string& userName) account->setCharacters(beings); } - return account; + return account.get(); } catch (const DbSqlQueryExecFailure& e) { return NULL; // TODO: Throw exception here @@ -287,9 +269,9 @@ DALStorage::getAccount(const std::string& userName) * Add a new account. */ void -DALStorage::addAccount(const Account* account) +DALStorage::addAccount(const AccountPtr& account) { - if (account == 0) { + if (account.get() == 0) { // maybe we should throw an exception instead return; } @@ -301,7 +283,7 @@ DALStorage::addAccount(const Account* account) // the account id is set to 0 because we know nothing about it at the // moment, it will be updated once saved into the database. ai.id = 0; - mAccounts.insert(std::make_pair(const_cast<Account*>(account), ai)); + mAccounts.insert(std::make_pair(account, ai)); } @@ -325,12 +307,7 @@ DALStorage::delAccount(const std::string& userName) { // this is a newly added account and it has not even been // saved into the database: remove it immediately. - - // TODO: delete the associated characters. - - delete it->first; - - // TODO: remove from the map. + mAccounts.erase(it); } break; @@ -356,6 +333,7 @@ DALStorage::delAccount(const std::string& userName) } catch (const dal::DbSqlQueryExecFailure& e) { // TODO: throw an exception. + LOG_ERROR("SQL query failure: " << e.what()) } } @@ -366,9 +344,9 @@ DALStorage::delAccount(const std::string& userName) void DALStorage::flush(void) { - Accounts::const_iterator it = mAccounts.begin(); - Accounts::const_iterator it_end = mAccounts.end(); - for (; it != it_end; ++it) { + Accounts::iterator it = mAccounts.begin(); + Accounts::iterator it_end = mAccounts.end(); + for (; it != it_end; ) { switch ((it->second).status) { case AS_NEW_ACCOUNT: _addAccount(it->first); @@ -379,13 +357,15 @@ DALStorage::flush(void) break; case AS_ACC_TO_DELETE: - // TODO: accounts to be deleted must be handled differently - // as mAccounts will be altered once the accounts are deleted. + _delAccount(it->first); + mAccounts.erase(it); break; default: break; } + + ++it; } } @@ -429,9 +409,9 @@ DALStorage::createTable(const std::string& tblName, * Add an account to the database. */ void -DALStorage::_addAccount(const Account* account) +DALStorage::_addAccount(const AccountPtr& account) { - if (account == 0) { + if (account.get() == 0) { return; } @@ -471,7 +451,7 @@ DALStorage::_addAccount(const Account* account) (account_it->second).id = toUint(accountInfo(0, 0)); // insert the characters. - Beings& characters = (const_cast<Account*>(account))->getCharacters(); + Beings& characters = account->getCharacters(); Beings::const_iterator it = characters.begin(); Beings::const_iterator it_end = characters.end(); @@ -505,9 +485,9 @@ DALStorage::_addAccount(const Account* account) * Update an account from the database. */ void -DALStorage::_updAccount(const Account* account) +DALStorage::_updAccount(const AccountPtr& account) { - if (account == 0) { + if (account.get() == 0) { return; } @@ -543,7 +523,7 @@ DALStorage::_updAccount(const Account* account) mDb->execSql(sql1.str()); // get the list of characters that belong to this account. - Beings& characters = (const_cast<Account*>(account))->getCharacters(); + Beings& characters = account->getCharacters(); // insert or update the characters. Beings::const_iterator it = characters.begin(); @@ -611,6 +591,18 @@ DALStorage::_updAccount(const Account* account) * Delete an account and its associated data from the database. */ void +DALStorage::_delAccount(const AccountPtr& account) +{ + if (account.get() != 0) { + _delAccount(account->getName()); + } +} + + +/** + * Delete an account and its associated data from the database. + */ +void DALStorage::_delAccount(const std::string& userName) { using namespace dal; diff --git a/src/dalstorage.h b/src/dalstorage.h index 80408f6c..637dfa39 100644 --- a/src/dalstorage.h +++ b/src/dalstorage.h @@ -81,7 +81,7 @@ class DALStorage: public Storage * @param account the new account. */ void - addAccount(const Account* account); + addAccount(const AccountPtr& account); /** @@ -150,7 +150,7 @@ class DALStorage: public Storage * @exeception tmwserv::dal::DbSqlQueryExecFailure. */ void - _addAccount(const Account* account); + _addAccount(const AccountPtr& account); /** @@ -161,7 +161,18 @@ class DALStorage: public Storage * @exception tmwserv::dal::DbSqlQueryExecFailure. */ void - _updAccount(const Account* account); + _updAccount(const AccountPtr& account); + + + /** + * Delete an account and its associated data from the database. + * + * @param account the account to update. + * + * @exception tmwserv::dal::DbSqlQueryExecFailure. + */ + void + _delAccount(const AccountPtr& account); /** diff --git a/src/storage.h b/src/storage.h index 6b8fdc44..3adf1b2f 100644 --- a/src/storage.h +++ b/src/storage.h @@ -73,10 +73,10 @@ typedef struct { * Functor to be used as the sorting criterion of the map defined below. */ struct account_sort_by_name - : public std::binary_function<Account*, Account*, bool> + : public std::binary_function<AccountPtr, AccountPtr, bool> { bool - operator()(Account* acc1, Account* acc2) const + operator()(const AccountPtr& acc1, const AccountPtr& acc2) const { return (acc1->getName() < acc2->getName()); } @@ -91,7 +91,7 @@ struct account_sort_by_name * only the storage should modify this value, this attribute is for * internal use. */ -typedef std::map<Account*, AccountInfo, account_sort_by_name> Accounts; +typedef std::map<AccountPtr, AccountInfo, account_sort_by_name> Accounts; /** @@ -114,7 +114,7 @@ class account_by_name * Operator(). */ bool - operator()(std::pair<Account*, AccountInfo> elem) const + operator()(std::pair<AccountPtr, AccountInfo> elem) const { return (elem.first)->getName() == mName; } @@ -268,7 +268,7 @@ class Storage * @param account the new account. */ virtual void - addAccount(const Account* account) = 0; + addAccount(const AccountPtr& account) = 0; /** diff --git a/src/tests/testaccount.cpp b/src/tests/testaccount.cpp index 814aaa29..d30c8a78 100644 --- a/src/tests/testaccount.cpp +++ b/src/tests/testaccount.cpp @@ -21,6 +21,7 @@ */ +#include "../utils/logger.h" #include "testaccount.h" @@ -37,18 +38,11 @@ using namespace tmwserv; void AccountTest::setUp(void) { - //RawStatistics stats; - //stats.strength = 1; - //stats.agility = 1; - //stats.vitality = 1; - //stats.intelligence = 1; - //stats.dexterity = 1; - //stats.luck = 1; const RawStatistics stats = {1, 1, 1, 1, 1, 1}; - Being* sam = new Being("sam", GENDER_MALE, 0, 0, stats); - Being* merry = new Being("merry", GENDER_MALE, 0, 0, stats); - Being* pippin = new Being("pippin", GENDER_MALE, 0, 0, stats); + BeingPtr sam(new Being("sam", GENDER_MALE, 0, 0, stats)); + BeingPtr merry(new Being("merry", GENDER_MALE, 0, 0, stats)); + BeingPtr pippin(new Being("pippin", GENDER_MALE, 0, 0, stats)); mCharacters.push_back(sam); mCharacters.push_back(merry); mCharacters.push_back(pippin); @@ -66,13 +60,6 @@ AccountTest::setUp(void) void AccountTest::tearDown(void) { - for (Beings::iterator it = mCharacters.begin(); - it != mCharacters.end(); - ++it) - { - delete (*it); - } - delete mAccount; mAccount = 0; } @@ -85,6 +72,8 @@ AccountTest::tearDown(void) void AccountTest::testCreate1(void) { + LOG("AccountTest::testCreate1()"); + const std::string name("frodo"); const std::string password("baggins"); const std::string email("frodo@theshire.com"); @@ -105,6 +94,8 @@ AccountTest::testCreate1(void) void AccountTest::testCreate2(void) { + LOG("AccountTest::testCreate2()"); + const std::string name("frodo"); const std::string password("baggins"); const std::string email("frodo@theshire.com"); @@ -118,7 +109,7 @@ AccountTest::testCreate2(void) CPPUNIT_ASSERT_EQUAL(mCharacters.size(), mAccount->getCharacters().size()); - Beings& characters = account.getCharacters(); + const Beings& characters = account.getCharacters(); for (size_t i = 0; i < mCharacters.size(); ++i) { CPPUNIT_ASSERT_EQUAL(characters[i]->getName(), @@ -133,15 +124,11 @@ AccountTest::testCreate2(void) void AccountTest::testAddCharacter1(void) { - RawStatistics stats; - stats.strength = 1; - stats.agility = 1; - stats.vitality = 1; - stats.intelligence = 1; - stats.dexterity = 1; - stats.luck = 1; + LOG("AccountTest::testAddCharacter1()"); + + RawStatistics stats = {1, 1, 1, 1, 1, 1}; - Being* bilbo = new Being("bilbo", GENDER_MALE, 0, 0, stats); + BeingPtr bilbo(new Being("bilbo", GENDER_MALE, 0, 0, stats)); mAccount->addCharacter(bilbo); @@ -156,8 +143,6 @@ AccountTest::testAddCharacter1(void) for (size_t i = 0; i < mCharacters.size(); ++i) { CPPUNIT_ASSERT_EQUAL(names[i], mCharacters[i]->getName()); } - - delete bilbo; } @@ -167,7 +152,11 @@ AccountTest::testAddCharacter1(void) void AccountTest::testAddCharacter2(void) { - mAccount->addCharacter(NULL); + LOG("AccountTest::testAddCharacter2()"); + + BeingPtr nullBeing(0); + + mAccount->addCharacter(nullBeing); CPPUNIT_ASSERT_EQUAL((size_t) 3, mAccount->getCharacters().size()); @@ -188,9 +177,11 @@ AccountTest::testAddCharacter2(void) void AccountTest::testGetCharacter1(void) { + LOG("AccountTest::testGetCharacter1()"); + const std::string name("merry"); - Being* merry = mAccount->getCharacter(name); + const Being* merry = mAccount->getCharacter(name); CPPUNIT_ASSERT(merry != 0); CPPUNIT_ASSERT_EQUAL(name, merry->getName()); @@ -203,7 +194,9 @@ AccountTest::testGetCharacter1(void) void AccountTest::testGetCharacter2(void) { - Being* nobody = mAccount->getCharacter("johndoe"); + LOG("AccountTest::testGetCharacter2()"); + + const Being* nobody = mAccount->getCharacter("johndoe"); CPPUNIT_ASSERT(nobody == 0); } diff --git a/src/tests/testcipher.cpp b/src/tests/testcipher.cpp index d51a4404..85e34099 100644 --- a/src/tests/testcipher.cpp +++ b/src/tests/testcipher.cpp @@ -24,6 +24,7 @@ #include <string> #include "../utils/cipher.h" +#include "../utils/logger.h" #include "testcipher.h" @@ -60,8 +61,10 @@ CipherTest::tearDown(void) void CipherTest::testMd5_1(void) { + LOG("CipherTest::testMd5_1()"); + const std::string expected("d41d8cd98f00b204e9800998ecf8427e"); - std::string actual(Cipher::instance().md5("")); + const std::string actual(Cipher::instance().md5("")); CPPUNIT_ASSERT_EQUAL(expected, actual); } @@ -73,8 +76,10 @@ CipherTest::testMd5_1(void) void CipherTest::testMd5_2(void) { + LOG("CipherTest::testMd5_2()"); + const std::string expected("0cc175b9c0f1b6a831c399e269772661"); - std::string actual(Cipher::instance().md5("a")); + const std::string actual(Cipher::instance().md5("a")); CPPUNIT_ASSERT_EQUAL(expected, actual); } @@ -86,8 +91,10 @@ CipherTest::testMd5_2(void) void CipherTest::testMd5_3(void) { + LOG("CipherTest::testMd5_3()"); + const std::string expected("900150983cd24fb0d6963f7d28e17f72"); - std::string actual(Cipher::instance().md5("abc")); + const std::string actual(Cipher::instance().md5("abc")); CPPUNIT_ASSERT_EQUAL(expected, actual); } @@ -99,8 +106,10 @@ CipherTest::testMd5_3(void) void CipherTest::testMd5_4(void) { + LOG("CipherTest::testMd5_4()"); + const std::string expected("f96b697d7cb7938d525a2f31aaf161d0"); - std::string actual(Cipher::instance().md5("message digest")); + const std::string actual(Cipher::instance().md5("message digest")); CPPUNIT_ASSERT_EQUAL(expected, actual); } @@ -112,8 +121,11 @@ CipherTest::testMd5_4(void) void CipherTest::testMd5_5(void) { + LOG("CipherTest::testMd5_6()"); + const std::string expected("c3fcd3d76192e4007dfb496cca67e13b"); - std::string actual(Cipher::instance().md5("abcdefghijklmnopqrstuvwxyz")); + const std::string actual( + Cipher::instance().md5("abcdefghijklmnopqrstuvwxyz")); CPPUNIT_ASSERT_EQUAL(expected, actual); } @@ -125,12 +137,14 @@ CipherTest::testMd5_5(void) void CipherTest::testMd5_6(void) { + LOG("CipherTest::testMd5_6()"); + const std::string expected("d174ab98d277d9f5a5611c2c9f419d9f"); std::string s("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); s += "abcdefghijklmnopqrstuvwxyz"; s += "0123456789"; - std::string actual(Cipher::instance().md5(s)); + const std::string actual(Cipher::instance().md5(s)); CPPUNIT_ASSERT_EQUAL(expected, actual); } @@ -142,13 +156,15 @@ CipherTest::testMd5_6(void) void CipherTest::testMd5_7(void) { + LOG("CipherTest::testMd5_7()"); + const std::string expected("57edf4a22be3c955ac49da2e2107b67a"); std::string s; for (int i = 0; i < 8; ++i) { s += "1234567890"; } - std::string actual(Cipher::instance().md5(s)); + const std::string actual(Cipher::instance().md5(s)); CPPUNIT_ASSERT_EQUAL(expected, actual); } diff --git a/src/tests/testdataprovider.cpp b/src/tests/testdataprovider.cpp index 06a2b0ee..dd5aff4f 100644 --- a/src/tests/testdataprovider.cpp +++ b/src/tests/testdataprovider.cpp @@ -30,6 +30,7 @@ #endif #include "../dal/dataproviderfactory.h" +#include "../utils/logger.h" #include "testdataprovider.h" @@ -97,6 +98,8 @@ DataProviderTest::tearDown(void) void DataProviderTest::testConnection1(void) { + LOG("DataProviderTest::testConnection1()"); + #ifdef SQLITE_SUPPORT std::string dbFile(mDbName); dbFile += ".db"; @@ -116,6 +119,8 @@ DataProviderTest::testConnection1(void) void DataProviderTest::testCreateTable1(void) { + LOG("DataProviderTest::testCreateTable1()"); + #ifdef SQLITE_SUPPORT std::string dbFile(mDbName); dbFile += ".db"; @@ -141,6 +146,8 @@ DataProviderTest::testCreateTable1(void) void DataProviderTest::testCreateTable2(void) { + LOG("DataProviderTest::testCreateTable2()"); + #ifdef SQLITE_SUPPORT std::string dbFile(mDbName); dbFile += ".db"; @@ -164,6 +171,8 @@ DataProviderTest::testCreateTable2(void) void DataProviderTest::testInsert1(void) { + LOG("DataProviderTest::testInsert1()"); + #ifdef SQLITE_SUPPORT std::string dbFile(mDbName); dbFile += ".db"; @@ -193,6 +202,8 @@ DataProviderTest::testInsert1(void) void DataProviderTest::testInsert2(void) { + LOG("DataProviderTest::testInsert2()"); + #ifdef SQLITE_SUPPORT std::string dbFile(mDbName); dbFile += ".db"; @@ -216,6 +227,8 @@ DataProviderTest::testInsert2(void) void DataProviderTest::testFetch1(void) { + LOG("DataProviderTest::testFetch1()"); + #ifdef SQLITE_SUPPORT std::string dbFile(mDbName); dbFile += ".db"; @@ -249,6 +262,8 @@ DataProviderTest::testFetch1(void) void DataProviderTest::testDisconnection1(void) { + LOG("DataProviderTest::testDisconnection1()"); + #ifdef SQLITE_SUPPORT std::string dbFile(mDbName); dbFile += ".db"; @@ -271,6 +286,8 @@ DataProviderTest::testDisconnection1(void) void DataProviderTest::testDisconnection2(void) { + LOG("DataProviderTest::testDisconnection2()"); + mDb->disconnect(); CPPUNIT_ASSERT(!mDb->isConnected()); } diff --git a/src/tests/testrecordset.cpp b/src/tests/testrecordset.cpp index 26a9e016..df9a7100 100644 --- a/src/tests/testrecordset.cpp +++ b/src/tests/testrecordset.cpp @@ -23,6 +23,7 @@ #include <sstream> +#include "../utils/logger.h" #include "testrecordset.h" @@ -73,6 +74,8 @@ RecordSetTest::tearDown(void) void RecordSetTest::testRows1(void) { + LOG("RecordSetTest::testRows1()"); + CPPUNIT_ASSERT_EQUAL((unsigned int) 0, mEmptyRs.rows()); } @@ -83,6 +86,8 @@ RecordSetTest::testRows1(void) void RecordSetTest::testRows2(void) { + LOG("RecordSetTest::testRows2()"); + CPPUNIT_ASSERT_EQUAL((unsigned int) 2, mNonEmptyRs.rows()); } @@ -93,6 +98,8 @@ RecordSetTest::testRows2(void) void RecordSetTest::testCols1(void) { + LOG("RecordSetTest::testCols1()"); + CPPUNIT_ASSERT_EQUAL((unsigned int) 0, mEmptyRs.cols()); } @@ -103,6 +110,8 @@ RecordSetTest::testCols1(void) void RecordSetTest::testCols2(void) { + LOG("RecordSetTest::testCols2()"); + CPPUNIT_ASSERT_EQUAL((unsigned int) 2, mNonEmptyRs.cols()); } @@ -113,6 +122,8 @@ RecordSetTest::testCols2(void) void RecordSetTest::testIsEmpty1(void) { + LOG("RecordSetTest::testIsEmpty1()"); + CPPUNIT_ASSERT(mEmptyRs.isEmpty()); } @@ -123,6 +134,8 @@ RecordSetTest::testIsEmpty1(void) void RecordSetTest::testIsEmpty2(void) { + LOG("RecordSetTest::testIsEmpty2()"); + CPPUNIT_ASSERT(!mNonEmptyRs.isEmpty()); } @@ -133,6 +146,8 @@ RecordSetTest::testIsEmpty2(void) void RecordSetTest::testOperator1(void) { + LOG("RecordSetTest::testOperator1()"); + // this should throw std::invalid_argument. mEmptyRs(0, 0); } @@ -145,7 +160,9 @@ RecordSetTest::testOperator1(void) void RecordSetTest::testOperator2(void) { - std::string value("mike"); + LOG("RecordSetTest::testRows1()"); + + const std::string value("mike"); CPPUNIT_ASSERT_EQUAL(value, mNonEmptyRs(1, 1)); } @@ -159,6 +176,8 @@ RecordSetTest::testOperator2(void) void RecordSetTest::testOperator3(void) { + LOG("RecordSetTest::testOperator3()"); + // this should throw std::out_of_range. mNonEmptyRs(2, 2); } @@ -171,7 +190,9 @@ RecordSetTest::testOperator3(void) void RecordSetTest::testOperator4(void) { - std::string value("1"); + LOG("RecordSetTest::testOperator4()"); + + const std::string value("1"); CPPUNIT_ASSERT_EQUAL(value, mNonEmptyRs(0, "id")); } @@ -184,6 +205,8 @@ RecordSetTest::testOperator4(void) void RecordSetTest::testOperator5(void) { + LOG("RecordSetTest::testOperator5()"); + // this should throw std::out_of_range. mNonEmptyRs(3, "id"); } @@ -196,6 +219,8 @@ RecordSetTest::testOperator5(void) void RecordSetTest::testOperator6(void) { + LOG("RecordSetTest::testOperator6()"); + // this should throw std::invalid_argument. mNonEmptyRs(1, "noname"); } @@ -207,7 +232,9 @@ RecordSetTest::testOperator6(void) void RecordSetTest::testOutputStream1(void) { - std::string emptyStr; + LOG("RecordSetTest::testOutputStream1()"); + + const std::string emptyStr; std::ostringstream os; os << mEmptyRs; @@ -222,6 +249,8 @@ RecordSetTest::testOutputStream1(void) void RecordSetTest::testOutputStream2(void) { + LOG("RecordSetTest::testOutputStream2()"); + std::ostringstream os1; os1 << "|id|name|" << std::endl << std::endl << "|1|john|" << std::endl @@ -240,8 +269,10 @@ RecordSetTest::testOutputStream2(void) void RecordSetTest::testAdd1(void) { - std::string id("3"); - std::string name("elena"); + LOG("RecordSetTest::testAdd1()"); + + const std::string id("3"); + const std::string name("elena"); Row r; r.push_back(id); @@ -262,6 +293,8 @@ RecordSetTest::testAdd1(void) void RecordSetTest::testAdd2(void) { + LOG("RecordSetTest::testAdd2()"); + Row r; r.push_back("4"); @@ -277,6 +310,8 @@ RecordSetTest::testAdd2(void) void RecordSetTest::testAdd3(void) { + LOG("RecordSetTest::testAdd3()"); + Row r; r.push_back("5"); diff --git a/src/tests/testsmain.cpp b/src/tests/testsmain.cpp index 70cdc185..21237601 100644 --- a/src/tests/testsmain.cpp +++ b/src/tests/testsmain.cpp @@ -26,6 +26,8 @@ #include <physfs.h> +#include "../utils/logger.h" + /** * Notes: @@ -45,6 +47,9 @@ int main(int argc, char* argv[]) PHYSFS_addToSearchPath(".", 1); PHYSFS_setWriteDir("."); + // initialize the logger. + tmwserv::utils::Logger::instance().setTimestamp(false); + using namespace CppUnit; // get the top level suite from the registry. diff --git a/src/tests/teststorage.cpp b/src/tests/teststorage.cpp index 7a7cb7fd..977c2940 100644 --- a/src/tests/teststorage.cpp +++ b/src/tests/teststorage.cpp @@ -38,6 +38,7 @@ #include "../utils/cipher.h" #include "../utils/functors.h" +#include "../utils/logger.h" #include "../dalstoragesql.h" #include "../storage.h" #include "teststorage.h" @@ -99,6 +100,8 @@ StorageTest::tearDown(void) void StorageTest::testGetAccount1(void) { + LOG("StorageTest::testGetAccount1()"); + Storage& myStorage = Storage::instance(mStorageName); CPPUNIT_ASSERT(myStorage.isOpen()); @@ -124,6 +127,8 @@ StorageTest::testGetAccount1(void) void StorageTest::testGetAccount2(void) { + LOG("StorageTest::testGetAccount2()"); + Storage& myStorage = Storage::instance(mStorageName); if (!myStorage.isOpen()) { @@ -142,6 +147,8 @@ StorageTest::testGetAccount2(void) void StorageTest::testAddAccount1(void) { + LOG("StorageTest::testAddAccount1()"); + Storage& myStorage = Storage::instance(mStorageName); if (!myStorage.isOpen()) { @@ -151,58 +158,14 @@ StorageTest::testAddAccount1(void) // TODO: when addAccount will throw exceptions, test the exceptions // thrown. // nothing should happen at the moment. - myStorage.addAccount(NULL); + AccountPtr nullAccount(0); + myStorage.addAccount(nullAccount); myStorage.flush(); -#if defined (MYSQL_SUPPORT) || defined (POSTGRESQL_SUPPORT) || \ - defined (SQLITE_SUPPORT) - - using namespace tmwserv::dal; - - std::auto_ptr<DataProvider> db(DataProviderFactory::createDataProvider()); - - try { -#ifdef SQLITE_SUPPORT - std::string dbFile(mStorageName); - dbFile += ".db"; - db->connect(dbFile, mStorageUser, mStorageUserPassword); -#else - db->connect(mStorageName, mStorageUser, mStorageUserPassword); -#endif - - std::string sql("select * from "); - sql += ACCOUNTS_TBL_NAME; - sql += ";"; - const RecordSet& rs = db->execSql(sql); - - CPPUNIT_ASSERT(rs.rows() == 3); - - const std::string frodo("frodo"); - const std::string merry("merry"); - const std::string pippin("pippin"); - - CPPUNIT_ASSERT_EQUAL(frodo, rs(0, "username")); - CPPUNIT_ASSERT_EQUAL(merry, rs(1, "username")); - CPPUNIT_ASSERT_EQUAL(pippin, rs(2, "username")); - - db->disconnect(); - } - catch (const DbConnectionFailure& e) { - CPPUNIT_FAIL(e.what()); - } - catch (const DbSqlQueryExecFailure& e) { - CPPUNIT_FAIL(e.what()); - } - catch (const DbDisconnectionFailure& e) { - CPPUNIT_FAIL(e.what()); - } - catch (const std::exception& e) { - CPPUNIT_FAIL(e.what()); - } - catch (...) { - CPPUNIT_FAIL("unexpected exception"); - } -#endif + // check the database. + Checks checks; + checks.set(CHK_DEFAULT_ACCOUNTS); + checkDb(checks); } @@ -212,6 +175,8 @@ StorageTest::testAddAccount1(void) void StorageTest::testAddAccount2(void) { + LOG("StorageTest::testAddAccount2()"); + Storage& myStorage = Storage::instance(mStorageName); if (!myStorage.isOpen()) { @@ -219,91 +184,29 @@ StorageTest::testAddAccount2(void) } // prepare new account. - RawStatistics stats; - stats.strength = 1; - stats.agility = 1; - stats.vitality = 1; - stats.intelligence = 1; - stats.dexterity = 1; - stats.luck = 1; + RawStatistics stats = {1, 1, 1, 1, 1, 1}; const std::string sam1("sam1"); const std::string sam2("sam2"); - Being* b1 = new Being(sam1, GENDER_MALE, 0, 0, stats); - Being* b2 = new Being(sam2, GENDER_MALE, 0, 0, stats); + BeingPtr b1(new Being(sam1, GENDER_MALE, 0, 0, stats)); + BeingPtr b2(new Being(sam2, GENDER_MALE, 0, 0, stats)); Beings characters; characters.push_back(b1); characters.push_back(b2); const std::string sam("sam"); - Account* acc = new Account(sam, sam, "sam@domain", characters); + AccountPtr acc(new Account(sam, sam, "sam@domain", characters)); // TODO: when addAccount will throw exceptions, test the exceptions // thrown. myStorage.addAccount(acc); myStorage.flush(); -#if defined (MYSQL_SUPPORT) || defined (POSTGRESQL_SUPPORT) || \ - defined (SQLITE_SUPPORT) - - using namespace tmwserv::dal; - - std::auto_ptr<DataProvider> db(DataProviderFactory::createDataProvider()); - - try { -#ifdef SQLITE_SUPPORT - std::string dbFile(mStorageName); - dbFile += ".db"; - db->connect(dbFile, mStorageUser, mStorageUserPassword); -#else - db->connect(mStorageName, mStorageUser, mStorageUserPassword); -#endif - - std::string sql("select * from "); - sql += ACCOUNTS_TBL_NAME; - sql += ";"; - const RecordSet& rs = db->execSql(sql); - - CPPUNIT_ASSERT(rs.rows() == 4); - - const std::string frodo("frodo"); - const std::string merry("merry"); - const std::string pippin("pippin"); - - CPPUNIT_ASSERT_EQUAL(frodo, rs(0, "username")); - CPPUNIT_ASSERT_EQUAL(merry, rs(1, "username")); - CPPUNIT_ASSERT_EQUAL(pippin, rs(2, "username")); - CPPUNIT_ASSERT_EQUAL(sam, rs(3, "username")); - - sql = "select * from "; - sql += CHARACTERS_TBL_NAME; - sql += " where user_id = 4;"; - - db->execSql(sql); - - CPPUNIT_ASSERT(rs.rows() == 2); - - CPPUNIT_ASSERT_EQUAL(sam1, rs(0, "name")); - CPPUNIT_ASSERT_EQUAL(sam2, rs(1, "name")); - - db->disconnect(); - } - catch (const DbConnectionFailure& e) { - CPPUNIT_FAIL(e.what()); - } - catch (const DbSqlQueryExecFailure& e) { - CPPUNIT_FAIL(e.what()); - } - catch (const DbDisconnectionFailure& e) { - CPPUNIT_FAIL(e.what()); - } - catch (const std::exception& e) { - CPPUNIT_FAIL(e.what()); - } - catch (...) { - CPPUNIT_FAIL("unexpected exception"); - } -#endif + // check the database. + Checks checks; + checks.set(CHK_NEW_ADDED_ACCOUNT); + checks.set(CHK_CHARACTERS_4); + checkDb(checks); } @@ -313,6 +216,8 @@ StorageTest::testAddAccount2(void) void StorageTest::testUpdAccount1(void) { + LOG("StorageTest::testUpdAccount1()"); + Storage& myStorage = Storage::instance(mStorageName); CPPUNIT_ASSERT(myStorage.isOpen()); @@ -322,18 +227,12 @@ StorageTest::testUpdAccount1(void) Account* account = myStorage.getAccount(name); // create new characters. - RawStatistics stats; - stats.strength = 1; - stats.agility = 1; - stats.vitality = 1; - stats.intelligence = 1; - stats.dexterity = 1; - stats.luck = 1; + RawStatistics stats = {1, 1, 1, 1, 1, 1}; const std::string sam1("sam1"); const std::string sam2("sam2"); - Being* b1 = new Being(sam1, GENDER_MALE, 0, 0, stats); - Being* b2 = new Being(sam2, GENDER_MALE, 0, 0, stats); + BeingPtr b1(new Being(sam1, GENDER_MALE, 0, 0, stats)); + BeingPtr b2(new Being(sam2, GENDER_MALE, 0, 0, stats)); // add the characters to the account. account->addCharacter(b1); @@ -342,66 +241,11 @@ StorageTest::testUpdAccount1(void) // update the database. myStorage.flush(); -#if defined (MYSQL_SUPPORT) || defined (POSTGRESQL_SUPPORT) || \ - defined (SQLITE_SUPPORT) - - using namespace tmwserv::dal; - - std::auto_ptr<DataProvider> db(DataProviderFactory::createDataProvider()); - - try { -#ifdef SQLITE_SUPPORT - std::string dbFile(mStorageName); - dbFile += ".db"; - db->connect(dbFile, mStorageUser, mStorageUserPassword); -#else - db->connect(mStorageName, mStorageUser, mStorageUserPassword); -#endif - - std::string sql("select * from "); - sql += ACCOUNTS_TBL_NAME; - sql += ";"; - const RecordSet& rs = db->execSql(sql); - - CPPUNIT_ASSERT(rs.rows() == 3); - - const std::string frodo("frodo"); - const std::string merry("merry"); - const std::string pippin("pippin"); - - CPPUNIT_ASSERT_EQUAL(frodo, rs(0, "username")); - CPPUNIT_ASSERT_EQUAL(merry, rs(1, "username")); - CPPUNIT_ASSERT_EQUAL(pippin, rs(2, "username")); - - sql = "select * from "; - sql += CHARACTERS_TBL_NAME; - sql += " where user_id = 1;"; - - db->execSql(sql); - - CPPUNIT_ASSERT(rs.rows() == 2); - - CPPUNIT_ASSERT_EQUAL(sam1, rs(0, "name")); - CPPUNIT_ASSERT_EQUAL(sam2, rs(1, "name")); - - db->disconnect(); - } - catch (const DbConnectionFailure& e) { - CPPUNIT_FAIL(e.what()); - } - catch (const DbSqlQueryExecFailure& e) { - CPPUNIT_FAIL(e.what()); - } - catch (const DbDisconnectionFailure& e) { - CPPUNIT_FAIL(e.what()); - } - catch (const std::exception& e) { - CPPUNIT_FAIL(e.what()); - } - catch (...) { - CPPUNIT_FAIL("unexpected exception"); - } -#endif + // check the database. + Checks checks; + checks.set(CHK_DEFAULT_ACCOUNTS); + checks.set(CHK_CHARACTERS_1); + checkDb(checks); } @@ -412,6 +256,8 @@ StorageTest::testUpdAccount1(void) void StorageTest::testUpdAccount2(void) { + LOG("StorageTest::testUpdAccount2()"); + Storage& myStorage = Storage::instance(mStorageName); CPPUNIT_ASSERT(myStorage.isOpen()); @@ -421,18 +267,12 @@ StorageTest::testUpdAccount2(void) Account* account = myStorage.getAccount(name); // create new characters. - RawStatistics stats; - stats.strength = 1; - stats.agility = 1; - stats.vitality = 1; - stats.intelligence = 1; - stats.dexterity = 1; - stats.luck = 1; + RawStatistics stats = {1, 1, 1, 1, 1, 1}; const std::string sam1("sam1"); const std::string sam2("sam2"); - Being* b1 = new Being(sam1, GENDER_MALE, 0, 0, stats); - Being* b2 = new Being(sam2, GENDER_MALE, 0, 0, stats); + BeingPtr b1(new Being(sam1, GENDER_MALE, 0, 0, stats)); + BeingPtr b2(new Being(sam2, GENDER_MALE, 0, 0, stats)); // add the characters to the account. account->addCharacter(b1); @@ -528,59 +368,151 @@ StorageTest::testUpdAccount2(void) void StorageTest::testDelAccount1(void) { + LOG("StorageTest::testDelAccount1()"); + Storage& myStorage = Storage::instance(mStorageName); CPPUNIT_ASSERT(myStorage.isOpen()); myStorage.delAccount("frodo"); -#if defined (MYSQL_SUPPORT) || defined (POSTGRESQL_SUPPORT) || \ - defined (SQLITE_SUPPORT) + // check the database. + Checks checks; + checks.set(CHK_1ST_ACCOUNT_DELETED); + checkDb(checks); +} - using namespace tmwserv::dal; - std::auto_ptr<DataProvider> db(DataProviderFactory::createDataProvider()); +/** + * Test deleting an account that was added to the storage but not + * yet persisted. + */ +void +StorageTest::testDelAccount2(void) +{ + LOG("StorageTest::testDelAccount2()"); - try { -#ifdef SQLITE_SUPPORT - std::string dbFile(mStorageName); - dbFile += ".db"; - db->connect(dbFile, mStorageUser, mStorageUserPassword); -#else - db->connect(mStorageName, mStorageUser, mStorageUserPassword); -#endif + Storage& myStorage = Storage::instance(mStorageName); - std::string sql("select * from "); - sql += ACCOUNTS_TBL_NAME; - sql += ";"; - const RecordSet& rs = db->execSql(sql); + if (!myStorage.isOpen()) { + CPPUNIT_FAIL("the storage is not opened."); + } - CPPUNIT_ASSERT(rs.rows() == 2); + // prepare new account. + RawStatistics stats = {1, 1, 1, 1, 1, 1}; - const std::string merry("merry"); - const std::string pippin("pippin"); + const std::string sam1("sam1"); + const std::string sam2("sam2"); + BeingPtr b1(new Being(sam1, GENDER_MALE, 0, 0, stats)); + BeingPtr b2(new Being(sam2, GENDER_MALE, 0, 0, stats)); + Beings characters; + characters.push_back(b1); + characters.push_back(b2); - CPPUNIT_ASSERT_EQUAL(merry, rs(0, "username")); - CPPUNIT_ASSERT_EQUAL(pippin, rs(1, "username")); + const std::string sam("sam"); + AccountPtr acc(new Account(sam, sam, "sam@domain", characters)); - db->disconnect(); - } - catch (const DbConnectionFailure& e) { - CPPUNIT_FAIL(e.what()); - } - catch (const DbSqlQueryExecFailure& e) { - CPPUNIT_FAIL(e.what()); - } - catch (const DbDisconnectionFailure& e) { - CPPUNIT_FAIL(e.what()); + myStorage.addAccount(acc); + myStorage.delAccount(sam); + + // nothing should be added to the database. + myStorage.flush(); + + // check the database. + Checks checks; + checks.set(CHK_DEFAULT_ACCOUNTS); + checkDb(checks); +} + + +/** + * Test deleting an account that exists in the database and loaded + * in memory. + */ +void +StorageTest::testDelAccount3(void) +{ + LOG("StorageTest::testDelAccount3()"); + + Storage& myStorage = Storage::instance(mStorageName); + + if (!myStorage.isOpen()) { + CPPUNIT_FAIL("the storage is not opened."); } - catch (const std::exception& e) { - CPPUNIT_FAIL(e.what()); + + // get an existing account. + const std::string name("frodo"); + Account* account = myStorage.getAccount(name); + + CPPUNIT_ASSERT_EQUAL(name, account->getName()); + + myStorage.delAccount(name); + myStorage.flush(); + + // check the database. + Checks checks; + checks.set(CHK_1ST_ACCOUNT_DELETED); + checkDb(checks); +} + + +/** + * Test deleting an account that does not exist. + */ +void +StorageTest::testDelAccount4(void) +{ + LOG("StorageTest::testDelAccount4()"); + + Storage& myStorage = Storage::instance(mStorageName); + + if (!myStorage.isOpen()) { + CPPUNIT_FAIL("the storage is not opened."); } - catch (...) { - CPPUNIT_FAIL("unexpected exception"); + + // nothing should happen nor modified in the database. + myStorage.delAccount("xxx"); + myStorage.flush(); + + // check the database. + Checks checks; + checks.set(CHK_DEFAULT_ACCOUNTS); + checkDb(checks); +} + + +/** + * Test deleting twice an account that exists in the database and + * loaded in memory. + */ +void +StorageTest::testDelAccount5(void) +{ + LOG("StorageTest::testDelAccount5()"); + + Storage& myStorage = Storage::instance(mStorageName); + + if (!myStorage.isOpen()) { + CPPUNIT_FAIL("the storage is not opened."); } -#endif + + // get an existing account. + const std::string name("frodo"); + Account* account = myStorage.getAccount(name); + + CPPUNIT_ASSERT_EQUAL(name, account->getName()); + + myStorage.delAccount(name); + myStorage.flush(); + + // delete it again. + myStorage.delAccount(name); + myStorage.flush(); + + // check the database. + Checks checks; + checks.set(CHK_1ST_ACCOUNT_DELETED); + checkDb(checks); } @@ -757,3 +689,110 @@ StorageTest::insertAccount(std::auto_ptr<DataProvider>& db, db->execSql(sql.str()); } + + +/** + * Check the state of the database. + */ +void +StorageTest::checkDb(const Checks& what) +{ +#if defined (MYSQL_SUPPORT) || defined (POSTGRESQL_SUPPORT) || \ + defined (SQLITE_SUPPORT) + + using namespace tmwserv::dal; + + std::auto_ptr<DataProvider> db(DataProviderFactory::createDataProvider()); + + try { +#ifdef SQLITE_SUPPORT + std::string dbFile(mStorageName); + dbFile += ".db"; + db->connect(dbFile, mStorageUser, mStorageUserPassword); +#else + db->connect(mStorageName, mStorageUser, mStorageUserPassword); +#endif + + std::string sql("select * from "); + sql += ACCOUNTS_TBL_NAME; + sql += ";"; + const RecordSet& rs = db->execSql(sql); + + if (what[CHK_DEFAULT_ACCOUNTS]) { + CPPUNIT_ASSERT(rs.rows() == 3); + + const std::string frodo("frodo"); + const std::string merry("merry"); + const std::string pippin("pippin"); + + CPPUNIT_ASSERT_EQUAL(frodo, rs(0, "username")); + CPPUNIT_ASSERT_EQUAL(merry, rs(1, "username")); + CPPUNIT_ASSERT_EQUAL(pippin, rs(2, "username")); + } + + if (what[CHK_1ST_ACCOUNT_DELETED]) { + CPPUNIT_ASSERT(rs.rows() == 2); + + const std::string merry("merry"); + const std::string pippin("pippin"); + + CPPUNIT_ASSERT_EQUAL(merry, rs(0, "username")); + CPPUNIT_ASSERT_EQUAL(pippin, rs(1, "username")); + } + + if (what[CHK_NEW_ADDED_ACCOUNT]) { + CPPUNIT_ASSERT(rs.rows() == 4); + + const std::string frodo("frodo"); + const std::string merry("merry"); + const std::string pippin("pippin"); + const std::string sam("sam"); + + CPPUNIT_ASSERT_EQUAL(frodo, rs(0, "username")); + CPPUNIT_ASSERT_EQUAL(merry, rs(1, "username")); + CPPUNIT_ASSERT_EQUAL(pippin, rs(2, "username")); + CPPUNIT_ASSERT_EQUAL(sam, rs(3, "username")); + } + + if (what[CHK_CHARACTERS_1]) { + sql = "select * from "; + sql += CHARACTERS_TBL_NAME; + sql += " where user_id = 1;"; + } + else if (what[CHK_CHARACTERS_4]) { + sql = "select * from "; + sql += CHARACTERS_TBL_NAME; + sql += " where user_id = 4;"; + } + + if (what[CHK_CHARACTERS_1] || what[CHK_CHARACTERS_4]) { + db->execSql(sql); + + CPPUNIT_ASSERT(rs.rows() == 2); + + const std::string sam1("sam1"); + const std::string sam2("sam2"); + + CPPUNIT_ASSERT_EQUAL(sam1, rs(0, "name")); + CPPUNIT_ASSERT_EQUAL(sam2, rs(1, "name")); + } + + db->disconnect(); + } + catch (const DbConnectionFailure& e) { + CPPUNIT_FAIL(e.what()); + } + catch (const DbSqlQueryExecFailure& e) { + CPPUNIT_FAIL(e.what()); + } + catch (const DbDisconnectionFailure& e) { + CPPUNIT_FAIL(e.what()); + } + catch (const std::exception& e) { + CPPUNIT_FAIL(e.what()); + } + catch (...) { + CPPUNIT_FAIL("unexpected exception"); + } +#endif +} diff --git a/src/tests/teststorage.h b/src/tests/teststorage.h index da1eae8e..8eef60cc 100644 --- a/src/tests/teststorage.h +++ b/src/tests/teststorage.h @@ -25,6 +25,7 @@ #define _TMWSERV_TEST_STORAGE_H_ +#include <bitset> #include <vector> #include <cppunit/extensions/HelperMacros.h> @@ -59,6 +60,10 @@ class StorageTest: public CppUnit::TestFixture CPPUNIT_TEST(testUpdAccount1); CPPUNIT_TEST(testUpdAccount2); CPPUNIT_TEST(testDelAccount1); + CPPUNIT_TEST(testDelAccount2); + CPPUNIT_TEST(testDelAccount3); + CPPUNIT_TEST(testDelAccount4); + CPPUNIT_TEST(testDelAccount5); CPPUNIT_TEST_SUITE_END(); @@ -129,6 +134,37 @@ class StorageTest: public CppUnit::TestFixture testDelAccount1(void); + /** + * Test deleting an account that was added to the storage but not + * yet persisted. + */ + void + testDelAccount2(void); + + + /** + * Test deleting an account that exists in the database and loaded + * in memory. + */ + void + testDelAccount3(void); + + + /** + * Test deleting an account that does not exist. + */ + void + testDelAccount4(void); + + + /** + * Test deleting twice an account that exists in the database and + * loaded in memory. + */ + void + testDelAccount5(void); + + private: /** * Initialize the storage. @@ -166,6 +202,35 @@ class StorageTest: public CppUnit::TestFixture const std::string& name); + /** + * Enumeration type for the bits. + * Each bit represents a particular check. + */ + enum CheckValues { + CHK_DEFAULT_ACCOUNTS, + CHK_1ST_ACCOUNT_DELETED, + CHK_NEW_ADDED_ACCOUNT, + CHK_CHARACTERS_1, + CHK_CHARACTERS_4, + NUM_CHECKS + }; + + + /** + * Type definition for the checks. + */ + typedef std::bitset<NUM_CHECKS> Checks; + + + /** + * Check the state of the database. + * + * @param what bitmask that contains information about what to check. + */ + void + checkDb(const Checks& what); + + private: static std::string mStorageName; /**< name of the storage */ static std::string mStorageUser; /**< storage user */ diff --git a/src/utils/countedptr.h b/src/utils/countedptr.h new file mode 100644 index 00000000..f8dbcd51 --- /dev/null +++ b/src/utils/countedptr.h @@ -0,0 +1,163 @@ +/* + * The Mana World Server + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or any later version. + * + * The Mana World is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with The Mana World; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + + +#ifndef _TMWSERV_COUNTED_PTR_H_ +#define _TMWSERV_COUNTED_PTR_H_ + + +namespace tmwserv +{ +namespace utils +{ + + +/** + * Class for counted reference semantics. It deletes the object to which it + * refers when the last CountedPtr that refers to it is destroyed. + * + * @copyright Nicolai M. Josuttis + * (The C++ standard library: a tutorial and reference). + * + * Notes from kindjal: + * - should we use the Boost's shared_ptr instead? + * - reference-counted smart pointers are very useful if we want automatic + * memory management with STL containers (e.g. vector of pointers). + */ +template <typename T> +class CountedPtr +{ + public: + /** + * Constructor. + * Initialize pointer with existing pointer. + * + * It is required that the pointer p is a return value of new. + */ + explicit + CountedPtr(T* p = 0) + : ptr(p), + count(new long(1)) + { + // NOOP + } + + + /** + * Destructor. + * Delete value if this was the last owner. + */ + ~CountedPtr(void) + throw() + { + dispose(); + } + + + /** + * Copy pointer (one more owner). + */ + CountedPtr(const CountedPtr<T>& p) + throw() + : ptr(p.ptr), + count(p.count) + { + ++*count; + } + + + /** + * Assignment (unshare old and share new value). + */ + CountedPtr<T>& + operator=(const CountedPtr<T>& p) + throw() + { + if (this != &p) { + dispose(); + ptr = p.ptr; + count = p.count; + ++*count; + } + + return *this; + } + + + /** + * Access the value to which the pointer refers. + */ + T& + operator*(void) const + throw() + { + return *ptr; + } + + + /** + * Access the pointer. + */ + T* + operator->(void) const + throw() + { + return ptr; + } + + + /** + * Get the pointer (mimic std::auto_ptr::get()). + */ + T* + get(void) const + throw() + { + return ptr; + } + + + private: + /** + * Manage the counter and free memory. + */ + void + dispose(void) + { + if (--*count == 0) { + delete count; + delete ptr; + } + } + + + private: + T* ptr; /**< pointer to the value */ + long* count; /**< shared number of owners */ +}; + + +} // namespace utils +} // namespace tmwserv + + +#endif // _TMWSERV_COUNTED_PTR_H_ |