Catch2 - 用于 test 的轻量级库
此部分的主要内容来自:https://blog.csdn.net/ithiker/article/details/87909651
在 catch 的文档指出,对于C++单元测试框架,目前已经有 Google Test, Boost.Test, CppUnit, Cute, 以及其它的一些,那么 catch 有什么优势呢,文档主要列举了以下这些优势:
- 简单易用:只需要下载 catch.hpp ,包含到你的工程就可以了
- 不依赖外部库:只要你可以编译 C++11 ,有 C++ 的标准库就可以了
- 测试 case 可以分割为 sections :每个 setcion 都是独立的运行单元
- 提供了 BDD 式的测试模式:可以使用 Given-When-Then section 来做 BDD 测试
- 只用一个核心的 assertion 宏来做比较。用标准的 C++ 运算符来做比较,但是可以分解表达式,记录表达式等号左侧和右侧的值
- 可以用任何形式的字符串给测试命名,不用担心名字是否合法
其它一些关键特性有:
- 可以给 test case 打 tag ,因而可以很容易的只跑某个 tag 组的 test cases
- 输出通过 reporter 对象完成,支持基本的文本和 XML 格式输出测试结果,也支持自定义 reporter
- 支持 JUnit xml 输出,这样可以和第三方工具整合,如 CI 服务器等
- 提供默认的 main() 函数,用户也可以使用自己的 main() 函数
- 提供一个命令行解析工具,用户在使用自己的 main() 函数的时候可以添加命令行参数
- catch 软件可以做自测试
- 提供可选的 assertion 宏,可以报告错误但不终止 test case
- 通过内置的 Approx() 语法支持可控制精度的浮点数比较
- 通过 Matchers 支持各种形式的比较,也支持自定义的比较方法
简单易用
Catch 是一个 header-only 的开源库,这意味着你只需要把一个头文件放到系统或者你的工程的某个目录,编译的时候指向它就可以了。
下面用一个 Catch 文档中的小例子说明如何使用 Catch ,假设你写了一个求阶乘的函数:
int Factorial( int number )
{
return number <= 1 ? number : Factorial( number - 1 ) * number;
}
为了简单起见,将被测函数和要测试代码放在一个文件中,你只需要在这个函数之前加入两行:
#define CATCH_CONFIG_MAIN
#include <catch.hpp>
第一行的作用是由 catch 提供一个 main 函数,第二行的作用是包含测试所需要的头文件,假设最后的文件为 catchTest.cpp ,假设相关的文件安装到了 /usr/local/include 下,下面这样编译就可以了:
g++ -std=c++11 -o catchTest catchTest.cpp -I/usr/local/include/
后面的头文件路径可以不要
运行一下,结果为:
===============================================================================
No tests ran
那么如何加入一个 test case 呢,很简单:
TEST_CASE()
{
REQUIRE(Factorial(2) == 2);
}
当然你也可以为你的 TEST_CASE 起名字,或者加标签:
TEST_CASE("Test with number big than 0", "[tag1]")
{
REQUIRE(Factorial(2) == 2);
}
其中 "Test with number big than 0" 是 test case 的名字,全局必须唯一; "tag1" 是标签名,需要放在 []
内部,一个 test case 可以有多个标签,多个 test case 可以使用相同的标签。 REQUIRE 是一个 assert 宏,用来判断是否相等。
命令行选项
以上面的这个简单程序为例,可以通过下面-?来查询命令行选项参数:
./catchTest -?
你会得到选项参数
Catch v2.13.8
usage:
test [<test name|pattern|tags> ... ] options
where options are:
-?, -h, --help display usage information
-l, --list-tests list all/matching test cases
-t, --list-tags list all/matching tags
-s, --success include successful tests in
output
-b, --break break into debugger on failure
-e, --nothrow skip exception tests
-i, --invisibles show invisibles (tabs, newlines)
-o, --out <filename> output filename
-r, --reporter <name> reporter to use (defaults to
console)
-n, --name <name> suite name
-a, --abort abort at first failure
-x, --abortx <no. failures> abort after x failures
-w, --warn <warning name> enable warnings
-d, --durations <yes|no> show test durations
-D, --min-duration <seconds> show test durations for tests
taking at least the given number
of seconds
-f, --input-file <filename> load test names to run from a
file
-#, --filenames-as-tags adds a tag for the filename
-c, --section <section name> specify section to run
-v, --verbosity <quiet|normal|high> set output verbosity
--list-test-names-only list all/matching test cases
names only
--list-reporters list all reporters
--order <decl|lex|rand> test case order (defaults to
decl)
--rng-seed <'time'|number> set a specific seed for random
numbers
--use-colour <yes|no> should output be colourised
--libidentify report name and version according
to libidentify standard
--wait-for-keypress <never|start|exit waits for a keypress before
|both> exiting
--benchmark-samples <samples> number of samples to collect
(default: 100)
--benchmark-resamples <resamples> number of resamples for the
bootstrap (default: 100000)
--benchmark-confidence-interval confidence interval for the
<confidence interval> bootstrap (between 0 and 1,
default: 0.95)
--benchmark-no-analysis perform only measurements; do not
perform any analysis
--benchmark-warmup-time amount of time in milliseconds
<benchmarkWarmupTime> spent on warming up each test
(default: 100)
For more detailed usage please see the project docs
一些比较常见的命令行选项的使用如下:
显示 test case 总体情况:
./catchTest -l
得到结果:
All available test cases:
Anonymous test case 1
1 test case
显示所有的标签(tags):
./catchTest -t
得到结果:
All available tags:
0 tags
运行某个tag下的所有 test cases :
./catchTest [tag1]
运行某个名字的 test case :
./catchTest "Test with number big than 0"
Sections
一般的测试框架都采用基于类的 test fixture , 通常需要定义 setup() 和 teardown() 函数(或者在构造/析构函数中做类似的事情)。 catch 不仅全面支持 test fixture 模式,还提供了一种 section 机制:每个 section 都是独立运行单元,比如下面:
TEST_CASE( "vectors can be sized and resized", "[vector]" )
{
// 共享部分代码
std::vector<int> v( 5 );
REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 5 );
// 依次执行这些 SECTION
SECTION( "resizing bigger changes size and capacity" )
{
v.resize( 10 );
REQUIRE( v.size() == 10 );
REQUIRE( v.capacity() >= 10 );
}
SECTION( "resizing smaller changes size but not capacity" )
{
v.resize( 0 );
REQUIRE( v.size() == 0 );
REQUIRE( v.capacity() >= 5 );
}
SECTION( "reserving bigger changes capacity but not size" )
{
v.reserve( 10 );
REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 10 );
}
SECTION( "reserving smaller does not change size or capacity" )
{
v.reserve( 0 );
REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 5 );
}
}
BDD-style
将 test case 和 section 重命名就可以得到一种 BDD 模式的测试,TDD(测试驱动开发)和 BDD(行为驱动开发)是两种比较流行的开发模式。下面是一个例子:
SCENARIO( "vectors can be sized and resized", "[vector]" )
{
// 给定条件
GIVEN( "A vector with some items" )
{
std::vector<int> v( 5 );
REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 5 );
// 当满足情况
WHEN( "the size is increased" )
{
v.resize( 10 );
// 就得到结果
THEN( "the size and capacity change" )
{
REQUIRE( v.size() == 10 );
REQUIRE( v.capacity() >= 10 );
}
}
WHEN( "the size is reduced" )
{
v.resize( 0 );
THEN( "the size changes but not capacity" )
{
REQUIRE( v.size() == 0 );
REQUIRE( v.capacity() >= 5 );
}
}
WHEN( "more capacity is reserved" )
{
v.reserve( 10 );
THEN( "the capacity changes but not the size" )
{
REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 10 );
}
}
WHEN( "less capacity is reserved" )
{
v.reserve( 0 );
THEN( "neither size nor capacity are changed" )
{
REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 5 );
}
}
}
}
其中的 GIVEN WHEN THEN 都是用于测试结果的解释。
添加参数: success 输出成功结果, reporter 指定输出格式为 compact 简洁的
./test --reporter compact --success
输出结果:
test.cpp:11: passed: v.size() == 5 for: 5 == 5
test.cpp:12: passed: v.capacity() >= 5 for: 5 >= 5
test.cpp:20: passed: v.size() == 10 for: 10 == 10
test.cpp:21: passed: v.capacity() >= 10 for: 10 >= 10
test.cpp:11: passed: v.size() == 5 for: 5 == 5
test.cpp:12: passed: v.capacity() >= 5 for: 5 >= 5
test.cpp:30: passed: v.size() == 0 for: 0 == 0
test.cpp:31: passed: v.capacity() >= 5 for: 5 >= 5
test.cpp:11: passed: v.size() == 5 for: 5 == 5
test.cpp:12: passed: v.capacity() >= 5 for: 5 >= 5
test.cpp:40: passed: v.size() == 5 for: 5 == 5
test.cpp:41: passed: v.capacity() >= 10 for: 10 >= 10
test.cpp:11: passed: v.size() == 5 for: 5 == 5
test.cpp:12: passed: v.capacity() >= 5 for: 5 >= 5
test.cpp:50: passed: v.size() == 5 for: 5 == 5
test.cpp:51: passed: v.capacity() >= 5 for: 5 >= 5
Passed 1 test case with 16 assertions.
如果直接输出成功结果
./test --success
输出结果:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test is a Catch v2.13.8 host application.
Run with -? for options
-------------------------------------------------------------------------------
Scenario: vectors can be sized and resized
Given: A vector with some items
-------------------------------------------------------------------------------
test.cpp:7
...............................................................................
test.cpp:11: PASSED:
REQUIRE( v.size() == 5 )
with expansion:
5 == 5
test.cpp:12: PASSED:
REQUIRE( v.capacity() >= 5 )
with expansion:
5 >= 5
-------------------------------------------------------------------------------
Scenario: vectors can be sized and resized
Given: A vector with some items
When: the size is increased
Then: the size and capacity change
-------------------------------------------------------------------------------
test.cpp:18
...............................................................................
test.cpp:20: PASSED:
REQUIRE( v.size() == 10 )
with expansion:
10 == 10
test.cpp:21: PASSED:
REQUIRE( v.capacity() >= 10 )
with expansion:
10 >= 10
-------------------------------------------------------------------------------
Scenario: vectors can be sized and resized
Given: A vector with some items
-------------------------------------------------------------------------------
test.cpp:7
...............................................................................
test.cpp:11: PASSED:
REQUIRE( v.size() == 5 )
with expansion:
5 == 5
test.cpp:12: PASSED:
REQUIRE( v.capacity() >= 5 )
with expansion:
5 >= 5
-------------------------------------------------------------------------------
Scenario: vectors can be sized and resized
Given: A vector with some items
When: the size is reduced
Then: the size changes but not capacity
-------------------------------------------------------------------------------
test.cpp:28
...............................................................................
test.cpp:30: PASSED:
REQUIRE( v.size() == 0 )
with expansion:
0 == 0
test.cpp:31: PASSED:
REQUIRE( v.capacity() >= 5 )
with expansion:
5 >= 5
-------------------------------------------------------------------------------
Scenario: vectors can be sized and resized
Given: A vector with some items
-------------------------------------------------------------------------------
test.cpp:7
...............................................................................
test.cpp:11: PASSED:
REQUIRE( v.size() == 5 )
with expansion:
5 == 5
test.cpp:12: PASSED:
REQUIRE( v.capacity() >= 5 )
with expansion:
5 >= 5
-------------------------------------------------------------------------------
Scenario: vectors can be sized and resized
Given: A vector with some items
When: more capacity is reserved
Then: the capacity changes but not the size
-------------------------------------------------------------------------------
test.cpp:38
...............................................................................
test.cpp:40: PASSED:
REQUIRE( v.size() == 5 )
with expansion:
5 == 5
test.cpp:41: PASSED:
REQUIRE( v.capacity() >= 10 )
with expansion:
10 >= 10
-------------------------------------------------------------------------------
Scenario: vectors can be sized and resized
Given: A vector with some items
-------------------------------------------------------------------------------
test.cpp:7
...............................................................................
test.cpp:11: PASSED:
REQUIRE( v.size() == 5 )
with expansion:
5 == 5
test.cpp:12: PASSED:
REQUIRE( v.capacity() >= 5 )
with expansion:
5 >= 5
-------------------------------------------------------------------------------
Scenario: vectors can be sized and resized
Given: A vector with some items
When: less capacity is reserved
Then: neither size nor capacity are changed
-------------------------------------------------------------------------------
test.cpp:48
...............................................................................
test.cpp:50: PASSED:
REQUIRE( v.size() == 5 )
with expansion:
5 == 5
test.cpp:51: PASSED:
REQUIRE( v.capacity() >= 5 )
with expansion:
5 >= 5
===============================================================================
All tests passed (16 assertions in 1 test case)
也可以使用下面的两个宏来使用链式的 WHEN 和 THEN
AND_WHEN( something )
AND_THEN( something )
AND_GIVEN( something )
其使用方式与上面相同
Assertion Macros
上面其实已经提到了一些 assertion 宏,像 REQUIRE 等,这里全面的介绍下。常用的有 REQUIRE 系列和 CHECK 系列:
REQUIRE( expression )
CHECK( expression )
REQUIRE 宏在 expression 为 false 时将会终止当前 test case , CHECK 在 expression 为 false 时会给出警告信息但当前 test case 继续往下执行。
对应的还有:
REQUIRE_FALSE( expression )
CHECK_FALSE( expression )
REQUIRE_FALSE 宏在 expression 为 true 时将会终止当前 test case , CHECK_FALSE 在 expression 为 true 时会给出警告信息但当前 test case 继续往下执行。
这里有一点要指出的是,对于:
CHECK(a == 1 && b == 2)
CHECK( a == 2 || b == 1 )
这样的语句,由于宏展开的原因, catch 不能通过编译,需要在表达式的两端加上括号:
CHECK((a == 1 && b == 2))
CHECK((a == 2 || b == 1 ))
我们在最初求阶乘的例子上进行测试,代码如下:
TEST_CASE("Test with number big than 0", "[tag1]")
{
REQUIRE(Factorial(2) == 2);
// REQUIRE((Factorial(3) == 6) && (Factorial(4) == 24)); cannot compile
CHECK(Factorial(0) == 1);
REQUIRE((Factorial(3) == 6 && Factorial(4) == 24));
}
编译运行得到:
~/work/test/catch$ ./test -r compact -s
test.cpp:11: passed: Factorial(2) == 2 for: 2 == 2
test.cpp:13: failed: Factorial(0) == 1 for: 0 == 1
test.cpp:14: passed: (Factorial(3) == 6 && Factorial(4) == 24) for: true
Failed 1 test case, failed 1 assertion.
注意到,这里 Factorial(0) == 1
使用的是 CHECK ,由于 0!= 1
,故该测试失败,但因为我们用的是 CHECK ,故这里只是给出了警告信息,没有终止 test case 。
Floating point comparisons
catch2 支持比较全面的浮点数比较,可能是作者在银行工作,这个测试框架也是针对作者写的银行业务的代码,这些代码对数值比较的要求较多。具体的说 catch2 浮点数比较采用类 Approx , Approx 采用数值初始化,同时支持以下三种属性:
epsilon:相当于误差相对于原值的百分比值,比如 epsilon=0.01 ,则意味着与其比较的值在该 Approx 值的 %1 的范围均视为相等。
默认值为 std::numeric_limits::epsilon()*100
Approx target = Approx(100).epsilon(0.01);
100.0 == target; // Obviously true
200.0 == target; // Obviously still false
100.5 == target; // True, because we set target to allow up to 1% difference
margin: epsilon 是一个相对的百分比值, margin 是一个绝对值,其默认值为 0 。比如:
Approx target = Approx(100).margin(5);
100.0 == target; // Obviously true
200.0 == target; // Obviously still false
104.0 == target; // True, because we set target to allow absolute difference of at most 5
scale:有时比较的两边采用不同的量级,采用 scale 后, Approx 允许的误差为: (Approx::scale + Approx::value) * epsilon
, 其默认值为 0 。比如:
Approx target = Approx(100).scale(100).epsilon(0.01);
100.0 == target; // true
101.5 == target; // true
200.0 == target; // false
100.5 == target; // True, because we set target to allow up to 1% difference, and final target value is 100
Approx target1 = Approx(100).scale(100).margin(5);
100.0 == target1; // true
200.0 == target1; // false
104.0 == target1; // True, because we set target to allow absolute difference of at most 5
查看 Catch2 的源码,可以找到 Approx 的实现如下:
bool Approx::equalityComparisonImpl(const double other) const
{
// First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
// Thanks to Richard Harris for his help refining the scaled margin value
return marginComparison(m_value, other, m_margin)
|| marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value)));
}
// Performs equivalent check of std::fabs(lhs - rhs) <= margin
// But without the subtraction to allow for INFINITY in comparison
bool marginComparison(double lhs, double rhs, double margin)
{
return (lhs + margin >= rhs) && (rhs + margin >= lhs);
}
因此我们不需要显式的设置 epsilon , scale , 或者 margin ,一般情况下使用它们的默认值就可以了:
REQUIRE( 1 == Approx( 2.1 ) );
Catch2 也为用户定义了一个替代字符 _a ,这样使用时不用每次都写 Approx , 只需要在前部包含命名空间就可以了:
using namespace Catch::literals;
REQUIRE( 1 == 2.1_a );
Exceptions
下面两个宏用来测试 expression 中没有异常抛出,满足条件则 assertion 为 true
REQUIRE_NOTHROW( expression )
CHECK_NOTHROW( expression )
下面两个宏用来测试 expression 中有异常抛出,满足条件则 assertion 为 true
REQUIRE_THROWS( expression )
CHECK_THROWS( expression )
下面两个宏用来测试 expression 中有某种类型的异常抛出,满足条件则 assertion 为 true
REQUIRE_THROWS_AS( expression, exception type )
CHECK_THROWS_AS( expression, exception type )
下面两个宏用来测试 expression 中有异常名包含某个 string 的异常或符合某种 string matcher 的异常抛出,满足条件则 assertion 为 true
REQUIRE_THROWS_WITH( expression, string or string matcher )
CHECK_THROWS_WITH( expression, string or string matcher )
例如:
REQUIRE_THROWS_WITH( openThePodBayDoors(), Contains( "afraid" ) && Contains( "can't do that" ) );
REQUIRE_THROWS_WITH( dismantleHal(), "My mind is going" );
下面两个宏用来测试 expression 中有某种类型且符合某种 string matcher 的异常抛出,满足条件则 assertion 为 true
REQUIRE_THROWS_MATCHES( expression, exception type, matcher for given exception type )
CHECK_THROWS_MATCHES( expression, exception type, matcher for given exception type )
Matchers
Matchers 顾名思义就是某个 string 或 int 或其它类型是否和 Matcher 所定义的条件 match 。
String matchers
内置的 string matchers 有 StartsWith, EndsWith, Contains, Equals 和 Matches,前四个是常见的 string 或 substring 的比较。
例如,验证某个 string 是否以某个 string 结束:
using Catch::Matchers::EndsWith; // or Catch::EndsWith
std::string str = getStringFromSomewhere();
REQUIRE_THAT( str, EndsWith( "as a service" ) )
EndsWith 也支持是否大小写采用大小写匹配:
REQUIRE_THAT( str, EndsWith( "as a service", Catch::CaseSensitive::No ) );
也支持多个 Match 串联:
REQUIRE_THAT( str,
EndsWith( "as a service" ) ||
(StartsWith( "Big data" ) && !Contains( "web scale" ) ) );
最后一个 Matches 是 matchECMAScript 类型的正则表达式,例如:
using Catch::Matchers::Matches;
REQUIRE_THAT(std::string("this string contains 'abc' as a substring"),
Matches("this string CONTAINS 'abc' as a substring", Catch::CaseSensitive::No));
Vector matchers
vector 类型的 match 有 Contains , VectorContains 和 Equals 。 VectorContains 判断某个 vector 内部是否有某个元素, Contains 判断某个 vector 是否包含另外一个 vector 。
下面是来自 selftest 的一个例子:
TEST_CASE("Vector matchers", "[matchers][vector]") {
using Catch::Matchers::VectorContains;
using Catch::Matchers::Contains;
using Catch::Matchers::UnorderedEquals;
using Catch::Matchers::Equals;
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
std::vector<int> v2;
v2.push_back(1);
v2.push_back(2);
std::vector<int> empty;
SECTION("Contains (element)")
{
CHECK_THAT(v, VectorContains(1));
CHECK_THAT(v, VectorContains(2));
}
SECTION("Contains (vector)")
{
CHECK_THAT(v, Contains(v2));
v2.push_back(3); // now exactly matches
CHECK_THAT(v, Contains(v2));
CHECK_THAT(v, Contains(empty));
CHECK_THAT(empty, Contains(empty));
}
SECTION("Contains (element), composed")
{
CHECK_THAT(v, VectorContains(1) && VectorContains(2));
}
SECTION("Equals")
{
// Same vector
CHECK_THAT(v, Equals(v));
CHECK_THAT(empty, Equals(empty));
// Different vector with same elements
v2.push_back(3);
CHECK_THAT(v, Equals(v2));
}
SECTION("UnorderedEquals")
{
CHECK_THAT(v, UnorderedEquals(v));
CHECK_THAT(empty, UnorderedEquals(empty));
auto permuted = v;
std::next_permutation(begin(permuted), end(permuted));
REQUIRE_THAT(permuted, UnorderedEquals(v));
std::reverse(begin(permuted), end(permuted));
REQUIRE_THAT(permuted, UnorderedEquals(v));
}
}
Floating point matchers
浮点数类型的 matchers 有两种: WithinULP 和 WithinAbs , WithinAbs 比较两个浮点数是差的绝对值是否小于某个值; WithinULP 做 ULP 类型的检查。
下面是一个例子:
TEST_CASE("Floating point matchers: float", "[matchers][ULP]")
{
using Catch::Matchers::WithinAbs;
using Catch::Matchers::WithinULP;
SECTION("Margin")
{
REQUIRE_THAT(1.f, WithinAbs(1.f, 0));
REQUIRE_THAT(0.f, WithinAbs(1.f, 1));
REQUIRE_THAT(0.f, !WithinAbs(1.f, 0.99f));
REQUIRE_THAT(0.f, !WithinAbs(1.f, 0.99f));
REQUIRE_THAT(0.f, WithinAbs(-0.f, 0));
REQUIRE_THAT(NAN, !WithinAbs(NAN, 0));
REQUIRE_THAT(11.f, !WithinAbs(10.f, 0.5f));
REQUIRE_THAT(10.f, !WithinAbs(11.f, 0.5f));
REQUIRE_THAT(-10.f, WithinAbs(-10.f, 0.5f));
REQUIRE_THAT(-10.f, WithinAbs(-9.6f, 0.5f));
}
SECTION("ULPs")
{
REQUIRE_THAT(1.f, WithinULP(1.f, 0));
REQUIRE_THAT(1.1f, !WithinULP(1.f, 0));
REQUIRE_THAT(1.f, WithinULP(1.f, 0));
REQUIRE_THAT(-0.f, WithinULP(0.f, 0));
REQUIRE_THAT(NAN, !WithinULP(NAN, 123));
}
SECTION("Composed")
{
REQUIRE_THAT(1.f, WithinAbs(1.f, 0.5) || WithinULP(1.f, 1));
REQUIRE_THAT(1.f, WithinAbs(2.f, 0.5) || WithinULP(1.f, 0));
REQUIRE_THAT(NAN, !(WithinAbs(NAN, 100) || WithinULP(NAN, 123)));
}
}
Custom matchers
通过继承 MatchBase , 可以自定义用户的 matcher , Catch::MatcherBase 这里的 T 是用户想要做 match 的数据类型。同时还需要重写 match 和 describe 两个函数。
如下是一个判断某个数是否在某个范围类的自定义 matcher :
// The matcher class
class IntRange : public Catch::MatcherBase<int>
{
int m_begin, m_end;
public:
IntRange( int begin, int end ) : m_begin( begin ), m_end( end ) {}
// Performs the test for this matcher
virtual bool match( int const& i ) const override
{
return i >= m_begin && i <= m_end;
}
// Produces a string describing what this matcher does. It should
// include any provided data (the begin/ end in this case) and
// be written as if it were stating a fact (in the output it will be
// preceded by the value under test).
virtual std::string describe() const
{
std::ostringstream ss;
ss << "is between " << m_begin << " and " << m_end;
return ss.str();
}
};
// The builder function
inline IntRange IsBetween( int begin, int end )
{
return IntRange( begin, end );
}
// ...
// Usage
TEST_CASE("Integers are within a range")
{
CHECK_THAT( 3, IsBetween( 1, 10 ) );
CHECK_THAT( 100, IsBetween( 1, 10 ) );
}