Skip to content

Commit

Permalink
Add ES.CheckObjectCoercible checks everywhere. Closes gh-166.
Browse files Browse the repository at this point in the history
  • Loading branch information
paulmillr committed Dec 18, 2013
1 parent 89f589f commit a765855
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 28 deletions.
26 changes: 11 additions & 15 deletions es6-shim.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,7 @@

var ES = {
CheckObjectCoercible: function(x) {
if (x == null) { // `null` or `undefined`
throw TypeError();
}
if (x == null) throw TypeError('Cannot call method on ' + x);
return x;
},

Expand Down Expand Up @@ -137,27 +135,26 @@
};

return function(times) {
var thisStr = String(ES.CheckObjectCoercible(this));
times = ES.toInteger(times);
if (times < 0 || times === Infinity) {
throw new RangeError();
throw new RangeError('Invalid String#repeat value');
}
return repeat(String(ES.CheckObjectCoercible(this)), times);
return repeat(thisStr, times);
};
})(),

startsWith: function(searchStr) {
if (this == null) throw new TypeError("Cannot call method 'startsWith' of " + this);
var thisStr = String(ES.CheckObjectCoercible(this));
if (_toString.call(searchStr) === '[object RegExp]') throw new TypeError('Cannot call method "startsWith" with a regex');
var thisStr = String(this);
searchStr = String(searchStr);
var start = Math.max(ES.toInteger(arguments[1]), 0);
return thisStr.slice(start, start + searchStr.length) === searchStr;
},

