【C++】sophus : test_macros.hpp 用于单元测试的宏和辅助函数 (四)

这段代码定义了一组用于单元测试的宏和辅助函数,主要目的是方便地进行各种类型的断言,并提供清晰的错误信息输出。

1. details::pretty(T) 函数:

这是一个模板函数,用于将各种类型的值转换为易于阅读的字符串表示形式。它使用模板特化来处理不同类型:

  • 通用类型:

    使用 std::stringstream 将值转换为字符串。

  • 指针类型:

    将指针转换为其整数地址的字符串表示。

  • Eigen 矩阵类型:

    以格式化的方式输出矩阵,包括换行符,使其更易于阅读。

2. processTestResult(bool passed) 函数:

此函数根据测试结果输出信息。如果测试失败(passedfalse),则在 std::cerr 上输出 "failed!" 并调用 exit(-1) 终止程序。如果测试通过,则输出 "passed."。LCOV_EXCL_STARTLCOV_EXCL_STOP 注释用于代码覆盖率工具,表示这部分代码(错误处理)可以从覆盖率分析中排除。

3. 测试宏:

这些宏定义了各种类型的断言,用于在测试中检查条件是否满足。如果断言失败,则会输出详细的错误信息,包括失败的条件、左右两边的值(如果适用)以及可选的描述信息。所有宏都使用 do { ... } while (false) 结构,以确保在任何上下文中都能正确使用,即使在单行语句中也是如此。

  • SOPHUS_TEST(passed, condition, descr, ...):

    测试一个条件是否为真。如果条件为假,则将 passed 设置为 false,并输出错误信息,包含条件表达式的字符串表示。

  • SOPHUS_TEST_EQUAL(passed, left, right, descr, ...):

    测试 left 是否等于 right。如果两者不相等,则将 passed 设置为 false,并输出详细的错误信息,包括 leftright 的值及其字符串表示。

  • SOPHUS_TEST_NEQ(passed, left, right, descr, ...):

    测试 left 是否不等于 right。如果两者相等,则将 passed 设置为 false,并输出错误信息。

  • SOPHUS_TEST_APPROX(passed, left, right, thr, descr, ...):

    测试 left 是否近似等于 right,使用阈值 thr 进行比较。它使用 Sophus::maxMetric 计算 leftright 之间的最大差值,如果差值大于等于 thr,则断言失败。错误信息包含 leftrightthr 和计算出的差值。

  • SOPHUS_TEST_NOT_APPROX(passed, left, right, thr, descr, ...):

    测试 left 是否不近似等于 right,使用阈值 thr 进行比较。如果差值小于 thr,则断言失败。错误信息类似 SOPHUS_TEST_APPROX

4. 其他宏:

  • SOPHUS_STRINGIFY(x):

    将宏参数 x 转换为字符串字面量。

总结:

这段代码提供了一个简单的单元测试框架,通过宏定义简化了各种断言的编写,并利用 details::pretty 函数提供了清晰的错误信息输出,方便开发者快速定位测试失败的原因。其中,SOPHUS_TEST_APPROXSOPHUS_TEST_NOT_APPROX 宏特别针对浮点数的比较,避免了直接使用 == 运算符可能带来的问题。整个设计简洁有效,易于使用和扩展。

