misskey/packages/backend/test/unit/misc/search-query.ts

227 lines
6.7 KiB
TypeScript

/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { describe, expect, test } from '@jest/globals';
import { SearchCondition, parseSearchString } from '@/misc/search-query.js';
describe('misc:search-query', () => {
test('simple word', () => {
const q = 'word';
const condition: SearchCondition = { type: 'contains', value: 'word' };
expect(parseSearchString(q)).toStrictEqual(condition);
});
test('simple quoted word', () => {
const q = '"word + word - word OR word"';
const condition: SearchCondition = { type: 'contains', value: 'word + word - word or word' };
expect(parseSearchString(q)).toStrictEqual(condition);
});
test('simple and', () => {
const q = 'word1 word2 + word3+word4';
const condition: SearchCondition = {
type: 'and',
subConditions: [
{ type: 'contains', value: 'word1' },
{ type: 'contains', value: 'word2' },
{ type: 'contains', value: 'word3' },
{ type: 'contains', value: 'word4' },
],
};
expect(parseSearchString(q)).toStrictEqual(condition);
});
test('simple or', () => {
const q = 'word1 OR word2 OR word3 OR word4';
const condition: SearchCondition = {
type: 'or',
subConditions: [
{ type: 'contains', value: 'word1' },
{ type: 'contains', value: 'word2' },
{ type: 'contains', value: 'word3' },
{ type: 'contains', value: 'word4' },
],
};
expect(parseSearchString(q)).toStrictEqual(condition);
});
test('simple not', () => {
const q = 'word1 - word2';
const condition: SearchCondition = {
type: 'and',
subConditions: [
{ type: 'contains', value: 'word1' },
{ type: 'not_contains', value: 'word2' },
],
};
expect(parseSearchString(q)).toStrictEqual(condition);
});
test('simple and/or/not - left-associative', () => {
const q = 'word1 word2 OR word3 - word4';
const condition: SearchCondition = {
type: 'and',
subConditions: [
{ type: 'or', subConditions: [
{ type: 'and', subConditions: [
{ type: 'contains', value: 'word1' },
{ type: 'contains', value: 'word2' },
] },
{ type: 'contains', value: 'word3' },
] },
{ type: 'not_contains', value: 'word4' },
],
};
expect(parseSearchString(q)).toStrictEqual(condition);
});
test('brackets', () => {
const q = 'word1 (word2 OR word3)';
const condition: SearchCondition = {
type: 'and',
subConditions: [
{ type: 'contains', value: 'word1' },
{ type: 'or', subConditions: [
{ type: 'contains', value: 'word2' },
{ type: 'contains', value: 'word3' },
] },
],
};
expect(parseSearchString(q)).toStrictEqual(condition);
});
test('brackets - nested', () => {
const q = 'word1 (word2 OR (word3 -word4))';
const condition: SearchCondition = {
type: 'and',
subConditions: [
{ type: 'contains', value: 'word1' },
{ type: 'or', subConditions: [
{ type: 'contains', value: 'word2' },
{ type: 'and', subConditions: [
{ type: 'contains', value: 'word3' },
{ type: 'not_contains', value: 'word4' },
] },
] },
],
};
expect(parseSearchString(q)).toStrictEqual(condition);
});
test('brackets with not', () => {
const q = 'word1 -(word2 OR (word3 word4))';
const condition: SearchCondition = {
type: 'and',
subConditions: [
{ type: 'contains', value: 'word1' },
{ type: 'not_contains', value: 'word2' },
{ type: 'or', subConditions: [
{ type: 'not_contains', value: 'word3' },
{ type: 'not_contains', value: 'word4' },
] },
],
};
expect(parseSearchString(q)).toStrictEqual(condition);
});
test('unclosed brackets', () => {
const q = 'word1 (word2 OR word3';
const condition: SearchCondition = { type: 'and', subConditions: [
{ type: 'contains', value: 'word1' },
{ type: 'or', subConditions: [
{ type: 'contains', value: 'word2' },
{ type: 'contains', value: 'word3' },
] },
] };
expect(parseSearchString(q)).toStrictEqual(condition);
});
test('overclosed brackets', () => {
const q = '(word1 OR word2)) word3';
const condition: SearchCondition = { type: 'and', subConditions: [
{ type: 'or', subConditions: [
{ type: 'contains', value: 'word1' },
{ type: 'contains', value: 'word2' },
] },
{ type: 'contains', value: 'word3' },
] };
expect(parseSearchString(q)).toStrictEqual(condition);
});
test('empty string', () => {
const q = '';
const condition: SearchCondition = { type: 'empty' };
expect(parseSearchString(q)).toStrictEqual(condition);
});
test('empty brackets', () => {
const q = 'word1 () word2';
const condition: SearchCondition = { type: 'and', subConditions: [
{ type: 'contains', value: 'word1' },
{ type: 'contains', value: 'word2' },
] };
expect(parseSearchString(q)).toStrictEqual(condition);
});
test('empty brackets with not', () => {
const q = 'word1 -() word2';
const condition: SearchCondition = { type: 'and', subConditions: [
{ type: 'contains', value: 'word1' },
{ type: 'contains', value: 'word2' },
] };
expect(parseSearchString(q)).toStrictEqual(condition);
});
test('empty brackets with or', () => {
const q = 'word1 OR() word2';
const condition: SearchCondition = { type: 'and', subConditions: [
{ type: 'contains', value: 'word1' },
{ type: 'contains', value: 'word2' },
] };
expect(parseSearchString(q)).toStrictEqual(condition);
});
test('unclosed quoted word', () => {
const q = '"word';
const condition: SearchCondition = { type: 'contains', value: 'word' };
expect(parseSearchString(q)).toStrictEqual(condition);
});
test('escaped characters', () => {
const q = 'word\\- word\\+ word\\( word\\\\';
const condition: SearchCondition = { type: 'and', subConditions: [
{ type: 'contains', value: 'word-' },
{ type: 'contains', value: 'word+' },
{ type: 'contains', value: 'word(' },
{ type: 'contains', value: 'word\\' },
] };
expect(parseSearchString(q)).toStrictEqual(condition);
});
test('redundant conditions AND', () => {
const q = 'abc abc ab';
const condition: SearchCondition = { type: 'contains', value: 'abc' };
expect(parseSearchString(q)).toStrictEqual(condition);
});
test('redundant conditions OR', () => {
const q = 'abc OR abc OR ab';
const condition: SearchCondition = { type: 'contains', value: 'ab' };
expect(parseSearchString(q)).toStrictEqual(condition);
});
test('redundant conditions complex AND', () => {
const q = 'abab (abc OR ab)';
const condition: SearchCondition = { type: 'contains', value: 'abab' };
expect(parseSearchString(q)).toStrictEqual(condition);
});
test('redundant conditions complex OR', () => {
const q = 'abcde OR (abc ab)';
const condition: SearchCondition = { type: 'contains', value: 'abc' };
expect(parseSearchString(q)).toStrictEqual(condition);
});
});