2

I am trying to learn how to use boost::test's data-driven test functionality. How ever I ran into a trouble which I believe related to dataset(and samples)'s destruction. Take the following code snippet as example:

#define BOOST_TEST_MODULE dataset_example68
#include <boost/test/included/unit_test.hpp>
#include <boost/test/data/test_case.hpp>
#include <boost/test/data/monomorphic.hpp>
#include <sstream>
#include <cstdio>

namespace bdata = boost::unit_test::data;

// Dataset generating a Fibonacci sequence
class fibonacci_dataset {
public:
    // Samples type is int
    using sample=int;
    enum { arity = 1 };

    struct iterator {

        iterator() : a(1), b(1) {}

        int operator*() const   { return b; }
        void operator++()
        {
            a = a + b;
            std::swap(a, b);
        }
    private:
        int a;
        int b; // b is the output
    };

    fibonacci_dataset() {fprintf(stderr, "constructed %p\n", (void*)this);}
    ~fibonacci_dataset() {fprintf(stderr, "destructed %p\n", (void*)this);}
    // size is infinite
    bdata::size_t   size() const    { return bdata::BOOST_TEST_DS_INFINITE_SIZE; }

    // iterator
    iterator        begin() const   { return iterator(); }
};

namespace boost { namespace unit_test { namespace data { namespace monomorphic {
  // registering fibonacci_dataset as a proper dataset
  template <>
  struct is_dataset<fibonacci_dataset> : boost::mpl::true_ {};
}}}}

// Creating a test-driven dataset 
BOOST_DATA_TEST_CASE(
    test1,
    fibonacci_dataset() ^ bdata::make( { 1, 2, 3, 5, 8, 13, 21, 35, 56 } ),
    fib_sample, exp)
{
      BOOST_TEST(fib_sample == exp);
}

This code snippet is from boost::test's doc and I only added the fprintf(stderr,''') in constructor/destructor. I compiled and ran it on my arch linux(boost 1.63.0, gcc 6.3.1, compiler option -std=c++14), the output is as follow:

constructed 0x7ffd69e66e3e
destructed 0x7ffd69e66de0
destructed 0x7ffd69e66e3d
destructed 0x7ffd69e66e3e
Running 9 test cases...
4.cpp(53): error: in "test1/_7": check fib_sample == exp has failed [34 != 35]
Failure occurred in a following context:
    fib_sample = 34; exp = 35; 
4.cpp(53): error: in "test1/_8": check fib_sample == exp has failed [55 != 56]
Failure occurred in a following context:
    fib_sample = 55; exp = 56; 

*** 2 failures are detected in the test module "dataset_example68"

My question is:

  1. It seems that dataset get destruted before test case start to run, does it make sense?(Though not demonstrated in this snippet, it seems that data samples get destructed before test case start to run too, does it make sense?)
  2. I think if you declare a constructor, the compiler won't implicitly generate a default constructor for you. And if you declare a destructor, the compiler won't implicitly generate the copy/move operator/constructor for you, so how does "the other" dataset get constructed(from the output, there are more than one dataset destructed)?

Thank you very much for your help.

Jinpei Li
  • 21
  • 1
  • 5

1 Answers1

1

The first dataset at address 0x7ffd69e66e3e is constructed because of the call to its constructor in

fibonacci_dataset() ^ bdata::make( { 1, 2, 3, 5, 8, 13, 21, 35, 56 } )

and this is the only one you see with your default constructor. All the other datasets are actually moved. There is such a move for example in the operator^ implying the construction of the class boost::unit_test::data::monomorphic::zip.

At initialisation (before entering the main) the UTF declares the BOOST_DATA_TEST_CASE which calls make_test_case_gen. This registers a unit test for each sample of the dataset. The unit test holds the sample directly.

Once all the unit tests have been registered, there is no need to hold the dataset anymore. So it makes perfect sense to delete the dataset before the tests start.

Raffi
  • 3,068
  • 31
  • 33