PronounsPage/test/buildPronoun.test.ts
2024-03-12 15:11:40 +01:00

378 lines
14 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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,
));
});
});