| function shouldBe(actual, expected) { |
| if (actual !== expected) |
| throw new Error('bad value: ' + actual); |
| } |
| |
| function shouldThrow(func, message) { |
| var error = null; |
| try { |
| func(); |
| } catch (e) { |
| error = e; |
| } |
| if (!error) |
| throw new Error("not thrown."); |
| if (String(error) !== message) |
| throw new Error("bad error: " + String(error)); |
| } |
| |
| var originalArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; |
| |
| var array = Array.from(originalArray.values()); |
| shouldBe(array.length, originalArray.length); |
| for (var i = 0; i < array.length; ++i) { |
| shouldBe(array[i], originalArray[i]); |
| } |
| |
| function createIterator(callback) { |
| var array = [0,1,2,3,4,5]; |
| var iterator = array[Symbol.iterator](); |
| iterator.return = function () { |
| iterator.returned = true; |
| if (callback) |
| return callback(this); |
| return { done: true, value: undefined }; |
| }; |
| iterator.returned = false; |
| return iterator; |
| } |
| |
| var iterator = createIterator(); |
| var result = Array.from(iterator); |
| shouldBe(result.length, 6); |
| for (var i = 0; i < 6; ++i) { |
| shouldBe(result[i], i); |
| } |
| shouldBe(iterator.returned, false); |
| |
| // mapFn raises an error. |
| var iterator = createIterator(); |
| shouldThrow(function () { |
| var result = Array.from(iterator, function () { |
| throw new Error('map func'); |
| }); |
| }, "Error: map func"); |
| shouldBe(iterator.returned, true); |
| |
| // mapFn raises an error and iterator.return also raises an error. |
| var iterator = createIterator(function () { |
| throw new Error('iterator.return'); |
| }); |
| |
| // An error raised in iterator.return is discarded. |
| shouldThrow(function () { |
| var result = Array.from(iterator, function () { |
| throw new Error('map func'); |
| }); |
| }, "Error: map func"); |
| shouldBe(iterator.returned, true); |
| |
| // iterable[Symbol.iterator] is not a function. |
| shouldThrow(function () { |
| var iterator = [].values(); |
| iterator[Symbol.iterator] = {}; |
| Array.from(iterator); |
| }, "TypeError: Array.from requires that the property of the first argument, items[Symbol.iterator], when exists, be a function"); |
| |
| // iterable[Symbol.iterator] raises an error. |
| shouldThrow(function () { |
| var iterable = []; |
| iterable[Symbol.iterator] = function () { |
| throw new Error("iterator"); |
| }; |
| Array.from(iterable); |
| }, "Error: iterator"); |
| |
| // iterable[Symbol.iterator] lookup is only once. |
| (function () { |
| var iterable = [0, 1, 2, 3, 4, 5]; |
| var count = 0; |
| var iteratorCallCount = 0; |
| Object.defineProperty(iterable, Symbol.iterator, { |
| get() { |
| ++count; |
| return function () { |
| ++iteratorCallCount; |
| return this.values(); |
| }; |
| } |
| }); |
| var generated = Array.from(iterable); |
| shouldBe(generated.length, iterable.length); |
| for (var i = 0; i < iterable.length; ++i) { |
| shouldBe(generated[i], iterable[i]); |
| } |
| shouldBe(count, 1); |
| shouldBe(iteratorCallCount, 1); |
| }()); |
| |
| // The Symbol.iterator method of the iterator generated by iterable[Symbol.iterator] is not looked up. |
| (function () { |
| var iterable = [0, 1, 2, 3, 4, 5]; |
| var count = 0; |
| iterable[Symbol.iterator] = function () { |
| ++count; |
| var iterator = this.values(); |
| Object.defineProperty(iterator, Symbol.iterator, { |
| get() { |
| throw new Error('iterator[@@iterator] is touched'); |
| } |
| }); |
| return iterator; |
| }; |
| var generated = Array.from(iterable); |
| shouldBe(generated.length, iterable.length); |
| for (var i = 0; i < iterable.length; ++i) { |
| shouldBe(generated[i], iterable[i]); |
| } |
| shouldBe(count, 1); |
| }()); |