From a2b3370b0bff30007033d1c4553e932193116b8b Mon Sep 17 00:00:00 2001 From: jugglinmike Date: Fri, 10 Jun 2016 15:08:59 -0400 Subject: [PATCH] Add tests for additional uses of @@toPrimitive (#666) --- .../Date/value-get-symbol-to-prim-err.js | 33 ++++++++++ .../Date/value-symbol-to-prim-err.js | 36 +++++++++++ .../Date/value-symbol-to-prim-invocation.js | 48 ++++++++++++++ .../Date/value-symbol-to-prim-return-obj.js | 45 +++++++++++++ .../Date/value-symbol-to-prim-return-prim.js | 45 +++++++++++++ .../addition/coerce-symbol-to-prim-err.js | 55 ++++++++++++++++ .../coerce-symbol-to-prim-invocation.js | 59 +++++++++++++++++ .../coerce-symbol-to-prim-return-obj.js | 48 ++++++++++++++ .../coerce-symbol-to-prim-return-prim.js | 64 +++++++++++++++++++ .../addition/get-symbol-to-prim-err.js | 51 +++++++++++++++ 10 files changed, 484 insertions(+) create mode 100644 test/built-ins/Date/value-get-symbol-to-prim-err.js create mode 100644 test/built-ins/Date/value-symbol-to-prim-err.js create mode 100644 test/built-ins/Date/value-symbol-to-prim-invocation.js create mode 100644 test/built-ins/Date/value-symbol-to-prim-return-obj.js create mode 100644 test/built-ins/Date/value-symbol-to-prim-return-prim.js create mode 100644 test/language/expressions/addition/coerce-symbol-to-prim-err.js create mode 100644 test/language/expressions/addition/coerce-symbol-to-prim-invocation.js create mode 100644 test/language/expressions/addition/coerce-symbol-to-prim-return-obj.js create mode 100644 test/language/expressions/addition/coerce-symbol-to-prim-return-prim.js create mode 100644 test/language/expressions/addition/get-symbol-to-prim-err.js diff --git a/test/built-ins/Date/value-get-symbol-to-prim-err.js b/test/built-ins/Date/value-get-symbol-to-prim-err.js new file mode 100644 index 0000000000..b329d13cdc --- /dev/null +++ b/test/built-ins/Date/value-get-symbol-to-prim-err.js @@ -0,0 +1,33 @@ +// Copyright (c) 2016 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-date-value +es6id: 20.3.2.2 +description: > + Behavior when error thrown while accessing `Symbol.toPrimitive` property +info: > + [...] + 3. If NewTarget is not undefined, then + a. If Type(value) is Object and value has a [[DateValue]] internal slot, + then + [...] + b. Else, + i. Let v be ? ToPrimitive(value). + + ES6 Section 7.1.1 ToPrimitive ( input [, PreferredType] ) + + [...] + 4. Let exoticToPrim be GetMethod(input, @@toPrimitive). + 5. ReturnIfAbrupt(exoticToPrim). +features: [Symbol.toPrimitive] +---*/ + +var y = Object.defineProperty({}, Symbol.toPrimitive, { + get: function() { + throw new Test262Error(); + } +}); + +assert.throws(Test262Error, function() { + new Date(y); +}); diff --git a/test/built-ins/Date/value-symbol-to-prim-err.js b/test/built-ins/Date/value-symbol-to-prim-err.js new file mode 100644 index 0000000000..59311e5829 --- /dev/null +++ b/test/built-ins/Date/value-symbol-to-prim-err.js @@ -0,0 +1,36 @@ +// Copyright (c) 2016 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-date-value +es6id: 20.3.2.2 +description: > + Behavior when error thrown by invocation of `Symbol.toPrimitive` method + during coercion +info: > + [...] + 3. If NewTarget is not undefined, then + a. If Type(value) is Object and value has a [[DateValue]] internal slot, + then + [...] + b. Else, + i. Let v be ? ToPrimitive(value). + + ES6 Section 7.1.1 ToPrimitive ( input [, PreferredType] ) + + [...] + 4. Let exoticToPrim be GetMethod(input, @@toPrimitive). + 5. ReturnIfAbrupt(exoticToPrim). + 6. If exoticToPrim is not undefined, then + a. Let result be Call(exoticToPrim, input, «hint»). + b. ReturnIfAbrupt(result). +features: [Symbol.toPrimitive] +---*/ + +var y = {}; +y[Symbol.toPrimitive] = function() { + throw new Test262Error(); +}; + +assert.throws(Test262Error, function() { + new Date(y); +}); diff --git a/test/built-ins/Date/value-symbol-to-prim-invocation.js b/test/built-ins/Date/value-symbol-to-prim-invocation.js new file mode 100644 index 0000000000..bbdc8a3625 --- /dev/null +++ b/test/built-ins/Date/value-symbol-to-prim-invocation.js @@ -0,0 +1,48 @@ +// copyright (c) 2016 the v8 project authors. all rights reserved. +// this code is governed by the bsd license found in the license file. +/*--- +esid: sec-date-value +es6id: 20.3.2.2 +description: Invocation of `Symbol.toPrimitive` method +info: > + [...] + 3. If NewTarget is not undefined, then + a. If Type(value) is Object and value has a [[DateValue]] internal slot, + then + [...] + b. Else, + i. Let v be ? ToPrimitive(value). + [...] + + ES6 Section 7.1.1 ToPrimitive ( input [, PreferredType] ) + + 1. If PreferredType was not passed, let hint be "default". + [...] + 4. Let exoticToPrim be GetMethod(input, @@toPrimitive). + 5. ReturnIfAbrupt(exoticToPrim). + 6. If exoticToPrim is not undefined, then + a. Let result be Call(exoticToPrim, input, «hint»). + [...] +features: [Symbol.toPrimitive] +---*/ + +var y = {}; +var callCount = 0; +var thisVal, args; + +y[Symbol.toPrimitive] = function() { + callCount += 1; + thisVal = this; + args = arguments; +}; + +new Date(y); + +assert.sameValue(callCount, 1, 'method invoked exactly once'); +assert.sameValue(thisVal, y, '`this` value is the object being compared'); +assert.sameValue(args.length, 1, 'method invoked with exactly one argument'); +assert.sameValue( + args[0], + 'default', + 'method invoked with the string "default" as the first argument' +); diff --git a/test/built-ins/Date/value-symbol-to-prim-return-obj.js b/test/built-ins/Date/value-symbol-to-prim-return-obj.js new file mode 100644 index 0000000000..a3660eb682 --- /dev/null +++ b/test/built-ins/Date/value-symbol-to-prim-return-obj.js @@ -0,0 +1,45 @@ +// copyright (c) 2016 the v8 project authors. all rights reserved. +// this code is governed by the bsd license found in the license file. +/*--- +esid: sec-date-value +es6id: 20.3.2.2 +description: > + Behavior when coercion via `Symbol.toPrimitive` yields an Object +info: > + [...] + 3. If NewTarget is not undefined, then + a. If Type(value) is Object and value has a [[DateValue]] internal slot, + then + [...] + b. Else, + i. Let v be ? ToPrimitive(value). + + ES6 Section 7.1.1 ToPrimitive ( input [, PreferredType] ) + + [...] + 4. Let exoticToPrim be GetMethod(input, @@toPrimitive). + 5. ReturnIfAbrupt(exoticToPrim). + 6. If exoticToPrim is not undefined, then + a. Let result be Call(exoticToPrim, input, «hint»). + b. ReturnIfAbrupt(result). + c. If Type(result) is not Object, return result. + d. Throw a TypeError exception. +features: [Symbol.toPrimitive] +---*/ + +var y = {}; +var retVal; + +y[Symbol.toPrimitive] = function() { + return retVal; +}; + +retVal = {}; +assert.throws(TypeError, function() { + new Date(y); +}, 'ordinary object'); + +retVal = (function() { return arguments; }()); +assert.throws(TypeError, function() { + new Date(y); +}, 'arguments exotic object'); diff --git a/test/built-ins/Date/value-symbol-to-prim-return-prim.js b/test/built-ins/Date/value-symbol-to-prim-return-prim.js new file mode 100644 index 0000000000..68f7383c52 --- /dev/null +++ b/test/built-ins/Date/value-symbol-to-prim-return-prim.js @@ -0,0 +1,45 @@ +// Copyright (c) 2016 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-date-value +es6id: 20.3.2.2 +description: > + Behavior when coercion via `Symbol.toPrimitive` yields a primitive value +info: > + [...] + 3. If NewTarget is not undefined, then + a. If Type(value) is Object and value has a [[DateValue]] internal slot, + then + [...] + b. Else, + i. Let v be ? ToPrimitive(value). + + ES6 Section 7.1.1 ToPrimitive ( input [, PreferredType] ) + + [...] + 4. Let exoticToPrim be GetMethod(input, @@toPrimitive). + 5. ReturnIfAbrupt(exoticToPrim). + 6. If exoticToPrim is not undefined, then + a. Let result be Call(exoticToPrim, input, «hint»). + b. ReturnIfAbrupt(result). + c. If Type(result) is not Object, return result. +features: [Symbol.toPrimitive] +---*/ + +var y = {}; +var retVal; + +y[Symbol.toPrimitive] = function() { + return retVal; +}; + +retVal = 1234; +assert.sameValue(new Date(y).valueOf(), 1234); + +retVal = '2016-06-03T19:03:52.872Z'; +assert.sameValue(new Date(y).valueOf(), 1464980632872); + +retVal = Symbol.toPrimitive; +assert.throws(TypeError, function() { + new Date(y); +}); diff --git a/test/language/expressions/addition/coerce-symbol-to-prim-err.js b/test/language/expressions/addition/coerce-symbol-to-prim-err.js new file mode 100644 index 0000000000..77d1d23289 --- /dev/null +++ b/test/language/expressions/addition/coerce-symbol-to-prim-err.js @@ -0,0 +1,55 @@ +// Copyright (C) 2016 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-addition-operator-plus-runtime-semantics-evaluation +es6id: 12.7.3.1 +description: > + Behavior when error thrown by invocation of `Symbol.toPrimitive` method + during coercion +info: > + [...] + 5. Let lprim be ? ToPrimitive(lval). + 6. Let rprim be ? ToPrimitive(rval). + [...] + + ES6 Section 7.1.1 ToPrimitive ( input [, PreferredType] ) + + [...] + 4. Let exoticToPrim be GetMethod(input, @@toPrimitive). + 5. ReturnIfAbrupt(exoticToPrim). + 6. If exoticToPrim is not undefined, then + a. Let result be Call(exoticToPrim, input, «hint»). + b. ReturnIfAbrupt(result). +features: [Symbol.toPrimitive] +---*/ + +var thrower = {}; +var counter = {}; +var log; + +Object.defineProperty(thrower, Symbol.toPrimitive, { + get: function() { + log += 'accessThrower'; + return function() { throw new Test262Error(); }; + } +}); +Object.defineProperty(counter, Symbol.toPrimitive, { + get: function() { + log += 'accessCounter'; + return function() { log += 'callCounter'; }; + } +}); + +log = ''; + +assert.throws(Test262Error, function() { + thrower + counter; +}, 'error thrown by left-hand side'); +assert.sameValue(log, 'accessThrower'); + +log = ''; + +assert.throws(Test262Error, function() { + counter + thrower; +}, 'error thrown by right-hand side'); +assert.sameValue(log, 'accessCountercallCounteraccessThrower'); diff --git a/test/language/expressions/addition/coerce-symbol-to-prim-invocation.js b/test/language/expressions/addition/coerce-symbol-to-prim-invocation.js new file mode 100644 index 0000000000..a2a0de4cdb --- /dev/null +++ b/test/language/expressions/addition/coerce-symbol-to-prim-invocation.js @@ -0,0 +1,59 @@ +// Copyright (C) 2016 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-addition-operator-plus-runtime-semantics-evaluation +es6id: 12.7.3.1 +description: Invocation of `Symbol.toPrimitive` method during coercion +info: > + [...] + 5. Let lprim be ? ToPrimitive(lval). + 6. Let rprim be ? ToPrimitive(rval). + [...] + + ES6 Section 7.2.12 Abstract Equality Comparison + + [...] + 10. If Type(x) is either String, Number, or Symbol and Type(y) is Object, + then return the result of the comparison x == ToPrimitive(y). + + ES6 Section 7.1.1 ToPrimitive ( input [, PreferredType] ) + + 1. If PreferredType was not passed, let hint be "default". + [...] + 4. Let exoticToPrim be GetMethod(input, @@toPrimitive). + 5. ReturnIfAbrupt(exoticToPrim). + 6. If exoticToPrim is not undefined, then + a. Let result be Call(exoticToPrim, input, «hint»). + [...] +features: [Symbol.toPrimitive] +---*/ + +var left = {}; +var right = {}; +var log = ''; +var leftThisVal, rightThisVal, leftArgs, rightArgs; + +left[Symbol.toPrimitive] = function() { + log += 'left'; + leftThisVal = this; + leftArgs = arguments; +}; + +right[Symbol.toPrimitive] = function() { + log += 'right'; + rightThisVal = this; + rightArgs = arguments; +}; + + +left + right; + +assert.sameValue(log, 'leftright', 'methods invoked in correct sequence'); + +assert.sameValue(leftThisVal, left, 'left-hand side `this` value'); +assert.sameValue(leftArgs.length, 1, 'left-hand side argument length'); +assert.sameValue(leftArgs[0], 'default', 'left-hand side argument value'); + +assert.sameValue(rightThisVal, right, 'right-hand side `this` value'); +assert.sameValue(rightArgs.length, 1, 'right-hand side argument length'); +assert.sameValue(rightArgs[0], 'default', 'right-hand side argument value'); diff --git a/test/language/expressions/addition/coerce-symbol-to-prim-return-obj.js b/test/language/expressions/addition/coerce-symbol-to-prim-return-obj.js new file mode 100644 index 0000000000..a2d17f54ba --- /dev/null +++ b/test/language/expressions/addition/coerce-symbol-to-prim-return-obj.js @@ -0,0 +1,48 @@ +// Copyright (C) 2016 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-addition-operator-plus-runtime-semantics-evaluation +es6id: 12.7.3.1 +description: > + Behavior when coercion via `Symbol.toPrimitive` yields an Object +info: > + [...] + 5. Let lprim be ? ToPrimitive(lval). + 6. Let rprim be ? ToPrimitive(rval). + [...] + + ES6 Section 7.1.1 ToPrimitive ( input [, PreferredType] ) + + [...] + 4. Let exoticToPrim be GetMethod(input, @@toPrimitive). + 5. ReturnIfAbrupt(exoticToPrim). + 6. If exoticToPrim is not undefined, then + a. Let result be Call(exoticToPrim, input, «hint»). + b. ReturnIfAbrupt(result). + c. If Type(result) is not Object, return result. + d. Throw a TypeError exception. +features: [Symbol.toPrimitive] +---*/ + +var y = {}; +var retVal; + +y[Symbol.toPrimitive] = function() { + return retVal; +}; + +retVal = {}; +assert.throws(TypeError, function() { + 0 + y; +}, 'ordinary object value, right-hand side'); +assert.throws(TypeError, function() { + y + 0; +}, 'ordinary object value, left-hand side'); + +retVal = (function() { return arguments; }()); +assert.throws(TypeError, function() { + 0 + y; +}, 'arguments exotic object value, right-hand side'); +assert.throws(TypeError, function() { + y + 0; +}, 'arguments exotic object value, left-hand side'); diff --git a/test/language/expressions/addition/coerce-symbol-to-prim-return-prim.js b/test/language/expressions/addition/coerce-symbol-to-prim-return-prim.js new file mode 100644 index 0000000000..daf25e648b --- /dev/null +++ b/test/language/expressions/addition/coerce-symbol-to-prim-return-prim.js @@ -0,0 +1,64 @@ +// Copyright (C) 2016 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-addition-operator-plus-runtime-semantics-evaluation +es6id: 12.7.3.1 +description: > + Behavior when coercion via `Symbol.toPrimitive` yields a primitive value +info: > + [...] + 5. Let lprim be ? ToPrimitive(lval). + 6. Let rprim be ? ToPrimitive(rval). + 7. If Type(lprim) is String or Type(rprim) is String, then + a. Let lstr be ? ToString(lprim). + b. Let rstr be ? ToString(rprim). + c. Return the String that is the result of concatenating lstr and rstr. + 8. Let lnum be ? ToNumber(lprim). + 9. Let rnum be ? ToNumber(rprim). + 10. Return the result of applying the addition operation to lnum and rnum. + See the Note below 12.8.5. + + ES6 Section 7.1.1 ToPrimitive ( input [, PreferredType] ) + + [...] + 4. Let exoticToPrim be GetMethod(input, @@toPrimitive). + 5. ReturnIfAbrupt(exoticToPrim). + 6. If exoticToPrim is not undefined, then + a. Let result be Call(exoticToPrim, input, «hint»). + b. ReturnIfAbrupt(result). + c. If Type(result) is not Object, return result. +features: [Symbol.toPrimitive] +---*/ + +var y = {}; +var retVal; + +y[Symbol.toPrimitive] = function() { + return retVal; +}; + +retVal = 86; +assert.sameValue(1 + y, 87); +assert.sameValue(y + 2, 88); +assert.sameValue('s' + y, 's86'); +assert.sameValue(y + 's', '86s'); + +retVal = 'str'; +assert.sameValue(0 + y, '0str'); +assert.sameValue(y + 0, 'str0'); +assert.sameValue('s' + y, 'sstr'); +assert.sameValue(y + 's', 'strs'); + +retVal = Symbol.toPrimitive; +assert.throws(TypeError, function() { + 0 + y; +}, 'ToNumber(Symbol): right-hand side'); +assert.throws(TypeError, function() { + y + 0; +}, 'ToNumber(Symbol): left-hand side'); +assert.throws(TypeError, function() { + '' + y; +}, 'ToString(Symbol): right-hand side'); +assert.throws(TypeError, function() { + y + ''; +}, 'ToString(Symbol): left-hand size'); diff --git a/test/language/expressions/addition/get-symbol-to-prim-err.js b/test/language/expressions/addition/get-symbol-to-prim-err.js new file mode 100644 index 0000000000..1bccf6b9c0 --- /dev/null +++ b/test/language/expressions/addition/get-symbol-to-prim-err.js @@ -0,0 +1,51 @@ +// Copyright (C) 2016 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +esid: sec-addition-operator-plus-runtime-semantics-evaluation +es6id: 12.7.3.1 +description: > + Behavior when error is thrown while accessing `Symbol.toPrimitive` property +info: > + [...] + 5. Let lprim be ? ToPrimitive(lval). + 6. Let rprim be ? ToPrimitive(rval). + [...] + + ES6 Section 7.1.1 ToPrimitive ( input [, PreferredType] ) + + 1. If PreferredType was not passed, let hint be "default". + [...] + 4. Let exoticToPrim be GetMethod(input, @@toPrimitive). + 5. ReturnIfAbrupt(exoticToPrim). + 6. If exoticToPrim is not undefined, then + a. Let result be Call(exoticToPrim, input, «hint»). + [...] +features: [Symbol.toPrimitive] +---*/ + +var thrower = {}; +var counter = {}; +var callCount = 0; + +Object.defineProperty(thrower, Symbol.toPrimitive, { + get: function() { + throw new Test262Error(); + } +}); +Object.defineProperty(counter, Symbol.toPrimitive, { + get: function() { + callCount += 1; + } +}); + +assert.throws(Test262Error, function() { + thrower + counter; +}, 'error from property access of left-hand side'); + +assert.sameValue(callCount, 0); + +assert.throws(Test262Error, function() { + counter + thrower; +}, 'error from property access of right-hand side'); + +assert.sameValue(callCount, 1);