Software zum Installieren eines Smart-Mirror Frameworks , zum Nutzen von hochschulrelevanten Informationen, auf einem Raspberry-Pi.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

deep-equal.js 9.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. "use strict";
  2. var valueToString = require("@sinonjs/commons").valueToString;
  3. var className = require("@sinonjs/commons").className;
  4. var typeOf = require("@sinonjs/commons").typeOf;
  5. var arrayProto = require("@sinonjs/commons").prototypes.array;
  6. var objectProto = require("@sinonjs/commons").prototypes.object;
  7. var mapForEach = require("@sinonjs/commons").prototypes.map.forEach;
  8. var getClass = require("./get-class");
  9. var identical = require("./identical");
  10. var isArguments = require("./is-arguments");
  11. var isDate = require("./is-date");
  12. var isElement = require("./is-element");
  13. var isMap = require("./is-map");
  14. var isNaN = require("./is-nan");
  15. var isObject = require("./is-object");
  16. var isSet = require("./is-set");
  17. var isSubset = require("./is-subset");
  18. var concat = arrayProto.concat;
  19. var every = arrayProto.every;
  20. var push = arrayProto.push;
  21. var getTime = Date.prototype.getTime;
  22. var hasOwnProperty = objectProto.hasOwnProperty;
  23. var indexOf = arrayProto.indexOf;
  24. var keys = Object.keys;
  25. var getOwnPropertySymbols = Object.getOwnPropertySymbols;
  26. /**
  27. * Deep equal comparison. Two values are "deep equal" when:
  28. *
  29. * - They are equal, according to samsam.identical
  30. * - They are both date objects representing the same time
  31. * - They are both arrays containing elements that are all deepEqual
  32. * - They are objects with the same set of properties, and each property
  33. * in ``actual`` is deepEqual to the corresponding property in ``expectation``
  34. *
  35. * Supports cyclic objects.
  36. *
  37. * @alias module:samsam.deepEqual
  38. * @param {*} actual The object to examine
  39. * @param {*} expectation The object actual is expected to be equal to
  40. * @param {object} match A value to match on
  41. * @returns {boolean} Returns true when actual and expectation are considered equal
  42. */
  43. function deepEqualCyclic(actual, expectation, match) {
  44. // used for cyclic comparison
  45. // contain already visited objects
  46. var actualObjects = [];
  47. var expectationObjects = [];
  48. // contain pathes (position in the object structure)
  49. // of the already visited objects
  50. // indexes same as in objects arrays
  51. var actualPaths = [];
  52. var expectationPaths = [];
  53. // contains combinations of already compared objects
  54. // in the manner: { "$1['ref']$2['ref']": true }
  55. var compared = {};
  56. // does the recursion for the deep equal check
  57. // eslint-disable-next-line complexity
  58. return (function deepEqual(
  59. actualObj,
  60. expectationObj,
  61. actualPath,
  62. expectationPath
  63. ) {
  64. // If both are matchers they must be the same instance in order to be
  65. // considered equal If we didn't do that we would end up running one
  66. // matcher against the other
  67. if (match && match.isMatcher(expectationObj)) {
  68. if (match.isMatcher(actualObj)) {
  69. return actualObj === expectationObj;
  70. }
  71. return expectationObj.test(actualObj);
  72. }
  73. var actualType = typeof actualObj;
  74. var expectationType = typeof expectationObj;
  75. if (
  76. actualObj === expectationObj ||
  77. isNaN(actualObj) ||
  78. isNaN(expectationObj) ||
  79. actualObj === null ||
  80. expectationObj === null ||
  81. actualObj === undefined ||
  82. expectationObj === undefined ||
  83. actualType !== "object" ||
  84. expectationType !== "object"
  85. ) {
  86. return identical(actualObj, expectationObj);
  87. }
  88. // Elements are only equal if identical(expected, actual)
  89. if (isElement(actualObj) || isElement(expectationObj)) {
  90. return false;
  91. }
  92. var isActualDate = isDate(actualObj);
  93. var isExpectationDate = isDate(expectationObj);
  94. if (isActualDate || isExpectationDate) {
  95. if (
  96. !isActualDate ||
  97. !isExpectationDate ||
  98. getTime.call(actualObj) !== getTime.call(expectationObj)
  99. ) {
  100. return false;
  101. }
  102. }
  103. if (actualObj instanceof RegExp && expectationObj instanceof RegExp) {
  104. if (valueToString(actualObj) !== valueToString(expectationObj)) {
  105. return false;
  106. }
  107. }
  108. if (actualObj instanceof Promise && expectationObj instanceof Promise) {
  109. return actualObj === expectationObj;
  110. }
  111. if (actualObj instanceof Error && expectationObj instanceof Error) {
  112. return actualObj === expectationObj;
  113. }
  114. var actualClass = getClass(actualObj);
  115. var expectationClass = getClass(expectationObj);
  116. var actualKeys = keys(actualObj);
  117. var expectationKeys = keys(expectationObj);
  118. var actualName = className(actualObj);
  119. var expectationName = className(expectationObj);
  120. var expectationSymbols =
  121. typeOf(getOwnPropertySymbols) === "function"
  122. ? getOwnPropertySymbols(expectationObj)
  123. : /* istanbul ignore next: cannot collect coverage for engine that doesn't support Symbol */
  124. [];
  125. var expectationKeysAndSymbols = concat(
  126. expectationKeys,
  127. expectationSymbols
  128. );
  129. if (isArguments(actualObj) || isArguments(expectationObj)) {
  130. if (actualObj.length !== expectationObj.length) {
  131. return false;
  132. }
  133. } else {
  134. if (
  135. actualType !== expectationType ||
  136. actualClass !== expectationClass ||
  137. actualKeys.length !== expectationKeys.length ||
  138. (actualName &&
  139. expectationName &&
  140. actualName !== expectationName)
  141. ) {
  142. return false;
  143. }
  144. }
  145. if (isSet(actualObj) || isSet(expectationObj)) {
  146. if (
  147. !isSet(actualObj) ||
  148. !isSet(expectationObj) ||
  149. actualObj.size !== expectationObj.size
  150. ) {
  151. return false;
  152. }
  153. return isSubset(actualObj, expectationObj, deepEqual);
  154. }
  155. if (isMap(actualObj) || isMap(expectationObj)) {
  156. if (
  157. !isMap(actualObj) ||
  158. !isMap(expectationObj) ||
  159. actualObj.size !== expectationObj.size
  160. ) {
  161. return false;
  162. }
  163. var mapsDeeplyEqual = true;
  164. mapForEach(actualObj, function (value, key) {
  165. mapsDeeplyEqual =
  166. mapsDeeplyEqual &&
  167. deepEqualCyclic(value, expectationObj.get(key));
  168. });
  169. return mapsDeeplyEqual;
  170. }
  171. return every(expectationKeysAndSymbols, function (key) {
  172. if (!hasOwnProperty(actualObj, key)) {
  173. return false;
  174. }
  175. var actualValue = actualObj[key];
  176. var expectationValue = expectationObj[key];
  177. var actualObject = isObject(actualValue);
  178. var expectationObject = isObject(expectationValue);
  179. // determines, if the objects were already visited
  180. // (it's faster to check for isObject first, than to
  181. // get -1 from getIndex for non objects)
  182. var actualIndex = actualObject
  183. ? indexOf(actualObjects, actualValue)
  184. : -1;
  185. var expectationIndex = expectationObject
  186. ? indexOf(expectationObjects, expectationValue)
  187. : -1;
  188. // determines the new paths of the objects
  189. // - for non cyclic objects the current path will be extended
  190. // by current property name
  191. // - for cyclic objects the stored path is taken
  192. var newActualPath =
  193. actualIndex !== -1
  194. ? actualPaths[actualIndex]
  195. : `${actualPath}[${JSON.stringify(key)}]`;
  196. var newExpectationPath =
  197. expectationIndex !== -1
  198. ? expectationPaths[expectationIndex]
  199. : `${expectationPath}[${JSON.stringify(key)}]`;
  200. var combinedPath = newActualPath + newExpectationPath;
  201. // stop recursion if current objects are already compared
  202. if (compared[combinedPath]) {
  203. return true;
  204. }
  205. // remember the current objects and their paths
  206. if (actualIndex === -1 && actualObject) {
  207. push(actualObjects, actualValue);
  208. push(actualPaths, newActualPath);
  209. }
  210. if (expectationIndex === -1 && expectationObject) {
  211. push(expectationObjects, expectationValue);
  212. push(expectationPaths, newExpectationPath);
  213. }
  214. // remember that the current objects are already compared
  215. if (actualObject && expectationObject) {
  216. compared[combinedPath] = true;
  217. }
  218. // End of cyclic logic
  219. // neither actualValue nor expectationValue is a cycle
  220. // continue with next level
  221. return deepEqual(
  222. actualValue,
  223. expectationValue,
  224. newActualPath,
  225. newExpectationPath
  226. );
  227. });
  228. })(actual, expectation, "$1", "$2");
  229. }
  230. deepEqualCyclic.use = function (match) {
  231. return function deepEqual(a, b) {
  232. return deepEqualCyclic(a, b, match);
  233. };
  234. };
  235. module.exports = deepEqualCyclic;