Source: jsmock.js

import MockMethodFactory from './jsmockMethodFactory';
import TestDouble from '../testDouble';

/** @class Mock */
class Mock extends TestDouble {
	/**
	 * @access private
	 **/
	constructor(name, type = 'object') {
		super(name, type);
		this.type = 'Mock';
	}
	/**
	 * should_receive make method in mock.
	 * @memberof Mock
	 * @instance
	 * @param {string} methodName - method name in mock.
	 * @function should_receive
	 * @returns {MockMethod}
	 * @example
mock("obj").should_receive("something");
// obj.something();

mock("Sample",mock.INSTANCE).should_receive("something");
// let sample = new Sample();
// sample.something();

// class Test
// end
// let test = new Test();
mock(test).should_receive("something");
// test.something();

mock(Test,mock.INSTANCE).should_receive("instance");
// let test = new Test();
// test.instance()
	 **/
	should_receive(methodName) {
		return MockMethodFactory.getMethod(this.getTestDouble(), methodName);
	}

	/**
	 * Return specific information called method.
	 * @memberof Mock
	 * @instance
	 * @function verify
	 * @example
mock("obj").should_receive("something");
obj.something();
mock("obj").verify("something"); // {"total" : 1, param : {}}
	 **/
	verify(methodName) {
		const methodInfo = MockMethodFactory.getData(this.getTestDouble()).get(methodName);
		if (methodInfo) {
			if (methodInfo.record.total === 0) {
				throw new Error(`${methodName} isn't called.`);
			} else {
				return methodInfo.record;
			}
		} else {
			throw new Error(`${methodName} isn't method.`);
		}
	}

	/**
	 * Return all information called methods.
	 * @memberof Mock
	 * @instance
	 * @function verify_all
	 * @example
mock("obj").should_receive("something");
mock("obj").should_receive("something2");
obj.something();
obj.something2();

mock("obj").verify_all();
//{
//	"something": {total" : 1, param : {}}
//	"something2": {total" : 1, param : {}}
//}
	 **/
	verify_all() {
		const obj = MockMethodFactory.getData(this.getTestDouble());
		const returnValue = {};

		obj.forEach((v, i) => {
			if (i !== 'current_obj') returnValue[i] = this.verify(i);
		});

		return returnValue;
	}

	/**
	 * Resets specific information called method.
	 * @memberof Mock
	 * @instance
	 * @function reset
	 * @example
mock("obj").should_receive("something");
mock("obj").should_receive("something2");
obj.something();
obj.something2();

mock("obj").verify("something"); // {"total" : 1, param : {}}
mock("obj").verify("something2"); // {"total" : 1, param : {}}

mock("obj").reset("something");
mock("obj").verify("something"); // throw new Error(`something isn't called.`);
mock("obj").verify("something2"); // {"total" : 1, param : {}}
	 **/
	reset(methodName) {
		const obj = MockMethodFactory.getData(this.getTestDouble());
		obj.get(methodName).record = { total: 0, param: {} };
	}

	/**
	 * Resets all information called methods.
	 * @memberof Mock
	 * @instance
	 * @function reset_all
	 * @example
mock("obj").should_receive("something");
mock("obj").should_receive("something2");
obj.something();
obj.something2();
mock("obj").verify("something"); // {"total" : 1, param : {}}
mock("obj").verify("something2"); // {"total" : 1, param : {}}

mock("obj").reset_all();
mock("obj").verify("something"); // throw new Error(`something isn't called.`);
mock("obj").verify("something2"); // throw new Error(`something2 isn't called.`);
	 **/
	reset_all() {
		for (const [key, value] of MockMethodFactory.getData(this.getTestDouble())) {
			if (key !== 'current_obj') {
				value.record = { total: 0, param: {} };
			}
		}
	}


}

/**
 * @desc create mock in global.
 * @param {string|object|function|class} name - Mock object of name, object, function or class.
 * @param {string} type - Mock object of type. - mock.INSTANCE, mock.OBJECT(defalut)
 * @function mock
 * @returns {Mock}
 * @example
// If `name` is string and `global` not found `name` object that mock create object in global.
mock("obj").should_receive("something");
mock("Sample",mock.INSTANCE).should_receive("something");

// If `name` is object that mock don`t create object.
mock(obj).should_receive("something");
mock(zlass).should_receive("something");
 **/
export default function mockWrap(name, type) {
	if (this instanceof Mock) {
		this.createTestDouble(name, type);
	} else {
		return new Mock(name, type);
	}
}

/**
 * object string
 * @name mock.OBJECT
 * @global
 * @example
mock("obj", mock.OBJECT);
 **/
mockWrap.OBJECT = 'object';

/**
 * instance string
 * @name mock.INSTANCE
 * @global
 * @example
mock("obj", mock.INSTANCE);
 **/
mockWrap.INSTANCE = 'instance';

/**
 * `anything` return special string.
 * If you use `anything` in `with_param` that
 * `should_receive` execute method regardless of parameter value.
 * @name mock.anything
 * @global
 * @function anything
 * @returns {String} - '_js_mock_anything_param'
 * @example
mock("obj").should_receive("something").with_param(1,mock.anything()).and_return("1");
 **/
mockWrap.anything = () => '_js_mock_anything_param';