blob: 7214b478bd9622a9ed0fba0a1436896f4264ac15 [file] [log] [blame]
'use strict';
var forEach = require('foreach');
var has = Object.prototype.hasOwnProperty;
var assign = require('object.assign');
var define = require('define-properties');
var entries = require('object.entries');
var inspect = require('object-inspect');
var hasSticky = typeof (/a/).sticky === 'boolean';
var hasGroups = 'groups' in (/a/).exec('a');
var groups = function groups(matchObject) {
return hasGroups ? assign(matchObject, { groups: matchObject.groups }, matchObject) : matchObject;
};
var arraySpread = function arraySpread(iterator) {
if (Array.isArray(iterator)) { return iterator; }
var result;
var values = [];
do {
result = iterator.next();
values.push(result);
} while (!result.done);
return values;
};
var testResults = function (t, iterator, expectedResults, item) {
var prefix = arguments.length > 3 ? inspect(item) + ': ' : '';
var results = arraySpread(iterator);
var expecteds = arraySpread(expectedResults);
t.test(prefix + 'actual vs expected result lengths', function (st) {
st.equal(results.length, expecteds.length, 'actual and expected result counts are the same');
st.end();
});
t.test(prefix + 'actual vs expected results', { skip: results.length !== expecteds.length }, function (st) {
forEach(expecteds, function (expected, index) {
var result = results.shift();
st.equal(result.done, expected.done, 'result ' + (index + 1) + ' is ' + (expected.done ? '' : 'not ') + 'done');
st.test('result ' + (index + 1), { skip: result.done !== expected.done }, function (s2t) {
if (expected.done) {
s2t.equal(result.value, undefined, 'result ' + (index + 1) + ' value is undefined');
} else {
s2t.equal(Array.isArray(result.value), true, 'result ' + (index + 1) + ' value is an array');
s2t.deepEqual(entries(result.value || {}), entries(expected.value || {}), 'result ' + (index + 1) + ' has the same entries');
s2t.deepEqual(result.value, expected.value, 'result ' + (index + 1) + ' value is expected value');
}
s2t.end();
});
});
});
};
module.exports = function (matchAll, regexMatchAll, t) {
t.test('non-regexes', function (st) {
var notRegexes = [
[null, [{ value: undefined, done: true }]],
[undefined, [
{ value: assign([''], groups({ index: 0, input: 'abc' })), done: false },
{ value: assign([''], groups({ index: 1, input: 'abc' })), done: false },
{ value: assign([''], groups({ index: 2, input: 'abc' })), done: false },
{ value: assign([''], groups({ index: 3, input: 'abc' })), done: false },
{ value: undefined, done: true }
]],
[NaN, [{ value: undefined, done: true }]],
[42, [{ value: undefined, done: true }]],
[new Date(), [{ value: undefined, done: true }]],
[{}, [
{ value: assign(['b'], groups({ index: 1, input: 'abc' })), done: false },
{ value: assign(['c'], groups({ index: 2, input: 'abc' })), done: false },
{ value: undefined, done: true }
]],
[[], [
{ value: assign([''], groups({ index: 0, input: 'abc' })), done: false },
{ value: assign([''], groups({ index: 1, input: 'abc' })), done: false },
{ value: assign([''], groups({ index: 2, input: 'abc' })), done: false },
{ value: assign([''], groups({ index: 3, input: 'abc' })), done: false },
{ value: undefined, done: true }
]]
];
var str = 'abc';
forEach(notRegexes, function (notRegex) {
testResults(st, matchAll(str, notRegex[0]), notRegex[1], notRegex[0]);
});
st.end();
});
t.test('passing a string instead of a regex', function (st) {
var str = 'aabcaba';
testResults(st, matchAll(str, 'a'), matchAll(str, /a/g));
st.end();
});
t.test('ToString-able objects', function (st) {
var str = 'aabc';
var strObj = { toString: function () { return str; } };
var regex = /[ac]/g;
var expectedResults = [
{ value: assign(['a'], groups({ index: 0, input: str })), done: false },
{ value: assign(['a'], groups({ index: 1, input: str })), done: false },
{ value: assign(['c'], groups({ index: 3, input: str })), done: false },
{ value: undefined, done: true }
];
testResults(st, matchAll(strObj, regex), expectedResults);
st.end();
});
t.test('#flags', function (st) {
st.test('without a flags property', function (s2t) {
var str = 'aabc';
var regex = /[ac]/g;
if (define.supportsDescriptors) {
Object.defineProperty(regex, 'flags', { value: undefined });
}
s2t.equal(regex.flags, undefined, 'regex has an undefined "flags" property');
s2t['throws'](
function () { matchAll(str, regex); },
'undefined flags throws'
);
s2t.end();
});
st.test('with a static flags property', function (s2t) {
var str = 'AaBC';
var regex = /[ac]/;
define(regex, { flags: 'ig' }, { flags: function () { return true; } });
try {
define(regex, { global: true }, { global: function () { return true; } });
s2t.equal(regex.global, true);
} catch (e) {
s2t.comment('# SKIP in node < 6, `global` is not configurable on regexes');
return s2t.end();
}
s2t.equal(regex.flags, 'ig');
var expectedResults = [
{ value: assign(['A'], groups({ index: 0, input: str })), done: false },
{ value: assign(['a'], groups({ index: 1, input: str })), done: false },
{ value: assign(['C'], groups({ index: 3, input: str })), done: false },
{ value: undefined, done: true }
];
testResults(s2t, matchAll(str, regex), expectedResults);
return s2t.end();
});
st.test('respects flags', function (s2t) {
var str = 'A\na\nb\nC';
var regex = /^[ac]/img;
var expectedResults = [
{ value: assign(['A'], groups({ index: 0, input: str })), done: false },
{ value: assign(['a'], groups({ index: 2, input: str })), done: false },
{ value: assign(['C'], groups({ index: 6, input: str })), done: false },
{ value: undefined, done: true }
];
testResults(s2t, matchAll(str, regex), expectedResults);
s2t.end();
});
st.test('throws with a non-global regex', function (s2t) {
var str = 'AaBbCc';
var regex = /[bc]/i;
s2t['throws'](
function () { matchAll(str, regex); },
TypeError,
'a non-global regex throws'
);
s2t.end();
});
st.test('works with a global non-sticky regex', function (s2t) {
var str = 'AaBbCc';
var regex = /[bc]/gi;
var expectedResults = [
{ value: assign(['B'], groups({ index: 2, input: str })), done: false },
{ value: assign(['b'], groups({ index: 3, input: str })), done: false },
{ value: assign(['C'], groups({ index: 4, input: str })), done: false },
{ value: assign(['c'], groups({ index: 5, input: str })), done: false },
{ value: undefined, done: true }
];
testResults(s2t, matchAll(str, regex), expectedResults);
s2t.end();
});
});
t.test('returns an iterator', function (st) {
var str = 'aabc';
var iterator = matchAll(str, /[ac]/g);
st.ok(iterator, 'iterator is truthy');
st.equal(has.call(iterator, 'next'), false, 'iterator does not have own property "next"');
for (var key in iterator) {
st.fail('iterator has enumerable properties: ' + key);
}
var expectedResults = [
{ value: assign(['a'], groups({ index: 0, input: str })), done: false },
{ value: assign(['a'], groups({ index: 1, input: str })), done: false },
{ value: assign(['c'], groups({ index: 3, input: str })), done: false },
{ value: undefined, done: true }
];
testResults(st, iterator, expectedResults);
st.end();
});
t.test('zero-width matches', function (st) {
var str = 'abcde';
st.test('global', function (s2t) {
var expectedResults = [
{ value: assign([''], groups({ index: 1, input: str })), done: false },
{ value: assign([''], groups({ index: 2, input: str })), done: false },
{ value: assign([''], groups({ index: 3, input: str })), done: false },
{ value: assign([''], groups({ index: 4, input: str })), done: false },
{ value: undefined, done: true }
];
testResults(s2t, matchAll(str, /\B/g), expectedResults);
s2t.end();
});
st.test('sticky', { skip: !hasSticky }, function (s2t) {
var expectedResults = [
{ value: undefined, done: true }
];
/* eslint no-invalid-regexp: [2, { "allowConstructorFlags": ["y"] }] */
var regex = new RegExp('\\B', 'y');
s2t['throws'](
function () { matchAll(str, regex); },
TypeError,
'non-global sticky regex throws'
);
/* eslint no-invalid-regexp: [2, { "allowConstructorFlags": ["y"] }] */
testResults(s2t, matchAll(str, new RegExp('\\B', 'gy')), expectedResults);
s2t.end();
});
st.test('unflagged', function (s2t) {
s2t['throws'](
function () { matchAll(str, /\B/); },
TypeError,
'unflagged regex throws'
);
s2t.end();
});
st.end();
});
};