'use strict';

/* !

* Chai - checkError utility
* Copyright(c) 2012-2016 Jake Luer <jake@alogicalparadox.com>
* MIT Licensed
*/

/**

* ### .checkError
*
* Checks that an error conforms to a given set of criteria and/or retrieves information about it.
*
* @api public
*/

/**

* ### .compatibleInstance(thrown, errorLike)
*
* Checks if two instances are compatible (strict equal).
* Returns false if errorLike is not an instance of Error, because instances
* can only be compatible if they're both error instances.
*
* @name compatibleInstance
* @param {Error} thrown error
* @param {Error|ErrorConstructor} errorLike object to compare against
* @namespace Utils
* @api public
*/

function compatibleInstance(thrown, errorLike) {

return errorLike instanceof Error && thrown === errorLike;

}

/**

* ### .compatibleConstructor(thrown, errorLike)
*
* Checks if two constructors are compatible.
* This function can receive either an error constructor or
* an error instance as the `errorLike` argument.
* Constructors are compatible if they're the same or if one is
* an instance of another.
*
* @name compatibleConstructor
* @param {Error} thrown error
* @param {Error|ErrorConstructor} errorLike object to compare against
* @namespace Utils
* @api public
*/

function compatibleConstructor(thrown, errorLike) {

if (errorLike instanceof Error) {
  // If `errorLike` is an instance of any error we compare their constructors
  return thrown.constructor === errorLike.constructor || thrown instanceof errorLike.constructor;
} else if (errorLike.prototype instanceof Error || errorLike === Error) {
  // If `errorLike` is a constructor that inherits from Error, we compare `thrown` to `errorLike` directly
  return thrown.constructor === errorLike || thrown instanceof errorLike;
}

return false;

}

/**

* ### .compatibleMessage(thrown, errMatcher)
*
* Checks if an error's message is compatible with a matcher (String or RegExp).
* If the message contains the String or passes the RegExp test,
* it is considered compatible.
*
* @name compatibleMessage
* @param {Error} thrown error
* @param {String|RegExp} errMatcher to look for into the message
* @namespace Utils
* @api public
*/

function compatibleMessage(thrown, errMatcher) {

var comparisonString = typeof thrown === 'string' ? thrown : thrown.message;
if (errMatcher instanceof RegExp) {
  return errMatcher.test(comparisonString);
} else if (typeof errMatcher === 'string') {
  return comparisonString.indexOf(errMatcher) !== -1; // eslint-disable-line no-magic-numbers
}

return false;

}

/**

* ### .getFunctionName(constructorFn)
*
* Returns the name of a function.
* This also includes a polyfill function if `constructorFn.name` is not defined.
*
* @name getFunctionName
* @param {Function} constructorFn
* @namespace Utils
* @api private
*/

var functionNameMatch = /s*function(?:s|s*/*+*/s*)*(+)/; function getFunctionName(constructorFn) {

var name = '';
if (typeof constructorFn.name === 'undefined') {
  // Here we run a polyfill if constructorFn.name is not defined
  var match = String(constructorFn).match(functionNameMatch);
  if (match) {
    name = match[1];
  }
} else {
  name = constructorFn.name;
}

return name;

}

/**

* ### .getConstructorName(errorLike)
*
* Gets the constructor name for an Error instance or constructor itself.
*
* @name getConstructorName
* @param {Error|ErrorConstructor} errorLike
* @namespace Utils
* @api public
*/

function getConstructorName(errorLike) {

var constructorName = errorLike;
if (errorLike instanceof Error) {
  constructorName = getFunctionName(errorLike.constructor);
} else if (typeof errorLike === 'function') {
  // If `err` is not an instance of Error it is an error constructor itself or another function.
  // If we've got a common function we get its name, otherwise we may need to create a new instance
  // of the error just in case it's a poorly-constructed error. Please see chaijs/chai/issues/45 to know more.
  constructorName = getFunctionName(errorLike).trim() ||
      getFunctionName(new errorLike()); // eslint-disable-line new-cap
}

return constructorName;

}

/**

* ### .getMessage(errorLike)
*
* Gets the error message from an error.
* If `err` is a String itself, we return it.
* If the error has no message, we return an empty string.
*
* @name getMessage
* @param {Error|String} errorLike
* @namespace Utils
* @api public
*/

function getMessage(errorLike) {

var msg = '';
if (errorLike && errorLike.message) {
  msg = errorLike.message;
} else if (typeof errorLike === 'string') {
  msg = errorLike;
}

return msg;

}

module.exports = {

compatibleInstance: compatibleInstance,
compatibleConstructor: compatibleConstructor,
compatibleMessage: compatibleMessage,
getMessage: getMessage,
getConstructorName: getConstructorName,

};