xml 复制代码
#pragma once // 防止头文件重复包含
#include <iostream> // 引入输入输出流库#include <sstream> // 引入字符串流库
#include <sophus/types.hpp> // 引入Sophus库中的类型定义
namespace Sophus {namespace details { // 定义details命名空间
template <class Scalar, class Enable = void> // 定义模板类Pretty,模板参数为Scalar和Enableclass Pretty { public: // 公有成员  static std::string impl(Scalar s) { // 定义静态成员函数impl,用于将标量转换为字符串    std::stringstream sstr; // 定义字符串流    sstr << s; // 将标量写入字符串流    return sstr.str(); // 返回字符串  }};
template <class Ptr> // 定义模板类Pretty的特化版本,模板参数为Ptrclass Pretty<Ptr, std::enable_if_t<std::is_pointer<Ptr>::value>> { // 如果Ptr是指针类型,则启用该模板 public: // 公有成员  static std::string impl(Ptr ptr) { // 定义静态成员函数impl,用于将指针转换为字符串    std::stringstream sstr; // 定义字符串流    sstr << std::intptr_t(ptr); // 将指针的整数值写入字符串流    return sstr.str(); // 返回字符串  }};
template <class Scalar, int M, int N> // 定义模板类Pretty的特化版本,模板参数为Scalar, M和Nclass Pretty<Eigen::Matrix<Scalar, M, N>, void> { // 如果类型是Eigen矩阵,则启用该模板 public: // 公有成员  static std::string impl(Matrix<Scalar, M, N> const& v) { // 定义静态成员函数impl,用于将矩阵转换为字符串    std::stringstream sstr; // 定义字符串流    sstr << "\n" << v << "\n"; // 将矩阵写入字符串流    return sstr.str(); // 返回字符串  }};
template <class T> // 定义模板函数pretty,模板参数为Tstd::string pretty(T const& v) { // 将任意类型转换为字符串  return Pretty<T>::impl(v); // 调用Pretty类的impl函数}
}  // namespace details
void processTestResult(bool passed) { // 定义函数processTestResult,用于处理测试结果  if (!passed) { // 如果测试未通过    // LCOV_EXCL_START    std::cerr << "failed!" << std::endl << std::endl; // 输出失败信息    exit(-1); // 退出程序    // LCOV_EXCL_STOP  }  std::cerr << "passed." << std::endl << std::endl; // 输出通过信息}}  // namespace Sophus
#define SOPHUS_STRINGIFY(x) #x // 定义宏SOPHUS_STRINGIFY,将宏参数转换为字符串
/// 测试条件是否为真。/// 如果测试失败,in-out参数passed将被设置为false。#define SOPHUS_TEST(passed, condition, descr, ...)                       \  do {                                                                   \    if (!(condition)) {                                                  \      SOPHUS_DETAILS_FMT_LOG("Test failed: condition ``{}`` is false\n", \                             SOPHUS_STRINGIFY(condition));               \      passed = false;                                                    \    }                                                                    \  } while (false)
/// 测试left是否等于right。/// 如果测试失败,in-out参数passed将被设置为false。#define SOPHUS_TEST_EQUAL(passed, left, right, descr, ...)               \  do {                                                                   \    if (left != right) {                                                 \      std::string msg = SOPHUS_DETAILS_FMT_STR(                          \          "Test failed: {} (={}) is not equal to {} (={})\n",            \          SOPHUS_STRINGIFY(left), Sophus::details::pretty(left),         \          SOPHUS_STRINGIFY(right), Sophus::details::pretty(right));      \      msg += SOPHUS_DETAILS_FMT_STR(descr, ##__VA_ARGS__);               \      SOPHUS_DETAILS_FMT_LOG(                                            \          "{} (={}) is not equal to {} (={})\n", SOPHUS_STRINGIFY(left), \          Sophus::details::pretty(left), SOPHUS_STRINGIFY(right),        \          Sophus::details::pretty(right));                               \      passed = false;                                                    \    }                                                                    \  } while (false)
/// 测试left是否不等于right。/// 如果测试失败,in-out参数passed将被设置为false。#define SOPHUS_TEST_NEQ(passed, left, right, descr, ...)             \  do {                                                               \    if (!(left != right)) {                                          \      SOPHUS_DETAILS_FMT_LOG(                                        \          "Test failed: {} (={}) should not be equal to {} (={})\n", \          SOPHUS_STRINGIFY(left), Sophus::details::pretty(left),     \          SOPHUS_STRINGIFY(right), Sophus::details::pretty(right));  \      passed = false;                                                \    }                                                                \  } while (false)
/// 测试left是否近似等于right,误差在阈值范围内。/// 如果测试失败,in-out参数passed将被设置为false。#define SOPHUS_TEST_APPROX(passed, left, right, thr, descr, ...)            \  do {                                                                      \    auto nrm = Sophus::maxMetric((left), (right));                          \    if (!(nrm < (thr))) {                                                   \      SOPHUS_DETAILS_FMT_LOG(                                               \          "Test failed: {} (={}) is not approx {} (={}); {} is {}; nrm is " \          "{}\n",                                                           \          SOPHUS_STRINGIFY(left), Sophus::details::pretty(left),            \          SOPHUS_STRINGIFY(right), Sophus::details::pretty(right),          \          SOPHUS_STRINGIFY(thr), Sophus::details::pretty(thr),              \          Sophus::details::pretty(nrm));                                    \      passed = false;                                                       \    }                                                                       \  } while (false)
/// 测试left是否不近似等于right。/// 如果测试失败,in-out参数passed将被设置为false。#define SOPHUS_TEST_NOT_APPROX(passed, left, right, thr, descr, ...) \  do {                                                               \    auto nrm = Sophus::maxMetric((left), (right));                   \    if (nrm < (thr)) {                                               \      SOPHUS_DETAILS_FMT_LOG(                                        \          "Test failed: {} (={}) is approx {} (={}), but it should not!\n\          nrm is {}\n",                                              \          SOPHUS_STRINGIFY(left), Sophus::details::pretty(left),     \          SOPHUS_STRINGIFY(right), Sophus::details::pretty(right),   \          Sophus::details::pretty(nrm));                             \      passed = false;                                                \    }                                                                \  } while (false)
相关推荐
酷爱码2 小时前
如何通过python连接hive,并对里面的表进行增删改查操作
开发语言·hive·python
画个大饼2 小时前
Go语言实战:快速搭建完整的用户认证系统
开发语言·后端·golang
喵先生!3 小时前
C++中的vector和list的区别与适用场景
开发语言·c++
Thomas_YXQ3 小时前
Unity3D Lua集成技术指南
java·开发语言·驱动开发·junit·全文检索·lua·unity3d
xMathematics4 小时前
计算机图形学实践:结合Qt和OpenGL实现绘制彩色三角形
开发语言·c++·qt·计算机图形学·cmake·opengl
yuanManGan6 小时前
C++入门小馆: 深入了解STLlist
开发语言·c++
北极的企鹅886 小时前
XML内容解析成实体类
xml·java·开发语言
梁下轻语的秋缘6 小时前
每日c/c++题 备战蓝桥杯(P1049 [NOIP 2001 普及组] 装箱问题)
c语言·c++·学习·蓝桥杯
BillKu6 小时前
Vue3后代组件多祖先通讯设计方案
开发语言·javascript·ecmascript
Python自动化办公社区6 小时前
Python 3.14:探索新版本的魅力与革新
开发语言·python