var assert = require('chai').assert;

module.exports = function makeMock(object) {
  var args = [];
  var mockObj = function mockObj() {};

  for (prop in object.prototype) {
    mockObj.prototype[prop] = mockFunction(prop);
  }

  mockObj.prototype.reset = function reset() {
    for (prop in args) {
      if (args.hasOwnProperty(prop)) {
        args[prop] = [];
      }
    }
  }
  mockObj.prototype.getArgs = function getArgs() {
    return args;
  }
  return mockObj;

  function mockFunction(name) {
    var returns = undefined;
    var sideEffects = [];
    function _mockFunction() {
      applySideEffects.apply(this, arguments);
      args[name] = args[name] || [];
      args[name].push(Array.prototype.slice.call(arguments));
      return returns;
    }
    function applySideEffects() {
      for (var i = 0; i < sideEffects.length; i++) {
        sideEffects[i].apply(this, arguments);
      };
    }
    _mockFunction.assertCalledOnceWith = function assertCalledOnceWith(expectedArgs, message) {
      assert.deepEqual(args[name][0], expectedArgs, message);
    }
    _mockFunction.assertCalledWith = function assertCalledWith(expectedArgs, message) {
      // TODO: Implement Deep equal comparison
      actualArgs = args[name];
      for (var i = 0; i < actualArgs.length; i++) {
        for (var j = 0; j < actualArgs[i].length; j++) {
          if (expectedArgs[j] !== actualArgs[i][j]) {
            break;
          }
          if (j === actualArgs[i].length - 1) {
            return assert.deepEqual(actualArgs[i], expectedArgs);
          }
        };
      };
      assert.fail(actualArgs, expectedArgs, message);
    }
    _mockFunction.assertNotCalled = function assertNotCalled(message) {
      assert.equal(args[name].length, 0, message);
    }
    _mockFunction.assertNumTimesCalled = function assertNumTimesCalled(num, message) {
      assert.equal(args[name].length, num, message);
    }
    _mockFunction.returns = function returns(value) {
      returns = value;
    }
    _mockFunction.assertCalledOnceWithArgsIncluding = function assertCalledWithArgsIncluding(expectedArgs, message) {
      assert.includeMembers(args[name][0], expectedArgs, message);
    }
    _mockFunction.addSideEffect = function(sideEffectFunc) {
      sideEffects.push(sideEffectFunc);
    }
    return _mockFunction;
  }
}


@@ -72,20 +72,26 @@
 k(object
+, type
 ) %7B%0A
-
   var ar
@@ -256,16 +256,275 @@
 .reset =
+ reset;%0A  mockObj.prototype.getArgs = getArgs;%0A%0A  for (prop in object) %7B%0A    if (object.hasOwnProperty(prop) && typeof object%5Bprop%5D === 'function') %7B%0A      mockObj%5Bprop%5D = mockFunction(prop);%0A    %7D%0A  %7D%0A%0A  mockObj.reset = reset;%0A  mockObj.getArgs = getArgs;%0A%0A 
  functio
@@ -646,37 +646,10 @@
   %7D%0A
+%0A
  
- mockObj.prototype.getArgs =
  fun
@@ -687,16 +687,17 @@
 gs;%0A  %7D%0A
+%0A
   return
@@ -790,24 +790,45 @@
 fects = %5B%5D;%0A
+    args%5Bname%5D = %5B%5D;%0A
     function
@@ -850,92 +850,8 @@
 ) %7B%0A
-      applySideEffects.apply(this, arguments);%0A      args%5Bname%5D = args%5Bname%5D %7C%7C %5B%5D;%0A
     
@@ -908,16 +908,63 @@
 ents));%0A
+      applySideEffects.apply(this, arguments);%0A
       re
@@ -1220,32 +1220,32 @@
 rgs, message) %7B%0A
-
       assert.dee
@@ -1288,32 +1288,163 @@
 message);%0A    %7D%0A
+    _mockFunction.assertCalledOnce = function assertCalledOnce(message) %7B%0A      assert.equal(args%5Bname%5D.length, 1, message);%0A    %7D%0A
     _mockFunctio

Add support for mocking properties not in prototype