summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHuynh Tran <nthuynh75@gmail.com>2005-06-21 22:43:23 +0000
committerHuynh Tran <nthuynh75@gmail.com>2005-06-21 22:43:23 +0000
commit460a5bb2a9f57ddf9dbbd7095452c3c4fc660d65 (patch)
treeababb79e615ec1e2fcd82a4d2ddd1520c7c9179d /src
parent270163b535f64f2fd6baa32d8a76ecc1c5526539 (diff)
downloadmanaserv-460a5bb2a9f57ddf9dbbd7095452c3c4fc660d65.tar.gz
manaserv-460a5bb2a9f57ddf9dbbd7095452c3c4fc660d65.tar.bz2
manaserv-460a5bb2a9f57ddf9dbbd7095452c3c4fc660d65.tar.xz
manaserv-460a5bb2a9f57ddf9dbbd7095452c3c4fc660d65.zip
Reorganized unit tests and initial release of the unit tests for the Storage class (to be completed).
Diffstat (limited to 'src')
-rw-r--r--src/dal/sqlitedataprovider.cpp4
-rw-r--r--src/tests/testaccount.cpp (renamed from src/testaccount.cpp)1
-rw-r--r--src/tests/testaccount.h (renamed from src/testaccount.h)2
-rw-r--r--src/tests/testcipher.cpp (renamed from src/utils/testcipher.cpp)2
-rw-r--r--src/tests/testcipher.h (renamed from src/utils/testcipher.h)0
-rw-r--r--src/tests/testdataprovider.cpp (renamed from src/dal/testdataprovider.cpp)175
-rw-r--r--src/tests/testdataprovider.h (renamed from src/dal/testdataprovider.h)44
-rw-r--r--src/tests/testrecordset.cpp (renamed from src/dal/testrecordset.cpp)1
-rw-r--r--src/tests/testrecordset.h (renamed from src/dal/testrecordset.h)14
-rw-r--r--src/tests/testsmain.cpp (renamed from src/testsmain.cpp)21
-rw-r--r--src/tests/teststorage.cpp310
-rw-r--r--src/tests/teststorage.h132
12 files changed, 666 insertions, 40 deletions
diff --git a/src/dal/sqlitedataprovider.cpp b/src/dal/sqlitedataprovider.cpp
index a9ed365d..00d8298c 100644
--- a/src/dal/sqlitedataprovider.cpp
+++ b/src/dal/sqlitedataprovider.cpp
@@ -91,6 +91,10 @@ SqLiteDataProvider::connect(const std::string& dbName,
// the database after an unsuccessful call to sqlite3_open().
sqlite3_close(mDb);
+ // FIXME
+ // 21-Jun-2005: although we did invoke sqlite3_close(), there
+ // seems to be still a leak of 136 bytes here.
+
throw DbConnectionFailure(msg);
}
diff --git a/src/testaccount.cpp b/src/tests/testaccount.cpp
index 0198ff13..a4061164 100644
--- a/src/testaccount.cpp
+++ b/src/tests/testaccount.cpp
@@ -65,6 +65,7 @@ AccountTest::tearDown(void)
}
delete mAccount;
+ mAccount = 0;
}
diff --git a/src/testaccount.h b/src/tests/testaccount.h
index ee66bc9a..8806e766 100644
--- a/src/testaccount.h
+++ b/src/tests/testaccount.h
@@ -27,7 +27,7 @@
#include <cppunit/extensions/HelperMacros.h>
-#include "account.h"
+#include "../account.h"
/**
diff --git a/src/utils/testcipher.cpp b/src/tests/testcipher.cpp
index 6d2c03d1..0c40fdf9 100644
--- a/src/utils/testcipher.cpp
+++ b/src/tests/testcipher.cpp
@@ -23,7 +23,7 @@
#include <string>
-#include "cipher.h"
+#include "../utils/cipher.h"
#include "testcipher.h"
diff --git a/src/utils/testcipher.h b/src/tests/testcipher.h
index 7db81803..7db81803 100644
--- a/src/utils/testcipher.h
+++ b/src/tests/testcipher.h
diff --git a/src/dal/testdataprovider.cpp b/src/tests/testdataprovider.cpp
index 08b66da8..06a2b0ee 100644
--- a/src/dal/testdataprovider.cpp
+++ b/src/tests/testdataprovider.cpp
@@ -21,7 +21,16 @@
*/
-#include "dataproviderfactory.h"
+#include <physfs.h>
+
+#if defined (MYSQL_SUPPORT)
+#include <mysql/mysql.h>
+#elif defined (POSTGRE_SUPPORT)
+#include <libpq-fe.h>
+#endif
+
+#include "../dal/dataproviderfactory.h"
+
#include "testdataprovider.h"
@@ -29,6 +38,21 @@
CPPUNIT_TEST_SUITE_REGISTRATION(DataProviderTest);
+// initialize the static variables.
+std::string DataProviderTest::mDbName("tmwteststorage");
+std::string DataProviderTest::mDbUser("guest");
+std::string DataProviderTest::mDbPassword("guest");
+std::string DataProviderTest::mSqlCreateTable(
+ "create table employees ("
+ " id integer primary key, "
+ " name varchar(32) not null);"
+);
+std::string DataProviderTest::mSqlInsertRow(
+ "insert into employees values (1, 'john');"
+);
+std::string DataProviderTest::mSqlFetchRow("select * from employees;");
+
+
using namespace tmwserv::dal;
@@ -38,6 +62,9 @@ using namespace tmwserv::dal;
void
DataProviderTest::setUp(void)
{
+ // reinitialize the database before each test.
+ reinitDb();
+
// obtain a data provider.
try {
mDb = DataProviderFactory::createDataProvider();
@@ -45,24 +72,6 @@ DataProviderTest::setUp(void)
catch (const std::runtime_error& e) {
CPPUNIT_FAIL(e.what());
}
-
- // init db info and account.
-#ifdef SQLITE_SUPPORT
- mDbName = "mydb.db";
-#else
- mDbName = "mydb";
-#endif
- mDbUser = "guest";
- mDbPassword = "guest";
-
- // init SQL queries.
- mSqlCreateTable = "create table employees (";
- mSqlCreateTable += " id int primary key, ";
- mSqlCreateTable += " name varchar(32) not null);";
-
- mSqlInsertRow = "insert into employees values (1, 'john');";
-
- mSqlFetchRow = "select * from employees;";
}
@@ -72,7 +81,13 @@ DataProviderTest::setUp(void)
void
DataProviderTest::tearDown(void)
{
+ mDb->disconnect();
+
delete mDb;
+ mDb = 0;
+
+ // clean the database after each test.
+ reinitDb();
}
@@ -82,7 +97,15 @@ DataProviderTest::tearDown(void)
void
DataProviderTest::testConnection1(void)
{
+#ifdef SQLITE_SUPPORT
+ std::string dbFile(mDbName);
+ dbFile += ".db";
+
+ mDb->connect(dbFile, mDbUser, mDbPassword);
+#else
mDb->connect(mDbName, mDbUser, mDbPassword);
+#endif
+
CPPUNIT_ASSERT(mDb->isConnected());
}
@@ -93,7 +116,15 @@ DataProviderTest::testConnection1(void)
void
DataProviderTest::testCreateTable1(void)
{
+#ifdef SQLITE_SUPPORT
+ std::string dbFile(mDbName);
+ dbFile += ".db";
+
+ mDb->connect(dbFile, mDbUser, mDbPassword);
+#else
mDb->connect(mDbName, mDbUser, mDbPassword);
+#endif
+
CPPUNIT_ASSERT(mDb->isConnected());
const RecordSet& rs = mDb->execSql(mSqlCreateTable);
@@ -110,11 +141,20 @@ DataProviderTest::testCreateTable1(void)
void
DataProviderTest::testCreateTable2(void)
{
+#ifdef SQLITE_SUPPORT
+ std::string dbFile(mDbName);
+ dbFile += ".db";
+
+ mDb->connect(dbFile, mDbUser, mDbPassword);
+#else
mDb->connect(mDbName, mDbUser, mDbPassword);
+#endif
+
CPPUNIT_ASSERT(mDb->isConnected());
+ mDb->execSql(mSqlCreateTable);
// this should throw tmwserv::dal::DbSqlQueryExecFailure.
- const RecordSet& rs = mDb->execSql(mSqlCreateTable);
+ mDb->execSql(mSqlCreateTable);
}
@@ -124,9 +164,19 @@ DataProviderTest::testCreateTable2(void)
void
DataProviderTest::testInsert1(void)
{
+#ifdef SQLITE_SUPPORT
+ std::string dbFile(mDbName);
+ dbFile += ".db";
+
+ mDb->connect(dbFile, mDbUser, mDbPassword);
+#else
mDb->connect(mDbName, mDbUser, mDbPassword);
+#endif
+
CPPUNIT_ASSERT(mDb->isConnected());
+ mDb->execSql(mSqlCreateTable);
+
const RecordSet& rs = mDb->execSql(mSqlInsertRow);
// an insert query does not return any records
// so the recordset remains empty.
@@ -143,7 +193,15 @@ DataProviderTest::testInsert1(void)
void
DataProviderTest::testInsert2(void)
{
+#ifdef SQLITE_SUPPORT
+ std::string dbFile(mDbName);
+ dbFile += ".db";
+
+ mDb->connect(dbFile, mDbUser, mDbPassword);
+#else
mDb->connect(mDbName, mDbUser, mDbPassword);
+#endif
+
CPPUNIT_ASSERT(mDb->isConnected());
// this should throw tmwserv::dal::DbSqlQueryExecFailure
@@ -158,9 +216,20 @@ DataProviderTest::testInsert2(void)
void
DataProviderTest::testFetch1(void)
{
+#ifdef SQLITE_SUPPORT
+ std::string dbFile(mDbName);
+ dbFile += ".db";
+
+ mDb->connect(dbFile, mDbUser, mDbPassword);
+#else
mDb->connect(mDbName, mDbUser, mDbPassword);
+#endif
+
CPPUNIT_ASSERT(mDb->isConnected());
+ mDb->execSql(mSqlCreateTable);
+ mDb->execSql(mSqlInsertRow);
+
const RecordSet& rs = mDb->execSql(mSqlFetchRow);
CPPUNIT_ASSERT(!rs.isEmpty());
@@ -180,7 +249,15 @@ DataProviderTest::testFetch1(void)
void
DataProviderTest::testDisconnection1(void)
{
+#ifdef SQLITE_SUPPORT
+ std::string dbFile(mDbName);
+ dbFile += ".db";
+
+ mDb->connect(dbFile, mDbUser, mDbPassword);
+#else
mDb->connect(mDbName, mDbUser, mDbPassword);
+#endif
+
CPPUNIT_ASSERT(mDb->isConnected());
mDb->disconnect();
@@ -197,3 +274,61 @@ DataProviderTest::testDisconnection2(void)
mDb->disconnect();
CPPUNIT_ASSERT(!mDb->isConnected());
}
+
+
+/**
+ * Reinitialize the database.
+ */
+void
+DataProviderTest::reinitDb(void)
+{
+ // we are not using DataProvider::execSql() to execute the SQL queries
+ // here as the class is the purpose of these tests.
+
+#if defined (MYSQL_SUPPORT)
+ {
+ // initialize the MySQL library.
+ MYSQL* db = mysql_init(NULL);
+
+ if (!db) {
+ CPPUNIT_FAIL("unable to initialize the MySQL library: no memory");
+ }
+
+ // connect to the database.
+ if (!mysql_real_connect(db,
+ NULL,
+ mDbUser.c_str(),
+ mDbPassword.c_str(),
+ mDbName.c_str(),
+ 0,
+ NULL,
+ 0))
+ {
+ CPPUNIT_FAIL(mysql_error(db));
+ }
+
+ // drop the table.
+ std::string sql("drop table employees;");
+ if (mysql_query(db, sql.c_str()) != 0) {
+ // ignore, the table may not exist.
+ }
+
+ // close the connection and free memory.
+ mysql_close(db);
+ mysql_library_end();
+ db = 0;
+ }
+#elif defined (POSTGRE_SUPPORT)
+ // TODO: drop tables.
+#else // SQLITE_SUPPORT
+ std::string dbFile(mDbName);
+ dbFile += ".db";
+
+ // ensure that the database file does not exist.
+ if (PHYSFS_exists(dbFile.c_str())) {
+ if (PHYSFS_delete(dbFile.c_str()) == 0) {
+ CPPUNIT_FAIL(PHYSFS_getLastError());
+ }
+ }
+#endif
+}
diff --git a/src/dal/testdataprovider.h b/src/tests/testdataprovider.h
index e677840a..1f0a082c 100644
--- a/src/dal/testdataprovider.h
+++ b/src/tests/testdataprovider.h
@@ -21,14 +21,26 @@
*/
-
#ifndef _TMWSERV_TEST_DATA_PROVIDER_H_
#define _TMWSERV_TEST_DATA_PROVIDER_H_
#include <cppunit/extensions/HelperMacros.h>
-#include "dalexcept.h"
+#include "../dal/dalexcept.h"
+#include "../dal/dataprovider.h"
+
+
+/**
+ * Requirements:
+ * - if using MySQL or PostgreSQL as backends, then make sure that a user
+ * named 'guest' with the password 'guest' has enough privileges to
+ * create tables and populate them in a database named 'tmwteststorage'
+ * prior to running the teststorage unit tests.
+ */
+
+
+using namespace tmwserv::dal;
/**
@@ -41,10 +53,9 @@ class DataProviderTest: public CppUnit::TestFixture
// add tests to the test suite.
CPPUNIT_TEST(testConnection1);
CPPUNIT_TEST(testCreateTable1);
- CPPUNIT_TEST_EXCEPTION(testCreateTable2,
- tmwserv::dal::DbSqlQueryExecFailure);
+ CPPUNIT_TEST_EXCEPTION(testCreateTable2, DbSqlQueryExecFailure);
CPPUNIT_TEST(testInsert1);
- CPPUNIT_TEST_EXCEPTION(testInsert2, tmwserv::dal::DbSqlQueryExecFailure);
+ CPPUNIT_TEST_EXCEPTION(testInsert2, DbSqlQueryExecFailure);
CPPUNIT_TEST(testFetch1);
CPPUNIT_TEST(testDisconnection1);
CPPUNIT_TEST(testDisconnection2);
@@ -124,14 +135,21 @@ class DataProviderTest: public CppUnit::TestFixture
private:
- tmwserv::dal::DataProvider* mDb; /**< the data provider */
- std::string mDbName; /**< the database name */
- std::string mDbPath; /**< the database path */
- std::string mDbUser; /**< the database user */
- std::string mDbPassword; /**< the database password */
- std::string mSqlCreateTable; /**< SQL query to create table */
- std::string mSqlInsertRow; /**< SQL query to delete table */
- std::string mSqlFetchRow; /**< SQL query to fetch data */
+ /**
+ * Reinitialize the database.
+ */
+ void
+ reinitDb(void);
+
+
+ private:
+ DataProvider* mDb; /**< the data provider */
+ static std::string mDbName; /**< the database name */
+ static std::string mDbUser; /**< the database user */
+ static std::string mDbPassword; /**< the database password */
+ static std::string mSqlCreateTable; /**< SQL query to create table */
+ static std::string mSqlInsertRow; /**< SQL query to delete table */
+ static std::string mSqlFetchRow; /**< SQL query to fetch data */
};
diff --git a/src/dal/testrecordset.cpp b/src/tests/testrecordset.cpp
index 3d8e928a..26a9e016 100644
--- a/src/dal/testrecordset.cpp
+++ b/src/tests/testrecordset.cpp
@@ -23,7 +23,6 @@
#include <sstream>
-#include "recordset.h"
#include "testrecordset.h"
diff --git a/src/dal/testrecordset.h b/src/tests/testrecordset.h
index 60b31137..66dc7117 100644
--- a/src/dal/testrecordset.h
+++ b/src/tests/testrecordset.h
@@ -27,7 +27,13 @@
#include <cppunit/extensions/HelperMacros.h>
-#include "dalexcept.h"
+#include <stdexcept>
+
+#include "../dal/dalexcept.h"
+#include "../dal/recordset.h"
+
+
+using namespace tmwserv::dal;
/**
@@ -54,7 +60,7 @@ class RecordSetTest: public CppUnit::TestFixture
CPPUNIT_TEST(testOutputStream2);
CPPUNIT_TEST(testAdd1);
CPPUNIT_TEST_EXCEPTION(testAdd2, std::invalid_argument);
- CPPUNIT_TEST_EXCEPTION(testAdd3, tmwserv::dal::RsColumnHeadersNotSet);
+ CPPUNIT_TEST_EXCEPTION(testAdd3, RsColumnHeadersNotSet);
CPPUNIT_TEST_SUITE_END();
@@ -201,8 +207,8 @@ class RecordSetTest: public CppUnit::TestFixture
private:
- tmwserv::dal::RecordSet mEmptyRs; /**< empty recordset */
- tmwserv::dal::RecordSet mNonEmptyRs; /**< recordset with some data */
+ RecordSet mEmptyRs; /**< empty recordset */
+ RecordSet mNonEmptyRs; /**< recordset with some data */
};
diff --git a/src/testsmain.cpp b/src/tests/testsmain.cpp
index 2f24cc48..70cdc185 100644
--- a/src/testsmain.cpp
+++ b/src/tests/testsmain.cpp
@@ -24,9 +24,27 @@
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/text/TextTestRunner.h>
+#include <physfs.h>
+
+
+/**
+ * Notes:
+ * - if the unit test application is linked to libsqlite3, there will
+ * be a memory leak (8 bytes) while no leaks are detected when linked
+ * to libmysqlclient. the leak was detected using Valgrind, an
+ * excellent memory debugger.
+ *
+ * TODO: check memory leak when linked to libpq (PostgreSQL).
+ */
+
int main(int argc, char* argv[])
{
+ // initialize the PhysicsFS library.
+ PHYSFS_init(argv[0]);
+ PHYSFS_addToSearchPath(".", 1);
+ PHYSFS_setWriteDir(".");
+
using namespace CppUnit;
// get the top level suite from the registry.
@@ -39,6 +57,9 @@ int main(int argc, char* argv[])
// run the tests.
bool wasSuccessful = runner.run();
+ // denitialize the PhysicsFS library.
+ PHYSFS_deinit();
+
// return error code 1 if the one of test failed.
return wasSuccessful ? 0 : 1;
}
diff --git a/src/tests/teststorage.cpp b/src/tests/teststorage.cpp
new file mode 100644
index 00000000..9757fdf3
--- /dev/null
+++ b/src/tests/teststorage.cpp
@@ -0,0 +1,310 @@
+/*
+ * 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$
+ */
+
+
+#include <sstream>
+
+#include <physfs.h>
+
+#include "../utils/cipher.h"
+
+#include "../dalstoragesql.h"
+#include "../storage.h"
+#include "teststorage.h"
+
+
+// register the fixture into the 'registry'
+CPPUNIT_TEST_SUITE_REGISTRATION(StorageTest);
+
+
+// initialization of static attributes.
+std::string StorageTest::mStorageName("tmwteststorage");
+std::string StorageTest::mStorageUser("guest");
+std::string StorageTest::mStorageUserPassword("guest");
+
+
+using namespace tmwserv;
+
+
+/**
+ * Set up fixtures.
+ */
+void
+StorageTest::setUp(void)
+{
+ // reinitialize the storage before each test.
+ initStorage();
+
+ // create a storage.
+ Storage& myStorage = Storage::instance(mStorageName);
+ myStorage.setUser(mStorageUser);
+ myStorage.setPassword(mStorageUserPassword);
+
+ // open the storage.
+ myStorage.open();
+}
+
+
+/**
+ * Tear down fixtures.
+ */
+void
+StorageTest::tearDown(void)
+{
+ // close the storage.
+ Storage& myStorage = Storage::instance(mStorageName);
+ myStorage.close();
+
+ // delete the storage.
+ Storage::destroy();
+
+ // clean the storage after each test.
+ cleanStorage();
+}
+
+
+/**
+ * Fetch an existing account from the database.
+ */
+void
+StorageTest::testGetAccount1(void)
+{
+ Storage& myStorage = Storage::instance(mStorageName);
+
+ CPPUNIT_ASSERT(myStorage.isOpen());
+
+ Account* account = myStorage.getAccount("kindjal");
+
+ using namespace tmwserv::utils;
+
+ std::string name("kindjal");
+ std::string password(Cipher::instance().md5("kindjal"));
+ std::string email("kindjal@domain");
+
+ CPPUNIT_ASSERT(account != 0);
+ CPPUNIT_ASSERT_EQUAL(account->getName(), name);
+ CPPUNIT_ASSERT_EQUAL(account->getPassword(), password);
+ CPPUNIT_ASSERT_EQUAL(account->getEmail(), email);
+}
+
+
+/**
+ * Fetch an unexisting account from the database.
+ */
+void
+StorageTest::testGetAccount2(void)
+{
+ Storage& myStorage = Storage::instance(mStorageName);
+
+ if (!myStorage.isOpen()) {
+ CPPUNIT_FAIL("the storage is not opened.");
+ }
+
+ Account* account = myStorage.getAccount("xxx");
+
+ CPPUNIT_ASSERT(account == 0);
+}
+
+
+/**
+ * Initialize the storage.
+ */
+void
+StorageTest::initStorage(void)
+{
+#if defined (MYSQL_SUPPORT) || defined (POSTGRE_SUPPORT) || \
+ defined (SQLITE_SUPPORT)
+
+ // we are using a database to persist the data from the storage.
+
+ using namespace tmwserv::dal;
+
+ // insert initial data using the data provider directly.
+ // we must avoid using the APIs from Storage here as it's the purpose
+ // of these tests.
+ std::auto_ptr<DataProvider> db(DataProviderFactory::createDataProvider());
+
+ try {
+#ifdef SQLITE_SUPPORT
+ std::string dbFile(mStorageName);
+ dbFile += ".db";
+
+ // ensure that the file does not exist before the tests begin.
+ if (PHYSFS_exists(dbFile.c_str())) {
+ if (PHYSFS_delete(dbFile.c_str()) == 0) {
+ CPPUNIT_FAIL(PHYSFS_getLastError());
+ }
+ }
+
+ db->connect(dbFile, mStorageUser, mStorageUserPassword);
+#else
+ db->connect(mStorageName, mStorageUser, mStorageUserPassword);
+#endif
+
+ // drop the tables.
+ dropTable(db, MAPS_TBL_NAME);
+ dropTable(db, ACCOUNTS_TBL_NAME);
+ dropTable(db, CHARACTERS_TBL_NAME);
+ dropTable(db, ITEMS_TBL_NAME);
+ dropTable(db, WORLD_ITEMS_TBL_NAME);
+ dropTable(db, INVENTORIES_TBL_NAME);
+
+ // recreate the tables.
+ db->execSql(SQL_MAPS_TABLE);
+ db->execSql(SQL_ACCOUNTS_TABLE);
+ db->execSql(SQL_CHARACTERS_TABLE);
+ db->execSql(SQL_ITEMS_TABLE);
+ db->execSql(SQL_WORLD_ITEMS_TABLE);
+ db->execSql(SQL_INVENTORIES_TABLE);
+
+ // populate the tables.
+ insertAccount(db, "kindjal");
+
+ 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
+}
+
+
+/**
+ * Clean the storage.
+ */
+void
+StorageTest::cleanStorage(void)
+{
+#if defined (MYSQL_SUPPORT) || defined (POSTGRE_SUPPORT) || \
+ defined (SQLITE_SUPPORT)
+
+ // we are using a database to persist the data from the storage.
+
+ using namespace tmwserv::dal;
+
+ std::auto_ptr<DataProvider> db(DataProviderFactory::createDataProvider());
+
+ try {
+#ifdef SQLITE_SUPPORT
+ std::string dbFile(mStorageName);
+ dbFile += ".db";
+
+ // ensure that the file does not exist before the tests begin.
+ if (PHYSFS_exists(dbFile.c_str())) {
+ if (PHYSFS_delete(dbFile.c_str()) == 0) {
+ CPPUNIT_FAIL(PHYSFS_getLastError());
+ }
+ }
+#else
+ db->connect(mStorageName, mStorageUser, mStorageUserPassword);
+
+ // drop the tables.
+ dropTable(db, MAPS_TBL_NAME);
+ dropTable(db, ACCOUNTS_TBL_NAME);
+ dropTable(db, CHARACTERS_TBL_NAME);
+ dropTable(db, ITEMS_TBL_NAME);
+ dropTable(db, WORLD_ITEMS_TBL_NAME);
+ dropTable(db, INVENTORIES_TBL_NAME);
+
+ db->disconnect();
+#endif
+ }
+ 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
+}
+
+
+/**
+ * Drop a table.
+ */
+void
+StorageTest::dropTable(std::auto_ptr<DataProvider>& db,
+ const std::string& name)
+{
+ try {
+ std::string sql("drop table ");
+ sql += name;
+ sql += ";";
+ db->execSql(sql);
+ }
+ catch (const DbSqlQueryExecFailure& e) {
+ // ignore, the table may not exist.
+ }
+}
+
+
+/**
+ * Insert a new account.
+ */
+void
+StorageTest::insertAccount(std::auto_ptr<DataProvider>& db,
+ const std::string& name)
+{
+ std::ostringstream sql;
+
+ // the password will be identical to the name.
+
+ sql << "insert into " << ACCOUNTS_TBL_NAME
+ << "(username, password, email, level, banned) values "
+ << "('" << name << "', '" << name << "', '"
+ << name << "@domain', 1, 0);";
+
+ db->execSql(sql.str());
+}
diff --git a/src/tests/teststorage.h b/src/tests/teststorage.h
new file mode 100644
index 00000000..f8230735
--- /dev/null
+++ b/src/tests/teststorage.h
@@ -0,0 +1,132 @@
+/*
+ * 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_TEST_STORAGE_H_
+#define _TMWSERV_TEST_STORAGE_H_
+
+
+#include <cppunit/extensions/HelperMacros.h>
+
+#include "../dal/dataproviderfactory.h"
+
+
+/**
+ * Requirements:
+ * - if using MySQL or PostgreSQL as backends, then make sure that a user
+ * named 'guest' with the password 'guest' has enough privileges to
+ * create tables and populate them in a database named 'tmwteststorage'
+ * prior to running the teststorage unit tests.
+ */
+
+
+using namespace tmwserv::dal;
+
+
+/**
+ * Unit test for the Storage class.
+ */
+class StorageTest: public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(StorageTest);
+
+ // add tests to the test suite.
+ CPPUNIT_TEST(testGetAccount1);
+ CPPUNIT_TEST(testGetAccount2);
+
+ CPPUNIT_TEST_SUITE_END();
+
+
+ public:
+ /**
+ * Set up fixtures.
+ */
+ void
+ setUp(void);
+
+
+ /**
+ * Tear down fixtures.
+ */
+ void
+ tearDown(void);
+
+
+ /**
+ * Fetch an existing account from the database.
+ */
+ void
+ testGetAccount1(void);
+
+
+ /**
+ * Fetch an unexisting account from the database.
+ */
+ void
+ testGetAccount2(void);
+
+
+ private:
+ /**
+ * Initialize the storage.
+ */
+ void
+ initStorage(void);
+
+
+ /**
+ * Clean the storage.
+ */
+ void
+ cleanStorage(void);
+
+
+ /**
+ * Drop a table.
+ *
+ * @param db the database.
+ * @param name the table name.
+ */
+ void
+ dropTable(std::auto_ptr<DataProvider>& db,
+ const std::string& name);
+
+
+ /**
+ * Insert a new account.
+ *
+ * @param db the database.
+ * @param name the user name.
+ */
+ void
+ insertAccount(std::auto_ptr<DataProvider>&,
+ const std::string& name);
+
+
+ private:
+ static std::string mStorageName;
+ static std::string mStorageUser;
+ static std::string mStorageUserPassword;
+};
+
+
+#endif // _TMWSERV_TEST_STORAGE_H_