146 lines
6.0 KiB
JavaScript
146 lines
6.0 KiB
JavaScript
// Generated, do not edit. sha256:85fb028950f59216bdb01fd8cdbb5cd92ec098e018550fd5116c6e26d75ba680
|
|
import { describe, it, before } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
|
|
import { FIELD_POLICY, TABLE_POLICY, fieldClass, strictestClass } from '../../server/ai/policy.js';
|
|
import { openBaselineDb } from '../helpers/baseline-db.mjs';
|
|
import { CONFIG } from '../../shared/config.js';
|
|
|
|
let KOLOMMEN;
|
|
|
|
before(() => {
|
|
const db = openBaselineDb();
|
|
const tabellen = db.prepare(
|
|
`SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%'`
|
|
).all().map(r => r.name);
|
|
KOLOMMEN = new Set();
|
|
for (const t of tabellen) {
|
|
for (const k of db.prepare(`PRAGMA table_info(${t})`).all()) KOLOMMEN.add(k.name);
|
|
}
|
|
});
|
|
|
|
describe('AI-veldbeleid tegen het schema', () => {
|
|
it('classificeert élke kolom uit de baseline', () => {
|
|
const zonder = [...KOLOMMEN].filter(k => fieldClass(k) === null).sort();
|
|
assert.deepEqual(zonder, [],
|
|
`deze kolommen hebben geen klasse in server/ai/policy.js: ${zonder.join(', ')}`);
|
|
});
|
|
|
|
const GEEN_KOLOM = new Set(['portfolio', 'fiatValue']);
|
|
|
|
it('bevat geen regel voor een kolom die niet bestaat', () => {
|
|
const spoken = Object.keys(FIELD_POLICY).filter(k => !KOLOMMEN.has(k) && !GEEN_KOLOM.has(k)).sort();
|
|
assert.deepEqual(spoken, [],
|
|
`deze regels wijzen naar een kolom die niet (meer) bestaat: ${spoken.join(', ')}`);
|
|
});
|
|
|
|
it('houdt de uitzonderingenlijst eerlijk: elk veld erin is ook echt geen kolom', () => {
|
|
const tochKolom = [...GEEN_KOLOM].filter(k => KOLOMMEN.has(k)).sort();
|
|
assert.deepEqual(tochKolom, [],
|
|
`deze staan als uitzondering maar zijn wél een kolom: ${tochKolom.join(', ')}`);
|
|
});
|
|
|
|
it('gebruikt alleen klassen die in CONFIG.AI.FIELD_CLASSES staan', () => {
|
|
const onbekend = [...new Set(Object.values(FIELD_POLICY))]
|
|
.filter(k => !CONFIG.AI.FIELD_CLASSES.includes(k)).sort();
|
|
assert.deepEqual(onbekend, []);
|
|
});
|
|
});
|
|
|
|
describe('AI-veldbeleid: de gevaarlijke velden', () => {
|
|
const KETEN = ['address', 'externalAddress', 'automaticLabel', 'txid', 'transactionHash',
|
|
'blockHeight', 'blockTime', 'chainIndex', 'derivationIndex', 'scriptType'];
|
|
const WEG = ['value', 'rawData', 'settings', 'arguments'];
|
|
|
|
for (const veld of KETEN) {
|
|
it(`${veld} is keten-data en gaat alleen als alias`, () => {
|
|
assert.equal(fieldClass(veld), 'chain');
|
|
});
|
|
}
|
|
|
|
for (const veld of WEG) {
|
|
it(`${veld} verlaat de machine in geen enkele vorm`, () => {
|
|
assert.equal(fieldClass(veld), 'drop');
|
|
});
|
|
}
|
|
|
|
it('laat geen enkele hoeveelheid als plain door', () => {
|
|
for (const veld of ['amount', 'balance', 'balanceSats', 'valueSats', 'feeSats',
|
|
'balanceFound', 'unitFee', 'principalAmount']) {
|
|
assert.equal(fieldClass(veld), 'quantity', `${veld} hoort in de klasse quantity`);
|
|
}
|
|
});
|
|
|
|
it('kent geen enkel veld dat ongedeclareerd tóch een waarde geeft', () => {
|
|
assert.equal(fieldClass('eenNieuweKolomDieNietBestaat'), null);
|
|
assert.equal(fieldClass('constructor'), null);
|
|
assert.equal(fieldClass('toString'), null);
|
|
});
|
|
});
|
|
|
|
describe('AI-veldbeleid: de uitzonderingen per tabel', () => {
|
|
|
|
it('geeft zonder tabel-argument nog steeds de gevoeligste lezing', () => {
|
|
assert.equal(fieldClass('value'), 'drop');
|
|
assert.equal(fieldClass('value', null), 'drop');
|
|
assert.equal(fieldClass('value', 'WalletSource'), 'drop');
|
|
assert.equal(fieldClass('value', 'EenTabelDieNietBestaat'), 'drop');
|
|
});
|
|
|
|
it('past de uitzondering toe voor precies de tabel die hem heeft', () => {
|
|
assert.equal(fieldClass('value', 'Preference'), 'plain');
|
|
assert.equal(fieldClass('Preference.value'), 'plain');
|
|
assert.equal(fieldClass('WalletSource.value'), 'drop');
|
|
});
|
|
|
|
it('kan met een uitzondering geen veld OPENZETTEN dat de basis niet kent', () => {
|
|
assert.equal(fieldClass('eenVeldDatNergensStaat', 'Preference'), null);
|
|
assert.equal(fieldClass('Preference.eenVeldDatNergensStaat'), null);
|
|
assert.equal(fieldClass('constructor', 'Preference'), null);
|
|
});
|
|
|
|
it('noemt in elke uitzondering een tabel en een veld die echt bestaan', () => {
|
|
const tabellen = new Set();
|
|
const db = openBaselineDb();
|
|
for (const r of db.prepare(
|
|
`SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%'`).all()) {
|
|
tabellen.add(r.name);
|
|
}
|
|
for (const [tabel, velden] of Object.entries(TABLE_POLICY)) {
|
|
assert.ok(tabellen.has(tabel), `TABLE_POLICY noemt tabel '${tabel}', die niet bestaat`);
|
|
const kolommen = new Set(db.prepare(`PRAGMA table_info(${tabel})`).all().map(k => k.name));
|
|
for (const [veld, klasse] of Object.entries(velden)) {
|
|
assert.ok(kolommen.has(veld), `${tabel}.${veld} is geen kolom van die tabel`);
|
|
assert.ok(CONFIG.AI.FIELD_CLASSES.includes(klasse), `${tabel}.${veld} heeft een onbekende klasse`);
|
|
assert.ok(Object.hasOwn(FIELD_POLICY, veld),
|
|
`${tabel}.${veld} staat niet in het basisbeleid, dus de uitzondering doet niets`);
|
|
}
|
|
}
|
|
});
|
|
|
|
it('houdt de lijst kort, want elke regel is een plek waar de gevoeligste lezing NIET geldt', () => {
|
|
const regels = Object.values(TABLE_POLICY).reduce((n, v) => n + Object.keys(v).length, 0);
|
|
assert.ok(regels <= 5, `${regels} uitzonderingen; een uitzondering is een veld dat de AI onbewerkt ziet, dus niet zomaar meer`);
|
|
});
|
|
});
|
|
|
|
describe('strictestClass', () => {
|
|
it('kiest de gevoeligste van twee', () => {
|
|
assert.equal(strictestClass('plain', 'chain'), 'chain');
|
|
assert.equal(strictestClass('chain', 'plain'), 'chain');
|
|
assert.equal(strictestClass('handle', 'drop'), 'drop');
|
|
assert.equal(strictestClass('quantity', 'quantityFiat'), 'quantity');
|
|
});
|
|
|
|
it('behandelt een ontbrekende klasse als "de andere"', () => {
|
|
assert.equal(strictestClass(null, 'plain'), 'plain');
|
|
assert.equal(strictestClass('plain', null), 'plain');
|
|
});
|
|
|
|
it('is de regel waarmee de botsende namen zijn ingedeeld', () => {
|
|
assert.equal(fieldClass('value'), 'drop');
|
|
assert.equal(fieldClass('name'), 'handle');
|
|
assert.equal(fieldClass('key'), 'plain');
|
|
});
|
|
});
|