482 lines
18 KiB
JavaScript
482 lines
18 KiB
JavaScript
describe('Number', function () {
|
|
var functionsHaveNames = (function foo() {}).name === 'foo';
|
|
var ifFunctionsHaveNamesIt = functionsHaveNames ? it : xit;
|
|
var ifShimIt = (typeof process !== 'undefined' && process.env.NO_ES6_SHIM) ? it.skip : it;
|
|
|
|
var integers = [5295, -5295, -9007199254740991, 9007199254740991, 0, -0];
|
|
var nonIntegers = [-9007199254741992, 9007199254741992, 5.9];
|
|
var infinities = [Infinity, -Infinity];
|
|
|
|
var valueOfThree = { valueOf: function () { return 3; } };
|
|
var valueOfNaN = { valueOf: function () { return NaN; } };
|
|
var valueOfThrows = { valueOf: function () { throw Object(17); } };
|
|
var toStringThrows = { toString: function () { throw Object(42); } };
|
|
var toPrimitiveThrows = {
|
|
valueOf: function () { throw Object(17); },
|
|
toString: function () { throw Object(42); }
|
|
};
|
|
|
|
var nonNumbers = [
|
|
undefined,
|
|
true,
|
|
false,
|
|
null,
|
|
{},
|
|
[],
|
|
'str',
|
|
'',
|
|
valueOfThree,
|
|
valueOfNaN,
|
|
valueOfThrows,
|
|
toStringThrows,
|
|
toPrimitiveThrows,
|
|
/a/g
|
|
];
|
|
var expectTrue = function (item) {
|
|
expect(item).to.equal(true);
|
|
};
|
|
var expectFalse = function (item) {
|
|
expect(item).to.equal(false);
|
|
};
|
|
|
|
ifShimIt('is on the exported object', function () {
|
|
var exported = require('../');
|
|
expect(exported.Number).to.equal(Number);
|
|
});
|
|
|
|
describe('Number constants', function () {
|
|
it('should have max safe integer', function () {
|
|
expect(Number).to.have.property('MAX_SAFE_INTEGER');
|
|
expect(Object.prototype.propertyIsEnumerable.call(Number, 'MAX_SAFE_INTEGER')).to.equal(false);
|
|
expect(Number.MAX_SAFE_INTEGER).to.equal(Math.pow(2, 53) - 1);
|
|
});
|
|
|
|
it('should have min safe integer', function () {
|
|
expect(Number).to.have.property('MIN_SAFE_INTEGER');
|
|
expect(Object.prototype.propertyIsEnumerable.call(Number, 'MIN_SAFE_INTEGER')).to.equal(false);
|
|
expect(Number.MIN_SAFE_INTEGER).to.equal(-Math.pow(2, 53) + 1);
|
|
});
|
|
|
|
it('should have epsilon', function () {
|
|
expect(Number).to.have.property('EPSILON');
|
|
expect(Object.prototype.propertyIsEnumerable.call(Number, 'EPSILON')).to.equal(false);
|
|
expect(Number.EPSILON).to.equal(2.2204460492503130808472633361816e-16);
|
|
});
|
|
|
|
it('should have NaN', function () {
|
|
expect(Number).to.have.property('NaN');
|
|
expect(Object.prototype.propertyIsEnumerable.call(Number, 'NaN')).to.equal(false);
|
|
expect(isNaN(Number.NaN)).to.equal(true);
|
|
});
|
|
|
|
it('should have MAX_VALUE', function () {
|
|
expect(Number).to.have.property('MAX_VALUE');
|
|
expect(Object.prototype.propertyIsEnumerable.call(Number, 'MAX_VALUE')).to.equal(false);
|
|
expect(Number.MAX_VALUE).to.equal(1.7976931348623157e+308);
|
|
});
|
|
|
|
it('should have MIN_VALUE', function () {
|
|
expect(Number).to.have.property('MIN_VALUE');
|
|
expect(Object.prototype.propertyIsEnumerable.call(Number, 'MIN_VALUE')).to.equal(false);
|
|
expect(Number.MIN_VALUE).to.equal(5e-324);
|
|
});
|
|
|
|
it('should have NEGATIVE_INFINITY', function () {
|
|
expect(Number).to.have.property('NEGATIVE_INFINITY');
|
|
expect(Object.prototype.propertyIsEnumerable.call(Number, 'NEGATIVE_INFINITY')).to.equal(false);
|
|
expect(Number.NEGATIVE_INFINITY).to.equal(-Infinity);
|
|
});
|
|
|
|
it('should have POSITIVE_INFINITY', function () {
|
|
expect(Number).to.have.property('POSITIVE_INFINITY');
|
|
expect(Object.prototype.propertyIsEnumerable.call(Number, 'POSITIVE_INFINITY')).to.equal(false);
|
|
expect(Number.POSITIVE_INFINITY).to.equal(Infinity);
|
|
});
|
|
});
|
|
|
|
describe('.parseInt()', function () {
|
|
if (!Object.prototype.hasOwnProperty.call(Number, 'parseInt')) {
|
|
return it('exists', function () {
|
|
expect(Number).to.have.property('parseInt');
|
|
});
|
|
}
|
|
|
|
it('should work', function () {
|
|
/* eslint-disable radix */
|
|
expect(Number.parseInt('601')).to.equal(601);
|
|
/* eslint-enable radix */
|
|
});
|
|
|
|
ifFunctionsHaveNamesIt('has the right name', function () {
|
|
expect(Number.parseInt).to.have.property('name', 'parseInt');
|
|
});
|
|
|
|
it('is not enumerable', function () {
|
|
expect(Number).ownPropertyDescriptor('parseInt').to.have.property('enumerable', false);
|
|
});
|
|
|
|
it('has the right arity', function () {
|
|
// WebKit nightly had the wrong length; fixed in https://bugs.webkit.org/show_bug.cgi?id=143657
|
|
expect(Number.parseInt).to.have.property('length', 2);
|
|
});
|
|
|
|
it('is the same object as the global parseInt', function () {
|
|
// fixed in WebKit nightly in https://bugs.webkit.org/show_bug.cgi?id=143799#add_comment
|
|
expect(Number.parseInt).to.equal(parseInt);
|
|
});
|
|
});
|
|
|
|
describe('.parseFloat()', function () {
|
|
if (!Object.prototype.hasOwnProperty.call(Number, 'parseFloat')) {
|
|
return it('exists', function () {
|
|
expect(Number).to.have.property('parseFloat');
|
|
});
|
|
}
|
|
|
|
it('should work', function () {
|
|
expect(Number.parseFloat('5.5')).to.equal(5.5);
|
|
});
|
|
|
|
ifFunctionsHaveNamesIt('has the right name', function () {
|
|
expect(Number.parseFloat).to.have.property('name', 'parseFloat');
|
|
});
|
|
|
|
it('is not enumerable', function () {
|
|
expect(Number).ownPropertyDescriptor('parseFloat').to.have.property('enumerable', false);
|
|
});
|
|
|
|
it('has the right arity', function () {
|
|
expect(Number.parseFloat).to.have.property('length', 1);
|
|
});
|
|
});
|
|
|
|
describe('.isFinite()', function () {
|
|
if (!Object.prototype.hasOwnProperty.call(Number, 'isFinite')) {
|
|
return it('exists', function () {
|
|
expect(Number).to.have.property('isFinite');
|
|
});
|
|
}
|
|
|
|
ifFunctionsHaveNamesIt('has the right name', function () {
|
|
expect(Number.isFinite).to.have.property('name', 'isFinite');
|
|
});
|
|
|
|
it('is not enumerable', function () {
|
|
expect(Number).ownPropertyDescriptor('isFinite').to.have.property('enumerable', false);
|
|
});
|
|
|
|
it('has the right arity', function () {
|
|
expect(Number.isFinite).to.have.property('length', 1);
|
|
});
|
|
|
|
it('should work', function () {
|
|
integers.map(Number.isFinite).forEach(expectTrue);
|
|
infinities.map(Number.isFinite).forEach(expectFalse);
|
|
expect(Number.isFinite(Infinity)).to.equal(false);
|
|
expect(Number.isFinite(-Infinity)).to.equal(false);
|
|
expect(Number.isFinite(NaN)).to.equal(false);
|
|
expect(Number.isFinite(4)).to.equal(true);
|
|
expect(Number.isFinite(4.5)).to.equal(true);
|
|
expect(Number.isFinite('hi')).to.equal(false);
|
|
expect(Number.isFinite('1.3')).to.equal(false);
|
|
expect(Number.isFinite('51')).to.equal(false);
|
|
expect(Number.isFinite(0)).to.equal(true);
|
|
expect(Number.isFinite(-0)).to.equal(true);
|
|
expect(Number.isFinite(valueOfThree)).to.equal(false);
|
|
expect(Number.isFinite(valueOfNaN)).to.equal(false);
|
|
expect(Number.isFinite(valueOfThrows)).to.equal(false);
|
|
expect(Number.isFinite(toStringThrows)).to.equal(false);
|
|
expect(Number.isFinite(toPrimitiveThrows)).to.equal(false);
|
|
});
|
|
|
|
it('should not be confused by type coercion', function () {
|
|
nonNumbers.map(Number.isFinite).forEach(expectFalse);
|
|
});
|
|
});
|
|
|
|
describe('.isInteger()', function () {
|
|
if (!Object.prototype.hasOwnProperty.call(Number, 'isInteger')) {
|
|
return it('exists', function () {
|
|
expect(Number).to.have.property('isInteger');
|
|
});
|
|
}
|
|
|
|
ifFunctionsHaveNamesIt('has the right name', function () {
|
|
expect(Number.isInteger).to.have.property('name', 'isInteger');
|
|
});
|
|
|
|
it('is not enumerable', function () {
|
|
expect(Number).ownPropertyDescriptor('isInteger').to.have.property('enumerable', false);
|
|
});
|
|
|
|
it('has the right arity', function () {
|
|
expect(Number.isInteger).to.have.property('length', 1);
|
|
});
|
|
|
|
it('should be truthy on integers', function () {
|
|
integers.map(Number.isInteger).forEach(expectTrue);
|
|
expect(Number.isInteger(4)).to.equal(true);
|
|
expect(Number.isInteger(4.0)).to.equal(true);
|
|
expect(Number.isInteger(1801439850948)).to.equal(true);
|
|
});
|
|
|
|
it('should be false when the type is not number', function () {
|
|
nonNumbers.forEach(function (thing) {
|
|
expect(Number.isInteger(thing)).to.equal(false);
|
|
});
|
|
});
|
|
|
|
it('should be false when NaN', function () {
|
|
expect(Number.isInteger(NaN)).to.equal(false);
|
|
});
|
|
|
|
it('should be false when ∞', function () {
|
|
expect(Number.isInteger(Infinity)).to.equal(false);
|
|
expect(Number.isInteger(-Infinity)).to.equal(false);
|
|
});
|
|
|
|
it('should be false when number is not integer', function () {
|
|
expect(Number.isInteger(3.4)).to.equal(false);
|
|
expect(Number.isInteger(-3.4)).to.equal(false);
|
|
});
|
|
|
|
it('should be true when abs(number) is 2^53 or larger', function () {
|
|
expect(Number.isInteger(Math.pow(2, 53))).to.equal(true);
|
|
expect(Number.isInteger(Math.pow(2, 54))).to.equal(true);
|
|
expect(Number.isInteger(-Math.pow(2, 53))).to.equal(true);
|
|
expect(Number.isInteger(-Math.pow(2, 54))).to.equal(true);
|
|
});
|
|
|
|
it('should be true when abs(number) is less than 2^53', function () {
|
|
var safeIntegers = [0, 1, Math.pow(2, 53) - 1];
|
|
safeIntegers.forEach(function (integer) {
|
|
expect(Number.isInteger(integer)).to.equal(true);
|
|
expect(Number.isInteger(-integer)).to.equal(true);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('.isSafeInteger()', function () {
|
|
if (!Object.prototype.hasOwnProperty.call(Number, 'isSafeInteger')) {
|
|
return it('exists', function () {
|
|
expect(Number).to.have.property('isSafeInteger');
|
|
});
|
|
}
|
|
|
|
ifFunctionsHaveNamesIt('has the right name', function () {
|
|
expect(Number.isSafeInteger).to.have.property('name', 'isSafeInteger');
|
|
});
|
|
|
|
it('is not enumerable', function () {
|
|
expect(Number).ownPropertyDescriptor('isSafeInteger').to.have.property('enumerable', false);
|
|
});
|
|
|
|
it('has the right arity', function () {
|
|
expect(Number.isSafeInteger).to.have.property('length', 1);
|
|
});
|
|
|
|
it('should be truthy on integers', function () {
|
|
integers.map(Number.isSafeInteger).forEach(expectTrue);
|
|
expect(Number.isSafeInteger(4)).to.equal(true);
|
|
expect(Number.isSafeInteger(4.0)).to.equal(true);
|
|
expect(Number.isSafeInteger(1801439850948)).to.equal(true);
|
|
});
|
|
|
|
it('should be false when the type is not number', function () {
|
|
nonNumbers.forEach(function (thing) {
|
|
expect(Number.isSafeInteger(thing)).to.equal(false);
|
|
});
|
|
});
|
|
|
|
it('should be false when NaN', function () {
|
|
expect(Number.isSafeInteger(NaN)).to.equal(false);
|
|
});
|
|
|
|
it('should be false when ∞', function () {
|
|
expect(Number.isSafeInteger(Infinity)).to.equal(false);
|
|
expect(Number.isSafeInteger(-Infinity)).to.equal(false);
|
|
});
|
|
|
|
it('should be false when number is not integer', function () {
|
|
expect(Number.isSafeInteger(3.4)).to.equal(false);
|
|
expect(Number.isSafeInteger(-3.4)).to.equal(false);
|
|
});
|
|
|
|
it('should be false when abs(number) is 2^53 or larger', function () {
|
|
expect(Number.isSafeInteger(Math.pow(2, 53))).to.equal(false);
|
|
expect(Number.isSafeInteger(Math.pow(2, 54))).to.equal(false);
|
|
expect(Number.isSafeInteger(-Math.pow(2, 53))).to.equal(false);
|
|
expect(Number.isSafeInteger(-Math.pow(2, 54))).to.equal(false);
|
|
});
|
|
|
|
it('should be true when abs(number) is less than 2^53', function () {
|
|
var safeIntegers = [0, 1, Math.pow(2, 53) - 1];
|
|
safeIntegers.forEach(function (integer) {
|
|
expect(Number.isSafeInteger(integer)).to.equal(true);
|
|
expect(Number.isSafeInteger(-integer)).to.equal(true);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('.isNaN()', function () {
|
|
if (!Object.prototype.hasOwnProperty.call(Number, 'isNaN')) {
|
|
return it('exists', function () {
|
|
expect(Number).to.have.property('isNaN');
|
|
});
|
|
}
|
|
|
|
ifFunctionsHaveNamesIt('has the right name', function () {
|
|
expect(Number.isNaN).to.have.property('name', 'isNaN');
|
|
});
|
|
|
|
it('is not enumerable', function () {
|
|
expect(Number).ownPropertyDescriptor('isNaN').to.have.property('enumerable', false);
|
|
});
|
|
|
|
it('has the right arity', function () {
|
|
expect(Number.isNaN).to.have.property('length', 1);
|
|
});
|
|
|
|
it('should be truthy only on NaN', function () {
|
|
integers.concat(nonIntegers).map(Number.isNaN).forEach(expectFalse);
|
|
nonNumbers.map(Number.isNaN).forEach(expectFalse);
|
|
expect(Number.isNaN(NaN)).to.equal(true);
|
|
expect(Number.isNaN(0 / 0)).to.equal(true);
|
|
expect(Number.isNaN(Number('NaN'))).to.equal(true);
|
|
expect(Number.isNaN(4)).to.equal(false);
|
|
expect(Number.isNaN(4.5)).to.equal(false);
|
|
expect(Number.isNaN('hi')).to.equal(false);
|
|
expect(Number.isNaN('1.3')).to.equal(false);
|
|
expect(Number.isNaN('51')).to.equal(false);
|
|
expect(Number.isNaN(0)).to.equal(false);
|
|
expect(Number.isNaN(-0)).to.equal(false);
|
|
expect(Number.isNaN(valueOfThree)).to.equal(false);
|
|
expect(Number.isNaN(valueOfNaN)).to.equal(false);
|
|
expect(Number.isNaN(valueOfThrows)).to.equal(false);
|
|
expect(Number.isNaN(toStringThrows)).to.equal(false);
|
|
expect(Number.isNaN(toPrimitiveThrows)).to.equal(false);
|
|
});
|
|
});
|
|
|
|
describe('constructor', function () {
|
|
it('behaves like the builtin', function () {
|
|
expect((1).constructor).to.equal(Number);
|
|
expect(Number()).to.equal(0);
|
|
});
|
|
|
|
describe('strings in the constructor', function () {
|
|
it('works on normal literals', function () {
|
|
expect(Number('1')).to.equal(+'1');
|
|
expect(Number('1.1')).to.equal(+'1.1');
|
|
expect(Number('0xA')).to.equal(0xA);
|
|
});
|
|
});
|
|
|
|
describe('when called with a receiver', function () {
|
|
it('returns a primitive when called with a primitive receiver', function () {
|
|
expect((1).constructor(2)).to.equal(2);
|
|
expect((1).constructor.call(null, 3)).to.equal(3);
|
|
expect(Object(1).constructor.call(null, 5)).to.equal(5);
|
|
});
|
|
|
|
it('returns a primitive when called with a different number as an object receiver', function () {
|
|
expect(Object(1).constructor(6)).to.equal(6);
|
|
expect(Object(1).constructor.call(Object(1), 7)).to.equal(7);
|
|
});
|
|
|
|
it('returns a primitive when called with the same number as an object receiver', function () {
|
|
expect(Object(1).constructor.call(Object(8), 8)).to.equal(8);
|
|
});
|
|
});
|
|
|
|
it('works with boxed primitives', function () {
|
|
expect(1 instanceof Number).to.equal(false);
|
|
expect(Object(1) instanceof Number).to.equal(true);
|
|
});
|
|
|
|
it('works with `new`', function () {
|
|
/* jshint -W053 */
|
|
/* eslint-disable no-new-wrappers */
|
|
var one = new Number('1');
|
|
var a = new Number('0xA');
|
|
/* eslint-enable no-new-wrappers */
|
|
/* jshint +W053 */
|
|
|
|
expect(+one).to.equal(1);
|
|
expect(one instanceof Number).to.equal(true);
|
|
expect(+a).to.equal(0xA);
|
|
expect(a instanceof Number).to.equal(true);
|
|
});
|
|
|
|
it('works with binary literals in string form', function () {
|
|
expect(Number('0b1')).to.equal(1);
|
|
expect(Number(' 0b1')).to.equal(1);
|
|
expect(Number('0b1 ')).to.equal(1);
|
|
|
|
expect(Number('0b10')).to.equal(2);
|
|
expect(Number(' 0b10')).to.equal(2);
|
|
expect(Number('0b10 ')).to.equal(2);
|
|
|
|
expect(Number('0b11')).to.equal(3);
|
|
expect(Number(' 0b11')).to.equal(3);
|
|
expect(Number('0b11 ')).to.equal(3);
|
|
|
|
expect(Number({
|
|
toString: function () { return '0b100'; },
|
|
valueOf: function () { return '0b101'; }
|
|
})).to.equal(5);
|
|
});
|
|
|
|
it('works with octal literals in string form', function () {
|
|
expect(Number('0o7')).to.equal(7);
|
|
expect(Number('0o10')).to.equal(8);
|
|
expect(Number('0o11')).to.equal(9);
|
|
expect(Number({
|
|
toString: function () { return '0o12'; },
|
|
valueOf: function () { return '0o13'; }
|
|
})).to.equal(11);
|
|
});
|
|
|
|
it('should produce NaN', function () {
|
|
expect(String(Number('0b12'))).to.equal('NaN');
|
|
expect(String(Number('0o18'))).to.equal('NaN');
|
|
expect(String(Number('0x1g'))).to.equal('NaN');
|
|
expect(String(Number('+0b1'))).to.equal('NaN');
|
|
expect(String(Number('+0o1'))).to.equal('NaN');
|
|
expect(String(Number('+0x1'))).to.equal('NaN');
|
|
expect(String(Number('-0b1'))).to.equal('NaN');
|
|
expect(String(Number('-0o1'))).to.equal('NaN');
|
|
expect(String(Number('-0x1'))).to.equal('NaN');
|
|
});
|
|
|
|
it('should work with well formed and poorly formed objects', function () {
|
|
expect(String(Number({}))).to.equal('NaN');
|
|
expect(String(Number({ valueOf: '1.1' }))).to.equal('NaN');
|
|
expect(Number({ valueOf: '1.1', toString: function () { return '2.2'; } })).to.equal(2.2);
|
|
expect(Number({ valueOf: function () { return '1.1'; }, toString: '2.2' })).to.equal(1.1);
|
|
expect(Number({
|
|
valueOf: function () { return '1.1'; },
|
|
toString: function () { return '2.2'; }
|
|
})).to.equal(1.1);
|
|
expect(String(Number({ valueOf: function () { return '-0x1a2b3c'; } }))).to.equal('NaN');
|
|
expect(String(Number({ toString: function () { return '-0x1a2b3c'; } }))).to.equal('NaN');
|
|
expect(Number({ valueOf: function () { return '0o12345'; } })).to.equal(5349);
|
|
expect(Number({ toString: function () { return '0o12345'; } })).to.equal(5349);
|
|
expect(Number({ valueOf: function () { return '0b101010'; } })).to.equal(42);
|
|
expect(Number({ toString: function () { return '0b101010'; } })).to.equal(42);
|
|
});
|
|
|
|
it('should work with correct whitespaces', function () {
|
|
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';
|
|
|
|
// Zero-width space (zws), next line character (nel), and non-character (bom) are not whitespace.
|
|
var nonWhitespaces = ['\u0085', '\u200b', '\ufffe'];
|
|
|
|
expect(String(Number(nonWhitespaces[0] + '0' + nonWhitespaces[0]))).to.equal('NaN');
|
|
expect(String(Number(nonWhitespaces[1] + '1' + nonWhitespaces[1]))).to.equal('NaN');
|
|
expect(String(Number(nonWhitespaces[2] + '2' + nonWhitespaces[2]))).to.equal('NaN');
|
|
expect(String(Number(whitespace + '3' + whitespace))).to.equal('3');
|
|
});
|
|
});
|
|
});
|