securityos/node_modules/lunr/test/search_test.js

1101 lines
32 KiB
JavaScript
Raw Normal View History

2024-09-06 15:32:35 +00:00
suite('search', function () {
setup(function () {
this.documents = [{
id: 'a',
title: 'Mr. Green kills Colonel Mustard',
body: 'Mr. Green killed Colonel Mustard in the study with the candlestick. Mr. Green is not a very nice fellow.',
wordCount: 19
},{
id: 'b',
title: 'Plumb waters plant',
body: 'Professor Plumb has a green plant in his study',
wordCount: 9
},{
id: 'c',
title: 'Scarlett helps Professor',
body: 'Miss Scarlett watered Professor Plumbs green plant while he was away from his office last week.',
wordCount: 16
}]
})
suite('with build-time field boosts', function () {
setup(function () {
var self = this
this.idx = lunr(function () {
this.ref('id')
this.field('title')
this.field('body', { boost: 10 })
self.documents.forEach(function (document) {
this.add(document)
}, this)
})
})
suite('no query boosts', function () {
var assertions = function () {
test('document b ranks highest', function () {
assert.equal('b', this.results[0].ref)
})
}
suite('#search', function () {
setup(function () {
this.results = this.idx.search('professor')
})
assertions()
})
suite('#query', function () {
setup(function () {
this.results = this.idx.query(function (q) {
q.term('professor')
})
})
assertions()
})
})
})
suite('with build-time document boost', function () {
setup(function () {
var self = this
this.idx = lunr(function () {
this.ref('id')
this.field('title')
this.field('body')
self.documents.forEach(function (document) {
var boost = document.id == 'c' ? 10 : 1
this.add(document, { boost: boost })
}, this)
})
})
suite('no query boost', function () {
var assertions = function () {
test('document c ranks highest', function () {
assert.equal('c', this.results[0].ref)
})
}
suite('#search', function () {
setup(function () {
this.results = this.idx.search('plumb')
})
assertions()
})
suite('#query', function () {
setup(function () {
this.results = this.idx.query(function (q) {
q.term('plumb')
})
})
assertions()
})
})
suite('with query boost', function () {
var assertions = function () {
test('document b ranks highest', function () {
assert.equal('b', this.results[0].ref)
})
}
suite('#search', function () {
setup(function () {
this.results = this.idx.search('green study^10')
})
assertions()
})
suite('#query', function () {
setup(function () {
this.results = this.idx.query(function (q) {
q.term('green')
q.term('study', { boost: 10 })
})
})
assertions()
})
})
})
suite('without build-time boosts', function () {
setup(function () {
var self = this
this.idx = lunr(function () {
this.ref('id')
this.field('title')
this.field('body')
self.documents.forEach(function (document) {
this.add(document)
}, this)
})
})
suite('single term search', function () {
suite('one match', function () {
var assertions = function () {
test('one result returned', function () {
assert.lengthOf(this.results, 1)
})
test('document c matches', function () {
assert.equal('c', this.results[0].ref)
})
test('matching term', function () {
assert.sameMembers(['scarlett'], Object.keys(this.results[0].matchData.metadata))
})
}
suite('#seach', function () {
setup(function () {
this.results = this.idx.search('scarlett')
})
assertions()
})
suite('#query', function () {
setup(function () {
this.results = this.idx.query(function (q) {
q.term('scarlett')
})
})
assertions()
})
})
suite('no match', function () {
setup(function () {
this.results = this.idx.search('foo')
})
test('no matches', function () {
assert.lengthOf(this.results, 0)
})
})
suite('multiple matches', function () {
setup(function () {
this.results = this.idx.search('plant')
})
test('has two matches', function () {
assert.lengthOf(this.results, 2)
})
test('sorted by relevance', function () {
assert.equal('b', this.results[0].ref)
assert.equal('c', this.results[1].ref)
})
})
suite('pipeline processing', function () {
// study would be stemmed to studi, tokens
// are stemmed by default on index and must
// also be stemmed on search to match
suite('enabled (default)', function () {
setup(function () {
this.results = this.idx.query(function (q) {
q.clause({term: 'study', usePipeline: true})
})
})
test('has two matches', function () {
assert.lengthOf(this.results, 2)
})
test('sorted by relevance', function () {
assert.equal('b', this.results[0].ref)
assert.equal('a', this.results[1].ref)
})
})
suite('disabled', function () {
setup(function () {
this.results = this.idx.query(function (q) {
q.clause({term: 'study', usePipeline: false})
})
})
test('no matches', function () {
assert.lengthOf(this.results, 0)
})
})
})
})
suite('multiple terms', function () {
suite('all terms match', function () {
setup(function () {
this.results = this.idx.search('fellow candlestick')
})
test('has one match', function () {
assert.lengthOf(this.results, 1)
})
test('correct document returned', function () {
assert.equal('a', this.results[0].ref)
})
test('matched terms returned', function () {
assert.sameMembers(['fellow', 'candlestick'], Object.keys(this.results[0].matchData.metadata))
assert.sameMembers(['body'], Object.keys(this.results[0].matchData.metadata['fellow']));
assert.sameMembers(['body'], Object.keys(this.results[0].matchData.metadata['candlestick']));
})
})
suite('one term matches', function () {
setup(function () {
this.results = this.idx.search('week foo')
})
test('has one match', function () {
assert.lengthOf(this.results, 1)
})
test('correct document returned', function () {
assert.equal('c', this.results[0].ref)
})
test('only matching terms returned', function () {
assert.sameMembers(['week'], Object.keys(this.results[0].matchData.metadata))
})
})
suite('duplicate query terms', function () {
// https://github.com/olivernn/lunr.js/issues/256
// previously this would throw a duplicate index error
// because the query vector already contained an entry
// for the term 'fellow'
test('no errors', function () {
var idx = this.idx
assert.doesNotThrow(function () {
idx.search('fellow candlestick foo bar green plant fellow')
})
})
})
suite('documents with all terms score higher', function () {
setup(function () {
this.results = this.idx.search('candlestick green')
})
test('has three matches', function () {
assert.lengthOf(this.results, 3)
})
test('correct documents returned', function () {
var matchingDocuments = this.results.map(function (r) {
return r.ref
})
assert.sameMembers(['a', 'b', 'c'], matchingDocuments)
})
test('documents with all terms score highest', function () {
assert.equal('a', this.results[0].ref)
})
test('matching terms are returned', function () {
assert.sameMembers(['candlestick', 'green'], Object.keys(this.results[0].matchData.metadata))
assert.sameMembers(['green'], Object.keys(this.results[1].matchData.metadata))
assert.sameMembers(['green'], Object.keys(this.results[2].matchData.metadata))
})
})
suite('no terms match', function () {
setup(function () {
this.results = this.idx.search('foo bar')
})
test('no matches', function () {
assert.lengthOf(this.results, 0)
})
})
suite('corpus terms are stemmed', function () {
setup(function () {
this.results = this.idx.search('water')
})
test('matches two documents', function () {
assert.lengthOf(this.results, 2)
})
test('matches correct documents', function () {
var matchingDocuments = this.results.map(function (r) {
return r.ref
})
assert.sameMembers(['b', 'c'], matchingDocuments)
})
})
suite('field scoped terms', function () {
suite('only matches on scoped field', function () {
setup(function () {
this.results = this.idx.search('title:plant')
})
test('one result returned', function () {
assert.lengthOf(this.results, 1)
})
test('returns the correct document', function () {
assert.equal('b', this.results[0].ref)
})
test('match data', function () {
assert.sameMembers(['plant'], Object.keys(this.results[0].matchData.metadata))
})
})
suite('no matching terms', function () {
setup(function () {
this.results = this.idx.search('title:candlestick')
})
test('no results returned', function () {
assert.lengthOf(this.results, 0)
})
})
})
suite('wildcard matching', function () {
suite('trailing wildcard', function () {
suite('no matches', function () {
setup(function () {
this.results = this.idx.search('fo*')
})
test('no results returned', function () {
assert.lengthOf(this.results, 0)
})
})
suite('one match', function () {
setup(function () {
this.results = this.idx.search('candle*')
})
test('one result returned', function () {
assert.lengthOf(this.results, 1)
})
test('correct document matched', function () {
assert.equal('a', this.results[0].ref)
})
test('matching terms returned', function () {
assert.sameMembers(['candlestick'], Object.keys(this.results[0].matchData.metadata))
})
})
suite('multiple terms match', function () {
setup(function () {
this.results = this.idx.search('pl*')
})
test('two results returned', function () {
assert.lengthOf(this.results, 2)
})
test('correct documents matched', function () {
var matchingDocuments = this.results.map(function (r) {
return r.ref
})
assert.sameMembers(['b', 'c'], matchingDocuments)
})
test('matching terms returned', function () {
assert.sameMembers(['plumb', 'plant'], Object.keys(this.results[0].matchData.metadata))
assert.sameMembers(['plumb', 'plant'], Object.keys(this.results[1].matchData.metadata))
})
})
})
})
})
suite('wildcard matching', function () {
suite('trailing wildcard', function () {
suite('no matches found', function () {
setup(function () {
this.results = this.idx.search('fo*')
})
test('no results returned', function () {
assert.lengthOf(this.results, 0)
})
})
suite('results found', function () {
setup(function () {
this.results = this.idx.search('pl*')
})
test('two results returned', function () {
assert.lengthOf(this.results, 2)
})
test('matching documents returned', function () {
assert.equal('b', this.results[0].ref)
assert.equal('c', this.results[1].ref)
})
test('matching terms returned', function () {
assert.sameMembers(['plant', 'plumb'], Object.keys(this.results[0].matchData.metadata))
assert.sameMembers(['plant', 'plumb'], Object.keys(this.results[1].matchData.metadata))
})
})
})
suite('leading wildcard', function () {
suite('no results found', function () {
setup(function () {
this.results = this.idx.search('*oo')
})
test('no results found', function () {
assert.lengthOf(this.results, 0)
})
})
suite('results found', function () {
setup(function () {
this.results = this.idx.search('*ant')
})
test('two results found', function () {
assert.lengthOf(this.results, 2)
})
test('matching documents returned', function () {
assert.equal('b', this.results[0].ref)
assert.equal('c', this.results[1].ref)
})
test('matching terms returned', function () {
assert.sameMembers(['plant'], Object.keys(this.results[0].matchData.metadata))
assert.sameMembers(['plant'], Object.keys(this.results[1].matchData.metadata))
})
})
})
suite('contained wildcard', function () {
suite('no results found', function () {
setup(function () {
this.results = this.idx.search('f*o')
})
test('no results found', function () {
assert.lengthOf(this.results, 0)
})
})
suite('results found', function () {
setup(function () {
this.results = this.idx.search('pl*nt')
})
test('two results found', function () {
assert.lengthOf(this.results, 2)
})
test('matching documents returned', function () {
assert.equal('b', this.results[0].ref)
assert.equal('c', this.results[1].ref)
})
test('matching terms returned', function () {
assert.sameMembers(['plant'], Object.keys(this.results[0].matchData.metadata))
assert.sameMembers(['plant'], Object.keys(this.results[1].matchData.metadata))
})
})
})
})
suite('edit distance', function () {
suite('no results found', function () {
setup(function () {
this.results = this.idx.search('foo~1')
})
test('no results returned', function () {
assert.lengthOf(this.results, 0)
})
})
suite('results found', function () {
setup(function () {
this.results = this.idx.search('plont~1')
})
test('two results found', function () {
assert.lengthOf(this.results, 2)
})
test('matching documents returned', function () {
assert.equal('b', this.results[0].ref)
assert.equal('c', this.results[1].ref)
})
test('matching terms returned', function () {
assert.sameMembers(['plant'], Object.keys(this.results[0].matchData.metadata))
assert.sameMembers(['plant'], Object.keys(this.results[1].matchData.metadata))
})
})
})
suite('searching by field', function () {
suite('unknown field', function () {
test('throws lunr.QueryParseError', function () {
assert.throws(function () {
this.idx.search('unknown-field:plant')
}.bind(this), lunr.QueryParseError)
})
})
suite('no results found', function () {
setup(function () {
this.results = this.idx.search('title:candlestick')
})
test('no results found', function () {
assert.lengthOf(this.results, 0)
})
})
suite('results found', function () {
setup(function () {
this.results = this.idx.search('title:plant')
})
test('one results found', function () {
assert.lengthOf(this.results, 1)
})
test('matching documents returned', function () {
assert.equal('b', this.results[0].ref)
})
test('matching terms returned', function () {
assert.sameMembers(['plant'], Object.keys(this.results[0].matchData.metadata))
})
})
})
suite('term boosts', function () {
suite('no results found', function () {
setup(function () {
this.results = this.idx.search('foo^10')
})
test('no results found', function () {
assert.lengthOf(this.results, 0)
})
})
suite('results found', function () {
setup(function () {
this.results = this.idx.search('scarlett candlestick^5')
})
test('two results found', function () {
assert.lengthOf(this.results, 2)
})
test('matching documents returned', function () {
assert.equal('a', this.results[0].ref)
assert.equal('c', this.results[1].ref)
})
test('matching terms returned', function () {
assert.sameMembers(['candlestick'], Object.keys(this.results[0].matchData.metadata))
assert.sameMembers(['scarlett'], Object.keys(this.results[1].matchData.metadata))
})
})
})
suite('typeahead style search', function () {
suite('no results found', function () {
setup(function () {
this.results = this.idx.query(function (q) {
q.term("xyz", { boost: 100, usePipeline: true })
q.term("xyz", { boost: 10, usePipeline: false, wildcard: lunr.Query.wildcard.TRAILING })
q.term("xyz", { boost: 1, editDistance: 1 })
})
})
test('no results found', function () {
assert.lengthOf(this.results, 0)
})
})
suite('results found', function () {
setup(function () {
this.results = this.idx.query(function (q) {
q.term("pl", { boost: 100, usePipeline: true })
q.term("pl", { boost: 10, usePipeline: false, wildcard: lunr.Query.wildcard.TRAILING })
q.term("pl", { boost: 1, editDistance: 1 })
})
})
test('two results found', function () {
assert.lengthOf(this.results, 2)
})
test('matching documents returned', function () {
assert.equal('b', this.results[0].ref)
assert.equal('c', this.results[1].ref)
})
test('matching terms returned', function () {
assert.sameMembers(['plumb', 'plant'], Object.keys(this.results[0].matchData.metadata))
assert.sameMembers(['plumb', 'plant'], Object.keys(this.results[1].matchData.metadata))
})
})
})
suite('term presence', function () {
suite('prohibited', function () {
suite('match', function () {
var assertions = function () {
test('two results found', function () {
assert.lengthOf(this.results, 2)
})
test('matching documents returned', function () {
assert.equal('b', this.results[0].ref)
assert.equal('c', this.results[1].ref)
})
test('matching terms returned', function () {
assert.sameMembers(['green'], Object.keys(this.results[0].matchData.metadata))
assert.sameMembers(['green'], Object.keys(this.results[1].matchData.metadata))
})
}
suite('#query', function () {
setup(function () {
this.results = this.idx.query(function (q) {
q.term('candlestick', { presence: lunr.Query.presence.PROHIBITED })
q.term('green', { presence: lunr.Query.presence.OPTIONAL })
})
})
assertions()
})
suite('#search', function () {
setup(function () {
this.results = this.idx.search('-candlestick green')
})
assertions()
})
})
suite('no match', function () {
var assertions = function () {
test('no matches', function () {
assert.lengthOf(this.results, 0)
})
}
suite('#query', function () {
setup(function () {
this.results = this.idx.query(function (q) {
q.term('green', { presence: lunr.Query.presence.PROHIBITED })
})
})
assertions()
})
suite('#search', function () {
setup(function () {
this.results = this.idx.search('-green')
})
assertions()
})
})
suite('negated query no match', function () {
var assertions = function () {
test('all documents returned', function () {
assert.lengthOf(this.results, 3)
})
test('all results have same score', function () {
assert.isTrue(this.results.every(function (r) { return r.score === 0 }))
})
}
suite('#query', function () {
setup(function () {
this.results = this.idx.query(function (q) {
q.term('qwertyuiop', { presence: lunr.Query.presence.PROHIBITED })
})
})
assertions()
})
suite('#search', function () {
setup(function () {
this.results = this.idx.search("-qwertyuiop")
})
assertions()
})
})
suite('negated query some match', function () {
var assertions = function () {
test('all documents returned', function () {
assert.lengthOf(this.results, 1)
})
test('all results have same score', function () {
assert.isTrue(this.results.every(function (r) { return r.score === 0 }))
})
test('matching documents returned', function () {
assert.equal('a', this.results[0].ref)
})
}
suite('#query', function () {
setup(function () {
this.results = this.idx.query(function (q) {
q.term('plant', { presence: lunr.Query.presence.PROHIBITED })
})
})
assertions()
})
suite('#search', function () {
setup(function () {
this.results = this.idx.search("-plant")
})
assertions()
})
})
suite('field match', function () {
var assertions = function () {
test('one result found', function () {
assert.lengthOf(this.results, 1)
})
test('matching documents returned', function () {
assert.equal('c', this.results[0].ref)
})
test('matching terms returned', function () {
assert.sameMembers(['plumb'], Object.keys(this.results[0].matchData.metadata))
})
}
suite('#query', function () {
setup(function () {
this.results = this.idx.query(function (q) {
q.term('plant', { presence: lunr.Query.presence.PROHIBITED, fields: ['title'] })
q.term('plumb', { presence: lunr.Query.presence.OPTIONAL })
})
})
assertions()
})
suite('#search', function () {
setup(function () {
this.results = this.idx.search('-title:plant plumb')
})
assertions()
})
})
})
suite('required', function () {
suite('match', function () {
var assertions = function () {
test('one result found', function () {
assert.lengthOf(this.results, 1)
})
test('matching documents returned', function () {
assert.equal('a', this.results[0].ref)
})
test('matching terms returned', function () {
assert.sameMembers(['candlestick', 'green'], Object.keys(this.results[0].matchData.metadata))
})
}
suite('#search', function () {
setup(function () {
this.results = this.idx.search("+candlestick green")
})
assertions()
})
suite('#query', function () {
setup(function () {
this.results = this.idx.query(function (q) {
q.term('candlestick', { presence: lunr.Query.presence.REQUIRED })
q.term('green', { presence: lunr.Query.presence.OPTIONAL })
})
})
assertions()
})
})
suite('no match', function () {
var assertions = function () {
test('no matches', function () {
assert.lengthOf(this.results, 0)
})
}
suite('#query', function () {
setup(function () {
this.results = this.idx.query(function (q) {
q.term('mustard', { presence: lunr.Query.presence.REQUIRED })
q.term('plant', { presence: lunr.Query.presence.REQUIRED })
})
})
assertions()
})
suite('#search', function () {
setup(function () {
this.results = this.idx.search('+mustard +plant')
})
assertions()
})
})
suite('no matching term', function () {
var assertions = function () {
test('no matches', function () {
assert.lengthOf(this.results, 0)
})
}
suite('#query', function () {
setup(function () {
this.results = this.idx.query(function (q) {
q.term('qwertyuiop', { presence: lunr.Query.presence.REQUIRED })
q.term('green', { presence: lunr.Query.presence.OPTIONAL })
})
})
assertions()
})
suite('#search', function () {
setup(function () {
this.results = this.idx.search('+qwertyuiop green')
})
assertions()
})
})
suite('field match', function () {
var assertions = function () {
test('one result found', function () {
assert.lengthOf(this.results, 1)
})
test('matching documents returned', function () {
assert.equal('b', this.results[0].ref)
})
test('matching terms returned', function () {
assert.sameMembers(['plant', 'green'], Object.keys(this.results[0].matchData.metadata))
})
}
suite('#query', function () {
setup(function () {
this.results = this.idx.query(function (q) {
q.term('plant', { presence: lunr.Query.presence.REQUIRED, fields: ['title'] })
q.term('green', { presence: lunr.Query.presence.OPTIONAL })
})
})
assertions()
})
suite('#search', function () {
setup(function () {
this.results = this.idx.search('+title:plant green')
})
assertions()
})
})
suite('field and non field match', function () {
var assertions = function () {
test('one result found', function () {
assert.lengthOf(this.results, 1)
})
test('matching documents returned', function () {
assert.equal('b', this.results[0].ref)
})
test('matching terms returned', function () {
assert.sameMembers(['plant', 'green'], Object.keys(this.results[0].matchData.metadata))
})
}
suite('#search', function () {
setup(function () {
this.results = this.idx.search('+title:plant +green')
})
assertions()
})
suite('#query', function () {
setup(function () {
this.results = this.idx.query(function (q) {
q.term('plant', { fields: ['title'], presence: lunr.Query.presence.REQUIRED })
q.term('green', { presence: lunr.Query.presence.REQUIRED })
})
})
assertions()
})
})
suite('different fields', function () {
var assertions = function () {
test('one result found', function () {
assert.lengthOf(this.results, 1)
})
test('matching documents returned', function () {
assert.equal('b', this.results[0].ref)
})
test('matching terms returned', function () {
assert.sameMembers(['studi', 'plant'], Object.keys(this.results[0].matchData.metadata))
})
}
suite('#search', function () {
setup(function () {
this.results = this.idx.search('+title:plant +body:study')
})
assertions()
})
suite('#query', function () {
setup(function () {
this.results = this.idx.query(function (q) {
q.term('plant', { fields: ['title'], presence: lunr.Query.presence.REQUIRED })
q.term('study', { fields: ['body'], presence: lunr.Query.presence.REQUIRED })
})
})
assertions()
})
})
suite('different fields one without match', function () {
var assertions = function () {
test('no matches', function () {
assert.lengthOf(this.results, 0)
})
}
suite('#search', function () {
setup(function () {
this.results = this.idx.search('+title:plant +body:qwertyuiop')
})
assertions()
})
suite('#query', function () {
setup(function () {
this.results = this.idx.query(function (q) {
q.term('plant', { fields: ['title'], presence: lunr.Query.presence.REQUIRED })
q.term('qwertyuiop', { fields: ['body'], presence: lunr.Query.presence.REQUIRED })
})
})
assertions()
})
})
})
suite('combined', function () {
var assertions = function () {
test('one result found', function () {
assert.lengthOf(this.results, 1)
})
test('matching documents returned', function () {
assert.equal('b', this.results[0].ref)
})
test('matching terms returned', function () {
assert.sameMembers(['plant', 'green'], Object.keys(this.results[0].matchData.metadata))
})
}
suite('#query', function () {
setup(function () {
this.results = this.idx.query(function (q) {
q.term('plant', { presence: lunr.Query.presence.REQUIRED })
q.term('green', { presence: lunr.Query.presence.OPTIONAL })
q.term('office', { presence: lunr.Query.presence.PROHIBITED })
})
})
assertions()
})
suite('#search', function () {
setup(function () {
this.results = this.idx.search('+plant green -office')
})
assertions()
})
})
})
})
})