'use strict';
var util = require('util');
var assert = require('assert');
var EventEmitter = require('events').EventEmitter;
var fnName = require('fn-name');
var claim = require('claim');
var objectAssign = require('object-assign');

/**
 * Initialize a new `Test`
 *
 * @param {String} title
 * @param {Function} fn
 * @api public
 */

function Test(title, fn) {
	if (!(this instanceof Test)) {
		return new Test(title, fn);
	}

	if (typeof title !== 'string') {
		fn = title;
		title = null;
	}

	EventEmitter.call(this);

	this.title = title || fnName(fn) || '[anonymous]';
	this.fn = fn;
	this.assertCount = 0;
	this.planCount = null;

	// TODO: find a better way to count assertions
	this.onAssert(function () {
		if (++this.assertCount === this.planCount) {
			setImmediate(this.exit.bind(this));
		}
	}.bind(this));
}

util.inherits(Test, EventEmitter);
objectAssign(Test.prototype, claim);
module.exports = Test;

/**
 * Plan number of assertions
 *
 * @param {Number} count
 * @api public
 */

Test.prototype.plan = function (count) {
	if (typeof count !== 'number') {
		throw new TypeError('Expected a number');
	}

	this.planCount = count;
};

/**
 * Skip test
 *
 * @api public
 */

Test.prototype.skip = function () {
	this.skipTest = true;
};

/**
 * Run test
 *
 * @param {Function} cb
 * @api public
 */

Test.prototype.run = function (cb) {
	this.cb = cb;

	if (!this.fn || this.skipTest) {
		this.exit();
	}

	try {
		this.fn(this);
	} catch (err) {
		this.assertError = err;
		this.exit();
	}
};

/**
 * End test
 *
 * @api public
 */

Test.prototype.end = function () {
	if (this.endCalled) {
		throw new Error('.end() called more than once');
	}

	this.endCalled = true;
	this.exit();
};

/**
 * Exit test
 *
 * @api private
 */

Test.prototype.exit = function () {
	if (this.planCount !== null && this.planCount !== this.assertCount) {
		this.assertError = new assert.AssertionError({
			actual: this.assertCount,
			expected: this.planCount,
			message: 'Assertion count does not match planned',
			operator: 'plan'
		});
	}

	if (!this.ended) {
		this.ended = true;

		setImmediate(function () {
			this.cb.call(this, this.assertError);
		}.bind(this));
	}
};

@@ -184,53 +184,8 @@
 m');
-%0Avar objectAssign = require('object-assign');
 %0A%0A/*
@@ -591,72 +591,95 @@
 ll;%0A
-%0A%09// TODO: find a better way to count assertions%0A%09this.onA
+%7D%0A%0Autil.inherits(Test, EventEmitter);%0Amodule.exports = Test;%0A%0ATest.prototype._a
 ssert
-(
+ = 
 func
@@ -688,17 +688,16 @@
 on () %7B%0A
-%09
 %09if (++t
@@ -734,17 +734,16 @@
 ount) %7B%0A
-%09
 %09%09setImm
@@ -776,124 +776,257 @@
 ));%0A
-%09
 %09%7D%0A
-%09%7D.bind(this));%0A%7D%0A%0Autil.inherits(Test, EventEmitter);%0AobjectAssign(Test.prototype, claim);%0Amodule.exports = Test
+%7D%0A%0A// TODO: find a better way to count assertions%0A// decorate the %60claim%60 methods with our assert counter%0AObject.keys(claim).forEach(function (el) %7B%0A%09Test.prototype%5Bel%5D = function () %7B%0A%09%09this._assert();%0A%09%09claim%5Bel%5D.apply(claim, arguments);%0A%09%7D;%0A%7D)
 ;%0A%0A/

rewrite assert counter