【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)
相关推荐
爱喝coffee的人19 分钟前
关于SpringBoot中AOP的深入理解
java·开发语言·spring boot·后端·学习·spring
7yewh23 分钟前
LeetCode 力扣 热题 100道(二十)三数之和(C++)
c语言·数据结构·c++·算法·leetcode
新知图书36 分钟前
R语言函数简介
开发语言·python·r语言
君逸~~41 分钟前
环境搭建——CUDA、Python、Pytorch
开发语言·人工智能·pytorch·python·深度学习
吳所畏惧41 分钟前
C#轻松实现Winform监控文件夹变化以及监控文件新增、修改、删除、重命名等操作保姆级详细教程
开发语言·windows·c#·.net·.netcore
Mr_TianSDQ42 分钟前
Vue3 根据窗口的大小动态调整列表的长度
开发语言·前端·javascript
知识分享小能手1 小时前
Java学习教程,从入门到精通,Java ConcurrentHashMap语法知识点及案例代码(63)
java·大数据·开发语言·学习·intellij-idea·后端开发·java开发
编程之路,妙趣横生1 小时前
list使用
c++
xlsw_1 小时前
java全栈day18--Web后端实战(java操作数据库2)
java·开发语言