mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-08-03 19:17:07 -04:00
378 lines
14 KiB
TypeScript
378 lines
14 KiB
TypeScript
import { beforeEach, describe, expect, jest, test } from '@jest/globals';
|
||
import { Translator } from '../src/translator.js';
|
||
import type { NullPronounsConfig } from '../locale/config.ts';
|
||
|
||
const translations = {
|
||
pronouns: {
|
||
slashes: {
|
||
plural: 'plural',
|
||
pluralHonorific: 'plural-honorific',
|
||
description: 'description',
|
||
},
|
||
},
|
||
};
|
||
const translator = new Translator(translations, translations, []);
|
||
|
||
// workaround to be independent of the current selected locale
|
||
jest.unstable_mockModule('../data/pronouns/morphemes.js', () => {
|
||
return {
|
||
default: ['pronoun_subject', 'pronoun_object', 'possessive_determiner', 'possessive_pronoun', 'reflexive'],
|
||
};
|
||
});
|
||
|
||
const { Pronoun } = await import('../src/classes.ts');
|
||
const { buildPronoun } = await import('../src/buildPronoun.ts');
|
||
const { default: pronouns, generated: generatedPronouns } = await import('./fixtures/pronouns.ts');
|
||
|
||
beforeEach(() => {
|
||
global.config.pronouns = {
|
||
enabled: true,
|
||
route: 'pronouns',
|
||
default: 'he',
|
||
any: 'any',
|
||
plurals: true,
|
||
honorifics: false,
|
||
multiple: {
|
||
name: 'Interchangeable forms',
|
||
description: '…',
|
||
examples: ['he&she'],
|
||
},
|
||
null: false,
|
||
emoji: false,
|
||
};
|
||
});
|
||
|
||
test('finds pronouns by canonical name', () => {
|
||
const actual = expect(buildPronoun(pronouns, 'they', translator));
|
||
actual.toBeDefined();
|
||
actual.toBe(pronouns.they);
|
||
});
|
||
|
||
test('finds pronouns by alias', () => {
|
||
const actual = expect(buildPronoun(pronouns, 'they/them', translator));
|
||
actual.toBeDefined();
|
||
actual.toBe(pronouns.they);
|
||
});
|
||
|
||
describe('when configured that emojiself pronouns are available', () => {
|
||
beforeEach(() => {
|
||
global.config.pronouns.emoji = {
|
||
description: 'Emojiself pronouns',
|
||
history: 'Emojiself pronouns are intended for online communication and not supposed to be pronounced',
|
||
morphemes: {
|
||
pronoun_subject: '#',
|
||
pronoun_object: '#',
|
||
possessive_determiner: '#\'s',
|
||
possessive_pronoun: '#\'s',
|
||
reflexive: '#self',
|
||
},
|
||
examples: ['💫', '💙'],
|
||
template: '…',
|
||
};
|
||
});
|
||
|
||
test('builds pronouns from emoji', () => {
|
||
const actual = expect(buildPronoun(pronouns, '💙', translator));
|
||
actual.toBeDefined();
|
||
actual.toEqual(new Pronoun(
|
||
'💙',
|
||
'Emojiself pronouns',
|
||
false,
|
||
{
|
||
pronoun_subject: '💙',
|
||
pronoun_object: '💙',
|
||
possessive_determiner: '💙\'s',
|
||
possessive_pronoun: '💙\'s',
|
||
reflexive: '💙self',
|
||
},
|
||
[false],
|
||
[false],
|
||
[],
|
||
'Emojiself pronouns are intended for online communication and not supposed to be pronounced@__generator__',
|
||
false,
|
||
));
|
||
});
|
||
});
|
||
|
||
describe('when configured that null pronouns are available', () => {
|
||
const nullPronounsConfig: NullPronounsConfig = {
|
||
description: 'Avoiding gendered forms',
|
||
history: 'Some people prefer not using any pronouns',
|
||
morphemes: {
|
||
pronoun_subject: '#',
|
||
pronoun_object: '#',
|
||
possessive_determiner: '#\'s',
|
||
possessive_pronoun: '#\'s',
|
||
reflexive: '#self',
|
||
},
|
||
examples: [':S'],
|
||
template: '…',
|
||
};
|
||
|
||
beforeEach(() => {
|
||
global.config.pronouns.null = nullPronounsConfig;
|
||
});
|
||
|
||
test('builds pronouns from name', () => {
|
||
const actual = expect(buildPronoun(pronouns, ':S', translator));
|
||
actual.toBeDefined();
|
||
actual.toEqual(new Pronoun(
|
||
'S',
|
||
'Avoiding gendered forms',
|
||
false,
|
||
{
|
||
pronoun_subject: 'S',
|
||
pronoun_object: 'S',
|
||
possessive_determiner: 'S\'s',
|
||
possessive_pronoun: 'S\'s',
|
||
reflexive: 'Sself',
|
||
},
|
||
[false],
|
||
[false],
|
||
[],
|
||
'Some people prefer not using any pronouns@__generator__',
|
||
false,
|
||
));
|
||
});
|
||
test('builds nothing if name too long', () => {
|
||
expect(buildPronoun(pronouns, ':Abcdefghijklmnopqrstuvwxyz', translator)).toBeNull();
|
||
});
|
||
|
||
describe('with conditional placeholders', () => {
|
||
beforeEach(() => {
|
||
nullPronounsConfig.morphemes!.possessive_pronoun = '#/[sxzß]$/i#’|#s';
|
||
});
|
||
|
||
test.each(['S', 'Ringelnatz', 'Max', 'X'])('builds morpheme conditionally if name matches', (name) => {
|
||
expect(buildPronoun(pronouns, `:${name}`, translator)!.morphemes.possessive_pronoun).toBe(`${name}’`);
|
||
});
|
||
test.each(['Sofi', 'Xavier'])('builds morpheme by default if name does not match', (name) => {
|
||
expect(buildPronoun(pronouns, `:${name}`, translator)!.morphemes.possessive_pronoun).toBe(`${name}s`);
|
||
});
|
||
});
|
||
|
||
describe('when some morphemes are not defined in template', () => {
|
||
beforeEach(() => {
|
||
nullPronounsConfig.morphemes = {
|
||
pronoun_subject: '#',
|
||
pronoun_object: '#',
|
||
possessive_determiner: '#\'s',
|
||
possessive_pronoun: '#\'s',
|
||
};
|
||
});
|
||
test('they become null', () => {
|
||
const actual = expect(buildPronoun(pronouns, ':S', translator));
|
||
actual.toBeDefined();
|
||
actual.toEqual(new Pronoun(
|
||
'S',
|
||
'Avoiding gendered forms',
|
||
false,
|
||
{
|
||
pronoun_subject: 'S',
|
||
pronoun_object: 'S',
|
||
possessive_determiner: 'S\'s',
|
||
possessive_pronoun: 'S\'s',
|
||
reflexive: null,
|
||
},
|
||
[false],
|
||
[false],
|
||
[],
|
||
'Some people prefer not using any pronouns@__generator__',
|
||
false,
|
||
));
|
||
});
|
||
});
|
||
});
|
||
|
||
describe('when configured that slashes contain all morphemes', () => {
|
||
beforeEach(() => {
|
||
global.config.pronouns.honorifics = true;
|
||
global.config.pronouns.slashes = true;
|
||
});
|
||
|
||
test('builds generated pronoun from all morphemes', () => {
|
||
const actual = expect(buildPronoun(pronouns, 'ae/aer/aer/aers/aerself', translator));
|
||
actual.toBeDefined();
|
||
actual.toEqual(generatedPronouns.aer);
|
||
});
|
||
test('unescapes morphemes', () => {
|
||
const actual = expect(buildPronoun(pronouns, 's`/he/hir/hir/hirs/hirself', translator));
|
||
actual.toBeDefined();
|
||
actual.toEqual(generatedPronouns.sSlashHe);
|
||
});
|
||
test('builds generated pronoun from all required morphemes and plural modifier', () => {
|
||
const actual = expect(buildPronoun(pronouns, 'ae/aer/aer/aers/aerselves/:plural', translator));
|
||
actual.toBeDefined();
|
||
actual.toEqual(generatedPronouns.aerPlural);
|
||
});
|
||
test('builds generated pronoun from all required morphemes and plural honorific modifier', () => {
|
||
const actual = expect(buildPronoun(pronouns, 'ae/aer/aer/aers/aerselves/:plural-honorific', translator));
|
||
actual.toBeDefined();
|
||
actual.toEqual(generatedPronouns.aerPluralHonorific);
|
||
});
|
||
test('builds generated pronoun from all required morphemes and description', () => {
|
||
const actual = expect(buildPronoun(
|
||
pronouns,
|
||
'ae/aer/aer/aers/aerself/:description=Neopronoun “ae” `/ “æ”',
|
||
translator,
|
||
));
|
||
actual.toBeDefined();
|
||
actual.toEqual(generatedPronouns.aerWithDescription);
|
||
});
|
||
test('builds generated pronoun from all required morphemes and modifiers', () => {
|
||
const actual = expect(buildPronoun(
|
||
pronouns,
|
||
'ae/aer/:description=Neopronoun “ae” `/ “æ”/:plural/aer/aers/aerselves',
|
||
translator,
|
||
));
|
||
actual.toBeDefined();
|
||
actual.toEqual(generatedPronouns.aerPluralWithDescription);
|
||
});
|
||
test('builds generated pronoun with some morphemes empty', () => {
|
||
const actual = expect(buildPronoun(pronouns, 'ae/aer/aer/ /aerself', translator));
|
||
actual.toBeDefined();
|
||
actual.toEqual(generatedPronouns.aerWithEmptyPossessivePronoun);
|
||
});
|
||
test('builds generated pronoun with morpheme at end empty', () => {
|
||
const actual = expect(buildPronoun(pronouns, 'ae/aer/aer/aers/', translator));
|
||
actual.toBeDefined();
|
||
actual.toEqual(generatedPronouns.aerWithEmptyReflexive);
|
||
});
|
||
test('builds generated pronoun with some morphemes unset', () => {
|
||
const actual = expect(buildPronoun(pronouns, 'ae/aer/aer/~/aerself', translator));
|
||
actual.toBeDefined();
|
||
actual.toEqual(generatedPronouns.aerWithUnsetPossessivePronoun);
|
||
});
|
||
test('builds nothing if morphemes are missing', () => {
|
||
expect(buildPronoun(pronouns, 'ae/aer/aer/aerself', translator)).toBeNull();
|
||
});
|
||
test('builds nothing if too many morphemes are given', () => {
|
||
expect(buildPronoun(pronouns, 'ae/aer/aer/aers/aerself/aer', translator)).toBeNull();
|
||
});
|
||
test('builds nothing if description too long', () => {
|
||
expect(buildPronoun(
|
||
pronouns,
|
||
'ae/aer/aer/aers/aerself/:description=Neopronoun “ae” `/ “æ” which is my favorite so you should use it too',
|
||
translator,
|
||
)).toBeNull();
|
||
});
|
||
});
|
||
describe('when configured that slashes contain some morphemes', () => {
|
||
beforeEach(() => {
|
||
global.config.pronouns.slashes = ['pronoun_subject', 'pronoun_object', 'possessive_determiner', 'reflexive'];
|
||
});
|
||
|
||
test('builds generated pronoun from all required morphemes', () => {
|
||
const actual = expect(buildPronoun(pronouns, 'ae/aer/aer/aerself', translator));
|
||
actual.toBeDefined();
|
||
actual.toEqual(generatedPronouns.aerWithUnsetPossessivePronoun);
|
||
});
|
||
test('builds nothing if morphemes are missing', () => {
|
||
expect(buildPronoun(pronouns, 'ae/aer/aer', translator)).toBeNull();
|
||
});
|
||
test('builds nothing if too many morphemes are given', () => {
|
||
expect(buildPronoun(pronouns, 'ae/aer/aer/aers/aerself', translator)).toBeNull();
|
||
});
|
||
});
|
||
describe('when configured that slashes cannot contain morphemes', () => {
|
||
beforeEach(() => {
|
||
global.config.pronouns.slashes = false;
|
||
});
|
||
|
||
const pathBase = 'ae/aer/aer/aers/aerself/aer';
|
||
|
||
test.each([3, 4, 5, 6])('builds nothing if %d morphemes are given', (count) => {
|
||
const path = pathBase.split('/').slice(0, count)
|
||
.join('/');
|
||
expect(buildPronoun(pronouns, path.slice(0, count), translator)).toBeUndefined();
|
||
});
|
||
});
|
||
|
||
describe('building generated pronouns from commas', () => {
|
||
test('succeeds with all parts present', () => {
|
||
const actual = expect(buildPronoun(pronouns, 'ae,aer,aer,aers,aerself,0,', translator));
|
||
actual.toBeDefined();
|
||
actual.toEqual(generatedPronouns.aer);
|
||
});
|
||
test('succeeds with description missing present', () => {
|
||
const actual = expect(buildPronoun(pronouns, 'ae,aer,aer,aers,aerself,0', translator));
|
||
actual.toBeDefined();
|
||
actual.toEqual(generatedPronouns.aer);
|
||
});
|
||
test('succeeds with base pronoun and some custom morphemes', () => {
|
||
const actual = expect(buildPronoun(pronouns, 'they,!2,aers,!2,', translator));
|
||
actual.toBeDefined();
|
||
actual.toEqual(new Pronoun(
|
||
'they/them',
|
||
'',
|
||
false,
|
||
{
|
||
pronoun_subject: 'they',
|
||
pronoun_object: 'them',
|
||
possessive_determiner: 'their',
|
||
possessive_pronoun: 'aers',
|
||
reflexive: 'themselves',
|
||
},
|
||
[true],
|
||
[false],
|
||
[],
|
||
'__generator__',
|
||
false,
|
||
));
|
||
});
|
||
test('fails when too few parts are given', () => {
|
||
expect(buildPronoun(pronouns, 'ae, translator,aer,aer,aers,aerself', translator)).toBeNull();
|
||
});
|
||
test('fails when many few parts are given', () => {
|
||
expect(buildPronoun(pronouns, 'ae, translator,aer,aer,aers,aerself,aersing,0,', translator)).toBeNull();
|
||
});
|
||
test('fails when base pronoun is unknown', () => {
|
||
expect(buildPronoun(pronouns, 's/he, translator,!2,aers,!2,', translator)).toBeNull();
|
||
});
|
||
});
|
||
|
||
describe('builds interchangable pronouns from ampersand', () => {
|
||
test('two interchangable pronouns', () => {
|
||
const actual = expect(buildPronoun(pronouns, 'he&she', translator));
|
||
actual.toBeDefined();
|
||
actual.toEqual(new Pronoun(
|
||
'he&she',
|
||
['Normative “he/him”', 'Normative “she/her”'],
|
||
true,
|
||
{
|
||
pronoun_subject: 'he&she',
|
||
pronoun_object: 'him&her',
|
||
possessive_determiner: 'his&her',
|
||
possessive_pronoun: 'his&hers',
|
||
reflexive: 'himself&herself',
|
||
},
|
||
[false, false],
|
||
[false, false],
|
||
[],
|
||
'',
|
||
false,
|
||
));
|
||
});
|
||
test('three interchangable pronouns', () => {
|
||
const actual = expect(buildPronoun(pronouns, 'he&she&they', translator));
|
||
actual.toBeDefined();
|
||
actual.toEqual(new Pronoun(
|
||
'he&she&they',
|
||
['Normative “he/him”', 'Normative “she/her”', 'Singular “they”'],
|
||
true,
|
||
{
|
||
pronoun_subject: 'he&she&they',
|
||
pronoun_object: 'him&her&them',
|
||
possessive_determiner: 'his&her&their',
|
||
possessive_pronoun: 'his&hers&theirs',
|
||
reflexive: 'himself&herself&themselves',
|
||
},
|
||
[false, false, true],
|
||
[false, false, true],
|
||
[],
|
||
'',
|
||
false,
|
||
));
|
||
});
|
||
});
|