diff --git a/test/language/for-of/break-from-catch.js b/test/language/for-of/break-from-catch.js new file mode 100644 index 0000000000..b3ef56b0fd --- /dev/null +++ b/test/language/for-of/break-from-catch.js @@ -0,0 +1,29 @@ +// Copyright (C) Copyright 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.n +description: > + Control flow during body evaluation should honor `break` statements within + the `catch` block of `try` statements. +---*/ + +function* values() { + yield 1; + yield 1; +} +var iterable = values(); +var i = 0; + +for (var x of iterable) { + i++; + + try { + throw new Error(); + } catch (err) { + break; + } + + $ERROR('This code is unreachable.'); +} + +assert.sameValue(i, 1); diff --git a/test/language/for-of/break-from-try.js b/test/language/for-of/break-from-try.js new file mode 100644 index 0000000000..795b671bdb --- /dev/null +++ b/test/language/for-of/break-from-try.js @@ -0,0 +1,28 @@ +// Copyright (C) Copyright 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.n +description: > + Control flow during body evaluation should honor `break` statements within + `try` blocks. +---*/ + +function* values() { + yield 1; + yield 1; +} +var iterable = values(); +var i = 0; + +for (var x of iterable) { + i++; + + try { + break; + $ERROR('This code is unreachable.'); + } catch (err) {} + + $ERROR('This code is unreachable.'); +} + +assert.sameValue(i, 1); diff --git a/test/language/for-of/break-label.js b/test/language/for-of/break-label.js new file mode 100644 index 0000000000..30d3c6737d --- /dev/null +++ b/test/language/for-of/break-label.js @@ -0,0 +1,28 @@ +// Copyright (C) Copyright 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.n +description: > + Control flow during body evaluation should honor labeled `break` + statements. +---*/ + +function* values() { + yield 1; + yield 1; +} +var iterable = values(); +var i = 0; + +outer: +while (true) { + for (var x of iterable) { + i++; + break outer; + + $ERROR('This code is unreachable.'); + } + $ERROR('This code is unreachable.'); +} + +assert.sameValue(i, 1); diff --git a/test/language/for-of/break.js b/test/language/for-of/break.js new file mode 100644 index 0000000000..89bfc6bc42 --- /dev/null +++ b/test/language/for-of/break.js @@ -0,0 +1,23 @@ +// Copyright (C) Copyright 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.n +description: > + Control flow during body evaluation should honor `break` statements. +---*/ + +function* values() { + yield 1; + yield 1; +} +var iterable = values(); +var i = 0; + +for (var x of iterable) { + i++; + break; + + $ERROR('This code is unreachable.'); +} + +assert.sameValue(i, 1); diff --git a/test/language/for-of/continue-from-catch.js b/test/language/for-of/continue-from-catch.js new file mode 100644 index 0000000000..5a3a6ebab5 --- /dev/null +++ b/test/language/for-of/continue-from-catch.js @@ -0,0 +1,28 @@ +// Copyright (C) Copyright 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.n +description: > + Control flow during body evaluation should honor `continue` statements + within the `catch` block of `try` statements. +---*/ + +function* values() { + yield 1; + yield 1; +} +var iterable = values(); +var i = 0; + +for (var x of iterable) { + i++; + try { + throw new Error(); + } catch (err) { + continue; + } + + $ERROR('This code is unreachable.'); +} + +assert.sameValue(i, 2); diff --git a/test/language/for-of/continue-from-try.js b/test/language/for-of/continue-from-try.js new file mode 100644 index 0000000000..0378fba7f4 --- /dev/null +++ b/test/language/for-of/continue-from-try.js @@ -0,0 +1,27 @@ +// Copyright (C) Copyright 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.n +description: > + Control flow during body evaluation should honor `continue` statements + within `try` blocks. +---*/ + +function* values() { + yield 1; + yield 1; +} +var iterable = values(); +var i = 0; + +for (var x of iterable) { + i++; + try { + continue; + $ERROR('This code is unreachable.'); + } catch (err) {} + + $ERROR('This code is unreachable.'); +} + +assert.sameValue(i, 2); diff --git a/test/language/for-of/continue-label.js b/test/language/for-of/continue-label.js new file mode 100644 index 0000000000..760b9dbcf3 --- /dev/null +++ b/test/language/for-of/continue-label.js @@ -0,0 +1,30 @@ +// Copyright (C) Copyright 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.n +description: > + Control flow during body evaluation should honor labeled `continue` + statements. +---*/ + +function* values() { + yield 1; +} +var iterable = values(); +var i = 0; +var loop = true; + +outer: +while (loop) { + loop = false; + + for (var x of iterable) { + i++; + continue outer; + + $ERROR('This code is unreachable (inside for-of).'); + } + $ERROR('This code is unreachable (inside while).'); +} + +assert.sameValue(i, 1); diff --git a/test/language/for-of/continue.js b/test/language/for-of/continue.js new file mode 100644 index 0000000000..571377e924 --- /dev/null +++ b/test/language/for-of/continue.js @@ -0,0 +1,23 @@ +// Copyright (C) Copyright 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.n +description: > + Control flow during body evaluation should honor `continue` statements. +---*/ + +function* values() { + yield 1; + yield 1; +} +var iterable = values(); +var i = 0; + +for (var x of iterable) { + i++; + continue; + + $ERROR('This code is unreachable.'); +} + +assert.sameValue(i, 2); diff --git a/test/language/for-of/generator.js b/test/language/for-of/generator.js new file mode 100644 index 0000000000..7d0a5af27e --- /dev/null +++ b/test/language/for-of/generator.js @@ -0,0 +1,23 @@ +// Copyright (C) Copyright 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 +description: > + Generator function should return valid iterable objects. +---*/ + +function* values() { + yield 2; + yield 4; + yield 8; +} +var iterable = values(); +var expected = [2, 4, 8]; +var i = 0; + +for (var x of iterable) { + assert.sameValue(x, expected[i]); + i++; +} + +assert.sameValue(i, 3); diff --git a/test/language/for-of/generic-iterable.js b/test/language/for-of/generic-iterable.js new file mode 100644 index 0000000000..96cdd40271 --- /dev/null +++ b/test/language/for-of/generic-iterable.js @@ -0,0 +1,27 @@ +// Copyright (C) Copyright 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 +description: > + Generic objects with `@@iterator` protocols should function as iterables. +---*/ + +var iterable = {}; +iterable[Symbol.iterator] = function() { + var j = 0; + return { + next: function() { + j = j + 2; + return { value: j, done: j === 8 }; + } + } +}; +var expected = [2, 4, 6]; +var i = 0; + +for (var x of iterable) { + assert.sameValue(x, expected[i]); + i++; +} + +assert.sameValue(i, 3); diff --git a/test/language/for-of/head-expr-obj-iterator-method.js b/test/language/for-of/head-expr-obj-iterator-method.js new file mode 100644 index 0000000000..20b4dc6ae0 --- /dev/null +++ b/test/language/for-of/head-expr-obj-iterator-method.js @@ -0,0 +1,13 @@ +// Copyright (C) Copyright 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.12 S8.b +description: > + The value of the expression in a for-of statement's head must have an + `@@iterator` method. +---*/ +var x; + +assert.throws(TypeError, function() { + for (x of {}) {} +}); diff --git a/test/language/for-of/head-expr-primitive-iterator-method.js b/test/language/for-of/head-expr-primitive-iterator-method.js new file mode 100644 index 0000000000..0c7abe9bee --- /dev/null +++ b/test/language/for-of/head-expr-primitive-iterator-method.js @@ -0,0 +1,17 @@ +// Copyright (C) Copyright 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.12 S8.b +description: > + The value of the expression in a for-of statement's head must have an + `@@iterator` method. +---*/ +var x; + +assert.throws(TypeError, function() { + for (x of false) {} +}); + +assert.throws(TypeError, function() { + for (x of 37) {} +}); diff --git a/test/language/for-of/head-expr-to-obj.js b/test/language/for-of/head-expr-to-obj.js new file mode 100644 index 0000000000..085ca18308 --- /dev/null +++ b/test/language/for-of/head-expr-to-obj.js @@ -0,0 +1,17 @@ +// Copyright (C) Copyright 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.12 S8.b +description: > + The value of the expression in a for-of statement's head is subject to the + semantics of the ToObject abstract operation. +---*/ +var x; + +assert.throws(TypeError, function() { + for (x of null) {} +}); + +assert.throws(TypeError, function() { + for (x of undefined) {} +}); diff --git a/test/language/for-of/iterator-as-proxy.js b/test/language/for-of/iterator-as-proxy.js new file mode 100644 index 0000000000..c9b975d414 --- /dev/null +++ b/test/language/for-of/iterator-as-proxy.js @@ -0,0 +1,35 @@ +// Copyright (C) Copyright 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 +description: > + Iterators that are implemented as proxies should behave identically to + non-proxy versions. +---*/ + +var iterable = {}; +var nextResult = { value: 23, done: false }; +var lastResult = { value: null, done: true }; +var i; + +var iterator = { + next: function() { + var result = nextResult; + nextResult = lastResult; + return result; + } +}; +var proxiedIterator = new Proxy(iterator, { + get: function(target, name) { + return target[name]; + } +}); +iterable[Symbol.iterator] = function() { return proxiedIterator; }; + +i = 0; +for (var x of iterable) { + assert.sameValue(x, 23); + i++; +} + +assert.sameValue(i, 1); diff --git a/test/language/for-of/iterator-next-reference.js b/test/language/for-of/iterator-next-reference.js new file mode 100644 index 0000000000..8770b406d5 --- /dev/null +++ b/test/language/for-of/iterator-next-reference.js @@ -0,0 +1,40 @@ +// Copyright (C) Copyright 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 +description: > + The iterator's `next` method should be accessed with each iteration as per + the `IteratorStep` abstract operation (7.4.5). +---*/ + +var iterable = {}; +var iterator = {}; +var firstIterResult = { done: false }; +var iterationCount, invocationCount; + +iterable[Symbol.iterator] = function() { + return iterator; +}; + +iterator.next = function() { return { value: 45, done: false }; }; +iterationCount = 0; +invocationCount = 0; +for (var x of iterable) { + assert.sameValue(x, 45); + + iterator.next = function() { + invocationCount++; + + Object.defineProperty(iterator, 'next', { + get: function() { + $ERROR('Should not access the `next` method after iteration ' + + 'is complete.'); + } + }); + + return { value: null, done: true }; + }; + iterationCount++; +} +assert.sameValue(iterationCount, 1); +assert.sameValue(invocationCount, 1); diff --git a/test/language/for-of/iterator-next-result-done-attr.js b/test/language/for-of/iterator-next-result-done-attr.js new file mode 100644 index 0000000000..50c9f414cd --- /dev/null +++ b/test/language/for-of/iterator-next-result-done-attr.js @@ -0,0 +1,129 @@ +// Copyright (C) Copyright 2013 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +es6id: 7.4.3 +description: > + The `done` value of iteration result objects should be interpreted as + incomplete as per `ToBoolean` (7.1.2). +---*/ + +var iterable = {}; +var i, firstIterResult; + +iterable[Symbol.iterator] = function() { + var finalIterResult = { value: null, done: true }; + var nextIterResult = firstIterResult; + + return { + next: function() { + var iterResult = nextIterResult; + + nextIterResult = finalIterResult; + + return iterResult; + } + }; +}; + +firstIterResult = { value: null, done: undefined }; +i = 0; +for (var x of iterable) { + i++; +} +assert.sameValue(i, 1); + +firstIterResult = { value: null }; +i = 0; +for (var x of iterable) { + i++; +} +assert.sameValue(i, 1); + +firstIterResult = { value: null, done: null }; +i = 0; +for (var x of iterable) { + i++; +} +assert.sameValue(i, 1); + +firstIterResult = { value: null, done: false }; +i = 0; +for (var x of iterable) { + i++; +} +assert.sameValue(i, 1); + +firstIterResult = { value: null, done: true }; +i = 0; +for (var x of iterable) { + i++; +} +assert.sameValue(i, 0); + +firstIterResult = { value: null, done: 1 }; +i = 0; +for (var x of iterable) { + i++; +} +assert.sameValue(i, 0); + +firstIterResult = { value: null, done: 0 }; +i = 0; +for (var x of iterable) { + i++; +} +assert.sameValue(i, 1); + +firstIterResult = { value: null, done: -0 }; +i = 0; +for (var x of iterable) { + i++; +} +assert.sameValue(i, 1); + +firstIterResult = { value: null, done: NaN }; +i = 0; +for (var x of iterable) { + i++; +} +assert.sameValue(i, 1); + +firstIterResult = { value: null, done: '' }; +i = 0; +for (var x of iterable) { + i++; +} +assert.sameValue(i, 1); + +firstIterResult = { value: null, done: '0' }; +i = 0; +for (var x of iterable) { + i++; +} +assert.sameValue(i, 0); + +firstIterResult = { value: null, done: Symbol() }; +i = 0; +for (var x of iterable) { + i++; +} +assert.sameValue(i, 0); + +firstIterResult = { value: null, done: {} }; +i = 0; +for (var x of iterable) { + i++; +} +assert.sameValue(i, 0); + +firstIterResult = { value: null }; +Object.defineProperty(firstIterResult, 'done', { + get: function() { + return true; + } +}); +i = 0; +for (var x of iterable) { + i++; +} +assert.sameValue(i, 0); diff --git a/test/language/for-of/iterator-next-result-type.js b/test/language/for-of/iterator-next-result-type.js new file mode 100644 index 0000000000..351ce1b97a --- /dev/null +++ b/test/language/for-of/iterator-next-result-type.js @@ -0,0 +1,105 @@ +// Copyright (C) Copyright 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 +description: > + If Type(result) is not Object, throw a TypeError exception as per + `IteratorNext` (7.4.2 S4) +---*/ + +var iterable = {}; +var firstIterResult; + +iterable[Symbol.iterator] = function() { + var finalIterResult = { value: null, done: true }; + var nextIterResult = firstIterResult; + + return { + next: function() { + var iterResult = nextIterResult; + + nextIterResult = finalIterResult; + + return iterResult; + } + }; +}; + +firstIterResult = true; +assert.throws(TypeError, function() { + for (var x of iterable) {} +}); + +firstIterResult = false; +assert.throws(TypeError, function() { + for (var x of iterable) {} +}); + +firstIterResult = 'string'; +assert.throws(TypeError, function() { + for (var x of iterable) {} +}); + +firstIterResult = undefined; +assert.throws(TypeError, function() { + for (var x of iterable) {} +}); + +firstIterResult = null; +assert.throws(TypeError, function() { + for (var x of iterable) {} +}); + +firstIterResult = 4; +assert.throws(TypeError, function() { + for (var x of iterable) {} +}); + +firstIterResult = NaN; +assert.throws(TypeError, function() { + for (var x of iterable) {} +}); + +firstIterResult = Symbol('s'); +assert.throws(TypeError, function() { + for (var x of iterable) {} +}); + +firstIterResult = /regexp/; +for (var x of iterable) {} + +firstIterResult = {}; +for (var x of iterable) {} + +firstIterResult = new Proxy({}, { + get: function(receiver, name) { + if (name === 'done') { + return true; + } + if (name === 'value') { + return null; + } + $ERROR('This code is unreachable.'); + } +}); +for (var x of iterable) { + $ERROR('This code is unreachable.'); +} + +firstIterResult = new Proxy({}, { + get: function(receiver, name) { + if (name === 'done') { + return false; + } + if (name === 'value') { + return 23; + } + $ERROR('This code is unreachable.'); + } +}); +i = 0; +for (var x of iterable) { + assert.sameValue(x, 23); + i++; +} +assert.sameValue(i, 1); diff --git a/test/language/for-of/iterator-next-result-value-attr.js b/test/language/for-of/iterator-next-result-value-attr.js new file mode 100644 index 0000000000..1afda16b1d --- /dev/null +++ b/test/language/for-of/iterator-next-result-value-attr.js @@ -0,0 +1,47 @@ +// Copyright (C) Copyright 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 +description: > + The `done` value of iteration result objects should be interpreted as + incomplete as per `ToBoolean` (7.1.2). +---*/ + +var iterable = {}; +var i, firstIterResult; + +iterable[Symbol.iterator] = function() { + var finalIterResult = { value: null, done: true }; + var nextIterResult = firstIterResult; + + return { + next: function() { + var iterResult = nextIterResult; + + nextIterResult = finalIterResult; + + return iterResult; + } + }; +}; + +firstIterResult = { value: 45, done: false }; +i = 0; +for (var x of iterable) { + assert.sameValue(x, 45); + i++; +} +assert.sameValue(i, 1); + +firstIterResult = { done: false }; +Object.defineProperty(firstIterResult, 'value', { + get: function() { + return 23; + } +}); +i = 0; +for (var x of iterable) { + assert.sameValue(x, 23); + i++; +} +assert.sameValue(i, 1); diff --git a/test/language/for-of/nested.js b/test/language/for-of/nested.js new file mode 100644 index 0000000000..eedfbda798 --- /dev/null +++ b/test/language/for-of/nested.js @@ -0,0 +1,37 @@ +// Copyright (C) Copyright 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 +description: > + Nested statements should operate independently. +---*/ + +function* values() { + yield 3; + yield 7; +} + +var outerIterable, expectedOuter, i, innerIterable, expectedInner, j; + +outerIterable = values(); +expectedOuter = 3; +i = 0; + +for (var x of outerIterable) { + assert.sameValue(x, expectedOuter); + expectedOuter = 7; + i++; + + innerIterable = values(); + expectedInner = 3; + j = 0; + for (var y of innerIterable) { + assert.sameValue(y, expectedInner); + expectedInner = 7; + j++; + } + + assert.sameValue(j, 2); +} + +assert.sameValue(i, 2); diff --git a/test/language/for-of/return.js b/test/language/for-of/return.js new file mode 100644 index 0000000000..b849d0ba58 --- /dev/null +++ b/test/language/for-of/return.js @@ -0,0 +1,28 @@ +// Copyright (C) Copyright 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 +description: > + Control flow during body evaluation should honor `return` statements. +---*/ + +function* values() { + yield 1; + yield 1; +} +var iterable = values(); +var i = 0; + +var result = (function() { + for (var x of iterable) { + i++; + return 34; + + $ERROR('This code is unreachable.'); + } + + $ERROR('This code is unreachable.'); +})(); + +assert.sameValue(result, 34); +assert.sameValue(i, 1);