Projekt

Obecné

Profil

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

    
3
var ES = require('../').ES5;
4
var test = require('tape');
5

    
6
var forEach = require('foreach');
7
var is = require('object-is');
8
var debug = require('object-inspect');
9

    
10
var v = require('./helpers/values');
11

    
12
require('./helpers/runManifestTest')(test, ES, 5);
13

    
14
test('ToPrimitive', function (t) {
15
	t.test('primitives', function (st) {
16
		var testPrimitive = function (primitive) {
17
			st.ok(is(ES.ToPrimitive(primitive), primitive), debug(primitive) + ' is returned correctly');
18
		};
19
		forEach(v.primitives, testPrimitive);
20
		st.end();
21
	});
22

    
23
	t.test('objects', function (st) {
24
		st.equal(ES.ToPrimitive(v.coercibleObject), v.coercibleObject.valueOf(), 'coercibleObject coerces to valueOf');
25
		st.equal(ES.ToPrimitive(v.coercibleObject, Number), v.coercibleObject.valueOf(), 'coercibleObject with hint Number coerces to valueOf');
26
		st.equal(ES.ToPrimitive(v.coercibleObject, String), v.coercibleObject.toString(), 'coercibleObject with hint String coerces to toString');
27
		st.equal(ES.ToPrimitive(v.coercibleFnObject), v.coercibleFnObject.toString(), 'coercibleFnObject coerces to toString');
28
		st.equal(ES.ToPrimitive(v.toStringOnlyObject), v.toStringOnlyObject.toString(), 'toStringOnlyObject returns toString');
29
		st.equal(ES.ToPrimitive(v.valueOfOnlyObject), v.valueOfOnlyObject.valueOf(), 'valueOfOnlyObject returns valueOf');
30
		st.equal(ES.ToPrimitive({}), '[object Object]', '{} with no hint coerces to Object#toString');
31
		st.equal(ES.ToPrimitive({}, String), '[object Object]', '{} with hint String coerces to Object#toString');
32
		st.equal(ES.ToPrimitive({}, Number), '[object Object]', '{} with hint Number coerces to Object#toString');
33
		st['throws'](function () { return ES.ToPrimitive(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws a TypeError');
34
		st['throws'](function () { return ES.ToPrimitive(v.uncoercibleFnObject); }, TypeError, 'uncoercibleFnObject throws a TypeError');
35
		st.end();
36
	});
37

    
38
	t.end();
39
});
40

    
41
test('ToBoolean', function (t) {
42
	t.equal(false, ES.ToBoolean(undefined), 'undefined coerces to false');
43
	t.equal(false, ES.ToBoolean(null), 'null coerces to false');
44
	t.equal(false, ES.ToBoolean(false), 'false returns false');
45
	t.equal(true, ES.ToBoolean(true), 'true returns true');
46
	forEach([0, -0, NaN], function (falsyNumber) {
47
		t.equal(false, ES.ToBoolean(falsyNumber), 'falsy number ' + falsyNumber + ' coerces to false');
48
	});
49
	forEach([Infinity, 42, 1, -Infinity], function (truthyNumber) {
50
		t.equal(true, ES.ToBoolean(truthyNumber), 'truthy number ' + truthyNumber + ' coerces to true');
51
	});
52
	t.equal(false, ES.ToBoolean(''), 'empty string coerces to false');
53
	t.equal(true, ES.ToBoolean('foo'), 'nonempty string coerces to true');
54
	forEach(v.objects, function (obj) {
55
		t.equal(true, ES.ToBoolean(obj), 'object coerces to true');
56
	});
57
	t.equal(true, ES.ToBoolean(v.uncoercibleObject), 'uncoercibleObject coerces to true');
58
	t.end();
59
});
60

    
61
test('ToNumber', function (t) {
62
	t.ok(is(NaN, ES.ToNumber(undefined)), 'undefined coerces to NaN');
63
	t.ok(is(ES.ToNumber(null), 0), 'null coerces to +0');
64
	t.ok(is(ES.ToNumber(false), 0), 'false coerces to +0');
65
	t.equal(1, ES.ToNumber(true), 'true coerces to 1');
66
	t.ok(is(NaN, ES.ToNumber(NaN)), 'NaN returns itself');
67
	forEach([0, -0, 42, Infinity, -Infinity], function (num) {
68
		t.equal(num, ES.ToNumber(num), num + ' returns itself');
69
	});
70
	forEach(['foo', '0', '4a', '2.0', 'Infinity', '-Infinity'], function (numString) {
71
		t.ok(is(+numString, ES.ToNumber(numString)), '"' + numString + '" coerces to ' + Number(numString));
72
	});
73
	forEach(v.objects, function (object) {
74
		t.ok(is(ES.ToNumber(object), ES.ToNumber(ES.ToPrimitive(object))), 'object ' + object + ' coerces to same as ToPrimitive of object does');
75
	});
76
	t['throws'](function () { return ES.ToNumber(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws');
77
	t.end();
78
});
79

    
80
test('ToInteger', function (t) {
81
	t.ok(is(0, ES.ToInteger(NaN)), 'NaN coerces to +0');
82
	forEach([0, Infinity, 42], function (num) {
83
		t.ok(is(num, ES.ToInteger(num)), num + ' returns itself');
84
		t.ok(is(-num, ES.ToInteger(-num)), '-' + num + ' returns itself');
85
	});
86
	t.equal(3, ES.ToInteger(Math.PI), 'pi returns 3');
87
	t['throws'](function () { return ES.ToInteger(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws');
88
	t.end();
89
});
90

    
91
test('ToInt32', function (t) {
92
	t.ok(is(0, ES.ToInt32(NaN)), 'NaN coerces to +0');
93
	forEach([0, Infinity], function (num) {
94
		t.ok(is(0, ES.ToInt32(num)), num + ' returns +0');
95
		t.ok(is(0, ES.ToInt32(-num)), '-' + num + ' returns +0');
96
	});
97
	t['throws'](function () { return ES.ToInt32(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws');
98
	t.ok(is(ES.ToInt32(0x100000000), 0), '2^32 returns +0');
99
	t.ok(is(ES.ToInt32(0x100000000 - 1), -1), '2^32 - 1 returns -1');
100
	t.ok(is(ES.ToInt32(0x80000000), -0x80000000), '2^31 returns -2^31');
101
	t.ok(is(ES.ToInt32(0x80000000 - 1), 0x80000000 - 1), '2^31 - 1 returns 2^31 - 1');
102
	forEach([0, Infinity, NaN, 0x100000000, 0x80000000, 0x10000, 0x42], function (num) {
103
		t.ok(is(ES.ToInt32(num), ES.ToInt32(ES.ToUint32(num))), 'ToInt32(x) === ToInt32(ToUint32(x)) for 0x' + num.toString(16));
104
		t.ok(is(ES.ToInt32(-num), ES.ToInt32(ES.ToUint32(-num))), 'ToInt32(x) === ToInt32(ToUint32(x)) for -0x' + num.toString(16));
105
	});
106
	t.end();
107
});
108

    
109
test('ToUint32', function (t) {
110
	t.ok(is(0, ES.ToUint32(NaN)), 'NaN coerces to +0');
111
	forEach([0, Infinity], function (num) {
112
		t.ok(is(0, ES.ToUint32(num)), num + ' returns +0');
113
		t.ok(is(0, ES.ToUint32(-num)), '-' + num + ' returns +0');
114
	});
115
	t['throws'](function () { return ES.ToUint32(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws');
116
	t.ok(is(ES.ToUint32(0x100000000), 0), '2^32 returns +0');
117
	t.ok(is(ES.ToUint32(0x100000000 - 1), 0x100000000 - 1), '2^32 - 1 returns 2^32 - 1');
118
	t.ok(is(ES.ToUint32(0x80000000), 0x80000000), '2^31 returns 2^31');
119
	t.ok(is(ES.ToUint32(0x80000000 - 1), 0x80000000 - 1), '2^31 - 1 returns 2^31 - 1');
120
	forEach([0, Infinity, NaN, 0x100000000, 0x80000000, 0x10000, 0x42], function (num) {
121
		t.ok(is(ES.ToUint32(num), ES.ToUint32(ES.ToInt32(num))), 'ToUint32(x) === ToUint32(ToInt32(x)) for 0x' + num.toString(16));
122
		t.ok(is(ES.ToUint32(-num), ES.ToUint32(ES.ToInt32(-num))), 'ToUint32(x) === ToUint32(ToInt32(x)) for -0x' + num.toString(16));
123
	});
124
	t.end();
125
});
126

    
127
test('ToUint16', function (t) {
128
	t.ok(is(0, ES.ToUint16(NaN)), 'NaN coerces to +0');
129
	forEach([0, Infinity], function (num) {
130
		t.ok(is(0, ES.ToUint16(num)), num + ' returns +0');
131
		t.ok(is(0, ES.ToUint16(-num)), '-' + num + ' returns +0');
132
	});
133
	t['throws'](function () { return ES.ToUint16(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws');
134
	t.ok(is(ES.ToUint16(0x100000000), 0), '2^32 returns +0');
135
	t.ok(is(ES.ToUint16(0x100000000 - 1), 0x10000 - 1), '2^32 - 1 returns 2^16 - 1');
136
	t.ok(is(ES.ToUint16(0x80000000), 0), '2^31 returns +0');
137
	t.ok(is(ES.ToUint16(0x80000000 - 1), 0x10000 - 1), '2^31 - 1 returns 2^16 - 1');
138
	t.ok(is(ES.ToUint16(0x10000), 0), '2^16 returns +0');
139
	t.ok(is(ES.ToUint16(0x10000 - 1), 0x10000 - 1), '2^16 - 1 returns 2^16 - 1');
140
	t.end();
141
});
142

    
143
test('ToString', function (t) {
144
	t['throws'](function () { return ES.ToString(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws');
145
	t.end();
146
});
147

    
148
test('ToObject', function (t) {
149
	t['throws'](function () { return ES.ToObject(undefined); }, TypeError, 'undefined throws');
150
	t['throws'](function () { return ES.ToObject(null); }, TypeError, 'null throws');
151
	forEach(v.numbers, function (number) {
152
		var obj = ES.ToObject(number);
153
		t.equal(typeof obj, 'object', 'number ' + number + ' coerces to object');
154
		t.equal(true, obj instanceof Number, 'object of ' + number + ' is Number object');
155
		t.ok(is(obj.valueOf(), number), 'object of ' + number + ' coerces to ' + number);
156
	});
157
	t.end();
158
});
159

    
160
test('CheckObjectCoercible', function (t) {
161
	t['throws'](function () { return ES.CheckObjectCoercible(undefined); }, TypeError, 'undefined throws');
162
	t['throws'](function () { return ES.CheckObjectCoercible(null); }, TypeError, 'null throws');
163
	var checkCoercible = function (value) {
164
		t.doesNotThrow(function () { return ES.CheckObjectCoercible(value); }, debug(value) + ' does not throw');
165
	};
166
	forEach(v.objects.concat(v.nonNullPrimitives), checkCoercible);
167
	t.end();
168
});
169

    
170
test('IsCallable', function (t) {
171
	t.equal(true, ES.IsCallable(function () {}), 'function is callable');
172
	var nonCallables = [/a/g, {}, Object.prototype, NaN].concat(v.primitives);
173
	forEach(nonCallables, function (nonCallable) {
174
		t.equal(false, ES.IsCallable(nonCallable), debug(nonCallable) + ' is not callable');
175
	});
176
	t.end();
177
});
178

    
179
test('SameValue', function (t) {
180
	t.equal(true, ES.SameValue(NaN, NaN), 'NaN is SameValue as NaN');
181
	t.equal(false, ES.SameValue(0, -0), '+0 is not SameValue as -0');
182
	forEach(v.objects.concat(v.primitives), function (val) {
183
		t.equal(val === val, ES.SameValue(val, val), debug(val) + ' is SameValue to itself');
184
	});
185
	t.end();
186
});
187

    
188
test('Type', function (t) {
189
	t.equal(ES.Type(), 'Undefined', 'Type() is Undefined');
190
	t.equal(ES.Type(undefined), 'Undefined', 'Type(undefined) is Undefined');
191
	t.equal(ES.Type(null), 'Null', 'Type(null) is Null');
192
	t.equal(ES.Type(true), 'Boolean', 'Type(true) is Boolean');
193
	t.equal(ES.Type(false), 'Boolean', 'Type(false) is Boolean');
194
	t.equal(ES.Type(0), 'Number', 'Type(0) is Number');
195
	t.equal(ES.Type(NaN), 'Number', 'Type(NaN) is Number');
196
	t.equal(ES.Type('abc'), 'String', 'Type("abc") is String');
197
	t.equal(ES.Type(function () {}), 'Object', 'Type(function () {}) is Object');
198
	t.equal(ES.Type({}), 'Object', 'Type({}) is Object');
199
	t.end();
200
});
201

    
202
test('IsPropertyDescriptor', function (t) {
203
	forEach(v.primitives, function (primitive) {
204
		t.equal(ES.IsPropertyDescriptor(primitive), false, debug(primitive) + ' is not a Property Descriptor');
205
	});
206

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

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

    
211
	t.equal(ES.IsPropertyDescriptor(v.accessorDescriptor()), true, 'accessor descriptor is a Property Descriptor');
212
	t.equal(ES.IsPropertyDescriptor(v.mutatorDescriptor()), true, 'mutator descriptor is a Property Descriptor');
213
	t.equal(ES.IsPropertyDescriptor(v.dataDescriptor()), true, 'data descriptor is a Property Descriptor');
214
	t.equal(ES.IsPropertyDescriptor(v.genericDescriptor()), true, 'generic descriptor is a Property Descriptor');
215

    
216
	t['throws'](
217
		function () { ES.IsPropertyDescriptor(v.bothDescriptor()); },
218
		TypeError,
219
		'a Property Descriptor can not be both a Data and an Accessor Descriptor'
220
	);
221

    
222
	t['throws'](
223
		function () { ES.IsPropertyDescriptor(v.bothDescriptorWritable()); },
224
		TypeError,
225
		'a Property Descriptor can not be both a Data and an Accessor Descriptor'
226
	);
227

    
228
	t.end();
229
});
230

    
231
test('IsAccessorDescriptor', function (t) {
232
	forEach(v.nonNullPrimitives.concat(null), function (primitive) {
233
		t['throws'](function () { ES.IsAccessorDescriptor(primitive); }, TypeError, debug(primitive) + ' is not a Property Descriptor');
234
	});
235

    
236
	t.equal(ES.IsAccessorDescriptor(), false, 'no value is not an Accessor Descriptor');
237
	t.equal(ES.IsAccessorDescriptor(undefined), false, 'undefined value is not an Accessor Descriptor');
238

    
239
	t.equal(ES.IsAccessorDescriptor(v.accessorDescriptor()), true, 'accessor descriptor is an Accessor Descriptor');
240
	t.equal(ES.IsAccessorDescriptor(v.mutatorDescriptor()), true, 'mutator descriptor is an Accessor Descriptor');
241
	t.equal(ES.IsAccessorDescriptor(v.dataDescriptor()), false, 'data descriptor is not an Accessor Descriptor');
242
	t.equal(ES.IsAccessorDescriptor(v.genericDescriptor()), false, 'generic descriptor is not an Accessor Descriptor');
243

    
244
	t.end();
245
});
246

    
247
test('IsDataDescriptor', function (t) {
248
	forEach(v.nonNullPrimitives.concat(null), function (primitive) {
249
		t['throws'](function () { ES.IsDataDescriptor(primitive); }, TypeError, debug(primitive) + ' is not a Property Descriptor');
250
	});
251

    
252
	t.equal(ES.IsDataDescriptor(), false, 'no value is not a Data Descriptor');
253
	t.equal(ES.IsDataDescriptor(undefined), false, 'undefined value is not a Data Descriptor');
254

    
255
	t.equal(ES.IsDataDescriptor(v.accessorDescriptor()), false, 'accessor descriptor is not a Data Descriptor');
256
	t.equal(ES.IsDataDescriptor(v.mutatorDescriptor()), false, 'mutator descriptor is not a Data Descriptor');
257
	t.equal(ES.IsDataDescriptor(v.dataDescriptor()), true, 'data descriptor is a Data Descriptor');
258
	t.equal(ES.IsDataDescriptor(v.genericDescriptor()), false, 'generic descriptor is not a Data Descriptor');
259

    
260
	t.end();
261
});
262

    
263
test('IsGenericDescriptor', function (t) {
264
	forEach(v.nonNullPrimitives.concat(null), function (primitive) {
265
		t['throws'](
266
			function () { ES.IsGenericDescriptor(primitive); },
267
			TypeError,
268
			debug(primitive) + ' is not a Property Descriptor'
269
		);
270
	});
271

    
272
	t.equal(ES.IsGenericDescriptor(), false, 'no value is not a Data Descriptor');
273
	t.equal(ES.IsGenericDescriptor(undefined), false, 'undefined value is not a Data Descriptor');
274

    
275
	t.equal(ES.IsGenericDescriptor(v.accessorDescriptor()), false, 'accessor descriptor is not a generic Descriptor');
276
	t.equal(ES.IsGenericDescriptor(v.mutatorDescriptor()), false, 'mutator descriptor is not a generic Descriptor');
277
	t.equal(ES.IsGenericDescriptor(v.dataDescriptor()), false, 'data descriptor is not a generic Descriptor');
278

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

    
281
	t.end();
282
});
283

    
284
test('FromPropertyDescriptor', function (t) {
285
	t.equal(ES.FromPropertyDescriptor(), undefined, 'no value begets undefined');
286
	t.equal(ES.FromPropertyDescriptor(undefined), undefined, 'undefined value begets undefined');
287

    
288
	forEach(v.nonNullPrimitives.concat(null), function (primitive) {
289
		t['throws'](
290
			function () { ES.FromPropertyDescriptor(primitive); },
291
			TypeError,
292
			debug(primitive) + ' is not a Property Descriptor'
293
		);
294
	});
295

    
296
	var accessor = v.accessorDescriptor();
297
	t.deepEqual(ES.FromPropertyDescriptor(accessor), {
298
		get: accessor['[[Get]]'],
299
		set: accessor['[[Set]]'],
300
		enumerable: !!accessor['[[Enumerable]]'],
301
		configurable: !!accessor['[[Configurable]]']
302
	});
303

    
304
	var mutator = v.mutatorDescriptor();
305
	t.deepEqual(ES.FromPropertyDescriptor(mutator), {
306
		get: mutator['[[Get]]'],
307
		set: mutator['[[Set]]'],
308
		enumerable: !!mutator['[[Enumerable]]'],
309
		configurable: !!mutator['[[Configurable]]']
310
	});
311
	var data = v.dataDescriptor();
312
	t.deepEqual(ES.FromPropertyDescriptor(data), {
313
		value: data['[[Value]]'],
314
		writable: data['[[Writable]]'],
315
		enumerable: !!data['[[Enumerable]]'],
316
		configurable: !!data['[[Configurable]]']
317
	});
318

    
319
	t['throws'](
320
		function () { ES.FromPropertyDescriptor(v.genericDescriptor()); },
321
		TypeError,
322
		'a complete Property Descriptor is required'
323
	);
324

    
325
	t.end();
326
});
327

    
328
test('ToPropertyDescriptor', function (t) {
329
	forEach(v.nonNullPrimitives.concat(null), function (primitive) {
330
		t['throws'](
331
			function () { ES.ToPropertyDescriptor(primitive); },
332
			TypeError,
333
			debug(primitive) + ' is not an Object'
334
		);
335
	});
336

    
337
	var accessor = v.accessorDescriptor();
338
	t.deepEqual(ES.ToPropertyDescriptor({
339
		get: accessor['[[Get]]'],
340
		enumerable: !!accessor['[[Enumerable]]'],
341
		configurable: !!accessor['[[Configurable]]']
342
	}), accessor);
343

    
344
	var mutator = v.mutatorDescriptor();
345
	t.deepEqual(ES.ToPropertyDescriptor({
346
		set: mutator['[[Set]]'],
347
		enumerable: !!mutator['[[Enumerable]]'],
348
		configurable: !!mutator['[[Configurable]]']
349
	}), mutator);
350

    
351
	var data = v.descriptors.nonConfigurable(v.dataDescriptor());
352
	t.deepEqual(ES.ToPropertyDescriptor({
353
		value: data['[[Value]]'],
354
		writable: data['[[Writable]]'],
355
		configurable: !!data['[[Configurable]]']
356
	}), data);
357

    
358
	var both = v.bothDescriptor();
359
	t['throws'](
360
		function () {
361
			ES.ToPropertyDescriptor({ get: both['[[Get]]'], value: both['[[Value]]'] });
362
		},
363
		TypeError,
364
		'data and accessor descriptors are mutually exclusive'
365
	);
366

    
367
	t['throws'](
368
		function () { ES.ToPropertyDescriptor({ get: 'not callable' }); },
369
		TypeError,
370
		'"get" must be undefined or callable'
371
	);
372

    
373
	t['throws'](
374
		function () { ES.ToPropertyDescriptor({ set: 'not callable' }); },
375
		TypeError,
376
		'"set" must be undefined or callable'
377
	);
378

    
379
	t.end();
380
});
381

    
382
test('Abstract Equality Comparison', function (t) {
383
	t.test('same types use ===', function (st) {
384
		forEach(v.primitives.concat(v.objects), function (value) {
385
			st.equal(ES['Abstract Equality Comparison'](value, value), value === value, debug(value) + ' is abstractly equal to itself');
386
		});
387
		st.end();
388
	});
389

    
390
	t.test('different types coerce', function (st) {
391
		var pairs = [
392
			[null, undefined],
393
			[3, '3'],
394
			[true, '3'],
395
			[true, 3],
396
			[false, 0],
397
			[false, '0'],
398
			[3, [3]],
399
			['3', [3]],
400
			[true, [1]],
401
			[false, [0]],
402
			[String(v.coercibleObject), v.coercibleObject],
403
			[Number(String(v.coercibleObject)), v.coercibleObject],
404
			[Number(v.coercibleObject), v.coercibleObject],
405
			[String(Number(v.coercibleObject)), v.coercibleObject]
406
		];
407
		forEach(pairs, function (pair) {
408
			var a = pair[0];
409
			var b = pair[1];
410
			// eslint-disable-next-line eqeqeq
411
			st.equal(ES['Abstract Equality Comparison'](a, b), a == b, debug(a) + ' == ' + debug(b));
412
			// eslint-disable-next-line eqeqeq
413
			st.equal(ES['Abstract Equality Comparison'](b, a), b == a, debug(b) + ' == ' + debug(a));
414
		});
415
		st.end();
416
	});
417

    
418
	t.end();
419
});
420

    
421
test('Strict Equality Comparison', function (t) {
422
	t.test('same types use ===', function (st) {
423
		forEach(v.primitives.concat(v.objects), function (value) {
424
			st.equal(ES['Strict Equality Comparison'](value, value), value === value, debug(value) + ' is strictly equal to itself');
425
		});
426
		st.end();
427
	});
428

    
429
	t.test('different types are not ===', function (st) {
430
		var pairs = [
431
			[null, undefined],
432
			[3, '3'],
433
			[true, '3'],
434
			[true, 3],
435
			[false, 0],
436
			[false, '0'],
437
			[3, [3]],
438
			['3', [3]],
439
			[true, [1]],
440
			[false, [0]],
441
			[String(v.coercibleObject), v.coercibleObject],
442
			[Number(String(v.coercibleObject)), v.coercibleObject],
443
			[Number(v.coercibleObject), v.coercibleObject],
444
			[String(Number(v.coercibleObject)), v.coercibleObject]
445
		];
446
		forEach(pairs, function (pair) {
447
			var a = pair[0];
448
			var b = pair[1];
449
			st.equal(ES['Strict Equality Comparison'](a, b), a === b, debug(a) + ' === ' + debug(b));
450
			st.equal(ES['Strict Equality Comparison'](b, a), b === a, debug(b) + ' === ' + debug(a));
451
		});
452
		st.end();
453
	});
454

    
455
	t.end();
456
});
457

    
458
test('Abstract Relational Comparison', function (t) {
459
	t.test('at least one operand is NaN', function (st) {
460
		st.equal(ES['Abstract Relational Comparison'](NaN, {}, true), undefined, 'LeftFirst: first is NaN, returns undefined');
461
		st.equal(ES['Abstract Relational Comparison']({}, NaN, true), undefined, 'LeftFirst: second is NaN, returns undefined');
462
		st.equal(ES['Abstract Relational Comparison'](NaN, {}, false), undefined, '!LeftFirst: first is NaN, returns undefined');
463
		st.equal(ES['Abstract Relational Comparison']({}, NaN, false), undefined, '!LeftFirst: second is NaN, returns undefined');
464
		st.end();
465
	});
466

    
467
	t.equal(ES['Abstract Relational Comparison'](3, 4, true), true, 'LeftFirst: 3 is less than 4');
468
	t.equal(ES['Abstract Relational Comparison'](4, 3, true), false, 'LeftFirst: 3 is not less than 4');
469
	t.equal(ES['Abstract Relational Comparison'](3, 4, false), true, '!LeftFirst: 3 is less than 4');
470
	t.equal(ES['Abstract Relational Comparison'](4, 3, false), false, '!LeftFirst: 3 is not less than 4');
471

    
472
	t.equal(ES['Abstract Relational Comparison']('3', '4', true), true, 'LeftFirst: "3" is less than "4"');
473
	t.equal(ES['Abstract Relational Comparison']('4', '3', true), false, 'LeftFirst: "3" is not less than "4"');
474
	t.equal(ES['Abstract Relational Comparison']('3', '4', false), true, '!LeftFirst: "3" is less than "4"');
475
	t.equal(ES['Abstract Relational Comparison']('4', '3', false), false, '!LeftFirst: "3" is not less than "4"');
476

    
477
	t.equal(ES['Abstract Relational Comparison'](v.coercibleObject, 42, true), true, 'LeftFirst: coercible object is less than 42');
478
	t.equal(ES['Abstract Relational Comparison'](42, v.coercibleObject, true), false, 'LeftFirst: 42 is not less than coercible object');
479
	t.equal(ES['Abstract Relational Comparison'](v.coercibleObject, 42, false), true, '!LeftFirst: coercible object is less than 42');
480
	t.equal(ES['Abstract Relational Comparison'](42, v.coercibleObject, false), false, '!LeftFirst: 42 is not less than coercible object');
481

    
482
	t.equal(ES['Abstract Relational Comparison'](v.coercibleObject, '3', true), false, 'LeftFirst: coercible object is not less than "3"');
483
	t.equal(ES['Abstract Relational Comparison']('3', v.coercibleObject, true), false, 'LeftFirst: "3" is not less than coercible object');
484
	t.equal(ES['Abstract Relational Comparison'](v.coercibleObject, '3', false), false, '!LeftFirst: coercible object is not less than "3"');
485
	t.equal(ES['Abstract Relational Comparison']('3', v.coercibleObject, false), false, '!LeftFirst: "3" is not less than coercible object');
486

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

    
490
test('FromPropertyDescriptor', function (t) {
491
	t.equal(ES.FromPropertyDescriptor(), undefined, 'no value begets undefined');
492
	t.equal(ES.FromPropertyDescriptor(undefined), undefined, 'undefined value begets undefined');
493

    
494
	forEach(v.nonUndefinedPrimitives, function (primitive) {
495
		t['throws'](
496
			function () { ES.FromPropertyDescriptor(primitive); },
497
			TypeError,
498
			debug(primitive) + ' is not a Property Descriptor'
499
		);
500
	});
501

    
502
	var accessor = v.accessorDescriptor();
503
	t.deepEqual(ES.FromPropertyDescriptor(accessor), {
504
		get: accessor['[[Get]]'],
505
		set: accessor['[[Set]]'],
506
		enumerable: !!accessor['[[Enumerable]]'],
507
		configurable: !!accessor['[[Configurable]]']
508
	});
509

    
510
	var mutator = v.mutatorDescriptor();
511
	t.deepEqual(ES.FromPropertyDescriptor(mutator), {
512
		get: mutator['[[Get]]'],
513
		set: mutator['[[Set]]'],
514
		enumerable: !!mutator['[[Enumerable]]'],
515
		configurable: !!mutator['[[Configurable]]']
516
	});
517
	var data = v.dataDescriptor();
518
	t.deepEqual(ES.FromPropertyDescriptor(data), {
519
		value: data['[[Value]]'],
520
		writable: data['[[Writable]]'],
521
		enumerable: !!data['[[Enumerable]]'],
522
		configurable: !!data['[[Configurable]]']
523
	});
524

    
525
	t['throws'](
526
		function () { ES.FromPropertyDescriptor(v.genericDescriptor()); },
527
		TypeError,
528
		'a complete Property Descriptor is required'
529
	);
530

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

    
534
test('SecFromTime', function (t) {
535
	var now = new Date();
536
	t.equal(ES.SecFromTime(now.getTime()), now.getUTCSeconds(), 'second from Date timestamp matches getUTCSeconds');
537
	t.end();
538
});
539

    
540
test('MinFromTime', function (t) {
541
	var now = new Date();
542
	t.equal(ES.MinFromTime(now.getTime()), now.getUTCMinutes(), 'minute from Date timestamp matches getUTCMinutes');
543
	t.end();
544
});
545

    
546
test('HourFromTime', function (t) {
547
	var now = new Date();
548
	t.equal(ES.HourFromTime(now.getTime()), now.getUTCHours(), 'hour from Date timestamp matches getUTCHours');
549
	t.end();
550
});
551

    
552
test('msFromTime', function (t) {
553
	var now = new Date();
554
	t.equal(ES.msFromTime(now.getTime()), now.getUTCMilliseconds(), 'ms from Date timestamp matches getUTCMilliseconds');
555
	t.end();
556
});
557

    
558
var msPerSecond = 1e3;
559
var msPerMinute = 60 * msPerSecond;
560
var msPerHour = 60 * msPerMinute;
561
var msPerDay = 24 * msPerHour;
562

    
563
test('Day', function (t) {
564
	var time = Date.UTC(2019, 8, 10, 2, 3, 4, 5);
565
	var add = 2.5;
566
	var later = new Date(time + (add * msPerDay));
567

    
568
	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');
569
	t.end();
570
});
571

    
572
test('TimeWithinDay', function (t) {
573
	var time = Date.UTC(2019, 8, 10, 2, 3, 4, 5);
574
	var add = 2.5;
575
	var later = new Date(time + (add * msPerDay));
576

    
577
	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');
578
	t.end();
579
});
580

    
581
test('DayFromYear', function (t) {
582
	t.equal(ES.DayFromYear(2021) - ES.DayFromYear(2020), 366, '2021 is a leap year, has 366 days');
583
	t.equal(ES.DayFromYear(2020) - ES.DayFromYear(2019), 365, '2020 is not a leap year, has 365 days');
584
	t.equal(ES.DayFromYear(2019) - ES.DayFromYear(2018), 365, '2019 is not a leap year, has 365 days');
585
	t.equal(ES.DayFromYear(2018) - ES.DayFromYear(2017), 365, '2018 is not a leap year, has 365 days');
586
	t.equal(ES.DayFromYear(2017) - ES.DayFromYear(2016), 366, '2017 is a leap year, has 366 days');
587

    
588
	t.end();
589
});
590

    
591
test('TimeFromYear', function (t) {
592
	for (var i = 1900; i < 2100; i += 1) {
593
		t.equal(ES.TimeFromYear(i), Date.UTC(i, 0, 1), 'TimeFromYear matches a Date object’s year: ' + i);
594
	}
595
	t.end();
596
});
597

    
598
test('YearFromTime', function (t) {
599
	for (var i = 1900; i < 2100; i += 1) {
600
		t.equal(ES.YearFromTime(Date.UTC(i, 0, 1)), i, 'YearFromTime matches a Date object’s year on 1/1: ' + i);
601
		t.equal(ES.YearFromTime(Date.UTC(i, 10, 1)), i, 'YearFromTime matches a Date object’s year on 10/1: ' + i);
602
	}
603
	t.end();
604
});
605

    
606
test('WeekDay', function (t) {
607
	var now = new Date();
608
	var today = now.getUTCDay();
609
	for (var i = 0; i < 7; i += 1) {
610
		var weekDay = ES.WeekDay(now.getTime() + (i * msPerDay));
611
		t.equal(weekDay, (today + i) % 7, i + ' days after today (' + today + '), WeekDay is ' + weekDay);
612
	}
613
	t.end();
614
});
615

    
616
test('DaysInYear', function (t) {
617
	t.equal(ES.DaysInYear(2021), 365, '2021 is not a leap year');
618
	t.equal(ES.DaysInYear(2020), 366, '2020 is a leap year');
619
	t.equal(ES.DaysInYear(2019), 365, '2019 is not a leap year');
620
	t.equal(ES.DaysInYear(2018), 365, '2018 is not a leap year');
621
	t.equal(ES.DaysInYear(2017), 365, '2017 is not a leap year');
622
	t.equal(ES.DaysInYear(2016), 366, '2016 is a leap year');
623

    
624
	t.end();
625
});
626

    
627
test('InLeapYear', function (t) {
628
	t.equal(ES.InLeapYear(Date.UTC(2021, 0, 1)), 0, '2021 is not a leap year');
629
	t.equal(ES.InLeapYear(Date.UTC(2020, 0, 1)), 1, '2020 is a leap year');
630
	t.equal(ES.InLeapYear(Date.UTC(2019, 0, 1)), 0, '2019 is not a leap year');
631
	t.equal(ES.InLeapYear(Date.UTC(2018, 0, 1)), 0, '2018 is not a leap year');
632
	t.equal(ES.InLeapYear(Date.UTC(2017, 0, 1)), 0, '2017 is not a leap year');
633
	t.equal(ES.InLeapYear(Date.UTC(2016, 0, 1)), 1, '2016 is a leap year');
634

    
635
	t.end();
636
});
637

    
638
test('DayWithinYear', function (t) {
639
	t.equal(ES.DayWithinYear(Date.UTC(2019, 0, 1)), 0, '1/1 is the 1st day');
640
	t.equal(ES.DayWithinYear(Date.UTC(2019, 11, 31)), 364, '12/31 is the 365th day in a non leap year');
641
	t.equal(ES.DayWithinYear(Date.UTC(2016, 11, 31)), 365, '12/31 is the 366th day in a leap year');
642

    
643
	t.end();
644
});
645

    
646
test('MonthFromTime', function (t) {
647
	t.equal(ES.MonthFromTime(Date.UTC(2019, 0, 1)), 0, 'non-leap: 1/1 gives January');
648
	t.equal(ES.MonthFromTime(Date.UTC(2019, 0, 31)), 0, 'non-leap: 1/31 gives January');
649
	t.equal(ES.MonthFromTime(Date.UTC(2019, 1, 1)), 1, 'non-leap: 2/1 gives February');
650
	t.equal(ES.MonthFromTime(Date.UTC(2019, 1, 28)), 1, 'non-leap: 2/28 gives February');
651
	t.equal(ES.MonthFromTime(Date.UTC(2019, 1, 29)), 2, 'non-leap: 2/29 gives March');
652
	t.equal(ES.MonthFromTime(Date.UTC(2019, 2, 1)), 2, 'non-leap: 3/1 gives March');
653
	t.equal(ES.MonthFromTime(Date.UTC(2019, 2, 31)), 2, 'non-leap: 3/31 gives March');
654
	t.equal(ES.MonthFromTime(Date.UTC(2019, 3, 1)), 3, 'non-leap: 4/1 gives April');
655
	t.equal(ES.MonthFromTime(Date.UTC(2019, 3, 30)), 3, 'non-leap: 4/30 gives April');
656
	t.equal(ES.MonthFromTime(Date.UTC(2019, 4, 1)), 4, 'non-leap: 5/1 gives May');
657
	t.equal(ES.MonthFromTime(Date.UTC(2019, 4, 31)), 4, 'non-leap: 5/31 gives May');
658
	t.equal(ES.MonthFromTime(Date.UTC(2019, 5, 1)), 5, 'non-leap: 6/1 gives June');
659
	t.equal(ES.MonthFromTime(Date.UTC(2019, 5, 30)), 5, 'non-leap: 6/30 gives June');
660
	t.equal(ES.MonthFromTime(Date.UTC(2019, 6, 1)), 6, 'non-leap: 7/1 gives July');
661
	t.equal(ES.MonthFromTime(Date.UTC(2019, 6, 31)), 6, 'non-leap: 7/31 gives July');
662
	t.equal(ES.MonthFromTime(Date.UTC(2019, 7, 1)), 7, 'non-leap: 8/1 gives August');
663
	t.equal(ES.MonthFromTime(Date.UTC(2019, 7, 30)), 7, 'non-leap: 8/30 gives August');
664
	t.equal(ES.MonthFromTime(Date.UTC(2019, 8, 1)), 8, 'non-leap: 9/1 gives September');
665
	t.equal(ES.MonthFromTime(Date.UTC(2019, 8, 30)), 8, 'non-leap: 9/30 gives September');
666
	t.equal(ES.MonthFromTime(Date.UTC(2019, 9, 1)), 9, 'non-leap: 10/1 gives October');
667
	t.equal(ES.MonthFromTime(Date.UTC(2019, 9, 31)), 9, 'non-leap: 10/31 gives October');
668
	t.equal(ES.MonthFromTime(Date.UTC(2019, 10, 1)), 10, 'non-leap: 11/1 gives November');
669
	t.equal(ES.MonthFromTime(Date.UTC(2019, 10, 30)), 10, 'non-leap: 11/30 gives November');
670
	t.equal(ES.MonthFromTime(Date.UTC(2019, 11, 1)), 11, 'non-leap: 12/1 gives December');
671
	t.equal(ES.MonthFromTime(Date.UTC(2019, 11, 31)), 11, 'non-leap: 12/31 gives December');
672

    
673
	t.equal(ES.MonthFromTime(Date.UTC(2016, 0, 1)), 0, 'leap: 1/1 gives January');
674
	t.equal(ES.MonthFromTime(Date.UTC(2016, 0, 31)), 0, 'leap: 1/31 gives January');
675
	t.equal(ES.MonthFromTime(Date.UTC(2016, 1, 1)), 1, 'leap: 2/1 gives February');
676
	t.equal(ES.MonthFromTime(Date.UTC(2016, 1, 28)), 1, 'leap: 2/28 gives February');
677
	t.equal(ES.MonthFromTime(Date.UTC(2016, 1, 29)), 1, 'leap: 2/29 gives February');
678
	t.equal(ES.MonthFromTime(Date.UTC(2016, 2, 1)), 2, 'leap: 3/1 gives March');
679
	t.equal(ES.MonthFromTime(Date.UTC(2016, 2, 31)), 2, 'leap: 3/31 gives March');
680
	t.equal(ES.MonthFromTime(Date.UTC(2016, 3, 1)), 3, 'leap: 4/1 gives April');
681
	t.equal(ES.MonthFromTime(Date.UTC(2016, 3, 30)), 3, 'leap: 4/30 gives April');
682
	t.equal(ES.MonthFromTime(Date.UTC(2016, 4, 1)), 4, 'leap: 5/1 gives May');
683
	t.equal(ES.MonthFromTime(Date.UTC(2016, 4, 31)), 4, 'leap: 5/31 gives May');
684
	t.equal(ES.MonthFromTime(Date.UTC(2016, 5, 1)), 5, 'leap: 6/1 gives June');
685
	t.equal(ES.MonthFromTime(Date.UTC(2016, 5, 30)), 5, 'leap: 6/30 gives June');
686
	t.equal(ES.MonthFromTime(Date.UTC(2016, 6, 1)), 6, 'leap: 7/1 gives July');
687
	t.equal(ES.MonthFromTime(Date.UTC(2016, 6, 31)), 6, 'leap: 7/31 gives July');
688
	t.equal(ES.MonthFromTime(Date.UTC(2016, 7, 1)), 7, 'leap: 8/1 gives August');
689
	t.equal(ES.MonthFromTime(Date.UTC(2016, 7, 30)), 7, 'leap: 8/30 gives August');
690
	t.equal(ES.MonthFromTime(Date.UTC(2016, 8, 1)), 8, 'leap: 9/1 gives September');
691
	t.equal(ES.MonthFromTime(Date.UTC(2016, 8, 30)), 8, 'leap: 9/30 gives September');
692
	t.equal(ES.MonthFromTime(Date.UTC(2016, 9, 1)), 9, 'leap: 10/1 gives October');
693
	t.equal(ES.MonthFromTime(Date.UTC(2016, 9, 31)), 9, 'leap: 10/31 gives October');
694
	t.equal(ES.MonthFromTime(Date.UTC(2016, 10, 1)), 10, 'leap: 11/1 gives November');
695
	t.equal(ES.MonthFromTime(Date.UTC(2016, 10, 30)), 10, 'leap: 11/30 gives November');
696
	t.equal(ES.MonthFromTime(Date.UTC(2016, 11, 1)), 11, 'leap: 12/1 gives December');
697
	t.equal(ES.MonthFromTime(Date.UTC(2016, 11, 31)), 11, 'leap: 12/31 gives December');
698
	t.end();
699
});
700

    
701
test('DateFromTime', function (t) {
702
	var i;
703
	for (i = 1; i <= 28; i += 1) {
704
		t.equal(ES.DateFromTime(Date.UTC(2019, 1, i)), i, '2019.02.' + i + ' is date ' + i);
705
	}
706
	for (i = 1; i <= 29; i += 1) {
707
		t.equal(ES.DateFromTime(Date.UTC(2016, 1, i)), i, '2016.02.' + i + ' is date ' + i);
708
	}
709
	for (i = 1; i <= 30; i += 1) {
710
		t.equal(ES.DateFromTime(Date.UTC(2019, 8, i)), i, '2019.09.' + i + ' is date ' + i);
711
	}
712
	for (i = 1; i <= 31; i += 1) {
713
		t.equal(ES.DateFromTime(Date.UTC(2019, 9, i)), i, '2019.10.' + i + ' is date ' + i);
714
	}
715
	t.end();
716
});
717

    
718
test('MakeDay', function (t) {
719
	var day2015 = 16687;
720
	t.equal(ES.MakeDay(2015, 8, 9), day2015, '2015.09.09 is day 16687');
721
	var day2016 = day2015 + 366; // 2016 is a leap year
722
	t.equal(ES.MakeDay(2016, 8, 9), day2016, '2015.09.09 is day 17053');
723
	var day2017 = day2016 + 365;
724
	t.equal(ES.MakeDay(2017, 8, 9), day2017, '2017.09.09 is day 17418');
725
	var day2018 = day2017 + 365;
726
	t.equal(ES.MakeDay(2018, 8, 9), day2018, '2018.09.09 is day 17783');
727
	var day2019 = day2018 + 365;
728
	t.equal(ES.MakeDay(2019, 8, 9), day2019, '2019.09.09 is day 18148');
729
	t.end();
730
});
731

    
732
test('MakeDate', function (t) {
733
	forEach(v.infinities.concat(NaN), function (nonFiniteNumber) {
734
		t.ok(is(ES.MakeDate(nonFiniteNumber, 0), NaN), debug(nonFiniteNumber) + ' is not a finite `day`');
735
		t.ok(is(ES.MakeDate(0, nonFiniteNumber), NaN), debug(nonFiniteNumber) + ' is not a finite `time`');
736
	});
737
	t.equal(ES.MakeDate(0, 0), 0, 'zero day and zero time is zero date');
738
	t.equal(ES.MakeDate(0, 123), 123, 'zero day and nonzero time is a date of the "time"');
739
	t.equal(ES.MakeDate(1, 0), msPerDay, 'day of 1 and zero time is a date of "ms per day"');
740
	t.equal(ES.MakeDate(3, 0), 3 * msPerDay, 'day of 3 and zero time is a date of thrice "ms per day"');
741
	t.equal(ES.MakeDate(1, 123), msPerDay + 123, 'day of 1 and nonzero time is a date of "ms per day" plus the "time"');
742
	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"');
743

    
744
	t.end();
745
});
746

    
747
test('MakeTime', function (t) {
748
	forEach(v.infinities.concat(NaN), function (nonFiniteNumber) {
749
		t.ok(is(ES.MakeTime(nonFiniteNumber, 0, 0, 0), NaN), debug(nonFiniteNumber) + ' is not a finite `hour`');
750
		t.ok(is(ES.MakeTime(0, nonFiniteNumber, 0, 0), NaN), debug(nonFiniteNumber) + ' is not a finite `min`');
751
		t.ok(is(ES.MakeTime(0, 0, nonFiniteNumber, 0), NaN), debug(nonFiniteNumber) + ' is not a finite `sec`');
752
		t.ok(is(ES.MakeTime(0, 0, 0, nonFiniteNumber), NaN), debug(nonFiniteNumber) + ' is not a finite `ms`');
753
	});
754

    
755
	t.equal(
756
		ES.MakeTime(1.2, 2.3, 3.4, 4.5),
757
		(1 * msPerHour) + (2 * msPerMinute) + (3 * msPerSecond) + 4,
758
		'all numbers are converted to integer, multiplied by the right number of ms, and summed'
759
	);
760
	t.end();
761
});
762

    
763
test('TimeClip', function (t) {
764
	forEach(v.infinities.concat(NaN), function (nonFiniteNumber) {
765
		t.ok(is(ES.TimeClip(nonFiniteNumber), NaN), debug(nonFiniteNumber) + ' is not a finite `time`');
766
	});
767
	t.ok(is(ES.TimeClip(8.64e15 + 1), NaN), '8.64e15 is the largest magnitude considered "finite"');
768
	t.ok(is(ES.TimeClip(-8.64e15 - 1), NaN), '-8.64e15 is the largest magnitude considered "finite"');
769

    
770
	forEach(v.zeroes.concat([-10, 10, +new Date()]), function (time) {
771
		t.looseEqual(ES.TimeClip(time), time, debug(time) + ' is a time of ' + debug(time));
772
	});
773

    
774
	t.end();
775
});
776

    
777
test('modulo', function (t) {
778
	t.equal(3 % 2, 1, '+3 % 2 is +1');
779
	t.equal(ES.modulo(3, 2), 1, '+3 mod 2 is +1');
780

    
781
	t.equal(-3 % 2, -1, '-3 % 2 is -1');
782
	t.equal(ES.modulo(-3, 2), 1, '-3 mod 2 is +1');
783
	t.end();
784
});
(8-8/12)