测试:GoogleTest 全面单测(10工况设备表/故障检测/协议/消息/SQLite读回)+ UDP→SQLite 集成测试,src 零改动
build-test-deploy / ci (push) Failing after 11m45s
build-test-deploy / ci (push) Failing after 11m45s
This commit is contained in:
+84
-4
@@ -5,10 +5,12 @@ project(H100PowerMangerTests)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# 需要 GoogleTest(由 CI Dockerfile 或本地安装,提供 GTestConfig/库)
|
||||
find_package(GTest REQUIRED)
|
||||
|
||||
################################################SQLiteTest####################################################################
|
||||
################################################SQLiteTest(保留原有)#######
|
||||
# 添加 SQLite 测试可执行文件(不使用第三方测试库)
|
||||
add_executable(SQLiteTest
|
||||
add_executable(SQLiteTest
|
||||
until/testSqlitdb.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/pPowerManger/sqlit3/SQLite.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/pPowerManger/sqlit3/sqlite3.c
|
||||
@@ -16,7 +18,7 @@ add_executable(SQLiteTest
|
||||
)
|
||||
|
||||
# 包含目录
|
||||
target_include_directories(SQLiteTest PRIVATE
|
||||
target_include_directories(SQLiteTest PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/src/pPowerManger
|
||||
${CMAKE_SOURCE_DIR}/src/pPowerManger/sqlit3
|
||||
)
|
||||
@@ -27,4 +29,82 @@ target_link_libraries(SQLiteTest
|
||||
dl
|
||||
)
|
||||
|
||||
################################################PowerMangerTest####################################################################
|
||||
################################################PowerMangerTests(gtest)####
|
||||
# 综合单元测试:Driver / SystemData / FaultMap / Upmsg / UdpComm /
|
||||
# PmSysvariable / SQLite 读回。仅链接现有 src 源码,不改动生产代码。
|
||||
set(PM_SRC_DIR ${CMAKE_SOURCE_DIR}/src/pPowerManger)
|
||||
|
||||
set(PM_TEST_SOURCES
|
||||
until/DriverTest.cpp
|
||||
until/SystemDataTest.cpp
|
||||
until/FaultMapTest.cpp
|
||||
until/UpmsgTest.cpp
|
||||
until/UdpCommTest.cpp
|
||||
until/PmSysvariableTest.cpp
|
||||
until/SqliteTest.cpp
|
||||
)
|
||||
|
||||
add_executable(PowerMangerTests ${PM_TEST_SOURCES}
|
||||
${PM_SRC_DIR}/driver.cpp
|
||||
${PM_SRC_DIR}/udpcomm/udpComm.cpp
|
||||
${PM_SRC_DIR}/upmsg/upmsg_definitions.cpp
|
||||
${PM_SRC_DIR}/sqlit3/SQLite.cpp
|
||||
${PM_SRC_DIR}/sqlit3/sqlite3.c
|
||||
${PM_SRC_DIR}/logc/loguru.cpp
|
||||
)
|
||||
|
||||
target_include_directories(PowerMangerTests PRIVATE
|
||||
${PM_SRC_DIR}
|
||||
${PM_SRC_DIR}/sqlit3
|
||||
${PM_SRC_DIR}/upmsg
|
||||
${PM_SRC_DIR}/udpcomm
|
||||
${PM_SRC_DIR}/logc
|
||||
)
|
||||
|
||||
# gtest 需要 C++14+
|
||||
set_target_properties(PowerMangerTests PROPERTIES
|
||||
CXX_STANDARD 14
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
)
|
||||
|
||||
# 兼容两种 gtest 安装方式:镜像安装(提供 GTest::gtest_main) 或 apt(仅 GTest_LIBRARIES)
|
||||
if(TARGET GTest::gtest_main)
|
||||
set(GTEST_LIBS GTest::gtest_main GTest::gtest)
|
||||
else()
|
||||
set(GTEST_LIBS ${GTest_LIBRARIES})
|
||||
target_include_directories(PowerMangerTests PRIVATE ${GTest_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
target_link_libraries(PowerMangerTests
|
||||
${GTEST_LIBS}
|
||||
${MOOS_LIBRARIES}
|
||||
mbutil
|
||||
jsoncpp
|
||||
m
|
||||
pthread
|
||||
dl
|
||||
)
|
||||
|
||||
################################################udpFeeder(集成测试用)#######
|
||||
# 集成测试辅助:向 pPowerManger 发送真实 CCU 状态反馈 UDP 消息(字节级一致)
|
||||
add_executable(udpFeeder
|
||||
integration/udp_feeder.cpp
|
||||
${PM_SRC_DIR}/udpcomm/udpComm.cpp
|
||||
${PM_SRC_DIR}/logc/loguru.cpp
|
||||
)
|
||||
target_include_directories(udpFeeder PRIVATE
|
||||
${PM_SRC_DIR}
|
||||
${PM_SRC_DIR}/udpcomm
|
||||
${PM_SRC_DIR}/logc
|
||||
)
|
||||
set_target_properties(udpFeeder PROPERTIES
|
||||
CXX_STANDARD 11
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
)
|
||||
target_link_libraries(udpFeeder
|
||||
${MOOS_LIBRARIES}
|
||||
mbutil
|
||||
m
|
||||
pthread
|
||||
dl
|
||||
)
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env python3
|
||||
#=======================================================================
|
||||
# check_db.py: 校验 pPowerManger 写入的 power_data.db 是否有 CCU 反馈记录
|
||||
#(验证 UDP 反馈 → SystemData → SQLite 全链路)。
|
||||
#=======================================================================
|
||||
import sys, os, sqlite3
|
||||
|
||||
def main():
|
||||
db = os.environ.get('PM_DB', '/src/bin/power_data.db')
|
||||
if not os.path.exists(db):
|
||||
print(f"DB not found: {db}")
|
||||
return 1
|
||||
conn = sqlite3.connect(db)
|
||||
cur = conn.cursor()
|
||||
try:
|
||||
cur.execute("SELECT COUNT(*) FROM ccuState")
|
||||
n = cur.fetchone()[0]
|
||||
except Exception as e: # noqa: BLE001
|
||||
print(f"query failed: {e}")
|
||||
conn.close()
|
||||
return 1
|
||||
conn.close()
|
||||
print(f"ccuState rows = {n}")
|
||||
return 0 if n > 0 else 1
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,54 @@
|
||||
//=======================================================================
|
||||
// udp_feeder.cpp: 集成测试用 — 向 pPowerManger 发送 CCU 状态反馈 UDP 消息。
|
||||
// 直接使用真实 C++ 结构体构造消息(字节级与协议一致,无 Python 打包漂移)。
|
||||
// 用法: udpFeeder [host] [port] [count]
|
||||
//=======================================================================
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <unistd.h>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include "udpcomm/udpComm.h"
|
||||
#include "udpcomm/ccuUdpMsg.h"
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
const char* host = (argc > 1) ? argv[1] : "127.0.0.1";
|
||||
int port = (argc > 2) ? atoi(argv[2]) : 5001;
|
||||
int count = (argc > 3) ? atoi(argv[3]) : 6;
|
||||
|
||||
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0) { perror("socket"); return 1; }
|
||||
sockaddr_in addr{};
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(static_cast<unsigned short>(port));
|
||||
if (inet_pton(AF_INET, host, &addr.sin_addr) != 1) {
|
||||
perror("inet_pton");
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
udpComm u;
|
||||
for (int i = 0; i < count; i++) {
|
||||
msg_CcuStateFbMsg m;
|
||||
memset(&m, 0, sizeof(m));
|
||||
m.header.start1 = CCU_UDPMSG_START1;
|
||||
m.header.start2 = CCU_UDPMSG_START2;
|
||||
m.header.id = CCU_STATE_FB_ID;
|
||||
m.data.ins_soc = 42;
|
||||
m.data.dyn_soc = 66;
|
||||
m.data.fc_status = 0x04;
|
||||
m.data.heartbeat = i + 1;
|
||||
m.checkCode = u.calculateChecksum(reinterpret_cast<unsigned char*>(&m), sizeof(m));
|
||||
ssize_t n = sendto(fd, &m, sizeof(m), 0, reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
|
||||
if (n < 0) { perror("sendto"); close(fd); return 1; }
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(300));
|
||||
}
|
||||
close(fd);
|
||||
printf("sent %d CCU state msgs to %s:%d\n", count, host, port);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
//=======================================================================
|
||||
// DriverTest: Driver 类的设备表生成(覆盖全部 10 个工况)、设备状态读写、
|
||||
// JSON 序列化/反序列化。
|
||||
// 不改动生产代码;仅链接 src/pPowerManger/driver.cpp。
|
||||
//=======================================================================
|
||||
#include <gtest/gtest.h>
|
||||
#include <cstring>
|
||||
#include "driver.h"
|
||||
#include "pmSysvariable.h"
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// 全字段比较宏(62 个设备字段)
|
||||
// ----------------------------------------------------------------------
|
||||
#define EXPECT_TABLE_EQ(a, b) do { \
|
||||
EXPECT_EQ((a).depth1,(b).depth1); EXPECT_EQ((a).depth2,(b).depth2); \
|
||||
EXPECT_EQ((a).depth3,(b).depth3); EXPECT_EQ((a).overDeep1,(b).overDeep1); \
|
||||
EXPECT_EQ((a).overDeep2,(b).overDeep2); EXPECT_EQ((a).ctd1,(b).ctd1); \
|
||||
EXPECT_EQ((a).ctd2,(b).ctd2); EXPECT_EQ((a).soundVeloc,(b).soundVeloc); \
|
||||
EXPECT_EQ((a).commMast,(b).commMast); EXPECT_EQ((a).ins,(b).ins); \
|
||||
EXPECT_EQ((a).ntp,(b).ntp); \
|
||||
EXPECT_EQ((a).inputWaterSensor1,(b).inputWaterSensor1); \
|
||||
EXPECT_EQ((a).inputWaterSensor2,(b).inputWaterSensor2); \
|
||||
EXPECT_EQ((a).inputWaterSensor3,(b).inputWaterSensor3); \
|
||||
EXPECT_EQ((a).singleBeamSonar1,(b).singleBeamSonar1); \
|
||||
EXPECT_EQ((a).singleBeamSonar2,(b).singleBeamSonar2); \
|
||||
EXPECT_EQ((a).singleBeamSonar3,(b).singleBeamSonar3); \
|
||||
EXPECT_EQ((a).singleBeamSonar4,(b).singleBeamSonar4); \
|
||||
EXPECT_EQ((a).singleBeamSonar5,(b).singleBeamSonar5); \
|
||||
EXPECT_EQ((a).singleBeamSonar6,(b).singleBeamSonar6); \
|
||||
EXPECT_EQ((a).singleBeamSonar7,(b).singleBeamSonar7); \
|
||||
EXPECT_EQ((a).singleBeamSonar8,(b).singleBeamSonar8); \
|
||||
EXPECT_EQ((a).forwardSonar,(b).forwardSonar); EXPECT_EQ((a).DVL,(b).DVL); \
|
||||
EXPECT_EQ((a).lowFreqSonar,(b).lowFreqSonar); EXPECT_EQ((a).USBL,(b).USBL); \
|
||||
EXPECT_EQ((a).bowWaterInet1,(b).bowWaterInet1); \
|
||||
EXPECT_EQ((a).bowWaterInet2,(b).bowWaterInet2); \
|
||||
EXPECT_EQ((a).bowWaterInet3,(b).bowWaterInet3); \
|
||||
EXPECT_EQ((a).bowWaterInet4,(b).bowWaterInet4); \
|
||||
EXPECT_EQ((a).bowWaterInet5,(b).bowWaterInet5); \
|
||||
EXPECT_EQ((a).bowWaterInet6,(b).bowWaterInet6); \
|
||||
EXPECT_EQ((a).bowWaterInet7,(b).bowWaterInet7); \
|
||||
EXPECT_EQ((a).bowWaterInet8,(b).bowWaterInet8); \
|
||||
EXPECT_EQ((a).bowRudderDeploy,(b).bowRudderDeploy); \
|
||||
EXPECT_EQ((a).bowRudderServo1,(b).bowRudderServo1); \
|
||||
EXPECT_EQ((a).bowRudderServo2,(b).bowRudderServo2); \
|
||||
EXPECT_EQ((a).bowCover1,(b).bowCover1); EXPECT_EQ((a).bowCover2,(b).bowCover2); \
|
||||
EXPECT_EQ((a).bowCover3,(b).bowCover3); EXPECT_EQ((a).bowCover4,(b).bowCover4); \
|
||||
EXPECT_EQ((a).bowCover5,(b).bowCover5); EXPECT_EQ((a).bowCover6,(b).bowCover6); \
|
||||
EXPECT_EQ((a).waterInject,(b).waterInject); \
|
||||
EXPECT_EQ((a).mastLiftingServo,(b).mastLiftingServo); \
|
||||
EXPECT_EQ((a).buoyancyAdjust1,(b).buoyancyAdjust1); \
|
||||
EXPECT_EQ((a).buoyancyAdjust2,(b).buoyancyAdjust2); \
|
||||
EXPECT_EQ((a).buoyancyAdjust3,(b).buoyancyAdjust3); \
|
||||
EXPECT_EQ((a).buoyancyAdjust4,(b).buoyancyAdjust4); \
|
||||
EXPECT_EQ((a).buoyancyAdjust5,(b).buoyancyAdjust5); \
|
||||
EXPECT_EQ((a).sternRudderServo1,(b).sternRudderServo1); \
|
||||
EXPECT_EQ((a).sternRudderServo2,(b).sternRudderServo2); \
|
||||
EXPECT_EQ((a).sternRudderServo3,(b).sternRudderServo3); \
|
||||
EXPECT_EQ((a).sternRudderServo4,(b).sternRudderServo4); \
|
||||
EXPECT_EQ((a).thruster,(b).thruster); EXPECT_EQ((a).bowThrow,(b).bowThrow); \
|
||||
EXPECT_EQ((a).sternThrow,(b).sternThrow); \
|
||||
EXPECT_EQ((a).photoSensor,(b).photoSensor); \
|
||||
EXPECT_EQ((a).electSensor,(b).electSensor); \
|
||||
EXPECT_EQ((a).launchControler,(b).launchControler); \
|
||||
EXPECT_EQ((a).sideSonar,(b).sideSonar); EXPECT_EQ((a).buoyage,(b).buoyage); \
|
||||
} while (0)
|
||||
|
||||
// 传感器统一全开
|
||||
static void setSensors(DriverTable& t) {
|
||||
t.depth1 = t.depth2 = t.depth3 = 1;
|
||||
t.overDeep1 = t.overDeep2 = 1;
|
||||
t.ctd1 = t.ctd2 = 1;
|
||||
t.soundVeloc = 1;
|
||||
t.commMast = 1;
|
||||
t.ins = 1;
|
||||
t.ntp = 1;
|
||||
t.inputWaterSensor1 = t.inputWaterSensor2 = t.inputWaterSensor3 = 1;
|
||||
}
|
||||
|
||||
// 执行机构(舵/浮调/推进/抛载)全开
|
||||
static void setActuatorsOn(DriverTable& t) {
|
||||
t.bowRudderDeploy = t.bowRudderServo1 = t.bowRudderServo2 = 1;
|
||||
t.buoyancyAdjust1 = t.buoyancyAdjust2 = t.buoyancyAdjust3 = 1;
|
||||
t.buoyancyAdjust4 = t.buoyancyAdjust5 = 1;
|
||||
t.sternRudderServo1 = t.sternRudderServo2 = t.sternRudderServo3 = t.sternRudderServo4 = 1;
|
||||
t.thruster = 1;
|
||||
t.bowThrow = t.sternThrow = 1;
|
||||
}
|
||||
|
||||
static DriverTable makeSTANDBY() {
|
||||
DriverTable t{}; setSensors(t); /* 其余全 0 */ return t;
|
||||
}
|
||||
static DriverTable makeSHORE_WATER() {
|
||||
DriverTable t{}; setSensors(t); setActuatorsOn(t);
|
||||
t.mastLiftingServo = 1;
|
||||
t.bowCover1 = t.bowCover2 = t.bowCover3 = 1;
|
||||
t.bowCover4 = t.bowCover5 = t.bowCover6 = 1;
|
||||
t.bowWaterInet1 = t.bowWaterInet2 = t.bowWaterInet3 = t.bowWaterInet4 = 1;
|
||||
t.bowWaterInet5 = t.bowWaterInet6 = t.bowWaterInet7 = t.bowWaterInet8 = 1;
|
||||
t.waterInject = 1;
|
||||
return t;
|
||||
}
|
||||
static DriverTable makeCRUISE() {
|
||||
DriverTable t{}; setSensors(t); setActuatorsOn(t);
|
||||
t.mastLiftingServo = 1;
|
||||
return t; // 水声设备不设置(保持 0)
|
||||
}
|
||||
static DriverTable makeHIGH_SPEED() {
|
||||
DriverTable t{}; setSensors(t);
|
||||
t.bowRudderDeploy = t.bowRudderServo1 = t.bowRudderServo2 = 1;
|
||||
t.sternRudderServo1 = t.sternRudderServo2 = t.sternRudderServo3 = t.sternRudderServo4 = 1;
|
||||
t.thruster = 1; t.bowThrow = t.sternThrow = 1;
|
||||
/* mastLiftingServo / buoyancyAdjust 全 0 */
|
||||
return t;
|
||||
}
|
||||
static DriverTable makeASCEND_BUOYANCY() {
|
||||
DriverTable t{}; setSensors(t); setActuatorsOn(t);
|
||||
t.mastLiftingServo = 1;
|
||||
return t;
|
||||
}
|
||||
static DriverTable makeUNDERWATER() {
|
||||
DriverTable t{}; setSensors(t); setActuatorsOn(t);
|
||||
t.sideSonar = DRIVER_STANDBY; /* mastLiftingServo = 0 */
|
||||
return t;
|
||||
}
|
||||
static DriverTable makeSURFACE() {
|
||||
DriverTable t{}; setSensors(t); setActuatorsOn(t);
|
||||
t.mastLiftingServo = 1;
|
||||
t.photoSensor = t.electSensor = DRIVER_STANDBY;
|
||||
return t;
|
||||
}
|
||||
static DriverTable makeDJ() {
|
||||
DriverTable t{}; setSensors(t); setActuatorsOn(t);
|
||||
t.mastLiftingServo = 1;
|
||||
t.launchControler = 1;
|
||||
t.buoyage = DRIVER_STANDBY;
|
||||
t.bowCover1 = t.bowCover2 = t.bowCover3 = 1;
|
||||
t.bowCover4 = t.bowCover5 = t.bowCover6 = 1;
|
||||
t.bowWaterInet1 = t.bowWaterInet2 = t.bowWaterInet3 = t.bowWaterInet4 = 1;
|
||||
t.bowWaterInet5 = t.bowWaterInet6 = t.bowWaterInet7 = t.bowWaterInet8 = 1;
|
||||
return t;
|
||||
}
|
||||
|
||||
using TableFn = void (Driver::*)(DriverTable*);
|
||||
|
||||
TEST(DriverTest, StandbyTable) {
|
||||
DriverTable e = makeSTANDBY(); DriverTable a{}; Driver d; d.getSTANDBYTable(&a);
|
||||
EXPECT_TABLE_EQ(a, e);
|
||||
}
|
||||
TEST(DriverTest, ShoreBasedReadyTable) {
|
||||
DriverTable e = makeSHORE_WATER(); DriverTable a{}; Driver d; d.getSHORE_BASED_READYable(&a);
|
||||
EXPECT_TABLE_EQ(a, e);
|
||||
}
|
||||
TEST(DriverTest, WaterBasedReadyTable) {
|
||||
DriverTable e = makeSHORE_WATER(); DriverTable a{}; Driver d; d.getWATER_BASED_READYable(&a);
|
||||
EXPECT_TABLE_EQ(a, e);
|
||||
}
|
||||
TEST(DriverTest, CruiseModeTable) {
|
||||
DriverTable e = makeCRUISE(); DriverTable a{}; Driver d; d.getCRUISE_MODEable(&a);
|
||||
EXPECT_TABLE_EQ(a, e);
|
||||
}
|
||||
TEST(DriverTest, HighSpeedModeTable) {
|
||||
DriverTable e = makeHIGH_SPEED(); DriverTable a{}; Driver d; d.getHIGH_SPEED_MODEable(&a);
|
||||
EXPECT_TABLE_EQ(a, e);
|
||||
}
|
||||
TEST(DriverTest, AscendDescendTable) {
|
||||
DriverTable e = makeASCEND_BUOYANCY(); DriverTable a{}; Driver d; d.getASCEND_DESCENDable(&a);
|
||||
EXPECT_TABLE_EQ(a, e);
|
||||
}
|
||||
TEST(DriverTest, BuoyancyAdjustTable) {
|
||||
DriverTable e = makeASCEND_BUOYANCY(); DriverTable a{}; Driver d; d.getBUOYANCY_ADJUSTable(&a);
|
||||
EXPECT_TABLE_EQ(a, e);
|
||||
}
|
||||
TEST(DriverTest, UnderwaterReconTable) {
|
||||
DriverTable e = makeUNDERWATER(); DriverTable a{}; Driver d; d.getUNDERWATER_RECONable(&a);
|
||||
EXPECT_TABLE_EQ(a, e);
|
||||
}
|
||||
TEST(DriverTest, SurfaceReconTable) {
|
||||
DriverTable e = makeSURFACE(); DriverTable a{}; Driver d; d.getSURFACE_RECONable(&a);
|
||||
EXPECT_TABLE_EQ(a, e);
|
||||
}
|
||||
TEST(DriverTest, DjModeTable) {
|
||||
DriverTable e = makeDJ(); DriverTable a{}; Driver d; d.getDJ_MODEable(&a);
|
||||
EXPECT_TABLE_EQ(a, e);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// setDeviceState / getDeviceState
|
||||
// ----------------------------------------------------------------------
|
||||
TEST(DriverTest, SetGetDeviceState)
|
||||
{
|
||||
Driver d;
|
||||
DriverTable t{};
|
||||
d.setDeviceState(t, DeviceId::thruster, DRIVER_FULL_POWER_ON);
|
||||
EXPECT_EQ(d.getDeviceState(t, DeviceId::thruster), 1u);
|
||||
d.setDeviceState(t, DeviceId::thruster, DRIVER_POWER_OFF);
|
||||
EXPECT_EQ(d.getDeviceState(t, DeviceId::thruster), 0u);
|
||||
d.setDeviceState(t, DeviceId::sideSonar, DRIVER_STANDBY);
|
||||
EXPECT_EQ(d.getDeviceState(t, DeviceId::sideSonar), 4u);
|
||||
d.setDeviceState(t, DeviceId::bowCover1, DRIVER_FULL_POWER_ON);
|
||||
EXPECT_EQ(d.getDeviceState(t, DeviceId::bowCover1), 1u);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// JSON 序列化/反序列化往返
|
||||
// ----------------------------------------------------------------------
|
||||
TEST(DriverTest, JsonRoundTrip)
|
||||
{
|
||||
Driver d;
|
||||
DriverTable t{};
|
||||
d.setDeviceState(t, DeviceId::thruster, DRIVER_FULL_POWER_ON);
|
||||
d.setDeviceState(t, DeviceId::sideSonar, DRIVER_STANDBY);
|
||||
d.setDeviceState(t, DeviceId::bowCover3, DRIVER_FULL_POWER_ON);
|
||||
std::string json = d.saveDriverTableToJson(&t);
|
||||
ASSERT_FALSE(json.empty());
|
||||
|
||||
DriverTable out{};
|
||||
EXPECT_EQ(d.loadDriverTableFromJson(json, out), 0);
|
||||
EXPECT_EQ(out.thruster, 1u);
|
||||
EXPECT_EQ(out.sideSonar, 4u);
|
||||
EXPECT_EQ(out.bowCover3, 1u);
|
||||
EXPECT_EQ(out.depth1, 0u); // 未设置字段为 0
|
||||
}
|
||||
|
||||
TEST(DriverTest, LoadDriverIdFromJson)
|
||||
{
|
||||
Driver d;
|
||||
std::string json = R"({"thruster_uint8":1,"sideSonar_uint8":4})";
|
||||
auto cmds = d.loadDriverIdFromJson(json);
|
||||
ASSERT_EQ(cmds.size(), 2u);
|
||||
bool hasThruster = false, hasSide = false;
|
||||
for (auto& c : cmds) {
|
||||
if (c.id == DeviceId::thruster) { EXPECT_EQ(c.cmd, 1); hasThruster = true; }
|
||||
if (c.id == DeviceId::sideSonar) { EXPECT_EQ(c.cmd, 4); hasSide = true; }
|
||||
}
|
||||
EXPECT_TRUE(hasThruster);
|
||||
EXPECT_TRUE(hasSide);
|
||||
}
|
||||
|
||||
TEST(DriverTest, SafeReadUInt)
|
||||
{
|
||||
Driver d;
|
||||
Json::Value root;
|
||||
root["a"] = 5u;
|
||||
root["b"] = -3;
|
||||
unsigned char v = 0;
|
||||
EXPECT_EQ(d.SafeReadUInt(root, "a", v), 0);
|
||||
EXPECT_EQ(v, 5u);
|
||||
// 缺字段
|
||||
EXPECT_EQ(d.SafeReadUInt(root, "missing", v), -1);
|
||||
// 类型错误(有符号负数)
|
||||
EXPECT_EQ(d.SafeReadUInt(root, "b", v), -2);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
//=======================================================================
|
||||
// FaultMapTest: 锂电池/配电故障码表的完整性(码值唯一、级别正确)
|
||||
// 不改动生产代码;仅验证 faultCode.h 中的静态表。
|
||||
//=======================================================================
|
||||
#include <gtest/gtest.h>
|
||||
#include <set>
|
||||
#include "faultCode.h"
|
||||
|
||||
TEST(FaultMapTest, BatteryFaultMap)
|
||||
{
|
||||
const size_t n = sizeof(batfaultMap) / sizeof(batfaultMap[0]);
|
||||
ASSERT_EQ(n, 54u) << "batfaultMap 应有 54 条";
|
||||
std::set<uint8_t> codes;
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
EXPECT_EQ(batfaultMap[i].id, (int)i + 1) << "id 必须从 1 连续";
|
||||
EXPECT_GE(batfaultMap[i].level, 1);
|
||||
EXPECT_LE(batfaultMap[i].level, 4);
|
||||
EXPECT_TRUE(batfaultMap[i].desc != nullptr && batfaultMap[i].desc[0] != '\0')
|
||||
<< "desc 不能为空, id=" << i + 1;
|
||||
EXPECT_TRUE(codes.insert(batfaultMap[i].code).second)
|
||||
<< "重复故障码 0x" << std::hex << (int)batfaultMap[i].code;
|
||||
}
|
||||
// 抽样:4级故障码在 0xCx,3级在 0x8x,1级在 0x0x-0x1x
|
||||
EXPECT_EQ(batfaultMap[0].code, 0xC1); // id1 四级 MBMS绝缘故障
|
||||
EXPECT_EQ(batfaultMap[9].code, 0x81); // id10 三级
|
||||
EXPECT_EQ(batfaultMap[40].code, 0x01); // id41 一级
|
||||
}
|
||||
|
||||
TEST(FaultMapTest, DistributionFaultMap)
|
||||
{
|
||||
const size_t n = sizeof(disfaultMap) / sizeof(disfaultMap[0]);
|
||||
ASSERT_EQ(n, 45u) << "disfaultMap 应有 45 条";
|
||||
std::set<int> codes;
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
EXPECT_EQ(disfaultMap[i].id, (int)i + 1) << "id 必须从 1 连续";
|
||||
EXPECT_GE(disfaultMap[i].level, 1);
|
||||
EXPECT_LE(disfaultMap[i].level, 4);
|
||||
EXPECT_TRUE(disfaultMap[i].desc != nullptr && disfaultMap[i].desc[0] != '\0');
|
||||
EXPECT_TRUE(codes.insert(disfaultMap[i].code).second)
|
||||
<< "重复故障码 " << disfaultMap[i].code;
|
||||
}
|
||||
// 断路器脱扣基本是 4 级故障
|
||||
EXPECT_EQ(disfaultMap[0].level, 3); // id1 燃料电池断路器 3级
|
||||
EXPECT_EQ(disfaultMap[1].level, 4); // id2 动力锂电池断路器 4级
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
//=======================================================================
|
||||
// PmSysvariableTest: 协议结构体 pack(1) 大小/偏移 + 枚举/宏完整性
|
||||
// 不改动生产代码;检测二进制协议漂移与枚举值变化。
|
||||
//=======================================================================
|
||||
#include <gtest/gtest.h>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include "pmSysvariable.h"
|
||||
#include "driver.h"
|
||||
#include "udpcomm/ccuUdpMsg.h"
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// pack(1) 协议结构体大小断言
|
||||
// ----------------------------------------------------------------------
|
||||
TEST(PmSysvariableTest, HeaderStructSize)
|
||||
{
|
||||
EXPECT_EQ(sizeof(m_header), 6u); // start1+start2+id+length = 1+1+2+2
|
||||
EXPECT_EQ(offsetof(m_header, id), 2u);
|
||||
EXPECT_EQ(offsetof(m_header, length), 4u);
|
||||
}
|
||||
|
||||
TEST(PmSysvariableTest, PackedMessageStructSizes)
|
||||
{
|
||||
// header(6) + flag(1) + failureCode(1) + Checksum(4)
|
||||
EXPECT_EQ(sizeof(msg_CcuSetParmFbMsg), 12u);
|
||||
// header(6) + m_date(8) + ccuColCmd + Checksum(4)
|
||||
EXPECT_EQ(sizeof(msg_CcuColCmdMsg), 6u + sizeof(m_date) + sizeof(ccuColCmd) + 4u);
|
||||
// header(6) + disHighVolBusCmd + cChecksum(1)
|
||||
EXPECT_EQ(sizeof(msg_disHVBCmd), 6u + sizeof(disHighVolBusCmd) + 1u);
|
||||
// header(6) + ccuState + Checksum(4)
|
||||
EXPECT_EQ(sizeof(msg_CcuStateFbMsg), 6u + sizeof(ccuState) + 4u);
|
||||
}
|
||||
|
||||
TEST(PmSysvariableTest, NoImplicitPadding)
|
||||
{
|
||||
// pack(1):字段偏移必须连续(抽样检查,防意外 padding)
|
||||
EXPECT_EQ(offsetof(ccuColCmd, heartbeat), offsetof(ccuColCmd, powerBatEfficiency) + sizeof(unsigned short));
|
||||
EXPECT_EQ(offsetof(disHighVolBusCmd, coolingSystem),
|
||||
offsetof(disHighVolBusCmd, dcdc5Module) + 1);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// 宏值
|
||||
// ----------------------------------------------------------------------
|
||||
TEST(PmSysvariableTest, MacroConstants)
|
||||
{
|
||||
EXPECT_EQ(BREAK_ON, 0x55);
|
||||
EXPECT_EQ(BREAK_OFF, 0xAA);
|
||||
EXPECT_EQ(BREAK_FALSE, 0x5A);
|
||||
EXPECT_EQ(DIS_BREAKER_ON, 0x55);
|
||||
EXPECT_EQ(DIS_BREAKER_OFF, 0xAA);
|
||||
EXPECT_EQ(DIS_FAULTOFF, 0x5A);
|
||||
EXPECT_EQ(DRIVER_POWER_OFF, 0x00);
|
||||
EXPECT_EQ(DRIVER_FULL_POWER_ON, 0x01);
|
||||
EXPECT_EQ(DRIVER_INSTRUMENT_POWER_ON, 0x02);
|
||||
EXPECT_EQ(DRIVER_MOTIVE_POWER_ON, 0x03);
|
||||
EXPECT_EQ(DRIVER_STANDBY, 0x04);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// 工况枚举
|
||||
// ----------------------------------------------------------------------
|
||||
TEST(PmSysvariableTest, WorkConditionEnum)
|
||||
{
|
||||
EXPECT_EQ((int)WorkCondition::CHANING, 0);
|
||||
EXPECT_EQ((int)WorkCondition::STANDBY, 1);
|
||||
EXPECT_EQ((int)WorkCondition::SHORE_BASED_READY, 2);
|
||||
EXPECT_EQ((int)WorkCondition::WATER_BASED_READY, 3);
|
||||
EXPECT_EQ((int)WorkCondition::REMOTE_CONTROL, 4);
|
||||
EXPECT_EQ((int)WorkCondition::CRUISE_MODE, 5);
|
||||
EXPECT_EQ((int)WorkCondition::HIGH_SPEED_MODE, 6);
|
||||
EXPECT_EQ((int)WorkCondition::ASCEND_DESCEND, 7);
|
||||
EXPECT_EQ((int)WorkCondition::BUOYANCY_ADJUST, 8);
|
||||
EXPECT_EQ((int)WorkCondition::UNDERWATER_RECON, 9);
|
||||
EXPECT_EQ((int)WorkCondition::SURFACE_RECON, 10);
|
||||
EXPECT_EQ((int)WorkCondition::DJ_MODE, 11);
|
||||
EXPECT_EQ((int)WorkCondition::LIFT_MODE, 12);
|
||||
}
|
||||
|
||||
TEST(PmSysvariableTest, TaskTypeEnum)
|
||||
{
|
||||
EXPECT_EQ((int)TaskType::THROW_LOAD, 1);
|
||||
EXPECT_EQ((int)TaskType::FLOAT_UP, 2);
|
||||
EXPECT_EQ((int)TaskType::RECYCLE, 3);
|
||||
EXPECT_EQ((int)TaskType::HOVER, 4);
|
||||
EXPECT_EQ((int)TaskType::SAT_COMM, 5);
|
||||
EXPECT_EQ((int)TaskType::SAT_CALIBRATE, 6);
|
||||
EXPECT_EQ((int)TaskType::TOUR, 7);
|
||||
EXPECT_EQ((int)TaskType::SAIL, 8);
|
||||
EXPECT_EQ((int)TaskType::EMER_SAT_COMM, 9);
|
||||
EXPECT_EQ((int)TaskType::EMER_SAIL, 10);
|
||||
EXPECT_STREQ(TaskType::toString(TaskType::SAIL).c_str(), "sail");
|
||||
EXPECT_STREQ(TaskType::toString(TaskType::EMER_SAIL).c_str(), "emerSail");
|
||||
EXPECT_EQ((int)TaskType::fromString("tour"), (int)TaskType::TOUR);
|
||||
}
|
||||
|
||||
TEST(PmSysvariableTest, ModeEnum)
|
||||
{
|
||||
EXPECT_EQ((int)PMMode::Normal, 0);
|
||||
EXPECT_EQ((int)PMMode::Test, 1);
|
||||
EXPECT_EQ((int)PMMode::Debug, 2);
|
||||
EXPECT_EQ((int)RunMode::Normal, 0);
|
||||
EXPECT_EQ((int)RunMode::Test, 1);
|
||||
EXPECT_EQ((int)RunMode::Debug, 2);
|
||||
}
|
||||
|
||||
TEST(PmSysvariableTest, EquipmentCommandEnum)
|
||||
{
|
||||
EXPECT_EQ((int)EquipmentCommand::OFF, 0);
|
||||
EXPECT_EQ((int)EquipmentCommand::ON, 1);
|
||||
EXPECT_EQ((int)EquipmentCommand::METER_ON, 2);
|
||||
EXPECT_EQ((int)EquipmentCommand::POWER_ON, 3);
|
||||
EXPECT_EQ((int)EquipmentCommand::METER_OFF, 4);
|
||||
EXPECT_EQ((int)EquipmentCommand::POWER_OFF, 5);
|
||||
}
|
||||
|
||||
TEST(PmSysvariableTest, DeviceIdSpotCheck)
|
||||
{
|
||||
EXPECT_EQ((int)DeviceId::thruster, 53);
|
||||
EXPECT_EQ((int)DeviceId::sideSonar, 35);
|
||||
EXPECT_EQ((int)DeviceId::bowRudderDeploy, 15);
|
||||
EXPECT_EQ((int)DeviceId::mastLiftingServo, 41);
|
||||
EXPECT_EQ((int)DeviceId::buoyancyAdjust1, 44);
|
||||
EXPECT_EQ((int)DeviceId::sternRudderServo1, 49);
|
||||
EXPECT_EQ((int)DeviceId::commMast, 40);
|
||||
EXPECT_STREQ(DeviceId::toString(DeviceId::thruster).c_str(), "thruster");
|
||||
}
|
||||
|
||||
TEST(PmSysvariableTest, DeviceIdSets)
|
||||
{
|
||||
// 水声设备集合与无电设备集合互斥
|
||||
EXPECT_TRUE(underWterDevices.count(DeviceId::DVL) == 1);
|
||||
EXPECT_TRUE(underWterDevices.count(DeviceId::singleBeamSonar1) == 1);
|
||||
EXPECT_TRUE(noPowerDevices.count(DeviceId::depth1) == 1);
|
||||
EXPECT_TRUE(noPowerDevices.count(DeviceId::ins) == 1);
|
||||
// 无电设备不应出现在水声设备里
|
||||
EXPECT_TRUE(underWterDevices.count(DeviceId::depth1) == 0);
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
//=======================================================================
|
||||
// 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);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
//=======================================================================
|
||||
// SystemDataTest: SystemData 的故障检测逻辑(断路器映射、绝缘、电源失电、
|
||||
// 漏水、DCDC、继电器位提取、缩放、故障码集合、漏水位)。
|
||||
// 不改动生产代码;仅链接现有 systemData.h + SQLite + MOOS。
|
||||
//=======================================================================
|
||||
#include <gtest/gtest.h>
|
||||
#include "MOOS/libMOOS/Utils/MOOSUtilityFunctions.h" // MOOSTime (updateCommonStatus)
|
||||
#include "systemData.h"
|
||||
#include "faultCode.h"
|
||||
|
||||
TEST(SystemDataTest, BreakerMapping)
|
||||
{
|
||||
SystemData sd;
|
||||
unsigned char status = 0;
|
||||
// 0x55 = 闭合(1),无故障码
|
||||
sd.updateBreakerFault(status, 0x55, 99);
|
||||
EXPECT_EQ(status, 1u);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(99), 0u);
|
||||
// 0xAA = 断开(0),无故障码
|
||||
sd.updateBreakerFault(status, 0xAA, 99);
|
||||
EXPECT_EQ(status, 0u);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(99), 0u);
|
||||
// 0x5A = 故障脱扣(2),插入故障码
|
||||
sd.updateBreakerFault(status, 0x5A, 99);
|
||||
EXPECT_EQ(status, 2u);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(99), 1u);
|
||||
// 再次正常后擦除
|
||||
sd.updateBreakerFault(status, 0x55, 99);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(99), 0u);
|
||||
}
|
||||
|
||||
TEST(SystemDataTest, HighVolBusFaultDetection)
|
||||
{
|
||||
SystemData sd;
|
||||
disHighVolBusState s{};
|
||||
// 全 0xAA(断开,正常)
|
||||
s.fuelCellCircuitBreaker = 0xAA;
|
||||
s.powerLithiumBatteryCircuitBreaker = 0xAA;
|
||||
s.propulsionMotorCircuitBreaker = 0xAA;
|
||||
s.lithiumBatteryGroupInstrumentCircuitBreaker = 0xAA;
|
||||
s.dcDc5ModuleCircuitBreaker = 0xAA;
|
||||
s.bowHighVoltageDistributionBoxCircuitBreaker = 0xAA;
|
||||
s.sternFTDevice45CircuitBreaker = 0xAA;
|
||||
s.sternRudderSwitch1CircuitBreaker = 0xAA;
|
||||
s.sternRudderSwitch2CircuitBreaker = 0xAA;
|
||||
s.powerBusInsulationStatus = 0x55;
|
||||
s.aBusInsulationStatus = 0x55;
|
||||
s.meterPowerLossSignal = 0x55;
|
||||
s.emergencyPowerLossSignal = 0x55;
|
||||
sd.updateSystemData(s);
|
||||
EXPECT_EQ(sd.power_bus_status.fuelCellCircuitBreaker, 0u);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(1), 0u);
|
||||
|
||||
// 燃料电断路器故障脱扣
|
||||
s.fuelCellCircuitBreaker = 0x5A;
|
||||
sd.updateSystemData(s);
|
||||
EXPECT_EQ(sd.power_bus_status.fuelCellCircuitBreaker, 2u);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(1), 1u);
|
||||
|
||||
// 动力锂电池闭合 + A汇流排/动力母排绝缘低 → 34/35
|
||||
s.fuelCellCircuitBreaker = 0xAA;
|
||||
s.powerLithiumBatteryCircuitBreaker = 0x55;
|
||||
s.powerBusInsulationStatus = 0xAA;
|
||||
s.aBusInsulationStatus = 0xAA;
|
||||
sd.updateSystemData(s);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(34), 1u);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(35), 1u);
|
||||
EXPECT_EQ(sd.power_bus_status.powerBusInsulationStatus, 1u);
|
||||
EXPECT_EQ(sd.power_bus_status.aBusInsulationStatus, 1u);
|
||||
|
||||
// 电源失电 → 36/37
|
||||
s.meterPowerLossSignal = 0xAA;
|
||||
s.emergencyPowerLossSignal = 0xAA;
|
||||
sd.updateSystemData(s);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(36), 1u);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(37), 1u);
|
||||
|
||||
// 全部恢复正常后故障码擦除
|
||||
s.powerLithiumBatteryCircuitBreaker = 0xAA;
|
||||
s.powerBusInsulationStatus = 0x55;
|
||||
s.aBusInsulationStatus = 0x55;
|
||||
s.meterPowerLossSignal = 0x55;
|
||||
s.emergencyPowerLossSignal = 0x55;
|
||||
sd.updateSystemData(s);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(34), 0u);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(35), 0u);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(36), 0u);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(37), 0u);
|
||||
}
|
||||
|
||||
TEST(SystemDataTest, HighAVolBusFaultDetection)
|
||||
{
|
||||
SystemData sd;
|
||||
disHighAVolBusState s{};
|
||||
s.actuatorCircuitBreaker = 0x5A; // 启闭机构断路器脱扣 → 14
|
||||
s.xczCircuitBreaker = 0x55;
|
||||
s.instrumentPowerFailureSignal = 0x55;
|
||||
s.emergencyPowerFailureSignal = 0x55;
|
||||
s.waterIngressionAlarm = 0x55;
|
||||
sd.updateSystemData(s);
|
||||
EXPECT_EQ(sd.power_a_bus_status.actuatorCircuitBreaker, 2u);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(14), 1u);
|
||||
|
||||
s.actuatorCircuitBreaker = 0xAA;
|
||||
s.instrumentPowerFailureSignal = 0xAA; // 失电 → 38
|
||||
s.emergencyPowerFailureSignal = 0xAA; // 失电 → 39
|
||||
s.waterIngressionAlarm = 0xAA; // 浸水 → leakStatus[BOW_HIGH_VOLTAGE]
|
||||
sd.updateSystemData(s);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(14), 0u);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(38), 1u);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(39), 1u);
|
||||
EXPECT_TRUE(sd.leakStatus[SystemData::LEAKAGE_BOW_HIGH_VOLTAGE]);
|
||||
}
|
||||
|
||||
TEST(SystemDataTest, LowMainBusFaultDetection)
|
||||
{
|
||||
SystemData sd;
|
||||
disLowMainBusState s{};
|
||||
s.lithiumBatteryGroupInstrumentCircuitBreaker = 0x5A; // 19
|
||||
s.unit4InstrumentDC48VCircuitBreaker = 0x5A; // 21
|
||||
s.instrumentPowerFailureSignal = 0xAA; // 41
|
||||
s.emergencyPowerFailureSignal = 0xAA; // 42
|
||||
s.instrumentBusbarInsulationLow = 0xAA; // 43
|
||||
sd.updateSystemData(s);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(19), 1u);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(21), 1u);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(41), 1u);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(42), 1u);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(43), 1u);
|
||||
}
|
||||
|
||||
TEST(SystemDataTest, LowBusFaultDetection)
|
||||
{
|
||||
SystemData sd;
|
||||
disLowBusState s{};
|
||||
s.unit1CircuitBreaker = 0x5A; // 26
|
||||
s.emergencyLithiumBatteryGroup1CircuitBreaker = 0x5A; // 33
|
||||
s.powerFailureSignal = 0xAA; // 44
|
||||
s.emergencyPowerFailureSignal = 0xAA; // 45
|
||||
s.waterIngressionAlarm = 0xAA; // leakage BOW_LOW_VOLTAGE
|
||||
sd.updateSystemData(s);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(26), 1u);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(33), 1u);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(44), 1u);
|
||||
EXPECT_EQ(sd.disSysFaultCode.count(45), 1u);
|
||||
EXPECT_TRUE(sd.leakStatus[SystemData::LEAKAGE_BOW_LOW_VOLTAGE]);
|
||||
}
|
||||
|
||||
TEST(SystemDataTest, CcuStateScalingAndRelayBits)
|
||||
{
|
||||
SystemData sd;
|
||||
ccuState c{};
|
||||
c.ins_soc = 60;
|
||||
c.dyn_soc = 80;
|
||||
c.ins_relay_status1 = 0x12; // 高4位=1(充电), 低4位=2(正极)
|
||||
c.ins_relay_status2 = 0x34;
|
||||
c.ins_voltage_link = 4800; // ×0.1 = 480.0
|
||||
c.ins_water_leak_dcdc_status = 0x11; // 高4位=1 漏水, 低4位=1 DCDC故障
|
||||
c.dyn_water_leak_status = 0x21; // 高4位=2, 低4位=1
|
||||
sd.updateSystemData(c);
|
||||
EXPECT_EQ(sd.ins_soc, 60);
|
||||
EXPECT_EQ(sd.dyn_soc, 80);
|
||||
EXPECT_EQ(sd.ins_pos_relay_status, 2u); // 低4位
|
||||
EXPECT_EQ(sd.ins_charge_relay_status, 1u); // 高4位
|
||||
EXPECT_EQ(sd.ins_precharge_relay_status, 4u); // 低4位 of status2
|
||||
EXPECT_EQ(sd.ins_neg_relay_status, 3u); // 高4位 of status2
|
||||
EXPECT_NEAR(sd.ins_voltage_link, 480.0, 0.01);
|
||||
EXPECT_EQ(sd.water_leak_status_from_insbat, 1u);
|
||||
EXPECT_EQ(sd.dcdc_status_from_insbat, 1u);
|
||||
EXPECT_TRUE(sd.leakStatus[SystemData::LEAKAGE_LI_BATTERY]);
|
||||
}
|
||||
|
||||
TEST(SystemDataTest, FaultCodeSetAndLevel)
|
||||
{
|
||||
SystemData sd;
|
||||
EXPECT_EQ(sd.getFaultCodeLevel(), 0u);
|
||||
sd.insertFaultCode(0x1102); // 0x11>>... level = (0x1102>>8)&0xF = 1
|
||||
EXPECT_EQ(sd.getFaultCodeLevel(), 1u);
|
||||
sd.insertFaultCode(0x4402); // level = (0x4402>>8)&0xF = 4
|
||||
EXPECT_EQ(sd.getFaultCodeLevel(), 4u);
|
||||
sd.eraseFaultCode(0x4402);
|
||||
EXPECT_EQ(sd.getFaultCodeLevel(), 1u);
|
||||
auto codes = sd.getFaultCode();
|
||||
EXPECT_EQ(codes.count(0x1102), 1u);
|
||||
}
|
||||
|
||||
TEST(SystemDataTest, LeakageCodeGeneration)
|
||||
{
|
||||
SystemData sd;
|
||||
EXPECT_EQ(sd.generateLeakageCode(), 0u);
|
||||
sd.leakStatus[SystemData::LEAKAGE_BOW_EMERGENCY] = true; // 0x01
|
||||
sd.leakStatus[SystemData::LEAKAGE_FUEL_CELL] = true; // 0x08
|
||||
sd.leakStatus[SystemData::LEAKAGE_LI_BATTERY] = true; // 0x10
|
||||
EXPECT_EQ(sd.generateLeakageCode(), 0x19u);
|
||||
}
|
||||
|
||||
TEST(SystemDataTest, CommonStatusTimeout)
|
||||
{
|
||||
SystemData sd;
|
||||
sd.updateCommonStatus(30.0);
|
||||
// 新建 SystemData 的 lastUpdateTime=0,与当前 MOOSTime 之差远大于 30s
|
||||
EXPECT_TRUE(sd.device_common_status.ccu_status.isTimeout);
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
//=======================================================================
|
||||
// UdpCommTest: udpComm 纯逻辑函数(校验和、消息头识别、校验解析、日期)
|
||||
// 仅链接现有 udpcomm/udpComm.cpp(+ MOOS 提供 MOOSTime 等符号)。
|
||||
//=======================================================================
|
||||
#include <gtest/gtest.h>
|
||||
#include <cstring>
|
||||
#include "udpcomm/udpComm.h"
|
||||
|
||||
TEST(UdpCommTest, CalculateChecksum)
|
||||
{
|
||||
udpComm u;
|
||||
unsigned char data[5] = {1, 2, 3, 4, 5};
|
||||
// 2 参:sum 覆盖 size - sizeof(Checksum)=size-4 字节
|
||||
EXPECT_EQ(u.calculateChecksum(data, 4), 0u);
|
||||
EXPECT_EQ(u.calculateChecksum(data, 5), 1u); // 只 sum data[0]=1
|
||||
EXPECT_EQ(u.calculateChecksum(data, 6), 3u); // sum data[0..1]=1+2
|
||||
// 3 参:覆盖 dataSize - checkSize 字节
|
||||
EXPECT_EQ(u.calculateChecksum(data, 5, 2), 6u); // sum data[0..2]=1+2+3
|
||||
EXPECT_EQ(u.calculateChecksum(data, 5, 1), 10u);// sum data[0..3]
|
||||
}
|
||||
|
||||
TEST(UdpCommTest, GetMsgId)
|
||||
{
|
||||
udpComm u;
|
||||
m_header h{};
|
||||
char buf[sizeof(m_header)];
|
||||
unsigned short id = 0;
|
||||
|
||||
// DIS 头
|
||||
h.start1 = DIS_MSG_HEAD1;
|
||||
h.start2 = DIS_MSG_HEAD2;
|
||||
h.id = DIS_HVBUS_FB_ID;
|
||||
memcpy(buf, &h, sizeof(h));
|
||||
EXPECT_TRUE(u.getMsgId(buf, id));
|
||||
EXPECT_EQ(id, DIS_HVBUS_FB_ID);
|
||||
|
||||
// CCU 头
|
||||
h.start1 = CCU_UDPMSG_START1;
|
||||
h.start2 = CCU_UDPMSG_START2;
|
||||
h.id = CCU_STATE_FB_ID;
|
||||
memcpy(buf, &h, sizeof(h));
|
||||
EXPECT_TRUE(u.getMsgId(buf, id));
|
||||
EXPECT_EQ(id, CCU_STATE_FB_ID);
|
||||
|
||||
// 非法头
|
||||
h.start1 = 0x11;
|
||||
h.start2 = 0x22;
|
||||
memcpy(buf, &h, sizeof(h));
|
||||
EXPECT_FALSE(u.getMsgId(buf, id));
|
||||
}
|
||||
|
||||
TEST(UdpCommTest, GetMsgFromBuffCcu)
|
||||
{
|
||||
udpComm u;
|
||||
msg_CcuStateFbMsg m;
|
||||
memset(&m, 0, sizeof(m));
|
||||
m.header.start1 = CCU_UDPMSG_START1;
|
||||
m.header.start2 = CCU_UDPMSG_START2;
|
||||
m.header.id = CCU_STATE_FB_ID;
|
||||
m.data.ins_soc = 42;
|
||||
m.data.dyn_soc = 66;
|
||||
m.data.fc_status = 0x04;
|
||||
m.checkCode = u.calculateChecksum((unsigned char*)&m, sizeof(m));
|
||||
|
||||
msg_CcuStateFbMsg out{};
|
||||
EXPECT_TRUE(u.getMsgFromBuff((char*)&m, out));
|
||||
EXPECT_EQ(out.data.ins_soc, 42u);
|
||||
EXPECT_EQ(out.data.dyn_soc, 66u);
|
||||
EXPECT_EQ(out.data.fc_status, 0x04u);
|
||||
|
||||
// 篡改数据 → 校验失败
|
||||
m.data.dyn_soc = 99;
|
||||
EXPECT_FALSE(u.getMsgFromBuff((char*)&m, out));
|
||||
}
|
||||
|
||||
TEST(UdpCommTest, GetMsgFromBuffDis)
|
||||
{
|
||||
udpComm u;
|
||||
msg_disHighVolBusFbMsg m;
|
||||
memset(&m, 0, sizeof(m));
|
||||
m.header.start1 = DIS_MSG_HEAD1;
|
||||
m.header.start2 = DIS_MSG_HEAD2;
|
||||
m.header.id = DIS_HVBUS_FB_ID;
|
||||
m.data.fuelCellCircuitBreaker = 0x55;
|
||||
m.data.powerBusVoltage = 5200;
|
||||
m.checkCode = (cChecksum)(u.calculateChecksum((unsigned char*)&m, sizeof(m), sizeof(cChecksum)) & 0xFF);
|
||||
|
||||
msg_disHighVolBusFbMsg out{};
|
||||
EXPECT_TRUE(u.getMsgFromBuff((char*)&m, out));
|
||||
EXPECT_EQ(out.data.fuelCellCircuitBreaker, 0x55u);
|
||||
EXPECT_EQ(out.data.powerBusVoltage, 5200u);
|
||||
|
||||
// 篡改 → 校验失败
|
||||
m.data.fuelCellCircuitBreaker = 0xAA;
|
||||
EXPECT_FALSE(u.getMsgFromBuff((char*)&m, out));
|
||||
}
|
||||
|
||||
TEST(UdpCommTest, GetDate)
|
||||
{
|
||||
udpComm u;
|
||||
unsigned short year = 0;
|
||||
unsigned char month = 0, day = 0, hour = 0, minute = 0, second = 0, ms = 0;
|
||||
EXPECT_TRUE(u.getDate(year, month, day, hour, minute, second, ms));
|
||||
EXPECT_GE(year, 2000u);
|
||||
EXPECT_LE(year, 2100u);
|
||||
EXPECT_GE(month, 1u); EXPECT_LE(month, 12u);
|
||||
EXPECT_GE(day, 1u); EXPECT_LE(day, 31u);
|
||||
EXPECT_LE(hour, 23u);
|
||||
EXPECT_LE(minute, 59u);
|
||||
EXPECT_LE(second, 59u);
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
//=======================================================================
|
||||
// UpmsgTest: 上位机/外部通信 JSON 消息解析与序列化往返
|
||||
// 仅链接现有 upmsg/*.h + upmsg_definitions.cpp。
|
||||
// 注意:部分 upmsg 头文件未包含 json/loguru/pmSysvariable,需先包含。
|
||||
//=======================================================================
|
||||
#include <gtest/gtest.h>
|
||||
#include "json/json.h"
|
||||
#include "logc/loguru.hpp"
|
||||
#include "pmSysvariable.h"
|
||||
#include "upmsg/uPower_sysState.h"
|
||||
#include "upmsg/uExternComm_setOpMode.h"
|
||||
#include "upmsg/uExternComm_setOpCondition.h"
|
||||
#include "upmsg/uExternComm_setPowerSystem.h"
|
||||
#include "upmsg/uExternComm_setDeviceSwitch.h"
|
||||
#include "upmsg/uPlan_taskStart.h"
|
||||
#include "upmsg/uPlan_planStop.h"
|
||||
#include "upmsg/uDetect_xcVoltage_cmd.h"
|
||||
#include "upmsg/uDetect_zdpVoltage_cmd.h"
|
||||
|
||||
TEST(UpmsgTest, PowerSysStateParse)
|
||||
{
|
||||
uPower_sysStateMsg msg;
|
||||
MSControlCmd cmd;
|
||||
EXPECT_TRUE(msg.parseControlCmdFromJson(cmd, R"({"powerCMD":1,"modCMD":2,"workCMD":5})"));
|
||||
EXPECT_EQ(cmd.powerCMD, 1u);
|
||||
EXPECT_EQ(cmd.modCMD, 2u);
|
||||
EXPECT_EQ(cmd.workCMD, 5u);
|
||||
// 缺字段 → false
|
||||
EXPECT_FALSE(msg.parseControlCmdFromJson(cmd, R"({"powerCMD":1})"));
|
||||
// 非法 JSON → false
|
||||
EXPECT_FALSE(msg.parseControlCmdFromJson(cmd, "{bad json"));
|
||||
}
|
||||
|
||||
TEST(UpmsgTest, SetOpMode)
|
||||
{
|
||||
uExternComm_setOpModeMsg msg;
|
||||
EXPECT_EQ(msg.getSetOpMode("uExternComm_setOpMode_cmd", R"({"state_uint8":1})"), 1);
|
||||
EXPECT_EQ(msg.getSetOpMode("uExternComm_setOpMode_cmd", R"({})"), -1);
|
||||
EXPECT_EQ(msg.getSetOpMode("wrong_key", R"({"state_uint8":1})"), 0); // key 不匹配 → 0
|
||||
}
|
||||
|
||||
TEST(UpmsgTest, SetOpCondition)
|
||||
{
|
||||
uExternComm_setOpConditionMsg msg;
|
||||
EXPECT_EQ(msg.getSetOpCondition("uExternComm_setOpCondition_cmd", R"({"state_uint8":7})"), 7);
|
||||
EXPECT_EQ(msg.getSetOpCondition("uExternComm_setOpCondition_cmd", R"({})"), -1);
|
||||
}
|
||||
|
||||
TEST(UpmsgTest, SetPowerSystem)
|
||||
{
|
||||
uExternComm_setPowerSystemMsg msg;
|
||||
EXPECT_EQ(msg.getSetPMSys("uExternComm_setPowerSystem_cmd", R"({"powerCmd_uint8":4})"), 4);
|
||||
EXPECT_EQ(msg.getSetPMSys("uExternComm_setPowerSystem_cmd", R"({})"), -1);
|
||||
}
|
||||
|
||||
TEST(UpmsgTest, SetDeviceSwitch)
|
||||
{
|
||||
uExternComm_setDeviceSwitchMsg msg;
|
||||
DeviceSwitchCmd c = msg.getSetDevSwitch("uExternComm_setDeviceSwitch_cmd",
|
||||
R"({"id_uint8":53,"cmd_uint8":1})");
|
||||
EXPECT_EQ(c.id, 53);
|
||||
EXPECT_EQ(c.cmd, 1);
|
||||
// 空对象 → id=-1
|
||||
DeviceSwitchCmd c2 = msg.getSetDevSwitch("uExternComm_setDeviceSwitch_cmd", R"({})");
|
||||
EXPECT_EQ(c2.id, -1);
|
||||
}
|
||||
|
||||
TEST(UpmsgTest, TaskStart)
|
||||
{
|
||||
uPlan_taskStartMsg msg;
|
||||
MissionState m = msg.getMission("uPlan_taskStart_st",
|
||||
R"({"taskType_str":"sail","balanceEnabled_bool":true,"bowRudderUnfold_bool":false})");
|
||||
EXPECT_EQ(m.type, (int)TaskType::SAIL);
|
||||
EXPECT_TRUE(m.enableBuoyancyAdjustment);
|
||||
EXPECT_FALSE(m.enableBowRudder);
|
||||
}
|
||||
|
||||
TEST(UpmsgTest, TaskStop)
|
||||
{
|
||||
uPlan_planStopMsg msg;
|
||||
EXPECT_TRUE(msg.getTaskStop("uPlan_planStop_st", R"({"op_int32":1})"));
|
||||
EXPECT_FALSE(msg.getTaskStop("uPlan_planStop_st", R"({"op_int32":0})"));
|
||||
EXPECT_FALSE(msg.getTaskStop("uPlan_planStop_st", R"({})"));
|
||||
}
|
||||
|
||||
TEST(UpmsgTest, XcVoltageRoundTrip)
|
||||
{
|
||||
uDetect_xcVoltage_cmd cmd;
|
||||
cmd.xcLowVoltageAdd_int32 = 1;
|
||||
cmd.xcHighVoltageAdd_int32 = 2;
|
||||
std::string json = cmd.toJsonString();
|
||||
uDetect_xcVoltage_cmd cmd2;
|
||||
EXPECT_TRUE(cmd2.fromJsonString(json));
|
||||
EXPECT_EQ(cmd2.xcLowVoltageAdd_int32, 1);
|
||||
EXPECT_EQ(cmd2.xcHighVoltageAdd_int32, 2);
|
||||
EXPECT_FALSE(cmd2.fromJsonString("{bad json"));
|
||||
}
|
||||
|
||||
TEST(UpmsgTest, ZdpVoltageRoundTrip)
|
||||
{
|
||||
uDetect_zdpVoltage_cmd cmd;
|
||||
cmd.zdpVoltageAdd_int32 = 2;
|
||||
std::string json = cmd.toJsonString();
|
||||
uDetect_zdpVoltage_cmd cmd2;
|
||||
EXPECT_TRUE(cmd2.fromJsonString(json));
|
||||
EXPECT_EQ(cmd2.zdpVoltageAdd_int32, 2);
|
||||
}
|
||||
Reference in New Issue
Block a user