1
0
mirror of https://github.com/koloml/philomena-tagging-assistant.git synced 2026-06-23 18:22:20 +00:00

Cover 2 more functions in tag-utils module

This commit is contained in:
2026-06-21 19:19:34 +04:00
parent 51ea806ddc
commit 7af6124278

View File

@@ -1,76 +1,141 @@
import { URL } from 'url';
import { resolveTagNameFromLink, slugEncodedCharacters } from '$lib/philomena/tag-utils';
import {
buildTagsAndAliasesMap,
resolveTagCategoryFromTagName,
resolveTagNameFromLink,
slugEncodedCharacters
} from '$lib/philomena/tag-utils';
import { randomString } from "$tests/utils";
import { namespaceCategories } from "$config/tags";
describe('tag-utils', () => {
const origin = 'https://furbooru.org';
const origin = 'https://furbooru.org';
describe('resolveTagNameFromLink', () => {
function resolveFromSearchQuery(encodedQuery: string): string | null {
return resolveTagNameFromLink(new URL(`/search?q=${encodedQuery}`, origin));
}
describe('buildTagsAndAliasesMap', () => {
it('should return regular tags if both real and real+alias tags are the same', () => {
const tagsAndAliases = ['avali', 'experiment (casualties unknown)', 'fictional species'];
describe('Parsing from /search/?q=tag links', () => {
it('should resolve a single tag from /search URLs', () => {
expect(resolveFromSearchQuery('safe')).toBe('safe');
});
it('should return null for queries with multiple comma-separated tags', () => {
// Comma acts as a separator in the query, resulting in multiple tokens
expect(resolveFromSearchQuery('safe, suggestive')).toBe(null);
});
it('should return null if query is empty or not a term', () => {
expect(resolveFromSearchQuery('')).toBe(null);
expect(resolveFromSearchQuery('!')).toBe(null);
});
it('should properly treat parentheses in the query with single tag', () => {
// Parentheses are operators in the query language, but when inside the tag name, they should still be properly
// working.
expect(resolveFromSearchQuery('experiment (casualties unknown)')).toBe('experiment (casualties unknown)');
});
it('should properly resolve queries with encoded characters', () => {
expect(resolveFromSearchQuery('pok%C3%A9mon')).toBe('pokémon');
});
it('should unquote quoted term', () => {
expect(resolveFromSearchQuery('"experiment (casualties unknown)"')).toBe('experiment (casualties unknown)')
expect(resolveFromSearchQuery('"single tag, really"')).toBe('single tag, really');
});
})
describe('Parsing from /tags/name links', () => {
function resolveFromTagLink(encodedTagName: string): string | null {
return resolveTagNameFromLink(new URL(`/tags/${encodedTagName}`, origin));
expect(buildTagsAndAliasesMap(tagsAndAliases, tagsAndAliases)).toMatchInlineSnapshot(`
Map {
"avali" => "avali",
"experiment (casualties unknown)" => "experiment (casualties unknown)",
"fictional species" => "fictional species",
}
`);
});
it('should resolve a single tag', () => {
expect(resolveFromTagLink('safe')).toBe('safe');
});
it('should identify any aliases going after the real tag', () => {
const realTags = ['avali', 'experiment (casualties unknown)', 'fictional species'];
const realAndAliasesTags = ['avali', 'experiment (casualties unknown)', 'experiment (gunsaw)', 'fictional species'];
it('should only read the tag page even if query is provided', () => {
expect(resolveFromTagLink('grotesque?q=explicit')).toBe('grotesque');
});
expect(buildTagsAndAliasesMap(realAndAliasesTags, realTags)).toMatchInlineSnapshot(`
Map {
"avali" => "avali",
"experiment (casualties unknown)" => "experiment (casualties unknown)",
"fictional species" => "fictional species",
"experiment (gunsaw)" => "experiment (casualties unknown)",
}
`);
});
it('should properly resolve links with encoded characters', () => {
expect(resolveFromTagLink('pok%C3%A9mon')).toBe('pokémon');
});
it('should ignore any non-real tags coming before first tag is found', () => {
const outOfOrderTag = randomString();
it('should decoded slug-encoded characters', () => {
// More common example where tag is.
expect(resolveFromTagLink(`namespace-colon-tag+name`)).toBe('namespace:tag name');
const realTags = ['avali', 'experiment (casualties unknown)', 'fictional species'];
const realAndAliasesTags = [outOfOrderTag, 'avali', 'experiment (casualties unknown)', 'experiment (gunsaw)', 'fictional species'];
// Testing the whole list of encoded characters.
for (const [encodedCharacter, decodedCharacter] of slugEncodedCharacters.entries()) {
expect(resolveFromTagLink(`test+symbol${encodedCharacter}without+spaces`)).toBe(`test symbol${decodedCharacter}without spaces`);
expect(resolveFromTagLink(`test+symbol+${encodedCharacter}+with+spaces`)).toBe(`test symbol ${decodedCharacter} with spaces`);
}
});
});
const warn = vi.spyOn(console, 'warn');
it('should return null for unsupported URLs', () => {
expect(resolveTagNameFromLink(new URL('/pages/example', origin))).toBe(null);
});
expect(buildTagsAndAliasesMap(realAndAliasesTags, realTags)).toMatchInlineSnapshot(`
Map {
"avali" => "avali",
"experiment (casualties unknown)" => "experiment (casualties unknown)",
"fictional species" => "fictional species",
"experiment (gunsaw)" => "experiment (casualties unknown)",
}
`);
expect(warn).toHaveBeenCalledWith(`No real tag found for the alias:`, outOfOrderTag);
});
});
describe('resolveTagNameFromLink', () => {
function resolveFromSearchQuery(encodedQuery: string): string | null {
return resolveTagNameFromLink(new URL(`/search?q=${encodedQuery}`, origin));
}
describe('Parsing from /search/?q=tag links', () => {
it('should resolve a single tag from /search URLs', () => {
expect(resolveFromSearchQuery('safe')).toBe('safe');
});
it('should return null for queries with multiple comma-separated tags', () => {
// Comma acts as a separator in the query, resulting in multiple tokens
expect(resolveFromSearchQuery('safe, suggestive')).toBe(null);
});
it('should return null if query is empty or not a term', () => {
expect(resolveFromSearchQuery('')).toBe(null);
expect(resolveFromSearchQuery('!')).toBe(null);
});
it('should properly treat parentheses in the query with single tag', () => {
// Parentheses are operators in the query language, but when inside the tag name, they should still be properly
// working.
expect(resolveFromSearchQuery('experiment (casualties unknown)')).toBe('experiment (casualties unknown)');
});
it('should properly resolve queries with encoded characters', () => {
expect(resolveFromSearchQuery('pok%C3%A9mon')).toBe('pokémon');
});
it('should unquote quoted term', () => {
expect(resolveFromSearchQuery('"experiment (casualties unknown)"')).toBe('experiment (casualties unknown)')
expect(resolveFromSearchQuery('"single tag, really"')).toBe('single tag, really');
});
})
describe('Parsing from /tags/name links', () => {
function resolveFromTagLink(encodedTagName: string): string | null {
return resolveTagNameFromLink(new URL(`/tags/${encodedTagName}`, origin));
}
it('should resolve a single tag', () => {
expect(resolveFromTagLink('safe')).toBe('safe');
});
it('should only read the tag page even if query is provided', () => {
expect(resolveFromTagLink('grotesque?q=explicit')).toBe('grotesque');
});
it('should properly resolve links with encoded characters', () => {
expect(resolveFromTagLink('pok%C3%A9mon')).toBe('pokémon');
});
it('should decoded slug-encoded characters', () => {
// More common example where tag is.
expect(resolveFromTagLink(`namespace-colon-tag+name`)).toBe('namespace:tag name');
// Testing the whole list of encoded characters.
for (const [encodedCharacter, decodedCharacter] of slugEncodedCharacters.entries()) {
expect(resolveFromTagLink(`test+symbol${encodedCharacter}without+spaces`)).toBe(`test symbol${decodedCharacter}without spaces`);
expect(resolveFromTagLink(`test+symbol+${encodedCharacter}+with+spaces`)).toBe(`test symbol ${decodedCharacter} with spaces`);
}
});
});
it('should return null for unsupported URLs', () => {
expect(resolveTagNameFromLink(new URL('/pages/example', origin))).toBe(null);
});
});
describe('resolveTagCategoryFromTagName', () => {
it('should resolve any known namespace into its known category', () => {
for (const [namespace, category] of namespaceCategories) {
expect(resolveTagCategoryFromTagName(`${namespace}:${randomString()}`)).toBe(category);
}
});
it('should ignore any namespace not listed in config', () => {
expect(resolveTagCategoryFromTagName(`${randomString()}:${randomString()}`)).toBeNull();
});
});