Projekt

Obecné

Profil

Stáhnout (131 KB) Statistiky
| Větev: | Revize:
1
'use strict';
2

    
3
var test = require('tape');
4

    
5
var forEach = require('foreach');
6
var is = require('object-is');
7
var debug = require('object-inspect');
8
var assign = require('object.assign');
9
var keys = require('object-keys');
10
var has = require('has');
11
var arrowFns = require('make-arrow-function').list();
12
var hasStrictMode = require('has-strict-mode')();
13
var functionsHaveNames = require('functions-have-names')();
14
var functionsHaveConfigurableNames = require('functions-have-names').functionsHaveConfigurableNames();
15

    
16
var $getProto = require('../helpers/getProto');
17
var $setProto = require('../helpers/setProto');
18
var defineProperty = require('./helpers/defineProperty');
19
var getInferredName = require('../helpers/getInferredName');
20
var getOwnPropertyDescriptor = require('../helpers/getOwnPropertyDescriptor');
21
var assertRecordTests = require('./helpers/assertRecord');
22
var v = require('./helpers/values');
23
var diffOps = require('./diffOps');
24

    
25
var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || Math.pow(2, 53) - 1;
26

    
27
var canDistinguishSparseFromUndefined = 0 in [undefined]; // IE 6 - 8 have a bug where this returns false
28

    
29
var getArraySubclassWithSpeciesConstructor = function getArraySubclass(speciesConstructor) {
30
	var Bar = function Bar() {
31
		var inst = [];
32
		Object.setPrototypeOf(inst, Bar.prototype);
33
		defineProperty(inst, 'constructor', { value: Bar });
34
		return inst;
35
	};
36
	Bar.prototype = Object.create(Array.prototype);
37
	Object.setPrototypeOf(Bar, Array);
38
	defineProperty(Bar, Symbol.species, { value: speciesConstructor });
39

    
40
	return Bar;
41
};
42

    
43
var testIterator = function (t, iterator, expected) {
44
	var resultCount = 0;
45
	var result;
46
	while (result = iterator.next(), !result.done) { // eslint-disable-line no-sequences
47
		t.deepEqual(result, { done: false, value: expected[resultCount] }, 'result ' + resultCount);
48
		resultCount += 1;
49
	}
50
	t.equal(resultCount, expected.length, 'expected ' + expected.length + ', got ' + resultCount);
51
};
52

    
53
var hasSpecies = v.hasSymbols && Symbol.species;
54

    
55
var hasLastIndex = 'lastIndex' in (/a/).exec('a'); // IE 8
56
var hasGroups = 'groups' in (/a/).exec('a'); // modern engines
57
var kludgeMatch = function kludgeMatch(R, matchObject) {
58
	if (hasGroups) {
59
		assign(matchObject, { groups: matchObject.groups });
60
	}
61
	if (hasLastIndex) {
62
		assign(matchObject, { lastIndex: R.lastIndex });
63
	}
64
	return matchObject;
65
};
66

    
67
var testEnumerableOwnNames = function (t, enumerableOwnNames) {
68
	forEach(v.primitives, function (nonObject) {
69
		t['throws'](
70
			function () { enumerableOwnNames(nonObject); },
71
			debug(nonObject) + ' is not an Object'
72
		);
73
	});
74

    
75
	var Child = function Child() {
76
		this.own = {};
77
	};
78
	Child.prototype = {
79
		inherited: {}
80
	};
81

    
82
	var obj = new Child();
83

    
84
	t.equal('own' in obj, true, 'has "own"');
85
	t.equal(has(obj, 'own'), true, 'has own "own"');
86
	t.equal(Object.prototype.propertyIsEnumerable.call(obj, 'own'), true, 'has enumerable "own"');
87

    
88
	t.equal('inherited' in obj, true, 'has "inherited"');
89
	t.equal(has(obj, 'inherited'), false, 'has non-own "inherited"');
90
	t.equal(has(Child.prototype, 'inherited'), true, 'Child.prototype has own "inherited"');
91
	t.equal(Child.prototype.inherited, obj.inherited, 'Child.prototype.inherited === obj.inherited');
92
	t.equal(Object.prototype.propertyIsEnumerable.call(Child.prototype, 'inherited'), true, 'has enumerable "inherited"');
93

    
94
	t.equal('toString' in obj, true, 'has "toString"');
95
	t.equal(has(obj, 'toString'), false, 'has non-own "toString"');
96
	t.equal(has(Object.prototype, 'toString'), true, 'Object.prototype has own "toString"');
97
	t.equal(Object.prototype.toString, obj.toString, 'Object.prototype.toString === obj.toString');
98
	// eslint-disable-next-line no-useless-call
99
	t.equal(Object.prototype.propertyIsEnumerable.call(Object.prototype, 'toString'), false, 'has non-enumerable "toString"');
100

    
101
	return obj;
102
};
103

    
104
var es2015 = function ES2015(ES, ops, expectedMissing, skips) {
105
	test('has expected operations', function (t) {
106
		var diff = diffOps(ES, ops, expectedMissing);
107

    
108
		t.deepEqual(diff.extra, [], 'no extra ops');
109

    
110
		t.deepEqual(diff.missing, [], 'no unexpected missing ops');
111

    
112
		t.end();
113
	});
114

    
115
	test('ToPrimitive', function (t) {
116
		t.test('primitives', function (st) {
117
			var testPrimitive = function (primitive) {
118
				st.ok(is(ES.ToPrimitive(primitive), primitive), debug(primitive) + ' is returned correctly');
119
			};
120
			forEach(v.primitives, testPrimitive);
121
			st.end();
122
		});
123

    
124
		t.test('objects', function (st) {
125
			st.equal(ES.ToPrimitive(v.coercibleObject), 3, 'coercibleObject with no hint coerces to valueOf');
126
			st.ok(is(ES.ToPrimitive({}), '[object Object]'), '{} with no hint coerces to Object#toString');
127
			st.equal(ES.ToPrimitive(v.coercibleObject, Number), 3, 'coercibleObject with hint Number coerces to valueOf');
128
			st.ok(is(ES.ToPrimitive({}, Number), '[object Object]'), '{} with hint Number coerces to NaN');
129
			st.equal(ES.ToPrimitive(v.coercibleObject, String), 42, 'coercibleObject with hint String coerces to nonstringified toString');
130
			st.equal(ES.ToPrimitive({}, String), '[object Object]', '{} with hint String coerces to Object#toString');
131
			st.equal(ES.ToPrimitive(v.toStringOnlyObject), 7, 'toStringOnlyObject returns non-stringified toString');
132
			st.equal(ES.ToPrimitive(v.valueOfOnlyObject), 4, 'valueOfOnlyObject returns valueOf');
133
			st['throws'](function () { return ES.ToPrimitive(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws a TypeError');
134
			st.end();
135
		});
136

    
137
		t.test('dates', function (st) {
138
			var invalid = new Date(NaN);
139
			st.equal(ES.ToPrimitive(invalid), Date.prototype.toString.call(invalid), 'invalid Date coerces to Date#toString');
140
			var now = new Date();
141
			st.equal(ES.ToPrimitive(now), Date.prototype.toString.call(now), 'Date coerces to Date#toString');
142
			st.end();
143
		});
144

    
145
		t.end();
146
	});
147

    
148
	test('ToBoolean', function (t) {
149
		t.equal(false, ES.ToBoolean(undefined), 'undefined coerces to false');
150
		t.equal(false, ES.ToBoolean(null), 'null coerces to false');
151
		t.equal(false, ES.ToBoolean(false), 'false returns false');
152
		t.equal(true, ES.ToBoolean(true), 'true returns true');
153

    
154
		t.test('numbers', function (st) {
155
			forEach(v.zeroes.concat(NaN), function (falsyNumber) {
156
				st.equal(false, ES.ToBoolean(falsyNumber), 'falsy number ' + falsyNumber + ' coerces to false');
157
			});
158
			forEach(v.infinities.concat([42, 1]), function (truthyNumber) {
159
				st.equal(true, ES.ToBoolean(truthyNumber), 'truthy number ' + truthyNumber + ' coerces to true');
160
			});
161

    
162
			st.end();
163
		});
164

    
165
		t.equal(false, ES.ToBoolean(''), 'empty string coerces to false');
166
		t.equal(true, ES.ToBoolean('foo'), 'nonempty string coerces to true');
167

    
168
		t.test('objects', function (st) {
169
			forEach(v.objects, function (obj) {
170
				st.equal(true, ES.ToBoolean(obj), 'object coerces to true');
171
			});
172
			st.equal(true, ES.ToBoolean(v.uncoercibleObject), 'uncoercibleObject coerces to true');
173

    
174
			st.end();
175
		});
176

    
177
		t.end();
178
	});
179

    
180
	test('ToNumber', function (t) {
181
		t.ok(is(NaN, ES.ToNumber(undefined)), 'undefined coerces to NaN');
182
		t.ok(is(ES.ToNumber(null), 0), 'null coerces to +0');
183
		t.ok(is(ES.ToNumber(false), 0), 'false coerces to +0');
184
		t.equal(1, ES.ToNumber(true), 'true coerces to 1');
185

    
186
		t.test('numbers', function (st) {
187
			st.ok(is(NaN, ES.ToNumber(NaN)), 'NaN returns itself');
188
			forEach(v.zeroes.concat(v.infinities, 42), function (num) {
189
				st.equal(num, ES.ToNumber(num), num + ' returns itself');
190
			});
191
			forEach(['foo', '0', '4a', '2.0', 'Infinity', '-Infinity'], function (numString) {
192
				st.ok(is(+numString, ES.ToNumber(numString)), '"' + numString + '" coerces to ' + Number(numString));
193
			});
194
			st.end();
195
		});
196

    
197
		t.test('objects', function (st) {
198
			forEach(v.objects, function (object) {
199
				st.ok(is(ES.ToNumber(object), ES.ToNumber(ES.ToPrimitive(object))), 'object ' + object + ' coerces to same as ToPrimitive of object does');
200
			});
201
			st['throws'](function () { return ES.ToNumber(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws');
202
			st.end();
203
		});
204

    
205
		t.test('binary literals', function (st) {
206
			st.equal(ES.ToNumber('0b10'), 2, '0b10 is 2');
207
			st.equal(ES.ToNumber({ toString: function () { return '0b11'; } }), 3, 'Object that toStrings to 0b11 is 3');
208

    
209
			st.equal(true, is(ES.ToNumber('0b12'), NaN), '0b12 is NaN');
210
			st.equal(true, is(ES.ToNumber({ toString: function () { return '0b112'; } }), NaN), 'Object that toStrings to 0b112 is NaN');
211
			st.end();
212
		});
213

    
214
		t.test('octal literals', function (st) {
215
			st.equal(ES.ToNumber('0o10'), 8, '0o10 is 8');
216
			st.equal(ES.ToNumber({ toString: function () { return '0o11'; } }), 9, 'Object that toStrings to 0o11 is 9');
217

    
218
			st.equal(true, is(ES.ToNumber('0o18'), NaN), '0o18 is NaN');
219
			st.equal(true, is(ES.ToNumber({ toString: function () { return '0o118'; } }), NaN), 'Object that toStrings to 0o118 is NaN');
220
			st.end();
221
		});
222

    
223
		t.test('signed hex numbers', function (st) {
224
			st.equal(true, is(ES.ToNumber('-0xF'), NaN), '-0xF is NaN');
225
			st.equal(true, is(ES.ToNumber(' -0xF '), NaN), 'space-padded -0xF is NaN');
226
			st.equal(true, is(ES.ToNumber('+0xF'), NaN), '+0xF is NaN');
227
			st.equal(true, is(ES.ToNumber(' +0xF '), NaN), 'space-padded +0xF is NaN');
228

    
229
			st.end();
230
		});
231

    
232
		t.test('trimming of whitespace and non-whitespace characters', function (st) {
233
			var whitespace = ' \t\x0b\f\xa0\ufeff\n\r\u2028\u2029\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000';
234
			st.equal(0, ES.ToNumber(whitespace + 0 + whitespace), 'whitespace is trimmed');
235

    
236
			// Zero-width space (zws), next line character (nel), and non-character (bom) are not whitespace.
237
			var nonWhitespaces = {
238
				'\\u0085': '\u0085',
239
				'\\u200b': '\u200b',
240
				'\\ufffe': '\ufffe'
241
			};
242

    
243
			forEach(nonWhitespaces, function (desc, nonWS) {
244
				st.equal(true, is(ES.ToNumber(nonWS + 0 + nonWS), NaN), 'non-whitespace ' + desc + ' not trimmed');
245
			});
246

    
247
			st.end();
248
		});
249

    
250
		forEach(v.symbols, function (symbol) {
251
			t['throws'](
252
				function () { ES.ToNumber(symbol); },
253
				TypeError,
254
				'Symbols can’t be converted to a Number: ' + debug(symbol)
255
			);
256
		});
257

    
258
		t.test('dates', function (st) {
259
			var invalid = new Date(NaN);
260
			st.ok(is(ES.ToNumber(invalid), NaN), 'invalid Date coerces to NaN');
261
			var now = +new Date();
262
			st.equal(ES.ToNumber(new Date(now)), now, 'Date coerces to timestamp');
263
			st.end();
264
		});
265

    
266
		t.end();
267
	});
268

    
269
	test('ToInteger', function (t) {
270
		t.ok(is(0, ES.ToInteger(NaN)), 'NaN coerces to +0');
271
		forEach([0, Infinity, 42], function (num) {
272
			t.ok(is(num, ES.ToInteger(num)), num + ' returns itself');
273
			t.ok(is(-num, ES.ToInteger(-num)), '-' + num + ' returns itself');
274
		});
275
		t.equal(3, ES.ToInteger(Math.PI), 'pi returns 3');
276
		t['throws'](function () { return ES.ToInteger(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws');
277
		t.end();
278
	});
279

    
280
	test('ToInt32', function (t) {
281
		t.ok(is(0, ES.ToInt32(NaN)), 'NaN coerces to +0');
282
		forEach([0, Infinity], function (num) {
283
			t.ok(is(0, ES.ToInt32(num)), num + ' returns +0');
284
			t.ok(is(0, ES.ToInt32(-num)), '-' + num + ' returns +0');
285
		});
286
		t['throws'](function () { return ES.ToInt32(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws');
287
		t.ok(is(ES.ToInt32(0x100000000), 0), '2^32 returns +0');
288
		t.ok(is(ES.ToInt32(0x100000000 - 1), -1), '2^32 - 1 returns -1');
289
		t.ok(is(ES.ToInt32(0x80000000), -0x80000000), '2^31 returns -2^31');
290
		t.ok(is(ES.ToInt32(0x80000000 - 1), 0x80000000 - 1), '2^31 - 1 returns 2^31 - 1');
291
		forEach([0, Infinity, NaN, 0x100000000, 0x80000000, 0x10000, 0x42], function (num) {
292
			t.ok(is(ES.ToInt32(num), ES.ToInt32(ES.ToUint32(num))), 'ToInt32(x) === ToInt32(ToUint32(x)) for 0x' + num.toString(16));
293
			t.ok(is(ES.ToInt32(-num), ES.ToInt32(ES.ToUint32(-num))), 'ToInt32(x) === ToInt32(ToUint32(x)) for -0x' + num.toString(16));
294
		});
295
		t.end();
296
	});
297

    
298
	test('ToUint32', function (t) {
299
		t.ok(is(0, ES.ToUint32(NaN)), 'NaN coerces to +0');
300
		forEach([0, Infinity], function (num) {
301
			t.ok(is(0, ES.ToUint32(num)), num + ' returns +0');
302
			t.ok(is(0, ES.ToUint32(-num)), '-' + num + ' returns +0');
303
		});
304
		t['throws'](function () { return ES.ToUint32(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws');
305
		t.ok(is(ES.ToUint32(0x100000000), 0), '2^32 returns +0');
306
		t.ok(is(ES.ToUint32(0x100000000 - 1), 0x100000000 - 1), '2^32 - 1 returns 2^32 - 1');
307
		t.ok(is(ES.ToUint32(0x80000000), 0x80000000), '2^31 returns 2^31');
308
		t.ok(is(ES.ToUint32(0x80000000 - 1), 0x80000000 - 1), '2^31 - 1 returns 2^31 - 1');
309
		forEach([0, Infinity, NaN, 0x100000000, 0x80000000, 0x10000, 0x42], function (num) {
310
			t.ok(is(ES.ToUint32(num), ES.ToUint32(ES.ToInt32(num))), 'ToUint32(x) === ToUint32(ToInt32(x)) for 0x' + num.toString(16));
311
			t.ok(is(ES.ToUint32(-num), ES.ToUint32(ES.ToInt32(-num))), 'ToUint32(x) === ToUint32(ToInt32(x)) for -0x' + num.toString(16));
312
		});
313
		t.end();
314
	});
315

    
316
	test('ToInt16', function (t) {
317
		t.ok(is(0, ES.ToInt16(NaN)), 'NaN coerces to +0');
318
		forEach([0, Infinity], function (num) {
319
			t.ok(is(0, ES.ToInt16(num)), num + ' returns +0');
320
			t.ok(is(0, ES.ToInt16(-num)), '-' + num + ' returns +0');
321
		});
322
		t['throws'](function () { return ES.ToInt16(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws');
323
		t.ok(is(ES.ToInt16(0x100000000), 0), '2^32 returns +0');
324
		t.ok(is(ES.ToInt16(0x100000000 - 1), -1), '2^32 - 1 returns -1');
325
		t.ok(is(ES.ToInt16(0x80000000), 0), '2^31 returns +0');
326
		t.ok(is(ES.ToInt16(0x80000000 - 1), -1), '2^31 - 1 returns -1');
327
		t.ok(is(ES.ToInt16(0x10000), 0), '2^16 returns +0');
328
		t.ok(is(ES.ToInt16(0x10000 - 1), -1), '2^16 - 1 returns -1');
329
		t.end();
330
	});
331

    
332
	test('ToUint16', function (t) {
333
		t.ok(is(0, ES.ToUint16(NaN)), 'NaN coerces to +0');
334
		forEach([0, Infinity], function (num) {
335
			t.ok(is(0, ES.ToUint16(num)), num + ' returns +0');
336
			t.ok(is(0, ES.ToUint16(-num)), '-' + num + ' returns +0');
337
		});
338
		t['throws'](function () { return ES.ToUint16(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws');
339
		t.ok(is(ES.ToUint16(0x100000000), 0), '2^32 returns +0');
340
		t.ok(is(ES.ToUint16(0x100000000 - 1), 0x10000 - 1), '2^32 - 1 returns 2^16 - 1');
341
		t.ok(is(ES.ToUint16(0x80000000), 0), '2^31 returns +0');
342
		t.ok(is(ES.ToUint16(0x80000000 - 1), 0x10000 - 1), '2^31 - 1 returns 2^16 - 1');
343
		t.ok(is(ES.ToUint16(0x10000), 0), '2^16 returns +0');
344
		t.ok(is(ES.ToUint16(0x10000 - 1), 0x10000 - 1), '2^16 - 1 returns 2^16 - 1');
345
		t.end();
346
	});
347

    
348
	test('ToInt8', function (t) {
349
		t.ok(is(0, ES.ToInt8(NaN)), 'NaN coerces to +0');
350
		forEach([0, Infinity], function (num) {
351
			t.ok(is(0, ES.ToInt8(num)), num + ' returns +0');
352
			t.ok(is(0, ES.ToInt8(-num)), '-' + num + ' returns +0');
353
		});
354
		t['throws'](function () { return ES.ToInt8(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws');
355
		t.ok(is(ES.ToInt8(0x100000000), 0), '2^32 returns +0');
356
		t.ok(is(ES.ToInt8(0x100000000 - 1), -1), '2^32 - 1 returns -1');
357
		t.ok(is(ES.ToInt8(0x80000000), 0), '2^31 returns +0');
358
		t.ok(is(ES.ToInt8(0x80000000 - 1), -1), '2^31 - 1 returns -1');
359
		t.ok(is(ES.ToInt8(0x10000), 0), '2^16 returns +0');
360
		t.ok(is(ES.ToInt8(0x10000 - 1), -1), '2^16 - 1 returns -1');
361
		t.ok(is(ES.ToInt8(0x100), 0), '2^8 returns +0');
362
		t.ok(is(ES.ToInt8(0x100 - 1), -1), '2^8 - 1 returns -1');
363
		t.ok(is(ES.ToInt8(0x10), 0x10), '2^4 returns 2^4');
364
		t.end();
365
	});
366

    
367
	test('ToUint8', function (t) {
368
		t.ok(is(0, ES.ToUint8(NaN)), 'NaN coerces to +0');
369
		forEach([0, Infinity], function (num) {
370
			t.ok(is(0, ES.ToUint8(num)), num + ' returns +0');
371
			t.ok(is(0, ES.ToUint8(-num)), '-' + num + ' returns +0');
372
		});
373
		t['throws'](function () { return ES.ToUint8(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws');
374
		t.ok(is(ES.ToUint8(0x100000000), 0), '2^32 returns +0');
375
		t.ok(is(ES.ToUint8(0x100000000 - 1), 0x100 - 1), '2^32 - 1 returns 2^8 - 1');
376
		t.ok(is(ES.ToUint8(0x80000000), 0), '2^31 returns +0');
377
		t.ok(is(ES.ToUint8(0x80000000 - 1), 0x100 - 1), '2^31 - 1 returns 2^8 - 1');
378
		t.ok(is(ES.ToUint8(0x10000), 0), '2^16 returns +0');
379
		t.ok(is(ES.ToUint8(0x10000 - 1), 0x100 - 1), '2^16 - 1 returns 2^8 - 1');
380
		t.ok(is(ES.ToUint8(0x100), 0), '2^8 returns +0');
381
		t.ok(is(ES.ToUint8(0x100 - 1), 0x100 - 1), '2^8 - 1 returns 2^16 - 1');
382
		t.ok(is(ES.ToUint8(0x10), 0x10), '2^4 returns 2^4');
383
		t.ok(is(ES.ToUint8(0x10 - 1), 0x10 - 1), '2^4 - 1 returns 2^4 - 1');
384
		t.end();
385
	});
386

    
387
	test('ToUint8Clamp', function (t) {
388
		t.ok(is(0, ES.ToUint8Clamp(NaN)), 'NaN coerces to +0');
389
		t.ok(is(0, ES.ToUint8Clamp(0)), '+0 returns +0');
390
		t.ok(is(0, ES.ToUint8Clamp(-0)), '-0 returns +0');
391
		t.ok(is(0, ES.ToUint8Clamp(-Infinity)), '-Infinity returns +0');
392
		t['throws'](function () { return ES.ToUint8Clamp(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws');
393
		forEach([255, 256, 0x100000, Infinity], function (number) {
394
			t.ok(is(255, ES.ToUint8Clamp(number)), number + ' coerces to 255');
395
		});
396
		t.equal(1, ES.ToUint8Clamp(1.49), '1.49 coerces to 1');
397
		t.equal(2, ES.ToUint8Clamp(1.5), '1.5 coerces to 2, because 2 is even');
398
		t.equal(2, ES.ToUint8Clamp(1.51), '1.51 coerces to 2');
399

    
400
		t.equal(2, ES.ToUint8Clamp(2.49), '2.49 coerces to 2');
401
		t.equal(2, ES.ToUint8Clamp(2.5), '2.5 coerces to 2, because 2 is even');
402
		t.equal(3, ES.ToUint8Clamp(2.51), '2.51 coerces to 3');
403
		t.end();
404
	});
405

    
406
	test('ToString', function (t) {
407
		forEach(v.objects.concat(v.nonSymbolPrimitives), function (item) {
408
			t.equal(ES.ToString(item), String(item), 'ES.ToString(' + debug(item) + ') ToStrings to String(' + debug(item) + ')');
409
		});
410

    
411
		t['throws'](function () { return ES.ToString(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws');
412

    
413
		forEach(v.symbols, function (symbol) {
414
			t['throws'](function () { return ES.ToString(symbol); }, TypeError, debug(symbol) + ' throws');
415
		});
416
		t.end();
417
	});
418

    
419
	test('ToObject', function (t) {
420
		t['throws'](function () { return ES.ToObject(undefined); }, TypeError, 'undefined throws');
421
		t['throws'](function () { return ES.ToObject(null); }, TypeError, 'null throws');
422
		forEach(v.numbers, function (number) {
423
			var obj = ES.ToObject(number);
424
			t.equal(typeof obj, 'object', 'number ' + number + ' coerces to object');
425
			t.equal(true, obj instanceof Number, 'object of ' + number + ' is Number object');
426
			t.ok(is(obj.valueOf(), number), 'object of ' + number + ' coerces to ' + number);
427
		});
428
		t.end();
429
	});
430

    
431
	test('RequireObjectCoercible', function (t) {
432
		t.equal(false, 'CheckObjectCoercible' in ES, 'CheckObjectCoercible -> RequireObjectCoercible in ES6');
433
		t['throws'](function () { return ES.RequireObjectCoercible(undefined); }, TypeError, 'undefined throws');
434
		t['throws'](function () { return ES.RequireObjectCoercible(null); }, TypeError, 'null throws');
435
		var isCoercible = function (value) {
436
			t.doesNotThrow(function () { return ES.RequireObjectCoercible(value); }, debug(value) + ' does not throw');
437
		};
438
		forEach(v.objects.concat(v.nonNullPrimitives), isCoercible);
439
		t.end();
440
	});
441

    
442
	test('IsCallable', function (t) {
443
		t.equal(true, ES.IsCallable(function () {}), 'function is callable');
444
		var nonCallables = [/a/g, {}, Object.prototype, NaN].concat(v.nonFunctions);
445
		forEach(nonCallables, function (nonCallable) {
446
			t.equal(false, ES.IsCallable(nonCallable), debug(nonCallable) + ' is not callable');
447
		});
448
		t.end();
449
	});
450

    
451
	test('SameValue', function (t) {
452
		t.equal(true, ES.SameValue(NaN, NaN), 'NaN is SameValue as NaN');
453
		t.equal(false, ES.SameValue(0, -0), '+0 is not SameValue as -0');
454
		forEach(v.objects.concat(v.primitives), function (val) {
455
			t.equal(val === val, ES.SameValue(val, val), debug(val) + ' is SameValue to itself');
456
		});
457
		t.end();
458
	});
459

    
460
	test('SameValueZero', function (t) {
461
		t.equal(true, ES.SameValueZero(NaN, NaN), 'NaN is SameValueZero as NaN');
462
		t.equal(true, ES.SameValueZero(0, -0), '+0 is SameValueZero as -0');
463
		forEach(v.objects.concat(v.primitives), function (val) {
464
			t.equal(val === val, ES.SameValueZero(val, val), debug(val) + ' is SameValueZero to itself');
465
		});
466
		t.end();
467
	});
468

    
469
	test('ToPropertyKey', function (t) {
470
		forEach(v.objects.concat(v.nonSymbolPrimitives), function (value) {
471
			t.equal(ES.ToPropertyKey(value), String(value), 'ToPropertyKey(value) === String(value) for non-Symbols');
472
		});
473

    
474
		forEach(v.symbols, function (symbol) {
475
			t.equal(
476
				ES.ToPropertyKey(symbol),
477
				symbol,
478
				'ToPropertyKey(' + debug(symbol) + ') === ' + debug(symbol)
479
			);
480
			t.equal(
481
				ES.ToPropertyKey(Object(symbol)),
482
				symbol,
483
				'ToPropertyKey(' + debug(Object(symbol)) + ') === ' + debug(symbol)
484
			);
485
		});
486

    
487
		t.end();
488
	});
489

    
490
	test('ToLength', function (t) {
491
		t['throws'](function () { return ES.ToLength(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws a TypeError');
492
		t.equal(3, ES.ToLength(v.coercibleObject), 'coercibleObject coerces to 3');
493
		t.equal(42, ES.ToLength('42.5'), '"42.5" coerces to 42');
494
		t.equal(7, ES.ToLength(7.3), '7.3 coerces to 7');
495
		forEach([-0, -1, -42, -Infinity], function (negative) {
496
			t.ok(is(0, ES.ToLength(negative)), negative + ' coerces to +0');
497
		});
498
		t.equal(MAX_SAFE_INTEGER, ES.ToLength(MAX_SAFE_INTEGER + 1), '2^53 coerces to 2^53 - 1');
499
		t.equal(MAX_SAFE_INTEGER, ES.ToLength(MAX_SAFE_INTEGER + 3), '2^53 + 2 coerces to 2^53 - 1');
500
		t.end();
501
	});
502

    
503
	test('IsArray', function (t) {
504
		t.equal(true, ES.IsArray([]), '[] is array');
505
		t.equal(false, ES.IsArray({}), '{} is not array');
506
		t.equal(false, ES.IsArray({ length: 1, 0: true }), 'arraylike object is not array');
507
		forEach(v.objects.concat(v.primitives), function (value) {
508
			t.equal(false, ES.IsArray(value), debug(value) + ' is not array');
509
		});
510
		t.end();
511
	});
512

    
513
	test('IsRegExp', function (t) {
514
		forEach([/a/g, new RegExp('a', 'g')], function (regex) {
515
			t.equal(true, ES.IsRegExp(regex), regex + ' is regex');
516
		});
517

    
518
		forEach(v.objects.concat(v.primitives), function (nonRegex) {
519
			t.equal(false, ES.IsRegExp(nonRegex), debug(nonRegex) + ' is not regex');
520
		});
521

    
522
		t.test('Symbol.match', { skip: !v.hasSymbols || !Symbol.match }, function (st) {
523
			var obj = {};
524
			obj[Symbol.match] = true;
525
			st.equal(true, ES.IsRegExp(obj), 'object with truthy Symbol.match is regex');
526

    
527
			var regex = /a/;
528
			regex[Symbol.match] = false;
529
			st.equal(false, ES.IsRegExp(regex), 'regex with falsy Symbol.match is not regex');
530

    
531
			st.end();
532
		});
533

    
534
		t.end();
535
	});
536

    
537
	test('IsPropertyKey', function (t) {
538
		forEach(v.numbers.concat(v.objects), function (notKey) {
539
			t.equal(false, ES.IsPropertyKey(notKey), debug(notKey) + ' is not property key');
540
		});
541

    
542
		t.equal(true, ES.IsPropertyKey('foo'), 'string is property key');
543

    
544
		forEach(v.symbols, function (symbol) {
545
			t.equal(true, ES.IsPropertyKey(symbol), debug(symbol) + ' is property key');
546
		});
547
		t.end();
548
	});
549

    
550
	test('IsInteger', function (t) {
551
		for (var i = -100; i < 100; i += 10) {
552
			t.equal(true, ES.IsInteger(i), i + ' is integer');
553
			t.equal(false, ES.IsInteger(i + 0.2), (i + 0.2) + ' is not integer');
554
		}
555
		t.equal(true, ES.IsInteger(-0), '-0 is integer');
556
		var notInts = v.nonNumbers.concat(v.nonIntegerNumbers, v.infinities, [NaN, [], new Date()]);
557
		forEach(notInts, function (notInt) {
558
			t.equal(false, ES.IsInteger(notInt), debug(notInt) + ' is not integer');
559
		});
560
		t.equal(false, ES.IsInteger(v.uncoercibleObject), 'uncoercibleObject is not integer');
561
		t.end();
562
	});
563

    
564
	test('IsExtensible', function (t) {
565
		forEach(v.objects, function (object) {
566
			t.equal(true, ES.IsExtensible(object), debug(object) + ' object is extensible');
567
		});
568
		forEach(v.primitives, function (primitive) {
569
			t.equal(false, ES.IsExtensible(primitive), debug(primitive) + ' is not extensible');
570
		});
571
		if (Object.preventExtensions) {
572
			t.equal(false, ES.IsExtensible(Object.preventExtensions({})), 'object with extensions prevented is not extensible');
573
		}
574
		t.end();
575
	});
576

    
577
	test('CanonicalNumericIndexString', function (t) {
578
		var throwsOnNonString = function (notString) {
579
			t['throws'](
580
				function () { return ES.CanonicalNumericIndexString(notString); },
581
				TypeError,
582
				debug(notString) + ' is not a string'
583
			);
584
		};
585
		forEach(v.objects.concat(v.numbers), throwsOnNonString);
586
		t.ok(is(-0, ES.CanonicalNumericIndexString('-0')), '"-0" returns -0');
587
		for (var i = -50; i < 50; i += 10) {
588
			t.equal(i, ES.CanonicalNumericIndexString(String(i)), '"' + i + '" returns ' + i);
589
			t.equal(undefined, ES.CanonicalNumericIndexString(String(i) + 'a'), '"' + i + 'a" returns undefined');
590
		}
591
		t.end();
592
	});
593

    
594
	test('IsConstructor', function (t) {
595
		t.equal(true, ES.IsConstructor(function () {}), 'function is constructor');
596
		t.equal(false, ES.IsConstructor(/a/g), 'regex is not constructor');
597
		forEach(v.objects, function (object) {
598
			t.equal(false, ES.IsConstructor(object), object + ' object is not constructor');
599
		});
600

    
601
		try {
602
			var foo = Function('return class Foo {}')(); // eslint-disable-line no-new-func
603
			t.equal(ES.IsConstructor(foo), true, 'class is constructor');
604
		} catch (e) {
605
			t.comment('SKIP: class syntax not supported.');
606
		}
607
		t.end();
608
	});
609

    
610
	test('Call', function (t) {
611
		var receiver = {};
612
		var notFuncs = v.nonFunctions.concat([/a/g, new RegExp('a', 'g')]);
613
		t.plan(notFuncs.length + 4);
614
		var throwsIfNotCallable = function (notFunc) {
615
			t['throws'](
616
				function () { return ES.Call(notFunc, receiver); },
617
				TypeError,
618
				debug(notFunc) + ' (' + typeof notFunc + ') is not callable'
619
			);
620
		};
621
		forEach(notFuncs, throwsIfNotCallable);
622
		ES.Call(
623
			function (a, b) {
624
				t.equal(this, receiver, 'context matches expected');
625
				t.deepEqual([a, b], [1, 2], 'named args are correct');
626
				t.equal(arguments.length, 3, 'extra argument was passed');
627
				t.equal(arguments[2], 3, 'extra argument was correct');
628
			},
629
			receiver,
630
			[1, 2, 3]
631
		);
632
		t.end();
633
	});
634

    
635
	test('GetV', function (t) {
636
		t['throws'](function () { return ES.GetV({ 7: 7 }, 7); }, TypeError, 'Throws a TypeError if `P` is not a property key');
637
		var obj = { a: function () {} };
638
		t.equal(ES.GetV(obj, 'a'), obj.a, 'returns property if it exists');
639
		t.equal(ES.GetV(obj, 'b'), undefined, 'returns undefiend if property does not exist');
640
		t.end();
641
	});
642

    
643
	test('GetMethod', function (t) {
644
		t['throws'](function () { return ES.GetMethod({ 7: 7 }, 7); }, TypeError, 'Throws a TypeError if `P` is not a property key');
645
		t.equal(ES.GetMethod({}, 'a'), undefined, 'returns undefined in property is undefined');
646
		t.equal(ES.GetMethod({ a: null }, 'a'), undefined, 'returns undefined if property is null');
647
		t.equal(ES.GetMethod({ a: undefined }, 'a'), undefined, 'returns undefined if property is undefined');
648
		var obj = { a: function () {} };
649
		t['throws'](function () { ES.GetMethod({ a: 'b' }, 'a'); }, TypeError, 'throws TypeError if property exists and is not callable');
650
		t.equal(ES.GetMethod(obj, 'a'), obj.a, 'returns property if it is callable');
651
		t.end();
652
	});
653

    
654
	test('Get', function (t) {
655
		t['throws'](function () { return ES.Get('a', 'a'); }, TypeError, 'Throws a TypeError if `O` is not an Object');
656
		t['throws'](function () { return ES.Get({ 7: 7 }, 7); }, TypeError, 'Throws a TypeError if `P` is not a property key');
657

    
658
		var value = {};
659
		t.test('Symbols', { skip: !v.hasSymbols }, function (st) {
660
			var sym = Symbol('sym');
661
			var obj = {};
662
			obj[sym] = value;
663
			st.equal(ES.Get(obj, sym), value, 'returns property `P` if it exists on object `O`');
664
			st.end();
665
		});
666
		t.equal(ES.Get({ a: value }, 'a'), value, 'returns property `P` if it exists on object `O`');
667
		t.end();
668
	});
669

    
670
	test('Type', { skip: !v.hasSymbols }, function (t) {
671
		t.equal(ES.Type(Symbol.iterator), 'Symbol', 'Type(Symbol.iterator) is Symbol');
672
		t.end();
673
	});
674

    
675
	test('SpeciesConstructor', function (t) {
676
		t['throws'](function () { ES.SpeciesConstructor(null); }, TypeError);
677
		t['throws'](function () { ES.SpeciesConstructor(undefined); }, TypeError);
678

    
679
		var defaultConstructor = function Foo() {};
680

    
681
		t.equal(
682
			ES.SpeciesConstructor({ constructor: undefined }, defaultConstructor),
683
			defaultConstructor,
684
			'undefined constructor returns defaultConstructor'
685
		);
686

    
687
		t['throws'](
688
			function () { return ES.SpeciesConstructor({ constructor: null }, defaultConstructor); },
689
			TypeError,
690
			'non-undefined non-object constructor throws'
691
		);
692

    
693
		t.test('with Symbol.species', { skip: !hasSpecies }, function (st) {
694
			var Bar = function Bar() {};
695
			Bar[Symbol.species] = null;
696

    
697
			st.equal(
698
				ES.SpeciesConstructor(new Bar(), defaultConstructor),
699
				defaultConstructor,
700
				'undefined/null Symbol.species returns default constructor'
701
			);
702

    
703
			var Baz = function Baz() {};
704
			Baz[Symbol.species] = Bar;
705
			st.equal(
706
				ES.SpeciesConstructor(new Baz(), defaultConstructor),
707
				Bar,
708
				'returns Symbol.species constructor value'
709
			);
710

    
711
			Baz[Symbol.species] = {};
712
			st['throws'](
713
				function () { ES.SpeciesConstructor(new Baz(), defaultConstructor); },
714
				TypeError,
715
				'throws when non-constructor non-null non-undefined species value found'
716
			);
717

    
718
			st.end();
719
		});
720

    
721
		t.end();
722
	});
723

    
724
	test('IsPropertyDescriptor', { skip: skips && skips.IsPropertyDescriptor }, function (t) {
725
		forEach(v.nonUndefinedPrimitives, function (primitive) {
726
			t.equal(
727
				ES.IsPropertyDescriptor(primitive),
728
				false,
729
				debug(primitive) + ' is not a Property Descriptor'
730
			);
731
		});
732

    
733
		t.equal(ES.IsPropertyDescriptor({ invalid: true }), false, 'invalid keys not allowed on a Property Descriptor');
734

    
735
		t.equal(ES.IsPropertyDescriptor({}), true, 'empty object is an incomplete Property Descriptor');
736

    
737
		t.equal(ES.IsPropertyDescriptor(v.accessorDescriptor()), true, 'accessor descriptor is a Property Descriptor');
738
		t.equal(ES.IsPropertyDescriptor(v.mutatorDescriptor()), true, 'mutator descriptor is a Property Descriptor');
739
		t.equal(ES.IsPropertyDescriptor(v.dataDescriptor()), true, 'data descriptor is a Property Descriptor');
740
		t.equal(ES.IsPropertyDescriptor(v.genericDescriptor()), true, 'generic descriptor is a Property Descriptor');
741

    
742
		t['throws'](
743
			function () { ES.IsPropertyDescriptor(v.bothDescriptor()); },
744
			TypeError,
745
			'a Property Descriptor can not be both a Data and an Accessor Descriptor'
746
		);
747

    
748
		t.end();
749
	});
750

    
751
	assertRecordTests(ES, test);
752

    
753
	test('IsAccessorDescriptor', function (t) {
754
		forEach(v.nonUndefinedPrimitives, function (primitive) {
755
			t['throws'](
756
				function () { ES.IsAccessorDescriptor(primitive); },
757
				TypeError,
758
				debug(primitive) + ' is not a Property Descriptor'
759
			);
760
		});
761

    
762
		t.equal(ES.IsAccessorDescriptor(), false, 'no value is not an Accessor Descriptor');
763
		t.equal(ES.IsAccessorDescriptor(undefined), false, 'undefined value is not an Accessor Descriptor');
764

    
765
		t.equal(ES.IsAccessorDescriptor(v.accessorDescriptor()), true, 'accessor descriptor is an Accessor Descriptor');
766
		t.equal(ES.IsAccessorDescriptor(v.mutatorDescriptor()), true, 'mutator descriptor is an Accessor Descriptor');
767
		t.equal(ES.IsAccessorDescriptor(v.dataDescriptor()), false, 'data descriptor is not an Accessor Descriptor');
768
		t.equal(ES.IsAccessorDescriptor(v.genericDescriptor()), false, 'generic descriptor is not an Accessor Descriptor');
769

    
770
		t.end();
771
	});
772

    
773
	test('IsDataDescriptor', function (t) {
774
		forEach(v.nonUndefinedPrimitives, function (primitive) {
775
			t['throws'](
776
				function () { ES.IsDataDescriptor(primitive); },
777
				TypeError,
778
				debug(primitive) + ' is not a Property Descriptor'
779
			);
780
		});
781

    
782
		t.equal(ES.IsDataDescriptor(), false, 'no value is not a Data Descriptor');
783
		t.equal(ES.IsDataDescriptor(undefined), false, 'undefined value is not a Data Descriptor');
784

    
785
		t.equal(ES.IsDataDescriptor(v.accessorDescriptor()), false, 'accessor descriptor is not a Data Descriptor');
786
		t.equal(ES.IsDataDescriptor(v.mutatorDescriptor()), false, 'mutator descriptor is not a Data Descriptor');
787
		t.equal(ES.IsDataDescriptor(v.dataDescriptor()), true, 'data descriptor is a Data Descriptor');
788
		t.equal(ES.IsDataDescriptor(v.genericDescriptor()), false, 'generic descriptor is not a Data Descriptor');
789

    
790
		t.end();
791
	});
792

    
793
	test('IsGenericDescriptor', function (t) {
794
		forEach(v.nonUndefinedPrimitives, function (primitive) {
795
			t['throws'](
796
				function () { ES.IsGenericDescriptor(primitive); },
797
				TypeError,
798
				debug(primitive) + ' is not a Property Descriptor'
799
			);
800
		});
801

    
802
		t.equal(ES.IsGenericDescriptor(), false, 'no value is not a Data Descriptor');
803
		t.equal(ES.IsGenericDescriptor(undefined), false, 'undefined value is not a Data Descriptor');
804

    
805
		t.equal(ES.IsGenericDescriptor(v.accessorDescriptor()), false, 'accessor descriptor is not a generic Descriptor');
806
		t.equal(ES.IsGenericDescriptor(v.mutatorDescriptor()), false, 'mutator descriptor is not a generic Descriptor');
807
		t.equal(ES.IsGenericDescriptor(v.dataDescriptor()), false, 'data descriptor is not a generic Descriptor');
808

    
809
		t.equal(ES.IsGenericDescriptor(v.genericDescriptor()), true, 'generic descriptor is a generic Descriptor');
810

    
811
		t.end();
812
	});
813

    
814
	test('FromPropertyDescriptor', function (t) {
815
		t.equal(ES.FromPropertyDescriptor(), undefined, 'no value begets undefined');
816
		t.equal(ES.FromPropertyDescriptor(undefined), undefined, 'undefined value begets undefined');
817

    
818
		forEach(v.nonUndefinedPrimitives, function (primitive) {
819
			t['throws'](
820
				function () { ES.FromPropertyDescriptor(primitive); },
821
				TypeError,
822
				debug(primitive) + ' is not a Property Descriptor'
823
			);
824
		});
825

    
826
		var accessor = v.accessorDescriptor();
827
		t.deepEqual(ES.FromPropertyDescriptor(accessor), {
828
			get: accessor['[[Get]]'],
829
			enumerable: !!accessor['[[Enumerable]]'],
830
			configurable: !!accessor['[[Configurable]]']
831
		});
832

    
833
		var mutator = v.mutatorDescriptor();
834
		t.deepEqual(ES.FromPropertyDescriptor(mutator), {
835
			set: mutator['[[Set]]'],
836
			enumerable: !!mutator['[[Enumerable]]'],
837
			configurable: !!mutator['[[Configurable]]']
838
		});
839
		var data = v.dataDescriptor();
840
		t.deepEqual(ES.FromPropertyDescriptor(data), {
841
			value: data['[[Value]]'],
842
			writable: data['[[Writable]]']
843
		});
844

    
845
		t.deepEqual(ES.FromPropertyDescriptor(v.genericDescriptor()), {
846
			enumerable: false,
847
			configurable: true
848
		});
849

    
850
		t.end();
851
	});
852

    
853
	test('ToPropertyDescriptor', function (t) {
854
		forEach(v.nonUndefinedPrimitives, function (primitive) {
855
			t['throws'](
856
				function () { ES.ToPropertyDescriptor(primitive); },
857
				TypeError,
858
				debug(primitive) + ' is not an Object'
859
			);
860
		});
861

    
862
		var accessor = v.accessorDescriptor();
863
		t.deepEqual(ES.ToPropertyDescriptor({
864
			get: accessor['[[Get]]'],
865
			enumerable: !!accessor['[[Enumerable]]'],
866
			configurable: !!accessor['[[Configurable]]']
867
		}), accessor);
868

    
869
		var mutator = v.mutatorDescriptor();
870
		t.deepEqual(ES.ToPropertyDescriptor({
871
			set: mutator['[[Set]]'],
872
			enumerable: !!mutator['[[Enumerable]]'],
873
			configurable: !!mutator['[[Configurable]]']
874
		}), mutator);
875

    
876
		var data = v.dataDescriptor();
877
		t.deepEqual(ES.ToPropertyDescriptor({
878
			value: data['[[Value]]'],
879
			writable: data['[[Writable]]'],
880
			configurable: !!data['[[Configurable]]']
881
		}), assign(data, { '[[Configurable]]': false }));
882

    
883
		var both = v.bothDescriptor();
884
		t['throws'](
885
			function () {
886
				ES.FromPropertyDescriptor({ get: both['[[Get]]'], value: both['[[Value]]'] });
887
			},
888
			TypeError,
889
			'data and accessor descriptors are mutually exclusive'
890
		);
891

    
892
		t.end();
893
	});
894

    
895
	test('CompletePropertyDescriptor', function (t) {
896
		forEach(v.nonUndefinedPrimitives, function (primitive) {
897
			t['throws'](
898
				function () { ES.CompletePropertyDescriptor(primitive); },
899
				TypeError,
900
				debug(primitive) + ' is not a Property Descriptor'
901
			);
902
		});
903

    
904
		var generic = v.genericDescriptor();
905
		t.deepEqual(
906
			ES.CompletePropertyDescriptor(generic),
907
			{
908
				'[[Configurable]]': !!generic['[[Configurable]]'],
909
				'[[Enumerable]]': !!generic['[[Enumerable]]'],
910
				'[[Value]]': undefined,
911
				'[[Writable]]': false
912
			},
913
			'completes a Generic Descriptor'
914
		);
915

    
916
		var data = v.dataDescriptor();
917
		t.deepEqual(
918
			ES.CompletePropertyDescriptor(data),
919
			{
920
				'[[Configurable]]': !!data['[[Configurable]]'],
921
				'[[Enumerable]]': false,
922
				'[[Value]]': data['[[Value]]'],
923
				'[[Writable]]': !!data['[[Writable]]']
924
			},
925
			'completes a Data Descriptor'
926
		);
927

    
928
		var accessor = v.accessorDescriptor();
929
		t.deepEqual(
930
			ES.CompletePropertyDescriptor(accessor),
931
			{
932
				'[[Get]]': accessor['[[Get]]'],
933
				'[[Enumerable]]': !!accessor['[[Enumerable]]'],
934
				'[[Configurable]]': !!accessor['[[Configurable]]'],
935
				'[[Set]]': undefined
936
			},
937
			'completes an Accessor Descriptor'
938
		);
939

    
940
		var mutator = v.mutatorDescriptor();
941
		t.deepEqual(
942
			ES.CompletePropertyDescriptor(mutator),
943
			{
944
				'[[Set]]': mutator['[[Set]]'],
945
				'[[Enumerable]]': !!mutator['[[Enumerable]]'],
946
				'[[Configurable]]': !!mutator['[[Configurable]]'],
947
				'[[Get]]': undefined
948
			},
949
			'completes a mutator Descriptor'
950
		);
951

    
952
		t['throws'](
953
			function () { ES.CompletePropertyDescriptor(v.bothDescriptor()); },
954
			TypeError,
955
			'data and accessor descriptors are mutually exclusive'
956
		);
957

    
958
		t.end();
959
	});
960

    
961
	test('Set', function (t) {
962
		forEach(v.primitives, function (primitive) {
963
			t['throws'](
964
				function () { ES.Set(primitive, '', null, false); },
965
				TypeError,
966
				debug(primitive) + ' is not an Object'
967
			);
968
		});
969

    
970
		forEach(v.nonPropertyKeys, function (nonKey) {
971
			t['throws'](
972
				function () { ES.Set({}, nonKey, null, false); },
973
				TypeError,
974
				debug(nonKey) + ' is not a Property Key'
975
			);
976
		});
977

    
978
		forEach(v.nonBooleans, function (nonBoolean) {
979
			t['throws'](
980
				function () { ES.Set({}, '', null, nonBoolean); },
981
				TypeError,
982
				debug(nonBoolean) + ' is not a Boolean'
983
			);
984
		});
985

    
986
		var o = {};
987
		var value = {};
988
		ES.Set(o, 'key', value, true);
989
		t.deepEqual(o, { key: value }, 'key is set');
990

    
991
		t.test('nonwritable', { skip: !defineProperty.oDP }, function (st) {
992
			var obj = { a: value };
993
			defineProperty(obj, 'a', { writable: false });
994

    
995
			st['throws'](
996
				function () { ES.Set(obj, 'a', value, true); },
997
				TypeError,
998
				'can not Set nonwritable property'
999
			);
1000

    
1001
			st.doesNotThrow(
1002
				function () { ES.Set(obj, 'a', value, false); },
1003
				'setting Throw to false prevents an exception'
1004
			);
1005

    
1006
			st.end();
1007
		});
1008

    
1009
		t.test('nonconfigurable', { skip: !defineProperty.oDP }, function (st) {
1010
			var obj = { a: value };
1011
			defineProperty(obj, 'a', { configurable: false });
1012

    
1013
			ES.Set(obj, 'a', value, true);
1014
			st.deepEqual(obj, { a: value }, 'key is set');
1015

    
1016
			st.end();
1017
		});
1018

    
1019
		t.end();
1020
	});
1021

    
1022
	test('HasOwnProperty', function (t) {
1023
		forEach(v.primitives, function (primitive) {
1024
			t['throws'](
1025
				function () { ES.HasOwnProperty(primitive, 'key'); },
1026
				TypeError,
1027
				debug(primitive) + ' is not an Object'
1028
			);
1029
		});
1030

    
1031
		forEach(v.nonPropertyKeys, function (nonKey) {
1032
			t['throws'](
1033
				function () { ES.HasOwnProperty({}, nonKey); },
1034
				TypeError,
1035
				debug(nonKey) + ' is not a Property Key'
1036
			);
1037
		});
1038

    
1039
		t.equal(ES.HasOwnProperty({}, 'toString'), false, 'inherited properties are not own');
1040
		t.equal(
1041
			ES.HasOwnProperty({ toString: 1 }, 'toString'),
1042
			true,
1043
			'shadowed inherited own properties are own'
1044
		);
1045
		t.equal(ES.HasOwnProperty({ a: 1 }, 'a'), true, 'own properties are own');
1046

    
1047
		t.end();
1048
	});
1049

    
1050
	test('HasProperty', function (t) {
1051
		forEach(v.primitives, function (primitive) {
1052
			t['throws'](
1053
				function () { ES.HasProperty(primitive, 'key'); },
1054
				TypeError,
1055
				debug(primitive) + ' is not an Object'
1056
			);
1057
		});
1058

    
1059
		forEach(v.nonPropertyKeys, function (nonKey) {
1060
			t['throws'](
1061
				function () { ES.HasProperty({}, nonKey); },
1062
				TypeError,
1063
				debug(nonKey) + ' is not a Property Key'
1064
			);
1065
		});
1066

    
1067
		t.equal(ES.HasProperty({}, 'nope'), false, 'object does not have nonexistent properties');
1068
		t.equal(ES.HasProperty({}, 'toString'), true, 'object has inherited properties');
1069
		t.equal(
1070
			ES.HasProperty({ toString: 1 }, 'toString'),
1071
			true,
1072
			'object has shadowed inherited own properties'
1073
		);
1074
		t.equal(ES.HasProperty({ a: 1 }, 'a'), true, 'object has own properties');
1075

    
1076
		t.end();
1077
	});
1078

    
1079
	test('IsConcatSpreadable', function (t) {
1080
		forEach(v.primitives, function (primitive) {
1081
			t.equal(ES.IsConcatSpreadable(primitive), false, debug(primitive) + ' is not an Object');
1082
		});
1083

    
1084
		var hasSymbolConcatSpreadable = v.hasSymbols && Symbol.isConcatSpreadable;
1085
		t.test('Symbol.isConcatSpreadable', { skip: !hasSymbolConcatSpreadable }, function (st) {
1086
			forEach(v.falsies, function (falsy) {
1087
				var obj = {};
1088
				obj[Symbol.isConcatSpreadable] = falsy;
1089
				st.equal(
1090
					ES.IsConcatSpreadable(obj),
1091
					false,
1092
					'an object with ' + debug(falsy) + ' as Symbol.isConcatSpreadable is not concat spreadable'
1093
				);
1094
			});
1095

    
1096
			forEach(v.truthies, function (truthy) {
1097
				var obj = {};
1098
				obj[Symbol.isConcatSpreadable] = truthy;
1099
				st.equal(
1100
					ES.IsConcatSpreadable(obj),
1101
					true,
1102
					'an object with ' + debug(truthy) + ' as Symbol.isConcatSpreadable is concat spreadable'
1103
				);
1104
			});
1105

    
1106
			st.end();
1107
		});
1108

    
1109
		forEach(v.objects, function (object) {
1110
			t.equal(
1111
				ES.IsConcatSpreadable(object),
1112
				false,
1113
				'non-array without Symbol.isConcatSpreadable is not concat spreadable'
1114
			);
1115
		});
1116

    
1117
		t.equal(ES.IsConcatSpreadable([]), true, 'arrays are concat spreadable');
1118

    
1119
		t.end();
1120
	});
1121

    
1122
	test('Invoke', function (t) {
1123
		forEach(v.nonPropertyKeys, function (nonKey) {
1124
			t['throws'](
1125
				function () { ES.Invoke({}, nonKey); },
1126
				TypeError,
1127
				debug(nonKey) + ' is not a Property Key'
1128
			);
1129
		});
1130

    
1131
		t['throws'](function () { ES.Invoke({ o: false }, 'o'); }, TypeError, 'fails on a non-function');
1132

    
1133
		t.test('invoked callback', function (st) {
1134
			var aValue = {};
1135
			var bValue = {};
1136
			var obj = {
1137
				f: function (a) {
1138
					st.equal(arguments.length, 2, '2 args passed');
1139
					st.equal(a, aValue, 'first arg is correct');
1140
					st.equal(arguments[1], bValue, 'second arg is correct');
1141
				}
1142
			};
1143
			st.plan(3);
1144
			ES.Invoke(obj, 'f', aValue, bValue);
1145
		});
1146

    
1147
		t.end();
1148
	});
1149

    
1150
	test('GetIterator', function (t) {
1151
		var arr = [1, 2];
1152
		testIterator(t, ES.GetIterator(arr), arr);
1153

    
1154
		testIterator(t, ES.GetIterator('abc'), 'abc'.split(''));
1155

    
1156
		t.test('Symbol.iterator', { skip: !v.hasSymbols }, function (st) {
1157
			var m = new Map();
1158
			m.set(1, 'a');
1159
			m.set(2, 'b');
1160

    
1161
			testIterator(st, ES.GetIterator(m), [[1, 'a'], [2, 'b']]);
1162

    
1163
			st.end();
1164
		});
1165

    
1166
		t.end();
1167
	});
1168

    
1169
	test('IteratorNext', { skip: true });
1170

    
1171
	test('IteratorComplete', { skip: true });
1172

    
1173
	test('IteratorValue', { skip: true });
1174

    
1175
	test('IteratorStep', { skip: true });
1176

    
1177
	test('IteratorClose', { skip: true });
1178

    
1179
	test('CreateIterResultObject', function (t) {
1180
		forEach(v.nonBooleans, function (nonBoolean) {
1181
			t['throws'](
1182
				function () { ES.CreateIterResultObject({}, nonBoolean); },
1183
				TypeError,
1184
				'"done" argument must be a boolean; ' + debug(nonBoolean) + ' is not'
1185
			);
1186
		});
1187

    
1188
		var value = {};
1189
		t.deepEqual(
1190
			ES.CreateIterResultObject(value, true),
1191
			{ value: value, done: true },
1192
			'creates a "done" iteration result'
1193
		);
1194
		t.deepEqual(
1195
			ES.CreateIterResultObject(value, false),
1196
			{ value: value, done: false },
1197
			'creates a "not done" iteration result'
1198
		);
1199

    
1200
		t.end();
1201
	});
1202

    
1203
	test('RegExpExec', function (t) {
1204
		forEach(v.primitives, function (primitive) {
1205
			t['throws'](
1206
				function () { ES.RegExpExec(primitive); },
1207
				TypeError,
1208
				'"R" argument must be an object; ' + debug(primitive) + ' is not'
1209
			);
1210
		});
1211

    
1212
		forEach(v.nonStrings, function (nonString) {
1213
			t['throws'](
1214
				function () { ES.RegExpExec({}, nonString); },
1215
				TypeError,
1216
				'"S" argument must be a String; ' + debug(nonString) + ' is not'
1217
			);
1218
		});
1219

    
1220
		t.test('gets and calls a callable "exec"', function (st) {
1221
			var str = '123';
1222
			var o = {
1223
				exec: function (S) {
1224
					st.equal(this, o, '"exec" receiver is R');
1225
					st.equal(S, str, '"exec" argument is S');
1226

    
1227
					return null;
1228
				}
1229
			};
1230
			st.plan(2);
1231
			ES.RegExpExec(o, str);
1232
			st.end();
1233
		});
1234

    
1235
		t.test('throws if a callable "exec" returns a non-null non-object', function (st) {
1236
			var str = '123';
1237
			st.plan(v.nonNullPrimitives.length);
1238
			forEach(v.nonNullPrimitives, function (nonNullPrimitive) {
1239
				st['throws'](
1240
					function () { ES.RegExpExec({ exec: function () { return nonNullPrimitive; } }, str); },
1241
					TypeError,
1242
					'"exec" method must return `null` or an Object; ' + debug(nonNullPrimitive) + ' is not'
1243
				);
1244
			});
1245
			st.end();
1246
		});
1247

    
1248
		t.test('actual regex that should match against a string', function (st) {
1249
			var S = 'aabc';
1250
			var R = /a/g;
1251
			var match1 = ES.RegExpExec(R, S);
1252
			var expected1 = assign(['a'], kludgeMatch(R, { index: 0, input: S }));
1253
			var match2 = ES.RegExpExec(R, S);
1254
			var expected2 = assign(['a'], kludgeMatch(R, { index: 1, input: S }));
1255
			var match3 = ES.RegExpExec(R, S);
1256
			st.deepEqual(match1, expected1, 'match object 1 is as expected');
1257
			st.deepEqual(match2, expected2, 'match object 2 is as expected');
1258
			st.equal(match3, null, 'match 3 is null as expected');
1259
			st.end();
1260
		});
1261

    
1262
		t.test('actual regex that should match against a string, with shadowed "exec"', function (st) {
1263
			var S = 'aabc';
1264
			var R = /a/g;
1265
			R.exec = undefined;
1266
			var match1 = ES.RegExpExec(R, S);
1267
			var expected1 = assign(['a'], kludgeMatch(R, { index: 0, input: S }));
1268
			var match2 = ES.RegExpExec(R, S);
1269
			var expected2 = assign(['a'], kludgeMatch(R, { index: 1, input: S }));
1270
			var match3 = ES.RegExpExec(R, S);
1271
			st.deepEqual(match1, expected1, 'match object 1 is as expected');
1272
			st.deepEqual(match2, expected2, 'match object 2 is as expected');
1273
			st.equal(match3, null, 'match 3 is null as expected');
1274
			st.end();
1275
		});
1276
		t.end();
1277
	});
1278

    
1279
	test('ArraySpeciesCreate', function (t) {
1280
		t.test('errors', function (st) {
1281
			var testNonNumber = function (nonNumber) {
1282
				st['throws'](
1283
					function () { ES.ArraySpeciesCreate([], nonNumber); },
1284
					TypeError,
1285
					debug(nonNumber) + ' is not a number'
1286
				);
1287
			};
1288
			forEach(v.nonNumbers, testNonNumber);
1289

    
1290
			st['throws'](
1291
				function () { ES.ArraySpeciesCreate([], -1); },
1292
				TypeError,
1293
				'-1 is not >= 0'
1294
			);
1295
			st['throws'](
1296
				function () { ES.ArraySpeciesCreate([], -Infinity); },
1297
				TypeError,
1298
				'-Infinity is not >= 0'
1299
			);
1300

    
1301
			var testNonIntegers = function (nonInteger) {
1302
				st['throws'](
1303
					function () { ES.ArraySpeciesCreate([], nonInteger); },
1304
					TypeError,
1305
					debug(nonInteger) + ' is not an integer'
1306
				);
1307
			};
1308
			forEach(v.nonIntegerNumbers, testNonIntegers);
1309

    
1310
			st.end();
1311
		});
1312

    
1313
		t.test('works with a non-array', function (st) {
1314
			forEach(v.objects.concat(v.primitives), function (nonArray) {
1315
				var arr = ES.ArraySpeciesCreate(nonArray, 0);
1316
				st.ok(ES.IsArray(arr), 'is an array');
1317
				st.equal(arr.length, 0, 'length is correct');
1318
				st.equal(arr.constructor, Array, 'constructor is correct');
1319
			});
1320

    
1321
			st.end();
1322
		});
1323

    
1324
		t.test('works with a normal array', function (st) {
1325
			var len = 2;
1326
			var orig = [1, 2, 3];
1327
			var arr = ES.ArraySpeciesCreate(orig, len);
1328

    
1329
			st.ok(ES.IsArray(arr), 'is an array');
1330
			st.equal(arr.length, len, 'length is correct');
1331
			st.equal(arr.constructor, orig.constructor, 'constructor is correct');
1332

    
1333
			st.end();
1334
		});
1335

    
1336
		t.test('-0 length produces +0 length', function (st) {
1337
			var len = -0;
1338
			st.ok(is(len, -0), '-0 is negative zero');
1339
			st.notOk(is(len, 0), '-0 is not positive zero');
1340

    
1341
			var orig = [1, 2, 3];
1342
			var arr = ES.ArraySpeciesCreate(orig, len);
1343

    
1344
			st.equal(ES.IsArray(arr), true);
1345
			st.ok(is(arr.length, 0));
1346
			st.equal(arr.constructor, orig.constructor);
1347

    
1348
			st.end();
1349
		});
1350

    
1351
		t.test('works with species construtor', { skip: !hasSpecies }, function (st) {
1352
			var sentinel = {};
1353
			var Foo = function Foo(len) {
1354
				this.length = len;
1355
				this.sentinel = sentinel;
1356
			};
1357
			var Bar = getArraySubclassWithSpeciesConstructor(Foo);
1358
			var bar = new Bar();
1359

    
1360
			st.equal(ES.IsArray(bar), true, 'Bar instance is an array');
1361

    
1362
			var arr = ES.ArraySpeciesCreate(bar, 3);
1363
			st.equal(arr.constructor, Foo, 'result used species constructor');
1364
			st.equal(arr.length, 3, 'length property is correct');
1365
			st.equal(arr.sentinel, sentinel, 'Foo constructor was exercised');
1366

    
1367
			st.end();
1368
		});
1369

    
1370
		t.test('works with null species constructor', { skip: !hasSpecies }, function (st) {
1371
			var Bar = getArraySubclassWithSpeciesConstructor(null);
1372
			var bar = new Bar();
1373

    
1374
			st.equal(ES.IsArray(bar), true, 'Bar instance is an array');
1375

    
1376
			var arr = ES.ArraySpeciesCreate(bar, 3);
1377
			st.equal(arr.constructor, Array, 'result used default constructor');
1378
			st.equal(arr.length, 3, 'length property is correct');
1379

    
1380
			st.end();
1381
		});
1382

    
1383
		t.test('works with undefined species constructor', { skip: !hasSpecies }, function (st) {
1384
			var Bar = getArraySubclassWithSpeciesConstructor();
1385
			var bar = new Bar();
1386

    
1387
			st.equal(ES.IsArray(bar), true, 'Bar instance is an array');
1388

    
1389
			var arr = ES.ArraySpeciesCreate(bar, 3);
1390
			st.equal(arr.constructor, Array, 'result used default constructor');
1391
			st.equal(arr.length, 3, 'length property is correct');
1392

    
1393
			st.end();
1394
		});
1395

    
1396
		t.test('throws with object non-construtor species constructor', { skip: !hasSpecies }, function (st) {
1397
			forEach(v.objects, function (obj) {
1398
				var Bar = getArraySubclassWithSpeciesConstructor(obj);
1399
				var bar = new Bar();
1400

    
1401
				st.equal(ES.IsArray(bar), true, 'Bar instance is an array');
1402

    
1403
				st['throws'](
1404
					function () { ES.ArraySpeciesCreate(bar, 3); },
1405
					TypeError,
1406
					debug(obj) + ' is not a constructor'
1407
				);
1408
			});
1409

    
1410
			st.end();
1411
		});
1412

    
1413
		t.end();
1414
	});
1415

    
1416
	test('CreateDataProperty', function (t) {
1417
		forEach(v.primitives, function (primitive) {
1418
			t['throws'](
1419
				function () { ES.CreateDataProperty(primitive); },
1420
				TypeError,
1421
				debug(primitive) + ' is not an object'
1422
			);
1423
		});
1424

    
1425
		forEach(v.nonPropertyKeys, function (nonPropertyKey) {
1426
			t['throws'](
1427
				function () { ES.CreateDataProperty({}, nonPropertyKey); },
1428
				TypeError,
1429
				debug(nonPropertyKey) + ' is not a property key'
1430
			);
1431
		});
1432

    
1433
		var sentinel = { id: 'sentinel' };
1434
		var secondSentinel = { id: 'second sentinel' };
1435
		forEach(v.propertyKeys, function (propertyKey) {
1436
			var obj = {};
1437
			var status = ES.CreateDataProperty(obj, propertyKey, sentinel);
1438
			t.equal(status, true, 'status is true');
1439
			t.equal(
1440
				obj[propertyKey],
1441
				sentinel,
1442
				debug(sentinel) + ' is installed on "' + debug(propertyKey) + '" on the object'
1443
			);
1444
			var secondStatus = ES.CreateDataProperty(obj, propertyKey, secondSentinel);
1445
			t.equal(secondStatus, true, 'second status is true');
1446
			t.equal(
1447
				obj[propertyKey],
1448
				secondSentinel,
1449
				debug(secondSentinel) + ' is installed on "' + debug(propertyKey) + '" on the object'
1450
			);
1451

    
1452
			t.test('with defineProperty', { skip: !defineProperty.oDP }, function (st) {
1453
				var nonWritable = defineProperty({}, propertyKey, { configurable: true, writable: false });
1454

    
1455
				var nonWritableStatus = ES.CreateDataProperty(nonWritable, propertyKey, sentinel);
1456
				st.equal(nonWritableStatus, false, 'create data property failed');
1457
				st.notEqual(
1458
					nonWritable[propertyKey],
1459
					sentinel,
1460
					debug(sentinel) + ' is not installed on "' + debug(propertyKey) + '" on the object when key is nonwritable'
1461
				);
1462

    
1463
				var nonConfigurable = defineProperty({}, propertyKey, { configurable: false, writable: true });
1464

    
1465
				var nonConfigurableStatus = ES.CreateDataProperty(nonConfigurable, propertyKey, sentinel);
1466
				st.equal(nonConfigurableStatus, false, 'create data property failed');
1467
				st.notEqual(
1468
					nonConfigurable[propertyKey],
1469
					sentinel,
1470
					debug(sentinel) + ' is not installed on "' + debug(propertyKey) + '" on the object when key is nonconfigurable'
1471
				);
1472
				st.end();
1473
			});
1474
		});
1475

    
1476
		t.end();
1477
	});
1478

    
1479
	test('CreateDataPropertyOrThrow', function (t) {
1480
		forEach(v.primitives, function (primitive) {
1481
			t['throws'](
1482
				function () { ES.CreateDataPropertyOrThrow(primitive); },
1483
				TypeError,
1484
				debug(primitive) + ' is not an object'
1485
			);
1486
		});
1487

    
1488
		forEach(v.nonPropertyKeys, function (nonPropertyKey) {
1489
			t['throws'](
1490
				function () { ES.CreateDataPropertyOrThrow({}, nonPropertyKey); },
1491
				TypeError,
1492
				debug(nonPropertyKey) + ' is not a property key'
1493
			);
1494
		});
1495

    
1496
		var sentinel = {};
1497
		forEach(v.propertyKeys, function (propertyKey) {
1498
			var obj = {};
1499
			var status = ES.CreateDataPropertyOrThrow(obj, propertyKey, sentinel);
1500
			t.equal(status, true, 'status is true');
1501
			t.equal(
1502
				obj[propertyKey],
1503
				sentinel,
1504
				debug(sentinel) + ' is installed on "' + debug(propertyKey) + '" on the object'
1505
			);
1506

    
1507
			if (typeof Object.preventExtensions === 'function') {
1508
				var notExtensible = {};
1509
				Object.preventExtensions(notExtensible);
1510

    
1511
				t['throws'](
1512
					function () { ES.CreateDataPropertyOrThrow(notExtensible, propertyKey, sentinel); },
1513
					TypeError,
1514
					'can not install ' + debug(propertyKey) + ' on non-extensible object'
1515
				);
1516
				t.notEqual(
1517
					notExtensible[propertyKey],
1518
					sentinel,
1519
					debug(sentinel) + ' is not installed on "' + debug(propertyKey) + '" on the object'
1520
				);
1521
			}
1522
		});
1523

    
1524
		t.end();
1525
	});
1526

    
1527
	test('ObjectCreate', function (t) {
1528
		forEach(v.nonNullPrimitives, function (value) {
1529
			t['throws'](
1530
				function () { ES.ObjectCreate(value); },
1531
				TypeError,
1532
				debug(value) + ' is not null, or an object'
1533
			);
1534
		});
1535

    
1536
		t.test('proto arg', function (st) {
1537
			var Parent = function Parent() {};
1538
			Parent.prototype.foo = {};
1539
			var child = ES.ObjectCreate(Parent.prototype);
1540
			st.equal(child instanceof Parent, true, 'child is instanceof Parent');
1541
			st.equal(child.foo, Parent.prototype.foo, 'child inherits properties from Parent.prototype');
1542

    
1543
			st.end();
1544
		});
1545

    
1546
		t.test('internal slots arg', function (st) {
1547
			st.doesNotThrow(function () { ES.ObjectCreate({}, []); }, 'an empty slot list is valid');
1548

    
1549
			st['throws'](
1550
				function () { ES.ObjectCreate({}, ['a']); },
1551
				SyntaxError,
1552
				'internal slots are not supported'
1553
			);
1554

    
1555
			st.end();
1556
		});
1557

    
1558
		t.test('null proto', { skip: !$setProto }, function (st) {
1559
			st.equal('toString' in {}, true, 'normal objects have toString');
1560
			st.equal('toString' in ES.ObjectCreate(null), false, 'makes a null object');
1561

    
1562
			st.end();
1563
		});
1564

    
1565
		t.test('null proto when no native Object.create', { skip: $setProto }, function (st) {
1566
			st['throws'](
1567
				function () { ES.ObjectCreate(null); },
1568
				SyntaxError,
1569
				'without a native Object.create, can not create null objects'
1570
			);
1571

    
1572
			st.end();
1573
		});
1574

    
1575
		t.end();
1576
	});
1577

    
1578
	test('AdvanceStringIndex', function (t) {
1579
		forEach(v.nonStrings, function (nonString) {
1580
			t['throws'](
1581
				function () { ES.AdvanceStringIndex(nonString); },
1582
				TypeError,
1583
				'"S" argument must be a String; ' + debug(nonString) + ' is not'
1584
			);
1585
		});
1586

    
1587
		var notInts = v.nonNumbers.concat(
1588
			v.nonIntegerNumbers,
1589
			v.infinities,
1590
			[NaN, [], new Date(), Math.pow(2, 53), -1]
1591
		);
1592
		forEach(notInts, function (nonInt) {
1593
			t['throws'](
1594
				function () { ES.AdvanceStringIndex('abc', nonInt); },
1595
				TypeError,
1596
				'"index" argument must be an integer, ' + debug(nonInt) + ' is not.'
1597
			);
1598
		});
1599

    
1600
		forEach(v.nonBooleans, function (nonBoolean) {
1601
			t['throws'](
1602
				function () { ES.AdvanceStringIndex('abc', 0, nonBoolean); },
1603
				TypeError,
1604
				debug(nonBoolean) + ' is not a Boolean'
1605
			);
1606
		});
1607

    
1608
		var str = 'a\uD83D\uDCA9c';
1609

    
1610
		t.test('non-unicode mode', function (st) {
1611
			for (var i = 0; i < str.length + 2; i += 1) {
1612
				st.equal(ES.AdvanceStringIndex(str, i, false), i + 1, i + ' advances to ' + (i + 1));
1613
			}
1614

    
1615
			st.end();
1616
		});
1617

    
1618
		t.test('unicode mode', function (st) {
1619
			st.equal(ES.AdvanceStringIndex(str, 0, true), 1, '0 advances to 1');
1620
			st.equal(ES.AdvanceStringIndex(str, 1, true), 3, '1 advances to 3');
1621
			st.equal(ES.AdvanceStringIndex(str, 2, true), 3, '2 advances to 3');
1622
			st.equal(ES.AdvanceStringIndex(str, 3, true), 4, '3 advances to 4');
1623
			st.equal(ES.AdvanceStringIndex(str, 4, true), 5, '4 advances to 5');
1624

    
1625
			st.end();
1626
		});
1627

    
1628
		t.test('lone surrogates', function (st) {
1629
			var halfPoo = 'a\uD83Dc';
1630

    
1631
			st.equal(ES.AdvanceStringIndex(halfPoo, 0, true), 1, '0 advances to 1');
1632
			st.equal(ES.AdvanceStringIndex(halfPoo, 1, true), 2, '1 advances to 2');
1633
			st.equal(ES.AdvanceStringIndex(halfPoo, 2, true), 3, '2 advances to 3');
1634
			st.equal(ES.AdvanceStringIndex(halfPoo, 3, true), 4, '3 advances to 4');
1635

    
1636
			st.end();
1637
		});
1638

    
1639
		t.test('surrogate pairs', function (st) {
1640
			var lowestPair = String.fromCharCode('0xD800') + String.fromCharCode('0xDC00');
1641
			var highestPair = String.fromCharCode('0xDBFF') + String.fromCharCode('0xDFFF');
1642
			var poop = String.fromCharCode('0xD83D') + String.fromCharCode('0xDCA9');
1643

    
1644
			st.equal(ES.AdvanceStringIndex(lowestPair, 0, true), 2, 'lowest surrogate pair, 0 -> 2');
1645
			st.equal(ES.AdvanceStringIndex(highestPair, 0, true), 2, 'highest surrogate pair, 0 -> 2');
1646
			st.equal(ES.AdvanceStringIndex(poop, 0, true), 2, 'poop, 0 -> 2');
1647

    
1648
			st.end();
1649
		});
1650

    
1651
		t.end();
1652
	});
1653

    
1654
	test('CreateMethodProperty', function (t) {
1655
		forEach(v.primitives, function (primitive) {
1656
			t['throws'](
1657
				function () { ES.CreateMethodProperty(primitive, 'key'); },
1658
				TypeError,
1659
				'O must be an Object'
1660
			);
1661
		});
1662

    
1663
		forEach(v.nonPropertyKeys, function (nonPropertyKey) {
1664
			t['throws'](
1665
				function () { ES.CreateMethodProperty({}, nonPropertyKey); },
1666
				TypeError,
1667
				debug(nonPropertyKey) + ' is not a Property Key'
1668
			);
1669
		});
1670

    
1671
		t.test('defines correctly', function (st) {
1672
			var obj = {};
1673
			var key = 'the key';
1674
			var value = { foo: 'bar' };
1675

    
1676
			st.equal(ES.CreateMethodProperty(obj, key, value), true, 'defines property successfully');
1677
			st.test('property descriptor', { skip: !getOwnPropertyDescriptor }, function (s2t) {
1678
				s2t.deepEqual(
1679
					getOwnPropertyDescriptor(obj, key),
1680
					{
1681
						configurable: true,
1682
						enumerable: false,
1683
						value: value,
1684
						writable: true
1685
					},
1686
					'sets the correct property descriptor'
1687
				);
1688

    
1689
				s2t.end();
1690
			});
1691
			st.equal(obj[key], value, 'sets the correct value');
1692

    
1693
			st.end();
1694
		});
1695

    
1696
		t.test('fails as expected on a frozen object', { skip: !Object.freeze }, function (st) {
1697
			var obj = Object.freeze({ foo: 'bar' });
1698
			st['throws'](
1699
				function () { ES.CreateMethodProperty(obj, 'foo', { value: 'baz' }); },
1700
				TypeError,
1701
				'nonconfigurable key can not be defined'
1702
			);
1703

    
1704
			st.end();
1705
		});
1706

    
1707
		t.test('fails as expected on a function with a nonconfigurable name', { skip: !functionsHaveNames || functionsHaveConfigurableNames }, function (st) {
1708
			st['throws'](
1709
				function () { ES.CreateMethodProperty(function () {}, 'name', { value: 'baz' }); },
1710
				TypeError,
1711
				'nonconfigurable function name can not be defined'
1712
			);
1713
			st.end();
1714
		});
1715

    
1716
		t.end();
1717
	});
1718

    
1719
	test('DefinePropertyOrThrow', function (t) {
1720
		forEach(v.primitives, function (primitive) {
1721
			t['throws'](
1722
				function () { ES.DefinePropertyOrThrow(primitive, 'key', {}); },
1723
				TypeError,
1724
				'O must be an Object'
1725
			);
1726
		});
1727

    
1728
		forEach(v.nonPropertyKeys, function (nonPropertyKey) {
1729
			t['throws'](
1730
				function () { ES.DefinePropertyOrThrow({}, nonPropertyKey, {}); },
1731
				TypeError,
1732
				debug(nonPropertyKey) + ' is not a Property Key'
1733
			);
1734
		});
1735

    
1736
		t.test('defines correctly', function (st) {
1737
			var obj = {};
1738
			var key = 'the key';
1739
			var descriptor = {
1740
				configurable: true,
1741
				enumerable: false,
1742
				value: { foo: 'bar' },
1743
				writable: true
1744
			};
1745

    
1746
			st.equal(ES.DefinePropertyOrThrow(obj, key, descriptor), true, 'defines property successfully');
1747
			st.test('property descriptor', { skip: !getOwnPropertyDescriptor }, function (s2t) {
1748
				s2t.deepEqual(
1749
					getOwnPropertyDescriptor(obj, key),
1750
					descriptor,
1751
					'sets the correct property descriptor'
1752
				);
1753

    
1754
				s2t.end();
1755
			});
1756
			st.deepEqual(obj[key], descriptor.value, 'sets the correct value');
1757

    
1758
			st.end();
1759
		});
1760

    
1761
		t.test('fails as expected on a frozen object', { skip: !Object.freeze }, function (st) {
1762
			var obj = Object.freeze({ foo: 'bar' });
1763
			st['throws'](
1764
				function () {
1765
					ES.DefinePropertyOrThrow(obj, 'foo', { configurable: true, value: 'baz' });
1766
				},
1767
				TypeError,
1768
				'nonconfigurable key can not be defined'
1769
			);
1770

    
1771
			st.end();
1772
		});
1773

    
1774
		t.test('fails as expected on a function with a nonconfigurable name', { skip: !functionsHaveNames || functionsHaveConfigurableNames }, function (st) {
1775
			st['throws'](
1776
				function () {
1777
					ES.DefinePropertyOrThrow(function () {}, 'name', { configurable: true, value: 'baz' });
1778
				},
1779
				TypeError,
1780
				'nonconfigurable function name can not be defined'
1781
			);
1782
			st.end();
1783
		});
1784

    
1785
		t.end();
1786
	});
1787

    
1788
	test('DeletePropertyOrThrow', function (t) {
1789
		forEach(v.primitives, function (primitive) {
1790
			t['throws'](
1791
				function () { ES.DeletePropertyOrThrow(primitive, 'key', {}); },
1792
				TypeError,
1793
				'O must be an Object'
1794
			);
1795
		});
1796

    
1797
		forEach(v.nonPropertyKeys, function (nonPropertyKey) {
1798
			t['throws'](
1799
				function () { ES.DeletePropertyOrThrow({}, nonPropertyKey, {}); },
1800
				TypeError,
1801
				debug(nonPropertyKey) + ' is not a Property Key'
1802
			);
1803
		});
1804

    
1805
		t.test('defines correctly', function (st) {
1806
			var obj = { 'the key': 42 };
1807
			var key = 'the key';
1808

    
1809
			st.equal(ES.DeletePropertyOrThrow(obj, key), true, 'deletes property successfully');
1810
			st.equal(key in obj, false, 'key is no longer in the object');
1811

    
1812
			st.end();
1813
		});
1814

    
1815
		t.test('fails as expected on a frozen object', { skip: !Object.freeze }, function (st) {
1816
			var obj = Object.freeze({ foo: 'bar' });
1817
			st['throws'](
1818
				function () { ES.DeletePropertyOrThrow(obj, 'foo'); },
1819
				TypeError,
1820
				'nonconfigurable key can not be deleted'
1821
			);
1822

    
1823
			st.end();
1824
		});
1825

    
1826
		t.test('fails as expected on a function with a nonconfigurable name', { skip: !functionsHaveNames || functionsHaveConfigurableNames }, function (st) {
1827
			st['throws'](
1828
				function () { ES.DeletePropertyOrThrow(function () {}, 'name'); },
1829
				TypeError,
1830
				'nonconfigurable function name can not be deleted'
1831
			);
1832
			st.end();
1833
		});
1834

    
1835
		t.end();
1836
	});
1837

    
1838
	test('EnumerableOwnNames', { skip: skips && skips.EnumerableOwnNames }, function (t) {
1839
		var obj = testEnumerableOwnNames(t, function (O) { return ES.EnumerableOwnNames(O); });
1840

    
1841
		t.deepEqual(
1842
			ES.EnumerableOwnNames(obj),
1843
			['own'],
1844
			'returns enumerable own names'
1845
		);
1846

    
1847
		t.end();
1848
	});
1849

    
1850
	test('thisNumberValue', function (t) {
1851
		forEach(v.nonNumbers, function (nonNumber) {
1852
			t['throws'](
1853
				function () { ES.thisNumberValue(nonNumber); },
1854
				TypeError,
1855
				debug(nonNumber) + ' is not a Number'
1856
			);
1857
		});
1858

    
1859
		forEach(v.numbers, function (number) {
1860
			t.equal(ES.thisNumberValue(number), number, debug(number) + ' is its own thisNumberValue');
1861
			var obj = Object(number);
1862
			t.equal(ES.thisNumberValue(obj), number, debug(obj) + ' is the boxed thisNumberValue');
1863
		});
1864

    
1865
		t.end();
1866
	});
1867

    
1868
	test('thisBooleanValue', function (t) {
1869
		forEach(v.nonBooleans, function (nonBoolean) {
1870
			t['throws'](
1871
				function () { ES.thisBooleanValue(nonBoolean); },
1872
				TypeError,
1873
				debug(nonBoolean) + ' is not a Boolean'
1874
			);
1875
		});
1876

    
1877
		forEach(v.booleans, function (boolean) {
1878
			t.equal(ES.thisBooleanValue(boolean), boolean, debug(boolean) + ' is its own thisBooleanValue');
1879
			var obj = Object(boolean);
1880
			t.equal(ES.thisBooleanValue(obj), boolean, debug(obj) + ' is the boxed thisBooleanValue');
1881
		});
1882

    
1883
		t.end();
1884
	});
1885

    
1886
	test('thisStringValue', function (t) {
1887
		forEach(v.nonStrings, function (nonString) {
1888
			t['throws'](
1889
				function () { ES.thisStringValue(nonString); },
1890
				TypeError,
1891
				debug(nonString) + ' is not a String'
1892
			);
1893
		});
1894

    
1895
		forEach(v.strings, function (string) {
1896
			t.equal(ES.thisStringValue(string), string, debug(string) + ' is its own thisStringValue');
1897
			var obj = Object(string);
1898
			t.equal(ES.thisStringValue(obj), string, debug(obj) + ' is the boxed thisStringValue');
1899
		});
1900

    
1901
		t.end();
1902
	});
1903

    
1904
	test('thisTimeValue', function (t) {
1905
		forEach(v.primitives.concat(v.objects), function (nonDate) {
1906
			t['throws'](
1907
				function () { ES.thisTimeValue(nonDate); },
1908
				TypeError,
1909
				debug(nonDate) + ' is not a Date'
1910
			);
1911
		});
1912

    
1913
		forEach(v.timestamps, function (timestamp) {
1914
			var date = new Date(timestamp);
1915

    
1916
			t.equal(ES.thisTimeValue(date), timestamp, debug(date) + ' is its own thisTimeValue');
1917
		});
1918

    
1919
		t.end();
1920
	});
1921

    
1922
	test('SetIntegrityLevel', function (t) {
1923
		forEach(v.primitives, function (primitive) {
1924
			t['throws'](
1925
				function () { ES.SetIntegrityLevel(primitive); },
1926
				TypeError,
1927
				debug(primitive) + ' is not an Object'
1928
			);
1929
		});
1930

    
1931
		t['throws'](
1932
			function () { ES.SetIntegrityLevel({}); },
1933
			/^TypeError: Assertion failed: `level` must be `"sealed"` or `"frozen"`$/,
1934
			'`level` must be `"sealed"` or `"frozen"`'
1935
		);
1936

    
1937
		var O = { a: 1 };
1938
		t.test('sealed', { skip: !Object.preventExtensions }, function (st) {
1939
			st.equal(ES.SetIntegrityLevel(O, 'sealed'), true);
1940
			st['throws'](
1941
				function () { O.b = 2; },
1942
				/^TypeError: (Cannot|Can't) add property b, object is not extensible$/,
1943
				'sealing prevent new properties from being added'
1944
			);
1945
			O.a = 2;
1946
			st.equal(O.a, 2, 'pre-frozen, existing properties are mutable');
1947
			st.end();
1948
		});
1949

    
1950
		t.test('frozen', { skip: !Object.freeze }, function (st) {
1951
			st.equal(ES.SetIntegrityLevel(O, 'frozen'), true);
1952
			st['throws'](
1953
				function () { O.a = 3; },
1954
				/^TypeError: Cannot assign to read only property 'a' of /,
1955
				'freezing prevents existing properties from being mutated'
1956
			);
1957
			st.end();
1958
		});
1959

    
1960
		t.end();
1961
	});
1962

    
1963
	test('TestIntegrityLevel', function (t) {
1964
		forEach(v.primitives, function (primitive) {
1965
			t['throws'](
1966
				function () { ES.TestIntegrityLevel(primitive); },
1967
				TypeError,
1968
				debug(primitive) + ' is not an Object'
1969
			);
1970
		});
1971

    
1972
		t['throws'](
1973
			function () { ES.TestIntegrityLevel({ a: 1 }); },
1974
			/^TypeError: Assertion failed: `level` must be `"sealed"` or `"frozen"`$/,
1975
			'`level` must be `"sealed"` or `"frozen"`'
1976
		);
1977

    
1978
		t.equal(ES.TestIntegrityLevel({ a: 1 }, 'sealed'), false, 'basic object is not sealed');
1979
		t.equal(ES.TestIntegrityLevel({ a: 1 }, 'frozen'), false, 'basic object is not frozen');
1980

    
1981
		t.test('preventExtensions', { skip: !Object.preventExtensions }, function (st) {
1982
			var o = Object.preventExtensions({ a: 1 });
1983
			st.equal(ES.TestIntegrityLevel(o, 'sealed'), false, 'nonextensible object is not sealed');
1984
			st.equal(ES.TestIntegrityLevel(o, 'frozen'), false, 'nonextensible object is not frozen');
1985

    
1986
			var empty = Object.preventExtensions({});
1987
			st.equal(ES.TestIntegrityLevel(empty, 'sealed'), true, 'empty nonextensible object is sealed');
1988
			st.equal(ES.TestIntegrityLevel(empty, 'frozen'), true, 'empty nonextensible object is frozen');
1989
			st.end();
1990
		});
1991

    
1992
		t.test('seal', { skip: !Object.seal }, function (st) {
1993
			var o = Object.seal({ a: 1 });
1994
			st.equal(ES.TestIntegrityLevel(o, 'sealed'), true, 'sealed object is sealed');
1995
			st.equal(ES.TestIntegrityLevel(o, 'frozen'), false, 'sealed object is not frozen');
1996

    
1997
			var empty = Object.seal({});
1998
			st.equal(ES.TestIntegrityLevel(empty, 'sealed'), true, 'empty sealed object is sealed');
1999
			st.equal(ES.TestIntegrityLevel(empty, 'frozen'), true, 'empty sealed object is frozen');
2000

    
2001
			st.end();
2002
		});
2003

    
2004
		t.test('freeze', { skip: !Object.freeze }, function (st) {
2005
			var o = Object.freeze({ a: 1 });
2006
			st.equal(ES.TestIntegrityLevel(o, 'sealed'), true, 'frozen object is sealed');
2007
			st.equal(ES.TestIntegrityLevel(o, 'frozen'), true, 'frozen object is frozen');
2008

    
2009
			var empty = Object.freeze({});
2010
			st.equal(ES.TestIntegrityLevel(empty, 'sealed'), true, 'empty frozen object is sealed');
2011
			st.equal(ES.TestIntegrityLevel(empty, 'frozen'), true, 'empty frozen object is frozen');
2012

    
2013
			st.end();
2014
		});
2015

    
2016
		t.end();
2017
	});
2018

    
2019
	test('OrdinaryHasInstance', function (t) {
2020
		forEach(v.nonFunctions, function (nonFunction) {
2021
			t.equal(ES.OrdinaryHasInstance(nonFunction, {}), false, debug(nonFunction) + ' is not callable');
2022
		});
2023

    
2024
		forEach(v.primitives, function (primitive) {
2025
			t.equal(ES.OrdinaryHasInstance(function () {}, primitive), false, debug(primitive) + ' is not an object');
2026
		});
2027

    
2028
		var C = function C() {};
2029
		var D = function D() {};
2030
		t.equal(ES.OrdinaryHasInstance(C, new C()), true, 'constructor function has an instance of itself');
2031
		t.equal(ES.OrdinaryHasInstance(C, new D()), false, 'constructor/instance mismatch is false');
2032
		t.equal(ES.OrdinaryHasInstance(D, new C()), false, 'instance/constructor mismatch is false');
2033
		t.equal(ES.OrdinaryHasInstance(C, {}), false, 'plain object is not an instance of a constructor');
2034
		t.equal(ES.OrdinaryHasInstance(Object, {}), true, 'plain object is an instance of Object');
2035

    
2036
		t.end();
2037
	});
2038

    
2039
	test('OrdinaryHasProperty', function (t) {
2040
		forEach(v.primitives, function (primitive) {
2041
			t['throws'](
2042
				function () { ES.OrdinaryHasProperty(primitive, ''); },
2043
				TypeError,
2044
				debug(primitive) + ' is not an object'
2045
			);
2046
		});
2047
		forEach(v.nonPropertyKeys, function (nonPropertyKey) {
2048
			t['throws'](
2049
				function () { ES.OrdinaryHasProperty({}, nonPropertyKey); },
2050
				TypeError,
2051
				'P: ' + debug(nonPropertyKey) + ' is not a Property Key'
2052
			);
2053
		});
2054

    
2055
		t.equal(ES.OrdinaryHasProperty({ a: 1 }, 'a'), true, 'own property is true');
2056
		t.equal(ES.OrdinaryHasProperty({}, 'toString'), true, 'inherited property is true');
2057
		t.equal(ES.OrdinaryHasProperty({}, 'nope'), false, 'absent property is false');
2058

    
2059
		t.end();
2060
	});
2061

    
2062
	test('InstanceofOperator', function (t) {
2063
		forEach(v.primitives, function (primitive) {
2064
			t['throws'](
2065
				function () { ES.InstanceofOperator(primitive, function () {}); },
2066
				TypeError,
2067
				debug(primitive) + ' is not an object'
2068
			);
2069
		});
2070

    
2071
		forEach(v.nonFunctions, function (nonFunction) {
2072
			t['throws'](
2073
				function () { ES.InstanceofOperator({}, nonFunction); },
2074
				TypeError,
2075
				debug(nonFunction) + ' is not callable'
2076
			);
2077
		});
2078

    
2079
		var C = function C() {};
2080
		var D = function D() {};
2081

    
2082
		t.equal(ES.InstanceofOperator(new C(), C), true, 'constructor function has an instance of itself');
2083
		t.equal(ES.InstanceofOperator(new D(), C), false, 'constructor/instance mismatch is false');
2084
		t.equal(ES.InstanceofOperator(new C(), D), false, 'instance/constructor mismatch is false');
2085
		t.equal(ES.InstanceofOperator({}, C), false, 'plain object is not an instance of a constructor');
2086
		t.equal(ES.InstanceofOperator({}, Object), true, 'plain object is an instance of Object');
2087

    
2088
		t.test('Symbol.hasInstance', { skip: !v.hasSymbols || !Symbol.hasInstance }, function (st) {
2089
			st.plan(4);
2090

    
2091
			var O = {};
2092
			var C2 = function () {};
2093
			st.equal(ES.InstanceofOperator(O, C2), false, 'O is not an instance of C2');
2094

    
2095
			defineProperty(C2, Symbol.hasInstance, {
2096
				value: function (obj) {
2097
					st.equal(this, C2, 'hasInstance receiver is C2');
2098
					st.equal(obj, O, 'hasInstance argument is O');
2099

    
2100
					return {}; // testing coercion to boolean
2101
				}
2102
			});
2103

    
2104
			st.equal(ES.InstanceofOperator(O, C2), true, 'O is now an instance of C2');
2105

    
2106
			st.end();
2107
		});
2108

    
2109
		t.end();
2110
	});
2111

    
2112
	test('Abstract Equality Comparison', function (t) {
2113
		t.test('same types use ===', function (st) {
2114
			forEach(v.primitives.concat(v.objects), function (value) {
2115
				st.equal(ES['Abstract Equality Comparison'](value, value), value === value, debug(value) + ' is abstractly equal to itself');
2116
			});
2117
			st.end();
2118
		});
2119

    
2120
		t.test('different types coerce', function (st) {
2121
			var pairs = [
2122
				[null, undefined],
2123
				[3, '3'],
2124
				[true, '3'],
2125
				[true, 3],
2126
				[false, 0],
2127
				[false, '0'],
2128
				[3, [3]],
2129
				['3', [3]],
2130
				[true, [1]],
2131
				[false, [0]],
2132
				[String(v.coercibleObject), v.coercibleObject],
2133
				[Number(String(v.coercibleObject)), v.coercibleObject],
2134
				[Number(v.coercibleObject), v.coercibleObject],
2135
				[String(Number(v.coercibleObject)), v.coercibleObject]
2136
			];
2137
			forEach(pairs, function (pair) {
2138
				var a = pair[0];
2139
				var b = pair[1];
2140
				// eslint-disable-next-line eqeqeq
2141
				st.equal(ES['Abstract Equality Comparison'](a, b), a == b, debug(a) + ' == ' + debug(b));
2142
				// eslint-disable-next-line eqeqeq
2143
				st.equal(ES['Abstract Equality Comparison'](b, a), b == a, debug(b) + ' == ' + debug(a));
2144
			});
2145
			st.end();
2146
		});
2147

    
2148
		t.end();
2149
	});
2150

    
2151
	test('Strict Equality Comparison', function (t) {
2152
		t.test('same types use ===', function (st) {
2153
			forEach(v.primitives.concat(v.objects), function (value) {
2154
				st.equal(ES['Strict Equality Comparison'](value, value), value === value, debug(value) + ' is strictly equal to itself');
2155
			});
2156
			st.end();
2157
		});
2158

    
2159
		t.test('different types are not ===', function (st) {
2160
			var pairs = [
2161
				[null, undefined],
2162
				[3, '3'],
2163
				[true, '3'],
2164
				[true, 3],
2165
				[false, 0],
2166
				[false, '0'],
2167
				[3, [3]],
2168
				['3', [3]],
2169
				[true, [1]],
2170
				[false, [0]],
2171
				[String(v.coercibleObject), v.coercibleObject],
2172
				[Number(String(v.coercibleObject)), v.coercibleObject],
2173
				[Number(v.coercibleObject), v.coercibleObject],
2174
				[String(Number(v.coercibleObject)), v.coercibleObject]
2175
			];
2176
			forEach(pairs, function (pair) {
2177
				var a = pair[0];
2178
				var b = pair[1];
2179
				st.equal(ES['Strict Equality Comparison'](a, b), a === b, debug(a) + ' === ' + debug(b));
2180
				st.equal(ES['Strict Equality Comparison'](b, a), b === a, debug(b) + ' === ' + debug(a));
2181
			});
2182
			st.end();
2183
		});
2184

    
2185
		t.end();
2186
	});
2187

    
2188
	test('Abstract Relational Comparison', function (t) {
2189
		t.test('at least one operand is NaN', function (st) {
2190
			st.equal(ES['Abstract Relational Comparison'](NaN, {}, true), undefined, 'LeftFirst: first is NaN, returns undefined');
2191
			st.equal(ES['Abstract Relational Comparison']({}, NaN, true), undefined, 'LeftFirst: second is NaN, returns undefined');
2192
			st.equal(ES['Abstract Relational Comparison'](NaN, {}, false), undefined, '!LeftFirst: first is NaN, returns undefined');
2193
			st.equal(ES['Abstract Relational Comparison']({}, NaN, false), undefined, '!LeftFirst: second is NaN, returns undefined');
2194
			st.end();
2195
		});
2196

    
2197
		t.equal(ES['Abstract Relational Comparison'](3, 4, true), true, 'LeftFirst: 3 is less than 4');
2198
		t.equal(ES['Abstract Relational Comparison'](4, 3, true), false, 'LeftFirst: 3 is not less than 4');
2199
		t.equal(ES['Abstract Relational Comparison'](3, 4, false), true, '!LeftFirst: 3 is less than 4');
2200
		t.equal(ES['Abstract Relational Comparison'](4, 3, false), false, '!LeftFirst: 3 is not less than 4');
2201

    
2202
		t.equal(ES['Abstract Relational Comparison']('3', '4', true), true, 'LeftFirst: "3" is less than "4"');
2203
		t.equal(ES['Abstract Relational Comparison']('4', '3', true), false, 'LeftFirst: "3" is not less than "4"');
2204
		t.equal(ES['Abstract Relational Comparison']('3', '4', false), true, '!LeftFirst: "3" is less than "4"');
2205
		t.equal(ES['Abstract Relational Comparison']('4', '3', false), false, '!LeftFirst: "3" is not less than "4"');
2206

    
2207
		t.equal(ES['Abstract Relational Comparison'](v.coercibleObject, 42, true), true, 'LeftFirst: coercible object is less than 42');
2208
		t.equal(ES['Abstract Relational Comparison'](42, v.coercibleObject, true), false, 'LeftFirst: 42 is not less than coercible object');
2209
		t.equal(ES['Abstract Relational Comparison'](v.coercibleObject, 42, false), true, '!LeftFirst: coercible object is less than 42');
2210
		t.equal(ES['Abstract Relational Comparison'](42, v.coercibleObject, false), false, '!LeftFirst: 42 is not less than coercible object');
2211

    
2212
		t.equal(ES['Abstract Relational Comparison'](v.coercibleObject, '3', true), false, 'LeftFirst: coercible object is not less than "3"');
2213
		t.equal(ES['Abstract Relational Comparison']('3', v.coercibleObject, true), false, 'LeftFirst: "3" is not less than coercible object');
2214
		t.equal(ES['Abstract Relational Comparison'](v.coercibleObject, '3', false), false, '!LeftFirst: coercible object is not less than "3"');
2215
		t.equal(ES['Abstract Relational Comparison']('3', v.coercibleObject, false), false, '!LeftFirst: "3" is not less than coercible object');
2216

    
2217
		t.end();
2218
	});
2219

    
2220
	test('ValidateAndApplyPropertyDescriptor', function (t) {
2221
		forEach(v.nonUndefinedPrimitives, function (nonUndefinedPrimitive) {
2222
			t['throws'](
2223
				function () { ES.ValidateAndApplyPropertyDescriptor(nonUndefinedPrimitive, '', false, v.genericDescriptor(), v.genericDescriptor()); },
2224
				TypeError,
2225
				'O: ' + debug(nonUndefinedPrimitive) + ' is not undefined or an Object'
2226
			);
2227
		});
2228

    
2229
		forEach(v.nonBooleans, function (nonBoolean) {
2230
			t['throws'](
2231
				function () {
2232
					return ES.ValidateAndApplyPropertyDescriptor(
2233
						undefined,
2234
						null,
2235
						nonBoolean,
2236
						v.genericDescriptor(),
2237
						v.genericDescriptor()
2238
					);
2239
				},
2240
				TypeError,
2241
				'extensible: ' + debug(nonBoolean) + ' is not a Boolean'
2242
			);
2243
		});
2244

    
2245
		forEach(v.primitives, function (primitive) {
2246
			// Desc must be a Property Descriptor
2247
			t['throws'](
2248
				function () {
2249
					return ES.ValidateAndApplyPropertyDescriptor(
2250
						undefined,
2251
						null,
2252
						false,
2253
						primitive,
2254
						v.genericDescriptor()
2255
					);
2256
				},
2257
				TypeError,
2258
				'Desc: ' + debug(primitive) + ' is not a Property Descriptor'
2259
			);
2260
		});
2261

    
2262
		forEach(v.nonUndefinedPrimitives, function (primitive) {
2263
			// current must be undefined or a Property Descriptor
2264
			t['throws'](
2265
				function () {
2266
					return ES.ValidateAndApplyPropertyDescriptor(
2267
						undefined,
2268
						null,
2269
						false,
2270
						v.genericDescriptor(),
2271
						primitive
2272
					);
2273
				},
2274
				TypeError,
2275
				'current: ' + debug(primitive) + ' is not a Property Descriptor or undefined'
2276
			);
2277
		});
2278

    
2279
		forEach(v.nonPropertyKeys, function (nonPropertyKey) {
2280
			// if O is an object, P must be a property key
2281
			t['throws'](
2282
				function () {
2283
					return ES.ValidateAndApplyPropertyDescriptor(
2284
						{},
2285
						nonPropertyKey,
2286
						false,
2287
						v.genericDescriptor(),
2288
						v.genericDescriptor()
2289
					);
2290
				},
2291
				TypeError,
2292
				'P: ' + debug(nonPropertyKey) + ' is not a Property Key'
2293
			);
2294
		});
2295

    
2296
		t.test('current is undefined', function (st) {
2297
			var propertyKey = 'howdy';
2298

    
2299
			st.test('generic descriptor', function (s2t) {
2300
				var generic = v.genericDescriptor();
2301
				generic['[[Enumerable]]'] = true;
2302
				var O = {};
2303
				ES.ValidateAndApplyPropertyDescriptor(undefined, propertyKey, true, generic);
2304
				s2t.equal(
2305
					ES.ValidateAndApplyPropertyDescriptor(O, propertyKey, false, generic),
2306
					false,
2307
					'when extensible is false, nothing happens'
2308
				);
2309
				s2t.deepEqual(O, {}, 'no changes applied when O is undefined or extensible is false');
2310
				s2t.equal(
2311
					ES.ValidateAndApplyPropertyDescriptor(O, propertyKey, true, generic),
2312
					true,
2313
					'operation is successful'
2314
				);
2315
				var expected = {};
2316
				expected[propertyKey] = undefined;
2317
				s2t.deepEqual(O, expected, 'generic descriptor has been defined as an own data property');
2318
				s2t.end();
2319
			});
2320

    
2321
			st.test('data descriptor', function (s2t) {
2322
				var data = v.dataDescriptor();
2323
				data['[[Enumerable]]'] = true;
2324

    
2325
				var O = {};
2326
				s2t.equal(
2327
					ES.ValidateAndApplyPropertyDescriptor(undefined, propertyKey, true, data),
2328
					true,
2329
					'noop when O is undefined'
2330
				);
2331
				s2t.equal(
2332
					ES.ValidateAndApplyPropertyDescriptor(O, propertyKey, false, data),
2333
					false,
2334
					'when extensible is false, nothing happens'
2335
				);
2336
				s2t.deepEqual(O, {}, 'no changes applied when O is undefined or extensible is false');
2337
				s2t.equal(
2338
					ES.ValidateAndApplyPropertyDescriptor(O, propertyKey, true, data),
2339
					true,
2340
					'operation is successful'
2341
				);
2342
				var expected = {};
2343
				expected[propertyKey] = data['[[Value]]'];
2344
				s2t.deepEqual(O, expected, 'data descriptor has been defined as an own data property');
2345
				s2t.end();
2346
			});
2347

    
2348
			st.test('accessor descriptor', { skip: !defineProperty.oDP }, function (s2t) {
2349
				var count = 0;
2350
				var accessor = v.accessorDescriptor();
2351
				accessor['[[Enumerable]]'] = true;
2352
				accessor['[[Get]]'] = function () {
2353
					count += 1;
2354
					return count;
2355
				};
2356

    
2357
				var O = {};
2358
				ES.ValidateAndApplyPropertyDescriptor(undefined, propertyKey, true, accessor);
2359
				s2t.equal(
2360
					ES.ValidateAndApplyPropertyDescriptor(O, propertyKey, false, accessor),
2361
					false,
2362
					'when extensible is false, nothing happens'
2363
				);
2364
				s2t.deepEqual(O, {}, 'no changes applied when O is undefined or extensible is false');
2365
				s2t.equal(
2366
					ES.ValidateAndApplyPropertyDescriptor(O, propertyKey, true, accessor),
2367
					true,
2368
					'operation is successful'
2369
				);
2370
				var expected = {};
2371
				expected[propertyKey] = accessor['[[Get]]']() + 1;
2372
				s2t.deepEqual(O, expected, 'accessor descriptor has been defined as an own accessor property');
2373
				s2t.end();
2374
			});
2375

    
2376
			st.end();
2377
		});
2378

    
2379
		t.test('every field in Desc is absent', { skip: 'it is unclear if having no fields qualifies Desc to be a Property Descriptor' });
2380

    
2381
		forEach([v.dataDescriptor, v.accessorDescriptor, v.mutatorDescriptor], function (getDescriptor) {
2382
			t.equal(
2383
				ES.ValidateAndApplyPropertyDescriptor(undefined, 'property key', true, getDescriptor(), getDescriptor()),
2384
				true,
2385
				'when Desc and current are the same, early return true'
2386
			);
2387
		});
2388

    
2389
		t.test('current is nonconfigurable', function (st) {
2390
			// note: these must not be generic descriptors, or else the algorithm returns an early true
2391
			st.equal(
2392
				ES.ValidateAndApplyPropertyDescriptor(
2393
					undefined,
2394
					'property key',
2395
					true,
2396
					v.descriptors.configurable(v.dataDescriptor()),
2397
					v.descriptors.nonConfigurable(v.dataDescriptor())
2398
				),
2399
				false,
2400
				'false if Desc is configurable'
2401
			);
2402

    
2403
			st.equal(
2404
				ES.ValidateAndApplyPropertyDescriptor(
2405
					undefined,
2406
					'property key',
2407
					true,
2408
					v.descriptors.enumerable(v.dataDescriptor()),
2409
					v.descriptors.nonEnumerable(v.dataDescriptor())
2410
				),
2411
				false,
2412
				'false if Desc is Enumerable and current is not'
2413
			);
2414

    
2415
			st.equal(
2416
				ES.ValidateAndApplyPropertyDescriptor(
2417
					undefined,
2418
					'property key',
2419
					true,
2420
					v.descriptors.nonEnumerable(v.dataDescriptor()),
2421
					v.descriptors.enumerable(v.dataDescriptor())
2422
				),
2423
				false,
2424
				'false if Desc is not Enumerable and current is'
2425
			);
2426

    
2427
			var descLackingEnumerable = v.accessorDescriptor();
2428
			delete descLackingEnumerable['[[Enumerable]]'];
2429
			st.equal(
2430
				ES.ValidateAndApplyPropertyDescriptor(
2431
					undefined,
2432
					'property key',
2433
					true,
2434
					descLackingEnumerable,
2435
					v.descriptors.enumerable(v.accessorDescriptor())
2436
				),
2437
				true,
2438
				'not false if Desc lacks Enumerable'
2439
			);
2440

    
2441
			st.end();
2442
		});
2443

    
2444
		t.test('Desc and current: one is a data descriptor, one is not', { skip: !defineProperty || !getOwnPropertyDescriptor }, function (st) {
2445
			// note: Desc must be configurable if current is nonconfigurable, to hit this branch
2446
			st.equal(
2447
				ES.ValidateAndApplyPropertyDescriptor(
2448
					undefined,
2449
					'property key',
2450
					true,
2451
					v.descriptors.configurable(v.accessorDescriptor()),
2452
					v.descriptors.nonConfigurable(v.dataDescriptor())
2453
				),
2454
				false,
2455
				'false if current (data) is nonconfigurable'
2456
			);
2457

    
2458
			st.equal(
2459
				ES.ValidateAndApplyPropertyDescriptor(
2460
					undefined,
2461
					'property key',
2462
					true,
2463
					v.descriptors.configurable(v.dataDescriptor()),
2464
					v.descriptors.nonConfigurable(v.accessorDescriptor())
2465
				),
2466
				false,
2467
				'false if current (not data) is nonconfigurable'
2468
			);
2469

    
2470
			// one is data and one is not,
2471
			//	// if current is data, convert to accessor
2472
			//	// else convert to data
2473

    
2474
			var startsWithData = {
2475
				'property key': 42
2476
			};
2477
			st.equal(
2478
				ES.ValidateAndApplyPropertyDescriptor(
2479
					startsWithData,
2480
					'property key',
2481
					true,
2482
					v.descriptors.enumerable(v.descriptors.configurable(v.accessorDescriptor())),
2483
					v.descriptors.enumerable(v.descriptors.configurable(v.dataDescriptor()))
2484
				),
2485
				true,
2486
				'operation is successful: current is data, Desc is accessor'
2487
			);
2488
			var shouldBeAccessor = getOwnPropertyDescriptor(startsWithData, 'property key');
2489
			st.equal(typeof shouldBeAccessor.get, 'function', 'has a getter');
2490

    
2491
			var key = 'property key';
2492
			var startsWithAccessor = {};
2493
			defineProperty(startsWithAccessor, key, {
2494
				configurable: true,
2495
				enumerable: true,
2496
				get: function get() { return 42; }
2497
			});
2498
			st.equal(
2499
				ES.ValidateAndApplyPropertyDescriptor(
2500
					startsWithAccessor,
2501
					key,
2502
					true,
2503
					v.descriptors.enumerable(v.descriptors.configurable(v.dataDescriptor())),
2504
					v.descriptors.enumerable(v.descriptors.configurable(v.accessorDescriptor(42)))
2505
				),
2506
				true,
2507
				'operation is successful: current is accessor, Desc is data'
2508
			);
2509
			var shouldBeData = getOwnPropertyDescriptor(startsWithAccessor, 'property key');
2510
			st.deepEqual(shouldBeData, { configurable: true, enumerable: true, value: 42, writable: false }, 'is a data property');
2511

    
2512
			st.end();
2513
		});
2514

    
2515
		t.test('Desc and current are both data descriptors', function (st) {
2516
			st.equal(
2517
				ES.ValidateAndApplyPropertyDescriptor(
2518
					undefined,
2519
					'property key',
2520
					true,
2521
					v.descriptors.writable(v.dataDescriptor()),
2522
					v.descriptors.nonWritable(v.descriptors.nonConfigurable(v.dataDescriptor()))
2523
				),
2524
				false,
2525
				'false if frozen current and writable Desc'
2526
			);
2527

    
2528
			st.equal(
2529
				ES.ValidateAndApplyPropertyDescriptor(
2530
					undefined,
2531
					'property key',
2532
					true,
2533
					v.descriptors.configurable({ '[[Value]]': 42 }),
2534
					v.descriptors.nonWritable({ '[[Value]]': 7 })
2535
				),
2536
				false,
2537
				'false if nonwritable current has a different value than Desc'
2538
			);
2539

    
2540
			st.end();
2541
		});
2542

    
2543
		t.test('current is nonconfigurable; Desc and current are both accessor descriptors', function (st) {
2544
			st.equal(
2545
				ES.ValidateAndApplyPropertyDescriptor(
2546
					undefined,
2547
					'property key',
2548
					true,
2549
					v.mutatorDescriptor(),
2550
					v.descriptors.nonConfigurable(v.mutatorDescriptor())
2551
				),
2552
				false,
2553
				'false if both Sets are not equal'
2554
			);
2555

    
2556
			st.equal(
2557
				ES.ValidateAndApplyPropertyDescriptor(
2558
					undefined,
2559
					'property key',
2560
					true,
2561
					v.accessorDescriptor(),
2562
					v.descriptors.nonConfigurable(v.accessorDescriptor())
2563
				),
2564
				false,
2565
				'false if both Gets are not equal'
2566
			);
2567

    
2568
			st.end();
2569
		});
2570

    
2571
		t.end();
2572
	});
2573

    
2574
	test('OrdinaryGetOwnProperty', function (t) {
2575
		forEach(v.primitives, function (primitive) {
2576
			t['throws'](
2577
				function () { ES.OrdinaryGetOwnProperty(primitive, ''); },
2578
				TypeError,
2579
				'O: ' + debug(primitive) + ' is not an Object'
2580
			);
2581
		});
2582
		forEach(v.nonPropertyKeys, function (nonPropertyKey) {
2583
			t['throws'](
2584
				function () { ES.OrdinaryGetOwnProperty({}, nonPropertyKey); },
2585
				TypeError,
2586
				'P: ' + debug(nonPropertyKey) + ' is not a Property Key'
2587
			);
2588
		});
2589

    
2590
		t.equal(ES.OrdinaryGetOwnProperty({}, 'not in the object'), undefined, 'missing property yields undefined');
2591
		t.equal(ES.OrdinaryGetOwnProperty({}, 'toString'), undefined, 'inherited non-own property yields undefined');
2592

    
2593
		t.deepEqual(
2594
			ES.OrdinaryGetOwnProperty({ a: 1 }, 'a'),
2595
			ES.ToPropertyDescriptor({
2596
				configurable: true,
2597
				enumerable: true,
2598
				value: 1,
2599
				writable: true
2600
			}),
2601
			'own assigned data property yields expected descriptor'
2602
		);
2603

    
2604
		t.deepEqual(
2605
			ES.OrdinaryGetOwnProperty(/a/, 'lastIndex'),
2606
			ES.ToPropertyDescriptor({
2607
				configurable: false,
2608
				enumerable: false,
2609
				value: 0,
2610
				writable: true
2611
			}),
2612
			'regex lastIndex yields expected descriptor'
2613
		);
2614

    
2615
		t.deepEqual(
2616
			ES.OrdinaryGetOwnProperty([], 'length'),
2617
			ES.ToPropertyDescriptor({
2618
				configurable: false,
2619
				enumerable: false,
2620
				value: 0,
2621
				writable: true
2622
			}),
2623
			'array length yields expected descriptor'
2624
		);
2625

    
2626
		t.deepEqual(
2627
			ES.OrdinaryGetOwnProperty(Object.prototype, 'toString'),
2628
			ES.ToPropertyDescriptor({
2629
				configurable: true,
2630
				enumerable: false,
2631
				value: Object.prototype.toString,
2632
				writable: true
2633
			}),
2634
			'own non-enumerable data property yields expected descriptor'
2635
		);
2636

    
2637
		t.test('ES5+', { skip: !defineProperty.oDP }, function (st) {
2638
			var O = {};
2639
			defineProperty(O, 'foo', {
2640
				configurable: false,
2641
				enumerable: false,
2642
				value: O,
2643
				writable: true
2644
			});
2645

    
2646
			st.deepEqual(
2647
				ES.OrdinaryGetOwnProperty(O, 'foo'),
2648
				ES.ToPropertyDescriptor({
2649
					configurable: false,
2650
					enumerable: false,
2651
					value: O,
2652
					writable: true
2653
				}),
2654
				'defined own property yields expected descriptor'
2655
			);
2656

    
2657
			st.end();
2658
		});
2659

    
2660
		t.end();
2661
	});
2662

    
2663
	test('OrdinaryDefineOwnProperty', { skip: !getOwnPropertyDescriptor }, function (t) {
2664
		forEach(v.primitives, function (primitive) {
2665
			t['throws'](
2666
				function () { ES.CopyDataProperties(primitive, {}, []); },
2667
				TypeError,
2668
				'O: ' + debug(primitive) + ' is not an Object'
2669
			);
2670
		});
2671
		forEach(v.nonPropertyKeys, function (nonPropertyKey) {
2672
			t['throws'](
2673
				function () { ES.OrdinaryDefineOwnProperty({}, nonPropertyKey, v.genericDescriptor()); },
2674
				TypeError,
2675
				'P: ' + debug(nonPropertyKey) + ' is not a Property Key'
2676
			);
2677
		});
2678
		forEach(v.primitives, function (primitive) {
2679
			t['throws'](
2680
				function () { ES.OrdinaryDefineOwnProperty(primitive, '', v.genericDescriptor()); },
2681
				TypeError,
2682
				'Desc: ' + debug(primitive) + ' is not a Property Descriptor'
2683
			);
2684
		});
2685

    
2686
		var O = {};
2687
		var P = 'property key';
2688
		var Desc = v.accessorDescriptor();
2689
		t.equal(
2690
			ES.OrdinaryDefineOwnProperty(O, P, Desc),
2691
			true,
2692
			'operation is successful'
2693
		);
2694
		t.deepEqual(
2695
			getOwnPropertyDescriptor(O, P),
2696
			ES.FromPropertyDescriptor(ES.CompletePropertyDescriptor(Desc)),
2697
			'expected property descriptor is defined'
2698
		);
2699

    
2700
		t.end();
2701
	});
2702

    
2703
	test('ArrayCreate', function (t) {
2704
		forEach(v.nonIntegerNumbers.concat([-1]), function (nonIntegerNumber) {
2705
			t['throws'](
2706
				function () { ES.ArrayCreate(nonIntegerNumber); },
2707
				TypeError,
2708
				'length must be an integer number >= 0'
2709
			);
2710
		});
2711

    
2712
		t['throws'](
2713
			function () { ES.ArrayCreate(Math.pow(2, 32)); },
2714
			RangeError,
2715
			'length must be < 2**32'
2716
		);
2717

    
2718
		t.deepEqual(ES.ArrayCreate(-0), [], 'length of -0 creates an empty array');
2719
		t.deepEqual(ES.ArrayCreate(0), [], 'length of +0 creates an empty array');
2720
		// eslint-disable-next-line no-sparse-arrays, comma-spacing
2721
		t.deepEqual(ES.ArrayCreate(1), [,], 'length of 1 creates a sparse array of length 1');
2722
		// eslint-disable-next-line no-sparse-arrays, comma-spacing
2723
		t.deepEqual(ES.ArrayCreate(2), [,,], 'length of 2 creates a sparse array of length 2');
2724

    
2725
		t.test('proto argument', { skip: !$setProto }, function (st) {
2726
			var fakeProto = {
2727
				push: { toString: function () { return 'not array push'; } }
2728
			};
2729
			st.equal(ES.ArrayCreate(0, fakeProto).push, fakeProto.push, 'passing the proto argument works');
2730
			st.end();
2731
		});
2732

    
2733
		t.end();
2734
	});
2735

    
2736
	test('ArraySetLength', function (t) {
2737
		forEach(v.primitives.concat(v.objects), function (nonArray) {
2738
			t['throws'](
2739
				function () { ES.ArraySetLength(nonArray, 0); },
2740
				TypeError,
2741
				'A: ' + debug(nonArray) + ' is not an Array'
2742
			);
2743
		});
2744

    
2745
		forEach(v.nonUndefinedPrimitives, function (primitive) {
2746
			t['throws'](
2747
				function () { ES.ArraySetLength([], primitive); },
2748
				TypeError,
2749
				'Desc: ' + debug(primitive) + ' is not a Property Descriptor'
2750
			);
2751
		});
2752

    
2753
		t.test('making length nonwritable', { skip: !getOwnPropertyDescriptor }, function (st) {
2754
			var a = [];
2755
			ES.ArraySetLength(a, { '[[Writable]]': false });
2756
			st.deepEqual(
2757
				getOwnPropertyDescriptor(a, 'length'),
2758
				{
2759
					configurable: false,
2760
					enumerable: false,
2761
					value: 0,
2762
					writable: false
2763
				},
2764
				'without a value, length becomes nonwritable'
2765
			);
2766
			st.end();
2767
		});
2768

    
2769
		var arr = [];
2770
		ES.ArraySetLength(arr, { '[[Value]]': 7 });
2771
		t.equal(arr.length, 7, 'array now has a length of 7');
2772

    
2773
		t.end();
2774
	});
2775

    
2776
	test('CreateHTML', function (t) {
2777
		forEach(v.nonStrings, function (nonString) {
2778
			t['throws'](
2779
				function () { ES.CreateHTML('', nonString, '', ''); },
2780
				TypeError,
2781
				'tag: ' + debug(nonString) + ' is not a String'
2782
			);
2783
			t['throws'](
2784
				function () { ES.CreateHTML('', '', nonString, ''); },
2785
				TypeError,
2786
				'attribute: ' + debug(nonString) + ' is not a String'
2787
			);
2788
		});
2789

    
2790
		t.equal(
2791
			ES.CreateHTML(
2792
				{ toString: function () { return 'the string'; } },
2793
				'some HTML tag!',
2794
				''
2795
			),
2796
			'<some HTML tag!>the string</some HTML tag!>',
2797
			'works with an empty string attribute value'
2798
		);
2799

    
2800
		t.equal(
2801
			ES.CreateHTML(
2802
				{ toString: function () { return 'the string'; } },
2803
				'some HTML tag!',
2804
				'attr',
2805
				'value "with quotes"'
2806
			),
2807
			'<some HTML tag! attr="value &quot;with quotes&quot;">the string</some HTML tag!>',
2808
			'works with an attribute, and a value with quotes'
2809
		);
2810

    
2811
		t.end();
2812
	});
2813

    
2814
	test('GetOwnPropertyKeys', function (t) {
2815
		forEach(v.primitives, function (primitive) {
2816
			t['throws'](
2817
				function () { ES.GetOwnPropertyKeys(primitive, 'String'); },
2818
				TypeError,
2819
				'O: ' + debug(primitive) + ' is not an Object'
2820
			);
2821
		});
2822

    
2823
		t['throws'](
2824
			function () { ES.GetOwnPropertyKeys({}, 'not string or symbol'); },
2825
			TypeError,
2826
			'Type: must be "String" or "Symbol"'
2827
		);
2828

    
2829
		t.test('Symbols', { skip: !v.hasSymbols }, function (st) {
2830
			var O = { a: 1 };
2831
			O[Symbol.iterator] = true;
2832
			var s = Symbol('test');
2833
			defineProperty(O, s, { enumerable: false, value: true });
2834

    
2835
			st.deepEqual(
2836
				ES.GetOwnPropertyKeys(O, 'Symbol'),
2837
				[Symbol.iterator, s],
2838
				'works with Symbols, enumerable or not'
2839
			);
2840

    
2841
			st.end();
2842
		});
2843

    
2844
		t.test('non-enumerable names', { skip: !defineProperty.oDP }, function (st) {
2845
			var O = { a: 1 };
2846
			defineProperty(O, 'b', { enumerable: false, value: 2 });
2847
			if (v.hasSymbols) {
2848
				O[Symbol.iterator] = true;
2849
			}
2850

    
2851
			st.deepEqual(
2852
				ES.GetOwnPropertyKeys(O, 'String').sort(),
2853
				['a', 'b'].sort(),
2854
				'works with Strings, enumerable or not'
2855
			);
2856

    
2857
			st.end();
2858
		});
2859

    
2860
		t.deepEqual(
2861
			ES.GetOwnPropertyKeys({ a: 1, b: 2 }, 'String').sort(),
2862
			['a', 'b'].sort(),
2863
			'works with enumerable keys'
2864
		);
2865

    
2866
		t.end();
2867
	});
2868

    
2869
	test('SymbolDescriptiveString', function (t) {
2870
		forEach(v.nonSymbolPrimitives.concat(v.objects), function (nonSymbol) {
2871
			t['throws'](
2872
				function () { ES.SymbolDescriptiveString(nonSymbol); },
2873
				TypeError,
2874
				debug(nonSymbol) + ' is not a Symbol'
2875
			);
2876
		});
2877

    
2878
		t.test('Symbols', { skip: !v.hasSymbols }, function (st) {
2879
			st.equal(ES.SymbolDescriptiveString(Symbol()), 'Symbol()', 'undefined description');
2880
			st.equal(ES.SymbolDescriptiveString(Symbol('')), 'Symbol()', 'empty string description');
2881
			st.equal(ES.SymbolDescriptiveString(Symbol.iterator), 'Symbol(Symbol.iterator)', 'well-known symbol');
2882
			st.equal(ES.SymbolDescriptiveString(Symbol('foo')), 'Symbol(foo)', 'string description');
2883

    
2884
			st.end();
2885
		});
2886

    
2887
		t.end();
2888
	});
2889

    
2890
	test('GetSubstitution', { skip: skips && skips.GetSubstitution }, function (t) {
2891
		forEach(v.nonStrings, function (nonString) {
2892
			t['throws'](
2893
				function () { ES.GetSubstitution(nonString, '', 0, [], ''); },
2894
				TypeError,
2895
				'`matched`: ' + debug(nonString) + ' is not a String'
2896
			);
2897

    
2898
			t['throws'](
2899
				function () { ES.GetSubstitution('', nonString, 0, [], ''); },
2900
				TypeError,
2901
				'`str`: ' + debug(nonString) + ' is not a String'
2902
			);
2903

    
2904
			t['throws'](
2905
				function () { ES.GetSubstitution('', '', 0, [], nonString); },
2906
				TypeError,
2907
				'`replacement`: ' + debug(nonString) + ' is not a String'
2908
			);
2909

    
2910
			if (canDistinguishSparseFromUndefined || typeof nonString !== 'undefined') {
2911
				t['throws'](
2912
					function () { ES.GetSubstitution('', '', 0, [nonString], ''); },
2913
					TypeError,
2914
					'`captures`: ' + debug([nonString]) + ' is not an Array of strings'
2915
				);
2916
			}
2917
		});
2918

    
2919
		forEach(v.nonIntegerNumbers.concat([-1, -42, -Infinity]), function (nonNonNegativeInteger) {
2920
			t['throws'](
2921
				function () { ES.GetSubstitution('', '', nonNonNegativeInteger, [], ''); },
2922
				TypeError,
2923
				'`position`: ' + debug(nonNonNegativeInteger) + ' is not a non-negative integer'
2924
			);
2925
		});
2926

    
2927
		forEach(v.nonArrays, function (nonArray) {
2928
			t['throws'](
2929
				function () { ES.GetSubstitution('', '', 0, nonArray, ''); },
2930
				TypeError,
2931
				'`captures`: ' + debug(nonArray) + ' is not an Array'
2932
			);
2933
		});
2934

    
2935
		t.equal(
2936
			ES.GetSubstitution('def', 'abcdefghi', 3, [], '123'),
2937
			'123',
2938
			'returns the substitution'
2939
		);
2940
		t.equal(
2941
			ES.GetSubstitution('abcdef', 'abcdefghi', 0, [], '$$2$'),
2942
			'$2$',
2943
			'supports $$, and trailing $'
2944
		);
2945

    
2946
		t.equal(
2947
			ES.GetSubstitution('abcdef', 'abcdefghi', 0, [], '>$&<'),
2948
			'>abcdef<',
2949
			'supports $&'
2950
		);
2951

    
2952
		t.equal(
2953
			ES.GetSubstitution('abcdef', 'abcdefghi', 0, [], '>$`<'),
2954
			'><',
2955
			'supports $` at position 0'
2956
		);
2957
		t.equal(
2958
			ES.GetSubstitution('def', 'abcdefghi', 3, [], '>$`<'),
2959
			'>ab<',
2960
			'supports $` at position > 0'
2961
		);
2962

    
2963
		t.equal(
2964
			ES.GetSubstitution('def', 'abcdefghi', 7, [], ">$'<"),
2965
			'><',
2966
			"supports $' at a position where there's less than `matched.length` chars left"
2967
		);
2968
		t.equal(
2969
			ES.GetSubstitution('def', 'abcdefghi', 3, [], ">$'<"),
2970
			'>ghi<',
2971
			"supports $' at a position where there's more than `matched.length` chars left"
2972
		);
2973

    
2974
		for (var i = 0; i < 100; i += 1) {
2975
			var captures = [];
2976
			captures[i] = 'test';
2977
			if (i > 0) {
2978
				t.equal(
2979
					ES.GetSubstitution('abcdef', 'abcdefghi', 0, [], '>$' + i + '<'),
2980
					'>undefined<',
2981
					'supports $' + i + ' with no captures'
2982
				);
2983
				t.equal(
2984
					ES.GetSubstitution('abcdef', 'abcdefghi', 0, [], '>$' + i),
2985
					'>undefined',
2986
					'supports $' + i + ' at the end of the replacement, with no captures'
2987
				);
2988
				t.equal(
2989
					ES.GetSubstitution('abcdef', 'abcdefghi', 0, captures, '>$' + i + '<'),
2990
					'><',
2991
					'supports $' + i + ' with a capture at that index'
2992
				);
2993
				t.equal(
2994
					ES.GetSubstitution('abcdef', 'abcdefghi', 0, captures, '>$' + i),
2995
					'>',
2996
					'supports $' + i + ' at the end of the replacement, with a capture at that index'
2997
				);
2998
			}
2999
			if (i < 10) {
3000
				t.equal(
3001
					ES.GetSubstitution('abcdef', 'abcdefghi', 0, [], '>$0' + i + '<'),
3002
					i === 0 ? '><' : '>undefined<',
3003
					'supports $0' + i + ' with no captures'
3004
				);
3005
				t.equal(
3006
					ES.GetSubstitution('abcdef', 'abcdefghi', 0, [], '>$0' + i),
3007
					i === 0 ? '>' : '>undefined',
3008
					'supports $0' + i + ' at the end of the replacement, with no captures'
3009
				);
3010
				t.equal(
3011
					ES.GetSubstitution('abcdef', 'abcdefghi', 0, captures, '>$0' + i + '<'),
3012
					'><',
3013
					'supports $0' + i + ' with a capture at that index'
3014
				);
3015
				t.equal(
3016
					ES.GetSubstitution('abcdef', 'abcdefghi', 0, captures, '>$0' + i),
3017
					'>',
3018
					'supports $0' + i + ' at the end of the replacement, with a capture at that index'
3019
				);
3020
			}
3021
		}
3022

    
3023
		t.end();
3024
	});
3025

    
3026
	test('SecFromTime', function (t) {
3027
		var now = new Date();
3028
		t.equal(ES.SecFromTime(now.getTime()), now.getUTCSeconds(), 'second from Date timestamp matches getUTCSeconds');
3029
		t.end();
3030
	});
3031

    
3032
	test('MinFromTime', function (t) {
3033
		var now = new Date();
3034
		t.equal(ES.MinFromTime(now.getTime()), now.getUTCMinutes(), 'minute from Date timestamp matches getUTCMinutes');
3035
		t.end();
3036
	});
3037

    
3038
	test('HourFromTime', function (t) {
3039
		var now = new Date();
3040
		t.equal(ES.HourFromTime(now.getTime()), now.getUTCHours(), 'hour from Date timestamp matches getUTCHours');
3041
		t.end();
3042
	});
3043

    
3044
	test('msFromTime', function (t) {
3045
		var now = new Date();
3046
		t.equal(ES.msFromTime(now.getTime()), now.getUTCMilliseconds(), 'ms from Date timestamp matches getUTCMilliseconds');
3047
		t.end();
3048
	});
3049

    
3050
	var msPerSecond = 1e3;
3051
	var msPerMinute = 60 * msPerSecond;
3052
	var msPerHour = 60 * msPerMinute;
3053
	var msPerDay = 24 * msPerHour;
3054

    
3055
	test('Day', function (t) {
3056
		var time = Date.UTC(2019, 8, 10, 2, 3, 4, 5);
3057
		var add = 2.5;
3058
		var later = new Date(time + (add * msPerDay));
3059

    
3060
		t.equal(ES.Day(later.getTime()), ES.Day(time) + Math.floor(add), 'adding 2.5 days worth of ms, gives a Day delta of 2');
3061
		t.end();
3062
	});
3063

    
3064
	test('TimeWithinDay', function (t) {
3065
		var time = Date.UTC(2019, 8, 10, 2, 3, 4, 5);
3066
		var add = 2.5;
3067
		var later = new Date(time + (add * msPerDay));
3068

    
3069
		t.equal(ES.TimeWithinDay(later.getTime()), ES.TimeWithinDay(time) + (0.5 * msPerDay), 'adding 2.5 days worth of ms, gives a TimeWithinDay delta of +0.5');
3070
		t.end();
3071
	});
3072

    
3073
	test('DayFromYear', function (t) {
3074
		t.equal(ES.DayFromYear(2021) - ES.DayFromYear(2020), 366, '2021 is a leap year, has 366 days');
3075
		t.equal(ES.DayFromYear(2020) - ES.DayFromYear(2019), 365, '2020 is not a leap year, has 365 days');
3076
		t.equal(ES.DayFromYear(2019) - ES.DayFromYear(2018), 365, '2019 is not a leap year, has 365 days');
3077
		t.equal(ES.DayFromYear(2018) - ES.DayFromYear(2017), 365, '2018 is not a leap year, has 365 days');
3078
		t.equal(ES.DayFromYear(2017) - ES.DayFromYear(2016), 366, '2017 is a leap year, has 366 days');
3079

    
3080
		t.end();
3081
	});
3082

    
3083
	test('TimeFromYear', function (t) {
3084
		for (var i = 1900; i < 2100; i += 1) {
3085
			t.equal(ES.TimeFromYear(i), Date.UTC(i, 0, 1), 'TimeFromYear matches a Date object’s year: ' + i);
3086
		}
3087
		t.end();
3088
	});
3089

    
3090
	test('YearFromTime', function (t) {
3091
		for (var i = 1900; i < 2100; i += 1) {
3092
			t.equal(ES.YearFromTime(Date.UTC(i, 0, 1)), i, 'YearFromTime matches a Date object’s year on 1/1: ' + i);
3093
			t.equal(ES.YearFromTime(Date.UTC(i, 10, 1)), i, 'YearFromTime matches a Date object’s year on 10/1: ' + i);
3094
		}
3095
		t.end();
3096
	});
3097

    
3098
	test('WeekDay', function (t) {
3099
		var now = new Date();
3100
		var today = now.getUTCDay();
3101
		for (var i = 0; i < 7; i += 1) {
3102
			var weekDay = ES.WeekDay(now.getTime() + (i * msPerDay));
3103
			t.equal(weekDay, (today + i) % 7, i + ' days after today (' + today + '), WeekDay is ' + weekDay);
3104
		}
3105
		t.end();
3106
	});
3107

    
3108
	test('DaysInYear', function (t) {
3109
		t.equal(ES.DaysInYear(2021), 365, '2021 is not a leap year');
3110
		t.equal(ES.DaysInYear(2020), 366, '2020 is a leap year');
3111
		t.equal(ES.DaysInYear(2019), 365, '2019 is not a leap year');
3112
		t.equal(ES.DaysInYear(2018), 365, '2018 is not a leap year');
3113
		t.equal(ES.DaysInYear(2017), 365, '2017 is not a leap year');
3114
		t.equal(ES.DaysInYear(2016), 366, '2016 is a leap year');
3115

    
3116
		t.end();
3117
	});
3118

    
3119
	test('InLeapYear', function (t) {
3120
		t.equal(ES.InLeapYear(Date.UTC(2021, 0, 1)), 0, '2021 is not a leap year');
3121
		t.equal(ES.InLeapYear(Date.UTC(2020, 0, 1)), 1, '2020 is a leap year');
3122
		t.equal(ES.InLeapYear(Date.UTC(2019, 0, 1)), 0, '2019 is not a leap year');
3123
		t.equal(ES.InLeapYear(Date.UTC(2018, 0, 1)), 0, '2018 is not a leap year');
3124
		t.equal(ES.InLeapYear(Date.UTC(2017, 0, 1)), 0, '2017 is not a leap year');
3125
		t.equal(ES.InLeapYear(Date.UTC(2016, 0, 1)), 1, '2016 is a leap year');
3126

    
3127
		t.end();
3128
	});
3129

    
3130
	test('DayWithinYear', function (t) {
3131
		t.equal(ES.DayWithinYear(Date.UTC(2019, 0, 1)), 0, '1/1 is the 1st day');
3132
		t.equal(ES.DayWithinYear(Date.UTC(2019, 11, 31)), 364, '12/31 is the 365th day in a non leap year');
3133
		t.equal(ES.DayWithinYear(Date.UTC(2016, 11, 31)), 365, '12/31 is the 366th day in a leap year');
3134

    
3135
		t.end();
3136
	});
3137

    
3138
	test('MonthFromTime', function (t) {
3139
		t.equal(ES.MonthFromTime(Date.UTC(2019, 0, 1)), 0, 'non-leap: 1/1 gives January');
3140
		t.equal(ES.MonthFromTime(Date.UTC(2019, 0, 31)), 0, 'non-leap: 1/31 gives January');
3141
		t.equal(ES.MonthFromTime(Date.UTC(2019, 1, 1)), 1, 'non-leap: 2/1 gives February');
3142
		t.equal(ES.MonthFromTime(Date.UTC(2019, 1, 28)), 1, 'non-leap: 2/28 gives February');
3143
		t.equal(ES.MonthFromTime(Date.UTC(2019, 1, 29)), 2, 'non-leap: 2/29 gives March');
3144
		t.equal(ES.MonthFromTime(Date.UTC(2019, 2, 1)), 2, 'non-leap: 3/1 gives March');
3145
		t.equal(ES.MonthFromTime(Date.UTC(2019, 2, 31)), 2, 'non-leap: 3/31 gives March');
3146
		t.equal(ES.MonthFromTime(Date.UTC(2019, 3, 1)), 3, 'non-leap: 4/1 gives April');
3147
		t.equal(ES.MonthFromTime(Date.UTC(2019, 3, 30)), 3, 'non-leap: 4/30 gives April');
3148
		t.equal(ES.MonthFromTime(Date.UTC(2019, 4, 1)), 4, 'non-leap: 5/1 gives May');
3149
		t.equal(ES.MonthFromTime(Date.UTC(2019, 4, 31)), 4, 'non-leap: 5/31 gives May');
3150
		t.equal(ES.MonthFromTime(Date.UTC(2019, 5, 1)), 5, 'non-leap: 6/1 gives June');
3151
		t.equal(ES.MonthFromTime(Date.UTC(2019, 5, 30)), 5, 'non-leap: 6/30 gives June');
3152
		t.equal(ES.MonthFromTime(Date.UTC(2019, 6, 1)), 6, 'non-leap: 7/1 gives July');
3153
		t.equal(ES.MonthFromTime(Date.UTC(2019, 6, 31)), 6, 'non-leap: 7/31 gives July');
3154
		t.equal(ES.MonthFromTime(Date.UTC(2019, 7, 1)), 7, 'non-leap: 8/1 gives August');
3155
		t.equal(ES.MonthFromTime(Date.UTC(2019, 7, 30)), 7, 'non-leap: 8/30 gives August');
3156
		t.equal(ES.MonthFromTime(Date.UTC(2019, 8, 1)), 8, 'non-leap: 9/1 gives September');
3157
		t.equal(ES.MonthFromTime(Date.UTC(2019, 8, 30)), 8, 'non-leap: 9/30 gives September');
3158
		t.equal(ES.MonthFromTime(Date.UTC(2019, 9, 1)), 9, 'non-leap: 10/1 gives October');
3159
		t.equal(ES.MonthFromTime(Date.UTC(2019, 9, 31)), 9, 'non-leap: 10/31 gives October');
3160
		t.equal(ES.MonthFromTime(Date.UTC(2019, 10, 1)), 10, 'non-leap: 11/1 gives November');
3161
		t.equal(ES.MonthFromTime(Date.UTC(2019, 10, 30)), 10, 'non-leap: 11/30 gives November');
3162
		t.equal(ES.MonthFromTime(Date.UTC(2019, 11, 1)), 11, 'non-leap: 12/1 gives December');
3163
		t.equal(ES.MonthFromTime(Date.UTC(2019, 11, 31)), 11, 'non-leap: 12/31 gives December');
3164

    
3165
		t.equal(ES.MonthFromTime(Date.UTC(2016, 0, 1)), 0, 'leap: 1/1 gives January');
3166
		t.equal(ES.MonthFromTime(Date.UTC(2016, 0, 31)), 0, 'leap: 1/31 gives January');
3167
		t.equal(ES.MonthFromTime(Date.UTC(2016, 1, 1)), 1, 'leap: 2/1 gives February');
3168
		t.equal(ES.MonthFromTime(Date.UTC(2016, 1, 28)), 1, 'leap: 2/28 gives February');
3169
		t.equal(ES.MonthFromTime(Date.UTC(2016, 1, 29)), 1, 'leap: 2/29 gives February');
3170
		t.equal(ES.MonthFromTime(Date.UTC(2016, 2, 1)), 2, 'leap: 3/1 gives March');
3171
		t.equal(ES.MonthFromTime(Date.UTC(2016, 2, 31)), 2, 'leap: 3/31 gives March');
3172
		t.equal(ES.MonthFromTime(Date.UTC(2016, 3, 1)), 3, 'leap: 4/1 gives April');
3173
		t.equal(ES.MonthFromTime(Date.UTC(2016, 3, 30)), 3, 'leap: 4/30 gives April');
3174
		t.equal(ES.MonthFromTime(Date.UTC(2016, 4, 1)), 4, 'leap: 5/1 gives May');
3175
		t.equal(ES.MonthFromTime(Date.UTC(2016, 4, 31)), 4, 'leap: 5/31 gives May');
3176
		t.equal(ES.MonthFromTime(Date.UTC(2016, 5, 1)), 5, 'leap: 6/1 gives June');
3177
		t.equal(ES.MonthFromTime(Date.UTC(2016, 5, 30)), 5, 'leap: 6/30 gives June');
3178
		t.equal(ES.MonthFromTime(Date.UTC(2016, 6, 1)), 6, 'leap: 7/1 gives July');
3179
		t.equal(ES.MonthFromTime(Date.UTC(2016, 6, 31)), 6, 'leap: 7/31 gives July');
3180
		t.equal(ES.MonthFromTime(Date.UTC(2016, 7, 1)), 7, 'leap: 8/1 gives August');
3181
		t.equal(ES.MonthFromTime(Date.UTC(2016, 7, 30)), 7, 'leap: 8/30 gives August');
3182
		t.equal(ES.MonthFromTime(Date.UTC(2016, 8, 1)), 8, 'leap: 9/1 gives September');
3183
		t.equal(ES.MonthFromTime(Date.UTC(2016, 8, 30)), 8, 'leap: 9/30 gives September');
3184
		t.equal(ES.MonthFromTime(Date.UTC(2016, 9, 1)), 9, 'leap: 10/1 gives October');
3185
		t.equal(ES.MonthFromTime(Date.UTC(2016, 9, 31)), 9, 'leap: 10/31 gives October');
3186
		t.equal(ES.MonthFromTime(Date.UTC(2016, 10, 1)), 10, 'leap: 11/1 gives November');
3187
		t.equal(ES.MonthFromTime(Date.UTC(2016, 10, 30)), 10, 'leap: 11/30 gives November');
3188
		t.equal(ES.MonthFromTime(Date.UTC(2016, 11, 1)), 11, 'leap: 12/1 gives December');
3189
		t.equal(ES.MonthFromTime(Date.UTC(2016, 11, 31)), 11, 'leap: 12/31 gives December');
3190
		t.end();
3191
	});
3192

    
3193
	test('DateFromTime', function (t) {
3194
		var i;
3195
		for (i = 1; i <= 28; i += 1) {
3196
			t.equal(ES.DateFromTime(Date.UTC(2019, 1, i)), i, '2019.02.' + i + ' is date ' + i);
3197
		}
3198
		for (i = 1; i <= 29; i += 1) {
3199
			t.equal(ES.DateFromTime(Date.UTC(2016, 1, i)), i, '2016.02.' + i + ' is date ' + i);
3200
		}
3201
		for (i = 1; i <= 30; i += 1) {
3202
			t.equal(ES.DateFromTime(Date.UTC(2019, 8, i)), i, '2019.09.' + i + ' is date ' + i);
3203
		}
3204
		for (i = 1; i <= 31; i += 1) {
3205
			t.equal(ES.DateFromTime(Date.UTC(2019, 9, i)), i, '2019.10.' + i + ' is date ' + i);
3206
		}
3207
		t.end();
3208
	});
3209

    
3210
	test('MakeDay', function (t) {
3211
		var day2015 = 16687;
3212
		t.equal(ES.MakeDay(2015, 8, 9), day2015, '2015.09.09 is day 16687');
3213
		var day2016 = day2015 + 366; // 2016 is a leap year
3214
		t.equal(ES.MakeDay(2016, 8, 9), day2016, '2015.09.09 is day 17053');
3215
		var day2017 = day2016 + 365;
3216
		t.equal(ES.MakeDay(2017, 8, 9), day2017, '2017.09.09 is day 17418');
3217
		var day2018 = day2017 + 365;
3218
		t.equal(ES.MakeDay(2018, 8, 9), day2018, '2018.09.09 is day 17783');
3219
		var day2019 = day2018 + 365;
3220
		t.equal(ES.MakeDay(2019, 8, 9), day2019, '2019.09.09 is day 18148');
3221
		t.end();
3222
	});
3223

    
3224
	test('MakeDate', function (t) {
3225
		forEach(v.infinities.concat(NaN), function (nonFiniteNumber) {
3226
			t.ok(is(ES.MakeDate(nonFiniteNumber, 0), NaN), debug(nonFiniteNumber) + ' is not a finite `day`');
3227
			t.ok(is(ES.MakeDate(0, nonFiniteNumber), NaN), debug(nonFiniteNumber) + ' is not a finite `time`');
3228
		});
3229
		t.equal(ES.MakeDate(0, 0), 0, 'zero day and zero time is zero date');
3230
		t.equal(ES.MakeDate(0, 123), 123, 'zero day and nonzero time is a date of the "time"');
3231
		t.equal(ES.MakeDate(1, 0), msPerDay, 'day of 1 and zero time is a date of "ms per day"');
3232
		t.equal(ES.MakeDate(3, 0), 3 * msPerDay, 'day of 3 and zero time is a date of thrice "ms per day"');
3233
		t.equal(ES.MakeDate(1, 123), msPerDay + 123, 'day of 1 and nonzero time is a date of "ms per day" plus the "time"');
3234
		t.equal(ES.MakeDate(3, 123), (3 * msPerDay) + 123, 'day of 3 and nonzero time is a date of thrice "ms per day" plus the "time"');
3235

    
3236
		t.end();
3237
	});
3238

    
3239
	test('MakeTime', function (t) {
3240
		forEach(v.infinities.concat(NaN), function (nonFiniteNumber) {
3241
			t.ok(is(ES.MakeTime(nonFiniteNumber, 0, 0, 0), NaN), debug(nonFiniteNumber) + ' is not a finite `hour`');
3242
			t.ok(is(ES.MakeTime(0, nonFiniteNumber, 0, 0), NaN), debug(nonFiniteNumber) + ' is not a finite `min`');
3243
			t.ok(is(ES.MakeTime(0, 0, nonFiniteNumber, 0), NaN), debug(nonFiniteNumber) + ' is not a finite `sec`');
3244
			t.ok(is(ES.MakeTime(0, 0, 0, nonFiniteNumber), NaN), debug(nonFiniteNumber) + ' is not a finite `ms`');
3245
		});
3246

    
3247
		t.equal(
3248
			ES.MakeTime(1.2, 2.3, 3.4, 4.5),
3249
			(1 * msPerHour) + (2 * msPerMinute) + (3 * msPerSecond) + 4,
3250
			'all numbers are converted to integer, multiplied by the right number of ms, and summed'
3251
		);
3252

    
3253
		t.end();
3254
	});
3255

    
3256
	test('TimeClip', function (t) {
3257
		forEach(v.infinities.concat(NaN), function (nonFiniteNumber) {
3258
			t.ok(is(ES.TimeClip(nonFiniteNumber), NaN), debug(nonFiniteNumber) + ' is not a finite `time`');
3259
		});
3260
		t.ok(is(ES.TimeClip(8.64e15 + 1), NaN), '8.64e15 is the largest magnitude considered "finite"');
3261
		t.ok(is(ES.TimeClip(-8.64e15 - 1), NaN), '-8.64e15 is the largest magnitude considered "finite"');
3262

    
3263
		forEach(v.zeroes.concat([-10, 10, +new Date()]), function (time) {
3264
			t.looseEqual(ES.TimeClip(time), time, debug(time) + ' is a time of ' + debug(time));
3265
		});
3266

    
3267
		t.end();
3268
	});
3269

    
3270
	test('modulo', function (t) {
3271
		t.equal(3 % 2, 1, '+3 % 2 is +1');
3272
		t.equal(ES.modulo(3, 2), 1, '+3 mod 2 is +1');
3273

    
3274
		t.equal(-3 % 2, -1, '-3 % 2 is -1');
3275
		t.equal(ES.modulo(-3, 2), 1, '-3 mod 2 is +1');
3276
		t.end();
3277
	});
3278

    
3279
	test('ToDateString', function (t) {
3280
		forEach(v.nonNumbers, function (nonNumber) {
3281
			t['throws'](
3282
				function () { ES.ToDateString(nonNumber); },
3283
				TypeError,
3284
				debug(nonNumber) + ' is not a Number'
3285
			);
3286
		});
3287

    
3288
		t.equal(ES.ToDateString(NaN), 'Invalid Date', 'NaN becomes "Invalid Date"');
3289
		var now = +new Date();
3290
		t.equal(ES.ToDateString(now), Date(now), 'any timestamp becomes `Date(timestamp)`');
3291
		t.end();
3292
	});
3293

    
3294
	test('CreateListFromArrayLike', function (t) {
3295
		forEach(v.primitives, function (nonObject) {
3296
			t['throws'](
3297
				function () { ES.CreateListFromArrayLike(nonObject); },
3298
				TypeError,
3299
				debug(nonObject) + ' is not an Object'
3300
			);
3301
		});
3302
		forEach(v.nonArrays, function (nonArray) {
3303
			t['throws'](
3304
				function () { ES.CreateListFromArrayLike({}, nonArray); },
3305
				TypeError,
3306
				debug(nonArray) + ' is not an Array'
3307
			);
3308
		});
3309

    
3310
		t.deepEqual(
3311
			ES.CreateListFromArrayLike({ length: 2, 0: 'a', 1: 'b', 2: 'c' }),
3312
			['a', 'b'],
3313
			'arraylike stops at the length'
3314
		);
3315

    
3316
		t.end();
3317
	});
3318

    
3319
	test('GetPrototypeFromConstructor', function (t) {
3320
		forEach(v.nonFunctions, function (nonFunction) {
3321
			t['throws'](
3322
				function () { ES.GetPrototypeFromConstructor(nonFunction, '%Array%'); },
3323
				TypeError,
3324
				debug(nonFunction) + ' is not a constructor'
3325
			);
3326
		});
3327

    
3328
		forEach(arrowFns, function (arrowFn) {
3329
			t['throws'](
3330
				function () { ES.GetPrototypeFromConstructor(arrowFn, '%Array%'); },
3331
				TypeError,
3332
				debug(arrowFn) + ' is not a constructor'
3333
			);
3334
		});
3335

    
3336
		var f = function () {};
3337
		t.equal(
3338
			ES.GetPrototypeFromConstructor(f, '%Array.prototype%'),
3339
			f.prototype,
3340
			'function with normal `prototype` property returns it'
3341
		);
3342
		forEach([true, 'foo', 42], function (truthyPrimitive) {
3343
			f.prototype = truthyPrimitive;
3344
			t.equal(
3345
				ES.GetPrototypeFromConstructor(f, '%Array.prototype%'),
3346
				Array.prototype,
3347
				'function with non-object `prototype` property (' + debug(truthyPrimitive) + ') returns default intrinsic'
3348
			);
3349
		});
3350

    
3351
		t.end();
3352
	});
3353

    
3354
	var getNamelessFunction = function () {
3355
		var f = Object(function () {});
3356
		try {
3357
			delete f.name;
3358
		} catch (e) { /**/ }
3359
		return f;
3360
	};
3361

    
3362
	test('SetFunctionName', function (t) {
3363
		t.test('non-extensible function', { skip: !Object.preventExtensions }, function (st) {
3364
			var f = getNamelessFunction();
3365
			Object.preventExtensions(f);
3366
			st['throws'](
3367
				function () { ES.SetFunctionName(f, ''); },
3368
				TypeError,
3369
				'throws on a non-extensible function'
3370
			);
3371
			st.end();
3372
		});
3373

    
3374
		t.test('has an own name property', { skip: !functionsHaveNames }, function (st) {
3375
			st['throws'](
3376
				function () { ES.SetFunctionName(function g() {}, ''); },
3377
				TypeError,
3378
				'throws if function has an own `name` property'
3379
			);
3380
			st.end();
3381
		});
3382

    
3383
		forEach(v.nonPropertyKeys, function (nonPropertyKey) {
3384
			t['throws'](
3385
				function () { ES.SetFunctionName(getNamelessFunction(), nonPropertyKey); },
3386
				TypeError,
3387
				debug(nonPropertyKey) + ' is not a Symbol or String'
3388
			);
3389
		});
3390

    
3391
		t.test('symbols', { skip: !v.hasSymbols || has(getNamelessFunction(), 'name') }, function (st) {
3392
			var pairs = [
3393
				[Symbol(), ''],
3394
				[Symbol(undefined), ''],
3395
				[Symbol(null), '[null]'],
3396
				[Symbol(''), getInferredName ? '[]' : ''],
3397
				[Symbol.iterator, '[Symbol.iterator]'],
3398
				[Symbol('foo'), '[foo]']
3399
			];
3400
			forEach(pairs, function (pair) {
3401
				var sym = pair[0];
3402
				var desc = pair[1];
3403
				var f = getNamelessFunction();
3404
				ES.SetFunctionName(f, sym);
3405
				st.equal(f.name, desc, debug(sym) + ' yields a name of ' + debug(desc));
3406
			});
3407

    
3408
			st.end();
3409
		});
3410

    
3411
		var f = getNamelessFunction();
3412
		t.test('when names are configurable', { skip: !functionsHaveConfigurableNames || has(f, 'name') }, function (st) {
3413
			// without prefix
3414
			st.notEqual(f.name, 'foo', 'precondition');
3415
			ES.SetFunctionName(f, 'foo');
3416
			st.equal(f.name, 'foo', 'function name is set without a prefix');
3417

    
3418
			// with prefix
3419
			var g = getNamelessFunction();
3420
			st.notEqual(g.name, 'pre- foo', 'precondition');
3421
			ES.SetFunctionName(g, 'foo', 'pre-');
3422
			st.equal(g.name, 'pre- foo', 'function name is set with a prefix');
3423

    
3424
			st.end();
3425
		});
3426

    
3427
		t.end();
3428
	});
3429
};
3430

    
3431
var es2016 = function ES2016(ES, ops, expectedMissing, skips) {
3432
	es2015(ES, ops, expectedMissing, skips);
3433

    
3434
	test('SameValueNonNumber', function (t) {
3435
		var willThrow = [
3436
			[3, 4],
3437
			[NaN, 4],
3438
			[4, ''],
3439
			['abc', true],
3440
			[{}, false]
3441
		];
3442
		forEach(willThrow, function (nums) {
3443
			t['throws'](function () { return ES.SameValueNonNumber.apply(ES, nums); }, TypeError, 'value must be same type and non-number');
3444
		});
3445

    
3446
		forEach(v.objects.concat(v.nonNumberPrimitives), function (val) {
3447
			t.equal(val === val, ES.SameValueNonNumber(val, val), debug(val) + ' is SameValueNonNumber to itself');
3448
		});
3449

    
3450
		t.end();
3451
	});
3452

    
3453
	test('IterableToArrayLike', { skip: skips && skips.IterableToArrayLike }, function (t) {
3454
		t.test('custom iterables', { skip: !v.hasSymbols }, function (st) {
3455
			var O = {};
3456
			O[Symbol.iterator] = function () {
3457
				var i = -1;
3458
				return {
3459
					next: function () {
3460
						i += 1;
3461
						return {
3462
							done: i >= 5,
3463
							value: i
3464
						};
3465
					}
3466
				};
3467
			};
3468
			st.deepEqual(
3469
				ES.IterableToArrayLike(O),
3470
				[0, 1, 2, 3, 4],
3471
				'Symbol.iterator method is called and values collected'
3472
			);
3473

    
3474
			st.end();
3475
		});
3476

    
3477
		t.deepEqual(ES.IterableToArrayLike('abc'), ['a', 'b', 'c'], 'a string of code units spreads');
3478
		t.deepEqual(ES.IterableToArrayLike('💩'), ['💩'], 'a string of code points spreads');
3479
		t.deepEqual(ES.IterableToArrayLike('a💩c'), ['a', '💩', 'c'], 'a string of code points and units spreads');
3480

    
3481
		var arr = [1, 2, 3];
3482
		t.deepEqual(ES.IterableToArrayLike(arr), arr, 'an array becomes a similar array');
3483
		t.notEqual(ES.IterableToArrayLike(arr), arr, 'an array becomes a different, but similar, array');
3484

    
3485
		var O = {};
3486
		t.equal(ES.IterableToArrayLike(O), O, 'a non-iterable non-array non-string object is returned directly');
3487

    
3488
		t.end();
3489
	});
3490

    
3491
	test('OrdinaryGetPrototypeOf', function (t) {
3492
		t.test('values', { skip: !$getProto }, function (st) {
3493
			st.equal(ES.OrdinaryGetPrototypeOf([]), Array.prototype, 'array [[Prototype]] is Array.prototype');
3494
			st.equal(ES.OrdinaryGetPrototypeOf({}), Object.prototype, 'object [[Prototype]] is Object.prototype');
3495
			st.equal(ES.OrdinaryGetPrototypeOf(/a/g), RegExp.prototype, 'regex [[Prototype]] is RegExp.prototype');
3496
			st.equal(ES.OrdinaryGetPrototypeOf(Object('')), String.prototype, 'boxed string [[Prototype]] is String.prototype');
3497
			st.equal(ES.OrdinaryGetPrototypeOf(Object(42)), Number.prototype, 'boxed number [[Prototype]] is Number.prototype');
3498
			st.equal(ES.OrdinaryGetPrototypeOf(Object(true)), Boolean.prototype, 'boxed boolean [[Prototype]] is Boolean.prototype');
3499
			if (v.hasSymbols) {
3500
				st.equal(ES.OrdinaryGetPrototypeOf(Object(Symbol.iterator)), Symbol.prototype, 'boxed symbol [[Prototype]] is Symbol.prototype');
3501
			}
3502
			st.end();
3503
		});
3504

    
3505
		forEach(v.primitives, function (primitive) {
3506
			t['throws'](
3507
				function () { ES.OrdinaryGetPrototypeOf(primitive); },
3508
				TypeError,
3509
				debug(primitive) + ' is not an Object'
3510
			);
3511
		});
3512
		t.end();
3513
	});
3514

    
3515
	test('OrdinarySetPrototypeOf', { skip: !$getProto || !$setProto }, function (t) {
3516
		var a = [];
3517
		var proto = {};
3518

    
3519
		t.equal(ES.OrdinaryGetPrototypeOf(a), Array.prototype, 'precondition');
3520
		t.equal(ES.OrdinarySetPrototypeOf(a, proto), true, 'setting prototype is successful');
3521
		t.equal(ES.OrdinaryGetPrototypeOf(a), proto, 'postcondition');
3522

    
3523
		t.end();
3524
	});
3525
};
3526

    
3527
var es2017 = function ES2017(ES, ops, expectedMissing, skips) {
3528
	es2016(ES, ops, expectedMissing, assign({}, skips, {
3529
		EnumerableOwnNames: true,
3530
		IterableToArrayLike: true
3531
	}));
3532

    
3533
	test('ToIndex', function (t) {
3534
		t.ok(is(ES.ToIndex(), 0), 'no value gives 0');
3535
		t.ok(is(ES.ToIndex(undefined), 0), 'undefined value gives 0');
3536

    
3537
		t['throws'](function () { ES.ToIndex(-1); }, RangeError, 'negative numbers throw');
3538

    
3539
		t['throws'](function () { ES.ToIndex(MAX_SAFE_INTEGER + 1); }, RangeError, 'too large numbers throw');
3540

    
3541
		t.equal(ES.ToIndex(3), 3, 'numbers work');
3542
		t.equal(ES.ToIndex(v.valueOfOnlyObject), 4, 'coercible objects are coerced');
3543

    
3544
		t.end();
3545
	});
3546

    
3547
	test('EnumerableOwnProperties', { skip: skips && skips.EnumerableOwnProperties }, function (t) {
3548
		var obj = testEnumerableOwnNames(t, function (O) {
3549
			return ES.EnumerableOwnProperties(O, 'key');
3550
		});
3551

    
3552
		t.deepEqual(
3553
			ES.EnumerableOwnProperties(obj, 'value'),
3554
			[obj.own],
3555
			'returns enumerable own values'
3556
		);
3557

    
3558
		t.deepEqual(
3559
			ES.EnumerableOwnProperties(obj, 'key+value'),
3560
			[['own', obj.own]],
3561
			'returns enumerable own entries'
3562
		);
3563

    
3564
		t.end();
3565
	});
3566

    
3567
	test('IterableToList', function (t) {
3568
		var customIterator = function () {
3569
			var i = -1;
3570
			return {
3571
				next: function () {
3572
					i += 1;
3573
					return {
3574
						done: i >= 5,
3575
						value: i
3576
					};
3577
				}
3578
			};
3579
		};
3580

    
3581
		t.deepEqual(
3582
			ES.IterableToList({}, customIterator),
3583
			[0, 1, 2, 3, 4],
3584
			'iterator method is called and values collected'
3585
		);
3586

    
3587
		t.test('Symbol support', { skip: !v.hasSymbols }, function (st) {
3588
			st.deepEqual(ES.IterableToList('abc', String.prototype[Symbol.iterator]), ['a', 'b', 'c'], 'a string of code units spreads');
3589
			st.deepEqual(ES.IterableToList('', String.prototype[Symbol.iterator]), [''], 'a string of code points spreads');
3590

    
3591
			var arr = [1, 2, 3];
3592
			st.deepEqual(ES.IterableToList(arr, arr[Symbol.iterator]), arr, 'an array becomes a similar array');
3593
			st.notEqual(ES.IterableToList(arr, arr[Symbol.iterator]), arr, 'an array becomes a different, but similar, array');
3594

    
3595
			st.end();
3596
		});
3597

    
3598
		t['throws'](
3599
			function () { ES.IterableToList({}, void 0); },
3600
			TypeError,
3601
			'non-function iterator method'
3602
		);
3603

    
3604
		t.end();
3605
	});
3606
};
3607

    
3608
var es2018 = function ES2018(ES, ops, expectedMissing, skips) {
3609
	es2017(ES, ops, expectedMissing, assign({}, skips, {
3610
		EnumerableOwnProperties: true,
3611
		GetSubstitution: true,
3612
		IsPropertyDescriptor: true
3613
	}));
3614

    
3615
	test('thisSymbolValue', function (t) {
3616
		forEach(v.nonSymbolPrimitives.concat(v.objects), function (nonSymbol) {
3617
			t['throws'](
3618
				function () { ES.thisSymbolValue(nonSymbol); },
3619
				v.hasSymbols ? TypeError : SyntaxError,
3620
				debug(nonSymbol) + ' is not a Symbol'
3621
			);
3622
		});
3623

    
3624
		t.test('no native Symbols', { skip: v.hasSymbols }, function (st) {
3625
			forEach(v.objects.concat(v.primitives), function (value) {
3626
				st['throws'](
3627
					function () { ES.thisSymbolValue(value); },
3628
					SyntaxError,
3629
					'Symbols are not supported'
3630
				);
3631
			});
3632
			st.end();
3633
		});
3634

    
3635
		t.test('symbol values', { skip: !v.hasSymbols }, function (st) {
3636
			forEach(v.symbols, function (symbol) {
3637
				st.equal(ES.thisSymbolValue(symbol), symbol, 'Symbol value of ' + debug(symbol) + ' is same symbol');
3638

    
3639
				st.equal(
3640
					ES.thisSymbolValue(Object(symbol)),
3641
					symbol,
3642
					'Symbol value of ' + debug(Object(symbol)) + ' is ' + debug(symbol)
3643
				);
3644
			});
3645

    
3646
			st.end();
3647
		});
3648

    
3649
		t.end();
3650
	});
3651

    
3652
	test('IsStringPrefix', function (t) {
3653
		forEach(v.nonStrings, function (nonString) {
3654
			t['throws'](
3655
				function () { ES.IsStringPrefix(nonString, 'a'); },
3656
				TypeError,
3657
				'first arg: ' + debug(nonString) + ' is not a string'
3658
			);
3659
			t['throws'](
3660
				function () { ES.IsStringPrefix('a', nonString); },
3661
				TypeError,
3662
				'second arg: ' + debug(nonString) + ' is not a string'
3663
			);
3664
		});
3665

    
3666
		forEach(v.strings, function (string) {
3667
			t.equal(ES.IsStringPrefix(string, string), true, debug(string) + ' is a prefix of itself');
3668

    
3669
			t.equal(ES.IsStringPrefix('', string), true, 'the empty string is a prefix of everything');
3670
		});
3671

    
3672
		t.equal(ES.IsStringPrefix('abc', 'abcd'), true, '"abc" is a prefix of "abcd"');
3673
		t.equal(ES.IsStringPrefix('abcd', 'abc'), false, '"abcd" is not a prefix of "abc"');
3674

    
3675
		t.equal(ES.IsStringPrefix('a', 'bc'), false, '"a" is not a prefix of "bc"');
3676

    
3677
		t.end();
3678
	});
3679

    
3680
	test('NumberToString', function (t) {
3681
		forEach(v.nonNumbers, function (nonNumber) {
3682
			t['throws'](
3683
				function () { ES.NumberToString(nonNumber); },
3684
				TypeError,
3685
				debug(nonNumber) + ' is not a Number'
3686
			);
3687
		});
3688

    
3689
		forEach(v.numbers, function (number) {
3690
			t.equal(ES.NumberToString(number), String(number), debug(number) + ' stringifies to ' + number);
3691
		});
3692

    
3693
		t.end();
3694
	});
3695

    
3696
	test('CopyDataProperties', function (t) {
3697
		t.test('first argument: target', function (st) {
3698
			forEach(v.primitives, function (primitive) {
3699
				st['throws'](
3700
					function () { ES.CopyDataProperties(primitive, {}, []); },
3701
					TypeError,
3702
					debug(primitive) + ' is not an Object'
3703
				);
3704
			});
3705
			st.end();
3706
		});
3707

    
3708
		t.test('second argument: source', function (st) {
3709
			var frozenTarget = Object.freeze ? Object.freeze({}) : {};
3710
			forEach(v.nullPrimitives, function (nullish) {
3711
				st.equal(
3712
					ES.CopyDataProperties(frozenTarget, nullish, []),
3713
					frozenTarget,
3714
					debug(nullish) + ' "source" yields identical, unmodified target'
3715
				);
3716
			});
3717

    
3718
			forEach(v.nonNullPrimitives, function (objectCoercible) {
3719
				var target = {};
3720
				var result = ES.CopyDataProperties(target, objectCoercible, []);
3721
				st.equal(result, target, 'result === target');
3722
				st.deepEqual(keys(result), keys(Object(objectCoercible)), 'target ends up with keys of ' + debug(objectCoercible));
3723
			});
3724

    
3725
			st.test('enumerable accessor property', { skip: !defineProperty.oDP }, function (s2t) {
3726
				var target = {};
3727
				var source = {};
3728
				defineProperty(source, 'a', {
3729
					enumerable: true,
3730
					get: function () { return 42; }
3731
				});
3732
				var result = ES.CopyDataProperties(target, source, []);
3733
				s2t.equal(result, target, 'result === target');
3734
				s2t.deepEqual(result, { a: 42 }, 'target ends up with enumerable accessor of source');
3735
				s2t.end();
3736
			});
3737

    
3738
			st.end();
3739
		});
3740

    
3741
		t.test('third argument: excludedItems', function (st) {
3742
			forEach(v.objects.concat(v.primitives), function (nonArray) {
3743
				st['throws'](
3744
					function () { ES.CopyDataProperties({}, {}, nonArray); },
3745
					TypeError,
3746
					debug(nonArray) + ' is not an Array'
3747
				);
3748
			});
3749

    
3750
			forEach(v.nonPropertyKeys, function (nonPropertyKey) {
3751
				st['throws'](
3752
					function () { ES.CopyDataProperties({}, {}, [nonPropertyKey]); },
3753
					TypeError,
3754
					debug(nonPropertyKey) + ' is not a Property Key'
3755
				);
3756
			});
3757

    
3758
			var result = ES.CopyDataProperties({}, { a: 1, b: 2, c: 3 }, ['b']);
3759
			st.deepEqual(keys(result).sort(), ['a', 'c'].sort(), 'excluded string keys are excluded');
3760

    
3761
			st.test('excluding symbols', { skip: !v.hasSymbols }, function (s2t) {
3762
				var source = {};
3763
				forEach(v.symbols, function (symbol) {
3764
					source[symbol] = true;
3765
				});
3766

    
3767
				var includedSymbols = v.symbols.slice(1);
3768
				var excludedSymbols = v.symbols.slice(0, 1);
3769
				var target = ES.CopyDataProperties({}, source, excludedSymbols);
3770

    
3771
				forEach(includedSymbols, function (symbol) {
3772
					s2t.equal(has(target, symbol), true, debug(symbol) + ' is included');
3773
				});
3774

    
3775
				forEach(excludedSymbols, function (symbol) {
3776
					s2t.equal(has(target, symbol), false, debug(symbol) + ' is excluded');
3777
				});
3778

    
3779
				s2t.end();
3780
			});
3781

    
3782
			st.end();
3783
		});
3784

    
3785
		t.end();
3786
	});
3787

    
3788
	test('PromiseResolve', function (t) {
3789
		t.test('Promises unsupported', { skip: typeof Promise === 'function' }, function (st) {
3790
			st['throws'](
3791
				function () { ES.PromiseResolve(); },
3792
				SyntaxError,
3793
				'Promises are not supported'
3794
			);
3795
			st.end();
3796
		});
3797

    
3798
		t.test('Promises supported', { skip: typeof Promise !== 'function' }, function (st) {
3799
			st.plan(2);
3800

    
3801
			var a = {};
3802
			var b = {};
3803
			var fulfilled = Promise.resolve(a);
3804
			var rejected = Promise.reject(b);
3805

    
3806
			ES.PromiseResolve(Promise, fulfilled).then(function (x) {
3807
				st.equal(x, a, 'fulfilled promise resolves to fulfilled');
3808
			});
3809

    
3810
			ES.PromiseResolve(Promise, rejected)['catch'](function (e) {
3811
				st.equal(e, b, 'rejected promise resolves to rejected');
3812
			});
3813
		});
3814

    
3815
		t.end();
3816
	});
3817

    
3818
	test('EnumerableOwnPropertyNames', { skip: skips && skips.EnumerableOwnPropertyNames }, function (t) {
3819
		var obj = testEnumerableOwnNames(t, function (O) {
3820
			return ES.EnumerableOwnPropertyNames(O, 'key');
3821
		});
3822

    
3823
		t.deepEqual(
3824
			ES.EnumerableOwnPropertyNames(obj, 'value'),
3825
			[obj.own],
3826
			'returns enumerable own values'
3827
		);
3828

    
3829
		t.deepEqual(
3830
			ES.EnumerableOwnPropertyNames(obj, 'key+value'),
3831
			[['own', obj.own]],
3832
			'returns enumerable own entries'
3833
		);
3834

    
3835
		t.end();
3836
	});
3837

    
3838
	test('IsPromise', { skip: typeof Promise !== 'function' }, function (t) {
3839
		forEach(v.objects.concat(v.primitives), function (nonPromise) {
3840
			t.equal(ES.IsPromise(nonPromise), false, debug(nonPromise) + ' is not a Promise');
3841
		});
3842

    
3843
		var thenable = { then: Promise.prototype.then };
3844
		t.equal(ES.IsPromise(thenable), false, 'generic thenable is not a Promise');
3845

    
3846
		t.equal(ES.IsPromise(Promise.resolve()), true, 'Promise is a Promise');
3847

    
3848
		t.end();
3849
	});
3850

    
3851
	test('GetSubstitution (ES2018+)', function (t) {
3852
		forEach(v.nonStrings, function (nonString) {
3853
			t['throws'](
3854
				function () { ES.GetSubstitution(nonString, '', 0, [], undefined, ''); },
3855
				TypeError,
3856
				'`matched`: ' + debug(nonString) + ' is not a String'
3857
			);
3858

    
3859
			t['throws'](
3860
				function () { ES.GetSubstitution('', nonString, 0, [], undefined, ''); },
3861
				TypeError,
3862
				'`str`: ' + debug(nonString) + ' is not a String'
3863
			);
3864

    
3865
			t['throws'](
3866
				function () { ES.GetSubstitution('', '', 0, [], undefined, nonString); },
3867
				TypeError,
3868
				'`replacement`: ' + debug(nonString) + ' is not a String'
3869
			);
3870

    
3871
			t['throws'](
3872
				function () { ES.GetSubstitution('', '', 0, [nonString], undefined, ''); },
3873
				TypeError,
3874
				'`captures`: ' + debug([nonString]) + ' is not an Array of strings'
3875
			);
3876
		});
3877

    
3878
		forEach(v.nonIntegerNumbers.concat([-1, -42, -Infinity]), function (nonNonNegativeInteger) {
3879
			t['throws'](
3880
				function () { ES.GetSubstitution('', '', nonNonNegativeInteger, [], undefined, ''); },
3881
				TypeError,
3882
				'`position`: ' + debug(nonNonNegativeInteger) + ' is not a non-negative integer'
3883
			);
3884
		});
3885

    
3886
		forEach(v.nonArrays, function (nonArray) {
3887
			t['throws'](
3888
				function () { ES.GetSubstitution('', '', 0, nonArray, undefined, ''); },
3889
				TypeError,
3890
				'`captures`: ' + debug(nonArray) + ' is not an Array'
3891
			);
3892
		});
3893

    
3894
		t.equal(
3895
			ES.GetSubstitution('def', 'abcdefghi', 3, [], undefined, '123'),
3896
			'123',
3897
			'returns the substitution'
3898
		);
3899
		t.equal(
3900
			ES.GetSubstitution('abcdef', 'abcdefghi', 0, [], undefined, '$$2$'),
3901
			'$2$',
3902
			'supports $$, and trailing $'
3903
		);
3904

    
3905
		t.equal(
3906
			ES.GetSubstitution('abcdef', 'abcdefghi', 0, [], undefined, '>$&<'),
3907
			'>abcdef<',
3908
			'supports $&'
3909
		);
3910

    
3911
		t.equal(
3912
			ES.GetSubstitution('abcdef', 'abcdefghi', 0, [], undefined, '>$`<'),
3913
			'><',
3914
			'supports $` at position 0'
3915
		);
3916
		t.equal(
3917
			ES.GetSubstitution('def', 'abcdefghi', 3, [], undefined, '>$`<'),
3918
			'>ab<',
3919
			'supports $` at position > 0'
3920
		);
3921

    
3922
		t.equal(
3923
			ES.GetSubstitution('def', 'abcdefghi', 7, [], undefined, ">$'<"),
3924
			'><',
3925
			"supports $' at a position where there's less than `matched.length` chars left"
3926
		);
3927
		t.equal(
3928
			ES.GetSubstitution('def', 'abcdefghi', 3, [], undefined, ">$'<"),
3929
			'>ghi<',
3930
			"supports $' at a position where there's more than `matched.length` chars left"
3931
		);
3932

    
3933
		for (var i = 0; i < 100; i += 1) {
3934
			var captures = [];
3935
			captures[i] = 'test';
3936
			if (i > 0) {
3937
				t.equal(
3938
					ES.GetSubstitution('abcdef', 'abcdefghi', 0, [], undefined, '>$' + i + '<'),
3939
					'>undefined<',
3940
					'supports $' + i + ' with no captures'
3941
				);
3942
				t.equal(
3943
					ES.GetSubstitution('abcdef', 'abcdefghi', 0, [], undefined, '>$' + i),
3944
					'>undefined',
3945
					'supports $' + i + ' at the end of the replacement, with no captures'
3946
				);
3947
				t.equal(
3948
					ES.GetSubstitution('abcdef', 'abcdefghi', 0, captures, undefined, '>$' + i + '<'),
3949
					'><',
3950
					'supports $' + i + ' with a capture at that index'
3951
				);
3952
				t.equal(
3953
					ES.GetSubstitution('abcdef', 'abcdefghi', 0, captures, undefined, '>$' + i),
3954
					'>',
3955
					'supports $' + i + ' at the end of the replacement, with a capture at that index'
3956
				);
3957
			}
3958
			if (i < 10) {
3959
				t.equal(
3960
					ES.GetSubstitution('abcdef', 'abcdefghi', 0, [], undefined, '>$0' + i + '<'),
3961
					i === 0 ? '><' : '>undefined<',
3962
					'supports $0' + i + ' with no captures'
3963
				);
3964
				t.equal(
3965
					ES.GetSubstitution('abcdef', 'abcdefghi', 0, [], undefined, '>$0' + i),
3966
					i === 0 ? '>' : '>undefined',
3967
					'supports $0' + i + ' at the end of the replacement, with no captures'
3968
				);
3969
				t.equal(
3970
					ES.GetSubstitution('abcdef', 'abcdefghi', 0, captures, undefined, '>$0' + i + '<'),
3971
					'><',
3972
					'supports $0' + i + ' with a capture at that index'
3973
				);
3974
				t.equal(
3975
					ES.GetSubstitution('abcdef', 'abcdefghi', 0, captures, undefined, '>$0' + i),
3976
					'>',
3977
					'supports $0' + i + ' at the end of the replacement, with a capture at that index'
3978
				);
3979
			}
3980
		}
3981

    
3982
		t.end();
3983
	});
3984

    
3985
	test('DateString', function (t) {
3986
		forEach(v.nonNumbers.concat(NaN), function (nonNumberOrNaN) {
3987
			t['throws'](
3988
				function () { ES.DateString(nonNumberOrNaN); },
3989
				TypeError,
3990
				debug(nonNumberOrNaN) + ' is not a non-NaN Number'
3991
			);
3992
		});
3993

    
3994
		t.equal(ES.DateString(Date.UTC(2019, 8, 10, 7, 8, 9)), 'Tue Sep 10 2019');
3995
		t.equal(ES.DateString(Date.UTC(2016, 1, 29, 7, 8, 9)), 'Mon Feb 29 2016'); // leap day
3996
		t.end();
3997
	});
3998

    
3999
	test('TimeString', function (t) {
4000
		forEach(v.nonNumbers.concat(NaN), function (nonNumberOrNaN) {
4001
			t['throws'](
4002
				function () { ES.TimeString(nonNumberOrNaN); },
4003
				TypeError,
4004
				debug(nonNumberOrNaN) + ' is not a non-NaN Number'
4005
			);
4006
		});
4007

    
4008
		var tv = Date.UTC(2019, 8, 10, 7, 8, 9);
4009
		t.equal(ES.TimeString(tv), '07:08:09 GMT');
4010
		t.end();
4011
	});
4012
};
4013

    
4014
var es2019 = function ES2018(ES, ops, expectedMissing, skips) {
4015
	es2018(ES, ops, expectedMissing, assign({}, skips, {
4016
	}));
4017

    
4018
	test('AddEntriesFromIterable', function (t) {
4019
		t['throws'](
4020
			function () { ES.AddEntriesFromIterable({}, undefined, function () {}); },
4021
			TypeError,
4022
			'iterable must not be undefined'
4023
		);
4024
		t['throws'](
4025
			function () { ES.AddEntriesFromIterable({}, null, function () {}); },
4026
			TypeError,
4027
			'iterable must not be null'
4028
		);
4029
		forEach(v.nonFunctions, function (nonFunction) {
4030
			t['throws'](
4031
				function () { ES.AddEntriesFromIterable({}, {}, nonFunction); },
4032
				TypeError,
4033
				debug(nonFunction) + ' is not a function'
4034
			);
4035
		});
4036

    
4037
		t.test('Symbol support', { skip: !v.hasSymbols }, function (st) {
4038
			st.plan(4);
4039

    
4040
			var O = {};
4041
			st.equal(ES.AddEntriesFromIterable(O, [], function () {}), O, 'returns the target');
4042

    
4043
			var adder = function (key, value) {
4044
				st.equal(this, O, 'adder gets proper receiver');
4045
				st.equal(key, 0, 'k is key');
4046
				st.equal(value, 'a', 'v is value');
4047
			};
4048
			ES.AddEntriesFromIterable(O, ['a'].entries(), adder);
4049

    
4050
			st.end();
4051
		});
4052

    
4053
		t.end();
4054
	});
4055

    
4056
	test('FlattenIntoArray', function (t) {
4057
		t.test('no mapper function', function (st) {
4058
			var testDepth = function testDepth(tt, depth, expected) {
4059
				var a = [];
4060
				var o = [[1], 2, , [[3]], [], 4, [[[[5]]]]]; // eslint-disable-line no-sparse-arrays
4061
				ES.FlattenIntoArray(a, o, o.length, 0, depth);
4062
				tt.deepEqual(a, expected, 'depth: ' + depth);
4063
			};
4064

    
4065
			testDepth(st, 1, [1, 2, [3], 4, [[[5]]]]);
4066
			testDepth(st, 2, [1, 2, 3, 4, [[5]]]);
4067
			testDepth(st, 3, [1, 2, 3, 4, [5]]);
4068
			testDepth(st, 4, [1, 2, 3, 4, 5]);
4069
			testDepth(st, Infinity, [1, 2, 3, 4, 5]);
4070
			st.end();
4071
		});
4072

    
4073
		t.test('mapper function', function (st) {
4074
			var testMapper = function testMapper(tt, mapper, expected, thisArg) {
4075
				var a = [];
4076
				var o = [[1], 2, , [[3]], [], 4, [[[[5]]]]]; // eslint-disable-line no-sparse-arrays
4077
				ES.FlattenIntoArray(a, o, o.length, 0, 1, mapper, thisArg);
4078
				tt.deepEqual(a, expected);
4079
			};
4080

    
4081
			var double = function double(x) {
4082
				return typeof x === 'number' ? 2 * x : x;
4083
			};
4084
			testMapper(
4085
				st,
4086
				double,
4087
				[1, 4, [3], 8, [[[5]]]]
4088
			);
4089
			var receiver = hasStrictMode ? 42 : Object(42);
4090
			testMapper(
4091
				st,
4092
				function (x) { return [this, double(x)]; },
4093
				[receiver, [1], receiver, 4, receiver, [[3]], receiver, [], receiver, 8, receiver, [[[[5]]]]],
4094
				42
4095
			);
4096
			st.end();
4097
		});
4098

    
4099
		t.end();
4100
	});
4101

    
4102
	test('TrimString', function (t) {
4103
		t.test('non-object string', function (st) {
4104
			forEach(v.nullPrimitives, function (nullish) {
4105
				st['throws'](
4106
					function () { ES.TrimString(nullish); },
4107
					debug(nullish) + ' is not an Object'
4108
				);
4109
			});
4110
			st.end();
4111
		});
4112

    
4113
		var string = ' \n abc  \n ';
4114
		t.equal(ES.TrimString(string, 'start'), string.slice(string.indexOf('a')));
4115
		t.equal(ES.TrimString(string, 'end'), string.slice(0, string.lastIndexOf('c') + 1));
4116
		t.equal(ES.TrimString(string, 'start+end'), string.slice(string.indexOf('a'), string.lastIndexOf('c') + 1));
4117

    
4118
		t.end();
4119
	});
4120
};
4121

    
4122
module.exports = {
4123
	es2015: es2015,
4124
	es2016: es2016,
4125
	es2017: es2017,
4126
	es2018: es2018,
4127
	es2019: es2019
4128
};
(12-12/12)