UNPKG

15.1 kBJavaScriptView Raw
1var getRegexLiteral = function (stringRegex) {
2 try {
3 /* eslint-disable no-new-func */
4 return Function('return ' + stringRegex + ';')();
5 /* eslint-enable no-new-func */
6 } catch (e) { /**/ }
7};
8var describeIfSupportsDescriptors = Object.getOwnPropertyDescriptor ? describe : describe.skip;
9var callAllowsPrimitives = (function () { return this === 3; }.call(3));
10var ifCallAllowsPrimitivesIt = callAllowsPrimitives ? it : it.skip;
11var ifShimIt = (typeof process !== 'undefined' && process.env.NO_ES6_SHIM) ? it.skip : it;
12var hasSymbols = typeof Symbol === 'function' && typeof Symbol['for'] === 'function' && typeof Symbol('') === 'symbol';
13var ifSymbolsDescribe = hasSymbols ? describe : describe.skip;
14var defaultRegex = (function () {
15 // Chrome Canary 51 has an undefined RegExp#toSource, and
16 // RegExp#toString produces `/undefined/`
17 try {
18 return RegExp.prototype.source ? String(RegExp.prototype) : '/(?:)/';
19 } catch (e) {
20 return '/(?:)/';
21 }
22}());
23
24describe('RegExp', function () {
25 ifShimIt('is on the exported object', function () {
26 var exported = require('../');
27 expect(exported.RegExp).to.equal(RegExp);
28 });
29
30 it('can be called with no arguments', function () {
31 var regex = RegExp();
32 expect(String(regex)).to.equal(defaultRegex);
33 expect(regex).to.be.an.instanceOf(RegExp);
34 });
35
36 it('can be called with null/undefined', function () {
37 expect(String(RegExp(null))).to.equal('/null/');
38 expect(String(RegExp(undefined))).to.equal(defaultRegex);
39 });
40
41 describe('constructor', function () {
42 it('allows a regex as the pattern', function () {
43 var a = /a/g;
44 var b = new RegExp(a);
45 if (typeof a !== 'function') {
46 // in browsers like Safari 5, new RegExp with a regex returns the same instance.
47 expect(a).not.to.equal(b);
48 }
49 expect(a).to.eql(b);
50 });
51
52 it('allows a string with flags', function () {
53 expect(new RegExp('a', 'mgi')).to.eql(/a/gim);
54 expect(String(new RegExp('a', 'mgi'))).to.equal('/a/gim');
55 });
56
57 it('allows a regex with flags', function () {
58 var a = /a/g;
59 var makeRegex = function () { return new RegExp(a, 'mi'); };
60 expect(makeRegex).not.to['throw'](TypeError);
61 expect(makeRegex()).to.eql(/a/mi);
62 expect(String(makeRegex())).to.equal('/a/im');
63 });
64
65 it('works with instanceof', function () {
66 expect(/a/g).to.be.an.instanceOf(RegExp);
67 expect(new RegExp('a', 'im')).to.be.an.instanceOf(RegExp);
68 expect(new RegExp(/a/g, 'im')).to.be.an.instanceOf(RegExp);
69 });
70
71 it('has the right constructor', function () {
72 expect(/a/g).to.have.property('constructor', RegExp);
73 expect(new RegExp('a', 'im')).to.have.property('constructor', RegExp);
74 expect(new RegExp(/a/g, 'im')).to.have.property('constructor', RegExp);
75 });
76
77 it('toStrings properly', function () {
78 expect(Object.prototype.toString.call(/a/g)).to.equal('[object RegExp]');
79 expect(Object.prototype.toString.call(new RegExp('a', 'g'))).to.equal('[object RegExp]');
80 expect(Object.prototype.toString.call(new RegExp(/a/g, 'im'))).to.equal('[object RegExp]');
81 });
82
83 it('functions as a boxed primitive wrapper', function () {
84 var regex = /a/g;
85 expect(RegExp(regex)).to.equal(regex);
86 });
87
88 ifSymbolsDescribe('Symbol.replace', function () {
89 if (!hasSymbols || typeof Symbol.replace === 'undefined') {
90 return;
91 }
92
93 it('is a function', function () {
94 expect(RegExp.prototype).to.have.property(Symbol.replace);
95 expect(typeof RegExp.prototype[Symbol.replace]).to.equal('function');
96 });
97
98 it('is the same as String#replace', function () {
99 var regex = /a/g;
100 var str = 'abc';
101 var symbolReplace = regex[Symbol.replace](str);
102 var stringReplace = str.replace(regex);
103 expect(Object.keys(symbolReplace)).to.eql(Object.keys(stringReplace));
104 expect(symbolReplace).to.eql(stringReplace);
105 });
106 });
107
108 ifSymbolsDescribe('Symbol.search', function () {
109 if (!hasSymbols || typeof Symbol.search === 'undefined') {
110 return;
111 }
112
113 it('is a function', function () {
114 expect(RegExp.prototype).to.have.property(Symbol.search);
115 expect(typeof RegExp.prototype[Symbol.search]).to.equal('function');
116 });
117
118 it('is the same as String#search', function () {
119 var regex = /a/g;
120 var str = 'abc';
121 var symbolSearch = regex[Symbol.search](str);
122 var stringSearch = str.search(regex);
123 expect(Object.keys(symbolSearch)).to.eql(Object.keys(stringSearch));
124 expect(symbolSearch).to.eql(stringSearch);
125 });
126 });
127
128 ifSymbolsDescribe('Symbol.split', function () {
129 if (!hasSymbols || typeof Symbol.split === 'undefined') {
130 return;
131 }
132
133 it('is a function', function () {
134 expect(RegExp.prototype).to.have.property(Symbol.split);
135 expect(typeof RegExp.prototype[Symbol.split]).to.equal('function');
136 });
137
138 it('is the same as String#split', function () {
139 var regex = /a/g;
140 var str = 'abcabc';
141 var symbolSplit = regex[Symbol.split](str, 1);
142 var stringSplit = str.split(regex, 1);
143 expect(Object.keys(symbolSplit)).to.eql(Object.keys(stringSplit));
144 expect(symbolSplit).to.eql(stringSplit);
145 });
146 });
147
148 ifSymbolsDescribe('Symbol.match', function () {
149 if (!hasSymbols || typeof Symbol.match === 'undefined') {
150 return;
151 }
152
153 var regexFalsyMatch;
154 var nonregexTruthyMatch;
155
156 beforeEach(function () {
157 regexFalsyMatch = /./;
158 regexFalsyMatch[Symbol.match] = false;
159 nonregexTruthyMatch = { constructor: RegExp };
160 nonregexTruthyMatch[Symbol.match] = true;
161 });
162
163 it('is a function', function () {
164 expect(RegExp.prototype).to.have.property(Symbol.match);
165 expect(typeof RegExp.prototype[Symbol.match]).to.equal('function');
166 });
167
168 it('is the same as String#match', function () {
169 var regex = /a/g;
170 var str = 'abc';
171 var symbolMatch = regex[Symbol.match](str);
172 var stringMatch = str.match(regex);
173 expect(Object.keys(symbolMatch)).to.eql(Object.keys(stringMatch));
174 expect(symbolMatch).to.eql(stringMatch);
175 });
176
177 it('function does not passthrough regexes with a falsy Symbol.match', function () {
178 expect(RegExp(regexFalsyMatch)).not.to.equal(regexFalsyMatch);
179 });
180
181 it('constructor does not passthrough regexes with a falsy Symbol.match', function () {
182 expect(new RegExp(regexFalsyMatch)).not.to.equal(regexFalsyMatch);
183 });
184
185 it('function passes through non-regexes with a truthy Symbol.match', function () {
186 expect(RegExp(nonregexTruthyMatch)).to.equal(nonregexTruthyMatch);
187 });
188
189 it('constructor does not pass through non-regexes with a truthy Symbol.match', function () {
190 expect(new RegExp(nonregexTruthyMatch)).not.to.equal(nonregexTruthyMatch);
191 });
192 });
193 });
194
195 describeIfSupportsDescriptors('#flags', function () {
196 if (!Object.prototype.hasOwnProperty.call(RegExp.prototype, 'flags')) {
197 return it('exists', function () {
198 expect(RegExp.prototype).to.have.property('flags');
199 });
200 }
201
202 var regexpFlagsDescriptor = Object.getOwnPropertyDescriptor(RegExp.prototype, 'flags');
203 var testGenericRegExpFlags = function (object) {
204 return regexpFlagsDescriptor.get.call(object);
205 };
206
207 it('has the correct descriptor', function () {
208 expect(regexpFlagsDescriptor.configurable).to.equal(true);
209 expect(regexpFlagsDescriptor.enumerable).to.equal(false);
210 expect(regexpFlagsDescriptor.get instanceof Function).to.equal(true);
211 expect(regexpFlagsDescriptor.set).to.equal(undefined);
212 });
213
214 ifCallAllowsPrimitivesIt('throws when not called on an object', function () {
215 var nonObjects = ['', false, true, 42, NaN, null, undefined];
216 nonObjects.forEach(function (nonObject) {
217 expect(function () { testGenericRegExpFlags(nonObject); }).to['throw'](TypeError);
218 });
219 });
220
221 it('has the correct flags on a literal', function () {
222 expect((/a/g).flags).to.equal('g');
223 expect((/a/i).flags).to.equal('i');
224 expect((/a/m).flags).to.equal('m');
225 if (Object.prototype.hasOwnProperty.call(RegExp.prototype, 'sticky')) {
226 expect(getRegexLiteral('/a/y').flags).to.equal('y');
227 }
228 if (Object.prototype.hasOwnProperty.call(RegExp.prototype, 'unicode')) {
229 expect(getRegexLiteral('/a/u').flags).to.equal('u');
230 }
231 });
232
233 it('has the correct flags on a constructed RegExp', function () {
234 expect(new RegExp('a', 'g').flags).to.equal('g');
235 expect(new RegExp('a', 'i').flags).to.equal('i');
236 expect(new RegExp('a', 'm').flags).to.equal('m');
237 if (Object.prototype.hasOwnProperty.call(RegExp.prototype, 'sticky')) {
238 expect(new RegExp('a', 'y').flags).to.equal('y');
239 }
240 if (Object.prototype.hasOwnProperty.call(RegExp.prototype, 'unicode')) {
241 expect(new RegExp('a', 'u').flags).to.equal('u');
242 }
243 });
244
245 it('returns flags sorted on a literal', function () {
246 expect((/a/gim).flags).to.equal('gim');
247 expect((/a/mig).flags).to.equal('gim');
248 expect((/a/mgi).flags).to.equal('gim');
249 if (Object.prototype.hasOwnProperty.call(RegExp.prototype, 'sticky')) {
250 expect(getRegexLiteral('/a/gyim').flags).to.equal('gimy');
251 }
252 if (Object.prototype.hasOwnProperty.call(RegExp.prototype, 'unicode')) {
253 expect(getRegexLiteral('/a/ugmi').flags).to.equal('gimu');
254 }
255 });
256
257 it('returns flags sorted on a constructed RegExp', function () {
258 expect(new RegExp('a', 'gim').flags).to.equal('gim');
259 expect(new RegExp('a', 'mig').flags).to.equal('gim');
260 expect(new RegExp('a', 'mgi').flags).to.equal('gim');
261 if (Object.prototype.hasOwnProperty.call(RegExp.prototype, 'sticky')) {
262 expect(new RegExp('a', 'mygi').flags).to.equal('gimy');
263 }
264 if (Object.prototype.hasOwnProperty.call(RegExp.prototype, 'unicode')) {
265 expect(new RegExp('a', 'mugi').flags).to.equal('gimu');
266 }
267 });
268 });
269
270 describe('#toString()', function () {
271 it('throws on null/undefined', function () {
272 expect(function () { RegExp.prototype.toString.call(null); }).to['throw'](TypeError);
273 expect(function () { RegExp.prototype.toString.call(undefined); }).to['throw'](TypeError);
274 });
275
276 it('has an undefined prototype', function () {
277 expect(RegExp.prototype.toString.prototype).to.equal(undefined);
278 });
279
280 it('works on regexes', function () {
281 expect(RegExp.prototype.toString.call(/a/g)).to.equal('/a/g');
282 expect(RegExp.prototype.toString.call(new RegExp('a', 'g'))).to.equal('/a/g');
283 });
284
285 it('works on non-regexes', function () {
286 expect(RegExp.prototype.toString.call({ source: 'abc', flags: '' })).to.equal('/abc/');
287 expect(RegExp.prototype.toString.call({ source: 'abc', flags: 'xyz' })).to.equal('/abc/xyz');
288 });
289
290 ifSymbolsDescribe('Symbol.match', function () {
291 if (!hasSymbols || typeof Symbol.match === 'undefined') {
292 return;
293 }
294
295 it('accepts a non-regex with Symbol.match', function () {
296 var obj = { source: 'abc', flags: 'def' };
297 obj[Symbol.match] = RegExp.prototype[Symbol.match];
298 expect(RegExp.prototype.toString.call(obj)).to.equal('/abc/def');
299 });
300 });
301 });
302
303 describe('Object properties', function () {
304 it('does not have the nonstandard $input property', function () {
305 expect(RegExp).not.to.have.property('$input'); // Chrome < 39, Opera < 26 have this
306 });
307
308 it('has "input" property', function () {
309 expect(RegExp).to.have.ownProperty('input');
310 expect(RegExp).to.have.ownProperty('$_');
311 });
312
313 it('has "last match" property', function () {
314 expect(RegExp).to.have.ownProperty('lastMatch');
315 expect(RegExp).to.have.ownProperty('$+');
316 });
317
318 it('has "last paren" property', function () {
319 expect(RegExp).to.have.ownProperty('lastParen');
320 expect(RegExp).to.have.ownProperty('$&');
321 });
322
323 it('has "leftContext" property', function () {
324 expect(RegExp).to.have.ownProperty('leftContext');
325 expect(RegExp).to.have.ownProperty('$`');
326 });
327
328 it('has "rightContext" property', function () {
329 expect(RegExp).to.have.ownProperty('rightContext');
330 expect(RegExp).to.have.ownProperty("$'");
331 });
332
333 it.skip('has "multiline" property', function () {
334 // fails in IE 9, 10, 11
335 expect(RegExp).to.have.ownProperty('multiline');
336 expect(RegExp).to.have.ownProperty('$*');
337 });
338
339 it('has the right globals', function () {
340 var matchVars = [
341 '$1',
342 '$2',
343 '$3',
344 '$4',
345 '$5',
346 '$6',
347 '$7',
348 '$8',
349 '$9'
350 ];
351 matchVars.forEach(function (match) {
352 expect(RegExp).to.have.property(match);
353 });
354 });
355
356 describe('updates RegExp globals', function () {
357 var str = 'abcdefghijklmnopq';
358 var re;
359 beforeEach(function () {
360 re = /(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)(m)(n)(o)(p)/;
361 re.exec(str);
362 });
363
364 it('has "input"', function () {
365 expect(RegExp.input).to.equal(str);
366 expect(RegExp.$_).to.equal(str);
367 });
368
369 it('has "multiline"', function () {
370 if (Object.prototype.hasOwnProperty.call(RegExp, 'multiline')) {
371 expect(RegExp.multiline).to.equal(false);
372 }
373 if (Object.prototype.hasOwnProperty.call(RegExp, '$*')) {
374 expect(RegExp['$*']).to.equal(false);
375 }
376 });
377
378 it('has "lastMatch"', function () {
379 expect(RegExp.lastMatch).to.equal('bcdefghijklmnop');
380 expect(RegExp['$&']).to.equal('bcdefghijklmnop');
381 });
382
383 // in all but IE, this works. IE lastParen breaks after 11 tokens.
384 it.skip('has "lastParen"', function () {
385 expect(RegExp.lastParen).to.equal('p');
386 expect(RegExp['$+']).to.equal('p');
387 });
388 it('has "lastParen" for less than 11 tokens', function () {
389 (/(b)(c)(d)/).exec('abcdef');
390 expect(RegExp.lastParen).to.equal('d');
391 expect(RegExp['$+']).to.equal('d');
392 });
393
394 it('has "leftContext"', function () {
395 expect(RegExp.leftContext).to.equal('a');
396 expect(RegExp['$`']).to.equal('a');
397 });
398
399 it('has "rightContext"', function () {
400 expect(RegExp.rightContext).to.equal('q');
401 expect(RegExp["$'"]).to.equal('q');
402 });
403
404 it('has $1 - $9', function () {
405 expect(RegExp.$1).to.equal('b');
406 expect(RegExp.$2).to.equal('c');
407 expect(RegExp.$3).to.equal('d');
408 expect(RegExp.$4).to.equal('e');
409 expect(RegExp.$5).to.equal('f');
410 expect(RegExp.$6).to.equal('g');
411 expect(RegExp.$7).to.equal('h');
412 expect(RegExp.$8).to.equal('i');
413 expect(RegExp.$9).to.equal('j');
414 });
415 });
416 });
417});