1 /// generate arbitrary random data 2 module qcheck.arbitrary; 3 4 import std.array, std.algorithm, std.typetuple; 5 import qcheck.detail.arbitrary, qcheck.detail.random, qcheck.config; 6 7 /** 8 Get a random value of type `T`. 9 Randomly generates necessary ctor arguments. 10 11 Depending on `Config.randomizeFields`, all fields of structs and classes are random initialized. 12 13 Params: 14 Generators = custom factory functions for specific types 15 config = Configuration for random generation 16 17 Throws: 18 CyclicDependencyException - when ctor arguments cyclically depend on each other 19 */ 20 T getArbitrary(T, Generators...)(Config config=Config.init) 21 { 22 auto builder = Builder!(T, Generators)(config); 23 return builder.get(); 24 } 25 26 /// basic usage 27 unittest 28 { 29 auto sarray = getArbitrary!(int[4])(); 30 auto array = getArbitrary!(float[])(); 31 auto aarray = getArbitrary!(int[string])(); 32 } 33 34 /// fields not randomized 35 unittest 36 { 37 static struct Tuple { TypeTuple!(uint, float) vals; alias vals this; } 38 Config config; 39 config.randomizeFields = false; 40 auto val = getArbitrary!(Tuple)(config); 41 assert(val[0] == uint.init); 42 assert(isNaN(val[1])); 43 } 44 45 /// complex example with ctor arguments and generators 46 unittest 47 { 48 static struct UserStruct 49 { 50 this(int val) { this.val = val; } 51 int val; 52 } 53 54 static struct UserStructHolder 55 { 56 this(UserStruct val) { this.val = val; } 57 UserStruct val; 58 } 59 60 static struct UserStructInit 61 { 62 UserStruct val; 63 } 64 65 static UserStruct generator() 66 { 67 return UserStruct(10); 68 } 69 70 auto val = getArbitrary!(UserStruct, generator)(); 71 assert(val.val == 10); 72 73 auto val2 = getArbitrary!(UserStructHolder, generator)(); 74 assert(val2.val.val == 10); 75 76 auto val3 = getArbitrary!(UserStructInit, generator)(); 77 assert(val3.val.val == 10); 78 } 79 80 /// picks a random ctor 81 unittest 82 { 83 static class MultiCtors 84 { 85 uint val; 86 87 this(uint) 88 { 89 this.val = 1; 90 } 91 92 this(uint, uint) 93 { 94 this.val = 2; 95 } 96 97 this(uint, uint, uint) 98 { 99 this.val = 3; 100 } 101 102 this(uint, uint, uint, uint) 103 { 104 this.val = 4; 105 } 106 } 107 108 auto initial = getArbitrary!(MultiCtors)(); 109 auto i = 0; 110 while (initial.val == getArbitrary!(MultiCtors)().val) 111 assert(++i < 100); 112 } 113 114 /// field can be configured to be non-random 115 unittest 116 { 117 static class ClassWCtor 118 { 119 this() 120 { 121 } 122 123 int m; 124 } 125 126 static class TestClass 127 { 128 ClassWCtor val; 129 } 130 131 static struct TestStruct 132 { 133 ClassWCtor val; 134 } 135 136 static class ClassWOCtor 137 { 138 int m; 139 } 140 141 Config config; 142 config.randomizeFields = false; 143 auto cl = getArbitrary!TestClass(config); 144 assert(cl.val is null); 145 cl = getArbitrary!(TestClass)(); 146 assert(!(cl.val is null)); 147 } 148 149 /** Randomly initialize all fields of tuple `Tup`. 150 151 See_also: getArbitrary 152 */ 153 Tup getArbitraryTuple(Tup, Generators...)(Config config=Config.init) 154 { 155 Tup tup; 156 auto builder = Builder!(Tup, Generators)(config); 157 tup = builder.getTuple!(typeof(tup.tupleof))(); 158 return tup; 159 } 160 161 /** Randomly initialize an array of `len` 162 163 See_also: getArbitrary 164 */ 165 T[] getArbitraryArray(T, Generators...)(size_t len, Config config=Config.init) 166 { 167 T[] result; 168 auto builder = Builder!(T, Generators)(config); 169 foreach(_; 0 .. len) 170 result ~= builder.get(); 171 return result; 172 } 173 174 /* 175 * Set the random seed for the random generator used by the qcheck 176 * library. This is useful to gain reproducible results. 177 */ 178 public alias randomSeed = qcheck.detail.random.randomSeed; 179 180 version (unittest): 181 182 import std.conv : to, roundTo; 183 import std.stdio : writeln, writefln; 184 import std.math; 185 import std.traits; 186 import std.typecons; 187 import std.typetuple; 188 import qcheck; 189 190 // debug=ARBITRARY; 191 192 template maxIt(T) if(isFloatingPoint!T) 193 { 194 enum maxIt = 0; 195 } 196 197 template maxIt(T) if(isSigned!T && isIntegral!T) 198 { 199 enum maxIt = maxIt!(Unsigned!T); 200 } 201 202 template maxIt(T) if(is(T == ulong)) { enum maxIt = 0; } 203 template maxIt(T) if(is(T == uint)) { enum maxIt = 0; } 204 template maxIt(T) if(is(T == ushort)) { enum maxIt = 1; } 205 template maxIt(T) if(is(T == ubyte)) { enum maxIt = 1; } 206 template maxIt(T) if(is(T == bool)) { enum maxIt = 10; } 207 208 template testNumeric(T) 209 { 210 void run() 211 { 212 auto b0 = getArbitrary!T(); 213 size_t i; 214 while (b0 == getArbitrary!T()) 215 { 216 assert(i <= maxIt!T); 217 ++i; 218 } 219 } 220 } 221 222 223 unittest 224 { 225 testNumeric!bool.run(); 226 testNumeric!ulong.run(); 227 testNumeric!long.run(); 228 testNumeric!uint.run(); 229 testNumeric!int.run(); 230 testNumeric!ushort.run(); 231 testNumeric!short.run(); 232 testNumeric!ubyte.run(); 233 testNumeric!byte.run(); 234 testNumeric!float.run(); 235 testNumeric!double.run(); 236 testNumeric!real.run(); 237 } 238 239 240 enum BoolNum : bool 241 { 242 FALSE = false, 243 TRUE = true, 244 } 245 246 struct EnumStruct 247 { 248 this(string name) 249 { 250 this.name = name; 251 } 252 253 string name; 254 } 255 256 /// 257 unittest 258 { 259 static struct S 260 { 261 string name; // fields are randomized by default 262 } 263 264 assert(getArbitrary!S().name != getArbitrary!S().name); 265 } 266 267 /// 268 unittest 269 { 270 enum Enum 271 { 272 A = 10, 273 B = 20, 274 C = 30, 275 D = 40, 276 } 277 278 Enum val = getArbitrary!Enum(); 279 assert(cast(int)val % 10 == 0); 280 } 281 282 struct Entry 283 { 284 this(Second val) 285 { 286 this.val = val; 287 } 288 Second val; 289 } 290 291 class Second 292 { 293 this(Cyclic val) 294 { 295 this.val = val; 296 } 297 Cyclic val; 298 } 299 300 struct Cyclic 301 { 302 this(Entry val) 303 { 304 this.val = val; 305 } 306 Entry val; 307 } 308 309 unittest 310 { 311 bool succeeded = false; 312 try 313 { 314 auto val = getArbitrary!(Entry)(); 315 } 316 catch (CyclicDependencyException e) 317 { 318 succeeded = true; 319 } 320 assert(succeeded); 321 } 322 323 unittest 324 { 325 static bool testFloat(float f) 326 { 327 return -1000 < f && f < 1000; 328 } 329 330 static bool testArray(int K)(byte[] ary) 331 { 332 return ary.length <= K; 333 } 334 335 Config config; 336 config.minValue = -1000; 337 config.maxValue = 1000; 338 339 quickCheck!testFloat(config); 340 341 config.maxSize = 10; 342 quickCheck!(testArray!10)(config); 343 344 config.minValue = -2; 345 config.maxValue = 2; 346 config.maxSize = 5; 347 quickCheck!(testArray!5)(config); 348 }