1 module unit_threaded.randomized.random;
2 
3 
4 /** This type will generate a $(D Gen!T) for all passed $(D T...).
5     Every call to $(D genValues) will call $(D gen) of all $(D Gen) structs
6     present in $(D values). The member $(D values) can be passed to every
7     function accepting $(D T...).
8 */
9 struct RndValueGen(T...)
10 {
11     import std.meta : staticMap;
12     import std.random: Random;
13 
14     /* $(D Values) is a collection of $(D Gen) types created through
15        $(D ParameterToGen) of passed $(T ...).
16     */
17     static if(is(typeof(T[0]) == string[])) {
18         alias generators = T[1 .. $];
19         string[] parameterNames = T[0];
20     } else {
21         alias generators = T;
22         string[T.length] parameterNames;
23     }
24 
25     alias Values = staticMap!(ParameterToGen, generators);
26 
27     /// Ditto
28     Values values;
29 
30     /* The constructor accepting the required random number generator.
31        Params:
32        rnd = The required random number generator.
33     */
34     this(Random* rnd)
35     {
36         this.rnd = rnd;
37     }
38 
39     this(ref Random rnd) {
40         this.rnd = &rnd;
41     }
42 
43     /* The random number generator used to generate new value for all
44        $(D values).
45     */
46     Random* rnd;
47 
48     /** A call to this member function will call $(D gen) on all items in
49         $(D values) passing $(D the provided) random number generator
50     */
51     void genValues() scope
52         in(rnd !is null)
53         do
54     {
55         foreach (ref it; this.values)
56         {
57             it.gen(*this.rnd);
58         }
59     }
60 
61     void toString(scope void delegate(const(char)[]) sink)
62     {
63         import std.format : formattedWrite;
64 
65         foreach (idx, ref it; values)
66         {
67             formattedWrite(sink, "'%s' = %s ", parameterNames[idx], it);
68         }
69     }
70 }
71 
72 @("176")
73 @safe unittest {
74     import std.random: Random;
75     const seed = 0x1337;
76     scope random = Random(seed);
77     scope gen = RndValueGen!(int[])(&random);
78     gen.genValues;
79 }
80 
81 
82 /** A template that turns a $(D T) into a $(D Gen!T) unless $(D T) is
83     already a $(D Gen) or no $(D Gen) for given $(D T) is available.
84 */
85 template ParameterToGen(T)
86 {
87     import unit_threaded.randomized.gen: isGen, Gen;
88     static if (isGen!T)
89         alias ParameterToGen = T;
90     else static if (is(T : GenASCIIString!(S), S...))
91         alias ParameterToGen = T;
92     else {
93         static assert(__traits(compiles, Gen!T),
94                       "ParameterToGen does not handle " ~ T.stringof);
95         alias ParameterToGen = Gen!T;
96     }
97 }