1
0
mirror of https://github.com/nextapps-de/flexsearch.git synced 2025-08-23 22:24:31 +02:00
Files
flexsearch/test/basic.js
Thomas Wilkerling 1c4bcaac2e re-implement append
2025-06-05 08:33:21 +02:00

594 lines
19 KiB
JavaScript

global.self = global;
const env = process.argv[process.argv.length - 1] === "--exit" ? "" : process.argv[process.argv.length - 1];
import { expect } from "chai";
let FlexSearch = await import(env ? "../dist/" + env + ".js" : "../src/bundle.js");
if(FlexSearch.default) FlexSearch = FlexSearch.default;
if(FlexSearch.FlexSearch) FlexSearch = FlexSearch.FlexSearch;
const { Index, Document, Worker, Charset: _Charset, Encoder, Resolver } = FlexSearch;
const build_light = env && env.includes("light");
const build_compact = env && env.includes("compact");
const build_esm = !env || env.startsWith("module");
const Charset = _Charset || (await import("../src/charset.js")).default;
describe("Initialize", function(){
const index = new Index();
it("Should have proper constructor", function(){
expect(index).to.be.an.instanceOf(Index);
});
it("Should have all provided methods", function(){
expect(index).to.respondTo("search");
expect(index).to.respondTo("add");
expect(index).to.respondTo("append");
expect(index).to.respondTo("update");
expect(index).to.respondTo("remove");
expect(index).to.respondTo("clear");
expect(index).to.respondTo("cleanup");
expect(index).to.respondTo("contain");
expect(index).to.hasOwnProperty("map");
expect(index).to.hasOwnProperty("ctx");
expect(index).to.hasOwnProperty("reg");
if(!build_light){
expect(index).to.respondTo("searchAsync");
expect(index).to.respondTo("addAsync");
expect(index).to.respondTo("appendAsync");
expect(index).to.respondTo("updateAsync");
expect(index).to.respondTo("removeAsync");
expect(index).to.respondTo("export");
expect(index).to.respondTo("import");
expect(index).to.respondTo("serialize");
}
});
it("Should have the default options", function(){
expect(index.resolution).to.equal(9);
expect(index.depth).to.equal(0);
expect(index.fastupdate).to.equal(false);
});
it("Should have the default Encoder", function(){
const encoder = new Encoder(Charset.Default);
expect(index.tokenize).to.equal("strict");
expect(typeof index.encoder.normalize).to.equal(typeof encoder.normalize);
index.encoder.normalize = encoder.normalize;
expect(index.encoder).to.eql(encoder);
expect(index.encoder.minlength).to.equal(1);
expect(index.encoder.maxlength).to.equal(1024);
expect(index.encoder.rtl).to.equal(false);
expect(index.encoder.numeric).to.equal(true);
expect(index.encoder.dedupe).to.equal(true);
});
});
describe("Add", function(){
it("Should have been properly added to the index", function(){
const index = new Index();
index.add(0, "foo");
index.add(2, "bar");
index.add(1, "FooBar");
index.add(3, "Some 'short' content.");
expect(Array.from(index.reg.keys())).to.have.members([0, 1, 2, 3]);
expect(Array.from(index.map.keys())).to.have.members(["fo", "bar", "fobar", "some", "short", "content"]);
expect(index.ctx.size).to.equal(0);
expect(index.reg.size).to.equal(4);
});
it("Should have been numeric content properly added to the index (Triplets)", function(){
let index = new Index();
index.add(0, "TEST-123456789123456789");
index.add(1, "T10030");
index.add(2, "T10030T10030");
index.add(3, "1443-AB14345-1778");
expect(Array.from(index.reg.keys())).to.have.members([0, 1, 2, 3]);
expect(Array.from(index.map.keys())).to.have.members([
"test", "123", "456", "789",
"t", "10", "30",
// id 2 was already completely added, split: "t", "10", "30", "t", "10", "30"
"14", "3", "ab", "143", "45", "17", "8"
]);
expect(index.ctx.size).to.equal(0);
expect(index.reg.size).to.equal(4);
// disabled deduplication
index.clear();
index.encoder.dedupe = false;
index.add(0, "TEST-123456789123456789");
index.add(1, "T10030");
index.add(2, "T10030T10030");
index.add(3, "1443-AB14345-1778");
expect(Array.from(index.reg.keys())).to.have.members([0, 1, 2, 3]);
expect(Array.from(index.map.keys())).to.have.members([
"test", "123", "456", "789",
"t", "100", "30",
// id 2 was already completely added, split: "t", "100", "30", "t", "100", "30"
"144", "3", "ab", "143", "45", "177", "8"
]);
expect(index.ctx.size).to.equal(0);
expect(index.reg.size).to.equal(4);
});
it("Should not have been added to the index (Parameter)", function(){
const index = new Index();
index.add("foo");
index.add(3);
index.add(null, "foobar");
index.add(void 0, "foobar");
index.add(3, null);
index.add(3, false);
expect(index.reg.size).to.equal(0);
});
it("Should not have been added to the index (Empty)", function(){
const index = new Index();
index.add(1, "");
index.add(2, " ");
index.add(3, " ");
index.add(4, " - ");
index.add(5, ` ...
- : ,
<-- `);
expect(index.reg.size).to.equal(0);
});
});
describe("Append", function(){
it("Should have been properly appended to the index", function(){
const index = new Index();
index.append(0, "foo");
index.append(2, "bar");
index.append(1, "FooBar");
index.append(3, "Some 'short' content.");
expect(Array.from(index.reg.keys())).to.have.members([0, 1, 2, 3]);
expect(Array.from(index.map.keys())).to.have.members(["fo", "bar", "fobar", "some", "short", "content"]);
expect(index.ctx.size).to.equal(0);
expect(index.reg.size).to.equal(4);
});
it("Should have been properly appended by score", function(){
let index = new Index();
index.add(0, "foo A B C D E F bar");
index.add(1, "foo A B C bar D E F");
index.add(2, "foo bar A B C D E F");
expect(index.search("foo")).to.eql([0, 1, 2]);
expect(index.search("bar")).to.eql([2, 1, 0]);
expect(index.reg.size).to.equal(3);
expect(index.map.size).to.equal(8);
expect(index.ctx.size).to.equal(0);
index.append(0, "bar");
index.append(0, "foo");
index.append(0, "bar");
expect(index.search("foo")).to.eql([0, 1, 2]);
expect(index.search("bar")).to.eql([0, 2, 1]);
expect(index.reg.size).to.equal(3);
expect(index.map.size).to.equal(8);
expect(index.ctx.size).to.equal(0);
index.remove(2).remove(1).remove(0);
expect(index.reg.size).to.equal(0);
expect(index.map.size).to.equal(0);
expect(index.ctx.size).to.equal(0);
index = new Index({ context: true });
index.add(0, "foo A B C D E F bar");
index.add(1, "foo A B C bar D E F");
index.add(2, "foo bar A B C D E F");
expect(index.search("foo")).to.eql([0, 1, 2]);
expect(index.search("bar")).to.eql([2, 1, 0]);
expect(index.reg.size).to.equal(3);
expect(index.map.size).to.equal(8);
expect(index.ctx.size).to.equal(7);
index.append(0, "bar");
index.append(0, "foo");
index.append(0, "bar");
expect(index.search("foo")).to.eql([0, 1, 2]);
expect(index.search("bar")).to.eql([0, 2, 1]);
expect(index.reg.size).to.equal(3);
expect(index.map.size).to.equal(8);
expect(index.ctx.size).to.equal(7);
index.remove(2).remove(1).remove(0);
expect(index.reg.size).to.equal(0);
expect(index.map.size).to.equal(0);
expect(index.ctx.size).to.equal(0);
});
it("Should not have been appended to the index (Parameter)", function(){
const index = new Index();
index.append("foo");
index.append(3);
index.append(null, "foobar");
index.append(void 0, "foobar");
index.append(3, null);
index.append(3, false);
expect(index.reg.size).to.equal(0);
});
it("Should not have been appended to the index (Empty)", function(){
const index = new Index();
index.append(1, "");
index.append(2, " ");
index.append(3, " ");
index.append(4, " - ");
index.append(5, ` ...
- : ,
<-- `);
expect(index.reg.size).to.equal(0);
});
});
describe("Search (Sync)", function(){
it("Should have been matched properly", function(){
const index = new Index();
index.add(0, "foo");
index.add(1, "bar");
index.add(2, "FooBar");
index.add(3, "Some 'short' content.");
index.add(4, "Foo Bar");
expect(index.search("foo")).to.have.members([0, 4]);
expect(index.search("bar")).to.include(1, 4);
expect(index.search("foobar")).to.include(2);
expect(index.search("short 'content'")).to.include(3);
expect(index.search("foo foo")).to.have.members([0, 4]);
expect(index.search("foo foo bar foo bar")).to.have.members([4]);
});
it("Should have been applied limit/offset properly", function(){
const index = new Index();
for(let i = 0; i < 10; i++){
index.add(i, "foo");
}
expect(index.search("foo", 99)).to.have.members([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
expect(index.search("foo", 3)).to.have.members([0, 1, 2]);
expect(index.search("foo", { limit: 3 })).to.have.members([0, 1, 2]);
expect(index.search("foo", { limit: 3, offset: 3 })).to.have.members([3, 4, 5]);
expect(index.search("foo", { limit: 3, offset: 9 })).to.have.members([9]);
expect(index.search("foo", { limit: 3, offset: 10 })).to.have.members([]);
expect(index.search({ query: "foo", limit: 1 })).to.include(0);
});
});
describe("Search Scoring", function(){
it("Should have been matched properly", function(){
const index = new Index();
[ 'cats abcd efgh ijkl mnop qrst uvwx cute',
'cats abcd efgh ijkl mnop dogs cute',
'cats abcd efgh ijkl mnop cute',
'cats abcd efgh ijkl cute',
'cats abcd efgh cute',
'cats abcd cute',
'cats cute'
].forEach((item, id) => {
index.add(id, item);
});
let result = index.search("cats cute");
expect(result.length).to.equal(7);
expect(result).to.eql([6, 5, 4, 3, 2, 1, 0]);
result = index.search("cute cats");
expect(result.length).to.equal(7);
expect(result).to.eql([6, 5, 4, 3, 2, 1, 0]);
result = index.search("cute");
expect(result).to.eql([6, 5, 4, 3, 2, 1, 0]);
result = index.search("cute dogs cats");
expect(result.length).to.equal(1);
expect(result).to.eql([1]);
result = index.search("cute dogs cats", { suggest: true });
expect(result).to.eql([1, 6, 5, 4, 3, 2, 0]);
result = index.search("undefined cute undefined dogs undefined cats undefined", { suggest: true });
expect(result).to.eql([1, 6, 5, 4, 3, 2, 0]);
result = index.search("cute cat");
expect(result.length).to.equal(0);
});
});
describe("Tokenizer", function(){
it("Should have been \"forward\" tokenized properly", function(){
const index = new Index({ tokenize: "forward" });
[ 'cats abcd efgh ijkl mnop qrst uvwx cute',
'cats abcd efgh ijkl mnop dogs cute',
'cats abcd efgh ijkl mnop cute',
'cats abcd efgh ijkl cute',
'cats abcd efgh cute',
'cats abcd cute',
'cats cute'
].forEach((item, id) => {
index.add(id, item);
});
let result = index.search("cat cute");
expect(result.length).to.equal(7);
expect(result).to.eql([6, 5, 4, 3, 2, 1, 0]);
result = index.search("cute cat");
expect(result.length).to.equal(7);
expect(result).to.eql([6, 5, 4, 3, 2, 1, 0]);
result = index.search("cute");
expect(result).to.eql([6, 5, 4, 3, 2, 1, 0]);
});
it("Should have been \"reverse\" tokenized properly", function(){
const index = new Index({ tokenize: "reverse", resolution: 12 });
[ 'cats abcd efgh ijkl mnop qrst uvwx cute',
'cats abcd efgh ijkl mnop dogs cute',
'cats abcd efgh ijkl mnop cute',
'cats abcd efgh ijkl cute',
'cats abcd efgh cute',
'cats abcd cute',
'cats cute'
].forEach((item, id) => {
index.add(id, item);
});
let result = index.search("ats ute");
expect(result.length).to.equal(7);
expect(result).to.eql([6, 5, 4, 3, 2, 1, 0]);
result = index.search("ute ats");
expect(result.length).to.equal(7);
expect(result).to.eql([6, 5, 4, 3, 2, 1, 0]);
result = index.search("cute");
expect(result).to.eql([6, 5, 4, 3, 2, 1, 0]);
});
it("Should have been \"full\" tokenized properly", function(){
const index = new Index({ tokenize: "full", resolution: 12 });
[ 'cats abcd efgh ijkl mnop qrst uvwx cute',
'cats abcd efgh ijkl mnop dogs cute',
'cats abcd efgh ijkl mnop cute',
'cats abcd efgh ijkl cute',
'cats abcd efgh cute',
'cats abcd cute',
'cats cute'
].forEach((item, id) => {
index.add(id, item);
});
let result = index.search("at ut");
expect(result.length).to.equal(7);
expect(result).to.eql([6, 5, 4, 3, 2, 1, 0]);
result = index.search("ut at");
expect(result.length).to.equal(7);
expect(result).to.eql([6, 5, 4, 3, 2, 1, 0]);
result = index.search("cute");
expect(result).to.eql([6, 5, 4, 3, 2, 1, 0]);
});
});
describe("Search: Suggestion", function(){
it("Should have been provide suggestions properly", function(){
const index = new Index({ tokenize: "forward" });
[ 'cats abcd efgh ijkl mnop qrst uvwx cute',
'cats abcd efgh ijkl mnop dogs cute', // <-- dogs
'cats abcd efgh ijkl mnop cute',
'cats abcd efgh ijkl cute',
'cats abcd efgh cute',
'cats abcd cute',
'cats cute'
].forEach((item, id) => {
index.add(id, item);
});
let result = index.search("cute dog or cute cat or nothing", { suggest: true });
expect(result.length).to.equal(7);
expect(result).to.eql([1, 6, 5, 4, 3, 2, 0]);
result = index.search("nothing or cute cat or cute dog", { suggest: true });
expect(result.length).to.equal(7);
expect(result).to.eql([1, 6, 5, 4, 3, 2, 0]);
result = index.search("cute");
expect(result).to.eql([6, 5, 4, 3, 2, 1, 0]);
});
});
describe("Update (Sync)", function(){
it("Should have been updated to the index", function(){
const index = new Index({
fastupdate: true,
tokenize: "reverse"
});
index.add(1, "foo");
index.add(2, "bar");
index.add(3, "foobar");
index.update(1, "bar");
index.update(2, "foobar");
index.update(3, "foo");
expect(index.reg.size).to.equal(3);
expect(index.search("foo")).to.eql([2, 3]);
expect(index.search("bar")).to.eql([1, 2]);
expect(index.search("bar")).to.not.include(3);
expect(index.search("foobar")).to.eql([2]);
index.update(1, "bar");
index.update(2, "foobar");
index.update(3, "foo");
index.update(4, "new");
index.update(5, "foo");
index.update(5);
index.update(6, "foo");
index.update(6, null);
index.update(7, "foo");
index.update(7, false);
expect(index.reg.size).to.equal(4);
expect(index.search("foo")).to.eql([2, 3]);
expect(index.search("bar")).to.eql([1, 2]);
expect(index.search("bar")).to.not.include(3);
expect(index.search("foobar")).to.eql([2]);
expect(index.search("new")).to.eql([4]);
});
it("Should not have been updated to the index", function(){
const index = new Index({ tokenize: "bidirectional" });
index.add(1, "bar");
index.add(2, "foobar");
index.add(3, "foo");
index.update("foo");
index.update(null, "foobar");
index.update(void 0, "foobar");
expect(index.reg.size).to.equal(3);
expect(index.search("foo")).to.eql([2, 3]);
expect(index.search("bar")).to.eql([1, 2]);
expect(index.search("bar")).to.not.include(3);
expect(index.search("foobar")).to.eql([2]);
});
});
describe("Remove (Sync)", function(){
it("Should have been removed from the index", function(){
const index = new Index({
fastupdate: true,
tokenize: "reverse"
});
index.add(1, "bar");
index.add(2, "foobar");
index.add(3, "foo");
index.remove(2);
index.remove(1);
index.remove(3);
index.remove(4);
expect(index.reg.size).to.equal(0);
expect(index.search("foo")).to.have.lengthOf(0);
expect(index.search("bar")).to.have.lengthOf(0);
expect(index.search("foobar")).to.have.lengthOf(0);
});
});
describe("Reserved Words", function(){
it("Should have reserved properties taken into account", function(){
const index = new Index({
encode: function(str){ return [str]; },
tokenize: "strict"
});
let array = Object.getOwnPropertyNames({}.__proto__);
array = array.concat(Object.getOwnPropertyNames(index));
array = array.concat(Object.getOwnPropertyNames(index.map));
array.includes("prototype") || array.push("prototype");
array.includes("constructor") || array.push("constructor");
array.includes("__proto__") || array.push("__proto__");
array.includes("concat") || array.push("concat");
array.includes("hasOwnProperty") || array.push("hasOwnProperty");
array.includes("length") || array.push("length");
array.includes("ctx") || array.push("ctx");
for(let i = 0; i < array.length; i++){
index.add(i, array[i]);
}
for(let i = 0; i < array.length; i++){
expect(index.search(array[i])).to.eql([i]);
}
});
});
describe("Presets", function(){
it("Should have been properly initialized", function(){
expect(Index("memory").resolution).to.equal(1);
expect(Index("performance").resolution).to.equal(3);
expect(Index("match").resolution).to.equal(9);
expect(Index("score").resolution).to.equal(9);
expect(Index("default").resolution).to.equal(9);
});
it("Should have been properly extended", function(){
let index = Index({ preset: "performance" });
index.add(0, "foobar");
expect(index.search("bar")).to.have.lengthOf(0);
index = Index({
preset: "performance",
tokenize: "reverse"
});
index.add(0, "foobar");
expect(index.search("bar")).to.eql([0]);
index = Index("match");
index.add(0, "foobar");
expect(index.search("foo")).to.eql([0]);
});
});