endsWith: function(searchStr) {
if (this == null) throw new TypeError("Cannot call method 'endsWith' of " + this);
var thisStr = String(ES.CheckObjectCoercible(this));
if (_toString.call(searchStr) === '[object RegExp]') throw new TypeError('Cannot call method "endsWith" with a regex');
var thisStr = String(this);
searchStr = String(searchStr);
var thisLen = thisStr.length;
var pos = arguments[1] === undefined ? thisLen : ES.toInteger(arguments[1]);
Expand All @@ -167,20 +164,19 @@

contains: function(searchString) {
var position = arguments[1];

// Somehow this trick makes method 100% compat with the spec.
return _indexOf.call(this, searchString, position) !== -1;
},

codePointAt: function(pos) {
var s = String(this);
var thisStr = String(ES.CheckObjectCoercible(this));
var position = ES.toInteger(pos);
var length = s.length;
var length = thisStr.length;
if (position < 0 || position >= length) return undefined;
var first = s.charCodeAt(position);
var first = thisStr.charCodeAt(position);
var isEnd = (position + 1 === length);
if (first < 0xD800 || first > 0xDBFF || isEnd) return first;
var second = s.charCodeAt(position + 1);
var second = thisStr.charCodeAt(position + 1);
if (second < 0xDC00 || second > 0xDFFF) return first;
return ((first - 0xD800) * 1024) + (second - 0xDC00) + 0x10000;
}
Expand All @@ -192,7 +188,7 @@
var thisArg = arguments[2];

if (mapFn !== undefined && _toString.call(mapFn) !== '[object Function]') {
throw new TypeError('when provided, the second argument must be a function');
throw new TypeError('Array.from: when provided, the second argument must be a function');
}

var list = Object(iterable);
Expand Down
2 changes: 1 addition & 1 deletion test/object.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ describe('Object', function() {
describe('Object.setPrototypeOf()', function() {
describe('argument checking', function() {
it('should throw TypeError if first arg is not object', function() {
var nonObjects = [null, true, false, 1, 3, 'foo'];
var nonObjects = [null, undefined, true, false, 1, 3, 'foo'];
nonObjects.forEach(function(value) {
expect(function() { Object.setPrototypeOf(value); }).to.throw(TypeError);
});
Expand Down
46 changes: 34 additions & 12 deletions test/string.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
describe('String', function() {
var testObjectCoercible = function(methodName) {
var fn = String.prototype[methodName];
expect(function() { return fn.call(undefined); }).to.throw(TypeError);
expect(function() { return fn.call(null); }).to.throw(TypeError);
expect(function() { return fn.apply(undefined); }).to.throw(TypeError);
expect(function() { return fn.apply(null); }).to.throw(TypeError);
};
describe('#repeat()', function() {
it('should throw a TypeError when called on null or undefined', function() {
testObjectCoercible('repeat');
});

it('should throw a RangeError when negative or infinite', function() {
expect(function negativeOne() { return 'test'.repeat(-1); }).to.throw(RangeError);
expect(function infinite() { return 'test'.repeat(Infinity); }).to.throw(RangeError);
});
it('should throw a TypeError when called on null or undefined', function() {
expect(function callOnUndefined() { return String.prototype.repeat.call(undefined); }).to.throw(TypeError);
expect(function callOnNull() { return String.prototype.repeat.call(null); }).to.throw(TypeError);
expect(function callOnUndefined() { return String.prototype.repeat.apply(undefined); }).to.throw(TypeError);
expect(function callOnNull() { return String.prototype.repeat.apply(null); }).to.throw(TypeError);
});

it('should coerce to an integer', function() {
expect('test'.repeat(null)).to.eql('');
expect('test'.repeat(false)).to.eql('');
Expand All @@ -22,19 +28,23 @@ describe('String', function() {
it('should work', function() {
expect('test'.repeat(3)).to.eql('testtesttest');
});
it('should work - integer type', function() {
it('should work on integers', function() {
expect(String.prototype.repeat.call(2, 3)).to.eql('222');
});
it('should work - boolean type', function() {
it('should work on booleans', function() {
expect(String.prototype.repeat.call(true, 3)).to.eql('truetruetrue');
});
it('should work - Date type', function() {
it('should work on dates', function() {
var d = new Date();
expect(String.prototype.repeat.call(d, 3)).to.eql([d, d, d].join(''));
});
});

describe('#startsWith()', function() {
it('should throw a TypeError when called on null or undefined', function() {
testObjectCoercible('startsWith');
});

it('should be truthy on correct results', function() {
expect('test'.startsWith('te')).to.be.ok;
expect('test'.startsWith('st')).to.not.be.ok;
Expand Down Expand Up @@ -110,6 +120,10 @@ describe('String', function() {
});

describe('#endsWith()', function() {
it('should throw a TypeError when called on null or undefined', function() {
testObjectCoercible('endsWith');
});

it('should be truthy on correct results', function() {
expect('test'.endsWith('st')).to.be.ok;
expect('test'.endsWith('te')).to.not.be.ok;
Expand Down Expand Up @@ -192,6 +206,10 @@ describe('String', function() {
});

describe('#contains()', function() {
it('should throw a TypeError when called on null or undefined', function() {
testObjectCoercible('contains');
});

it('should be truthy on correct results', function() {
expect('test'.contains('es')).to.be.ok;
expect('abc'.contains('a')).to.be.ok;
Expand Down Expand Up @@ -296,14 +314,18 @@ describe('String', function() {
});

describe('#codePointAt()', function() {
it('works', function() {
it('should throw a TypeError when called on null or undefined', function() {
testObjectCoercible('codePointAt');
});

it('should work', function() {
var str = 'abc';
expect(str.codePointAt(0)).to.equal(97);
expect(str.codePointAt(1)).to.equal(98);
expect(str.codePointAt(2)).to.equal(99);
});

it('works with unicode', function() {
it('should work with unicode', function() {
expect('\u2500'.codePointAt(0)).to.equal(0x2500);
expect('\ud800\udc00'.codePointAt(0)).to.equal(0x10000);
expect('\udbff\udfff'.codePointAt(0)).to.equal(0x10ffff);
Expand All @@ -312,7 +334,7 @@ describe('String', function() {
expect('\ud800\udc00\udbff\udfff'.codePointAt(2)).to.equal(0x10ffff);
});

it('returns undefined when pos is negative or too large', function() {
it('should return undefined when pos is negative or too large', function() {
var str = 'abc';
expect(str.codePointAt(-1)).to.be.undefined;
expect(str.codePointAt(str.length)).to.be.undefined;
Expand Down

0 comments on commit a765855

Please sign in to comment.