//---------------------------------------------------------------------------// // ," /\ ", Azur: A game engine for CASIO fx-CG and PC // // | _/__\_ | Designed by Lephe' and the Planète Casio community. // // "._`\/'_." License: MIT // //---------------------------------------------------------------------------// // unit_sample.h: Utility for generating sample values for testing // // This file mainly provides the runOnSampleInputs() function which runs a // boolean function f() on a series of generated inputs. It achieves this by // reading a storage of pre-computed inputs for each of the arguments of f. // This requires a storage to exist for each argument's type, which is provided // by SampleBase and subclassed by Sample. // // The meat of the generation is the generateIntSample() function, which // generates sparse sets of integers of varied size that omit needlessly // redundant input while densely covering special cases. //--- #pragma once #include #include #include #include #include #include using namespace libnum; //--- // Integer sampling //--- template void generateIntSample(std::vector &v, std::function ctor, Uint start, Uint length, int count) { /* When we get to a set of size 16, do all values. */ if(count <= 16) { /* If we have an even-only range, force in some odd numbers too. */ bool switch_odd = (length >= (Uint)(2*count)); Uint step = length / count; while(count-- > 0) { v.push_back(ctor(start)); start += switch_odd ? step ^ (count & 1) : step; } return; } /* Otherwise, fractally divide into 16 segments and assign a portion of the available points to each section. We divide the count of points in 16ths so that there is at least one point in each segment. */ Uint sublength = length / 16; int subcount = count / 16; /* This array must add up to 16. */ int props[16] = { 4, 1, 1, 0, 0, 2, 0, 0, 1, 0, 2, 0, 0, 0, 1, 4 }; for(int i = 0; i < 16; i++) { if(props[i]) generateIntSample(v, ctor, (Uint)(start + i * sublength), sublength, subcount * props[i]); } } //--- // Input sampling //--- template struct SampleBase { static std::vector v; }; template std::vector SampleBase::v; template struct Sample {}; template concept has_sample = requires { Sample::get; }; template<> struct Sample: SampleBase { static std::vector const &get() { if(v.size() > 0) return v; for(int i = 0; i <= 0xff; i++) { num8 x; x.v = i; v.push_back(x); } return v; } }; template<> struct Sample: SampleBase { static std::vector const &get() { if(v.size() > 0) return v; auto f = [](uint16_t i) { num16 x; x.v = i; return x; }; generateIntSample(v, f, 0, 1 << 15, 512); generateIntSample(v, f, -(1 << 15), 1 << 15, 512); return v; } }; template<> struct Sample: SampleBase { static std::vector const &get() { if(v.size() > 0) return v; auto f = [](uint32_t i) { num32 x; x.v = i; return x; }; generateIntSample(v, f, 0, 1 << 15, 512); generateIntSample(v, f, -(1 << 15), 1 << 15, 512); generateIntSample(v, f, 0, 1ul << 31, 512); generateIntSample(v, f, 1ul << 31, 1ul << 31, 512); return v; } }; template<> struct Sample: SampleBase { static std::vector const &get() { if(v.size() > 0) return v; auto f = [](uint32_t i) { return i; }; generateIntSample(v, f, 0, 1 << 15, 512); generateIntSample(v, f, -(1 << 15), 1 << 15, 512); generateIntSample(v, f, 0, 1ul << 31, 512); generateIntSample(v, f, 1ul << 31, 1ul << 31, 512); return v; } }; template<> struct Sample: SampleBase { static std::vector const &get() { if(v.size() > 0) return v; auto f = [](uint64_t i) { num64 x; x.v = i; return x; }; generateIntSample(v, f, 0, 1 << 15, 512); generateIntSample(v, f, -(1 << 15), 1 << 15, 512); generateIntSample(v, f, 0, 1ul << 31, 512); generateIntSample(v, f, -(1ul << 31), 1ul << 31, 512); generateIntSample(v, f, 0, 1ull << 63, 512); generateIntSample(v, f, 1ull << 63, 1ull << 63, 512); return v; } }; //--- // Automatic test functions //--- template requires(has_sample) void runOnSampleInputs(std::function f) { for(auto t: Sample::get()) f(t); } template requires(has_sample && has_sample) void runOnSampleInputs(std::function f) { for(auto t: Sample::get()) for(auto u: Sample::get()) f(t, u); }