philomena/assets/js/query/__tests__/parse.spec.ts
liamwhite 3590be1429
match_query: unit test and rewrite for TypeScript (#208)
* match_query: unit test and rewrite for TypeScript

* match_query: use new type for parse errors

* match_query: avoid exceptional control flow in date parsing
2024-03-18 08:20:47 -04:00

84 lines
2.9 KiB
TypeScript

import { defaultMatcher } from '../matcher';
import { termSpaceToImageField } from '../fields';
import { generateLexArray } from '../lex';
import { getAstMatcherForTerm } from '../term';
import { parseTokens } from '../parse';
function parseWithDefaultMatcher(term: string, fuzz: number) {
return getAstMatcherForTerm(term, fuzz, defaultMatcher);
}
describe('Semantic analysis', () => {
let documents: HTMLElement[];
beforeAll(() => {
const e0 = document.createElement('div');
e0.setAttribute(termSpaceToImageField.id, '0');
e0.setAttribute(termSpaceToImageField.tags, 'safe, solo, fluttershy');
const e1 = document.createElement('div');
e1.setAttribute(termSpaceToImageField.id, '1');
e1.setAttribute(termSpaceToImageField.tags, 'suggestive, solo, fluttershy');
const e2 = document.createElement('div');
e2.setAttribute(termSpaceToImageField.id, '2');
e2.setAttribute(termSpaceToImageField.tags, 'suggestive, fluttershy, twilight sparkle');
documents = [e0, e1, e2];
});
it('should match single term expressions', () => {
const tokens = generateLexArray('fluttershy', parseWithDefaultMatcher);
const matcher = parseTokens(tokens);
expect(matcher(documents[0])).toBe(true);
expect(matcher(documents[1])).toBe(true);
expect(matcher(documents[2])).toBe(true);
});
it('should match AND expressions', () => {
const tokens = generateLexArray('fluttershy,solo', parseWithDefaultMatcher);
const matcher = parseTokens(tokens);
expect(matcher(documents[0])).toBe(true);
expect(matcher(documents[1])).toBe(true);
expect(matcher(documents[2])).toBe(false);
});
it('should match OR expressions', () => {
const tokens = generateLexArray('suggestive || twilight sparkle', parseWithDefaultMatcher);
const matcher = parseTokens(tokens);
expect(matcher(documents[0])).toBe(false);
expect(matcher(documents[1])).toBe(true);
expect(matcher(documents[2])).toBe(true);
});
it('should match NOT expressions', () => {
const tokens = generateLexArray('NOT twilight sparkle', parseWithDefaultMatcher);
const matcher = parseTokens(tokens);
expect(matcher(documents[0])).toBe(true);
expect(matcher(documents[1])).toBe(true);
expect(matcher(documents[2])).toBe(false);
});
it('should allow empty expressions', () => {
const tokens = generateLexArray('', parseWithDefaultMatcher);
const matcher = parseTokens(tokens);
expect(matcher(documents[0])).toBe(false);
expect(matcher(documents[1])).toBe(false);
expect(matcher(documents[2])).toBe(false);
});
it('should throw on unpaired AND', () => {
const tokens = generateLexArray(' AND ', parseWithDefaultMatcher);
expect(() => parseTokens(tokens)).toThrow('Missing operand.');
});
it('should throw on unjoined parenthetical', () => {
const tokens = generateLexArray('(safe) solo', parseWithDefaultMatcher);
expect(() => parseTokens(tokens)).toThrow('Missing operator.');
});
});