diff options
author | Huynh Tran <nthuynh75@gmail.com> | 2005-06-28 21:17:36 +0000 |
---|---|---|
committer | Huynh Tran <nthuynh75@gmail.com> | 2005-06-28 21:17:36 +0000 |
commit | f83980082a8ee69b1356f58159867e1313ebf868 (patch) | |
tree | ef1def3a2412c64c1cf49bb02a864e8e6d709f40 /src | |
parent | 69979fb043a4dbaa1fb3f40584c6ad2a0cb5d39e (diff) | |
download | manaserv-f83980082a8ee69b1356f58159867e1313ebf868.tar.gz manaserv-f83980082a8ee69b1356f58159867e1313ebf868.tar.bz2 manaserv-f83980082a8ee69b1356f58159867e1313ebf868.tar.xz manaserv-f83980082a8ee69b1356f58159867e1313ebf868.zip |
Fixed bugs and added new unit tests.
Diffstat (limited to 'src')
-rw-r--r-- | src/account.h | 14 | ||||
-rw-r--r-- | src/dal/recordset.cpp | 5 | ||||
-rw-r--r-- | src/dalstorage.cpp | 53 | ||||
-rw-r--r-- | src/dalstoragesql.h | 4 | ||||
-rw-r--r-- | src/tests/teststorage.cpp | 342 | ||||
-rw-r--r-- | src/tests/teststorage.h | 28 |
6 files changed, 375 insertions, 71 deletions
diff --git a/src/account.h b/src/account.h index 704a6739..3eee1d5e 100644 --- a/src/account.h +++ b/src/account.h @@ -36,6 +36,19 @@ namespace tmwserv /** + * Notes: + * - change from the previous implementation: this class does not encrypt + * passwords anymore and will just store the passwords as they are + * passed to setPassword(). + * - the encryption should and must be performed externally from this + * class or else we would end up with the password being encrypted many + * times (e.g setPassword(getPassword()) would encrypt the password + * twice or setPassword(encrypted_password_from_database) would also + * encrypt the password twice). + */ + + +/** * A player account. */ class Account @@ -94,7 +107,6 @@ class Account /** * Set the user password. - * The password will be encrypted before saved into the storage. * * @param password the user password. */ diff --git a/src/dal/recordset.cpp b/src/dal/recordset.cpp index ae335f5e..f404c2a2 100644 --- a/src/dal/recordset.cpp +++ b/src/dal/recordset.cpp @@ -69,10 +69,7 @@ RecordSet::clear(void) bool RecordSet::isEmpty(void) const { - // we just need to check the size of the list of column headers - // as it is not possible to insert a new record if the column - // headers are not defined. - return (mHeaders.size() == 0); + return (mRows.size() == 0); } diff --git a/src/dalstorage.cpp b/src/dalstorage.cpp index 2a491564..b66e25a3 100644 --- a/src/dalstorage.cpp +++ b/src/dalstorage.cpp @@ -368,9 +368,17 @@ DALStorage::createTable(const std::string& tblName, } catch (const dal::DbSqlQueryExecFailure& e) { // error message to check against. +#if defined (MYSQL_SUPPORT) + std::string alreadyExists("Table '"); + alreadyExists += tblName; + alreadyExists += "' already exists"; +#elif defined (POSTGRESQL_SUPPORT) + // TODO +#else // SQLITE_SUPPORT std::string alreadyExists("table "); alreadyExists += tblName; alreadyExists += " already exists"; +#endif const std::string msg(e.what()); @@ -405,7 +413,7 @@ DALStorage::_addAccount(const Account* account) std::ostringstream sql1; sql1 << "insert into " << ACCOUNTS_TBL_NAME << " values (null, '" << account->getName() << "', '" - << utils::Cipher::instance().md5(account->getPassword()) << "', '" + << account->getPassword() << "', '" << account->getEmail() << "', " << account->getLevel() << ", 0);"; mDb->execSql(sql1.str()); @@ -490,22 +498,45 @@ DALStorage::_updAccount(const Account* account) << "where id = '" << (account_it->second).id << "';"; mDb->execSql(sql1.str()); - // insert the characters. + // get the list of characters that belong to this account. Beings& characters = (const_cast<Account*>(account))->getCharacters(); + // insert or update the characters. Beings::const_iterator it = characters.begin(); Beings::const_iterator it_end = characters.end(); + using namespace dal; + for (; it != it_end; ++it) { - // TODO: location on the map & statistics & inventories. + // check if the character already exists in the database + // (reminder: the character names are unique in the database). 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()); + sql2 << "select id from " << CHARACTERS_TBL_NAME + << " where name = '" << (*it)->getName() << "';"; + const RecordSet& charInfo = mDb->execSql(sql2.str()); + + // TODO: location on the map & statistics & inventories. + std::ostringstream sql3; + if (charInfo.rows() == 0) { + 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" + << ");"; + } + else { + sql3 << "update " << CHARACTERS_TBL_NAME + << " set name = '" << (*it)->getName() << "', " + << " gender = '" << (*it)->getGender() << "', " + << " level = '" << (*it)->getLevel() << "', " + << " money = '" << (*it)->getMoney() << "' " + << "where user_id = '" << (account_it->second).id + << "';"; + } + mDb->execSql(sql3.str()); } } diff --git a/src/dalstoragesql.h b/src/dalstoragesql.h index fd8e7661..eacb165d 100644 --- a/src/dalstoragesql.h +++ b/src/dalstoragesql.h @@ -25,7 +25,9 @@ #define _TMWSERV_DALSTORAGE_SQL_H_ -#if !defined (MYSQL_SUPPORT) && !defined (SQLITE_SUPPORT) && !defined (POSTGRESQL_SUPPORT) +#if !defined (MYSQL_SUPPORT) && !defined (SQLITE_SUPPORT) && \ + !defined (POSTGRESQL_SUPPORT) + #error "(dalstorage.h) no database backend defined" #endif diff --git a/src/tests/teststorage.cpp b/src/tests/teststorage.cpp index 59a5fd4f..6836bc56 100644 --- a/src/tests/teststorage.cpp +++ b/src/tests/teststorage.cpp @@ -21,6 +21,17 @@ */ +#if !defined (MYSQL_SUPPORT) && !defined (SQLITE_SUPPORT) && \ + !defined (POSTGRESQL_SUPPORT) + + // 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 + + #include <sstream> #include <physfs.h> @@ -91,18 +102,18 @@ StorageTest::testGetAccount1(void) CPPUNIT_ASSERT(myStorage.isOpen()); - std::string name("frodo"); + const std::string name("frodo"); Account* account = myStorage.getAccount(name); using namespace tmwserv::utils; - std::string password(Cipher::instance().md5(name)); - std::string email("frodo@domain"); + const std::string password(Cipher::instance().md5(name)); + const std::string email("frodo@domain"); CPPUNIT_ASSERT(account != 0); - CPPUNIT_ASSERT_EQUAL(account->getName(), name); - CPPUNIT_ASSERT_EQUAL(account->getPassword(), password); - CPPUNIT_ASSERT_EQUAL(account->getEmail(), email); + CPPUNIT_ASSERT_EQUAL(name, account->getName()); + CPPUNIT_ASSERT_EQUAL(password, account->getPassword()); + CPPUNIT_ASSERT_EQUAL(email, account->getEmail()); } @@ -165,13 +176,13 @@ StorageTest::testAddAccount1(void) CPPUNIT_ASSERT(rs.rows() == 3); - std::string frodo("frodo"); - std::string merry("merry"); - std::string pippin("pippin"); + const std::string frodo("frodo"); + const std::string merry("merry"); + const 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(frodo, rs(0, "username")); + CPPUNIT_ASSERT_EQUAL(merry, rs(1, "username")); + CPPUNIT_ASSERT_EQUAL(pippin, rs(2, "username")); db->disconnect(); } @@ -190,12 +201,6 @@ StorageTest::testAddAccount1(void) 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 } @@ -213,15 +218,15 @@ StorageTest::testAddAccount2(void) } // prepare new account. - std::string sam1("sam1"); - std::string sam2("sam2"); + const std::string sam1("sam1"); + const 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"); + const std::string sam("sam"); Account* acc = new Account(sam, sam, "sam@domain", characters); // TODO: when addAccount will throw exceptions, test the exceptions @@ -252,14 +257,14 @@ StorageTest::testAddAccount2(void) CPPUNIT_ASSERT(rs.rows() == 4); - std::string frodo("frodo"); - std::string merry("merry"); - std::string pippin("pippin"); + const std::string frodo("frodo"); + const std::string merry("merry"); + const 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); + 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; @@ -271,8 +276,8 @@ StorageTest::testAddAccount2(void) CPPUNIT_ASSERT(rs.rows() == 2); - CPPUNIT_ASSERT_EQUAL(rs(0, "name"), sam1); - CPPUNIT_ASSERT_EQUAL(rs(1, "name"), sam2); + CPPUNIT_ASSERT_EQUAL(sam1, rs(0, "name")); + CPPUNIT_ASSERT_EQUAL(sam2, rs(1, "name")); db->disconnect(); } @@ -291,23 +296,272 @@ StorageTest::testAddAccount2(void) 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. + * Test updating an existing account with new characters. */ void StorageTest::testUpdAccount1(void) { - // TODO + Storage& myStorage = Storage::instance(mStorageName); + + CPPUNIT_ASSERT(myStorage.isOpen()); + + // get an existing account. + const std::string name("frodo"); + Account* account = myStorage.getAccount(name); + + // create new characters. + const std::string sam1("sam1"); + const 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); + + // add the characters to the account. + account->addCharacter(b1); + account->addCharacter(b2); + + // 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 = '"; + sql += frodo; + sql += "';"; + + 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 +} + + +/** + * Test updating an existing account with a new password and new + * character stats. + */ +void +StorageTest::testUpdAccount2(void) +{ + Storage& myStorage = Storage::instance(mStorageName); + + CPPUNIT_ASSERT(myStorage.isOpen()); + + // get an existing account. + const std::string name("frodo"); + Account* account = myStorage.getAccount(name); + + // create new characters. + const std::string sam1("sam1"); + const 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); + + // add the characters to the account. + account->addCharacter(b1); + account->addCharacter(b2); + + // update the database. + myStorage.flush(); + + // change the account password. + using tmwserv::utils::Cipher; + const std::string newPassword(Cipher::instance().md5("myprecious")); + account->setPassword(newPassword); + + // change the strength of the first character. + // TODO: at the moment, there are no mutators defined for the Being class. + + // 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")); + + CPPUNIT_ASSERT_EQUAL(newPassword, rs(0, "password")); + + sql = "select * from "; + sql += CHARACTERS_TBL_NAME; + sql += " where user_id = '"; + sql += frodo; + sql += "';"; + + db->execSql(sql); + + CPPUNIT_ASSERT(rs.rows() == 2); + + CPPUNIT_ASSERT_EQUAL(sam1, rs(0, "name")); + CPPUNIT_ASSERT_EQUAL(sam2, rs(1, "name")); + + // TODO: when the mutators are implemented for the Being class, + // check the strength of the first character. + + 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 +} + + +/** + * Test deleting an account that exists in the database but not + * loaded yet in memory. + */ +void +StorageTest::testDelAccount1(void) +{ + Storage& myStorage = Storage::instance(mStorageName); + + CPPUNIT_ASSERT(myStorage.isOpen()); + + myStorage.delAccount("frodo"); + +#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() == 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")); + + 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 } @@ -384,12 +638,6 @@ StorageTest::initStorage(void) 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 } @@ -449,12 +697,6 @@ StorageTest::cleanStorage(void) 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 } diff --git a/src/tests/teststorage.h b/src/tests/teststorage.h index 1d71a860..da1eae8e 100644 --- a/src/tests/teststorage.h +++ b/src/tests/teststorage.h @@ -25,6 +25,8 @@ #define _TMWSERV_TEST_STORAGE_H_ +#include <vector> + #include <cppunit/extensions/HelperMacros.h> #include "../dal/dataproviderfactory.h" @@ -55,6 +57,8 @@ class StorageTest: public CppUnit::TestFixture CPPUNIT_TEST(testAddAccount1); CPPUNIT_TEST(testAddAccount2); CPPUNIT_TEST(testUpdAccount1); + CPPUNIT_TEST(testUpdAccount2); + CPPUNIT_TEST(testDelAccount1); CPPUNIT_TEST_SUITE_END(); @@ -103,12 +107,28 @@ class StorageTest: public CppUnit::TestFixture /** - * Test updating an existing account. + * Test updating an existing account with new characters. */ void testUpdAccount1(void); + /** + * Test updating an existing account with a new password and new + * character stats. + */ + void + testUpdAccount2(void); + + + /** + * Test deleting an account that exists in the database but not + * loaded yet in memory. + */ + void + testDelAccount1(void); + + private: /** * Initialize the storage. @@ -147,9 +167,9 @@ class StorageTest: public CppUnit::TestFixture private: - static std::string mStorageName; - static std::string mStorageUser; - static std::string mStorageUserPassword; + static std::string mStorageName; /**< name of the storage */ + static std::string mStorageUser; /**< storage user */ + static std::string mStorageUserPassword; /**< user password */ }; |