45 lines · 2.3 KB
import { describe, expect, test } from "bun:test";
import { compileQuery, matchLines, requiredLiteral } from "./text-search";

describe("workspace text search", () => {
  test("literal patterns are escaped and case-insensitive unless asked", () => {
    const content = "const a = foo.bar();\nFOO.BAR\nfooXbar";
    expect(matchLines(content, compileQuery({ pattern: "foo.bar" }), 10)).toEqual([
      { line: 0, text: "const a = foo.bar();", ranges: [[10, 17]] },
      { line: 1, text: "FOO.BAR", ranges: [[0, 7]] },
    ]);
    expect(matchLines(content, compileQuery({ pattern: "foo.bar", isCaseSensitive: true }), 10)).toHaveLength(1);
  });

  test("regular expressions, whole words, every match on a line, and the limit", () => {
    const content = "cat concat cat\ndog\ncat";
    expect(matchLines(content, compileQuery({ pattern: "cat", isWordMatch: true }), 10)[0].ranges).toEqual([
      [0, 3],
      [11, 14],
    ]);
    expect(matchLines(content, compileQuery({ pattern: "^d.g$", isRegExp: true }), 10)).toEqual([
      { line: 1, text: "dog", ranges: [[0, 3]] },
    ]);
    expect(matchLines(content, compileQuery({ pattern: "cat" }), 1)).toHaveLength(1);
    expect(matchLines("abc", compileQuery({ pattern: "x*", isRegExp: true }), 10)).toEqual([]);
    expect(() => compileQuery({ pattern: "(", isRegExp: true })).toThrow();
  });
});

describe("index prefilter literal", () => {
  test("literal patterns are their own prefilter once long enough", () => {
    expect(requiredLiteral({ pattern: "foo.bar" })).toBe("foo.bar");
    expect(requiredLiteral({ pattern: "ab" })).toBeNull();
  });

  test("regexes yield only substrings every match must contain", () => {
    expect(requiredLiteral({ pattern: "function\\s+handle\\w*Request", isRegExp: true })).toBe("function");
    expect(requiredLiteral({ pattern: "colou?r_name", isRegExp: true })).toBe("r_name");
    expect(requiredLiteral({ pattern: "import\\.meta", isRegExp: true })).toBe("import.meta");
    expect(requiredLiteral({ pattern: "[abc]+xyz(opt)?tail", isRegExp: true })).toBe("tail");
    expect(requiredLiteral({ pattern: "foo|barbaz", isRegExp: true })).toBeNull();