diff --git a/test/language/statements/for-of/body-dstr-assign-error.js b/test/language/statements/for-of/body-dstr-assign-error.js new file mode 100644 index 0000000000000000000000000000000000000000..4e063574c1186361fcfb55bdb0e93f5a107e3bdf --- /dev/null +++ b/test/language/statements/for-of/body-dstr-assign-error.js @@ -0,0 +1,39 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 13.6.4.13 S5.i.i +description: > + If the left-hand side requires a DestructuringAssignment operation and that + operation produces an error, the iterator should be closed and the error + forwarded to the runtime. +features: [Symbol.iterator] +---*/ + +var callCount = 0; +var iterationCount = 0; +var iterable = {}; +var x = { + set attr(_) { + throw new Test262Error(); + } +}; + +iterable[Symbol.iterator] = function() { + return { + next: function() { + return { done: false, value: [0] }; + }, + return: function() { + callCount += 1; + } + } +}; + +assert.throws(Test262Error, function() { + for ([x.attr] of iterable) { + iterationCount += 1; + } +}); + +assert.sameValue(iterationCount, 0, 'The loop body is not evaluated'); +assert.sameValue(callCount, 1, 'Iterator is closed'); diff --git a/test/language/statements/for-of/body-dstr-assign.js b/test/language/statements/for-of/body-dstr-assign.js new file mode 100644 index 0000000000000000000000000000000000000000..0bb9007c7d6c8ce3f3bef1a54948401a5991b4a3 --- /dev/null +++ b/test/language/statements/for-of/body-dstr-assign.js @@ -0,0 +1,17 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 13.6.4.13 S5.i.i +description: > + The left-hand side may take the form of a DestructuringAssignment. +---*/ + +var iterationCount = 0; +var x; + +for ([x] of [[0]]) { + assert.sameValue(x, 0); + iterationCount += 1; +} + +assert.sameValue(iterationCount, 1); diff --git a/test/language/statements/for-of/body-put-error.js b/test/language/statements/for-of/body-put-error.js new file mode 100644 index 0000000000000000000000000000000000000000..dd339e7e02071097ecfe185a50224c988a259b6b --- /dev/null +++ b/test/language/statements/for-of/body-put-error.js @@ -0,0 +1,39 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 13.6.4.13 S5.h.ii +description: > + If the left-hand side is not a lexical binding and the assignment produces + an error, the iterator should be closed and the error forwarded to the + runtime. +features: [Symbol.iterator] +---*/ + +var callCount = 0; +var iterationCount = 0; +var iterable = {}; +var x = { + set attr(_) { + throw new Test262Error(); + } +}; + +iterable[Symbol.iterator] = function() { + return { + next: function() { + return { done: false, value: 0 }; + }, + return: function() { + callCount += 1; + } + } +}; + +assert.throws(Test262Error, function() { + for (x.attr of iterable) { + iterationCount += 1; + } +}); + +assert.sameValue(iterationCount, 0, 'The loop body is not evaluated'); +assert.sameValue(callCount, 1, 'Iterator is closed'); diff --git a/test/language/statements/for-of/generator-close-via-break.js b/test/language/statements/for-of/generator-close-via-break.js new file mode 100644 index 0000000000000000000000000000000000000000..ca18fde77b04f427b3441acf5bdbd28fa07bd5d6 --- /dev/null +++ b/test/language/statements/for-of/generator-close-via-break.js @@ -0,0 +1,47 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 13.6.4.13 +description: > + Generators should be closed via their `return` method when iteration is + interrupted via a `break` statement. +features: [generators] +---*/ + +var startedCount = 0; +var finallyCount = 0; +var iterationCount = 0; +function* values() { + startedCount += 1; + try { + yield; + $ERROR('This code is unreachable (within `try` block)'); + } finally { + finallyCount += 1; + } + $ERROR('This code is unreachable (following `try` statement)'); +} +var iterable = values(); + +assert.sameValue( + startedCount, 0, 'Generator is initialized in suspended state' +); + +for (var x of iterable) { + assert.sameValue( + startedCount, 1, 'Generator executes prior to first iteration' + ); + assert.sameValue( + finallyCount, 0, 'Generator is paused during first iteration' + ); + iterationCount += 1; + break; +} + +assert.sameValue( + startedCount, 1, 'Generator does not restart following interruption' +); +assert.sameValue(iterationCount, 1, 'A single iteration occurs'); +assert.sameValue( + finallyCount, 1, 'Generator is closed after `break` statement' +); diff --git a/test/language/statements/for-of/generator-close-via-return.js b/test/language/statements/for-of/generator-close-via-return.js new file mode 100644 index 0000000000000000000000000000000000000000..a5963fae59a78c3881662e2d4322b608e0aa20c6 --- /dev/null +++ b/test/language/statements/for-of/generator-close-via-return.js @@ -0,0 +1,49 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 13.6.4.13 +description: > + Generators should be closed via their `return` method when iteration is + interrupted via a `return` statement. +features: [generators] +---*/ + +var startedCount = 0; +var finallyCount = 0; +var iterationCount = 0; +function* values() { + startedCount += 1; + try { + yield; + $ERROR('This code is unreachable (within `try` block)'); + } finally { + finallyCount += 1; + } + $ERROR('This code is unreachable (following `try` statement)'); +} +var iterable = values(); + +assert.sameValue( + startedCount, 0, 'Generator is initialized in suspended state' +); + +(function() { + for (var x of iterable) { + assert.sameValue( + startedCount, 1, 'Generator executes prior to first iteration' + ); + assert.sameValue( + finallyCount, 0, 'Generator is paused during first iteration' + ); + iterationCount += 1; + return; + } +}()); + +assert.sameValue( + startedCount, 1, 'Generator does not restart following interruption' +); +assert.sameValue(iterationCount, 1, 'A single iteration occurs'); +assert.sameValue( + finallyCount, 1, 'Generator is closed after `return` statement' +); diff --git a/test/language/statements/for-of/generator-close-via-throw.js b/test/language/statements/for-of/generator-close-via-throw.js new file mode 100644 index 0000000000000000000000000000000000000000..bbdadaf19bb16259fffaa9196418be4dea72c438 --- /dev/null +++ b/test/language/statements/for-of/generator-close-via-throw.js @@ -0,0 +1,49 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 13.6.4.13 +description: > + Generators should be closed via their `return` method when iteration is + interrupted via a `throw` statement. +features: [generators] +---*/ + +var startedCount = 0; +var finallyCount = 0; +var iterationCount = 0; +function* values() { + startedCount += 1; + try { + yield; + $ERROR('This code is unreachable (within `try` block)'); + } finally { + finallyCount += 1; + } + $ERROR('This code is unreachable (following `try` statement)'); +} +var iterable = values(); + +assert.sameValue( + startedCount, 0, 'Generator is initialized in suspended state' +); + +try { + for (var x of iterable) { + assert.sameValue( + startedCount, 1, 'Generator executes prior to first iteration' + ); + assert.sameValue( + finallyCount, 0, 'Generator is paused during first iteration' + ); + iterationCount += 1; + throw 0; + } +} catch(err) {} + +assert.sameValue( + startedCount, 1, 'Generator does not restart following interruption' +); +assert.sameValue(iterationCount, 1, 'A single iteration occurs'); +assert.sameValue( + finallyCount, 1, 'Generator is closed after `throw` statement' +); diff --git a/test/language/statements/for-of/generator-next-error.js b/test/language/statements/for-of/generator-next-error.js new file mode 100644 index 0000000000000000000000000000000000000000..d284c5c252f4b59114c11f4c3ea2e756d88b25b7 --- /dev/null +++ b/test/language/statements/for-of/generator-next-error.js @@ -0,0 +1,22 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 13.6.4.13 S5.g +description: > + If `nextResult` is an abrupt completion as per IteratorStep (ES6 7.4.5), + return the completion. +features: [generators] +---*/ + +var iterable = (function*() { + throw new Test262Error(); +}()); +var iterationCount = 0; + +assert.throws(Test262Error, function() { + for (var x of iterable) { + iterationCount += 1; + } +}); + +assert.sameValue(iterationCount, 0, 'The loop body is not evaluated'); diff --git a/test/language/statements/for-of/generator.js b/test/language/statements/for-of/generator.js index 68a27ec4c192ce4378a3a762fa019d354b6dfe88..0caaaee8a959e54c79e47eda7e35336923677d67 100644 --- a/test/language/statements/for-of/generator.js +++ b/test/language/statements/for-of/generator.js @@ -4,6 +4,7 @@ es6id: 13.6.4.13 description: > Generator function should return valid iterable objects. +features: [generators] ---*/ function* values() { diff --git a/test/language/statements/for-of/generic-iterable.js b/test/language/statements/for-of/generic-iterable.js index f1e6d978bea121b6c2d1a99c980d19c3e025554f..b862c336d6d4df03d372c46de3e19abc2f728631 100644 --- a/test/language/statements/for-of/generic-iterable.js +++ b/test/language/statements/for-of/generic-iterable.js @@ -4,6 +4,7 @@ es6id: 13.6.4.13 description: > Generic objects with `@@iterator` protocols should function as iterables. +features: [Symbol.iterator] ---*/ var iterable = {}; diff --git a/test/language/statements/for-of/iterator-as-proxy.js b/test/language/statements/for-of/iterator-as-proxy.js index cfb318ee596c1d694fbe0a3439cde34d6d333220..181e963e659643c4dc59621c115f1470df0634ba 100644 --- a/test/language/statements/for-of/iterator-as-proxy.js +++ b/test/language/statements/for-of/iterator-as-proxy.js @@ -5,6 +5,7 @@ es6id: 13.6.4.13 description: > Iterators that are implemented as proxies should behave identically to non-proxy versions. +features: [Proxy, Symbol.iterator] ---*/ var iterable = {}; diff --git a/test/language/statements/for-of/iterator-close-get-method-error.js b/test/language/statements/for-of/iterator-close-get-method-error.js new file mode 100644 index 0000000000000000000000000000000000000000..cec2854534f07947b405fa0b4afb1af615745dff --- /dev/null +++ b/test/language/statements/for-of/iterator-close-get-method-error.js @@ -0,0 +1,32 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 13.6.4.13 +description: > + If retrieving an iterator's `return` method generates an error while + closing the iterator, the error should be forwarded to the runtime. +features: [Symbol.iterator] +---*/ + +var iterable = {}; +var iterationCount = 0; + +iterable[Symbol.iterator] = function() { + return { + next: function() { + return { done: false, value: null }; + }, + get return() { + throw new Test262Error(); + } + }; +}; + +assert.throws(Test262Error, function() { + for (var x of iterable) { + iterationCount += 1; + break; + } +}); + +assert.sameValue(iterationCount, 1, 'The loop body is evaluated'); diff --git a/test/language/statements/for-of/iterator-close-non-object.js b/test/language/statements/for-of/iterator-close-non-object.js new file mode 100644 index 0000000000000000000000000000000000000000..5f53f43ede3555062f32b042f483bc669bb94789 --- /dev/null +++ b/test/language/statements/for-of/iterator-close-non-object.js @@ -0,0 +1,32 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 13.6.4.13 +description: > + If an iterator's `return` method returns a non-Object value, a TypeError + should be thrown. +features: [Symbol.iterator] +---*/ + +var iterable = {}; +var iterationCount = 0; + +iterable[Symbol.iterator] = function() { + return { + next: function() { + return { done: false, value: null }; + }, + return: function() { + return 0; + } + }; +}; + +assert.throws(TypeError, function() { + for (var x of iterable) { + iterationCount += 1; + break; + } +}); + +assert.sameValue(iterationCount, 1, 'The loop body is evaluated'); diff --git a/test/language/statements/for-of/iterator-close-via-break.js b/test/language/statements/for-of/iterator-close-via-break.js new file mode 100644 index 0000000000000000000000000000000000000000..f78664f7613fe6d4d5b87e1db43454b4e7f16e53 --- /dev/null +++ b/test/language/statements/for-of/iterator-close-via-break.js @@ -0,0 +1,46 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 13.6.4.13 +description: > + Iterators should be closed via their `return` method when iteration is + interrupted via a `break` statement. +features: [Symbol.iterator] +---*/ + +var startedCount = 0; +var returnCount = 0; +var iterationCount = 0; +var iterable = {}; + +iterable[Symbol.iterator] = function() { + return { + next: function() { + startedCount += 1; + return { done: false, value: null }; + }, + return: function() { + returnCount += 1; + return {}; + } + }; +}; + +for (var x of iterable) { + assert.sameValue( + startedCount, 1, 'Value is retrieved' + ); + assert.sameValue( + returnCount, 0, 'Iterator is not closed' + ); + iterationCount += 1; + break; +} + +assert.sameValue( + startedCount, 1, 'Iterator does not restart following interruption' +); +assert.sameValue(iterationCount, 1, 'A single iteration occurs'); +assert.sameValue( + returnCount, 1, 'Iterator is closed after `break` statement' +); diff --git a/test/language/statements/for-of/iterator-close-via-return.js b/test/language/statements/for-of/iterator-close-via-return.js new file mode 100644 index 0000000000000000000000000000000000000000..5748c241972caf29f73dc6d0f76770f1d2937111 --- /dev/null +++ b/test/language/statements/for-of/iterator-close-via-return.js @@ -0,0 +1,48 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 13.6.4.13 +description: > + Iterators should be closed via their `return` method when iteration is + interrupted via a `return` statement. +features: [Symbol.iterator] +---*/ + +var startedCount = 0; +var returnCount = 0; +var iterationCount = 0; +var iterable = {}; + +iterable[Symbol.iterator] = function() { + return { + next: function() { + startedCount += 1; + return { done: false, value: null }; + }, + return: function() { + returnCount += 1; + return {}; + } + }; +}; + +(function() { + for (var x of iterable) { + assert.sameValue( + startedCount, 1, 'Value is retrieved' + ); + assert.sameValue( + returnCount, 0, 'Iterator is not closed' + ); + iterationCount += 1; + return; + } +}()); + +assert.sameValue( + startedCount, 1, 'Iterator does not restart following interruption' +); +assert.sameValue(iterationCount, 1, 'A single iteration occurs'); +assert.sameValue( + returnCount, 1, 'Iterator is closed after `return` statement' +); diff --git a/test/language/statements/for-of/iterator-close-via-throw.js b/test/language/statements/for-of/iterator-close-via-throw.js new file mode 100644 index 0000000000000000000000000000000000000000..1245c940e15fd8f9bd7c34a5b1d1371d975e63d5 --- /dev/null +++ b/test/language/statements/for-of/iterator-close-via-throw.js @@ -0,0 +1,48 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 13.6.4.13 +description: > + Iterators should be closed via their `return` method when iteration is + interrupted via a `throw` statement. +features: [Symbol.iterator] +---*/ + +var startedCount = 0; +var returnCount = 0; +var iterationCount = 0; +var iterable = {}; + +iterable[Symbol.iterator] = function() { + return { + next: function() { + startedCount += 1; + return { done: false, value: null }; + }, + return: function() { + returnCount += 1; + return {}; + } + }; +}; + +try { + for (var x of iterable) { + assert.sameValue( + startedCount, 1, 'Value is retrieved' + ); + assert.sameValue( + returnCount, 0, 'Iterator is not closed' + ); + iterationCount += 1; + throw 0; + } +} catch (err) {} + +assert.sameValue( + startedCount, 1, 'Iterator does not restart following interruption' +); +assert.sameValue(iterationCount, 1, 'A single iteration occurs'); +assert.sameValue( + returnCount, 1, 'Iterator is closed after `throw` statement' +); diff --git a/test/language/statements/for-of/iterator-next-error.js b/test/language/statements/for-of/iterator-next-error.js new file mode 100644 index 0000000000000000000000000000000000000000..bcecc0bb4c583c93f7d0d20927f3456b06961391 --- /dev/null +++ b/test/language/statements/for-of/iterator-next-error.js @@ -0,0 +1,28 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 13.6.4.13 S5.d +description: > + If `nextResult` is an abrupt completion as per IteratorStep (ES6 7.4.5), + return the completion. +features: [Symbol.iterator] +---*/ + +var iterable = {}; +var iterationCount = 0; + +iterable[Symbol.iterator] = function() { + return { + next: function() { + throw new Test262Error(); + } + }; +}; + +assert.throws(Test262Error, function() { + for (var x of iterable) { + iterationCount += 1; + } +}); + +assert.sameValue(iterationCount, 0, 'The loop body is not evaluated'); diff --git a/test/language/statements/for-of/iterator-next-reference.js b/test/language/statements/for-of/iterator-next-reference.js index c661bd24b0114f84d59668b0c83ed8568e61ea99..3fd8ebad54ce5a01731bf59dafc2d8631e8009aa 100644 --- a/test/language/statements/for-of/iterator-next-reference.js +++ b/test/language/statements/for-of/iterator-next-reference.js @@ -5,6 +5,7 @@ es6id: 13.6.4.13 S5.c description: > The iterator's `next` method should be accessed with each iteration as per the `IteratorStep` abstract operation (7.4.5). +features: [Symbol.iterator] ---*/ var iterable = {}; diff --git a/test/language/statements/for-of/iterator-next-result-done-attr.js b/test/language/statements/for-of/iterator-next-result-done-attr.js index 2ae62891b1cbb7c7a8b3f7c270cc2abfb7e84167..cc793dd9afc2bd9f5e3c8da1aa5ab10f6196eee1 100644 --- a/test/language/statements/for-of/iterator-next-result-done-attr.js +++ b/test/language/statements/for-of/iterator-next-result-done-attr.js @@ -5,6 +5,7 @@ es6id: 7.4.3 description: > The `done` value of iteration result objects should be interpreted as incomplete as per `ToBoolean` (7.1.2). +features: [Symbol.iterator] ---*/ var iterable = {}; diff --git a/test/language/statements/for-of/iterator-next-result-type.js b/test/language/statements/for-of/iterator-next-result-type.js index 6ef932c83f8fa01dee3c4fd17a8fe669eb313eca..1b27b856a64ac0da125e2446fbb63b9f9e5748f6 100644 --- a/test/language/statements/for-of/iterator-next-result-type.js +++ b/test/language/statements/for-of/iterator-next-result-type.js @@ -5,6 +5,7 @@ es6id: 13.6.4.13 S5.c description: > If Type(result) is not Object, throw a TypeError exception as per `IteratorNext` (7.4.2 S4) +features: [Symbol.iterator] ---*/ var iterable = {}; diff --git a/test/language/statements/for-of/iterator-next-result-value-attr-error.js b/test/language/statements/for-of/iterator-next-result-value-attr-error.js new file mode 100644 index 0000000000000000000000000000000000000000..9344c5ec328e98d2ea6c103fb6770ad87e7d02c7 --- /dev/null +++ b/test/language/statements/for-of/iterator-next-result-value-attr-error.js @@ -0,0 +1,33 @@ +// Copyright (C) 2015 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 13.6.4.13 S5.g +description: > + If `nextValue` is an abrupt completion as per IteratorValue (ES6 7.4.4), + return the completion. +features: [Symbol.iterator] +---*/ + +var iterable = {}; +var iterationCount = 0; + +iterable[Symbol.iterator] = function() { + return { + next: function() { + return { + done: false, + get value() { + throw new Test262Error(); + } + }; + } + }; +}; + +assert.throws(Test262Error, function() { + for (var x of iterable) { + iterationCount += 1; + } +}); + +assert.sameValue(iterationCount, 0, 'The loop body is not evaluated'); diff --git a/test/language/statements/for-of/iterator-next-result-value-attr.js b/test/language/statements/for-of/iterator-next-result-value-attr.js index a0545c53f2c438853cd99d858aa6229669acc9c1..5448efed3531c1f0a3952222410125ebd9f6eb24 100644 --- a/test/language/statements/for-of/iterator-next-result-value-attr.js +++ b/test/language/statements/for-of/iterator-next-result-value-attr.js @@ -1,10 +1,11 @@ // Copyright (C) 2013 the V8 project authors. All rights reserved. // This code is governed by the BSD license found in the LICENSE file. /*--- -es6id: 13.6.4.13 S5.c +es6id: 13.6.4.13 S5.f description: > - The `done` value of iteration result objects should be interpreted as - incomplete as per `ToBoolean` (7.1.2). + The `value` of iteration result objects should be retrieved using the Get + abstract operation. +features: [Symbol.iterator] ---*/ var iterable = {};