Entkopple Partnersuche vom Altersabstand und entferne garantierte Schwangerschaften
All checks were successful
Deploy to production / deploy (push) Successful in 2m41s

This commit is contained in:
Torsten Schulz (local)
2026-11-04 15:09:49 +01:00
parent 0178d33a21
commit 6e31a114cf
4 changed files with 98 additions and 148 deletions

View File

@@ -1,9 +1,10 @@
import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
import test from 'node:test';
import { Sequelize } from 'sequelize';
import { Sequelize, DataTypes } from 'sequelize';
import migration from '../migrations-active/20261104000000-add-character-development-ages.cjs';
import { getCharacterDevelopment, hasReachedFertility } from '../utils/falukant/characterDevelopment.js';
import { buildPartnerCandidateQuery } from '../utils/falukant/partnerCandidates.js';
test('development follows each character, independently of the marriage age', () => {
const early = { pubertyStartAge: 10, fertileFromAge: 13 };
@@ -71,6 +72,25 @@ test('database migration, persistence and daemon conception paths', {
await assert.rejects(db.query(`INSERT INTO falukant_data.character
(puberty_start_age, fertile_from_age) VALUES (12, 11)`));
await t.test('partner candidates have a minimum age without age-gap or creation-age restrictions', async () => {
const [inserted] = await db.query(`INSERT INTO falukant_data.character (gender, birthdate)
VALUES ('male', CURRENT_DATE - INTERVAL '65 days'),
('male', CURRENT_DATE - INTERVAL '10 days' + INTERVAL '12 hours'),
('male', CURRENT_DATE - INTERVAL '9 days')
RETURNING id`);
const Candidate = db.define('DevelopmentPartnerCandidate', {
id: { type: DataTypes.INTEGER, primaryKey: true },
gender: DataTypes.STRING,
birthdate: DataTypes.DATE,
regionId: { type: DataTypes.INTEGER, field: 'region_id' },
titleOfNobility: { type: DataTypes.INTEGER, field: 'title_of_nobility' },
}, { schema: 'falukant_data', tableName: 'character', timestamps: false });
const rows = await Candidate.findAll(buildPartnerCandidateQuery({
characterId: 1, gender: 'female', regionId: 1, titleId: 1, minimumAge: 10,
}));
assert.deepEqual(rows.map(c => c.id).sort((a, b) => a - b), [inserted[0].id, inserted[1].id]);
});
await t.test('repeating the migration preserves all existing character data', async () => {
const [saved] = await db.query('SELECT * FROM falukant_data.character ORDER BY id');
await migration.up(qi);
@@ -100,11 +120,11 @@ test('database migration, persistence and daemon conception paths', {
skip: !process.env.DAEMON_SQL_PATH,
}, async (t) => {
const source = await readFile(process.env.DAEMON_SQL_PATH, 'utf8');
const sql = (name) => {
const sql = (name, randomRoll = 0) => {
const match = source.match(new RegExp(`pub const ${name}: &str = r#"([\\s\\S]*?)"#;`));
assert.ok(match, name);
// Remove chance from these eligibility tests only.
return match[1].replaceAll('random()', '0.0');
return match[1].replaceAll('random()', `${randomRoll}::double precision`);
};
await db.query(`
TRUNCATE falukant_data.character RESTART IDENTITY;
@@ -154,6 +174,29 @@ test('database migration, persistence and daemon conception paths', {
}
}
}
await t.test('marriage, engagement and every lover role use exactly fifty percent', async () => {
for (const [name, type, role] of [
['QUERY_TRY_MARRIAGE_CONCEPTION_UPDATE', 1, null],
['QUERY_GET_LEGACY_MARRIAGE_INSTANT_PREGNANCY_CANDIDATES', 1, null],
['QUERY_GET_LOVER_PREGNANCY_CANDIDATES', 3, null],
...['secret_affair', 'lover', 'mistress_or_favorite'].map(role => ['QUERY_GET_LOVER_PREGNANCY_CANDIDATES', 2, role]),
]) {
for (const [roll, expected] of [[0.499, true], [0.5, false], [0.99, false]]) {
await db.query(`UPDATE falukant_data.character SET birthdate = CURRENT_DATE - INTERVAL '20 days', pregnancy_due_at = NULL;
UPDATE falukant_data.relationship SET relationship_type_id = :type, marriage_pregnancy_due_at = NULL;
UPDATE falukant_data.relationship_state SET lover_role = :role, affection = 80, visibility = 80`, {
replacements: { type, role },
});
const [rows] = await db.query(sql(name, roll));
if (name === 'QUERY_TRY_MARRIAGE_CONCEPTION_UPDATE') {
const [[row]] = await db.query('SELECT marriage_pregnancy_due_at FROM falukant_data.relationship');
assert.equal(row.marriage_pregnancy_due_at != null, expected, `${name}/${role}/${roll}`);
} else {
assert.equal(rows.length > 0, expected, `${name}/${role}/${roll}`);
}
}
}
});
await t.test('engaged couples need no lover maintenance and retain their relationship', async () => {
const candidates = () => db.query(sql('QUERY_GET_LOVER_PREGNANCY_CANDIDATES')).then(([rows]) => rows);
await db.query(`UPDATE falukant_data.character SET birthdate = CURRENT_DATE - INTERVAL '13 days',