...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
Several generators for datasets are implemented in Unit Test Framework:
forward iterable
containers and C
array like datasets
stl
and C-array
generators are merely a dataset
view on existing collection, while ranges and random number sequences
are describing new datasets.
A singleton is a dataset containing a unique value. The size and arity of such a dataset is 1. This value can be
As mentioned in zip, when zipped with a distribution of infinite size, the resulting dataset will have a size of 1.
The singleton is constructible through the function boost::unit_test::data::make
.
Code |
---|
#define BOOST_TEST_MODULE dataset_example65 #include <boost/test/included/unit_test.hpp> #include <boost/test/data/test_case.hpp> #include <boost/test/data/monomorphic.hpp> namespace bdata = boost::unit_test::data; BOOST_DATA_TEST_CASE( test1, bdata::make(2), singleton) { std::cout << "test 1: " << singleton << std::endl; BOOST_TEST(singleton == 2); } BOOST_DATA_TEST_CASE( test2, bdata::xrange(3) ^ bdata::make(2), xr, singleton) { std::cout << "test 2: " << xr << ", " << singleton << std::endl; BOOST_TEST(singleton == 2); } |
Output |
---|
> dataset_example65 Running 4 test cases... test 1: 2 test 2: 0, 2 test 2: 1, 2 test 2: 2, 2 *** No errors detected |
This type of datasets does not contains the logic for generating the
sequence of values, and is used as a wrapper on an existing sequence
contained in a C
array.
The arity is 1 and the size is the size of the array.
Such datasets are simply constructed from an overload of the make
function.
Code |
---|
#define BOOST_TEST_MODULE dataset_example66 #include <boost/test/included/unit_test.hpp> #include <boost/test/data/test_case.hpp> #include <boost/test/data/monomorphic.hpp> namespace bdata = boost::unit_test::data; const char* arr[] = {"cat", "dog"}; BOOST_DATA_TEST_CASE( test1, bdata::xrange(2) ^ bdata::make(arr), xr, array_element) { std::cout << "test 1: " << xr << ", " << array_element << std::endl; BOOST_TEST(array_element != "mammoth"); } |
Output |
---|
> dataset_example66 Running 2 test cases... test 1: 0, cat test 1: 1, dog *** No errors detected |
As for C
arrays, this
type of datasets does not contain the logic for generating sequence of
values, and are used for parsing an existing sequence. The arity is 1
and the size is the same as the one of the container.
Tip | |
---|---|
C++11 implementation enables the dataset generation from any container which iterator implements the forward iterator concept. For C++03, the feature is enabled on most STL containers. |
std::vector
and std::map
Code |
---|
#define BOOST_TEST_MODULE example67 #include <boost/test/included/unit_test.hpp> #include <boost/test/data/test_case.hpp> #include <boost/test/data/monomorphic.hpp> #include <sstream> namespace bdata = boost::unit_test::data; // Generates a Fibonacci sequence std::vector<float> fibonacci() { std::vector<float> ret(8); ret[0] = 0; ret[1] = 1; for(std::size_t s(2); s < ret.size(); s++) { ret[s] = ret[s-1] + ret[s-2]; } return ret; } BOOST_DATA_TEST_CASE( test1, bdata::make(fibonacci()), array_element) { std::cout << "test 1: " << array_element << std::endl; BOOST_TEST(array_element <= 13); } // Generates a map from a vector std::map<std::string, float> vect_2_str(std::vector<float> v) { std::map<std::string, float> out; for(std::size_t s(0); s < v.size(); s++) { std::ostringstream o; o << v[s]; out[o.str()] = v[s]; } return out; } typedef std::pair<const std::string, float> pair_map_t; BOOST_TEST_DONT_PRINT_LOG_VALUE( pair_map_t ) BOOST_DATA_TEST_CASE( test2, bdata::make(vect_2_str(fibonacci())), array_element) { std::cout << "test 2: \"" << array_element.first << "\", " << array_element.second << std::endl; BOOST_TEST(array_element.second <= 13); } |
Output |
---|
> dataset_example67 Running 15 test cases... test 1: 0 test 1: 1 test 1: 1 test 1: 2 test 1: 3 test 1: 5 test 1: 8 test 1: 13 test 2: "0", 0 test 2: "1", 1 test 2: "13", 13 test 2: "2", 2 test 2: "3", 3 test 2: "5", 5 test 2: "8", 8 *** No errors detected |
A range is a dataset that implements a sequence of equally spaced values, defined by a start, and end and a step.
It is possible to construct a range using the factory boost::unit_test::data::xrange
,
available in the overloads below:
#include <boost/test/data/test_case.hpp> #include <boost/test/data/monomorphic.hpp> auto range1 = data::xrange( (data::step = 0.5, data::end = 3 ) ); // Constructs with named values, starting at 0 auto range2 = data::xrange( begin, end ); // begin < end required auto range5 = data::xrange( begin, end, step ); // begin < end required auto range3 = data::xrange( end ); // begin=0, end cannot be <= 0, see above auto range4 = data::xrange( end, (data::begin=1) ); // named value after end
Tip | |
---|---|
The named value parameters should be declared inside parenthesis |
The details of the named value parameters is given in the table below.
Table 1. Range parameters
Name |
Default |
Description |
---|---|---|
|
0 |
Beginning of the generated sequence. The |
|
+ infinity |
End of the generated sequence. The |
|
1 |
Number indicating the step between two consecutive samples
of the generated range. The default type is the same as the
input type. This value should not be 0. It should be of the
same sign as |
Code |
---|
#define BOOST_TEST_MODULE dataset_example59 #include <boost/test/included/unit_test.hpp> #include <boost/test/data/test_case.hpp> #include <boost/test/data/monomorphic.hpp> namespace bdata = boost::unit_test::data; BOOST_DATA_TEST_CASE( test1, bdata::xrange(5) ) { std::cout << "test 1: " << sample << std::endl; BOOST_TEST((sample <= 4 && sample >= 0)); } BOOST_DATA_TEST_CASE( test2, bdata::xrange<int>( (bdata::begin=1, bdata::end=10, bdata::step=3)) ) { std::cout << "test 2: " << sample << std::endl; BOOST_TEST((sample <= 4 && sample >= 0)); } |
Output |
---|
> dataset_example61 Running 8 test cases... test 1: 0 test 1: 1 test 1: 2 test 1: 3 test 1: 4 test 2: 1 test 2: 4 test 2: 7 test.cpp(27): error: in "test2": check (sample <= 4 && sample >= 0) has failed Failure occurred in a following context: sample = 7; *** 1 failure is detected in the test module "dataset_example59" |
This type of dataset generates a sequence of random numbers following a given distribution. The seed and the engine may also be specified.
Caution | |
---|---|
The random value generator is available only for C++11 capable compilers.
If this feature is not supported for your compiler, the macro |
It is possible to construct a random sequence using the factory boost::unit_test::data::random
,
available in the overloads below:
auto rdgen = random(); // uniform distribution (real) on [0, 1) auto rdgen = random(1, 17); // uniform distribution (integer) on [1, 17] // Default random generator engine, Gaussian distribution (mean=5, sigma=2) and seed set to 100. auto rdgen = random( (data::seed = 100UL, data::distribution = std::normal_distribution<>(5.,2)) );
Since the generated datasets will have infinite size, the sequence size should be narrowed by combining the dataset with another one through e.g. a zip operation.
Tip | |
---|---|
In order to be able to reproduce a failure within a randomized parameter test case, the seed that generated the failure may be set in order to generate the same sequence of random values. |
The details of the named value parameters is given in the table below.
Table 2. Range parameters
Parameter name |
Default |
Description |
---|---|---|
|
(not set) |
Seed for the generation of the random sequence. |
|
Uniform |
Distribution instance for generating the random number sequences.
The |
|
|
Random number generator engine. |
Code |
---|
#define BOOST_TEST_MODULE dataset_example63 #include <boost/test/included/unit_test.hpp> #include <boost/test/data/test_case.hpp> #include <boost/test/data/monomorphic.hpp> namespace bdata = boost::unit_test::data; BOOST_DATA_TEST_CASE( test1, bdata::random(1, 17) ^ bdata::xrange(7), random_sample, index ) { std::cout << "test 1: " << random_sample << ", " << index << std::endl; BOOST_TEST((random_sample <= 17 && random_sample >= 1)); } BOOST_DATA_TEST_CASE( test2, bdata::random( (bdata::distribution=std::uniform_real_distribution<float>(1, 2)) ) ^ bdata::xrange(7), random_sample, index ) { std::cout << "test 2: " << random_sample << ", " << index << std::endl; BOOST_TEST(random_sample < 1.7); // 30% chance of failure } |
Output |
---|
> dataset_example63 Running 14 test cases... test 1: 1, 0 test 1: 14, 1 test 1: 13, 2 test 1: 15, 3 test 1: 13, 4 test 1: 17, 5 test 1: 11, 6 test 2: 1.81472, 0 test.cpp(35): error: in "test2": check random_sample < 1.7 has failed Failure occurred in a following context: random_sample = 1.81472373; index = 0; test 2: 1.13548, 1 test 2: 1.90579, 2 test.cpp(35): error: in "test2": check random_sample < 1.7 has failed Failure occurred in a following context: random_sample = 1.905792; index = 2; test 2: 1.83501, 3 test.cpp(35): error: in "test2": check random_sample < 1.7 has failed Failure occurred in a following context: random_sample = 1.83500862; index = 3; test 2: 1.12699, 4 test 2: 1.96887, 5 test.cpp(35): error: in "test2": check random_sample < 1.7 has failed Failure occurred in a following context: random_sample = 1.96886778; index = 5; test 2: 1.91338, 6 test.cpp(35): error: in "test2": check random_sample < 1.7 has failed Failure occurred in a following context: random_sample = 1.91337585; index = 6; *** 5 failures are detected in the test module "dataset_example63" |