From d80e4e4f5505f5da52eed454b174bbac03886a02 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 30 Apr 2015 00:27:27 +0100 Subject: Adds support for SQLite, SQLite mocking and some basic tests --- project2/Jamfile.jam | 2 + project2/sql/Jamfile.jam | 14 ++++ project2/sql/sql-modSQLite.cpp | 61 ++++++++++++++++ project2/sql/sql-modSQLite.h | 24 ++++++ project2/sql/unittests/Jamfile.jam | 28 ++++--- project2/sql/unittests/datasources/sqlitemock.xml | 5 ++ project2/sql/unittests/sqliteschema.sql | 6 ++ project2/sql/unittests/testsqlite.cpp | 89 +++++++++++++++++++++++ 8 files changed, 219 insertions(+), 10 deletions(-) create mode 100644 project2/sql/sql-modSQLite.cpp create mode 100644 project2/sql/sql-modSQLite.h create mode 100644 project2/sql/unittests/datasources/sqlitemock.xml create mode 100644 project2/sql/unittests/sqliteschema.sql create mode 100644 project2/sql/unittests/testsqlite.cpp diff --git a/project2/Jamfile.jam b/project2/Jamfile.jam index 8e083e7..70c8c5b 100644 --- a/project2/Jamfile.jam +++ b/project2/Jamfile.jam @@ -4,6 +4,7 @@ import feature : feature ; feature odbc : yes no ; feature pq : yes no ; feature mysql : yes no ; +feature sqlite : yes no ; alias p2parts : : : : url//p2url @@ -22,6 +23,7 @@ alias p2parts : : : : yes:sql//p2sqlmodODBC yes:sql//p2sqlmodPQ yes:sql//p2sqlmodMySQL + yes:sql//p2sqlmodSQLite ; alias p2daemonparts : : : : diff --git a/project2/sql/Jamfile.jam b/project2/sql/Jamfile.jam index 306c94a..01ba44b 100644 --- a/project2/sql/Jamfile.jam +++ b/project2/sql/Jamfile.jam @@ -2,6 +2,7 @@ alias glibmm : : : : "`pkg-config --cflags glibmm-2.4`" "`pkg-config --libs glibmm-2.4`" ; +lib boost_filesystem ; build-project unittests ; @@ -16,6 +17,19 @@ lib p2sqlmodMySQL : : : ../../libmysqlpp//mysqlpp ; + +explicit library p2sqlmodSQLite ; +lib p2sqlmodSQLite : + sql-modSQLite.cpp : + ../../libsqlitepp//sqlitepp + glibmm + ../../libmisc + ../common//p2common + p2sql + boost_filesystem + : : + ../../libsqlitepp//sqlitepp + ; explicit library p2sqlmodODBC ; lib p2sqlmodODBC : diff --git a/project2/sql/sql-modSQLite.cpp b/project2/sql/sql-modSQLite.cpp new file mode 100644 index 0000000..6b4cb85 --- /dev/null +++ b/project2/sql/sql-modSQLite.cpp @@ -0,0 +1,61 @@ +#include "connectionLoader.h" +#include "../libsqlitepp/connection.h" +#include "sql-modSQLite.h" +#include +#include +#include +#include + +typedef SQLite::Connection SQLiteConnection; +DECLARE_GENERIC_LOADER("sqlite", ConnectionLoader, SQLiteConnection) + +MockSQLiteDatabase::MockSQLiteDatabase(const std::string & name, const std::vector & ss) : + testDbPath(boost::filesystem::path("/tmp") / "sqliteut" / stringbf("%d", getpid()) / stringbf("%d", ++MockConnectionLoader::mocked)), + mockName(name) +{ + Logger()->messagebf(LOG_DEBUG, "Setting up new mocked database at %s", testDbPath); + DropDatabase(); + CreateNewDatabase(); + try { + for (auto s : ss) { + Logger()->messagebf(LOG_DEBUG, "%s << %s", testDbPath, s); + if (system(("sqlite3 -bail " + testDbPath.string() + " < " + s.string()).c_str())) { + throw std::runtime_error("Failed to execute " + s.string()); + } + } + Logger()->messagebf(LOG_DEBUG, "%s initialized", testDbPath); + MockConnectionLoader::mocks[name] = boost::bind(MockSQLiteDatabase::openConnection, testDbPath.string()); + } + catch (...) { + DropDatabase(); + throw; + } +} + +DB::Connection * +MockSQLiteDatabase::openConnection(const std::string & connStr) +{ + return InstanceMap::Get("sqlite")->create(connStr); +} + +MockSQLiteDatabase::~MockSQLiteDatabase() +{ + Logger()->messagebf(LOG_DEBUG, "Tearing down mocked database %s", testDbPath); + DropDatabase(); + MockConnectionLoader::mocks.erase(mockName); + Logger()->messagebf(LOG_DEBUG, "%s torn down", testDbPath); +} + +void MockSQLiteDatabase::DropDatabase() const +{ + Logger()->messagebf(LOG_INFO, "Deleting database %s", testDbPath); + boost::filesystem::remove(testDbPath); +} + +void MockSQLiteDatabase::CreateNewDatabase() const +{ + Logger()->messagebf(LOG_INFO, "Creating new database at %s", testDbPath); + boost::filesystem::create_directories(testDbPath.parent_path()); +} + + diff --git a/project2/sql/sql-modSQLite.h b/project2/sql/sql-modSQLite.h new file mode 100644 index 0000000..267ba0b --- /dev/null +++ b/project2/sql/sql-modSQLite.h @@ -0,0 +1,24 @@ +#ifndef MOCKSQLITEDATASOURCE_H +#define MOCKSQLITEDATASOURCE_H + +#include "mockDatasource.h" +#include + +class MockSQLiteDatabase { + public: + MockSQLiteDatabase(const std::string & name, const std::vector & ss); + ~MockSQLiteDatabase(); + + protected: + void DropDatabase() const; + void CreateNewDatabase() const; + + private: + static DB::Connection * openConnection(const std::string & connStr); + const boost::filesystem::path testDbPath; + const std::string mockName; +}; + +#endif + + diff --git a/project2/sql/unittests/Jamfile.jam b/project2/sql/unittests/Jamfile.jam index 24db2e5..d9874ce 100644 --- a/project2/sql/unittests/Jamfile.jam +++ b/project2/sql/unittests/Jamfile.jam @@ -1,4 +1,3 @@ - import testing ; lib boost_system ; @@ -10,29 +9,38 @@ path-constant me : . ; lib sqlTestCore : testCore.cpp - : : + : ../../ut//p2ut ../../common//p2common boost_filesystem ROOT=\"$(me)\" - ; - -run - testpq.cpp - : : : - BOOST_TEST_DYN_LINK - sqlTestCore + : : ../../common//p2common ../../basics//p2basics ../../ut//p2ut ../../lib//p2lib ../../xml//p2xml ..//p2sql - ..//p2sqlmodPQ boost_system boost_filesystem ../../ut//boost_utf ROOT=\"$(me)\" + BOOST_TEST_DYN_LINK + ; + +run + testpq.cpp + : : : + sqlTestCore + ..//p2sqlmodPQ pqschema.sql : testpq ; +run + testsqlite.cpp + : : : + sqlTestCore + ..//p2sqlmodSQLite + sqliteschema.sql + : testsqlite ; + diff --git a/project2/sql/unittests/datasources/sqlitemock.xml b/project2/sql/unittests/datasources/sqlitemock.xml new file mode 100644 index 0000000..762de90 --- /dev/null +++ b/project2/sql/unittests/datasources/sqlitemock.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/project2/sql/unittests/sqliteschema.sql b/project2/sql/unittests/sqliteschema.sql new file mode 100644 index 0000000..393d21a --- /dev/null +++ b/project2/sql/unittests/sqliteschema.sql @@ -0,0 +1,6 @@ +CREATE TABLE test( + id int, + fl numeric(5,2), + string text); +INSERT INTO test VALUES(4, 123.45, 'some text'); + diff --git a/project2/sql/unittests/testsqlite.cpp b/project2/sql/unittests/testsqlite.cpp new file mode 100644 index 0000000..89a1f77 --- /dev/null +++ b/project2/sql/unittests/testsqlite.cpp @@ -0,0 +1,89 @@ +#define BOOST_TEST_MODULE TestSQLite +#include + +#include +#include +#include +#include +#include +#include +#include "testCore.h" +#include + +class StandardMockDatabase : public MockSQLiteDatabase { + public: + StandardMockDatabase() : MockSQLiteDatabase("sqlitemock", { + RootDir / "sqliteschema.sql" }) + { + } +}; + +BOOST_GLOBAL_FIXTURE( StandardMockDatabase ); + +BOOST_FIXTURE_TEST_SUITE( Core, TestCore ); + +BOOST_AUTO_TEST_CASE( transactions ) +{ + RdbmsDataSource * ds = CommonObjects::dataSource("sqlitemock"); + auto ro = ds->getReadonly(); + + BOOST_REQUIRE_EQUAL(false, ro->inTx()); + ro->beginTx(); + BOOST_REQUIRE_EQUAL(true, ro->inTx()); + ro->rollbackTx(); + BOOST_REQUIRE_EQUAL(false, ro->inTx()); + + ro->beginTx(); + BOOST_REQUIRE_EQUAL(true, ro->inTx()); + ro->commitTx(); + BOOST_REQUIRE_EQUAL(false, ro->inTx()); + + ds->close(); +} + +BOOST_AUTO_TEST_CASE( bindAndSend ) +{ + RdbmsDataSource * ds = CommonObjects::dataSource("sqlitemock"); + auto rw = ds->getWritable(); + + auto mod = rw->newModifyCommand("INSERT INTO test VALUES(?, ?, ?)"); + mod->bindParamI(0, testInt); + mod->bindParamF(1, testDouble); + mod->bindParamS(2, testString); + mod->execute(); + delete mod; + ds->commit(); + ds->close(); +} + +template +void +assertColumnValueHelper(DB::SelectCommand & sel, unsigned int col, const T & t) +{ + HandleAsVariableType h; + sel[col].apply(h); + BOOST_REQUIRE_EQUAL(t, h.variable.as()); +} + +BOOST_AUTO_TEST_CASE( bindAndSelect ) +{ + RdbmsDataSource * ds = CommonObjects::dataSource("sqlitemock"); + auto ro = ds->getReadonly(); + + auto select = ro->newSelectCommand("SELECT * FROM test WHERE id = ?"); + select->bindParamI(0, testInt); + select->execute(); + int rows = 0; + while (select->fetch()) { + assertColumnValueHelper(*select, 0, testInt); + assertColumnValueHelper(*select, 1, testDouble); + assertColumnValueHelper(*select, 2, testString); + rows += 1; + } + delete select; + BOOST_REQUIRE_EQUAL(1, rows); + ds->close(); +} + +BOOST_AUTO_TEST_SUITE_END(); + -- cgit v1.2.3