Giter Club home page Giter Club logo

damncheck's Introduction

damncheck v0.2

A property based testing library for D. Forked from dashcheck. It features a customizable tester and diverse generators and meta-generators. Bellow is a simple documentation based on examples. The full documentation as rendered with Ddoc can be found here

Generators

Generators are used to generate random values of a certain type. This is how you can use some of the generators in D.

T generate(T)(T min=T.init, T max=T.init)

Will return a random element of type T.

generate!bool; // will generate a random boolean
generate!string; // will generate a random string
generate!(int[]); // will use the meta-generator list!int
generate!(immutable int[char[immutable bool]]);
// will use the meta-generator dict!(immutable int, char[immutable bool])

generate!int(-100); // generate a random integer in [-100,int.max]
generate!float(10.037f, 100f); // generate a random float in [10.037, 100]

T choose(T)(T[] array)

Will return a random element form the array provided

choose([1, -1, 8, -8, 23]);
choose(["D", "C", "Python"]);

Generating Predictable Results

To easily recreate a set of test values there is a function setGeneratorSeed that allows you to provide the seed to the random number generator.

void setGeneratorSeed(uint seed = unpredictableSeed)

setGeneratorSeed(); // the seed will be unpredictable
// ... testing code here
setGeneratorSeed(100); // the seed is now 100, same values will be generated on each run
// ... testing code here

Meta-generators

Meta-generators are generators that take as arguments generators. They are used to construct more complex generators.

auto oneOf(T...)(lazy T generators) if(generators.length >= 2)

Takes at least 2 generators and returns whatever a randomly selected generator returns.

oneOf(generate!float(-1f,1f), generate!float(99f,100f)); // random number in [-1,1]U[99,100]
oneOf(2,4,0,5,10); // a random number in {2, 4, 0, 5, 10}, equivalent to choose([2,4,0,5,10])

U mapGenerate(alias mapper,T,U=T)(lazy T generator=generate!T)

A map function that operates on generators to construct other generators.

mapGenerate!(a => a % 2 == 0 ? a + 1 : a)(generate!int); // random odd int
mapGenerate!(a => a % 2 == 0 ? a : a + 1)(generate!int(-100,100)) // random even int between -100 and 100
mapGenerate!(a => a % 10, int) // generate a number between -10 and 10

T[] list(T, size_t N=ARRAY_MAX_SIZE)(lazy T generator=generate!T)

Produce an array that has at most length N whose elements are from the provided generator.

list!int // generate a list of integers
list!(bool,4) // a list of at most 4 booleans
list!int(0) // generate a list of all 0s
list!(float, 3)(generate!float(3, 5)) // a list of at most 3 floats between 3 and 5

T[U] dict(T, U, size_t N=ARRAY_MAX_SIZE)(lazy T values=generate!T, lazy U keys=generate!U)

Produce an associative array whose keys are generated from the keys generator and values are from the keys generator.

dict!(int, int) // a dictionary whose keys and values are random integers
dict!(int, bool) // [false: 2841782, true: -194927830]
dict!(int, bool, 10000000)(3) // [false: 3, true: 3]

Sampling

Sampling is very similar to the list meta-generator. But it's usually used for illustration purposes and not as a generator. As well it generates a list of exactly N elements as opposed to one that has at most N elements.

T[] sample(T, const(int) N=10)(lazy T gen=generate!T)

sample!int // a list of 10 integers
sample!(bool, 2) // a list of 2 booleans
sample(generate!float(-1f,1f)) // a list of 10 floats between -1 and 1
sample!(float, 3)(generate!float(-1f,1f)) // a list of 3 floats between -1 and 1

Testing

DamnStat forAll(alias property, const(int) n=NUM_TESTS, alias reporter=null, Generators...)(lazy Generators generators) if (isCallable!property && is(ReturnType!property == bool))

Start a property-based test.

/+ Example without reporting +/
bool idempotentSort(int[] list) {
    return list.sort == list.sort.sort;
}
auto stat1 = forAll!property(generate!(int[]));
auto stat2 = forAll!(property,1000)(generate!(ulong[]));
if(stat1.passed && stat2.passed) {
    writef("***** %d tests passed *****\n", stat1.testNum + stat2.testNum);
} else {
    writef("***** %d/%d tests passed *****\nError at input:\n%s",
           stat1.testNumRan, stat1.testNum, stat1.failStr);
    writef("***** %d/%d tests passed *****\nError at input:\n%s",
           stat2.testNumRan, stat2.testNum, stat2.failStr);
}
/+ Example with reporting +/
bool expandingFloat(float a, float b, float c) {
    return a * (b + c) == a * b + a * c;
}
void expandingFloatReporter(float a, float b, float c) {
    writeln("Failed for: ", a, " ", b, " ", c);
    writefln("%.12f * (%.12f + %.12f) = %.12f", a, b, c, a*(b+c));
    writefln("%.12f * %.12f + %.12f * %.12f = %.12f", a, b, a, c, a*b+a*c));
}

auto stat = forAll!(expandingFloat, 100, expandingFloatShrinker)
                       (generate!float, generate!float, generate!float);

damncheck's People

Contributors

geezee avatar

Stargazers

Mohammad Sadegh Khoeini avatar Paul Crane avatar  avatar Brian Schott avatar Tomáš Chaloupka avatar

Watchers

James Cloos avatar  avatar

Forkers

bayanr

damncheck's Issues

Generator for structs and classes

I was thinking of probably picking randomly a constructor of a given struct or class and based on the types of its arguments generate random arguments which will lead to a "random" object.

Improve on DamnStat

DamnStat should be a struct with a boolean, int, int and a tuple. The first boolean will be if all the tests passed, the second int is how many tests were scheduled to run, the third int is how many tests actually ran and the last tuple is the arguments passed to the tester that failed the test. It's more logical to decompose it this way and brings an advantage that is accessing the failing arguments without reducing them to a string representation.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.