测试代码
cpp
#pragma once
#include <string>
#include <vector>
// Assume OperationLog is a struct representing a row in the table
struct OperationLog {
int id;
std::string op_type;
std::string op_subtype;
std::string details;
std::string timestamp;
};
class OperationLogRepositoryWCDB {
public:
// Query by op_type
std::vector<OperationLog> queryByOpType(const std::string& opType);
// Query by op_subtype
std::vector<OperationLog> queryByOpSubType(const std::string& opSubType);
};
#include "operation_log_repository_wcdb.h"
#include <WCDB/WCDB.h>
std::vector<OperationLog> OperationLogRepositoryWCDB::queryByOpType(const std::string& opType) {
std::vector<OperationLog> result;
WCDB::Database db("operation_log.db");
auto rows = db.getRows("operation_log", WCDB::Column::All(), "op_type = ?", {opType});
for (const auto& row : rows) {
OperationLog log;
log.id = row.getValue<int>(0);
log.op_type = row.getValue<std::string>(1);
log.op_subtype = row.getValue<std::string>(2);
log.details = row.getValue<std::string>(3);
log.timestamp = row.getValue<std::string>(4);
result.push_back(log);
}
return result;
}
std::vector<OperationLog> OperationLogRepositoryWCDB::queryByOpSubType(const std::string& opSubType) {
std::vector<OperationLog> result;
WCDB::Database db("operation_log.db");
auto rows = db.getRows("operation_log", WCDB::Column::All(), "op_subtype = ?", {opSubType});
for (const auto& row : rows) {
OperationLog log;
log.id = row.getValue<int>(0);
log.op_type = row.getValue<std::string>(1);
log.op_subtype = row.getValue<std::string>(2);
log.details = row.getValue<std::string>(3);
log.timestamp = row.getValue<std::string>(4);
result.push_back(log);
}
return result;
}
#pragma once
#include <string>
#include <vector>
// Assume OperationLog is a struct representing a row in the table
struct OperationLog {
int id;
std::string op_type;
std::string op_subtype;
std::string details;
std::string timestamp;
};
class OperationLogRepositorySOCI {
public:
// Query by op_type
std::vector<OperationLog> queryByOpType(const std::string& opType);
// Query by op_subtype
std::vector<OperationLog> queryByOpSubType(const std::string& opSubType);
};
#include "operation_log_repository_soci.h"
#include <soci/soci.h>
#include <soci/sqlite3/soci-sqlite3.h>
std::vector<OperationLog> OperationLogRepositorySOCI::queryByOpType(const std::string& opType) {
std::vector<OperationLog> result;
soci::session sql(soci::sqlite3, "operation_log.db");
soci::rowset<soci::row> rs = (sql.prepare << "SELECT id, op_type, op_subtype, details, timestamp FROM operation_log WHERE op_type = :op_type", soci::use(opType));
for (const auto& r : rs) {
OperationLog log;
log.id = r.get<int>(0);
log.op_type = r.get<std::string>(1);
log.op_subtype = r.get<std::string>(2);
log.details = r.get<std::string>(3);
log.timestamp = r.get<std::string>(4);
result.push_back(log);
}
return result;
}
std::vector<OperationLog> OperationLogRepositorySOCI::queryByOpSubType(const std::string& opSubType) {
std::vector<OperationLog> result;
soci::session sql(soci::sqlite3, "operation_log.db");
soci::rowset<soci::row> rs = (sql.prepare << "SELECT id, op_type, op_subtype, details, timestamp FROM operation_log WHERE op_subtype = :op_subtype", soci::use(opSubType));
for (const auto& r : rs) {
OperationLog log;
log.id = r.get<int>(0);
log.op_type = r.get<std::string>(1);
log.op_subtype = r.get<std::string>(2);
log.details = r.get<std::string>(3);
log.timestamp = r.get<std::string>(4);
result.push_back(log);
}
return result;
}
带gtest代码
cpp
#pragma once
#include <string>
#include <vector>
struct OperationLog {
int id;
std::string op_type;
std::string op_subtype;
std::string op_content;
std::string timestamp;
};
class OperationLogInterface {
public:
virtual ~OperationLogInterface() = default;
// 1. Query operation_log using op_type as index, limit 20
virtual std::vector<OperationLog> queryByOpType(const std::string& op_type) = 0;
// 2. Query operation_log using op_subtype as index, limit 20
virtual std::vector<OperationLog> queryByOpSubtype(const std::string& op_subtype) = 0;
// 3. Query count of total rows in operation_log
virtual int getTotalCount() = 0;
};
#include "operation_log_interface.h"
#include <WCDB.h>
class OperationLogWCDB : public OperationLogInterface {
public:
OperationLogWCDB(const std::string& dbPath)
: database(dbPath) {}
std::vector<OperationLog> queryByOpType(const std::string& op_type) override {
std::vector<OperationLog> result;
auto statement = WCDB::StatementSelect().from("operation_log")
.where(WCDB::Column("op_type") == op_type)
.limit(20);
auto rows = database.selectRows(statement);
for (const auto& row : rows) {
OperationLog log;
log.id = row[0].int32Value();
log.op_type = row[1].stringValue();
log.op_subtype = row[2].stringValue();
log.op_content = row[3].stringValue();
log.timestamp = row[4].stringValue();
result.push_back(log);
}
return result;
}
std::vector<OperationLog> queryByOpSubtype(const std::string& op_subtype) override {
std::vector<OperationLog> result;
auto statement = WCDB::StatementSelect().from("operation_log")
.where(WCDB::Column("op_subtype") == op_subtype)
.limit(20);
auto rows = database.selectRows(statement);
for (const auto& row : rows) {
OperationLog log;
log.id = row[0].int32Value();
log.op_type = row[1].stringValue();
log.op_subtype = row[2].stringValue();
log.op_content = row[3].stringValue();
log.timestamp = row[4].stringValue();
result.push_back(log);
}
return result;
}
int getTotalCount() override {
auto statement = WCDB::StatementSelect().from("operation_log")
.column(WCDB::Column::count("*"));
auto rows = database.selectRows(statement);
if (!rows.empty()) {
return rows[0][0].int32Value();
}
return 0;
}
private:
WCDB::Database database;
};
#include "operation_log_interface.h"
#include <soci/soci.h>
class OperationLogSOCI : public OperationLogInterface {
public:
OperationLogSOCI(const std::string& connStr)
: sql(soci::sqlite3, connStr) {}
std::vector<OperationLog> queryByOpType(const std::string& op_type) override {
std::vector<OperationLog> result;
soci::rowset<soci::row> rs = (sql.prepare <<
"SELECT id, op_type, op_subtype, op_content, timestamp FROM operation_log WHERE op_type = ? LIMIT 20", op_type);
for (auto& r : rs) {
OperationLog log;
log.id = r.get<int>(0);
log.op_type = r.get<std::string>(1);
log.op_subtype = r.get<std::string>(2);
log.op_content = r.get<std::string>(3);
log.timestamp = r.get<std::string>(4);
result.push_back(log);
}
return result;
}
std::vector<OperationLog> queryByOpSubtype(const std::string& op_subtype) override {
std::vector<OperationLog> result;
soci::rowset<soci::row> rs = (sql.prepare <<
"SELECT id, op_type, op_subtype, op_content, timestamp FROM operation_log WHERE op_subtype = ? LIMIT 20", op_subtype);
for (auto& r : rs) {
OperationLog log;
log.id = r.get<int>(0);
log.op_type = r.get<std::string>(1);
log.op_subtype = r.get<std::string>(2);
log.op_content = r.get<std::string>(3);
log.timestamp = r.get<std::string>(4);
result.push_back(log);
}
return result;
}
int getTotalCount() override {
int count = 0;
sql << "SELECT count(*) FROM operation_log", soci::into(count);
return count;
}
private:
soci::session sql;
};
#include <gtest/gtest.h>
#include "operation_log_interface.h"
// You would need to include the appropriate subclasses and initialize the DB with test data.
class OperationLogTest : public ::testing::Test {
protected:
void SetUp() override {
// initialize db and insert test data for both WCDB and SOCI
// You may want to use a test database for this
}
// Provide implementations for both
OperationLogInterface* wcdb_impl;
OperationLogInterface* soci_impl;
};
// Test queryByOpType
TEST_F(OperationLogTest, QueryByOpType_WCDB) {
auto logs = wcdb_impl->queryByOpType("typeA");
ASSERT_LE(logs.size(), 20);
for (const auto& log : logs) {
EXPECT_EQ(log.op_type, "typeA");
}
}
TEST_F(OperationLogTest, QueryByOpType_SOCI) {
auto logs = soci_impl->queryByOpType("typeA");
ASSERT_LE(logs.size(), 20);
for (const auto& log : logs) {
EXPECT_EQ(log.op_type, "typeA");
}
}
// Test queryByOpSubtype
TEST_F(OperationLogTest, QueryByOpSubtype_WCDB) {
auto logs = wcdb_impl->queryByOpSubtype("subtypeB");
ASSERT_LE(logs.size(), 20);
for (const auto& log : logs) {
EXPECT_EQ(log.op_subtype, "subtypeB");
}
}
TEST_F(OperationLogTest, QueryByOpSubtype_SOCI) {
auto logs = soci_impl->queryByOpSubtype("subtypeB");
ASSERT_LE(logs.size(), 20);
for (const auto& log : logs) {
EXPECT_EQ(log.op_subtype, "subtypeB");
}
}
// Test getTotalCount
TEST_F(OperationLogTest, GetTotalCount_WCDB) {
int count = wcdb_impl->getTotalCount();
// Expect count equals to number of inserted rows
EXPECT_GT(count, 0);
}
TEST_F(OperationLogTest, GetTotalCount_SOCI) {
int count = soci_impl->getTotalCount();
EXPECT_GT(count, 0);
}
另一版测试代码
cpp
#include "operation_log_wcdb.h"
#include <WCDB/WCDBCpp.h>
using namespace WCDB;
OperationLogWCDB::OperationLogWCDB(const std::string& dbPath)
: m_dbPath(dbPath)
{
}
OperationLogWCDB::~OperationLogWCDB() = default;
bool OperationLogWCDB::InitDB()
{
m_db = std::make_unique<Database>(m_dbPath);
if (!m_db->isOpened()) {
m_db->open();
}
// Create table if not exists
std::string sql = "CREATE TABLE IF NOT EXISTS operation_log ("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"op_type TEXT, "
"op_subtype TEXT, "
"detail TEXT, "
"ts INTEGER)";
return m_db->execute(sql);
}
bool OperationLogWCDB::Insert(const OperationLogRow& row)
{
StatementInsert insert("operation_log");
insert.columns({"op_type", "op_subtype", "detail", "ts"});
insert.values({row.op_type, row.op_subtype, row.detail, row.ts});
return m_db->execute(insert);
}
std::vector<OperationLogRow> OperationLogWCDB::QueryByOpType(const std::string& opType, int limit)
{
StatementSelect select("operation_log");
select.columns({"id", "op_type", "op_subtype", "detail", "ts"});
select.where(Column("op_type") == opType);
select.limit(limit);
std::vector<OperationLogRow> results;
auto rows = m_db->getRows(select);
for (const auto& row : rows) {
OperationLogRow log;
log.id = row[0].int64Value();
log.op_type = row[1].stringValue();
log.op_subtype = row[2].stringValue();
log.detail = row[3].stringValue();
log.ts = row[4].int64Value();
results.push_back(log);
}
return results;
}
std::vector<OperationLogRow> OperationLogWCDB::QueryByOpSubType(const std::string& opSubType, int limit)
{
StatementSelect select("operation_log");
select.columns({"id", "op_type", "op_subtype", "detail", "ts"});
select.where(Column("op_subtype") == opSubType);
select.limit(limit);
std::vector<OperationLogRow> results;
auto rows = m_db->getRows(select);
for (const auto& row : rows) {
OperationLogRow log;
log.id = row[0].int64Value();
log.op_type = row[1].stringValue();
log.op_subtype = row[2].stringValue();
log.detail = row[3].stringValue();
log.ts = row[4].int64Value();
results.push_back(log);
}
return results;
}
int64_t OperationLogWCDB::QueryRowCount()
{
StatementSelect select("operation_log");
select.columns({"COUNT(*)"});
auto rows = m_db->getRows(select);
if (!rows.empty()) {
return rows[0][0].int64Value();
}
return 0;
}
#include "operation_log_soci.h"
#include <soci/sqlite3/soci-sqlite3.h>
OperationLogSOCI::OperationLogSOCI(const std::string& connectString)
{
m_session = std::make_unique<soci::session>(soci::sqlite3, connectString);
}
OperationLogSOCI::~OperationLogSOCI() = default;
bool OperationLogSOCI::InitDB()
{
try {
*m_session << "CREATE TABLE IF NOT EXISTS operation_log ("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"op_type TEXT, "
"op_subtype TEXT, "
"detail TEXT, "
"ts INTEGER)";
return true;
} catch (...) {
return false;
}
}
bool OperationLogSOCI::Insert(const OperationLogRow& row)
{
try {
*m_session << "INSERT INTO operation_log (op_type, op_subtype, detail, ts) VALUES (:op_type, :op_subtype, :detail, :ts)",
soci::use(row.op_type), soci::use(row.op_subtype), soci::use(row.detail), soci::use(row.ts);
return true;
} catch (...) {
return false;
}
}
std::vector<OperationLogRow> OperationLogSOCI::QueryByOpType(const std::string& opType, int limit)
{
std::vector<OperationLogRow> results;
soci::rowset<soci::row> rs =
(m_session->prepare << "SELECT id, op_type, op_subtype, detail, ts FROM operation_log WHERE op_type = :op_type LIMIT :limit",
soci::use(opType), soci::use(limit));
for (auto it = rs.begin(); it != rs.end(); ++it) {
const soci::row& r = *it;
OperationLogRow log;
log.id = r.get<int64_t>(0);
log.op_type = r.get<std::string>(1);
log.op_subtype = r.get<std::string>(2);
log.detail = r.get<std::string>(3);
log.ts = r.get<int64_t>(4);
results.push_back(log);
}
return results;
}
std::vector<OperationLogRow> OperationLogSOCI::QueryByOpSubType(const std::string& opSubType, int limit)
{
std::vector<OperationLogRow> results;
soci::rowset<soci::row> rs =
(m_session->prepare << "SELECT id, op_type, op_subtype, detail, ts FROM operation_log WHERE op_subtype = :op_subtype LIMIT :limit",
soci::use(opSubType), soci::use(limit));
for (auto it = rs.begin(); it != rs.end(); ++it) {
const soci::row& r = *it;
OperationLogRow log;
log.id = r.get<int64_t>(0);
log.op_type = r.get<std::string>(1);
log.op_subtype = r.get<std::string>(2);
log.detail = r.get<std::string>(3);
log.ts = r.get<int64_t>(4);
results.push_back(log);
}
return results;
}
int64_t OperationLogSOCI::QueryRowCount()
{
int64_t cnt = 0;
*m_session << "SELECT COUNT(*) FROM operation_log", soci::into(cnt);
return cnt;
}
#pragma once
#include <string>
#include <vector>
#include <memory>
// WCDB Forward declarations
class WCDBDatabase;
struct OperationLogRow {
int64_t id;
std::string op_type;
std::string op_subtype;
std::string detail;
int64_t ts;
};
class OperationLogWCDB {
public:
OperationLogWCDB(const std::string& dbPath);
~OperationLogWCDB();
bool InitDB();
bool Insert(const OperationLogRow& row);
std::vector<OperationLogRow> QueryByOpType(const std::string& opType, int limit = 20);
std::vector<OperationLogRow> QueryByOpSubType(const std::string& opSubType, int limit = 20);
int64_t QueryRowCount();
private:
std::unique_ptr<WCDBDatabase> m_db;
std::string m_dbPath;
};
#pragma once
#include <string>
#include <vector>
#include <memory>
#include <soci/soci.h>
struct OperationLogRow {
int64_t id;
std::string op_type;
std::string op_subtype;
std::string detail;
int64_t ts;
};
class OperationLogSOCI {
public:
OperationLogSOCI(const std::string& connectString);
~OperationLogSOCI();
bool InitDB();
bool Insert(const OperationLogRow& row);
std::vector<OperationLogRow> QueryByOpType(const std::string& opType, int limit = 20);
std::vector<OperationLogRow> QueryByOpSubType(const std::string& opSubType, int limit = 20);
int64_t QueryRowCount();
private:
std::unique_ptr<soci::session> m_session;
};
#include <gtest/gtest.h>
#include "operation_log_wcdb.h"
#include "operation_log_soci.h"
#include <cstdio>
// Helper to clean up db file
void RemoveDBFile(const std::string& path) {
std::remove(path.c_str());
}
OperationLogRow MakeTestRow(int idx, const std::string& type = "typeA", const std::string& subtype = "subtypeA") {
OperationLogRow row;
row.id = 0;
row.op_type = type;
row.op_subtype = subtype;
row.detail = "detail_" + std::to_string(idx);
row.ts = 1000 + idx;
return row;
}
TEST(OperationLogWCDBTest, BasicCRUD) {
std::string dbPath = "test_wcdb.sqlite";
RemoveDBFile(dbPath);
OperationLogWCDB db(dbPath);
ASSERT_TRUE(db.InitDB());
// Insert 30 rows, 10 with typeA, 20 with typeB
for (int i = 0; i < 10; ++i)
ASSERT_TRUE(db.Insert(MakeTestRow(i, "typeA", "subtypeA")));
for (int i = 10; i < 30; ++i)
ASSERT_TRUE(db.Insert(MakeTestRow(i, "typeB", "subtypeB")));
EXPECT_EQ(db.QueryRowCount(), 30);
auto typeAList = db.QueryByOpType("typeA", 20);
EXPECT_EQ(typeAList.size(), 10);
EXPECT_EQ(typeAList[0].op_type, "typeA");
auto subtypeBList = db.QueryByOpSubType("subtypeB", 20);
EXPECT_EQ(subtypeBList.size(), 20);
EXPECT_EQ(subtypeBList[0].op_subtype, "subtypeB");
RemoveDBFile(dbPath);
}
TEST(OperationLogSOCI, BasicCRUD) {
std::string dbPath = "test_soci.sqlite";
RemoveDBFile(dbPath);
OperationLogSOCI db(dbPath);
ASSERT_TRUE(db.InitDB());
// Insert 30 rows, 15 with typeA, 15 with typeB
for (int i = 0; i < 15; ++i)
ASSERT_TRUE(db.Insert(MakeTestRow(i, "typeA", "subtypeA")));
for (int i = 15; i < 30; ++i)
ASSERT_TRUE(db.Insert(MakeTestRow(i, "typeB", "subtypeB")));
EXPECT_EQ(db.QueryRowCount(), 30);
auto typeAList = db.QueryByOpType("typeA", 20);
EXPECT_EQ(typeAList.size(), 15);
EXPECT_EQ(typeAList[0].op_type, "typeA");
auto subtypeBList = db.QueryByOpSubType("subtypeB", 20);
EXPECT_EQ(subtypeBList.size(), 15);
EXPECT_EQ(subtypeBList[0].op_subtype, "subtypeB");
RemoveDBFile(dbPath);
}