macgyver

declarative assertion framework for invocation ordering.

macgyver

declarative assertion framework for invocation ordering.

when evented code really gets mission critical there is one man you send in...

useful for testing streams, and other complex evented modules.

 
var macgyver = require('macgyver')
 
//create a context 
var mac = macgyver()
 
//wrap a function... 
 
function hello () {
  console.log('hello')
}
 
function goodbye () {
  console.log('goodbye')
}
 
var hi = mac(hello)
 
//declare it's behaviours 
 
hi.isCalled(1, 7) //must be called between 1 and 7 times. 
 
var bye = mac(goodbye).once() //must be called strictly once. 
 
hi.before(bye) //hi must be called strictly before bye is called 
 
hi(); hi(); bye()
 
/*
  //this will produce an error!
  hi(); hi(); bye(); hi()
*/
 
mac.validate()

here is a real life example: dominictarr/event-stream/test/spec.js

create a maggyver context.

var macgyver = require('macgyver')
var mac = macgyver()
 

wrap a function

 
function doSomething() {}
 
var _doSomething = mac(doSomething)
 

now, we can make declairations about how the wrapped function must be called.

assert that the function is called at least min times, and at most max times. if min, or max is null, then that bound is not checked. i.e. mac(fun).isCalled(null, 10) will assert that fun is called not more than 10 times.

alias for isCalled (1, 1)

alias for isCalled (n, n)

alias for isCalled (null, 1)

alias for isCalled (0, 0)

alias for isCalled (null, 1)

alias for isCalled (null, max)

alias for isCalled (min, null)

increments the number of times a function may be called. (inc may be negative)

assert that a function is called before another function. the other must also be a wrapped function. mac(first).before(second = mac(second))

before does not check wether the second function is eventually called or not. use isCalled or an alias.

just like before but checks that the function is called before the other function returns, so that it is possible for the first function to be called by the other.

assert that a function returns a value. if value is a function, it will be called with the return value.

//assert that fun returns a string. 
mac(fun).returns(function (val) {
  assert.equal(typeof val, 'string')
})
 

the function should throw if the return value was not valid.

assert that a function is passed the correct arguments. if args is a function, that function is called as in returns.

assert that a function throws. test may be a value or a function. test is optional.

if supplyed test is called on every call.

mac(fun).throws(function (errthrew) {
  if(threw) {
    assert.equal(err.code,'ERRCODE') //check correct error 
  } else {
    //what to do if there was no error? 
  }
})

this is useful for checking conditions about when the error should be thrown. example stream#write

check all rules passed. must be called once you are sure all calls are finished. for example process.on('exit', mac.validate) is a good time. validate in necessary to check that lower bounds of isCalled and aliases where met.

call validate on process.on('exit', mac.validate). if process.on is not available (as on the browser) wait until browserTimeout instead. testling ci kills tests after 30 seconds, so by default browserTimeout = 10e3 (10 seconds)

MIT / Apachce2