index.js 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284
  1. (function (global, module) {
  2. var exports = module.exports;
  3. /**
  4. * Exports.
  5. */
  6. module.exports = expect;
  7. expect.Assertion = Assertion;
  8. /**
  9. * Exports version.
  10. */
  11. expect.version = '0.3.1';
  12. /**
  13. * Possible assertion flags.
  14. */
  15. var flags = {
  16. not: ['to', 'be', 'have', 'include', 'only']
  17. , to: ['be', 'have', 'include', 'only', 'not']
  18. , only: ['have']
  19. , have: ['own']
  20. , be: ['an']
  21. };
  22. function expect (obj) {
  23. return new Assertion(obj);
  24. }
  25. /**
  26. * Constructor
  27. *
  28. * @api private
  29. */
  30. function Assertion (obj, flag, parent) {
  31. this.obj = obj;
  32. this.flags = {};
  33. if (undefined != parent) {
  34. this.flags[flag] = true;
  35. for (var i in parent.flags) {
  36. if (parent.flags.hasOwnProperty(i)) {
  37. this.flags[i] = true;
  38. }
  39. }
  40. }
  41. var $flags = flag ? flags[flag] : keys(flags)
  42. , self = this;
  43. if ($flags) {
  44. for (var i = 0, l = $flags.length; i < l; i++) {
  45. // avoid recursion
  46. if (this.flags[$flags[i]]) continue;
  47. var name = $flags[i]
  48. , assertion = new Assertion(this.obj, name, this)
  49. if ('function' == typeof Assertion.prototype[name]) {
  50. // clone the function, make sure we dont touch the prot reference
  51. var old = this[name];
  52. this[name] = function () {
  53. return old.apply(self, arguments);
  54. };
  55. for (var fn in Assertion.prototype) {
  56. if (Assertion.prototype.hasOwnProperty(fn) && fn != name) {
  57. this[name][fn] = bind(assertion[fn], assertion);
  58. }
  59. }
  60. } else {
  61. this[name] = assertion;
  62. }
  63. }
  64. }
  65. }
  66. /**
  67. * Performs an assertion
  68. *
  69. * @api private
  70. */
  71. Assertion.prototype.assert = function (truth, msg, error, expected) {
  72. var msg = this.flags.not ? error : msg
  73. , ok = this.flags.not ? !truth : truth
  74. , err;
  75. if (!ok) {
  76. err = new Error(msg.call(this));
  77. if (arguments.length > 3) {
  78. err.actual = this.obj;
  79. err.expected = expected;
  80. err.showDiff = true;
  81. }
  82. throw err;
  83. }
  84. this.and = new Assertion(this.obj);
  85. };
  86. /**
  87. * Check if the value is truthy
  88. *
  89. * @api public
  90. */
  91. Assertion.prototype.ok = function () {
  92. this.assert(
  93. !!this.obj
  94. , function(){ return 'expected ' + i(this.obj) + ' to be truthy' }
  95. , function(){ return 'expected ' + i(this.obj) + ' to be falsy' });
  96. };
  97. /**
  98. * Creates an anonymous function which calls fn with arguments.
  99. *
  100. * @api public
  101. */
  102. Assertion.prototype.withArgs = function() {
  103. expect(this.obj).to.be.a('function');
  104. var fn = this.obj;
  105. var args = Array.prototype.slice.call(arguments);
  106. return expect(function() { fn.apply(null, args); });
  107. };
  108. /**
  109. * Assert that the function throws.
  110. *
  111. * @param {Function|RegExp} callback, or regexp to match error string against
  112. * @api public
  113. */
  114. Assertion.prototype.throwError =
  115. Assertion.prototype.throwException = function (fn) {
  116. expect(this.obj).to.be.a('function');
  117. var thrown = false
  118. , not = this.flags.not;
  119. try {
  120. this.obj();
  121. } catch (e) {
  122. if (isRegExp(fn)) {
  123. var subject = 'string' == typeof e ? e : e.message;
  124. if (not) {
  125. expect(subject).to.not.match(fn);
  126. } else {
  127. expect(subject).to.match(fn);
  128. }
  129. } else if ('function' == typeof fn) {
  130. fn(e);
  131. }
  132. thrown = true;
  133. }
  134. if (isRegExp(fn) && not) {
  135. // in the presence of a matcher, ensure the `not` only applies to
  136. // the matching.
  137. this.flags.not = false;
  138. }
  139. var name = this.obj.name || 'fn';
  140. this.assert(
  141. thrown
  142. , function(){ return 'expected ' + name + ' to throw an exception' }
  143. , function(){ return 'expected ' + name + ' not to throw an exception' });
  144. };
  145. /**
  146. * Checks if the array is empty.
  147. *
  148. * @api public
  149. */
  150. Assertion.prototype.empty = function () {
  151. var expectation;
  152. if ('object' == typeof this.obj && null !== this.obj && !isArray(this.obj)) {
  153. if ('number' == typeof this.obj.length) {
  154. expectation = !this.obj.length;
  155. } else {
  156. expectation = !keys(this.obj).length;
  157. }
  158. } else {
  159. if ('string' != typeof this.obj) {
  160. expect(this.obj).to.be.an('object');
  161. }
  162. expect(this.obj).to.have.property('length');
  163. expectation = !this.obj.length;
  164. }
  165. this.assert(
  166. expectation
  167. , function(){ return 'expected ' + i(this.obj) + ' to be empty' }
  168. , function(){ return 'expected ' + i(this.obj) + ' to not be empty' });
  169. return this;
  170. };
  171. /**
  172. * Checks if the obj exactly equals another.
  173. *
  174. * @api public
  175. */
  176. Assertion.prototype.be =
  177. Assertion.prototype.equal = function (obj) {
  178. this.assert(
  179. obj === this.obj
  180. , function(){ return 'expected ' + i(this.obj) + ' to equal ' + i(obj) }
  181. , function(){ return 'expected ' + i(this.obj) + ' to not equal ' + i(obj) });
  182. return this;
  183. };
  184. /**
  185. * Checks if the obj sortof equals another.
  186. *
  187. * @api public
  188. */
  189. Assertion.prototype.eql = function (obj) {
  190. this.assert(
  191. expect.eql(this.obj, obj)
  192. , function(){ return 'expected ' + i(this.obj) + ' to sort of equal ' + i(obj) }
  193. , function(){ return 'expected ' + i(this.obj) + ' to sort of not equal ' + i(obj) }
  194. , obj);
  195. return this;
  196. };
  197. /**
  198. * Assert within start to finish (inclusive).
  199. *
  200. * @param {Number} start
  201. * @param {Number} finish
  202. * @api public
  203. */
  204. Assertion.prototype.within = function (start, finish) {
  205. var range = start + '..' + finish;
  206. this.assert(
  207. this.obj >= start && this.obj <= finish
  208. , function(){ return 'expected ' + i(this.obj) + ' to be within ' + range }
  209. , function(){ return 'expected ' + i(this.obj) + ' to not be within ' + range });
  210. return this;
  211. };
  212. /**
  213. * Assert typeof / instance of
  214. *
  215. * @api public
  216. */
  217. Assertion.prototype.a =
  218. Assertion.prototype.an = function (type) {
  219. if ('string' == typeof type) {
  220. // proper english in error msg
  221. var n = /^[aeiou]/.test(type) ? 'n' : '';
  222. // typeof with support for 'array'
  223. this.assert(
  224. 'array' == type ? isArray(this.obj) :
  225. 'regexp' == type ? isRegExp(this.obj) :
  226. 'object' == type
  227. ? 'object' == typeof this.obj && null !== this.obj
  228. : type == typeof this.obj
  229. , function(){ return 'expected ' + i(this.obj) + ' to be a' + n + ' ' + type }
  230. , function(){ return 'expected ' + i(this.obj) + ' not to be a' + n + ' ' + type });
  231. } else {
  232. // instanceof
  233. var name = type.name || 'supplied constructor';
  234. this.assert(
  235. this.obj instanceof type
  236. , function(){ return 'expected ' + i(this.obj) + ' to be an instance of ' + name }
  237. , function(){ return 'expected ' + i(this.obj) + ' not to be an instance of ' + name });
  238. }
  239. return this;
  240. };
  241. /**
  242. * Assert numeric value above _n_.
  243. *
  244. * @param {Number} n
  245. * @api public
  246. */
  247. Assertion.prototype.greaterThan =
  248. Assertion.prototype.above = function (n) {
  249. this.assert(
  250. this.obj > n
  251. , function(){ return 'expected ' + i(this.obj) + ' to be above ' + n }
  252. , function(){ return 'expected ' + i(this.obj) + ' to be below ' + n });
  253. return this;
  254. };
  255. /**
  256. * Assert numeric value below _n_.
  257. *
  258. * @param {Number} n
  259. * @api public
  260. */
  261. Assertion.prototype.lessThan =
  262. Assertion.prototype.below = function (n) {
  263. this.assert(
  264. this.obj < n
  265. , function(){ return 'expected ' + i(this.obj) + ' to be below ' + n }
  266. , function(){ return 'expected ' + i(this.obj) + ' to be above ' + n });
  267. return this;
  268. };
  269. /**
  270. * Assert string value matches _regexp_.
  271. *
  272. * @param {RegExp} regexp
  273. * @api public
  274. */
  275. Assertion.prototype.match = function (regexp) {
  276. this.assert(
  277. regexp.exec(this.obj)
  278. , function(){ return 'expected ' + i(this.obj) + ' to match ' + regexp }
  279. , function(){ return 'expected ' + i(this.obj) + ' not to match ' + regexp });
  280. return this;
  281. };
  282. /**
  283. * Assert property "length" exists and has value of _n_.
  284. *
  285. * @param {Number} n
  286. * @api public
  287. */
  288. Assertion.prototype.length = function (n) {
  289. expect(this.obj).to.have.property('length');
  290. var len = this.obj.length;
  291. this.assert(
  292. n == len
  293. , function(){ return 'expected ' + i(this.obj) + ' to have a length of ' + n + ' but got ' + len }
  294. , function(){ return 'expected ' + i(this.obj) + ' to not have a length of ' + len });
  295. return this;
  296. };
  297. /**
  298. * Assert property _name_ exists, with optional _val_.
  299. *
  300. * @param {String} name
  301. * @param {Mixed} val
  302. * @api public
  303. */
  304. Assertion.prototype.property = function (name, val) {
  305. if (this.flags.own) {
  306. this.assert(
  307. Object.prototype.hasOwnProperty.call(this.obj, name)
  308. , function(){ return 'expected ' + i(this.obj) + ' to have own property ' + i(name) }
  309. , function(){ return 'expected ' + i(this.obj) + ' to not have own property ' + i(name) });
  310. return this;
  311. }
  312. if (this.flags.not && undefined !== val) {
  313. if (undefined === this.obj[name]) {
  314. throw new Error(i(this.obj) + ' has no property ' + i(name));
  315. }
  316. } else {
  317. var hasProp;
  318. try {
  319. hasProp = name in this.obj
  320. } catch (e) {
  321. hasProp = undefined !== this.obj[name]
  322. }
  323. this.assert(
  324. hasProp
  325. , function(){ return 'expected ' + i(this.obj) + ' to have a property ' + i(name) }
  326. , function(){ return 'expected ' + i(this.obj) + ' to not have a property ' + i(name) });
  327. }
  328. if (undefined !== val) {
  329. this.assert(
  330. val === this.obj[name]
  331. , function(){ return 'expected ' + i(this.obj) + ' to have a property ' + i(name)
  332. + ' of ' + i(val) + ', but got ' + i(this.obj[name]) }
  333. , function(){ return 'expected ' + i(this.obj) + ' to not have a property ' + i(name)
  334. + ' of ' + i(val) });
  335. }
  336. this.obj = this.obj[name];
  337. return this;
  338. };
  339. /**
  340. * Assert that the array contains _obj_ or string contains _obj_.
  341. *
  342. * @param {Mixed} obj|string
  343. * @api public
  344. */
  345. Assertion.prototype.string =
  346. Assertion.prototype.contain = function (obj) {
  347. if ('string' == typeof this.obj) {
  348. this.assert(
  349. ~this.obj.indexOf(obj)
  350. , function(){ return 'expected ' + i(this.obj) + ' to contain ' + i(obj) }
  351. , function(){ return 'expected ' + i(this.obj) + ' to not contain ' + i(obj) });
  352. } else {
  353. this.assert(
  354. ~indexOf(this.obj, obj)
  355. , function(){ return 'expected ' + i(this.obj) + ' to contain ' + i(obj) }
  356. , function(){ return 'expected ' + i(this.obj) + ' to not contain ' + i(obj) });
  357. }
  358. return this;
  359. };
  360. /**
  361. * Assert exact keys or inclusion of keys by using
  362. * the `.own` modifier.
  363. *
  364. * @param {Array|String ...} keys
  365. * @api public
  366. */
  367. Assertion.prototype.key =
  368. Assertion.prototype.keys = function ($keys) {
  369. var str
  370. , ok = true;
  371. $keys = isArray($keys)
  372. ? $keys
  373. : Array.prototype.slice.call(arguments);
  374. if (!$keys.length) throw new Error('keys required');
  375. var actual = keys(this.obj)
  376. , len = $keys.length;
  377. // Inclusion
  378. ok = every($keys, function (key) {
  379. return ~indexOf(actual, key);
  380. });
  381. // Strict
  382. if (!this.flags.not && this.flags.only) {
  383. ok = ok && $keys.length == actual.length;
  384. }
  385. // Key string
  386. if (len > 1) {
  387. $keys = map($keys, function (key) {
  388. return i(key);
  389. });
  390. var last = $keys.pop();
  391. str = $keys.join(', ') + ', and ' + last;
  392. } else {
  393. str = i($keys[0]);
  394. }
  395. // Form
  396. str = (len > 1 ? 'keys ' : 'key ') + str;
  397. // Have / include
  398. str = (!this.flags.only ? 'include ' : 'only have ') + str;
  399. // Assertion
  400. this.assert(
  401. ok
  402. , function(){ return 'expected ' + i(this.obj) + ' to ' + str }
  403. , function(){ return 'expected ' + i(this.obj) + ' to not ' + str });
  404. return this;
  405. };
  406. /**
  407. * Assert a failure.
  408. *
  409. * @param {String ...} custom message
  410. * @api public
  411. */
  412. Assertion.prototype.fail = function (msg) {
  413. var error = function() { return msg || "explicit failure"; }
  414. this.assert(false, error, error);
  415. return this;
  416. };
  417. /**
  418. * Function bind implementation.
  419. */
  420. function bind (fn, scope) {
  421. return function () {
  422. return fn.apply(scope, arguments);
  423. }
  424. }
  425. /**
  426. * Array every compatibility
  427. *
  428. * @see bit.ly/5Fq1N2
  429. * @api public
  430. */
  431. function every (arr, fn, thisObj) {
  432. var scope = thisObj || global;
  433. for (var i = 0, j = arr.length; i < j; ++i) {
  434. if (!fn.call(scope, arr[i], i, arr)) {
  435. return false;
  436. }
  437. }
  438. return true;
  439. }
  440. /**
  441. * Array indexOf compatibility.
  442. *
  443. * @see bit.ly/a5Dxa2
  444. * @api public
  445. */
  446. function indexOf (arr, o, i) {
  447. if (Array.prototype.indexOf) {
  448. return Array.prototype.indexOf.call(arr, o, i);
  449. }
  450. if (arr.length === undefined) {
  451. return -1;
  452. }
  453. for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0
  454. ; i < j && arr[i] !== o; i++);
  455. return j <= i ? -1 : i;
  456. }
  457. // https://gist.github.com/1044128/
  458. var getOuterHTML = function(element) {
  459. if ('outerHTML' in element) return element.outerHTML;
  460. var ns = "http://www.w3.org/1999/xhtml";
  461. var container = document.createElementNS(ns, '_');
  462. var xmlSerializer = new XMLSerializer();
  463. var html;
  464. if (document.xmlVersion) {
  465. return xmlSerializer.serializeToString(element);
  466. } else {
  467. container.appendChild(element.cloneNode(false));
  468. html = container.innerHTML.replace('><', '>' + element.innerHTML + '<');
  469. container.innerHTML = '';
  470. return html;
  471. }
  472. };
  473. // Returns true if object is a DOM element.
  474. var isDOMElement = function (object) {
  475. if (typeof HTMLElement === 'object') {
  476. return object instanceof HTMLElement;
  477. } else {
  478. return object &&
  479. typeof object === 'object' &&
  480. object.nodeType === 1 &&
  481. typeof object.nodeName === 'string';
  482. }
  483. };
  484. /**
  485. * Inspects an object.
  486. *
  487. * @see taken from node.js `util` module (copyright Joyent, MIT license)
  488. * @api private
  489. */
  490. function i (obj, showHidden, depth) {
  491. var seen = [];
  492. function stylize (str) {
  493. return str;
  494. }
  495. function format (value, recurseTimes) {
  496. // Provide a hook for user-specified inspect functions.
  497. // Check that value is an object with an inspect function on it
  498. if (value && typeof value.inspect === 'function' &&
  499. // Filter out the util module, it's inspect function is special
  500. value !== exports &&
  501. // Also filter out any prototype objects using the circular check.
  502. !(value.constructor && value.constructor.prototype === value)) {
  503. return value.inspect(recurseTimes);
  504. }
  505. // Primitive types cannot have properties
  506. switch (typeof value) {
  507. case 'undefined':
  508. return stylize('undefined', 'undefined');
  509. case 'string':
  510. var simple = '\'' + json.stringify(value).replace(/^"|"$/g, '')
  511. .replace(/'/g, "\\'")
  512. .replace(/\\"/g, '"') + '\'';
  513. return stylize(simple, 'string');
  514. case 'number':
  515. return stylize('' + value, 'number');
  516. case 'boolean':
  517. return stylize('' + value, 'boolean');
  518. }
  519. // For some reason typeof null is "object", so special case here.
  520. if (value === null) {
  521. return stylize('null', 'null');
  522. }
  523. if (isDOMElement(value)) {
  524. return getOuterHTML(value);
  525. }
  526. // Look up the keys of the object.
  527. var visible_keys = keys(value);
  528. var $keys = showHidden ? Object.getOwnPropertyNames(value) : visible_keys;
  529. // Functions without properties can be shortcutted.
  530. if (typeof value === 'function' && $keys.length === 0) {
  531. if (isRegExp(value)) {
  532. return stylize('' + value, 'regexp');
  533. } else {
  534. var name = value.name ? ': ' + value.name : '';
  535. return stylize('[Function' + name + ']', 'special');
  536. }
  537. }
  538. // Dates without properties can be shortcutted
  539. if (isDate(value) && $keys.length === 0) {
  540. return stylize(value.toUTCString(), 'date');
  541. }
  542. // Error objects can be shortcutted
  543. if (value instanceof Error) {
  544. return stylize("["+value.toString()+"]", 'Error');
  545. }
  546. var base, type, braces;
  547. // Determine the object type
  548. if (isArray(value)) {
  549. type = 'Array';
  550. braces = ['[', ']'];
  551. } else {
  552. type = 'Object';
  553. braces = ['{', '}'];
  554. }
  555. // Make functions say that they are functions
  556. if (typeof value === 'function') {
  557. var n = value.name ? ': ' + value.name : '';
  558. base = (isRegExp(value)) ? ' ' + value : ' [Function' + n + ']';
  559. } else {
  560. base = '';
  561. }
  562. // Make dates with properties first say the date
  563. if (isDate(value)) {
  564. base = ' ' + value.toUTCString();
  565. }
  566. if ($keys.length === 0) {
  567. return braces[0] + base + braces[1];
  568. }
  569. if (recurseTimes < 0) {
  570. if (isRegExp(value)) {
  571. return stylize('' + value, 'regexp');
  572. } else {
  573. return stylize('[Object]', 'special');
  574. }
  575. }
  576. seen.push(value);
  577. var output = map($keys, function (key) {
  578. var name, str;
  579. if (value.__lookupGetter__) {
  580. if (value.__lookupGetter__(key)) {
  581. if (value.__lookupSetter__(key)) {
  582. str = stylize('[Getter/Setter]', 'special');
  583. } else {
  584. str = stylize('[Getter]', 'special');
  585. }
  586. } else {
  587. if (value.__lookupSetter__(key)) {
  588. str = stylize('[Setter]', 'special');
  589. }
  590. }
  591. }
  592. if (indexOf(visible_keys, key) < 0) {
  593. name = '[' + key + ']';
  594. }
  595. if (!str) {
  596. if (indexOf(seen, value[key]) < 0) {
  597. if (recurseTimes === null) {
  598. str = format(value[key]);
  599. } else {
  600. str = format(value[key], recurseTimes - 1);
  601. }
  602. if (str.indexOf('\n') > -1) {
  603. if (isArray(value)) {
  604. str = map(str.split('\n'), function (line) {
  605. return ' ' + line;
  606. }).join('\n').substr(2);
  607. } else {
  608. str = '\n' + map(str.split('\n'), function (line) {
  609. return ' ' + line;
  610. }).join('\n');
  611. }
  612. }
  613. } else {
  614. str = stylize('[Circular]', 'special');
  615. }
  616. }
  617. if (typeof name === 'undefined') {
  618. if (type === 'Array' && key.match(/^\d+$/)) {
  619. return str;
  620. }
  621. name = json.stringify('' + key);
  622. if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
  623. name = name.substr(1, name.length - 2);
  624. name = stylize(name, 'name');
  625. } else {
  626. name = name.replace(/'/g, "\\'")
  627. .replace(/\\"/g, '"')
  628. .replace(/(^"|"$)/g, "'");
  629. name = stylize(name, 'string');
  630. }
  631. }
  632. return name + ': ' + str;
  633. });
  634. seen.pop();
  635. var numLinesEst = 0;
  636. var length = reduce(output, function (prev, cur) {
  637. numLinesEst++;
  638. if (indexOf(cur, '\n') >= 0) numLinesEst++;
  639. return prev + cur.length + 1;
  640. }, 0);
  641. if (length > 50) {
  642. output = braces[0] +
  643. (base === '' ? '' : base + '\n ') +
  644. ' ' +
  645. output.join(',\n ') +
  646. ' ' +
  647. braces[1];
  648. } else {
  649. output = braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
  650. }
  651. return output;
  652. }
  653. return format(obj, (typeof depth === 'undefined' ? 2 : depth));
  654. }
  655. expect.stringify = i;
  656. function isArray (ar) {
  657. return Object.prototype.toString.call(ar) === '[object Array]';
  658. }
  659. function isRegExp(re) {
  660. var s;
  661. try {
  662. s = '' + re;
  663. } catch (e) {
  664. return false;
  665. }
  666. return re instanceof RegExp || // easy case
  667. // duck-type for context-switching evalcx case
  668. typeof(re) === 'function' &&
  669. re.constructor.name === 'RegExp' &&
  670. re.compile &&
  671. re.test &&
  672. re.exec &&
  673. s.match(/^\/.*\/[gim]{0,3}$/);
  674. }
  675. function isDate(d) {
  676. return d instanceof Date;
  677. }
  678. function keys (obj) {
  679. if (Object.keys) {
  680. return Object.keys(obj);
  681. }
  682. var keys = [];
  683. for (var i in obj) {
  684. if (Object.prototype.hasOwnProperty.call(obj, i)) {
  685. keys.push(i);
  686. }
  687. }
  688. return keys;
  689. }
  690. function map (arr, mapper, that) {
  691. if (Array.prototype.map) {
  692. return Array.prototype.map.call(arr, mapper, that);
  693. }
  694. var other= new Array(arr.length);
  695. for (var i= 0, n = arr.length; i<n; i++)
  696. if (i in arr)
  697. other[i] = mapper.call(that, arr[i], i, arr);
  698. return other;
  699. }
  700. function reduce (arr, fun) {
  701. if (Array.prototype.reduce) {
  702. return Array.prototype.reduce.apply(
  703. arr
  704. , Array.prototype.slice.call(arguments, 1)
  705. );
  706. }
  707. var len = +this.length;
  708. if (typeof fun !== "function")
  709. throw new TypeError();
  710. // no value to return if no initial value and an empty array
  711. if (len === 0 && arguments.length === 1)
  712. throw new TypeError();
  713. var i = 0;
  714. if (arguments.length >= 2) {
  715. var rv = arguments[1];
  716. } else {
  717. do {
  718. if (i in this) {
  719. rv = this[i++];
  720. break;
  721. }
  722. // if array contains no values, no initial value to return
  723. if (++i >= len)
  724. throw new TypeError();
  725. } while (true);
  726. }
  727. for (; i < len; i++) {
  728. if (i in this)
  729. rv = fun.call(null, rv, this[i], i, this);
  730. }
  731. return rv;
  732. }
  733. /**
  734. * Asserts deep equality
  735. *
  736. * @see taken from node.js `assert` module (copyright Joyent, MIT license)
  737. * @api private
  738. */
  739. expect.eql = function eql(actual, expected) {
  740. // 7.1. All identical values are equivalent, as determined by ===.
  741. if (actual === expected) {
  742. return true;
  743. } else if ('undefined' != typeof Buffer
  744. && Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) {
  745. if (actual.length != expected.length) return false;
  746. for (var i = 0; i < actual.length; i++) {
  747. if (actual[i] !== expected[i]) return false;
  748. }
  749. return true;
  750. // 7.2. If the expected value is a Date object, the actual value is
  751. // equivalent if it is also a Date object that refers to the same time.
  752. } else if (actual instanceof Date && expected instanceof Date) {
  753. return actual.getTime() === expected.getTime();
  754. // 7.3. Other pairs that do not both pass typeof value == "object",
  755. // equivalence is determined by ==.
  756. } else if (typeof actual != 'object' && typeof expected != 'object') {
  757. return actual == expected;
  758. // If both are regular expression use the special `regExpEquiv` method
  759. // to determine equivalence.
  760. } else if (isRegExp(actual) && isRegExp(expected)) {
  761. return regExpEquiv(actual, expected);
  762. // 7.4. For all other Object pairs, including Array objects, equivalence is
  763. // determined by having the same number of owned properties (as verified
  764. // with Object.prototype.hasOwnProperty.call), the same set of keys
  765. // (although not necessarily the same order), equivalent values for every
  766. // corresponding key, and an identical "prototype" property. Note: this
  767. // accounts for both named and indexed properties on Arrays.
  768. } else {
  769. return objEquiv(actual, expected);
  770. }
  771. };
  772. function isUndefinedOrNull (value) {
  773. return value === null || value === undefined;
  774. }
  775. function isArguments (object) {
  776. return Object.prototype.toString.call(object) == '[object Arguments]';
  777. }
  778. function regExpEquiv (a, b) {
  779. return a.source === b.source && a.global === b.global &&
  780. a.ignoreCase === b.ignoreCase && a.multiline === b.multiline;
  781. }
  782. function objEquiv (a, b) {
  783. if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
  784. return false;
  785. // an identical "prototype" property.
  786. if (a.prototype !== b.prototype) return false;
  787. //~~~I've managed to break Object.keys through screwy arguments passing.
  788. // Converting to array solves the problem.
  789. if (isArguments(a)) {
  790. if (!isArguments(b)) {
  791. return false;
  792. }
  793. a = pSlice.call(a);
  794. b = pSlice.call(b);
  795. return expect.eql(a, b);
  796. }
  797. try{
  798. var ka = keys(a),
  799. kb = keys(b),
  800. key, i;
  801. } catch (e) {//happens when one is a string literal and the other isn't
  802. return false;
  803. }
  804. // having the same number of owned properties (keys incorporates hasOwnProperty)
  805. if (ka.length != kb.length)
  806. return false;
  807. //the same set of keys (although not necessarily the same order),
  808. ka.sort();
  809. kb.sort();
  810. //~~~cheap key test
  811. for (i = ka.length - 1; i >= 0; i--) {
  812. if (ka[i] != kb[i])
  813. return false;
  814. }
  815. //equivalent values for every corresponding key, and
  816. //~~~possibly expensive deep test
  817. for (i = ka.length - 1; i >= 0; i--) {
  818. key = ka[i];
  819. if (!expect.eql(a[key], b[key]))
  820. return false;
  821. }
  822. return true;
  823. }
  824. var json = (function () {
  825. "use strict";
  826. if ('object' == typeof JSON && JSON.parse && JSON.stringify) {
  827. return {
  828. parse: nativeJSON.parse
  829. , stringify: nativeJSON.stringify
  830. }
  831. }
  832. var JSON = {};
  833. function f(n) {
  834. // Format integers to have at least two digits.
  835. return n < 10 ? '0' + n : n;
  836. }
  837. function date(d, key) {
  838. return isFinite(d.valueOf()) ?
  839. d.getUTCFullYear() + '-' +
  840. f(d.getUTCMonth() + 1) + '-' +
  841. f(d.getUTCDate()) + 'T' +
  842. f(d.getUTCHours()) + ':' +
  843. f(d.getUTCMinutes()) + ':' +
  844. f(d.getUTCSeconds()) + 'Z' : null;
  845. }
  846. var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
  847. escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
  848. gap,
  849. indent,
  850. meta = { // table of character substitutions
  851. '\b': '\\b',
  852. '\t': '\\t',
  853. '\n': '\\n',
  854. '\f': '\\f',
  855. '\r': '\\r',
  856. '"' : '\\"',
  857. '\\': '\\\\'
  858. },
  859. rep;
  860. function quote(string) {
  861. // If the string contains no control characters, no quote characters, and no
  862. // backslash characters, then we can safely slap some quotes around it.
  863. // Otherwise we must also replace the offending characters with safe escape
  864. // sequences.
  865. escapable.lastIndex = 0;
  866. return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
  867. var c = meta[a];
  868. return typeof c === 'string' ? c :
  869. '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
  870. }) + '"' : '"' + string + '"';
  871. }
  872. function str(key, holder) {
  873. // Produce a string from holder[key].
  874. var i, // The loop counter.
  875. k, // The member key.
  876. v, // The member value.
  877. length,
  878. mind = gap,
  879. partial,
  880. value = holder[key];
  881. // If the value has a toJSON method, call it to obtain a replacement value.
  882. if (value instanceof Date) {
  883. value = date(key);
  884. }
  885. // If we were called with a replacer function, then call the replacer to
  886. // obtain a replacement value.
  887. if (typeof rep === 'function') {
  888. value = rep.call(holder, key, value);
  889. }
  890. // What happens next depends on the value's type.
  891. switch (typeof value) {
  892. case 'string':
  893. return quote(value);
  894. case 'number':
  895. // JSON numbers must be finite. Encode non-finite numbers as null.
  896. return isFinite(value) ? String(value) : 'null';
  897. case 'boolean':
  898. case 'null':
  899. // If the value is a boolean or null, convert it to a string. Note:
  900. // typeof null does not produce 'null'. The case is included here in
  901. // the remote chance that this gets fixed someday.
  902. return String(value);
  903. // If the type is 'object', we might be dealing with an object or an array or
  904. // null.
  905. case 'object':
  906. // Due to a specification blunder in ECMAScript, typeof null is 'object',
  907. // so watch out for that case.
  908. if (!value) {
  909. return 'null';
  910. }
  911. // Make an array to hold the partial results of stringifying this object value.
  912. gap += indent;
  913. partial = [];
  914. // Is the value an array?
  915. if (Object.prototype.toString.apply(value) === '[object Array]') {
  916. // The value is an array. Stringify every element. Use null as a placeholder
  917. // for non-JSON values.
  918. length = value.length;
  919. for (i = 0; i < length; i += 1) {
  920. partial[i] = str(i, value) || 'null';
  921. }
  922. // Join all of the elements together, separated with commas, and wrap them in
  923. // brackets.
  924. v = partial.length === 0 ? '[]' : gap ?
  925. '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
  926. '[' + partial.join(',') + ']';
  927. gap = mind;
  928. return v;
  929. }
  930. // If the replacer is an array, use it to select the members to be stringified.
  931. if (rep && typeof rep === 'object') {
  932. length = rep.length;
  933. for (i = 0; i < length; i += 1) {
  934. if (typeof rep[i] === 'string') {
  935. k = rep[i];
  936. v = str(k, value);
  937. if (v) {
  938. partial.push(quote(k) + (gap ? ': ' : ':') + v);
  939. }
  940. }
  941. }
  942. } else {
  943. // Otherwise, iterate through all of the keys in the object.
  944. for (k in value) {
  945. if (Object.prototype.hasOwnProperty.call(value, k)) {
  946. v = str(k, value);
  947. if (v) {
  948. partial.push(quote(k) + (gap ? ': ' : ':') + v);
  949. }
  950. }
  951. }
  952. }
  953. // Join all of the member texts together, separated with commas,
  954. // and wrap them in braces.
  955. v = partial.length === 0 ? '{}' : gap ?
  956. '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
  957. '{' + partial.join(',') + '}';
  958. gap = mind;
  959. return v;
  960. }
  961. }
  962. // If the JSON object does not yet have a stringify method, give it one.
  963. JSON.stringify = function (value, replacer, space) {
  964. // The stringify method takes a value and an optional replacer, and an optional
  965. // space parameter, and returns a JSON text. The replacer can be a function
  966. // that can replace values, or an array of strings that will select the keys.
  967. // A default replacer method can be provided. Use of the space parameter can
  968. // produce text that is more easily readable.
  969. var i;
  970. gap = '';
  971. indent = '';
  972. // If the space parameter is a number, make an indent string containing that
  973. // many spaces.
  974. if (typeof space === 'number') {
  975. for (i = 0; i < space; i += 1) {
  976. indent += ' ';
  977. }
  978. // If the space parameter is a string, it will be used as the indent string.
  979. } else if (typeof space === 'string') {
  980. indent = space;
  981. }
  982. // If there is a replacer, it must be a function or an array.
  983. // Otherwise, throw an error.
  984. rep = replacer;
  985. if (replacer && typeof replacer !== 'function' &&
  986. (typeof replacer !== 'object' ||
  987. typeof replacer.length !== 'number')) {
  988. throw new Error('JSON.stringify');
  989. }
  990. // Make a fake root object containing our value under the key of ''.
  991. // Return the result of stringifying the value.
  992. return str('', {'': value});
  993. };
  994. // If the JSON object does not yet have a parse method, give it one.
  995. JSON.parse = function (text, reviver) {
  996. // The parse method takes a text and an optional reviver function, and returns
  997. // a JavaScript value if the text is a valid JSON text.
  998. var j;
  999. function walk(holder, key) {
  1000. // The walk method is used to recursively walk the resulting structure so
  1001. // that modifications can be made.
  1002. var k, v, value = holder[key];
  1003. if (value && typeof value === 'object') {
  1004. for (k in value) {
  1005. if (Object.prototype.hasOwnProperty.call(value, k)) {
  1006. v = walk(value, k);
  1007. if (v !== undefined) {
  1008. value[k] = v;
  1009. } else {
  1010. delete value[k];
  1011. }
  1012. }
  1013. }
  1014. }
  1015. return reviver.call(holder, key, value);
  1016. }
  1017. // Parsing happens in four stages. In the first stage, we replace certain
  1018. // Unicode characters with escape sequences. JavaScript handles many characters
  1019. // incorrectly, either silently deleting them, or treating them as line endings.
  1020. text = String(text);
  1021. cx.lastIndex = 0;
  1022. if (cx.test(text)) {
  1023. text = text.replace(cx, function (a) {
  1024. return '\\u' +
  1025. ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
  1026. });
  1027. }
  1028. // In the second stage, we run the text against regular expressions that look
  1029. // for non-JSON patterns. We are especially concerned with '()' and 'new'
  1030. // because they can cause invocation, and '=' because it can cause mutation.
  1031. // But just to be safe, we want to reject all unexpected forms.
  1032. // We split the second stage into 4 regexp operations in order to work around
  1033. // crippling inefficiencies in IE's and Safari's regexp engines. First we
  1034. // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
  1035. // replace all simple value tokens with ']' characters. Third, we delete all
  1036. // open brackets that follow a colon or comma or that begin the text. Finally,
  1037. // we look to see that the remaining characters are only whitespace or ']' or
  1038. // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
  1039. if (/^[\],:{}\s]*$/
  1040. .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
  1041. .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
  1042. .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
  1043. // In the third stage we use the eval function to compile the text into a
  1044. // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
  1045. // in JavaScript: it can begin a block or an object literal. We wrap the text
  1046. // in parens to eliminate the ambiguity.
  1047. j = eval('(' + text + ')');
  1048. // In the optional fourth stage, we recursively walk the new structure, passing
  1049. // each name/value pair to a reviver function for possible transformation.
  1050. return typeof reviver === 'function' ?
  1051. walk({'': j}, '') : j;
  1052. }
  1053. // If the text is not JSON parseable, then a SyntaxError is thrown.
  1054. throw new SyntaxError('JSON.parse');
  1055. };
  1056. return JSON;
  1057. })();
  1058. if ('undefined' != typeof window) {
  1059. window.expect = module.exports;
  1060. }
  1061. })(
  1062. this
  1063. , 'undefined' != typeof module ? module : {exports: {}}
  1064. );