From a78e59b9f2fb4eb7971eb5f46637df80157d787a Mon Sep 17 00:00:00 2001 From: Huynh Tran Date: Mon, 27 Jun 2005 15:41:00 +0000 Subject: Implemented addAccount() (+ unit tests). --- src/account.cpp | 44 +++++-- src/account.h | 41 ++++++- src/dalstorage.cpp | 304 +++++++++++++++++++++++++++++++++++++++------- src/dalstorage.h | 37 +++++- src/object.cpp | 2 +- src/storage.h | 20 ++- src/tests/testaccount.cpp | 49 +++----- src/tests/testaccount.h | 4 +- src/tests/testcipher.cpp | 14 +-- src/tests/teststorage.cpp | 209 +++++++++++++++++++++++++++++-- src/tests/teststorage.h | 24 ++++ 11 files changed, 634 insertions(+), 114 deletions(-) (limited to 'src') diff --git a/src/account.cpp b/src/account.cpp index 7fd8f77..ed2c358 100644 --- a/src/account.cpp +++ b/src/account.cpp @@ -32,10 +32,16 @@ namespace tmwserv /** - * Default constructor. + * Constructor with initial account info. */ -Account::Account(void) - throw() +Account::Account(const std::string& name, + const std::string& password, + const std::string& email) + : mName(name), + mPassword(password), + mEmail(email), + mCharacters(), + mLevel(AL_NORMAL) { // NOOP } @@ -49,11 +55,12 @@ Account::Account(const std::string& name, const std::string& email, const Beings& characters) : mName(name), + mPassword(password), mEmail(email), - mCharacters(characters) + mCharacters(characters), + mLevel(AL_NORMAL) { - // password must be encrypted. - setPassword(password); + // NOOP } @@ -104,15 +111,14 @@ Account::getName(void) const void Account::setPassword(const std::string& password) { - // use MD5 digest algorithm to cipher the password. - mPassword = utils::Cipher::instance().md5(password); + mPassword = password; } /** * Get the user password. */ -const std::string& +const std::string Account::getPassword(void) const { return mPassword; @@ -140,6 +146,26 @@ Account::getEmail(void) const } +/** + * Set the account level. + */ +void +Account::setLevel(const AccountLevels level) +{ + mLevel = level; +} + + +/** + * Get the account level. + */ +AccountLevels +Account::getLevel(void) const +{ + return mLevel; +} + + /** * Set the characters. */ diff --git a/src/account.h b/src/account.h index 62c0ec7..704a673 100644 --- a/src/account.h +++ b/src/account.h @@ -28,7 +28,7 @@ #include #include -#include "object.h" +#include "defines.h" namespace tmwserv @@ -42,10 +42,15 @@ class Account { public: /** - * Default constructor. + * Constructor with initial account info. + * + * @param name the user name. + * @param password the user password. + * @param email the user email. */ - Account(void) - throw(); + Account(const std::string& name, + const std::string& password, + const std::string& email); /** @@ -102,7 +107,7 @@ class Account * * @return the user password. */ - const std::string& + const std::string getPassword(void) const; @@ -124,6 +129,24 @@ class Account getEmail(void) const; + /** + * Set the account level. + * + * @param level the new level. + */ + void + setLevel(const AccountLevels level); + + + /** + * Get the account level. + * + * @return the account level. + */ + AccountLevels + getLevel(void) const; + + /** * Set the characters. * @@ -161,6 +184,13 @@ class Account private: + /** + * Default constructor. + */ + Account(void) + throw(); + + /** * Copy constructor. */ @@ -179,6 +209,7 @@ class Account std::string mPassword; /**< user password (encrypted) */ std::string mEmail; /**< user email address */ Beings mCharacters; /**< player data */ + AccountLevels mLevel; /**< account level */ }; diff --git a/src/dalstorage.cpp b/src/dalstorage.cpp index 14c3ff7..4e63371 100644 --- a/src/dalstorage.cpp +++ b/src/dalstorage.cpp @@ -22,7 +22,9 @@ #include +#include +#include "utils/cipher.h" #include "utils/functors.h" #include "utils/logger.h" @@ -194,13 +196,19 @@ DALStorage::getAccount(const std::string& userName) // create an Account instance // and initialize it with information about the user. - Account* account = new Account(); - account->setName(accountInfo(0, 1)); - account->setPassword(accountInfo(0, 2)); - account->setEmail(accountInfo(0, 3)); + Account* account = new Account(accountInfo(0, 1), + accountInfo(0, 2), + accountInfo(0, 3)); + + // specialize the string_to functor to convert + // a string to an unsigned int. + string_to toUint; // add the new Account to the list. - mAccounts.insert(std::make_pair(account, AS_ACC_TO_UPDATE)); + AccountInfo ai; + ai.status = AS_ACC_TO_UPDATE; + ai.id = toUint(accountInfo(0, 0)); + mAccounts.insert(std::make_pair(account, ai)); // load the characters associated with the account. sql = "select * from "; @@ -213,10 +221,6 @@ DALStorage::getAccount(const std::string& userName) if (!charInfo.isEmpty()) { Beings beings; - // specialize the string_to functor to convert - // a string to an unsigned int. - string_to toUint; - for (unsigned int i = 0; i < charInfo.rows(); ++i) { Being* being = new Being(charInfo(i, 2), // name @@ -249,7 +253,7 @@ DALStorage::getAccount(const std::string& userName) * Add a new account. */ void -DALStorage::addAccount(Account* account) +DALStorage::addAccount(const Account* account) { if (account == 0) { // maybe we should throw an exception instead @@ -258,7 +262,12 @@ DALStorage::addAccount(Account* account) // mark this account as new so that the next flush will execute a SQL // insert query instead of a SQL update query. - mAccounts.insert(std::make_pair(account, AS_NEW_ACCOUNT)); + AccountInfo ai; + ai.status = AS_NEW_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), ai)); } @@ -277,17 +286,24 @@ DALStorage::delAccount(const std::string& userName) ); if (it != mAccounts.end()) { - switch (it->second) { + switch ((it->second).status) { case AS_NEW_ACCOUNT: - // this is a newly added account and it has not even been - // saved into the database: remove it immediately. - delete it->first; + { + // 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. + } break; case AS_ACC_TO_UPDATE: // change the status to AS_ACC_TO_DELETE so that it will be // deleted at the next flush. - it->second = AS_ACC_TO_DELETE; + (it->second).status = AS_ACC_TO_DELETE; break; default: @@ -301,26 +317,10 @@ DALStorage::delAccount(const std::string& userName) using namespace dal; try { - std::string sql("select id from "); - sql += ACCOUNTS_TBL_NAME; - sql += " where username = '"; - sql += userName; - sql += "';"; - const RecordSet& accountInfo = mDb->execSql(sql); - - // the account does not even exist in the database, - // there is nothing to do then. - if (accountInfo.isEmpty()) { - return; - } - - // TODO: actually deleting the account from the database. - // order of deletion: - // 1. inventories of all the characters of the account, - // 2. all the characters, - // 3. the account itself. + // look for the account directly into the database. + _delAccount(userName); } - catch (const DbSqlQueryExecFailure& e) { + catch (const dal::DbSqlQueryExecFailure& e) { // TODO: throw an exception. } } @@ -332,15 +332,27 @@ DALStorage::delAccount(const std::string& userName) void DALStorage::flush(void) { - // TODO - // For each account in memory: - // - get the status - // - if AS_NEW_ACCOUNT then insert into database; - // - if AS_ACC_TO_UPDATE then update values from the database - // - if AS_ACC_TO_DELETE then delete from database - // Notes: - // - this will probably involve more than one table as the account may - // have characters associated to it. + Accounts::const_iterator it = mAccounts.begin(); + Accounts::const_iterator it_end = mAccounts.end(); + for (; it != it_end; ++it) { + switch ((it->second).status) { + case AS_NEW_ACCOUNT: + _addAccount(it->first); + break; + + case AS_ACC_TO_UPDATE: + _updAccount(it->first); + 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. + break; + + default: + break; + } + } } @@ -371,4 +383,208 @@ DALStorage::createTable(const std::string& tblName, } +/** + * Add an account to the database. + */ +void +DALStorage::_addAccount(const Account* account) +{ + if (account == 0) { + return; + } + + // assume that account is an element of mAccounts as this method is + // private and only called by flush(). + + using namespace dal; + + // TODO: we should start a transaction here so that in case of problem + // the lost of data would be minimized. + + // insert the account. + std::ostringstream sql1; + sql1 << "insert into " << ACCOUNTS_TBL_NAME << " values (null, '" + << account->getName() << "', '" + << utils::Cipher::instance().md5(account->getPassword()) << "', '" + << account->getEmail() << "', " + << account->getLevel() << ", 0);"; + mDb->execSql(sql1.str()); + + // get the account id. + std::ostringstream sql2; + sql2 << "select id from " << ACCOUNTS_TBL_NAME + << " where username = '" << account->getName() << "';"; + const RecordSet& accountInfo = mDb->execSql(sql2.str()); + string_to toUint; + + Accounts::iterator account_it = + std::find_if( + mAccounts.begin(), + mAccounts.end(), + account_by_name(account->getName()) + ); + + // update the info of the account. + (account_it->second).status = AS_ACC_TO_UPDATE; + (account_it->second).id = toUint(accountInfo(0, 0)); + + // insert the characters. + Beings& characters = (const_cast(account))->getCharacters(); + + Beings::const_iterator it = characters.begin(); + Beings::const_iterator it_end = characters.end(); + for (; it != it_end; ++it) { + // TODO: location on the map & statistics & inventories. + std::ostringstream sql3; + sql3 << "insert into " << CHARACTERS_TBL_NAME << " values (null, '" + << account->getName() << "', '" + << (*it)->getName() << "', '" + << (*it)->getGender() << "', " + << (*it)->getLevel() << ", " + << (*it)->getMoney() << ", " + << "0, 0, 0, 0, 0, 0, 0, 0, 0" + << ");"; + mDb->execSql(sql3.str()); + } +} + + +/** + * Update an account from the database. + */ +void +DALStorage::_updAccount(const Account* account) +{ + if (account == 0) { + return; + } + + // assume that account is an element of mAccounts as this method is + // private and only called by flush(). + + using namespace dal; + + // TODO: we should start a transaction here so that in case of problem + // the lost of data would be minimized. + + Accounts::iterator account_it = + std::find_if( + mAccounts.begin(), + mAccounts.end(), + account_by_name(account->getName()) + ); + + // doublecheck that this account already exists in the database + // and therefore its status must be AS_ACC_TO_UPDATE. + if ((account_it->second).status != AS_ACC_TO_UPDATE) { + return; // should we throw an exception here instead? + } + + // update the account. + std::ostringstream sql1; + sql1 << "update " << ACCOUNTS_TBL_NAME + << " set username = '" << account->getName() << "', " + << "password = '" << account->getPassword() << "', " + << "email = '" << account->getEmail() << "', " + << "level = '" << account->getLevel() << "' " + << "where id = '" << (account_it->second).id << "';"; + mDb->execSql(sql1.str()); + + // insert the characters. + Beings& characters = (const_cast(account))->getCharacters(); + + Beings::const_iterator it = characters.begin(); + Beings::const_iterator it_end = characters.end(); + for (; it != it_end; ++it) { + // TODO: location on the map & statistics & inventories. + std::ostringstream sql2; + sql2 << "update " << CHARACTERS_TBL_NAME + << "(user_id, name, gender, level, money) values (" + << " set name = '" << (*it)->getName() << "', " + << " gender = '" << (*it)->getGender() << "', " + << " level = '" << (*it)->getLevel() << "', " + << " money = '" << (*it)->getMoney() << "' " + << "where user_id = '" << (account_it->second).id << "';"; + mDb->execSql(sql2.str()); + } +} + + +/** + * Delete an account and its associated data from the database. + */ +void +DALStorage::_delAccount(const std::string& userName) +{ + using namespace dal; + + // TODO: optimize, we may be doing too much SQL queries here but this + // code should work with any database :( + + // get the account id. + std::string sql("select id from "); + sql += ACCOUNTS_TBL_NAME; + sql += " where username = '"; + sql += userName; + sql += "';"; + const RecordSet& accountInfo = mDb->execSql(sql); + + // the account does not even exist in the database, + // there is nothing to do then. + if (accountInfo.isEmpty()) { + return; + } + + // save the account id. + std::string accountId(accountInfo(0, 0)); + + // get the characters that belong to the account. + sql = "select id from "; + sql += CHARACTERS_TBL_NAME; + sql += " where user_id = '"; + sql += accountId; + sql += "';"; + const RecordSet& charsInfo = mDb->execSql(sql); + + // save the character ids. + using namespace std; + vector charIds; + for (unsigned int i = 0; i < charsInfo.rows(); ++i) { + charIds.push_back(charsInfo(i, 0)); + } + + // TODO: we should start a transaction here so that in case of problem + // the lost of data would be minimized. + + // actually removing data. + vector::const_iterator it = charIds.begin(); + vector::const_iterator it_end = charIds.end(); + for (; it != it_end; ++it) { + // delete the inventory. + sql = "delete from "; + sql += INVENTORIES_TBL_NAME; + sql += " where owner_id = '"; + sql += (*it); + sql += "';"; + mDb->execSql(sql); + + // now delete the character. + sql = "delete from "; + sql += CHARACTERS_TBL_NAME; + sql += " where id = '"; + sql += (*it); + sql += "';"; + mDb->execSql(sql); + } + + // delete the account. + sql = "delete from "; + sql += ACCOUNTS_TBL_NAME; + sql += " where id = '"; + sql += accountId; + sql += "';"; + mDb->execSql(sql); +} + + } // namespace tmwserv diff --git a/src/dalstorage.h b/src/dalstorage.h index 78a689c..80408f6 100644 --- a/src/dalstorage.h +++ b/src/dalstorage.h @@ -81,7 +81,7 @@ class DALStorage: public Storage * @param account the new account. */ void - addAccount(Account* account); + addAccount(const Account* account); /** @@ -95,6 +95,8 @@ class DALStorage: public Storage /** * Save changes to the database permanently. + * + * @exception tmwserv::dal::DbSqlQueryExecFailure. */ void flush(void); @@ -140,6 +142,39 @@ class DALStorage: public Storage const std::string& sql); + /** + * Add an account to the database. + * + * @param account the account to add. + * + * @exeception tmwserv::dal::DbSqlQueryExecFailure. + */ + void + _addAccount(const Account* account); + + + /** + * Update an account from the database. + * + * @param account the account to update. + * + * @exception tmwserv::dal::DbSqlQueryExecFailure. + */ + void + _updAccount(const Account* account); + + + /** + * Delete an account and its associated data from the database. + * + * @param userName the owner of the account. + * + * @exeception tmwserv::dal::DbSqlQueryExecFailure. + */ + void + _delAccount(const std::string& userName); + + private: std::auto_ptr mDb; /**< the data provider */ }; diff --git a/src/object.cpp b/src/object.cpp index 9ae2bd6..f67bae0 100644 --- a/src/object.cpp +++ b/src/object.cpp @@ -38,7 +38,7 @@ Being::Being(const std::string &bName, unsigned int bGender, dexterity(bDexterity), luck(bLuck) { - std::cout << "New being create with name \"" + name + "\"" << std::endl; + //std::cout << "New being create with name \"" + name + "\"" << std::endl; } void Being::update() diff --git a/src/storage.h b/src/storage.h index 5b695bb..4c6310d 100644 --- a/src/storage.h +++ b/src/storage.h @@ -61,6 +61,15 @@ typedef enum { } AccountStatus; +/** + * Structure type for the account info. + */ +typedef struct { + AccountStatus status; + unsigned int id; +} AccountInfo; + + /** * Functor to be used as the sorting criterion of the map defined below. */ @@ -77,8 +86,13 @@ struct account_sort_by_name /** * Data type for the list of accounts. + * + * Notes: + * - the account id is not attribute of Account but AccountInfo because + * only the storage should modify this value, this attribute is for + * internal use. */ -typedef std::map Accounts; +typedef std::map Accounts; /** @@ -101,7 +115,7 @@ class account_by_name * Operator(). */ bool - operator()(std::pair elem) const + operator()(std::pair elem) const { return (elem.first)->getName() == mName; } @@ -255,7 +269,7 @@ class Storage * @param account the new account. */ virtual void - addAccount(Account* account) = 0; + addAccount(const Account* account) = 0; /** diff --git a/src/tests/testaccount.cpp b/src/tests/testaccount.cpp index 987ab81..a086ef6 100644 --- a/src/tests/testaccount.cpp +++ b/src/tests/testaccount.cpp @@ -70,36 +70,22 @@ AccountTest::tearDown(void) /** - * Test creating an Account using the default constructor - * and setting the account info using the mutators. + * Test creating an Account passing the initial account info + * to the constructor. */ void AccountTest::testCreate1(void) { const std::string name("frodo"); const std::string password("baggins"); - const std::string encrypted("d70d266f4c276b5706881a46f43a88b0"); const std::string email("frodo@theshire.com"); - Account account; - account.setName(name); - account.setPassword(password); - account.setEmail(email); - account.setCharacters(mCharacters); - - CPPUNIT_ASSERT_EQUAL(account.getName(), name); - CPPUNIT_ASSERT_EQUAL(account.getPassword(), encrypted); - CPPUNIT_ASSERT_EQUAL(account.getEmail(), email); - - CPPUNIT_ASSERT_EQUAL(mAccount->getCharacters().size(), - mCharacters.size()); - - Beings& characters = account.getCharacters(); + Account account(name, password, email); - for (size_t i = 0; i < mCharacters.size(); ++i) { - CPPUNIT_ASSERT_EQUAL(characters[i]->getName(), - mCharacters[i]->getName()); - } + CPPUNIT_ASSERT_EQUAL(name, account.getName()); + CPPUNIT_ASSERT_EQUAL(password, account.getPassword()); + CPPUNIT_ASSERT_EQUAL(email, account.getEmail()); + CPPUNIT_ASSERT_EQUAL((size_t) 0, account.getCharacters().size()); } @@ -112,17 +98,16 @@ AccountTest::testCreate2(void) { const std::string name("frodo"); const std::string password("baggins"); - const std::string encrypted("d70d266f4c276b5706881a46f43a88b0"); const std::string email("frodo@theshire.com"); Account account(name, password, email, mCharacters); - CPPUNIT_ASSERT_EQUAL(account.getName(), name); - CPPUNIT_ASSERT_EQUAL(account.getPassword(), encrypted); - CPPUNIT_ASSERT_EQUAL(account.getEmail(), email); + CPPUNIT_ASSERT_EQUAL(name, account.getName()); + CPPUNIT_ASSERT_EQUAL(password, account.getPassword()); + CPPUNIT_ASSERT_EQUAL(email, account.getEmail()); - CPPUNIT_ASSERT_EQUAL(mAccount->getCharacters().size(), - mCharacters.size()); + CPPUNIT_ASSERT_EQUAL(mCharacters.size(), + mAccount->getCharacters().size()); Beings& characters = account.getCharacters(); @@ -143,7 +128,7 @@ AccountTest::testAddCharacter1(void) mAccount->addCharacter(bilbo); - CPPUNIT_ASSERT_EQUAL(mAccount->getCharacters().size(), (size_t) 4); + CPPUNIT_ASSERT_EQUAL((size_t) 4, mAccount->getCharacters().size()); std::vector names; names.push_back("sam"); @@ -152,7 +137,7 @@ AccountTest::testAddCharacter1(void) names.push_back("bilbo"); for (size_t i = 0; i < mCharacters.size(); ++i) { - CPPUNIT_ASSERT_EQUAL(mCharacters[i]->getName(), names[i]); + CPPUNIT_ASSERT_EQUAL(names[i], mCharacters[i]->getName()); } delete bilbo; @@ -167,7 +152,7 @@ AccountTest::testAddCharacter2(void) { mAccount->addCharacter(NULL); - CPPUNIT_ASSERT_EQUAL(mAccount->getCharacters().size(), (size_t) 3); + CPPUNIT_ASSERT_EQUAL((size_t) 3, mAccount->getCharacters().size()); std::vector names; names.push_back("sam"); @@ -175,7 +160,7 @@ AccountTest::testAddCharacter2(void) names.push_back("pippin"); for (size_t i = 0; i < mCharacters.size(); ++i) { - CPPUNIT_ASSERT_EQUAL(mCharacters[i]->getName(), names[i]); + CPPUNIT_ASSERT_EQUAL(names[i], mCharacters[i]->getName()); } } @@ -191,7 +176,7 @@ AccountTest::testGetCharacter1(void) Being* merry = mAccount->getCharacter(name); CPPUNIT_ASSERT(merry != 0); - CPPUNIT_ASSERT_EQUAL(merry->getName(), name); + CPPUNIT_ASSERT_EQUAL(name, merry->getName()); } diff --git a/src/tests/testaccount.h b/src/tests/testaccount.h index 8806e76..fc2363c 100644 --- a/src/tests/testaccount.h +++ b/src/tests/testaccount.h @@ -64,8 +64,8 @@ class AccountTest: public CppUnit::TestFixture /** - * Test creating an Account using the default constructor - * and setting the account info using the mutators. + * Test creating an Account passing the initial account info + * to the constructor. */ void testCreate1(void); diff --git a/src/tests/testcipher.cpp b/src/tests/testcipher.cpp index 0c40fdf..d51a440 100644 --- a/src/tests/testcipher.cpp +++ b/src/tests/testcipher.cpp @@ -63,7 +63,7 @@ CipherTest::testMd5_1(void) const std::string expected("d41d8cd98f00b204e9800998ecf8427e"); std::string actual(Cipher::instance().md5("")); - CPPUNIT_ASSERT_EQUAL(actual, expected); + CPPUNIT_ASSERT_EQUAL(expected, actual); } @@ -76,7 +76,7 @@ CipherTest::testMd5_2(void) const std::string expected("0cc175b9c0f1b6a831c399e269772661"); std::string actual(Cipher::instance().md5("a")); - CPPUNIT_ASSERT_EQUAL(actual, expected); + CPPUNIT_ASSERT_EQUAL(expected, actual); } @@ -89,7 +89,7 @@ CipherTest::testMd5_3(void) const std::string expected("900150983cd24fb0d6963f7d28e17f72"); std::string actual(Cipher::instance().md5("abc")); - CPPUNIT_ASSERT_EQUAL(actual, expected); + CPPUNIT_ASSERT_EQUAL(expected, actual); } @@ -102,7 +102,7 @@ CipherTest::testMd5_4(void) const std::string expected("f96b697d7cb7938d525a2f31aaf161d0"); std::string actual(Cipher::instance().md5("message digest")); - CPPUNIT_ASSERT_EQUAL(actual, expected); + CPPUNIT_ASSERT_EQUAL(expected, actual); } @@ -115,7 +115,7 @@ CipherTest::testMd5_5(void) const std::string expected("c3fcd3d76192e4007dfb496cca67e13b"); std::string actual(Cipher::instance().md5("abcdefghijklmnopqrstuvwxyz")); - CPPUNIT_ASSERT_EQUAL(actual, expected); + CPPUNIT_ASSERT_EQUAL(expected, actual); } @@ -132,7 +132,7 @@ CipherTest::testMd5_6(void) s += "0123456789"; std::string actual(Cipher::instance().md5(s)); - CPPUNIT_ASSERT_EQUAL(actual, expected); + CPPUNIT_ASSERT_EQUAL(expected, actual); } @@ -150,5 +150,5 @@ CipherTest::testMd5_7(void) } std::string actual(Cipher::instance().md5(s)); - CPPUNIT_ASSERT_EQUAL(actual, expected); + CPPUNIT_ASSERT_EQUAL(expected, actual); } diff --git a/src/tests/teststorage.cpp b/src/tests/teststorage.cpp index ac83151..59a5fd4 100644 --- a/src/tests/teststorage.cpp +++ b/src/tests/teststorage.cpp @@ -26,7 +26,6 @@ #include #include "../utils/cipher.h" - #include "../dalstoragesql.h" #include "../storage.h" #include "teststorage.h" @@ -92,13 +91,13 @@ StorageTest::testGetAccount1(void) CPPUNIT_ASSERT(myStorage.isOpen()); - Account* account = myStorage.getAccount("kindjal"); + std::string name("frodo"); + Account* account = myStorage.getAccount(name); using namespace tmwserv::utils; - std::string name("kindjal"); - std::string password(Cipher::instance().md5("kindjal")); - std::string email("kindjal@domain"); + std::string password(Cipher::instance().md5(name)); + std::string email("frodo@domain"); CPPUNIT_ASSERT(account != 0); CPPUNIT_ASSERT_EQUAL(account->getName(), name); @@ -125,13 +124,200 @@ StorageTest::testGetAccount2(void) } +/** + * Test passing a null pointer to addAcccount(). + */ +void +StorageTest::testAddAccount1(void) +{ + Storage& myStorage = Storage::instance(mStorageName); + + if (!myStorage.isOpen()) { + CPPUNIT_FAIL("the storage is not opened."); + } + + // TODO: when addAccount will throw exceptions, test the exceptions + // thrown. + // nothing should happen at the moment. + myStorage.addAccount(NULL); + myStorage.flush(); + +#if defined (MYSQL_SUPPORT) || defined (POSTGRESQL_SUPPORT) || \ + defined (SQLITE_SUPPORT) + + using namespace tmwserv::dal; + + std::auto_ptr 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); + + std::string frodo("frodo"); + std::string merry("merry"); + std::string pippin("pippin"); + + CPPUNIT_ASSERT_EQUAL(rs(0, "username"), frodo); + CPPUNIT_ASSERT_EQUAL(rs(1, "username"), merry); + CPPUNIT_ASSERT_EQUAL(rs(2, "username"), pippin); + + 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"); + } +#else + // if we are in this block it means that we are not using a database + // to persist the data from the storage. + // at the moment, Storage assume that the data are persisted in a database + // so let's raise a preprocessing error. +#error "no database backend defined" +#endif +} + + +/** + * Test adding a new account. + */ +void +StorageTest::testAddAccount2(void) +{ + Storage& myStorage = Storage::instance(mStorageName); + + if (!myStorage.isOpen()) { + CPPUNIT_FAIL("the storage is not opened."); + } + + // prepare new account. + std::string sam1("sam1"); + std::string sam2("sam2"); + Being* b1 = new Being(sam1, 1, 1, 1, 1, 1, 1, 1, 1); + Being* b2 = new Being(sam2, 1, 1, 1, 1, 1, 1, 1, 1); + Beings characters; + characters.push_back(b1); + characters.push_back(b2); + + std::string sam("sam"); + Account* 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 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); + + std::string frodo("frodo"); + std::string merry("merry"); + std::string pippin("pippin"); + + CPPUNIT_ASSERT_EQUAL(rs(0, "username"), frodo); + CPPUNIT_ASSERT_EQUAL(rs(1, "username"), merry); + CPPUNIT_ASSERT_EQUAL(rs(2, "username"), pippin); + CPPUNIT_ASSERT_EQUAL(rs(3, "username"), sam); + + sql = "select * from "; + sql += CHARACTERS_TBL_NAME; + sql += " where user_id = '"; + sql += sam; + sql += "';"; + + db->execSql(sql); + + CPPUNIT_ASSERT(rs.rows() == 2); + + CPPUNIT_ASSERT_EQUAL(rs(0, "name"), sam1); + CPPUNIT_ASSERT_EQUAL(rs(1, "name"), sam2); + + 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"); + } +#else + // if we are in this block it means that we are not using a database + // to persist the data from the storage. + // at the moment, Storage assume that the data are persisted in a database + // so let's raise a preprocessing error. +#error "no database backend defined" +#endif +} + + +/** + * Test updating an existing account. + */ +void +StorageTest::testUpdAccount1(void) +{ + // TODO +} + + /** * Initialize the storage. */ void StorageTest::initStorage(void) { -#if defined (MYSQL_SUPPORT) || defined (POSTGRE_SUPPORT) || \ +#if defined (MYSQL_SUPPORT) || defined (POSTGRESQL_SUPPORT) || \ defined (SQLITE_SUPPORT) // we are using a database to persist the data from the storage. @@ -177,7 +363,9 @@ StorageTest::initStorage(void) db->execSql(SQL_INVENTORIES_TABLE); // populate the tables. - insertAccount(db, "kindjal"); + insertAccount(db, "frodo"); + insertAccount(db, "merry"); + insertAccount(db, "pippin"); db->disconnect(); } @@ -212,7 +400,7 @@ StorageTest::initStorage(void) void StorageTest::cleanStorage(void) { -#if defined (MYSQL_SUPPORT) || defined (POSTGRE_SUPPORT) || \ +#if defined (MYSQL_SUPPORT) || defined (POSTGRESQL_SUPPORT) || \ defined (SQLITE_SUPPORT) // we are using a database to persist the data from the storage. @@ -302,8 +490,9 @@ StorageTest::insertAccount(std::auto_ptr& db, // the password will be identical to the name. sql << "insert into " << ACCOUNTS_TBL_NAME << " values " - << "(null, '" << name << "', '" << name << "', '" - << name << "@domain', 1, 0);"; + << "(null, '" << name << "', '" + << tmwserv::utils::Cipher::instance().md5(name) << "', '" + << name << "@domain', 0, 0);"; db->execSql(sql.str()); } diff --git a/src/tests/teststorage.h b/src/tests/teststorage.h index f823073..1d71a86 100644 --- a/src/tests/teststorage.h +++ b/src/tests/teststorage.h @@ -52,6 +52,9 @@ class StorageTest: public CppUnit::TestFixture // add tests to the test suite. CPPUNIT_TEST(testGetAccount1); CPPUNIT_TEST(testGetAccount2); + CPPUNIT_TEST(testAddAccount1); + CPPUNIT_TEST(testAddAccount2); + CPPUNIT_TEST(testUpdAccount1); CPPUNIT_TEST_SUITE_END(); @@ -85,6 +88,27 @@ class StorageTest: public CppUnit::TestFixture testGetAccount2(void); + /** + * Test passing a null pointer to addAcccount(). + */ + void + testAddAccount1(void); + + + /** + * Test adding a new account. + */ + void + testAddAccount2(void); + + + /** + * Test updating an existing account. + */ + void + testUpdAccount1(void); + + private: /** * Initialize the storage. -- cgit