Files
XYParser/XYParser/XYParserTests/Tests.cpp
2026-06-06 15:04:04 +08:00

480 lines
15 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// XYParser API 单元测试文件
// 测试 XYParser 库的核心功能,包括解析器创建、错误处理、帧解析等
#include <gtest/gtest.h>
#include "../XYParserApi.h"
#include <array>
#include <cstddef>
#include <cstdint>
#include <string>
#include <vector>
// 匿名命名空间,包含测试辅助代码
namespace {
/// ParserGuard 类RAII 封装,确保解析器资源自动释放
/// 当对象生命周期结束时自动调用 XYParser_DestroyParser 释放资源
class ParserGuard {
public:
/// 构造函数,接管解析器句柄的所有权
/// @param handle XYParser 解析器句柄
explicit ParserGuard(XYParserHandle handle) : handle_(handle) {}
/// 析构函数,自动释放解析器资源
~ParserGuard()
{
if (handle_ != nullptr) {
XYParser_DestroyParser(handle_);
}
}
/// 获取解析器句柄
/// @return XYParser 解析器句柄
XYParserHandle get() const
{
return handle_;
}
private:
XYParserHandle handle_; ///< 解析器句柄
};
/// 构建最小帧数据的辅助函数
/// 生成符合 XYParser 协议格式的测试帧数据
/// @param channel_count 通道数量
/// @return 包含完整帧数据的字节向量
std::vector<std::uint8_t> BuildMinimalFrame(std::uint8_t channel_count)
{
constexpr std::size_t kSamplesPerFrame = 5; ///< 每帧采样数
constexpr std::uint8_t kHeader = 0xAA; ///< 帧头标记
constexpr std::uint8_t kTail = 0x55; ///< 帧尾标记
constexpr std::size_t kTagLen = 25; ///< 标签长度
// 计算帧结构大小
const std::size_t sample_bytes = static_cast<std::size_t>(channel_count) * 3 + 2;
const std::uint16_t payload_length = static_cast<std::uint16_t>(sample_bytes * kSamplesPerFrame);
const std::size_t frame_size = 1 + kTagLen + payload_length + 2;
std::vector<std::uint8_t> frame(frame_size, 0);
std::size_t offset = 0;
// 写入帧头
frame[offset++] = kHeader;
// 写入标签数据(版本号等)
frame[offset++] = 0x01;
frame[offset++] = 0x00;
frame[offset++] = 0x00;
frame[offset++] = 0x00;
// 写入负载长度(大端序)
frame[offset++] = static_cast<std::uint8_t>((payload_length >> 8) & 0xFF);
frame[offset++] = static_cast<std::uint8_t>(payload_length & 0xFF);
// 写入电池电量和通道数
frame[offset++] = 95;
frame[offset++] = channel_count;
// 跳过保留字段
offset += 2 + 2 + 2 + 2 + 2 + 6;
// 写入采样数据
for (std::size_t sample = 0; sample < kSamplesPerFrame; ++sample) {
for (std::size_t channel = 0; channel < channel_count; ++channel) {
frame[offset++] = 0x00;
frame[offset++] = 0x00;
frame[offset++] = static_cast<std::uint8_t>(sample + channel + 1);
}
// 每个采样后的额外字节
frame[offset++] = 0x00;
frame[offset++] = 0x00;
}
// 写入帧尾
frame[offset++] = 0x00;
frame[offset++] = kTail;
frame[offset++] = kTail;
return frame;
}
} // namespace
/// 测试:创建解析器时拒绝不支持的通道数
TEST(XYParserApiTests, CreateParserRejectsUnsupportedChannelCount)
{
// 7 通道是不支持的配置,应返回 nullptr
EXPECT_EQ(XYParser_CreateParser(7), nullptr);
}
/// 测试:对空解析器句柄调用 GetLastError 应返回正确错误信息
TEST(XYParserApiTests, GetLastErrorReturnsMessageForNullParser)
{
// 传入 nullptr 应返回 "invalid parser handle"
EXPECT_EQ(std::string(XYParser_GetLastError(nullptr)), std::string("invalid parser handle"));
}
/// 测试Feed 函数能正确解析完整的 8 通道帧
TEST(XYParserApiTests, FeedParsesAComplete8ChannelFrame)
{
// 创建 8 通道解析器
ParserGuard parser(XYParser_CreateParser(8));
ASSERT_NE(parser.get(), nullptr);
// 设置 ADC 参数和校验和绕过标志
XYParser_SetAdcParams(parser.get(), 4.5, 6.0);
XYParser_SetBypassChecksum(parser.get(), 1);
// 构建测试帧并解析
const std::vector<std::uint8_t> bytes = BuildMinimalFrame(8);
std::array<XYParserFrameSummary, 1> summaries{};
const int frame_count = XYParser_Feed(
parser.get(),
bytes.data(),
bytes.size(),
summaries.data(),
static_cast<int>(summaries.size()));
// 验证解析结果
ASSERT_EQ(frame_count, 1); // 应解析出 1 帧
EXPECT_EQ(summaries[0].frame_index, 1U); // 帧索引应为 1
EXPECT_EQ(summaries[0].channel_count, 8U); // 通道数应为 8
EXPECT_EQ(summaries[0].battery, 95U); // 电池电量应为 95
EXPECT_EQ(summaries[0].sample_count, 5U); // 采样数应为 5
EXPECT_GT(summaries[0].channel_values_uv[0][0], 0.0); // 通道值应大于 0
EXPECT_EQ(summaries[0].trigger_types[0], 0U); // 触发类型应为 0
EXPECT_EQ(summaries[0].trigger_indices[0], 0U); // 触发索引应为 0
}
/// 测试Feed 函数能缓冲部分数据直到完整帧可用
TEST(XYParserApiTests, FeedBuffersPartialDataUntilAFullFrameIsAvailable)
{
// 创建 8 通道解析器
ParserGuard parser(XYParser_CreateParser(8));
ASSERT_NE(parser.get(), nullptr);
// 设置校验和绕过标志
XYParser_SetBypassChecksum(parser.get(), 1);
// 构建测试帧并分成两部分
const std::vector<std::uint8_t> bytes = BuildMinimalFrame(8);
const std::size_t split_index = bytes.size() / 2;
std::array<XYParserFrameSummary, 1> summaries{};
// 第一次 Feed传入前半部分数据
const int first_result = XYParser_Feed(
parser.get(),
bytes.data(),
split_index,
summaries.data(),
static_cast<int>(summaries.size()));
EXPECT_EQ(first_result, 0); // 数据不完整,不应解析出帧
// 第二次 Feed传入后半部分数据
const int second_result = XYParser_Feed(
parser.get(),
bytes.data() + split_index,
bytes.size() - split_index,
summaries.data(),
static_cast<int>(summaries.size()));
ASSERT_EQ(second_result, 1); // 数据完整,应解析出 1 帧
EXPECT_EQ(summaries[0].frame_index, 1U); // 帧索引应为 1
}
// ============================================================================
// 解析器创建测试
// ============================================================================
/// 测试:成功创建 8 通道解析器
TEST(XYParserApiTests, CreateParserSucceedsFor8Channels)
{
ParserGuard parser(XYParser_CreateParser(8));
EXPECT_NE(parser.get(), nullptr);
}
/// 测试:成功创建 64 通道解析器
TEST(XYParserApiTests, CreateParserSucceedsFor64Channels)
{
ParserGuard parser(XYParser_CreateParser(64));
EXPECT_NE(parser.get(), nullptr);
}
/// 测试:创建 0 通道解析器应失败
TEST(XYParserApiTests, CreateParserRejectsZeroChannels)
{
EXPECT_EQ(XYParser_CreateParser(0), nullptr);
}
/// 测试:创建不支持的通道数(如 100应失败
TEST(XYParserApiTests, CreateParserRejectsExcessiveChannels)
{
EXPECT_EQ(XYParser_CreateParser(100), nullptr);
}
// ============================================================================
// 参数设置函数测试
// ============================================================================
/// 测试:设置正常的 ADC 参数
TEST(XYParserApiTests, SetAdcParamsAcceptsValidValues)
{
ParserGuard parser(XYParser_CreateParser(8));
ASSERT_NE(parser.get(), nullptr);
// 不应崩溃
EXPECT_NO_THROW(XYParser_SetAdcParams(parser.get(), 4.5, 6.0));
}
/// 测试:设置边界值的 ADC 参数
TEST(XYParserApiTests, SetAdcParamsAcceptsBoundaryValues)
{
ParserGuard parser(XYParser_CreateParser(8));
ASSERT_NE(parser.get(), nullptr);
// 测试零值
EXPECT_NO_THROW(XYParser_SetAdcParams(parser.get(), 0.0, 0.0));
// 测试较大值
EXPECT_NO_THROW(XYParser_SetAdcParams(parser.get(), 100.0, 1000.0));
}
/// 测试:对空句柄调用 SetAdcParams
TEST(XYParserApiTests, SetAdcParamsOnNullHandle)
{
// 不应崩溃
EXPECT_NO_THROW(XYParser_SetAdcParams(nullptr, 4.5, 6.0));
}
/// 测试:关闭校验和绕过
TEST(XYParserApiTests, SetBypassChecksumOff)
{
ParserGuard parser(XYParser_CreateParser(8));
ASSERT_NE(parser.get(), nullptr);
EXPECT_NO_THROW(XYParser_SetBypassChecksum(parser.get(), 0));
}
/// 测试:对空句柄调用 SetBypassChecksum
TEST(XYParserApiTests, SetBypassChecksumOnNullHandle)
{
EXPECT_NO_THROW(XYParser_SetBypassChecksum(nullptr, 1));
}
// ============================================================================
// Feed 函数帧解析测试
// ============================================================================
/// 测试:传入空数据
TEST(XYParserApiTests, FeedParsesEmptyData)
{
ParserGuard parser(XYParser_CreateParser(8));
ASSERT_NE(parser.get(), nullptr);
std::array<XYParserFrameSummary, 10> summaries{};
const int result = XYParser_Feed(
parser.get(),
nullptr,
0,
summaries.data(),
static_cast<int>(summaries.size()));
EXPECT_EQ(result, 0);
}
/// 测试:只传入帧头数据
TEST(XYParserApiTests, FeedParsesOnlyHeader)
{
ParserGuard parser(XYParser_CreateParser(8));
ASSERT_NE(parser.get(), nullptr);
XYParser_SetBypassChecksum(parser.get(), 1);
// 只发送帧头
const std::vector<std::uint8_t> header_only = {0xAA, 0x01, 0x00, 0x00, 0x00};
std::array<XYParserFrameSummary, 10> summaries{};
const int result = XYParser_Feed(
parser.get(),
header_only.data(),
header_only.size(),
summaries.data(),
static_cast<int>(summaries.size()));
EXPECT_EQ(result, 0); // 数据不完整,不应解析出帧
}
/// 测试:解析完整的 64 通道帧
TEST(XYParserApiTests, FeedParses64ChannelFrame)
{
ParserGuard parser(XYParser_CreateParser(64));
ASSERT_NE(parser.get(), nullptr);
XYParser_SetAdcParams(parser.get(), 4.5, 6.0);
XYParser_SetBypassChecksum(parser.get(), 1);
const std::vector<std::uint8_t> bytes = BuildMinimalFrame(64);
std::array<XYParserFrameSummary, 1> summaries{};
const int frame_count = XYParser_Feed(
parser.get(),
bytes.data(),
bytes.size(),
summaries.data(),
static_cast<int>(summaries.size()));
ASSERT_EQ(frame_count, 1);
EXPECT_EQ(summaries[0].channel_count, 64U);
}
/// 测试:连续解析多个帧
TEST(XYParserApiTests, FeedParsesMultipleFrames)
{
ParserGuard parser(XYParser_CreateParser(8));
ASSERT_NE(parser.get(), nullptr);
XYParser_SetBypassChecksum(parser.get(), 1);
// 构建两个连续的帧
const std::vector<std::uint8_t> frame1 = BuildMinimalFrame(8);
const std::vector<std::uint8_t> frame2 = BuildMinimalFrame(8);
std::vector<std::uint8_t> combined(frame1);
combined.insert(combined.end(), frame2.begin(), frame2.end());
std::array<XYParserFrameSummary, 10> summaries{};
const int frame_count = XYParser_Feed(
parser.get(),
combined.data(),
combined.size(),
summaries.data(),
static_cast<int>(summaries.size()));
EXPECT_EQ(frame_count, 2);
EXPECT_EQ(summaries[0].frame_index, 1U);
EXPECT_EQ(summaries[1].frame_index, 2U);
}
/// 测试:帧索引递增
TEST(XYParserApiTests, FeedIncrementsFrameIndex)
{
ParserGuard parser(XYParser_CreateParser(8));
ASSERT_NE(parser.get(), nullptr);
XYParser_SetBypassChecksum(parser.get(), 1);
// 连续发送多个帧
std::array<XYParserFrameSummary, 10> summaries{};
int total_frames = 0;
for (int i = 0; i < 3; ++i) {
const std::vector<std::uint8_t> frame = BuildMinimalFrame(8);
const int count = XYParser_Feed(
parser.get(),
frame.data(),
frame.size(),
summaries.data() + total_frames,
static_cast<int>(summaries.size()) - total_frames);
total_frames += count;
}
EXPECT_EQ(total_frames, 3);
for (int i = 0; i < 3; ++i) {
EXPECT_EQ(summaries[i].frame_index, static_cast<std::uint32_t>(i + 1));
}
}
/// 测试:电池电量字段解析
TEST(XYParserApiTests, FeedParsesBatteryValue)
{
ParserGuard parser(XYParser_CreateParser(8));
ASSERT_NE(parser.get(), nullptr);
XYParser_SetBypassChecksum(parser.get(), 1);
const std::vector<std::uint8_t> bytes = BuildMinimalFrame(8);
std::array<XYParserFrameSummary, 1> summaries{};
XYParser_Feed(
parser.get(),
bytes.data(),
bytes.size(),
summaries.data(),
static_cast<int>(summaries.size()));
EXPECT_EQ(summaries[0].battery, 95U); // BuildMinimalFrame 中设置的电池电量
}
// ============================================================================
// 帧数据边界测试
// ============================================================================
/// 测试:跨多次 Feed 的不完整帧
TEST(XYParserApiTests, FeedHandlesIncompleteFrameAcrossMultipleFeeds)
{
ParserGuard parser(XYParser_CreateParser(8));
ASSERT_NE(parser.get(), nullptr);
XYParser_SetBypassChecksum(parser.get(), 1);
const std::vector<std::uint8_t> bytes = BuildMinimalFrame(8);
std::array<XYParserFrameSummary, 1> summaries{};
// 分成 3 次发送
const std::size_t part1_size = bytes.size() / 3;
const std::size_t part2_size = bytes.size() / 3;
EXPECT_EQ(XYParser_Feed(parser.get(), bytes.data(), part1_size,
summaries.data(), static_cast<int>(summaries.size())), 0);
EXPECT_EQ(XYParser_Feed(parser.get(), bytes.data() + part1_size, part2_size,
summaries.data(), static_cast<int>(summaries.size())), 0);
const int result = XYParser_Feed(
parser.get(),
bytes.data() + part1_size + part2_size,
bytes.size() - part1_size - part2_size,
summaries.data(),
static_cast<int>(summaries.size()));
ASSERT_EQ(result, 1);
EXPECT_EQ(summaries[0].frame_index, 1U);
}
// ============================================================================
// 销毁和错误处理测试
// ============================================================================
/// 测试:销毁空句柄
TEST(XYParserApiTests, DestroyParserAcceptsNullHandle)
{
EXPECT_NO_THROW(XYParser_DestroyParser(nullptr));
}
/// 测试:连续创建和销毁
TEST(XYParserApiTests, CreateAndDestroyMultipleParsers)
{
for (int i = 0; i < 10; ++i) {
ParserGuard parser(XYParser_CreateParser(8));
EXPECT_NE(parser.get(), nullptr);
}
// 析构时自动销毁所有解析器
}
/*
/// 测试GetLastError 在正常操作后
TEST(XYParserApiTests, GetLastErrorAfterSuccessfulCreate)
{
ParserGuard parser(XYParser_CreateParser(8));
ASSERT_NE(parser.get(), nullptr);
// 正常操作后,错误信息应为空或无错误
const char* error = XYParser_GetLastError(parser.get());
// 错误信息可能为空或特定实现
}
/// 测试GetLastError 在空句柄上
TEST(XYParserApiTests, GetLastErrorReturnsMessageForNullParser)
{
EXPECT_EQ(std::string(XYParser_GetLastError(nullptr)), std::string("invalid parser handle"));
}
*/