deepEqual.js 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464
  1. module("equiv");
  2. test("Primitive types and constants", function () {
  3. equal(QUnit.equiv(null, null), true, "null");
  4. equal(QUnit.equiv(null, {}), false, "null");
  5. equal(QUnit.equiv(null, undefined), false, "null");
  6. equal(QUnit.equiv(null, 0), false, "null");
  7. equal(QUnit.equiv(null, false), false, "null");
  8. equal(QUnit.equiv(null, ''), false, "null");
  9. equal(QUnit.equiv(null, []), false, "null");
  10. equal(QUnit.equiv(undefined, undefined), true, "undefined");
  11. equal(QUnit.equiv(undefined, null), false, "undefined");
  12. equal(QUnit.equiv(undefined, 0), false, "undefined");
  13. equal(QUnit.equiv(undefined, false), false, "undefined");
  14. equal(QUnit.equiv(undefined, {}), false, "undefined");
  15. equal(QUnit.equiv(undefined, []), false, "undefined");
  16. equal(QUnit.equiv(undefined, ""), false, "undefined");
  17. // Nan usually doest not equal to Nan using the '==' operator.
  18. // Only isNaN() is able to do it.
  19. equal(QUnit.equiv(0/0, 0/0), true, "NaN"); // NaN VS NaN
  20. equal(QUnit.equiv(1/0, 2/0), true, "Infinity"); // Infinity VS Infinity
  21. equal(QUnit.equiv(-1/0, 2/0), false, "-Infinity, Infinity"); // -Infinity VS Infinity
  22. equal(QUnit.equiv(-1/0, -2/0), true, "-Infinity, -Infinity"); // -Infinity VS -Infinity
  23. equal(QUnit.equiv(0/0, 1/0), false, "NaN, Infinity"); // Nan VS Infinity
  24. equal(QUnit.equiv(1/0, 0/0), false, "NaN, Infinity"); // Nan VS Infinity
  25. equal(QUnit.equiv(0/0, null), false, "NaN");
  26. equal(QUnit.equiv(0/0, undefined), false, "NaN");
  27. equal(QUnit.equiv(0/0, 0), false, "NaN");
  28. equal(QUnit.equiv(0/0, false), false, "NaN");
  29. equal(QUnit.equiv(0/0, function () {}), false, "NaN");
  30. equal(QUnit.equiv(1/0, null), false, "NaN, Infinity");
  31. equal(QUnit.equiv(1/0, undefined), false, "NaN, Infinity");
  32. equal(QUnit.equiv(1/0, 0), false, "NaN, Infinity");
  33. equal(QUnit.equiv(1/0, 1), false, "NaN, Infinity");
  34. equal(QUnit.equiv(1/0, false), false, "NaN, Infinity");
  35. equal(QUnit.equiv(1/0, true), false, "NaN, Infinity");
  36. equal(QUnit.equiv(1/0, function () {}), false, "NaN, Infinity");
  37. equal(QUnit.equiv(0, 0), true, "number");
  38. equal(QUnit.equiv(0, 1), false, "number");
  39. equal(QUnit.equiv(1, 0), false, "number");
  40. equal(QUnit.equiv(1, 1), true, "number");
  41. equal(QUnit.equiv(1.1, 1.1), true, "number");
  42. equal(QUnit.equiv(0.0000005, 0.0000005), true, "number");
  43. equal(QUnit.equiv(0, ''), false, "number");
  44. equal(QUnit.equiv(0, '0'), false, "number");
  45. equal(QUnit.equiv(1, '1'), false, "number");
  46. equal(QUnit.equiv(0, false), false, "number");
  47. equal(QUnit.equiv(1, true), false, "number");
  48. equal(QUnit.equiv(true, true), true, "boolean");
  49. equal(QUnit.equiv(true, false), false, "boolean");
  50. equal(QUnit.equiv(false, true), false, "boolean");
  51. equal(QUnit.equiv(false, 0), false, "boolean");
  52. equal(QUnit.equiv(false, null), false, "boolean");
  53. equal(QUnit.equiv(false, undefined), false, "boolean");
  54. equal(QUnit.equiv(true, 1), false, "boolean");
  55. equal(QUnit.equiv(true, null), false, "boolean");
  56. equal(QUnit.equiv(true, undefined), false, "boolean");
  57. equal(QUnit.equiv('', ''), true, "string");
  58. equal(QUnit.equiv('a', 'a'), true, "string");
  59. equal(QUnit.equiv("foobar", "foobar"), true, "string");
  60. equal(QUnit.equiv("foobar", "foo"), false, "string");
  61. equal(QUnit.equiv('', 0), false, "string");
  62. equal(QUnit.equiv('', false), false, "string");
  63. equal(QUnit.equiv('', null), false, "string");
  64. equal(QUnit.equiv('', undefined), false, "string");
  65. // Rename for lint validation.
  66. // We know this is bad, we are asserting whether we can coop with bad code like this.
  67. var SafeNumber = Number, SafeString = String, SafeBoolean = Boolean, SafeObject = Object;
  68. // primitives vs. objects
  69. equal(QUnit.equiv(0, new SafeNumber()), true, "primitives vs. objects");
  70. equal(QUnit.equiv(new SafeNumber(), 0), true, "primitives vs. objects");
  71. equal(QUnit.equiv(1, new SafeNumber(1)), true, "primitives vs. objects");
  72. equal(QUnit.equiv(new SafeNumber(1), 1), true, "primitives vs. objects");
  73. equal(QUnit.equiv(new SafeNumber(0), 1), false, "primitives vs. objects");
  74. equal(QUnit.equiv(0, new SafeNumber(1)), false, "primitives vs. objects");
  75. equal(QUnit.equiv(new SafeString(), ""), true, "primitives vs. objects");
  76. equal(QUnit.equiv("", new SafeString()), true, "primitives vs. objects");
  77. equal(QUnit.equiv(new SafeString("My String"), "My String"), true, "primitives vs. objects");
  78. equal(QUnit.equiv("My String", new SafeString("My String")), true, "primitives vs. objects");
  79. equal(QUnit.equiv("Bad String", new SafeString("My String")), false, "primitives vs. objects");
  80. equal(QUnit.equiv(new SafeString("Bad String"), "My String"), false, "primitives vs. objects");
  81. equal(QUnit.equiv(false, new SafeBoolean()), true, "primitives vs. objects");
  82. equal(QUnit.equiv(new SafeBoolean(), false), true, "primitives vs. objects");
  83. equal(QUnit.equiv(true, new SafeBoolean(true)), true, "primitives vs. objects");
  84. equal(QUnit.equiv(new SafeBoolean(true), true), true, "primitives vs. objects");
  85. equal(QUnit.equiv(true, new SafeBoolean(1)), true, "primitives vs. objects");
  86. equal(QUnit.equiv(false, new SafeBoolean(false)), true, "primitives vs. objects");
  87. equal(QUnit.equiv(new SafeBoolean(false), false), true, "primitives vs. objects");
  88. equal(QUnit.equiv(false, new SafeBoolean(0)), true, "primitives vs. objects");
  89. equal(QUnit.equiv(true, new SafeBoolean(false)), false, "primitives vs. objects");
  90. equal(QUnit.equiv(new SafeBoolean(false), true), false, "primitives vs. objects");
  91. equal(QUnit.equiv(new SafeObject(), {}), true, "object literal vs. instantiation");
  92. equal(QUnit.equiv({}, new SafeObject()), true, "object literal vs. instantiation");
  93. equal(QUnit.equiv(new SafeObject(), {a:1}), false, "object literal vs. instantiation");
  94. equal(QUnit.equiv({a:1}, new SafeObject()), false, "object literal vs. instantiation");
  95. equal(QUnit.equiv({a:undefined}, new SafeObject()), false, "object literal vs. instantiation");
  96. equal(QUnit.equiv(new SafeObject(), {a:undefined}), false, "object literal vs. instantiation");
  97. });
  98. test("Objects Basics.", function() {
  99. equal(QUnit.equiv({}, {}), true);
  100. equal(QUnit.equiv({}, null), false);
  101. equal(QUnit.equiv({}, undefined), false);
  102. equal(QUnit.equiv({}, 0), false);
  103. equal(QUnit.equiv({}, false), false);
  104. // This test is a hard one, it is very important
  105. // REASONS:
  106. // 1) They are of the same type "object"
  107. // 2) [] instanceof Object is true
  108. // 3) Their properties are the same (doesn't exists)
  109. equal(QUnit.equiv({}, []), false);
  110. equal(QUnit.equiv({a:1}, {a:1}), true);
  111. equal(QUnit.equiv({a:1}, {a:"1"}), false);
  112. equal(QUnit.equiv({a:[]}, {a:[]}), true);
  113. equal(QUnit.equiv({a:{}}, {a:null}), false);
  114. equal(QUnit.equiv({a:1}, {}), false);
  115. equal(QUnit.equiv({}, {a:1}), false);
  116. // Hard ones
  117. equal(QUnit.equiv({a:undefined}, {}), false);
  118. equal(QUnit.equiv({}, {a:undefined}), false);
  119. equal(QUnit.equiv(
  120. {
  121. a: [{ bar: undefined }]
  122. },
  123. {
  124. a: [{ bat: undefined }]
  125. }
  126. ), false);
  127. // Objects with no prototype, created via Object.create(null), are used e.g. as dictionaries.
  128. // Being able to test equivalence against object literals is quite useful.
  129. if (typeof Object.create === 'function') {
  130. equal(QUnit.equiv(Object.create(null), {}), true, "empty object without prototype VS empty object");
  131. var nonEmptyWithNoProto = Object.create(null);
  132. nonEmptyWithNoProto.foo = "bar";
  133. equal(QUnit.equiv(nonEmptyWithNoProto, { foo: "bar" }), true, "object without prototype VS object");
  134. }
  135. });
  136. test("Arrays Basics.", function() {
  137. equal(QUnit.equiv([], []), true);
  138. // May be a hard one, can invoke a crash at execution.
  139. // because their types are both "object" but null isn't
  140. // like a true object, it doesn't have any property at all.
  141. equal(QUnit.equiv([], null), false);
  142. equal(QUnit.equiv([], undefined), false);
  143. equal(QUnit.equiv([], false), false);
  144. equal(QUnit.equiv([], 0), false);
  145. equal(QUnit.equiv([], ""), false);
  146. // May be a hard one, but less hard
  147. // than {} with [] (note the order)
  148. equal(QUnit.equiv([], {}), false);
  149. equal(QUnit.equiv([null],[]), false);
  150. equal(QUnit.equiv([undefined],[]), false);
  151. equal(QUnit.equiv([],[null]), false);
  152. equal(QUnit.equiv([],[undefined]), false);
  153. equal(QUnit.equiv([null],[undefined]), false);
  154. equal(QUnit.equiv([[]],[[]]), true);
  155. equal(QUnit.equiv([[],[],[]],[[],[],[]]), true);
  156. equal(QUnit.equiv(
  157. [[],[],[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]],
  158. [[],[],[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]),
  159. true);
  160. equal(QUnit.equiv(
  161. [[],[],[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]],
  162. [[],[],[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]), // shorter
  163. false);
  164. equal(QUnit.equiv(
  165. [[],[],[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[{}]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]],
  166. [[],[],[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]), // deepest element not an array
  167. false);
  168. // same multidimensional
  169. equal(QUnit.equiv(
  170. [1,2,3,4,5,6,7,8,9, [
  171. 1,2,3,4,5,6,7,8,9, [
  172. 1,2,3,4,5,[
  173. [6,7,8,9, [
  174. [
  175. 1,2,3,4,[
  176. 2,3,4,[
  177. 1,2,[
  178. 1,2,3,4,[
  179. 1,2,3,4,5,6,7,8,9,[
  180. 0
  181. ],1,2,3,4,5,6,7,8,9
  182. ],5,6,7,8,9
  183. ],4,5,6,7,8,9
  184. ],5,6,7,8,9
  185. ],5,6,7
  186. ]
  187. ]
  188. ]
  189. ]
  190. ]]],
  191. [1,2,3,4,5,6,7,8,9, [
  192. 1,2,3,4,5,6,7,8,9, [
  193. 1,2,3,4,5,[
  194. [6,7,8,9, [
  195. [
  196. 1,2,3,4,[
  197. 2,3,4,[
  198. 1,2,[
  199. 1,2,3,4,[
  200. 1,2,3,4,5,6,7,8,9,[
  201. 0
  202. ],1,2,3,4,5,6,7,8,9
  203. ],5,6,7,8,9
  204. ],4,5,6,7,8,9
  205. ],5,6,7,8,9
  206. ],5,6,7
  207. ]
  208. ]
  209. ]
  210. ]
  211. ]]]),
  212. true, "Multidimensional");
  213. // different multidimensional
  214. equal(QUnit.equiv(
  215. [1,2,3,4,5,6,7,8,9, [
  216. 1,2,3,4,5,6,7,8,9, [
  217. 1,2,3,4,5,[
  218. [6,7,8,9, [
  219. [
  220. 1,2,3,4,[
  221. 2,3,4,[
  222. 1,2,[
  223. 1,2,3,4,[
  224. 1,2,3,4,5,6,7,8,9,[
  225. 0
  226. ],1,2,3,4,5,6,7,8,9
  227. ],5,6,7,8,9
  228. ],4,5,6,7,8,9
  229. ],5,6,7,8,9
  230. ],5,6,7
  231. ]
  232. ]
  233. ]
  234. ]
  235. ]]],
  236. [1,2,3,4,5,6,7,8,9, [
  237. 1,2,3,4,5,6,7,8,9, [
  238. 1,2,3,4,5,[
  239. [6,7,8,9, [
  240. [
  241. 1,2,3,4,[
  242. 2,3,4,[
  243. 1,2,[
  244. '1',2,3,4,[ // string instead of number
  245. 1,2,3,4,5,6,7,8,9,[
  246. 0
  247. ],1,2,3,4,5,6,7,8,9
  248. ],5,6,7,8,9
  249. ],4,5,6,7,8,9
  250. ],5,6,7,8,9
  251. ],5,6,7
  252. ]
  253. ]
  254. ]
  255. ]
  256. ]]]),
  257. false, "Multidimensional");
  258. // different multidimensional
  259. equal(QUnit.equiv(
  260. [1,2,3,4,5,6,7,8,9, [
  261. 1,2,3,4,5,6,7,8,9, [
  262. 1,2,3,4,5,[
  263. [6,7,8,9, [
  264. [
  265. 1,2,3,4,[
  266. 2,3,4,[
  267. 1,2,[
  268. 1,2,3,4,[
  269. 1,2,3,4,5,6,7,8,9,[
  270. 0
  271. ],1,2,3,4,5,6,7,8,9
  272. ],5,6,7,8,9
  273. ],4,5,6,7,8,9
  274. ],5,6,7,8,9
  275. ],5,6,7
  276. ]
  277. ]
  278. ]
  279. ]
  280. ]]],
  281. [1,2,3,4,5,6,7,8,9, [
  282. 1,2,3,4,5,6,7,8,9, [
  283. 1,2,3,4,5,[
  284. [6,7,8,9, [
  285. [
  286. 1,2,3,4,[
  287. 2,3,[ // missing an element (4)
  288. 1,2,[
  289. 1,2,3,4,[
  290. 1,2,3,4,5,6,7,8,9,[
  291. 0
  292. ],1,2,3,4,5,6,7,8,9
  293. ],5,6,7,8,9
  294. ],4,5,6,7,8,9
  295. ],5,6,7,8,9
  296. ],5,6,7
  297. ]
  298. ]
  299. ]
  300. ]
  301. ]]]),
  302. false, "Multidimensional");
  303. });
  304. test("Functions.", function() {
  305. var f0 = function () {};
  306. var f1 = function () {};
  307. // f2 and f3 have the same code, formatted differently
  308. var f2 = function () {var i = 0;};
  309. var f3 = function () {
  310. /*jshint asi:true */
  311. var i = 0 // this comment and no semicoma as difference
  312. };
  313. equal(QUnit.equiv(function() {}, function() {}), false, "Anonymous functions"); // exact source code
  314. equal(QUnit.equiv(function() {}, function() {return true;}), false, "Anonymous functions");
  315. equal(QUnit.equiv(f0, f0), true, "Function references"); // same references
  316. equal(QUnit.equiv(f0, f1), false, "Function references"); // exact source code, different references
  317. equal(QUnit.equiv(f2, f3), false, "Function references"); // equivalent source code, different references
  318. equal(QUnit.equiv(f1, f2), false, "Function references"); // different source code, different references
  319. equal(QUnit.equiv(function() {}, true), false);
  320. equal(QUnit.equiv(function() {}, undefined), false);
  321. equal(QUnit.equiv(function() {}, null), false);
  322. equal(QUnit.equiv(function() {}, {}), false);
  323. });
  324. test("Date instances.", function() {
  325. // Date, we don't need to test Date.parse() because it returns a number.
  326. // Only test the Date instances by setting them a fix date.
  327. // The date use is midnight January 1, 1970
  328. var d1 = new Date();
  329. d1.setTime(0); // fix the date
  330. var d2 = new Date();
  331. d2.setTime(0); // fix the date
  332. var d3 = new Date(); // The very now
  333. // Anyway their types differs, just in case the code fails in the order in which it deals with date
  334. equal(QUnit.equiv(d1, 0), false); // d1.valueOf() returns 0, but d1 and 0 are different
  335. // test same values date and different instances equality
  336. equal(QUnit.equiv(d1, d2), true);
  337. // test different date and different instances difference
  338. equal(QUnit.equiv(d1, d3), false);
  339. });
  340. test("RegExp.", function() {
  341. // Must test cases that imply those traps:
  342. // var a = /./;
  343. // a instanceof Object; // Oops
  344. // a instanceof RegExp; // Oops
  345. // typeof a === "function"; // Oops, false in IE and Opera, true in FF and Safari ("object")
  346. // Tests same regex with same modifiers in different order
  347. var r = /foo/;
  348. var r5 = /foo/gim;
  349. var r6 = /foo/gmi;
  350. var r7 = /foo/igm;
  351. var r8 = /foo/img;
  352. var r9 = /foo/mig;
  353. var r10 = /foo/mgi;
  354. var ri1 = /foo/i;
  355. var ri2 = /foo/i;
  356. var rm1 = /foo/m;
  357. var rm2 = /foo/m;
  358. var rg1 = /foo/g;
  359. var rg2 = /foo/g;
  360. equal(QUnit.equiv(r5, r6), true, "Modifier order");
  361. equal(QUnit.equiv(r5, r7), true, "Modifier order");
  362. equal(QUnit.equiv(r5, r8), true, "Modifier order");
  363. equal(QUnit.equiv(r5, r9), true, "Modifier order");
  364. equal(QUnit.equiv(r5, r10), true, "Modifier order");
  365. equal(QUnit.equiv(r, r5), false, "Modifier");
  366. equal(QUnit.equiv(ri1, ri2), true, "Modifier");
  367. equal(QUnit.equiv(r, ri1), false, "Modifier");
  368. equal(QUnit.equiv(ri1, rm1), false, "Modifier");
  369. equal(QUnit.equiv(r, rm1), false, "Modifier");
  370. equal(QUnit.equiv(rm1, ri1), false, "Modifier");
  371. equal(QUnit.equiv(rm1, rm2), true, "Modifier");
  372. equal(QUnit.equiv(rg1, rm1), false, "Modifier");
  373. equal(QUnit.equiv(rm1, rg1), false, "Modifier");
  374. equal(QUnit.equiv(rg1, rg2), true, "Modifier");
  375. // Different regex, same modifiers
  376. var r11 = /[a-z]/gi;
  377. var r13 = /[0-9]/gi; // oops! different
  378. equal(QUnit.equiv(r11, r13), false, "Regex pattern");
  379. var r14 = /0/ig;
  380. var r15 = /"0"/ig; // oops! different
  381. equal(QUnit.equiv(r14, r15), false, "Regex pattern");
  382. var r1 = /[\n\r\u2028\u2029]/g;
  383. var r2 = /[\n\r\u2028\u2029]/g;
  384. var r3 = /[\n\r\u2028\u2028]/g; // differs from r1
  385. var r4 = /[\n\r\u2028\u2029]/; // differs from r1
  386. equal(QUnit.equiv(r1, r2), true, "Regex pattern");
  387. equal(QUnit.equiv(r1, r3), false, "Regex pattern");
  388. equal(QUnit.equiv(r1, r4), false, "Regex pattern");
  389. // More complex regex
  390. var regex1 = "^[-_.a-z0-9]+@([-_a-z0-9]+\\.)+([A-Za-z][A-Za-z]|[A-Za-z][A-Za-z][A-Za-z])|(([0-9][0-9]?|[0-1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5]))$";
  391. var regex2 = "^[-_.a-z0-9]+@([-_a-z0-9]+\\.)+([A-Za-z][A-Za-z]|[A-Za-z][A-Za-z][A-Za-z])|(([0-9][0-9]?|[0-1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5]))$";
  392. // regex 3 is different: '.' not escaped
  393. var regex3 = "^[-_.a-z0-9]+@([-_a-z0-9]+.)+([A-Za-z][A-Za-z]|[A-Za-z][A-Za-z][A-Za-z])|(([0-9][0-9]?|[0-1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5]))$";
  394. var r21 = new RegExp(regex1);
  395. var r22 = new RegExp(regex2);
  396. var r23 = new RegExp(regex3); // diff from r21, not same pattern
  397. var r23a = new RegExp(regex3, "gi"); // diff from r23, not same modifier
  398. var r24a = new RegExp(regex3, "ig"); // same as r23a
  399. equal(QUnit.equiv(r21, r22), true, "Complex Regex");
  400. equal(QUnit.equiv(r21, r23), false, "Complex Regex");
  401. equal(QUnit.equiv(r23, r23a), false, "Complex Regex");
  402. equal(QUnit.equiv(r23a, r24a), true, "Complex Regex");
  403. // typeof r1 is "function" in some browsers and "object" in others so we must cover this test
  404. var re = / /;
  405. equal(QUnit.equiv(re, function () {}), false, "Regex internal");
  406. equal(QUnit.equiv(re, {}), false, "Regex internal");
  407. });
  408. test("Complex Objects.", function() {
  409. function fn1() {
  410. return "fn1";
  411. }
  412. function fn2() {
  413. return "fn2";
  414. }
  415. // Try to invert the order of some properties to make sure it is covered.
  416. // It can failed when properties are compared between unsorted arrays.
  417. equal(QUnit.equiv(
  418. {
  419. a: 1,
  420. b: null,
  421. c: [{}],
  422. d: {
  423. a: 3.14159,
  424. b: false,
  425. c: {
  426. e: fn1,
  427. f: [[[]]],
  428. g: {
  429. j: {
  430. k: {
  431. n: {
  432. r: "r",
  433. s: [1,2,3],
  434. t: undefined,
  435. u: 0,
  436. v: {
  437. w: {
  438. x: {
  439. y: "Yahoo!",
  440. z: null
  441. }
  442. }
  443. }
  444. },
  445. q: [],
  446. p: 1/0,
  447. o: 99
  448. },
  449. l: undefined,
  450. m: null
  451. }
  452. },
  453. d: 0,
  454. i: true,
  455. h: "false"
  456. }
  457. },
  458. e: undefined,
  459. g: "",
  460. h: "h",
  461. f: {},
  462. i: []
  463. },
  464. {
  465. a: 1,
  466. b: null,
  467. c: [{}],
  468. d: {
  469. b: false,
  470. a: 3.14159,
  471. c: {
  472. d: 0,
  473. e: fn1,
  474. f: [[[]]],
  475. g: {
  476. j: {
  477. k: {
  478. n: {
  479. r: "r",
  480. t: undefined,
  481. u: 0,
  482. s: [1,2,3],
  483. v: {
  484. w: {
  485. x: {
  486. z: null,
  487. y: "Yahoo!"
  488. }
  489. }
  490. }
  491. },
  492. o: 99,
  493. p: 1/0,
  494. q: []
  495. },
  496. l: undefined,
  497. m: null
  498. }
  499. },
  500. i: true,
  501. h: "false"
  502. }
  503. },
  504. e: undefined,
  505. g: "",
  506. f: {},
  507. h: "h",
  508. i: []
  509. }
  510. ), true);
  511. equal(QUnit.equiv(
  512. {
  513. a: 1,
  514. b: null,
  515. c: [{}],
  516. d: {
  517. a: 3.14159,
  518. b: false,
  519. c: {
  520. d: 0,
  521. e: fn1,
  522. f: [[[]]],
  523. g: {
  524. j: {
  525. k: {
  526. n: {
  527. //r: "r", // different: missing a property
  528. s: [1,2,3],
  529. t: undefined,
  530. u: 0,
  531. v: {
  532. w: {
  533. x: {
  534. y: "Yahoo!",
  535. z: null
  536. }
  537. }
  538. }
  539. },
  540. o: 99,
  541. p: 1/0,
  542. q: []
  543. },
  544. l: undefined,
  545. m: null
  546. }
  547. },
  548. h: "false",
  549. i: true
  550. }
  551. },
  552. e: undefined,
  553. f: {},
  554. g: "",
  555. h: "h",
  556. i: []
  557. },
  558. {
  559. a: 1,
  560. b: null,
  561. c: [{}],
  562. d: {
  563. a: 3.14159,
  564. b: false,
  565. c: {
  566. d: 0,
  567. e: fn1,
  568. f: [[[]]],
  569. g: {
  570. j: {
  571. k: {
  572. n: {
  573. r: "r",
  574. s: [1,2,3],
  575. t: undefined,
  576. u: 0,
  577. v: {
  578. w: {
  579. x: {
  580. y: "Yahoo!",
  581. z: null
  582. }
  583. }
  584. }
  585. },
  586. o: 99,
  587. p: 1/0,
  588. q: []
  589. },
  590. l: undefined,
  591. m: null
  592. }
  593. },
  594. h: "false",
  595. i: true
  596. }
  597. },
  598. e: undefined,
  599. f: {},
  600. g: "",
  601. h: "h",
  602. i: []
  603. }
  604. ), false);
  605. equal(QUnit.equiv(
  606. {
  607. a: 1,
  608. b: null,
  609. c: [{}],
  610. d: {
  611. a: 3.14159,
  612. b: false,
  613. c: {
  614. d: 0,
  615. e: fn1,
  616. f: [[[]]],
  617. g: {
  618. j: {
  619. k: {
  620. n: {
  621. r: "r",
  622. s: [1,2,3],
  623. t: undefined,
  624. u: 0,
  625. v: {
  626. w: {
  627. x: {
  628. y: "Yahoo!",
  629. z: null
  630. }
  631. }
  632. }
  633. },
  634. o: 99,
  635. p: 1/0,
  636. q: []
  637. },
  638. l: undefined,
  639. m: null
  640. }
  641. },
  642. h: "false",
  643. i: true
  644. }
  645. },
  646. e: undefined,
  647. f: {},
  648. g: "",
  649. h: "h",
  650. i: []
  651. },
  652. {
  653. a: 1,
  654. b: null,
  655. c: [{}],
  656. d: {
  657. a: 3.14159,
  658. b: false,
  659. c: {
  660. d: 0,
  661. e: fn1,
  662. f: [[[]]],
  663. g: {
  664. j: {
  665. k: {
  666. n: {
  667. r: "r",
  668. s: [1,2,3],
  669. //t: undefined, // different: missing a property with an undefined value
  670. u: 0,
  671. v: {
  672. w: {
  673. x: {
  674. y: "Yahoo!",
  675. z: null
  676. }
  677. }
  678. }
  679. },
  680. o: 99,
  681. p: 1/0,
  682. q: []
  683. },
  684. l: undefined,
  685. m: null
  686. }
  687. },
  688. h: "false",
  689. i: true
  690. }
  691. },
  692. e: undefined,
  693. f: {},
  694. g: "",
  695. h: "h",
  696. i: []
  697. }
  698. ), false);
  699. equal(QUnit.equiv(
  700. {
  701. a: 1,
  702. b: null,
  703. c: [{}],
  704. d: {
  705. a: 3.14159,
  706. b: false,
  707. c: {
  708. d: 0,
  709. e: fn1,
  710. f: [[[]]],
  711. g: {
  712. j: {
  713. k: {
  714. n: {
  715. r: "r",
  716. s: [1,2,3],
  717. t: undefined,
  718. u: 0,
  719. v: {
  720. w: {
  721. x: {
  722. y: "Yahoo!",
  723. z: null
  724. }
  725. }
  726. }
  727. },
  728. o: 99,
  729. p: 1/0,
  730. q: []
  731. },
  732. l: undefined,
  733. m: null
  734. }
  735. },
  736. h: "false",
  737. i: true
  738. }
  739. },
  740. e: undefined,
  741. f: {},
  742. g: "",
  743. h: "h",
  744. i: []
  745. },
  746. {
  747. a: 1,
  748. b: null,
  749. c: [{}],
  750. d: {
  751. a: 3.14159,
  752. b: false,
  753. c: {
  754. d: 0,
  755. e: fn1,
  756. f: [[[]]],
  757. g: {
  758. j: {
  759. k: {
  760. n: {
  761. r: "r",
  762. s: [1,2,3],
  763. t: undefined,
  764. u: 0,
  765. v: {
  766. w: {
  767. x: {
  768. y: "Yahoo!",
  769. z: null
  770. }
  771. }
  772. }
  773. },
  774. o: 99,
  775. p: 1/0,
  776. q: {} // different was []
  777. },
  778. l: undefined,
  779. m: null
  780. }
  781. },
  782. h: "false",
  783. i: true
  784. }
  785. },
  786. e: undefined,
  787. f: {},
  788. g: "",
  789. h: "h",
  790. i: []
  791. }
  792. ), false);
  793. var same1 = {
  794. a: [
  795. "string", null, 0, "1", 1, {
  796. prop: null,
  797. foo: [1,2,null,{}, [], [1,2,3]],
  798. bar: undefined
  799. }, 3, "Hey!", "Κάνε πάντα γνωÏίζουμε ας των, μηχανής επιδιόÏθωσης επιδιοÏθώσεις ÏŽÏ‚ μια. Κλπ ας"
  800. ],
  801. unicode: "è€ æ±‰è¯ä¸å˜åœ¨ 港澳和海外的åŽäººåœˆä¸ 贵州 我去了书店 现在尚有争",
  802. b: "b",
  803. c: fn1
  804. };
  805. var same2 = {
  806. a: [
  807. "string", null, 0, "1", 1, {
  808. prop: null,
  809. foo: [1,2,null,{}, [], [1,2,3]],
  810. bar: undefined
  811. }, 3, "Hey!", "Κάνε πάντα γνωÏίζουμε ας των, μηχανής επιδιόÏθωσης επιδιοÏθώσεις ÏŽÏ‚ μια. Κλπ ας"
  812. ],
  813. unicode: "è€ æ±‰è¯ä¸å˜åœ¨ 港澳和海外的åŽäººåœˆä¸ 贵州 我去了书店 现在尚有争",
  814. b: "b",
  815. c: fn1
  816. };
  817. var diff1 = {
  818. a: [
  819. "string", null, 0, "1", 1, {
  820. prop: null,
  821. foo: [1,2,null,{}, [], [1,2,3,4]], // different: 4 was add to the array
  822. bar: undefined
  823. }, 3, "Hey!", "Κάνε πάντα γνωÏίζουμε ας των, μηχανής επιδιόÏθωσης επιδιοÏθώσεις ÏŽÏ‚ μια. Κλπ ας"
  824. ],
  825. unicode: "è€ æ±‰è¯ä¸å˜åœ¨ 港澳和海外的åŽäººåœˆä¸ 贵州 我去了书店 现在尚有争",
  826. b: "b",
  827. c: fn1
  828. };
  829. var diff2 = {
  830. a: [
  831. "string", null, 0, "1", 1, {
  832. prop: null,
  833. foo: [1,2,null,{}, [], [1,2,3]],
  834. newprop: undefined, // different: newprop was added
  835. bar: undefined
  836. }, 3, "Hey!", "Κάνε πάντα γνωÏίζουμε ας των, μηχανής επιδιόÏθωσης επιδιοÏθώσεις ÏŽÏ‚ μια. Κλπ ας"
  837. ],
  838. unicode: "è€ æ±‰è¯ä¸å˜åœ¨ 港澳和海外的åŽäººåœˆä¸ 贵州 我去了书店 现在尚有争",
  839. b: "b",
  840. c: fn1
  841. };
  842. var diff3 = {
  843. a: [
  844. "string", null, 0, "1", 1, {
  845. prop: null,
  846. foo: [1,2,null,{}, [], [1,2,3]],
  847. bar: undefined
  848. }, 3, "Hey!", "Κάνε πάντα γνωÏίζουμε ας των, μηχανής επιδιόÏθωσης επιδιοÏθώσεις ÏŽÏ‚ μια. Κλπ α" // different: missing last char
  849. ],
  850. unicode: "è€ æ±‰è¯ä¸å˜åœ¨ 港澳和海外的åŽäººåœˆä¸ 贵州 我去了书店 现在尚有争",
  851. b: "b",
  852. c: fn1
  853. };
  854. var diff4 = {
  855. a: [
  856. "string", null, 0, "1", 1, {
  857. prop: null,
  858. foo: [1,2,undefined,{}, [], [1,2,3]], // different: undefined instead of null
  859. bar: undefined
  860. }, 3, "Hey!", "Κάνε πάντα γνωÏίζουμε ας των, μηχανής επιδιόÏθωσης επιδιοÏθώσεις ÏŽÏ‚ μια. Κλπ ας"
  861. ],
  862. unicode: "è€ æ±‰è¯ä¸å˜åœ¨ 港澳和海外的åŽäººåœˆä¸ 贵州 我去了书店 现在尚有争",
  863. b: "b",
  864. c: fn1
  865. };
  866. var diff5 = {
  867. a: [
  868. "string", null, 0, "1", 1, {
  869. prop: null,
  870. foo: [1,2,null,{}, [], [1,2,3]],
  871. bat: undefined // different: property name not "bar"
  872. }, 3, "Hey!", "Κάνε πάντα γνωÏίζουμε ας των, μηχανής επιδιόÏθωσης επιδιοÏθώσεις ÏŽÏ‚ μια. Κλπ ας"
  873. ],
  874. unicode: "è€ æ±‰è¯ä¸å˜åœ¨ 港澳和海外的åŽäººåœˆä¸ 贵州 我去了书店 现在尚有争",
  875. b: "b",
  876. c: fn1
  877. };
  878. equal(QUnit.equiv(same1, same2), true);
  879. equal(QUnit.equiv(same2, same1), true);
  880. equal(QUnit.equiv(same2, diff1), false);
  881. equal(QUnit.equiv(diff1, same2), false);
  882. equal(QUnit.equiv(same1, diff1), false);
  883. equal(QUnit.equiv(same1, diff2), false);
  884. equal(QUnit.equiv(same1, diff3), false);
  885. equal(QUnit.equiv(same1, diff3), false);
  886. equal(QUnit.equiv(same1, diff4), false);
  887. equal(QUnit.equiv(same1, diff5), false);
  888. equal(QUnit.equiv(diff5, diff1), false);
  889. });
  890. test("Complex Arrays.", function() {
  891. function fn() {
  892. }
  893. equal(QUnit.equiv(
  894. [1, 2, 3, true, {}, null, [
  895. {
  896. a: ["", '1', 0]
  897. },
  898. 5, 6, 7
  899. ], "foo"],
  900. [1, 2, 3, true, {}, null, [
  901. {
  902. a: ["", '1', 0]
  903. },
  904. 5, 6, 7
  905. ], "foo"]),
  906. true);
  907. equal(QUnit.equiv(
  908. [1, 2, 3, true, {}, null, [
  909. {
  910. a: ["", '1', 0]
  911. },
  912. 5, 6, 7
  913. ], "foo"],
  914. [1, 2, 3, true, {}, null, [
  915. {
  916. b: ["", '1', 0] // not same property name
  917. },
  918. 5, 6, 7
  919. ], "foo"]),
  920. false);
  921. var a = [{
  922. b: fn,
  923. c: false,
  924. "do": "reserved word",
  925. "for": {
  926. ar: [3,5,9,"hey!", [], {
  927. ar: [1,[
  928. 3,4,6,9, null, [], []
  929. ]],
  930. e: fn,
  931. f: undefined
  932. }]
  933. },
  934. e: 0.43445
  935. }, 5, "string", 0, fn, false, null, undefined, 0, [
  936. 4,5,6,7,8,9,11,22,33,44,55,"66", null, [], [[[[[3]]]], "3"], {}, 1/0
  937. ], [], [[[], "foo", null, {
  938. n: 1/0,
  939. z: {
  940. a: [3,4,5,6,"yep!", undefined, undefined],
  941. b: {}
  942. }
  943. }, {}]]];
  944. equal(QUnit.equiv(a,
  945. [{
  946. b: fn,
  947. c: false,
  948. "do": "reserved word",
  949. "for": {
  950. ar: [3,5,9,"hey!", [], {
  951. ar: [1,[
  952. 3,4,6,9, null, [], []
  953. ]],
  954. e: fn,
  955. f: undefined
  956. }]
  957. },
  958. e: 0.43445
  959. }, 5, "string", 0, fn, false, null, undefined, 0, [
  960. 4,5,6,7,8,9,11,22,33,44,55,"66", null, [], [[[[[3]]]], "3"], {}, 1/0
  961. ], [], [[[], "foo", null, {
  962. n: 1/0,
  963. z: {
  964. a: [3,4,5,6,"yep!", undefined, undefined],
  965. b: {}
  966. }
  967. }, {}]]]), true);
  968. equal(QUnit.equiv(a,
  969. [{
  970. b: fn,
  971. c: false,
  972. "do": "reserved word",
  973. "for": {
  974. ar: [3,5,9,"hey!", [], {
  975. ar: [1,[
  976. 3,4,6,9, null, [], []
  977. ]],
  978. e: fn,
  979. f: undefined
  980. }]
  981. },
  982. e: 0.43445
  983. }, 5, "string", 0, fn, false, null, undefined, 0, [
  984. 4,5,6,7,8,9,11,22,33,44,55,"66", null, [], [[[[[2]]]], "3"], {}, 1/0 // different: [[[[[2]]]]] instead of [[[[[3]]]]]
  985. ], [], [[[], "foo", null, {
  986. n: 1/0,
  987. z: {
  988. a: [3,4,5,6,"yep!", undefined, undefined],
  989. b: {}
  990. }
  991. }, {}]]]), false);
  992. equal(QUnit.equiv(a,
  993. [{
  994. b: fn,
  995. c: false,
  996. "do": "reserved word",
  997. "for": {
  998. ar: [3,5,9,"hey!", [], {
  999. ar: [1,[
  1000. 3,4,6,9, null, [], []
  1001. ]],
  1002. e: fn,
  1003. f: undefined
  1004. }]
  1005. },
  1006. e: 0.43445
  1007. }, 5, "string", 0, fn, false, null, undefined, 0, [
  1008. 4,5,6,7,8,9,11,22,33,44,55,"66", null, [], [[[[[3]]]], "3"], {}, 1/0
  1009. ], [], [[[], "foo", null, {
  1010. n: -1/0, // different, -Infinity instead of Infinity
  1011. z: {
  1012. a: [3,4,5,6,"yep!", undefined, undefined],
  1013. b: {}
  1014. }
  1015. }, {}]]]), false);
  1016. equal(QUnit.equiv(a,
  1017. [{
  1018. b: fn,
  1019. c: false,
  1020. "do": "reserved word",
  1021. "for": {
  1022. ar: [3,5,9,"hey!", [], {
  1023. ar: [1,[
  1024. 3,4,6,9, null, [], []
  1025. ]],
  1026. e: fn,
  1027. f: undefined
  1028. }]
  1029. },
  1030. e: 0.43445
  1031. }, 5, "string", 0, fn, false, null, undefined, 0, [
  1032. 4,5,6,7,8,9,11,22,33,44,55,"66", null, [], [[[[[3]]]], "3"], {}, 1/0
  1033. ], [], [[[], "foo", { // different: null is missing
  1034. n: 1/0,
  1035. z: {
  1036. a: [3,4,5,6,"yep!", undefined, undefined],
  1037. b: {}
  1038. }
  1039. }, {}]]]), false);
  1040. equal(QUnit.equiv(a,
  1041. [{
  1042. b: fn,
  1043. c: false,
  1044. "do": "reserved word",
  1045. "for": {
  1046. ar: [3,5,9,"hey!", [], {
  1047. ar: [1,[
  1048. 3,4,6,9, null, [], []
  1049. ]],
  1050. e: fn
  1051. // different: missing property f: undefined
  1052. }]
  1053. },
  1054. e: 0.43445
  1055. }, 5, "string", 0, fn, false, null, undefined, 0, [
  1056. 4,5,6,7,8,9,11,22,33,44,55,"66", null, [], [[[[[3]]]], "3"], {}, 1/0
  1057. ], [], [[[], "foo", null, {
  1058. n: 1/0,
  1059. z: {
  1060. a: [3,4,5,6,"yep!", undefined, undefined],
  1061. b: {}
  1062. }
  1063. }, {}]]]), false);
  1064. });
  1065. test("Prototypal inheritance", function() {
  1066. function Gizmo(id) {
  1067. this.id = id;
  1068. }
  1069. function Hoozit(id) {
  1070. this.id = id;
  1071. }
  1072. Hoozit.prototype = new Gizmo();
  1073. var gizmo = new Gizmo("ok");
  1074. var hoozit = new Hoozit("ok");
  1075. // Try this test many times after test on instances that hold function
  1076. // to make sure that our code does not mess with last object constructor memoization.
  1077. equal(QUnit.equiv(function () {}, function () {}), false);
  1078. // Hoozit inherit from Gizmo
  1079. // hoozit instanceof Hoozit; // true
  1080. // hoozit instanceof Gizmo; // true
  1081. equal(QUnit.equiv(hoozit, gizmo), true);
  1082. Gizmo.prototype.bar = true; // not a function just in case we skip them
  1083. // Hoozit inherit from Gizmo
  1084. // They are equivalent
  1085. equal(QUnit.equiv(hoozit, gizmo), true);
  1086. // Make sure this is still true !important
  1087. // The reason for this is that I forgot to reset the last
  1088. // caller to where it were called from.
  1089. equal(QUnit.equiv(function () {}, function () {}), false);
  1090. // Make sure this is still true !important
  1091. equal(QUnit.equiv(hoozit, gizmo), true);
  1092. Hoozit.prototype.foo = true; // not a function just in case we skip them
  1093. // Gizmo does not inherit from Hoozit
  1094. // gizmo instanceof Gizmo; // true
  1095. // gizmo instanceof Hoozit; // false
  1096. // They are not equivalent
  1097. equal(QUnit.equiv(hoozit, gizmo), false);
  1098. // Make sure this is still true !important
  1099. equal(QUnit.equiv(function () {}, function () {}), false);
  1100. });
  1101. test("Instances", function() {
  1102. function A() {}
  1103. var a1 = new A();
  1104. var a2 = new A();
  1105. function B() {
  1106. this.fn = function () {};
  1107. }
  1108. var b1 = new B();
  1109. var b2 = new B();
  1110. equal(QUnit.equiv(a1, a2), true, "Same property, same constructor");
  1111. // b1.fn and b2.fn are functions but they are different references
  1112. // But we decided to skip function for instances.
  1113. equal(QUnit.equiv(b1, b2), true, "Same property, same constructor");
  1114. equal(QUnit.equiv(a1, b1), false, "Same properties but different constructor"); // failed
  1115. function Car(year) {
  1116. var privateVar = 0;
  1117. this.year = year;
  1118. this.isOld = function() {
  1119. return year > 10;
  1120. };
  1121. }
  1122. function Human(year) {
  1123. var privateVar = 1;
  1124. this.year = year;
  1125. this.isOld = function() {
  1126. return year > 80;
  1127. };
  1128. }
  1129. var car = new Car(30);
  1130. var carSame = new Car(30);
  1131. var carDiff = new Car(10);
  1132. var human = new Human(30);
  1133. var diff = {
  1134. year: 30
  1135. };
  1136. var same = {
  1137. year: 30,
  1138. isOld: function () {}
  1139. };
  1140. equal(QUnit.equiv(car, car), true);
  1141. equal(QUnit.equiv(car, carDiff), false);
  1142. equal(QUnit.equiv(car, carSame), true);
  1143. equal(QUnit.equiv(car, human), false);
  1144. });
  1145. test("Complex Instances Nesting (with function value in literals and/or in nested instances)", function() {
  1146. function A(fn) {
  1147. this.a = {};
  1148. this.fn = fn;
  1149. this.b = {a: []};
  1150. this.o = {};
  1151. this.fn1 = fn;
  1152. }
  1153. function B(fn) {
  1154. this.fn = fn;
  1155. this.fn1 = function () {};
  1156. this.a = new A(function () {});
  1157. }
  1158. function fnOutside() {
  1159. }
  1160. function C(fn) {
  1161. function fnInside() {
  1162. }
  1163. this.x = 10;
  1164. this.fn = fn;
  1165. this.fn1 = function () {};
  1166. this.fn2 = fnInside;
  1167. this.fn3 = {
  1168. a: true,
  1169. b: fnOutside // ok make reference to a function in all instances scope
  1170. };
  1171. this.o1 = {};
  1172. // This function will be ignored.
  1173. // Even if it is not visible for all instances (e.g. locked in a closures),
  1174. // it is from a property that makes part of an instance (e.g. from the C constructor)
  1175. this.b1 = new B(function () {});
  1176. this.b2 = new B({
  1177. x: {
  1178. b2: new B(function() {})
  1179. }
  1180. });
  1181. }
  1182. function D(fn) {
  1183. function fnInside() {
  1184. }
  1185. this.x = 10;
  1186. this.fn = fn;
  1187. this.fn1 = function () {};
  1188. this.fn2 = fnInside;
  1189. this.fn3 = {
  1190. a: true,
  1191. b: fnOutside, // ok make reference to a function in all instances scope
  1192. // This function won't be ingored.
  1193. // It isn't visible for all C insances
  1194. // and it is not in a property of an instance. (in an Object instances e.g. the object literal)
  1195. c: fnInside
  1196. };
  1197. this.o1 = {};
  1198. // This function will be ignored.
  1199. // Even if it is not visible for all instances (e.g. locked in a closures),
  1200. // it is from a property that makes part of an instance (e.g. from the C constructor)
  1201. this.b1 = new B(function () {});
  1202. this.b2 = new B({
  1203. x: {
  1204. b2: new B(function() {})
  1205. }
  1206. });
  1207. }
  1208. function E(fn) {
  1209. function fnInside() {
  1210. }
  1211. this.x = 10;
  1212. this.fn = fn;
  1213. this.fn1 = function () {};
  1214. this.fn2 = fnInside;
  1215. this.fn3 = {
  1216. a: true,
  1217. b: fnOutside // ok make reference to a function in all instances scope
  1218. };
  1219. this.o1 = {};
  1220. // This function will be ignored.
  1221. // Even if it is not visible for all instances (e.g. locked in a closures),
  1222. // it is from a property that makes part of an instance (e.g. from the C constructor)
  1223. this.b1 = new B(function () {});
  1224. this.b2 = new B({
  1225. x: {
  1226. b1: new B({a: function() {}}),
  1227. b2: new B(function() {})
  1228. }
  1229. });
  1230. }
  1231. var a1 = new A(function () {});
  1232. var a2 = new A(function () {});
  1233. equal(QUnit.equiv(a1, a2), true);
  1234. equal(QUnit.equiv(a1, a2), true); // different instances
  1235. var b1 = new B(function () {});
  1236. var b2 = new B(function () {});
  1237. equal(QUnit.equiv(b1, b2), true);
  1238. var c1 = new C(function () {});
  1239. var c2 = new C(function () {});
  1240. equal(QUnit.equiv(c1, c2), true);
  1241. var d1 = new D(function () {});
  1242. var d2 = new D(function () {});
  1243. equal(QUnit.equiv(d1, d2), false);
  1244. var e1 = new E(function () {});
  1245. var e2 = new E(function () {});
  1246. equal(QUnit.equiv(e1, e2), false);
  1247. });
  1248. test('object with references to self wont loop', function() {
  1249. var circularA = {
  1250. abc:null
  1251. }, circularB = {
  1252. abc:null
  1253. };
  1254. circularA.abc = circularA;
  1255. circularB.abc = circularB;
  1256. equal(QUnit.equiv(circularA, circularB), true, "Should not repeat test on object (ambigous test)");
  1257. circularA.def = 1;
  1258. circularB.def = 1;
  1259. equal(QUnit.equiv(circularA, circularB), true, "Should not repeat test on object (ambigous test)");
  1260. circularA.def = 1;
  1261. circularB.def = 0;
  1262. equal(QUnit.equiv(circularA, circularB), false, "Should not repeat test on object (unambigous test)");
  1263. });
  1264. test('array with references to self wont loop', function() {
  1265. var circularA = [],
  1266. circularB = [];
  1267. circularA.push(circularA);
  1268. circularB.push(circularB);
  1269. equal(QUnit.equiv(circularA, circularB), true, "Should not repeat test on array (ambigous test)");
  1270. circularA.push( 'abc' );
  1271. circularB.push( 'abc' );
  1272. equal(QUnit.equiv(circularA, circularB), true, "Should not repeat test on array (ambigous test)");
  1273. circularA.push( 'hello' );
  1274. circularB.push( 'goodbye' );
  1275. equal(QUnit.equiv(circularA, circularB), false, "Should not repeat test on array (unambigous test)");
  1276. });
  1277. test('mixed object/array with references to self wont loop', function() {
  1278. var circularA = [{abc:null}],
  1279. circularB = [{abc:null}];
  1280. circularA[0].abc = circularA;
  1281. circularB[0].abc = circularB;
  1282. circularA.push(circularA);
  1283. circularB.push(circularB);
  1284. equal(QUnit.equiv(circularA, circularB), true, "Should not repeat test on object/array (ambigous test)");
  1285. circularA[0].def = 1;
  1286. circularB[0].def = 1;
  1287. equal(QUnit.equiv(circularA, circularB), true, "Should not repeat test on object/array (ambigous test)");
  1288. circularA[0].def = 1;
  1289. circularB[0].def = 0;
  1290. equal(QUnit.equiv(circularA, circularB), false, "Should not repeat test on object/array (unambigous test)");
  1291. });
  1292. test('compare self-referent to tree', function () {
  1293. var temp,
  1294. circularA = [0],
  1295. treeA = [0, null],
  1296. circularO = {},
  1297. treeO = {
  1298. o: null
  1299. };
  1300. circularA[1] = circularA;
  1301. circularO.o = circularO;
  1302. equal(QUnit.equiv(circularA, treeA), false, "Array: Should not consider circular equal to tree");
  1303. equal(QUnit.equiv(circularO, treeO), false, "Object: Should not consider circular equal to tree");
  1304. temp = [ 0, circularA ];
  1305. equal(QUnit.equiv(circularA, temp), true, "Array: Reference is circular for one, but equal on other");
  1306. equal(QUnit.equiv(temp, circularA), true, "Array: Reference is circular for one, but equal on other");
  1307. temp = {
  1308. o: circularO
  1309. };
  1310. equal(QUnit.equiv(circularO, temp), true, "Object: Reference is circular for one, but equal on other");
  1311. equal(QUnit.equiv(temp, circularO), true, "Object: Reference is circular for one, but equal on other");
  1312. });
  1313. test("Test that must be done at the end because they extend some primitive's prototype", function() {
  1314. // Try that a function looks like our regular expression.
  1315. // This tests if we check that a and b are really both instance of RegExp
  1316. Function.prototype.global = true;
  1317. Function.prototype.multiline = true;
  1318. Function.prototype.ignoreCase = false;
  1319. Function.prototype.source = "my regex";
  1320. var re = /my regex/gm;
  1321. equal(QUnit.equiv(re, function () {}), false, "A function that looks that a regex isn't a regex");
  1322. // This test will ensures it works in both ways, and ALSO especially that we can make differences
  1323. // between RegExp and Function constructor because typeof on a RegExpt instance is "function"
  1324. equal(QUnit.equiv(function () {}, re), false, "Same conversely, but ensures that function and regexp are distinct because their constructor are different");
  1325. });