框架 FPP 数组代码生成器单元测试解析:ArrayToStringTest 与 FormatTest 深度指南)
F´F Prime框架 FPP 数组代码生成器单元测试解析ArrayToStringTest 与 FormatTest 深度指南【免费下载链接】fprimeF´ - A flight software and embedded systems framework项目地址: https://gitcode.com/gh_mirrors/fp/fprime导读本文围绕 F´ 飞控与嵌入式系统框架中 FppTest/array 目录展开系统讲解 FPPF Prime Prime语言数组array类型代码生成器的两类单元测试数组toString()/ostream运算符测试ArrayToStringTest与 FPP 格式字符串format string测试FormatTest。读完本文你将掌握 FPP 数组类型的声明语法、默认值、格式字符串说明符{}、{d}、{o}、{x}、{.1e}等的精确行为以及如何通过fprime-util build --ut与fprime-util check一键构建并运行整套代码生成器回归测试。一、目录定位FPP 数组代码生成器的回归测试床FppTest/array 是 F´ 仓库中 FppTest 测试项目的一个子目录。FppTest 项目本身定位为 unit tests for the FPP autocoder即针对 FPP 自动代码生成器autocoder的单元测试套件array 子目录则专门聚焦于FPP 数组array类型代码生成器验证从.fpp声明生成的 C 数组类是否符合预期。该目录包含两组测试目标测试文件被测功能ArrayToStringTest.cpp数组类型的toString()与ostreamoperator运算符FormatTest.cppFPP 格式字符串format string说明符的展开行为从目录结构看list_files 确认测试输入由 5 个 FPP 声明文件提供array.fpp、enum.fpp、string.fpp、struct.fpp、format.fpp它们分别覆盖了数组元素为基本类型、枚举、字符串、结构体、以及带格式字符串的数组main.cpp 作为测试入口实例化整套 gtest 用例。二、环境前提与构建运行方式按 README 与 FppTest/README.md 的要求使用该测试目录需要两个前提已安装 F Prime 框架本仓库即为 F´ 源码本身需先完成框架安装与配置处于 F Prime Python 虚拟环境venv内——因为构建过程需要调用 FPP 自动代码生成器的 Python 工具链。构建与运行只有两条命令# 构建单元测试UT build fprime-util build --ut # 运行单元测试 fprime-util check其中--ut标志指示构建系统仅编译单元测试目标unit-test build。这一点在 CMakeLists.txt 中有明确注释However, only the UT build is allowed here.此处只允许 UT 构建说明该目录只服务于测试不参与飞行软件的常规产物构建。三、测试数据定义FPP 数组声明语法一览数组测试的输入全部由.fpp声明文件驱动代码生成器据此产出*ArrayAc.hpp头文件例如EnumArrayAc.hpp、StringArrayAc.hpp、FormatBoolArrayAc.hpp等见 ArrayToStringTest.cpp 与 FormatTest.cpp 的 include 列表。3.1 基本类型与嵌套数组array.fpparray Uint32 [2] U32; array Uint32Array [3] Uint32;Uint32是长度为 2、元素类型为U32的数组Uint32Array是长度为 3、元素类型为另一个数组Uint32的嵌套数组用于验证数组的元素本身是数组时代码生成器的行为。3.2 枚举元素数组与默认值enum.fppenum E { A, B, C, } array Enum [3] E default [ E.A, E.B, E.C ]这里演示了 FPP 数组的两点核心能力元素类型可以是枚举并且可以通过default关键字为数组指定逐元素默认值列表[ E.A, E.B, E.C ]。默认值会在生成的默认构造函数中被使用见第五节 ArrayTest.hpp 的Default用例。3.3 字符串元素数组string.fpparray String [3] string声明长度为 3、元素为 F´ 字符串类型的数组。字符串元素在代码生成中对应Fw::ExternalString见 main.cpp 中setTestValsString的Fw::ExternalString特化且生成类会额外暴露ELEMENT_BUFFER_SIZE常量用于为每个字符串元素分配缓冲区。3.4 结构体元素数组struct.fppstruct S { mU32: U32 mU32Arr: [3] U32 } array Struct [3] S数组元素可以是结构体而结构体成员本身又可以是数组mU32Arr: [3] U32形成了数组-结构体-数组的复合嵌套用于压力测试代码生成器的递归类型解析。四、toString 与 ostream 运算符测试ArrayToStringTest 深度解析ArrayToStringTest.cpp 的目标是验证数组类型的两类字符串输出接口toString()与ostream运算符operator。4.1 测试框架gtest 类型参数化测试使用 gtest 的type-parameterized testsTYPED_TEST_SUITE/TYPED_TEST一次性覆盖四类数组元素using ArrayTypes ::testing::Types Enum, String, Struct, Uint32Array ; TYPED_TEST_SUITE(ArrayToStringTest, ArrayTypes);Enum枚举元素数组String字符串元素数组Struct结构体元素数组Uint32Array嵌套数组数组元素为数组。SetUp()通过FppTest::Array::setTestValsArrayType(testVals)填充非平凡的测试值——这些特化定义在 main.cpp 中枚举值用STest::Pick::startLength随机挑选字符串与结构体值则调用FppTest::Utils辅助函数生成。4.2 断言策略与手工拼接的流输出逐字符比对核心测试逻辑非常直观将数组对象写入std::stringstream再与手工按元素逐个输出、首尾加括号的参考流比对TYPED_TEST(ArrayToStringTest, ToString) { TypeParam a(this-testVals); std::stringstream buf1, buf2; buf1 a; // 被测ostream 运算符 buf2 [ ; // 参考手工拼接 for (U32 i 0; i TypeParam::SIZE; i) { buf2 this-testVals[i] ; } buf2 ]; ASSERT_STREQ(buf1.str().c_str(), buf2.str().c_str()); }由此可以确认生成数组类的标准文本输出格式[ 元素0 元素1 元素2 ]即以[开头、每个元素后跟一个空格、以]结尾。每个元素自身的文本表示则由元素类型决定枚举输出常量名、字符串输出其字符内容、结构体输出其成员序列等并逐层递归到toString()实现。该用例同时覆盖了toString()与operator因为二者在生成代码中共享同一套元素序列化逻辑。五、FPP 格式字符串测试FormatTest 深度解析FormatTest.cpp 是 array 目录中信息量最大的测试文件验证 FPP 数组声明中format关键字的全部说明符行为。其输入定义在 format.fpp共 14 个带格式字符串的数组声明。5.1 FPP 格式字符串语法array FormatBool [3] bool format a {} b array FormatU8 [3] U8 format a {} b array FormatU16Dec [3] U16 format a {d} b array FormatU32Oct [3] U32 format a {o} b array FormatU64Hex [3] U64 format a {x} b array FormatF32e [3] F32 format a {.1e} b array FormatF32f [3] F32 format a {.2f} b array FormatF64g [3] F64 format a {.3g} b array FormatString [3] string format % {} array FormatChar [3] U8 format a {c} b格式字符串由普通文本与花括号占位符{...}组成占位符控制元素如何被格式化后嵌入字符串。结合 FormatTest.cpp 中每个用例的参考实现使用std::dec、std::oct、std::hex、std::scientific、std::fixed、std::setprecision等流操纵符可以归纳出完整的说明符语义表说明符语义参考实现测试代码示例数组声明{}默认格式直接输出元素FormatBool、FormatU8、FormatI8{d}十进制decimalstd::decFormatU16Dec、FormatI16Dec{o}八进制octalstd::octFormatU32Oct、FormatI32Oct{x}十六进制hexstd::hexFormatU64Hex、FormatI64Hex{c}字符char按U8直接输出FormatChar{.1e}科学计数法1 位精度std::setprecision(1) std::scientificFormatF32e{.2f}定点2 位小数std::setprecision(2) std::fixedFormatF32f{.3g}通用格式3 位有效数字std::setprecision(3)FormatF64g% {}字符串前置%前缀输出% str FormatString5.2 测试用例与断言方式FormatTest是一个普通 gtest fixtureTEST_F每个说明符对应一个独立用例被测与参考输出分别写入buf1、buf2两个stringstream最后ASSERT_STREQ逐字符比对TEST_F(FormatTest, U32Oct) { U32 testVals[FormatU32Oct::SIZE] {0, 100, std::numeric_limitsU32::max()}; FormatU32Oct a(testVals); buf1 a; for (U32 i 0; i FormatU32Oct::SIZE; i) { buf2 a std::oct testVals[i] b ; } buf2 ]; ASSERT_STREQ(buf1.str().c_str(), buf2.str().c_str()); }值得注意的测试设计细节边界值覆盖无符号类型使用{0, 100, std::numeric_limitsU8/U16/U32/U64::max()}最小值、中间值、最大值有符号类型使用{min, 0, max}浮点类型使用{min, 0.0, max}。这保证了格式代码在数值边界上行为正确。小整数提升U8/I8用例中参考代码将元素强制转换为U16/I16再输出(U16) testVals[i]避免char被当作字符打印验证了生成代码在整数提升上的正确处理。字符串用例FormatString用例通过Fw::ExternalString::setBuffer为每个元素分配缓冲区并填充测试字符串验证% {}前缀与字符串元素输出的组合。5.3 格式字符串的实战价值format是 FPP 数组类型面向日志、遥测、人机交互的核心特性开发者可以在类型声明层面统一约定数组元素如何显示十进制、八进制、十六进制、科学计数、定点小数等生成代码自动在toString()/operator中应用避免在每个组件中手工格式化。FormatTest 正是这批格式约定的行为契约。六、背后的完整测试矩阵typed_tests/ArrayTest.hpp 与 main.cppArrayToStringTest.cpp 与 FormatTest.cpp 只是该目录的两个专属测试文件通过 main.cpp 还实例化了一套通用的、模板化的数组行为测试套件 ArrayTest.hpp对Enum、String、Struct、Uint32Array四类数组做全面回归用例REGISTER_TYPED_TEST_SUITE_P验证内容DefaultSIZE常量等于 3默认构造后各元素等于默认值含default [...]声明的默认值Constructors数组构造从元素数组、单元素构造填充全部元素、多元素构造逐个传入、拷贝构造SubscriptOpoperator[]的读写能力AssignmentOp数组整体赋值、拷贝赋值、自赋值、单元素赋值EqualityOp与!运算符Serialization通过Fw::SerialBuffer序列化/反序列化往返一致缓冲区过小serializedSize-1时序列化失败其中序列化用例还验证了SERIALIZED_SIZE常量与元素类型感知的序列化大小计算对于字符串数组main.cpp 特化了getSerializedSize::String逐元素累加a[i].serializedSize()而非简单使用固定值——这是字符串数组与定长类型数组在序列化语义上的关键区别。测试入口 main.cpp 还做了两类关键特化默认值/测试值特化为Enum指定setDefaultValsE.A, E.B, E.C与随机化的setTestVals为String管理静态缓冲区并调用FppTest::Utils::setString为Struct/Uint32Array生成非零随机值。多元素构造特化getMultiElementConstructedArray演示了Enum(a[0], a[1], a[2])形式的多元素构造函数语法。主函数通过STest::Random::seed()初始化随机源保证每次运行测试值的多样性。七、构建集成CMakeLists.txt 的 UT 布局CMakeLists.txt 展示了 F´ 模块化构建体系register_fprime_module/register_fprime_ut在纯测试目录中的用法set(SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/array.fpp ${CMAKE_CURRENT_LIST_DIR}/enum.fpp ${CMAKE_CURRENT_LIST_DIR}/string.fpp ${CMAKE_CURRENT_LIST_DIR}/struct.fpp ${CMAKE_CURRENT_LIST_DIR}/format.fpp ) register_fprime_module() set(UT_MOD_DEPS Fw/Test STest) set(UT_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/ArrayToStringTest.cpp ${CMAKE_CURRENT_LIST_DIR}/FormatTest.cpp ${CMAKE_CURRENT_LIST_DIR}/../utils/Utils.cpp ${CMAKE_CURRENT_LIST_DIR}/main.cpp ) register_fprime_ut()关键点.fpp源文件通过register_fprime_module()注册触发 FPP 自动代码生成器在构建期生成*ArrayAc.hpp单元测试依赖Fw/Test提供Fw::ExternalString、Fw::SerialBuffer等基础设施与STest提供随机数/选择工具测试源码经register_fprime_ut()注册为 UT 目标且该目录只允许 UT 构建注释only the UT build is allowed here测试还复用了上层FppTest/utils/Utils.cpp的辅助函数体现跨目录共享测试设施的组织方式。八、总结与延伸阅读FppTest/array是 F´ 仓库中验证FPP 数组代码生成器正确性的最小但完整的回归测试样例它用 5 个声明文件覆盖了数组元素的全部主要类型基本类型、枚举、字符串、结构体、嵌套数组用两个专属测试文件锁定了toString()/ostream输出格式与 14 种格式字符串说明符的行为再通过模板化的 ArrayTest.hpp 与 main.cpp 特化补全构造函数、赋值、比较、序列化的全量契约。对开发者而言它同时是一份可直接运行的测试模板和一份FPP 数组 格式字符串的权威行为规范参考。若需继续深入可参考FppTest/array/format.fpp —— 格式字符串的完整声明样例FppTest/array/ArrayToStringTest.cpp 与 FormatTest.cpp —— 行为契约的断言实现FppTest/typed_tests/ArrayTest.hpp —— 可复用的数组类型模板测试套件FppTest/README.md —— FppTest 整体构建与运行说明。【免费下载链接】fprimeF´ - A flight software and embedded systems framework项目地址: https://gitcode.com/gh_mirrors/fp/fprime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考