1 | describe('Number', function () {
|
2 | var functionsHaveNames = (function foo() {}).name === 'foo';
|
3 | var ifFunctionsHaveNamesIt = functionsHaveNames ? it : xit;
|
4 | var ifShimIt = (typeof process !== 'undefined' && process.env.NO_ES6_SHIM) ? it.skip : it;
|
5 |
|
6 | var integers = [5295, -5295, -9007199254740991, 9007199254740991, 0, -0];
|
7 | var nonIntegers = [-9007199254741992, 9007199254741992, 5.9];
|
8 | var infinities = [Infinity, -Infinity];
|
9 |
|
10 | var valueOfThree = { valueOf: function () { return 3; } };
|
11 | var valueOfNaN = { valueOf: function () { return NaN; } };
|
12 | var valueOfThrows = { valueOf: function () { throw Object(17); } };
|
13 | var toStringThrows = { toString: function () { throw Object(42); } };
|
14 | var toPrimitiveThrows = {
|
15 | valueOf: function () { throw Object(17); },
|
16 | toString: function () { throw Object(42); }
|
17 | };
|
18 |
|
19 | var nonNumbers = [
|
20 | undefined,
|
21 | true,
|
22 | false,
|
23 | null,
|
24 | {},
|
25 | [],
|
26 | 'str',
|
27 | '',
|
28 | valueOfThree,
|
29 | valueOfNaN,
|
30 | valueOfThrows,
|
31 | toStringThrows,
|
32 | toPrimitiveThrows,
|
33 | /a/g
|
34 | ];
|
35 | var expectTrue = function (item) {
|
36 | expect(item).to.equal(true);
|
37 | };
|
38 | var expectFalse = function (item) {
|
39 | expect(item).to.equal(false);
|
40 | };
|
41 |
|
42 | ifShimIt('is on the exported object', function () {
|
43 | var exported = require('../');
|
44 | expect(exported.Number).to.equal(Number);
|
45 | });
|
46 |
|
47 | describe('Number constants', function () {
|
48 | it('should have max safe integer', function () {
|
49 | expect(Number).to.have.property('MAX_SAFE_INTEGER');
|
50 | expect(Object.prototype.propertyIsEnumerable.call(Number, 'MAX_SAFE_INTEGER')).to.equal(false);
|
51 | expect(Number.MAX_SAFE_INTEGER).to.equal(Math.pow(2, 53) - 1);
|
52 | });
|
53 |
|
54 | it('should have min safe integer', function () {
|
55 | expect(Number).to.have.property('MIN_SAFE_INTEGER');
|
56 | expect(Object.prototype.propertyIsEnumerable.call(Number, 'MIN_SAFE_INTEGER')).to.equal(false);
|
57 | expect(Number.MIN_SAFE_INTEGER).to.equal(-Math.pow(2, 53) + 1);
|
58 | });
|
59 |
|
60 | it('should have epsilon', function () {
|
61 | expect(Number).to.have.property('EPSILON');
|
62 | expect(Object.prototype.propertyIsEnumerable.call(Number, 'EPSILON')).to.equal(false);
|
63 | expect(Number.EPSILON).to.equal(2.2204460492503130808472633361816e-16);
|
64 | });
|
65 |
|
66 | it('should have NaN', function () {
|
67 | expect(Number).to.have.property('NaN');
|
68 | expect(Object.prototype.propertyIsEnumerable.call(Number, 'NaN')).to.equal(false);
|
69 | expect(isNaN(Number.NaN)).to.equal(true);
|
70 | });
|
71 |
|
72 | it('should have MAX_VALUE', function () {
|
73 | expect(Number).to.have.property('MAX_VALUE');
|
74 | expect(Object.prototype.propertyIsEnumerable.call(Number, 'MAX_VALUE')).to.equal(false);
|
75 | expect(Number.MAX_VALUE).to.equal(1.7976931348623157e+308);
|
76 | });
|
77 |
|
78 | it('should have MIN_VALUE', function () {
|
79 | expect(Number).to.have.property('MIN_VALUE');
|
80 | expect(Object.prototype.propertyIsEnumerable.call(Number, 'MIN_VALUE')).to.equal(false);
|
81 | expect(Number.MIN_VALUE).to.equal(5e-324);
|
82 | });
|
83 |
|
84 | it('should have NEGATIVE_INFINITY', function () {
|
85 | expect(Number).to.have.property('NEGATIVE_INFINITY');
|
86 | expect(Object.prototype.propertyIsEnumerable.call(Number, 'NEGATIVE_INFINITY')).to.equal(false);
|
87 | expect(Number.NEGATIVE_INFINITY).to.equal(-Infinity);
|
88 | });
|
89 |
|
90 | it('should have POSITIVE_INFINITY', function () {
|
91 | expect(Number).to.have.property('POSITIVE_INFINITY');
|
92 | expect(Object.prototype.propertyIsEnumerable.call(Number, 'POSITIVE_INFINITY')).to.equal(false);
|
93 | expect(Number.POSITIVE_INFINITY).to.equal(Infinity);
|
94 | });
|
95 | });
|
96 |
|
97 | describe('.parseInt()', function () {
|
98 | if (!Object.prototype.hasOwnProperty.call(Number, 'parseInt')) {
|
99 | return it('exists', function () {
|
100 | expect(Number).to.have.property('parseInt');
|
101 | });
|
102 | }
|
103 |
|
104 | it('should work', function () {
|
105 |
|
106 | expect(Number.parseInt('601')).to.equal(601);
|
107 |
|
108 | });
|
109 |
|
110 | ifFunctionsHaveNamesIt('has the right name', function () {
|
111 | expect(Number.parseInt).to.have.property('name', 'parseInt');
|
112 | });
|
113 |
|
114 | it('is not enumerable', function () {
|
115 | expect(Number).ownPropertyDescriptor('parseInt').to.have.property('enumerable', false);
|
116 | });
|
117 |
|
118 | it('has the right arity', function () {
|
119 |
|
120 | expect(Number.parseInt).to.have.property('length', 2);
|
121 | });
|
122 |
|
123 | it('is the same object as the global parseInt', function () {
|
124 |
|
125 | expect(Number.parseInt).to.equal(parseInt);
|
126 | });
|
127 | });
|
128 |
|
129 | describe('.parseFloat()', function () {
|
130 | if (!Object.prototype.hasOwnProperty.call(Number, 'parseFloat')) {
|
131 | return it('exists', function () {
|
132 | expect(Number).to.have.property('parseFloat');
|
133 | });
|
134 | }
|
135 |
|
136 | it('should work', function () {
|
137 | expect(Number.parseFloat('5.5')).to.equal(5.5);
|
138 | });
|
139 |
|
140 | ifFunctionsHaveNamesIt('has the right name', function () {
|
141 | expect(Number.parseFloat).to.have.property('name', 'parseFloat');
|
142 | });
|
143 |
|
144 | it('is not enumerable', function () {
|
145 | expect(Number).ownPropertyDescriptor('parseFloat').to.have.property('enumerable', false);
|
146 | });
|
147 |
|
148 | it('has the right arity', function () {
|
149 | expect(Number.parseFloat).to.have.property('length', 1);
|
150 | });
|
151 | });
|
152 |
|
153 | describe('.isFinite()', function () {
|
154 | if (!Object.prototype.hasOwnProperty.call(Number, 'isFinite')) {
|
155 | return it('exists', function () {
|
156 | expect(Number).to.have.property('isFinite');
|
157 | });
|
158 | }
|
159 |
|
160 | ifFunctionsHaveNamesIt('has the right name', function () {
|
161 | expect(Number.isFinite).to.have.property('name', 'isFinite');
|
162 | });
|
163 |
|
164 | it('is not enumerable', function () {
|
165 | expect(Number).ownPropertyDescriptor('isFinite').to.have.property('enumerable', false);
|
166 | });
|
167 |
|
168 | it('has the right arity', function () {
|
169 | expect(Number.isFinite).to.have.property('length', 1);
|
170 | });
|
171 |
|
172 | it('should work', function () {
|
173 | integers.map(Number.isFinite).forEach(expectTrue);
|
174 | infinities.map(Number.isFinite).forEach(expectFalse);
|
175 | expect(Number.isFinite(Infinity)).to.equal(false);
|
176 | expect(Number.isFinite(-Infinity)).to.equal(false);
|
177 | expect(Number.isFinite(NaN)).to.equal(false);
|
178 | expect(Number.isFinite(4)).to.equal(true);
|
179 | expect(Number.isFinite(4.5)).to.equal(true);
|
180 | expect(Number.isFinite('hi')).to.equal(false);
|
181 | expect(Number.isFinite('1.3')).to.equal(false);
|
182 | expect(Number.isFinite('51')).to.equal(false);
|
183 | expect(Number.isFinite(0)).to.equal(true);
|
184 | expect(Number.isFinite(-0)).to.equal(true);
|
185 | expect(Number.isFinite(valueOfThree)).to.equal(false);
|
186 | expect(Number.isFinite(valueOfNaN)).to.equal(false);
|
187 | expect(Number.isFinite(valueOfThrows)).to.equal(false);
|
188 | expect(Number.isFinite(toStringThrows)).to.equal(false);
|
189 | expect(Number.isFinite(toPrimitiveThrows)).to.equal(false);
|
190 | });
|
191 |
|
192 | it('should not be confused by type coercion', function () {
|
193 | nonNumbers.map(Number.isFinite).forEach(expectFalse);
|
194 | });
|
195 | });
|
196 |
|
197 | describe('.isInteger()', function () {
|
198 | if (!Object.prototype.hasOwnProperty.call(Number, 'isInteger')) {
|
199 | return it('exists', function () {
|
200 | expect(Number).to.have.property('isInteger');
|
201 | });
|
202 | }
|
203 |
|
204 | ifFunctionsHaveNamesIt('has the right name', function () {
|
205 | expect(Number.isInteger).to.have.property('name', 'isInteger');
|
206 | });
|
207 |
|
208 | it('is not enumerable', function () {
|
209 | expect(Number).ownPropertyDescriptor('isInteger').to.have.property('enumerable', false);
|
210 | });
|
211 |
|
212 | it('has the right arity', function () {
|
213 | expect(Number.isInteger).to.have.property('length', 1);
|
214 | });
|
215 |
|
216 | it('should be truthy on integers', function () {
|
217 | integers.map(Number.isInteger).forEach(expectTrue);
|
218 | expect(Number.isInteger(4)).to.equal(true);
|
219 | expect(Number.isInteger(4.0)).to.equal(true);
|
220 | expect(Number.isInteger(1801439850948)).to.equal(true);
|
221 | });
|
222 |
|
223 | it('should be false when the type is not number', function () {
|
224 | nonNumbers.forEach(function (thing) {
|
225 | expect(Number.isInteger(thing)).to.equal(false);
|
226 | });
|
227 | });
|
228 |
|
229 | it('should be false when NaN', function () {
|
230 | expect(Number.isInteger(NaN)).to.equal(false);
|
231 | });
|
232 |
|
233 | it('should be false when ∞', function () {
|
234 | expect(Number.isInteger(Infinity)).to.equal(false);
|
235 | expect(Number.isInteger(-Infinity)).to.equal(false);
|
236 | });
|
237 |
|
238 | it('should be false when number is not integer', function () {
|
239 | expect(Number.isInteger(3.4)).to.equal(false);
|
240 | expect(Number.isInteger(-3.4)).to.equal(false);
|
241 | });
|
242 |
|
243 | it('should be true when abs(number) is 2^53 or larger', function () {
|
244 | expect(Number.isInteger(Math.pow(2, 53))).to.equal(true);
|
245 | expect(Number.isInteger(Math.pow(2, 54))).to.equal(true);
|
246 | expect(Number.isInteger(-Math.pow(2, 53))).to.equal(true);
|
247 | expect(Number.isInteger(-Math.pow(2, 54))).to.equal(true);
|
248 | });
|
249 |
|
250 | it('should be true when abs(number) is less than 2^53', function () {
|
251 | var safeIntegers = [0, 1, Math.pow(2, 53) - 1];
|
252 | safeIntegers.forEach(function (integer) {
|
253 | expect(Number.isInteger(integer)).to.equal(true);
|
254 | expect(Number.isInteger(-integer)).to.equal(true);
|
255 | });
|
256 | });
|
257 | });
|
258 |
|
259 | describe('.isSafeInteger()', function () {
|
260 | if (!Object.prototype.hasOwnProperty.call(Number, 'isSafeInteger')) {
|
261 | return it('exists', function () {
|
262 | expect(Number).to.have.property('isSafeInteger');
|
263 | });
|
264 | }
|
265 |
|
266 | ifFunctionsHaveNamesIt('has the right name', function () {
|
267 | expect(Number.isSafeInteger).to.have.property('name', 'isSafeInteger');
|
268 | });
|
269 |
|
270 | it('is not enumerable', function () {
|
271 | expect(Number).ownPropertyDescriptor('isSafeInteger').to.have.property('enumerable', false);
|
272 | });
|
273 |
|
274 | it('has the right arity', function () {
|
275 | expect(Number.isSafeInteger).to.have.property('length', 1);
|
276 | });
|
277 |
|
278 | it('should be truthy on integers', function () {
|
279 | integers.map(Number.isSafeInteger).forEach(expectTrue);
|
280 | expect(Number.isSafeInteger(4)).to.equal(true);
|
281 | expect(Number.isSafeInteger(4.0)).to.equal(true);
|
282 | expect(Number.isSafeInteger(1801439850948)).to.equal(true);
|
283 | });
|
284 |
|
285 | it('should be false when the type is not number', function () {
|
286 | nonNumbers.forEach(function (thing) {
|
287 | expect(Number.isSafeInteger(thing)).to.equal(false);
|
288 | });
|
289 | });
|
290 |
|
291 | it('should be false when NaN', function () {
|
292 | expect(Number.isSafeInteger(NaN)).to.equal(false);
|
293 | });
|
294 |
|
295 | it('should be false when ∞', function () {
|
296 | expect(Number.isSafeInteger(Infinity)).to.equal(false);
|
297 | expect(Number.isSafeInteger(-Infinity)).to.equal(false);
|
298 | });
|
299 |
|
300 | it('should be false when number is not integer', function () {
|
301 | expect(Number.isSafeInteger(3.4)).to.equal(false);
|
302 | expect(Number.isSafeInteger(-3.4)).to.equal(false);
|
303 | });
|
304 |
|
305 | it('should be false when abs(number) is 2^53 or larger', function () {
|
306 | expect(Number.isSafeInteger(Math.pow(2, 53))).to.equal(false);
|
307 | expect(Number.isSafeInteger(Math.pow(2, 54))).to.equal(false);
|
308 | expect(Number.isSafeInteger(-Math.pow(2, 53))).to.equal(false);
|
309 | expect(Number.isSafeInteger(-Math.pow(2, 54))).to.equal(false);
|
310 | });
|
311 |
|
312 | it('should be true when abs(number) is less than 2^53', function () {
|
313 | var safeIntegers = [0, 1, Math.pow(2, 53) - 1];
|
314 | safeIntegers.forEach(function (integer) {
|
315 | expect(Number.isSafeInteger(integer)).to.equal(true);
|
316 | expect(Number.isSafeInteger(-integer)).to.equal(true);
|
317 | });
|
318 | });
|
319 | });
|
320 |
|
321 | describe('.isNaN()', function () {
|
322 | if (!Object.prototype.hasOwnProperty.call(Number, 'isNaN')) {
|
323 | return it('exists', function () {
|
324 | expect(Number).to.have.property('isNaN');
|
325 | });
|
326 | }
|
327 |
|
328 | ifFunctionsHaveNamesIt('has the right name', function () {
|
329 | expect(Number.isNaN).to.have.property('name', 'isNaN');
|
330 | });
|
331 |
|
332 | it('is not enumerable', function () {
|
333 | expect(Number).ownPropertyDescriptor('isNaN').to.have.property('enumerable', false);
|
334 | });
|
335 |
|
336 | it('has the right arity', function () {
|
337 | expect(Number.isNaN).to.have.property('length', 1);
|
338 | });
|
339 |
|
340 | it('should be truthy only on NaN', function () {
|
341 | integers.concat(nonIntegers).map(Number.isNaN).forEach(expectFalse);
|
342 | nonNumbers.map(Number.isNaN).forEach(expectFalse);
|
343 | expect(Number.isNaN(NaN)).to.equal(true);
|
344 | expect(Number.isNaN(0 / 0)).to.equal(true);
|
345 | expect(Number.isNaN(Number('NaN'))).to.equal(true);
|
346 | expect(Number.isNaN(4)).to.equal(false);
|
347 | expect(Number.isNaN(4.5)).to.equal(false);
|
348 | expect(Number.isNaN('hi')).to.equal(false);
|
349 | expect(Number.isNaN('1.3')).to.equal(false);
|
350 | expect(Number.isNaN('51')).to.equal(false);
|
351 | expect(Number.isNaN(0)).to.equal(false);
|
352 | expect(Number.isNaN(-0)).to.equal(false);
|
353 | expect(Number.isNaN(valueOfThree)).to.equal(false);
|
354 | expect(Number.isNaN(valueOfNaN)).to.equal(false);
|
355 | expect(Number.isNaN(valueOfThrows)).to.equal(false);
|
356 | expect(Number.isNaN(toStringThrows)).to.equal(false);
|
357 | expect(Number.isNaN(toPrimitiveThrows)).to.equal(false);
|
358 | });
|
359 | });
|
360 |
|
361 | describe('constructor', function () {
|
362 | it('behaves like the builtin', function () {
|
363 | expect((1).constructor).to.equal(Number);
|
364 | expect(Number()).to.equal(0);
|
365 | });
|
366 |
|
367 | describe('strings in the constructor', function () {
|
368 | it('works on normal literals', function () {
|
369 | expect(Number('1')).to.equal(+'1');
|
370 | expect(Number('1.1')).to.equal(+'1.1');
|
371 | expect(Number('0xA')).to.equal(0xA);
|
372 | });
|
373 | });
|
374 |
|
375 | describe('when called with a receiver', function () {
|
376 | it('returns a primitive when called with a primitive receiver', function () {
|
377 | expect((1).constructor(2)).to.equal(2);
|
378 | expect((1).constructor.call(null, 3)).to.equal(3);
|
379 | expect(Object(1).constructor.call(null, 5)).to.equal(5);
|
380 | });
|
381 |
|
382 | it('returns a primitive when called with a different number as an object receiver', function () {
|
383 | expect(Object(1).constructor(6)).to.equal(6);
|
384 | expect(Object(1).constructor.call(Object(1), 7)).to.equal(7);
|
385 | });
|
386 |
|
387 | it('returns a primitive when called with the same number as an object receiver', function () {
|
388 | expect(Object(1).constructor.call(Object(8), 8)).to.equal(8);
|
389 | });
|
390 | });
|
391 |
|
392 | it('works with boxed primitives', function () {
|
393 | expect(1 instanceof Number).to.equal(false);
|
394 | expect(Object(1) instanceof Number).to.equal(true);
|
395 | });
|
396 |
|
397 | it('works with `new`', function () {
|
398 |
|
399 | var one = new Number('1');
|
400 | var a = new Number('0xA');
|
401 |
|
402 |
|
403 | expect(+one).to.equal(1);
|
404 | expect(one instanceof Number).to.equal(true);
|
405 | expect(+a).to.equal(0xA);
|
406 | expect(a instanceof Number).to.equal(true);
|
407 | });
|
408 |
|
409 | it('works with binary literals in string form', function () {
|
410 | expect(Number('0b1')).to.equal(1);
|
411 | expect(Number(' 0b1')).to.equal(1);
|
412 | expect(Number('0b1 ')).to.equal(1);
|
413 |
|
414 | expect(Number('0b10')).to.equal(2);
|
415 | expect(Number(' 0b10')).to.equal(2);
|
416 | expect(Number('0b10 ')).to.equal(2);
|
417 |
|
418 | expect(Number('0b11')).to.equal(3);
|
419 | expect(Number(' 0b11')).to.equal(3);
|
420 | expect(Number('0b11 ')).to.equal(3);
|
421 |
|
422 | expect(Number({
|
423 | toString: function () { return '0b100'; },
|
424 | valueOf: function () { return '0b101'; }
|
425 | })).to.equal(5);
|
426 | });
|
427 |
|
428 | it('works with octal literals in string form', function () {
|
429 | expect(Number('0o7')).to.equal(7);
|
430 | expect(Number('0o10')).to.equal(8);
|
431 | expect(Number('0o11')).to.equal(9);
|
432 | expect(Number({
|
433 | toString: function () { return '0o12'; },
|
434 | valueOf: function () { return '0o13'; }
|
435 | })).to.equal(11);
|
436 | });
|
437 |
|
438 | it('should produce NaN', function () {
|
439 | expect(String(Number('0b12'))).to.equal('NaN');
|
440 | expect(String(Number('0o18'))).to.equal('NaN');
|
441 | expect(String(Number('0x1g'))).to.equal('NaN');
|
442 | expect(String(Number('+0b1'))).to.equal('NaN');
|
443 | expect(String(Number('+0o1'))).to.equal('NaN');
|
444 | expect(String(Number('+0x1'))).to.equal('NaN');
|
445 | expect(String(Number('-0b1'))).to.equal('NaN');
|
446 | expect(String(Number('-0o1'))).to.equal('NaN');
|
447 | expect(String(Number('-0x1'))).to.equal('NaN');
|
448 | });
|
449 |
|
450 | it('should work with well formed and poorly formed objects', function () {
|
451 | expect(String(Number({}))).to.equal('NaN');
|
452 | expect(String(Number({ valueOf: '1.1' }))).to.equal('NaN');
|
453 | expect(Number({ valueOf: '1.1', toString: function () { return '2.2'; } })).to.equal(2.2);
|
454 | expect(Number({ valueOf: function () { return '1.1'; }, toString: '2.2' })).to.equal(1.1);
|
455 | expect(Number({
|
456 | valueOf: function () { return '1.1'; },
|
457 | toString: function () { return '2.2'; }
|
458 | })).to.equal(1.1);
|
459 | expect(String(Number({ valueOf: function () { return '-0x1a2b3c'; } }))).to.equal('NaN');
|
460 | expect(String(Number({ toString: function () { return '-0x1a2b3c'; } }))).to.equal('NaN');
|
461 | expect(Number({ valueOf: function () { return '0o12345'; } })).to.equal(5349);
|
462 | expect(Number({ toString: function () { return '0o12345'; } })).to.equal(5349);
|
463 | expect(Number({ valueOf: function () { return '0b101010'; } })).to.equal(42);
|
464 | expect(Number({ toString: function () { return '0b101010'; } })).to.equal(42);
|
465 | });
|
466 |
|
467 | it('should work with correct whitespaces', function () {
|
468 |
|
469 | var nonWhitespaces = ['\u0085', '\u200b', '\ufffe'];
|
470 |
|
471 | expect(String(Number(nonWhitespaces[0] + '0' + nonWhitespaces[0]))).to.equal('NaN');
|
472 | expect(String(Number(nonWhitespaces[1] + '1' + nonWhitespaces[1]))).to.equal('NaN');
|
473 | expect(String(Number(nonWhitespaces[2] + '2' + nonWhitespaces[2]))).to.equal('NaN');
|
474 | });
|
475 |
|
476 | it.skip('it works with updated unicode values', function () {
|
477 | 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';
|
478 |
|
479 | expect(String(Number(whitespace + '3' + whitespace))).to.equal('3');
|
480 | });
|
481 | });
|
482 | });
|