1 | var getRegexLiteral = function (stringRegex) {
|
2 | try {
|
3 |
|
4 | return Function('return ' + stringRegex + ';')();
|
5 |
|
6 | } catch (e) { }
|
7 | };
|
8 | var describeIfSupportsDescriptors = Object.getOwnPropertyDescriptor ? describe : describe.skip;
|
9 | var callAllowsPrimitives = (function () { return this === 3; }.call(3));
|
10 | var ifCallAllowsPrimitivesIt = callAllowsPrimitives ? it : it.skip;
|
11 | var ifShimIt = (typeof process !== 'undefined' && process.env.NO_ES6_SHIM) ? it.skip : it;
|
12 | var hasSymbols = typeof Symbol === 'function' && typeof Symbol['for'] === 'function' && typeof Symbol('') === 'symbol';
|
13 | var ifSymbolsDescribe = hasSymbols ? describe : describe.skip;
|
14 | var defaultRegex = (function () {
|
15 |
|
16 |
|
17 | try {
|
18 | return RegExp.prototype.source ? String(RegExp.prototype) : '/(?:)/';
|
19 | } catch (e) {
|
20 | return '/(?:)/';
|
21 | }
|
22 | }());
|
23 |
|
24 | describe('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 |
|
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');
|
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 |
|
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 |
|
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 | });
|