当前位置: 首页 > article >正文

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

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

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

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

  • 通用类型:

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

  • 指针类型:

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

  • Eigen 矩阵类型:

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

2. processTestResult(bool passed) 函数:

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

3. 测试宏:

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

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

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

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

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

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

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

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

     测试 left 是否近似等于 right,使用阈值 thr 进行比较。它使用 Sophus::maxMetric 计算 left 和 right 之间的最大差值,如果差值大于等于 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_APPROX 和 SOPHUS_TEST_NOT_APPROX 宏特别针对浮点数的比较,避免了直接使用 == 运算符可能带来的问题。整个设计简洁有效,易于使用和扩展。

#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)

http://www.kler.cn/a/442921.html

相关文章:

  • js:正则表达式
  • 动态规划【打家劫舍】
  • Windows C++开发环境:VSCode + cmake + ninja + msvc (cl.exe) + msys2/bash shell
  • Java设计模式 —— 【行为型模式】命令模式(Command Pattern) 详解
  • 系统思考—因果关系
  • 2024AAAI SCTNet论文阅读笔记
  • 通过轻易云实现聚水潭数据集成到MySQL的高效方案
  • Moretl安全日志采集工具
  • 【mysql】mysql数据库表字符集utf8与utf8mb4的区别
  • vue自定义指令-图片懒加载
  • 【大模型】使用DPO技术对大模型Qwen2.5进行微调
  • linux下解压文件夹
  • ISP用到的一些名词简介
  • YOLOv9改进,YOLOv9引入LDConv线性可变形卷积,2024,二次创新RepNCSPELAN4结构
  • 04、Python爬虫——批量爬取douyin视频,下载到本地,半个小时内解决批量下载douyin视频
  • WEB开发: Node.js路由之由浅入深(三)自动配置路由 - 全栈工程师入门
  • redis问题解决方法
  • 深度学习常见名词概念:Sota、Benchmark、Baseline、端到端模型、迁移学习等的定义
  • 修改springboot的配置文件
  • ElasticSearch06-分片节点分配
  • 34.在 Vue 3 中使用 OpenLayers 上传 GeoJSON 文件并显示地图数据
  • 【DevOps基础篇】SCM(Source Code Management)
  • 网络安全管理员三级考试整理
  • 大数据治理相关工具:提升数据质量与合规性
  • 密码编码学与网络安全(第五版)答案
  • Redis篇--实际应用篇1--缓存穿透(布隆过滤器)