- pmSysvariable/ccuUdpMsg: 域起始符改为0x40 0x40,域标识符重编号0x0001~0x0004, ccuState/ccuColCmd/ccuSetParmCmd 按新协议字段布局与字节序重写(状态248B/操控45B/参数28B) - systemData/httpserver: 新增FC单片电压、甲醇制氢装置、DC/DC、尾气装置、一体化罐、 供氢供氧流量、应急上浮等字段解析与WebSocket JSON推送 - 新增 /fcs 燃料电池监控页(fuelcell.h):实时数据显示 + 操控指令交互按钮, 过滤日志推送消息避免界面闪烁 - SQLite/LowerCommManager/测试:更新建表列、解析打印与单元/集成测试适配新协议
256 lines
9.2 KiB
C++
256 lines
9.2 KiB
C++
//=======================================================================
|
|
// SqliteTest(gtest): 验证 SQLite 封装 10 个 insertData 写入正确。
|
|
// 不改动 SQLite 封装;用裸 sqlite3 打开同一文件读回验证。
|
|
//=======================================================================
|
|
#include <gtest/gtest.h>
|
|
#include <cstdio>
|
|
#include <string>
|
|
#include <unistd.h>
|
|
#include "sqlit3/SQLite.h"
|
|
#include "sqlit3/sqlite3.h"
|
|
|
|
static std::string tmpPath(const char* name) {
|
|
return std::string("/tmp/pmsqlite_") + name + "_" + std::to_string(::getpid()) + ".db";
|
|
}
|
|
|
|
static bool rawQueryInt(const std::string& path, const std::string& sql, long long& out) {
|
|
sqlite3* db = nullptr;
|
|
if (sqlite3_open(path.c_str(), &db) != SQLITE_OK) return false;
|
|
sqlite3_stmt* stmt = nullptr;
|
|
bool ok = false;
|
|
if (sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
|
|
if (sqlite3_step(stmt) == SQLITE_ROW) { out = sqlite3_column_int64(stmt, 0); ok = true; }
|
|
}
|
|
if (stmt) sqlite3_finalize(stmt);
|
|
sqlite3_close(db);
|
|
return ok;
|
|
}
|
|
|
|
static bool rawCount(const std::string& path, const std::string& table, long long& out) {
|
|
return rawQueryInt(path, "SELECT COUNT(*) FROM " + table, out);
|
|
}
|
|
|
|
static bool rawQueryText(const std::string& path, const std::string& sql, std::string& out) {
|
|
sqlite3* db = nullptr;
|
|
if (sqlite3_open(path.c_str(), &db) != SQLITE_OK) return false;
|
|
sqlite3_stmt* stmt = nullptr;
|
|
bool ok = false;
|
|
if (sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
|
|
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
|
const unsigned char* t = sqlite3_column_text(stmt, 0);
|
|
if (t) { out = reinterpret_cast<const char*>(t); ok = true; }
|
|
}
|
|
}
|
|
if (stmt) sqlite3_finalize(stmt);
|
|
sqlite3_close(db);
|
|
return ok;
|
|
}
|
|
|
|
TEST(SqliteTest, InsertCcuStateReadBack)
|
|
{
|
|
std::string path = tmpPath("ccu");
|
|
{
|
|
SQLite db(path);
|
|
ASSERT_TRUE(db.createTable());
|
|
ccuState c{}; c.ins_soc = 42; c.dyn_soc = 66; c.fc_status = 4;
|
|
EXPECT_TRUE(db.insertData(c));
|
|
}
|
|
long long v = 0;
|
|
EXPECT_TRUE(rawQueryInt(path, "SELECT ins_soc FROM ccuState ORDER BY id DESC LIMIT 1", v));
|
|
EXPECT_EQ(v, 42);
|
|
EXPECT_TRUE(rawQueryInt(path, "SELECT dyn_soc FROM ccuState ORDER BY id DESC LIMIT 1", v));
|
|
EXPECT_EQ(v, 66);
|
|
EXPECT_TRUE(rawQueryInt(path, "SELECT fc_status FROM ccuState ORDER BY id DESC LIMIT 1", v));
|
|
EXPECT_EQ(v, 4);
|
|
std::remove(path.c_str());
|
|
}
|
|
|
|
TEST(SqliteTest, InsertDisHighVolBusStateReadBack)
|
|
{
|
|
std::string path = tmpPath("dihv");
|
|
{
|
|
SQLite db(path);
|
|
ASSERT_TRUE(db.createTable());
|
|
disHighVolBusState s{};
|
|
s.fuelCellCircuitBreaker = 1;
|
|
s.powerBusVoltage = 5200;
|
|
EXPECT_TRUE(db.insertData(s));
|
|
}
|
|
long long v = 0;
|
|
EXPECT_TRUE(rawQueryInt(path, "SELECT fuelCellCircuitBreaker FROM disHighVolBusState ORDER BY id DESC LIMIT 1", v));
|
|
EXPECT_EQ(v, 1);
|
|
EXPECT_TRUE(rawQueryInt(path, "SELECT powerBusVoltage FROM disHighVolBusState ORDER BY id DESC LIMIT 1", v));
|
|
EXPECT_EQ(v, 5200);
|
|
std::remove(path.c_str());
|
|
}
|
|
|
|
TEST(SqliteTest, InsertDisHighAVolBusStateReadBack)
|
|
{
|
|
std::string path = tmpPath("dihva");
|
|
{
|
|
SQLite db(path); ASSERT_TRUE(db.createTable());
|
|
disHighAVolBusState s{}; s.bowFTDevice123CircuitBreaker = 1; s.busbarBVoltage = 100;
|
|
EXPECT_TRUE(db.insertData(s));
|
|
}
|
|
long long v = 0;
|
|
EXPECT_TRUE(rawQueryInt(path, "SELECT bowFTDevice123CircuitBreaker FROM disHighAVolBusState", v));
|
|
EXPECT_EQ(v, 1);
|
|
EXPECT_TRUE(rawQueryInt(path, "SELECT busbarBVoltage FROM disHighAVolBusState", v));
|
|
EXPECT_EQ(v, 100);
|
|
std::remove(path.c_str());
|
|
}
|
|
|
|
TEST(SqliteTest, InsertDisLowMainBusStateReadBack)
|
|
{
|
|
std::string path = tmpPath("dilmb");
|
|
{
|
|
SQLite db(path); ASSERT_TRUE(db.createTable());
|
|
disLowMainBusState s{}; s.unit4InstrumentDC48VCircuitBreaker = 1;
|
|
EXPECT_TRUE(db.insertData(s));
|
|
}
|
|
long long v = 0;
|
|
EXPECT_TRUE(rawQueryInt(path, "SELECT unit4InstrumentDC48VCircuitBreaker FROM disLowMainBusState", v));
|
|
EXPECT_EQ(v, 1);
|
|
std::remove(path.c_str());
|
|
}
|
|
|
|
TEST(SqliteTest, InsertDisLowBusStateReadBack)
|
|
{
|
|
std::string path = tmpPath("dilb");
|
|
{
|
|
SQLite db(path); ASSERT_TRUE(db.createTable());
|
|
disLowBusState s{}; s.unit1CircuitBreaker = 1;
|
|
EXPECT_TRUE(db.insertData(s));
|
|
}
|
|
long long v = 0;
|
|
EXPECT_TRUE(rawQueryInt(path, "SELECT unit1CircuitBreaker FROM disLowBusState", v));
|
|
EXPECT_EQ(v, 1);
|
|
std::remove(path.c_str());
|
|
}
|
|
|
|
TEST(SqliteTest, InsertCommandsReadBack)
|
|
{
|
|
std::string path = tmpPath("cmd");
|
|
{
|
|
SQLite db(path); ASSERT_TRUE(db.createTable());
|
|
ccuColCmd cc{}; cc.heartbeat = 5; EXPECT_TRUE(db.insertData(cc));
|
|
disHighVolBusCmd c1{}; c1.dcdc5Module = 1; c1.coolingSystem = 1; EXPECT_TRUE(db.insertData(c1));
|
|
disHighAVolBusCmd c2{}; c2.xczCircuitBreaker = 1; EXPECT_TRUE(db.insertData(c2));
|
|
disLowMainBusCmd c3{}; c3.dcC1DCDistributionPanelCircuitBreaker = 1; EXPECT_TRUE(db.insertData(c3));
|
|
disLowBusCmd c4{}; c4.unit2CircuitBreaker = 1; EXPECT_TRUE(db.insertData(c4));
|
|
}
|
|
long long v = 0;
|
|
EXPECT_TRUE(rawQueryInt(path, "SELECT heartbeat FROM ccuColCmd", v)); EXPECT_EQ(v, 5);
|
|
EXPECT_TRUE(rawQueryInt(path, "SELECT dcdc5Module FROM disHighVolBusCmd", v)); EXPECT_EQ(v, 1);
|
|
EXPECT_TRUE(rawQueryInt(path, "SELECT xczCircuitBreaker FROM disHighAVolBusCmd", v)); EXPECT_EQ(v, 1);
|
|
EXPECT_TRUE(rawQueryInt(path, "SELECT dcC1DCDistributionPanelCircuitBreaker FROM disLowMainBusCmd", v)); EXPECT_EQ(v, 1);
|
|
EXPECT_TRUE(rawQueryInt(path, "SELECT unit2CircuitBreaker FROM disLowBusCmd", v)); EXPECT_EQ(v, 1);
|
|
std::remove(path.c_str());
|
|
}
|
|
|
|
TEST(SqliteTest, MultipleInsertsCount)
|
|
{
|
|
std::string path = tmpPath("multi");
|
|
{
|
|
SQLite db(path); ASSERT_TRUE(db.createTable());
|
|
ccuState c{}; c.ins_soc = 10;
|
|
EXPECT_TRUE(db.insertData(c));
|
|
EXPECT_TRUE(db.insertData(c));
|
|
EXPECT_TRUE(db.insertData(c));
|
|
}
|
|
long long n = 0;
|
|
EXPECT_TRUE(rawCount(path, "ccuState", n));
|
|
EXPECT_EQ(n, 3);
|
|
std::remove(path.c_str());
|
|
}
|
|
|
|
TEST(SqliteTest, InsertCcuSetParmCmdReadBack)
|
|
{
|
|
std::string path = tmpPath("setparmcmd");
|
|
{
|
|
SQLite db(path); ASSERT_TRUE(db.createTable());
|
|
ccuSetParmCmd c{}; c.insSocHold1 = 7; c.powerSocHold2 = 88;
|
|
EXPECT_TRUE(db.insertData(c));
|
|
}
|
|
long long v = 0;
|
|
EXPECT_TRUE(rawQueryInt(path, "SELECT insSocHold1 FROM ccuSetParmCmd", v));
|
|
EXPECT_EQ(v, 7);
|
|
EXPECT_TRUE(rawQueryInt(path, "SELECT powerSocHold2 FROM ccuSetParmCmd", v));
|
|
EXPECT_EQ(v, 88);
|
|
std::remove(path.c_str());
|
|
}
|
|
|
|
TEST(SqliteTest, InsertCcuSetParmFbReadBack)
|
|
{
|
|
std::string path = tmpPath("setparmfb");
|
|
{
|
|
SQLite db(path); ASSERT_TRUE(db.createTable());
|
|
msg_CcuSetParmFbMsg fb{}; fb.flag = 1; fb.failureCode = 2;
|
|
EXPECT_TRUE(db.insertData(fb));
|
|
}
|
|
long long v = 0;
|
|
EXPECT_TRUE(rawQueryInt(path, "SELECT flag FROM ccuSetParmFb", v));
|
|
EXPECT_EQ(v, 1);
|
|
EXPECT_TRUE(rawQueryInt(path, "SELECT failureCode FROM ccuSetParmFb", v));
|
|
EXPECT_EQ(v, 2);
|
|
std::remove(path.c_str());
|
|
}
|
|
|
|
TEST(SqliteTest, LogRawFrameReadBack)
|
|
{
|
|
std::string path = tmpPath("raw");
|
|
{
|
|
SQLite db(path); ASSERT_TRUE(db.createTable());
|
|
const unsigned char frame[] = {0x20, 0x20, 0x51, 0x00, 0x01, 0x02, 0x03};
|
|
db.onFrame(0, 0x0051, "ccuState", frame, sizeof(frame), true);
|
|
db.onFrame(1, 0x0001, "disHighVolBusCmd", frame, sizeof(frame), true);
|
|
}
|
|
long long n = 0;
|
|
EXPECT_TRUE(rawCount(path, "msg_log", n));
|
|
EXPECT_EQ(n, 2);
|
|
std::string hex;
|
|
EXPECT_TRUE(rawQueryText(path, "SELECT payload_hex FROM msg_log ORDER BY id LIMIT 1", hex));
|
|
EXPECT_EQ(hex, "20205100010203");
|
|
long long dir = 0;
|
|
EXPECT_TRUE(rawQueryInt(path, "SELECT direction FROM msg_log ORDER BY id DESC LIMIT 1", dir));
|
|
EXPECT_EQ(dir, 1);
|
|
std::remove(path.c_str());
|
|
}
|
|
|
|
TEST(SqliteTest, InvalidPathIsFailOpen)
|
|
{
|
|
SQLite db("/invalid/path/nonexistent_dir/test.db");
|
|
EXPECT_EQ(db.status(), SQLite::Status::Disabled);
|
|
EXPECT_FALSE(db.isConnected());
|
|
ccuState c{}; c.ins_soc = 1;
|
|
EXPECT_FALSE(db.insertData(c)); // 不抛异常,返回 false
|
|
ccuColCmd cmd{};
|
|
EXPECT_FALSE(db.insertData(cmd));
|
|
const unsigned char frame[] = {0x20, 0x20};
|
|
db.onFrame(0, 0x0051, "ccuState", frame, sizeof(frame), true); // 不崩溃
|
|
}
|
|
|
|
TEST(SqliteTest, CorruptDatabaseRecovered)
|
|
{
|
|
std::string path = tmpPath("corrupt");
|
|
{
|
|
// 写入非 SQLite 内容,模拟损坏的库文件
|
|
FILE* f = fopen(path.c_str(), "wb");
|
|
ASSERT_TRUE(f != nullptr);
|
|
for (int i = 0; i < 4096; ++i) fputc((i * 7 + 3) & 0xFF, f);
|
|
fclose(f);
|
|
|
|
SQLite db(path);
|
|
// 应能备份损坏文件并重建,恢复可用
|
|
EXPECT_EQ(db.status(), SQLite::Status::OK);
|
|
EXPECT_TRUE(db.isConnected());
|
|
ccuState c{}; c.ins_soc = 99;
|
|
EXPECT_TRUE(db.insertData(c));
|
|
}
|
|
long long v = 0;
|
|
EXPECT_TRUE(rawQueryInt(path, "SELECT ins_soc FROM ccuState", v));
|
|
EXPECT_EQ(v, 99);
|
|
std::remove(path.c_str());
|
|
std::remove((path + ".corrupt").c_str());
|
|
}
|