Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[New] add t.match() and t.doesNotMatch(), new in node v13.6
  • Loading branch information
ljharb committed Jan 8, 2020
1 parent 21ac403 commit 0330d82
Show file tree
Hide file tree
Showing 4 changed files with 219 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .editorconfig
Expand Up @@ -7,7 +7,7 @@ end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 140
max_line_length = 180
block_comment_start = /*
block_comment = *
block_comment_end = */
Expand Down
37 changes: 37 additions & 0 deletions lib/test.js
Expand Up @@ -8,8 +8,10 @@ var isRegExp = require('is-regex');
var trim = require('string.prototype.trim');
var bind = require('function-bind');
var forEach = require('for-each');
var inspect = require('object-inspect');
var isEnumerable = bind.call(Function.call, Object.prototype.propertyIsEnumerable);
var toLowerCase = bind.call(Function.call, String.prototype.toLowerCase);
var $test = bind.call(Function.call, RegExp.prototype.test);

module.exports = Test;

Expand Down Expand Up @@ -545,6 +547,41 @@ Test.prototype.doesNotThrow = function (fn, expected, msg, extra) {
});
};

Test.prototype.match = function match(string, regexp, msg, extra) {
if (!isRegExp(regexp)) {
throw new TypeError('The "regexp" argument must be an instance of RegExp. Received type ' + typeof regexp + ' (' + inspect(regexp) + ')');
}
if (typeof string !== 'string') {
throw new TypeError('The "string" argument must be of type string. Received type ' + typeof string + ' (' + inspect(string) + ')');
}

var matches = $test(regexp, string);
this._assert(matches, {
message: defined(msg, 'The input did not match the regular expression ' + inspect(regexp) + '. Input: ' + inspect(string)),
operator: 'match',
actual: string,
expected: regexp,
extra: extra
});
};

Test.prototype.doesNotMatch = function doesNotMatch(string, regexp, msg, extra) {
if (!isRegExp(regexp)) {
throw new TypeError('The "regexp" argument must be an instance of RegExp. Received type ' + typeof regexp + ' (' + inspect(regexp) + ')');
}
if (typeof string !== 'string') {
throw new TypeError('The "string" argument must be of type string. Received type ' + typeof string + ' (' + inspect(string) + ')');
}
var matches = $test(regexp, string);
this._assert(!matches, {
message: defined(msg, 'The input was expected to not match the regular expression ' + inspect(regexp) + '. Input: ' + inspect(string)),
operator: 'doesNotMatch',
actual: string,
expected: regexp,
extra: extra
});
};

