index.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. 'use strict';
  2. var test = require('tape');
  3. var Test = require('tape/lib/test');
  4. var inspect = require('object-inspect');
  5. // eslint-disable-next-line global-require
  6. var hasSymbols = require('has-symbols')() || require('has-symbols/shams')();
  7. var hasBigInts = require('has-bigints')();
  8. var forEach = require('for-each');
  9. var getIterator = process.env.TEST_VARIANT === 'node' ? require('../node') : require('../');
  10. Test.prototype.iterate = function (value, expected, message) {
  11. var i = 0;
  12. this.test(message, function (t) {
  13. var iterator = getIterator(value);
  14. if (!iterator) {
  15. t.fail(inspect(value) + ' is not iterable');
  16. return t.end();
  17. }
  18. if (typeof iterator.next !== 'function') {
  19. t.fail('iterator does not have a next function, got ' + inspect(iterator));
  20. return t.end();
  21. }
  22. var result;
  23. while ((result = iterator.next()) && !result.done) {
  24. var expectedDebug = typeof expected[i] === 'string' ? expected[i].charCodeAt(0) : expected[i];
  25. var actualDebug = typeof result.value === 'string' ? result.value.charCodeAt(0) : result.value;
  26. t.deepEqual(result.value, expected[i], 'index ' + i + ': expected ' + inspect(expectedDebug) + ', got ' + inspect(actualDebug));
  27. i += 1;
  28. }
  29. t.equal(i, expected.length, 'expected ' + expected.length + ' values, got ' + i + ' values');
  30. t.end();
  31. });
  32. };
  33. Test.prototype.noIterate = function (value) {
  34. this.equal(getIterator(value), undefined, inspect(value) + ' is not iterable');
  35. };
  36. Test.prototype.fakeIterator = function (value) {
  37. this.test(inspect(value) + ' with a fake iterator', { skip: !hasSymbols }, function (t) {
  38. var fakeValues = ['fake', 'iterator', 'scary'];
  39. var o = Object(value);
  40. o[Symbol.iterator] = function () {
  41. return getIterator(fakeValues);
  42. };
  43. t.iterate(o, fakeValues, inspect(o) + ' with an overwritten iterator method, yields those values instead');
  44. t.end();
  45. });
  46. };
  47. var getArguments = function () { return arguments; };
  48. var getSloppyArguments = Function('return arguments');
  49. var collect = function createCollection(C, items) {
  50. var c = new C();
  51. forEach(items, function (item) {
  52. if (c.add) {
  53. c.add(item);
  54. } else {
  55. c.set(item[0], item[1]);
  56. }
  57. });
  58. return c;
  59. };
  60. var runTests = function runTests(t) {
  61. t.test('strings', function (st) {
  62. st.iterate('', [], '"" yields nothing');
  63. st.iterate(Object(''), [], inspect(Object('')) + ' yields nothing');
  64. st.iterate('foo', ['f', 'o', 'o'], '"foo" yields three chars');
  65. st.iterate(Object('foo'), ['f', 'o', 'o'], inspect(Object('foo')) + ' yields three chars');
  66. st.iterate('a💩z', ['a', '💩', 'z'], '"a💩z" yields three code points');
  67. st.iterate(Object('a💩z'), ['a', '💩', 'z'], inspect(Object('a💩z')) + ' yields three code points');
  68. st.iterate('\ud83dX', ['\ud83d', 'X'], '(lone surrogate followed by "not a lone surrogate ending") yields one code point');
  69. st.fakeIterator('abc');
  70. st.end();
  71. });
  72. t.test('arrays', function (st) {
  73. st.iterate([], [], '[] yields nothing');
  74. st.iterate([1, 2], [1, 2], '[1, 2] yields [1, 2]');
  75. // eslint-disable-next-line no-sparse-arrays
  76. st.iterate([1, , 3], [1, undefined, 3], 'sparse array does not skip holes');
  77. st.fakeIterator([1, 2, 3]);
  78. st.end();
  79. });
  80. t.test('arguments', function (st) {
  81. st.iterate(getArguments(), [], 'empty arguments object yields nothing');
  82. st.iterate(getSloppyArguments(), [], 'empty sloppy arguments object yields nothing');
  83. st.iterate(getArguments(1, 2, 3), [1, 2, 3], 'arguments object yields all args');
  84. st.iterate(getSloppyArguments(1, 2, 3), [1, 2, 3], 'sloppy arguments object yields all args');
  85. st.fakeIterator(getArguments(1, 2, 3));
  86. st.fakeIterator(getSloppyArguments(1, 2, 3));
  87. st.end();
  88. });
  89. t.test('non-iterables', function (st) {
  90. var numbers = [0, -0, NaN, Infinity, 42];
  91. var nonIterables = [
  92. undefined,
  93. null,
  94. true,
  95. false,
  96. {},
  97. /a/g,
  98. function () {}
  99. ];
  100. if (hasSymbols) {
  101. nonIterables.push(Symbol.iterator);
  102. }
  103. if (hasBigInts) {
  104. nonIterables.push(BigInt(42), BigInt(0));
  105. }
  106. forEach(nonIterables, function (nonIterable) {
  107. st.noIterate(nonIterable);
  108. if (nonIterable != null) {
  109. st.fakeIterator(nonIterable);
  110. }
  111. });
  112. if (hasSymbols && NaN[Symbol.iterator]) {
  113. st.comment('# SKIP core-js v2 makes numbers iterable, in violation of the spec');
  114. }
  115. forEach(numbers, function (number) {
  116. if (!hasSymbols || !number[Symbol.iterator]) {
  117. st.noIterate(number);
  118. }
  119. st.fakeIterator(number);
  120. });
  121. st.end();
  122. });
  123. t.test('Map', { skip: typeof Map !== 'function' }, function (st) {
  124. st.iterate(new Map(), [], 'empty Map yields nothing');
  125. var entries = [
  126. [1, 'a'],
  127. [2, 'b'],
  128. [3, 'c']
  129. ];
  130. var m = collect(Map, entries);
  131. st.iterate(m, entries, inspect(m) + ' yields expected entries');
  132. st.fakeIterator(collect(Map, entries));
  133. st.end();
  134. });
  135. t.test('Set', { skip: typeof Set !== 'function' }, function (st) {
  136. st.iterate(new Set(), [], 'empty Set yields nothing');
  137. var values = [
  138. 1,
  139. 2,
  140. 3
  141. ];
  142. var s = collect(Set, values);
  143. st.iterate(s, values, inspect(s) + ' yields expected values');
  144. st.fakeIterator(collect(Set, values));
  145. st.end();
  146. });
  147. };
  148. test((process.env.TEST_VARIANT || 'standard') + ': getIterator tests', function (t) {
  149. runTests(t);
  150. t.end();
  151. });