Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext
Datasets generators

Several generators for datasets are implemented in Unit Test Framework:

stl and C-array generators are merely a dataset view on existing collection, while ranges and random number sequences are describing new datasets.

Singletons

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.

Example: Singleton

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
Datasets from C arrays

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.

Example: Array

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
Datasets from forward iterable containers

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] 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.

Example: Dataset from 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
Ranges

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] Tip

The named value parameters should be declared inside parenthesis

Parameters

The details of the named value parameters is given in the table below.

Table 1. Range parameters

Name

Default

Description

begin

0

Beginning of the generated sequence. The begin value is included in set of values returned by the generator.

end

+ infinity

End of the generated sequence. The end value is not included in set of values returned by the generator. If omitted, the generator has infinite size.

step

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 end-begin.


Example: Declaring a test with a range

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_example59
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/_2": 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"
Random value dataset

This type of dataset generates a sequence of random numbers following a given distribution. The seed and the engine may also be specified.

[Caution] Caution

The random value generator is available only for C++11 capable compilers. If this feature is not supported for your compiler, the macro BOOST_TEST_NO_RANDOM_DATASET_AVAILABLE will be automatically set by the Unit Test Framework

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] 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.

Parameters

The details of the named value parameters is given in the table below.

Table 2. Range parameters

Parameter name

Default

Description

seed

(not set)

Seed for the generation of the random sequence.

distribution

Uniform

Distribution instance for generating the random number sequences. The end value is not included in set of values returned by the generator for real values, and is included for integers.

engine

std::default_random_engine

Random number generator engine.


Example: Declaring a test with a random sequence

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: 2, 0
test 1: 3, 1
test 1: 2, 2
test 1: 8, 3
test 1: 10, 4
test 1: 15, 5
test 1: 8, 6
test 2: 1.00001, 0
test 2: 1.13154, 1
test 2: 1.75561, 2
test.cpp(35): error: in "test2/_2": check random_sample < 1.7 has failed [1.75560534 >= 1.7]
Failure occurred in a following context:
    random_sample = 1.75560534; index = 2;
test 2: 1.45865, 3
test 2: 1.53277, 4
test 2: 1.21896, 5
test 2: 1.04704, 6

*** 1 failure is detected in the test module "dataset_example63"

PrevUpHomeNext