Test.skip = function (name_, _opts, _cb) {
var args = getTestArgs.apply(null, arguments);
args.opts.skip = true;
Expand Down
8 changes: 8 additions & 0 deletions readme.markdown
Expand Up @@ -285,6 +285,14 @@ You may pass the same options that [`test()`](#testname-opts-cb) accepts.

Print a message without breaking the tap output. (Useful when using e.g. `tap-colorize` where output is buffered & `console.log` will print in incorrect order vis-a-vis tap output.)

## t.match(string, regexp, message)

Assert that `string` matches the RegExp `regexp`. Will throw (not just fail) when the first two arguments are the wrong type.

## t.doesNotMatch(string, regexp, message)

Assert that `string` does not match the RegExp `regexp`. Will throw (not just fail) when the first two arguments are the wrong type.

## var htest = test.createHarness()

Create a new test harness instance, which is a function like `test()`, but with
Expand Down
173 changes: 173 additions & 0 deletions test/match.js
@@ -0,0 +1,173 @@
'use strict';

var tape = require('../');
var tap = require('tap');
var concat = require('concat-stream');

var stripFullStack = require('./common').stripFullStack;

tap.test('match', function (tt) {
tt.plan(1);

var test = tape.createHarness({ exit: false });
var tc = function (rows) {
tt.same(stripFullStack(rows.toString('utf8')), [
'TAP version 13',
'# match',
'ok 1 regex arg must be a regex',
'ok 2 string arg must be a string',
'not ok 3 The input did not match the regular expression /abc/. Input: \'string\'',
' ---',
' operator: match',
' expected: /abc/',
' actual: \'string\'',
' at: Test.<anonymous> ($TEST/match.js:$LINE:$COL)',
' stack: |-',
' Error: The input did not match the regular expression /abc/. Input: \'string\'',
' [... stack stripped ...]',
' at Test.<anonymous> ($TEST/match.js:$LINE:$COL)',
' [... stack stripped ...]',
' ...',
'not ok 4 "string" does not match /abc/',
' ---',
' operator: match',
' expected: /abc/',
' actual: \'string\'',
' at: Test.<anonymous> ($TEST/match.js:$LINE:$COL)',
' stack: |-',
' Error: "string" does not match /abc/',
' [... stack stripped ...]',
' at Test.<anonymous> ($TEST/match.js:$LINE:$COL)',
' [... stack stripped ...]',
' ...',
'ok 5 The input did not match the regular expression /pass$/. Input: \'I will pass\'',
'ok 6 "I will pass" matches /pass$/',
'',
'1..6',
'# tests 6',
'# pass 4',
'# fail 2',
''
].join('\n'));
};

test.createStream().pipe(concat(tc));

test('match', function (t) {
t.plan(6);

t.throws(
function () { t.match(/abc/, 'string'); },
TypeError,
'regex arg must be a regex'
);

t.throws(
function () { t.match({ abc: 123 }, /abc/); },
TypeError,
'string arg must be a string'
);

t.match('string', /abc/);
t.match('string', /abc/, '"string" does not match /abc/');

t.match('I will pass', /pass$/);
t.match('I will pass', /pass$/, '"I will pass" matches /pass$/');

t.end();
});
});

tap.test('doesNotMatch', function (tt) {
tt.plan(1);

var test = tape.createHarness({ exit: false });
var tc = function (rows) {
tt.same(stripFullStack(rows.toString('utf8')), [
'TAP version 13',
'# doesNotMatch',
'ok 1 regex arg must be a regex',
'ok 2 string arg must be a string',
'not ok 3 The input was expected to not match the regular expression /string/. Input: \'string\'',
' ---',
' operator: doesNotMatch',
' expected: /string/',
' actual: \'string\'',
' at: Test.<anonymous> ($TEST/match.js:$LINE:$COL)',
' stack: |-',
' Error: The input was expected to not match the regular expression /string/. Input: \'string\'',
' [... stack stripped ...]',
' at Test.<anonymous> ($TEST/match.js:$LINE:$COL)',
' [... stack stripped ...]',
' ...',
'not ok 4 "string" should not match /string/',
' ---',
' operator: doesNotMatch',
' expected: /string/',
' actual: \'string\'',
' at: Test.<anonymous> ($TEST/match.js:$LINE:$COL)',
' stack: |-',
' Error: "string" should not match /string/',
' [... stack stripped ...]',
' at Test.<anonymous> ($TEST/match.js:$LINE:$COL)',
' [... stack stripped ...]',
' ...',
'not ok 5 The input was expected to not match the regular expression /pass$/. Input: \'I will pass\'',
' ---',
' operator: doesNotMatch',
' expected: /pass$/',
' actual: \'I will pass\'',
' at: Test.<anonymous> ($TEST/match.js:$LINE:$COL)',
' stack: |-',
' Error: The input was expected to not match the regular expression /pass$/. Input: \'I will pass\'',
' [... stack stripped ...]',
' at Test.<anonymous> ($TEST/match.js:$LINE:$COL)',
' [... stack stripped ...]',
' ...',
'not ok 6 "I will pass" should not match /pass$/',
' ---',
' operator: doesNotMatch',
' expected: /pass$/',
' actual: \'I will pass\'',
' at: Test.<anonymous> ($TEST/match.js:$LINE:$COL)',
' stack: |-',
' Error: "I will pass" should not match /pass$/',
' [... stack stripped ...]',
' at Test.<anonymous> ($TEST/match.js:$LINE:$COL)',
' [... stack stripped ...]',
' ...',
'',
'1..6',
'# tests 6',
'# pass 2',
'# fail 4',
''
].join('\n'));
};

test.createStream().pipe(concat(tc));

test('doesNotMatch', function (t) {
t.plan(6);

t.throws(
function () { t.doesNotMatch(/abc/, 'string'); },
TypeError,
'regex arg must be a regex'
);

t.throws(
function () { t.doesNotMatch({ abc: 123 }, /abc/); },
TypeError,
'string arg must be a string'
);

t.doesNotMatch('string', /string/);
t.doesNotMatch('string', /string/, '"string" should not match /string/');

t.doesNotMatch('I will pass', /pass$/);
t.doesNotMatch('I will pass', /pass$/, '"I will pass" should not match /pass$/');

t.end();
});
});

0 comments on commit 0330d82

Please sign in to comment.