Skip to content

Commit

Permalink
full test coverage, adding tests, deleting dead code
Browse files Browse the repository at this point in the history
  • Loading branch information
isaacs committed Feb 8, 2022
1 parent 47e0e45 commit dbda065
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 54 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,6 @@ Suppress the behavior of treating a leading `!` character as negation.
Returns from negate expressions the same as if they were not negated.
(Ie, true on a hit, false on a miss.)


## Comparisons to other fnmatch/glob implementations

While strict compliance with the existing standards is a worthwhile
Expand Down
67 changes: 29 additions & 38 deletions minimatch.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ function filter (pattern, options) {
}

function ext (a, b) {
a = a || {}
b = b || {}
const t = {}
Object.keys(a).forEach(function (k) {
Expand Down Expand Up @@ -123,9 +122,6 @@ function minimatch (p, pattern, options) {
return false
}

// "" only matches ""
if (pattern.trim() === '') return p === ''

return new Minimatch(pattern, options).match(p)
}

Expand All @@ -137,7 +133,6 @@ function Minimatch (pattern, options) {
assertValidPattern(pattern)

if (!options) options = {}
pattern = pattern.trim()

// windows support: need to use /, not \
if (path.sep !== '/') {
Expand All @@ -160,9 +155,6 @@ Minimatch.prototype.debug = function () {}

Minimatch.prototype.make = make
function make () {
// don't do it more than once.
if (this._made) return

var pattern = this.pattern
var options = this.options

Expand All @@ -182,7 +174,7 @@ function make () {
// step 2: expand braces
var set = this.globSet = this.braceExpand()

if (options.debug) this.debug = console.error
if (options.debug) this.debug = (...args) => console.error(...args)

this.debug(this.pattern, set)

Expand Down Expand Up @@ -304,7 +296,12 @@ function parse (pattern, isSub) {
var options = this.options

// shortcuts
if (!options.noglobstar && pattern === '**') return GLOBSTAR
if (pattern === '**') {
if (!options.noglobstar)
return GLOBSTAR
else
pattern = '*'
}
if (pattern === '') return ''

var re = ''
Expand Down Expand Up @@ -360,7 +357,8 @@ function parse (pattern, isSub) {
}

switch (c) {
case '/': /* istanbul ignore next */ {
/* istanbul ignore next */
case '/': {
// completely not allowed, even escaped.
// Should already be path-split by now.
return false
Expand Down Expand Up @@ -483,25 +481,23 @@ function parse (pattern, isSub) {

// handle the case where we left a class open.
// "[z-a]" is valid, equivalent to "\[z-a\]"
if (inClass) {
// split where the last [ was, make sure we don't have
// an invalid re. if so, re-walk the contents of the
// would-be class to re-translate any characters that
// were passed through as-is
// TODO: It would probably be faster to determine this
// without a try/catch and a new RegExp, but it's tricky
// to do safely. For now, this is safe and works.
var cs = pattern.substring(classStart + 1, i)
try {
RegExp('[' + cs + ']')
} catch (er) {
// not a valid class!
var sp = this.parse(cs, SUBPARSE)
re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]'
hasMagic = hasMagic || sp[1]
inClass = false
continue
}
// split where the last [ was, make sure we don't have
// an invalid re. if so, re-walk the contents of the
// would-be class to re-translate any characters that
// were passed through as-is
// TODO: It would probably be faster to determine this
// without a try/catch and a new RegExp, but it's tricky
// to do safely. For now, this is safe and works.
var cs = pattern.substring(classStart + 1, i)
try {
RegExp('[' + cs + ']')
} catch (er) {
// not a valid class!
var sp = this.parse(cs, SUBPARSE)
re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]'
hasMagic = hasMagic || sp[1]
inClass = false
continue
}

// finish up the class.
Expand Down Expand Up @@ -585,9 +581,7 @@ function parse (pattern, isSub) {
// something that could conceivably capture a dot
var addPatternStart = false
switch (re.charAt(0)) {
case '.':
case '[':
case '(': addPatternStart = true
case '[': case '.': case '(': addPatternStart = true
}

// Hack to work around lack of negative lookbehind in JS
Expand Down Expand Up @@ -725,16 +719,13 @@ minimatch.match = function (list, pattern, options) {
return list
}

Minimatch.prototype.match = match
function match (f, partial) {
Minimatch.prototype.match = function match (f) {
this.debug('match', f, this.pattern)
// short-circuit in the case of busted things.
// comments, etc.
if (this.comment) return false
if (this.empty) return f === ''

if (f === '/' && partial) return true

var options = this.options

// windows: need to use /, not \
Expand Down Expand Up @@ -768,7 +759,7 @@ function match (f, partial) {
if (options.matchBase && pattern.length === 1) {
file = [filename]
}
var hit = this.matchOne(file, pattern, partial)
var hit = this.matchOne(file, pattern, false)
if (hit) {
if (options.flipNegate) return true
return !this.negate
Expand Down
80 changes: 68 additions & 12 deletions test/basic.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
// TODO: Some of these tests do very bad things with backslashes, and will
// most likely fail badly on windows. They should probably be skipped.

var tap = require('tap')
var globalBefore = Object.keys(global)
var mm = require('../')
var patterns = require('./patterns.js')
var regexps = patterns.regexps
var re = 0

tap.test('basic tests', function (t) {
const t = require('tap')
const globalBefore = Object.keys(global)
const mm = require('../')
const patterns = require('./patterns.js')
const regexps = patterns.regexps
let re = 0

t.test('basic tests', function (t) {
var start = Date.now()

// [ pattern, [matches], MM opts, files, TAP opts]
Expand Down Expand Up @@ -58,15 +58,15 @@ tap.test('basic tests', function (t) {
t.end()
})

tap.test('global leak test', function (t) {
t.test('global leak test', function (t) {
var globalAfter = Object.keys(global).filter(function (k) {
return (k !== '__coverage__' && k !== '__core-js_shared__')
})
t.same(globalAfter, globalBefore, 'no new globals, please')
t.end()
})

tap.test('invalid patterns', t => {
t.test('invalid patterns', t => {
const toolong = 'x'.repeat(64 * 1024) + 'y'
const expectTooLong = { message: 'pattern is too long' }
t.throws(() => mm.braceExpand(toolong), expectTooLong)
Expand Down Expand Up @@ -95,19 +95,75 @@ tap.test('invalid patterns', t => {
t.end()
})

tap.test('ctor is generator', t => {
t.test('ctor is generator', t => {
const m = mm.Minimatch('asdf')
t.type(m, mm.Minimatch)
t.equal(m.pattern, 'asdf')
t.end()
})

tap.test('nocomment matches nothing', t => {
t.test('nocomment matches nothing', t => {
t.equal(mm('#comment', '#comment', { nocomment: false }), false)
t.equal(mm('#comment', '#comment', { nocomment: true }), true)
t.end()
})

t.test('filter function', t => {
t.same(['a', 'b', 'c'].filter(mm.filter('@(a|b)')), ['a', 'b'])
t.end()
})

t.test('whitespace handling', t => {
t.equal(mm('x/y', 'y'), false)
t.equal(mm('x/y', 'y', { matchBase: true }), true)
t.equal(mm('x/ ', ' '), false)
t.equal(mm('x/ ', ' ', { matchBase: true }), true)
t.equal(mm('x/', ''), false)
t.equal(mm('x/', '', { matchBase: true }), false)
t.equal(mm('', ''), true)
t.equal(mm(' ', ''), false)
t.equal(mm('', ' '), false)
t.equal(mm(' ', ' '), true)
t.end()
})

t.test('mm debug', t => {
const { error } = console
t.teardown(() => console.error = error)
const errs = []
console.error = (...msg) => errs.push(msg)
t.equal(mm('a/b/c', 'a/**/@(b|c)/**', { debug: true }), true)
t.not(errs.length, 0)
t.end()
})

t.test('makeRe repeated', t => {
const mmRE = mm.makeRe('a/*/*')
const m = new mm.Minimatch('a/*/*')
const mRE = m.makeRe()
const mRE2 = m.makeRe()
t.equal(mRE, mRE2)
t.same(mmRE, mRE)
t.end()
})

t.test('in noglobstar mode, ** is equivalent to *', t => {
const re2s = mm.makeRe('**', { noglobstar: true })
const re1s = mm.makeRe('*', { noglobstar: true })
t.same(re2s, re1s)
t.end()
})

t.test('flipNegate', t => {
t.equal(mm('x', '!x', { flipNegate: true }), true)
t.equal(mm('x', '!!x', { flipNegate: true }), true)
t.equal(mm('x', 'x', { flipNegate: true }), true)

t.equal(mm('x', '!y', { flipNegate: true }), false)
t.equal(mm('x', '!!y', { flipNegate: true }), false)
t.equal(mm('x', 'y', { flipNegate: true }), false)
t.end()
})

function alpha (a, b) {
return a > b ? 1 : -1
Expand Down
18 changes: 15 additions & 3 deletions test/win-path-sep.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
const t = require('tap')
const mm = t.mock('../', { path: { sep: '\\' }})
t.test('path separator \\', t => {
const mm = t.mock('../', { path: { sep: '\\' }})

t.equal(mm('x\\y\\z', 'x/y/*/z'), false)
t.equal(mm('x\\y\\w\\z', 'x/y/*/z'), true)
t.equal(mm('x\\y\\z', 'x/y/*/z'), false)
t.equal(mm('x\\y\\w\\z', 'x/y/*/z'), true)
t.end()
})

// just in case Node every adds Mac OS 9 support 😅
t.test('path separator :', t => {
const mm = t.mock('../', { path: { sep: ':' }})

t.equal(mm('x:y:z', 'x/y/*/z'), false)
t.equal(mm('x:y:w:z', 'x/y/*/z'), true)
t.end()
})

0 comments on commit dbda065

Please sign in to comment.