Function Generators
Function generators generate values that are functions, that your code can call. This is mostly useful for testing higher-order functions.
qc.function([args...], returnGenerator)
This will generate a function that accepts any number of arguments and returns a value produced by returnGenerator
. It is a proper function mathematically speaking as the same arguments will produce the same return value. The args...
argument is currently ignored, but you can use it to indicate what arguments should the function expect (this is in no way enforced).
Arguments are checked for equality using
===
, so objects will not be equal to each other unless they point to the same underlying object.
describe('map', function() {
it('produces a list with the same length as passed in', function() {
expect(function(list, fn) {
return list.length === map(list, fn).length;
}).forAll(qc.array, qc.function(qc.any));
});
});
describe 'map', ->
it 'produces a list with the same length as passed in', ->
expect (list, fn) ->
list.length === map(list, fn).length
.forAll qc.array, qc.function(qc.any)
describe('map', function() {
it('produces a list with the same length as passed in', function() {
expect((list, fn) => list.length === map(list, fn).length)
.forAll(qc.array, qc.pureFunction(qc.any));
// Note that TypeScript doesn't allow the reserved name `function`
// as a property name, so we use the alias `pureFunction`.
});
});
qc.procedure(object, [injector])
Call for Feedback
This generator is provided as a beta release and feedback on it is welcome. If you use it in your codebase, please let the author know.
Generates a function that calls methods on the provided object
. If you provide a class (function), it will first be instantiated with the new
keyword and an array of arguments passed to the generated function. If there is a method called $final
, this will be invoked only once, at the very end, and its return value will be returned. Otherwise the function will return undefined
.
For example given this class:
function Animal() {
console.log('Constructor');
}
Animal.prototype.a = function() {
console.log('a');
};
Animal.prototype.b = function() {
console.log('b');
};
Animal.prototype.$final = function() {
console.log('$final');
return 'return value';
};
var randomAnimal = qc.procedure(Animal)(size);
randomAnimal();
class Animal
constructor: -> console.log('Constructor')
a: -> console.log('a')
b: -> console.log('b')
$final: ->
console.log('$final')
'return value'
randomAnimal = qc.procedure(Animal)(size)
randomAnimal()
class Animal {
constructor() { console.log('Constructor') }
a() { console.log('a') }
b() { console.log('b') }
$final() {
console.log('$final');
return 'return value';
}
}
let randomAnimal = qc.procedure(Animal)(size)
randomAnimal()
We would see an output something like this:
Constructor
b
b
a
b
a
a
$final
And the procedure would return 'return value'
.
Injection
Each method can also receive arguments that will be random. Inspired by the way the AngularJS injector works, each method can ask for random arguments by naming its arguments in a special way. You can have any of qc
's defined generators which take no arguments injected. Simply call them by name replacing dots with underscores. So qc.int
will be int
, qc.uint.large
would be uint_large
. You can optionally append a number which will be ignored. So function(int1, int2)
would be called with two different ints.
You can use your own generators by adding them using the second, optional argument injector
. The same rules apply: each matching key can also have an optional number appended to it.
Finally, you can opt to be explicit about injection and wrap your function in an array specifying generators explicitly. So function(int1, int2) {}
would become [qc.int, qc.int, function(a, b) {}]
. Or you can attach a special $inject
property that holds the generators.
function Animal(args) {
console.log('Constructor called with ', args);
}
Animal.prototype.a = function(int, string) {
console.log('a ', int, string);
};
Animal.prototype.b = function(uint_large1, uint_large2) {
console.log('b', uint_large1, uint_large2);
};
// $args is a special injector, it is the original arguments the function
// was called with.
Animal.prototype.$final = function($args) {
console.log('$final', $args);
return 'return value';
};
var randomAnimal = qc.procedure(Animal)(size);
randomAnimal('Hello');
class Animal
constructor: (args) ->
console.log('Constructor called with ', args)
a: (int, string) ->
console.log('a ', int, string)
b: (uint_large1, uint_large2) ->
console.log('b', uint_large1, uint_large2)
$final: ($args) ->
console.log('$final', $args)
'return value'
randomAnimal = qc.procedure(Animal)(size)
randomAnimal 'Hello'
class Animal {
constructor(args: any[]) {
console.log('Constructor called with ', args);
}
a(int: number, string: string) {
console.log('a ', int, string);
}
b(uint_large1: number, uint_large2: number) {
console.log('b', uint_large1, uint_large2);
}
$final($args: any[]) {
console.log('$final', $args);
return 'return value';
}
}
let randomAnimal = qc.procedure(Animal)(size);
randomAnimal('Hello');
Would output something like:
Constructor called with ['Hello']
a 45 ';r]etg'
a 23 'fbg345bg'
b 4235345 546923
b 2314 4325445
a 0 'JD2d32dj2d'
$final ['Hello']
Updated less than a minute ago