X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/2d39b0e377c0896910ee49ae70082ba665faf986..ed1e77d3adeb83d26fd1dfb16dd84cabdcefd250:/tests/stress/array-from-with-iterator.js diff --git a/tests/stress/array-from-with-iterator.js b/tests/stress/array-from-with-iterator.js new file mode 100644 index 0000000..6d645e4 --- /dev/null +++ b/tests/stress/array-from-with-iterator.js @@ -0,0 +1,129 @@ +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); +}());