When unit-testing the code, sooner or later the question of test data arises. And if in one case it is enough just a few hard-wired variables, in other cases some large and random data are needed. In a managed world, there are no problems with generating custom types (take the same Autofixture), but the C ++ world often causes pain and suffering (correct me if this is not the case). Not so long ago, I became acquainted with the remarkable library boost :: di, and under its influence, I began to ripen the idea of ββa library that would allow C ++ programmers to generate custom data types clogged with random values, and this would not require their prior description. It turned out something like:
struct dummy_member{ float a; int b; }; struct dummy{ explicit dummy(dummy_member val, std::string c) : val_(val), c_(c) {} private: dummy_member val_; std::string c_; }; int main(int argc, char* argv){ auto d = datagen::random<dummy>(); return 0; }
β Link to the code . Header-only library, C ++ 14. I ask all interested under the cat.
The generation of built-in types (char, wchar_t, etc.) is naturally supported. In this case, integer types are generated simply as a set of bits, and float and double - as the sum of a random integer (int32_t and int64_t, respectively) and random values ββin the range from -1 to 1. To generate a bool value, a comparison of two random integers is used.
std::cout << "The answer to the question of everything is:" << datagen::random<int>() << std::endl;
To generate custom types, the same idea was used as the basis for boost :: di (thanks to its author), namely the possibility of writing the universal type any_type, which is implicitly convertible into any other type (with rare exceptions). Adding a LITTLE template, it turned out a piece that generates custom types using the following tools:
struct dymmy
).struct dummy_member
).To generate objects based on a user-defined procedure, the pattern must be partially or fully specialized.
template<> struct datagen::value_generation_algorithm<TType> { TType get_random(random_source_base&); };
This adds the ability to take out some type generation parameters as members of this class, which in turn allows us to influence the type generation. For example, the algorithm for generating std std looks like this:
namespace datagen{ template <class CharType, class Traits, class Allocator> struct value_generation_algorithm<std::basic_string<CharType, Traits, Allocator>>{ using string_t = std::basic_string<CharType, Traits, Allocator>; string_t get_random(random_source_base& r_source){...}; size_t min_size{0}; size_t max_size{30}; std::basic_string<CharType> alphabet{"abcd...6789"}; }; }
The library supports limiters on generated values, for example:
std::cout << "The answer to the question of everything is:" << random<int>(between(42,42)) << std::endl;
There are 2 types of limiters:
value_generation_algorithm<T>
.With this, they can be used in 2 ways :
scoped_limit
based on scoped_limit
and applying it to a set of types. Then the limiter is applied to all of the specified types for the entire depth of the generated type tree throughout the life of the scoped_limit.To create custom constraints, you must declare a delimiter structure / class and implement one or both of the functions:
struct dummy_algorithm_limit{}; struct dummy_value_limit{}; namespace datagen{ namespace limits { void adjust_algorithm(random_source_base&, dummy_algorithm_limit const& l, value_generation_algorithm<dummy>& a){ // dummy } void adjust_value(random_source_base&, dummy_value_limit const& l, dummy& a){ // dummy } } }
Restrictions apply in the following order:
The source of entropy in the library is the class random_source_impl, using <random>
. But it is possible to override this by providing a specialization of the structure random_source_instance<int>
at the compilation stage.
For today, the generation of the following containers from stl has been implemented (actually what I need in my work):
pairs of types from boost:
Limiters for them:
Tested on the msvc-14.0 compiler, requires c ++ 14. Unfortunately, gcc behaves a little differently, as a result of which the library code did not gather under mingw (gcc-6.3.0), but I think those who have constant contact with him can quickly fix it.
The library is in the public domain . Ideas and implementations of new types are welcome.
Source: https://habr.com/ru/post/326576/
All Articles