Versie 0.2.0
This commit is contained in:
commit
e77d8fd373
495 files changed
+81026
No files matched your search
@@ -0,0 +1,140 @@
|
||||
// Generated, do not edit. sha256:9bbc954e336de37a55fc73310bcc550947a6f91fd3fa5c98c1be9921acfadb2d
|
||||
import { describe, it, before, mock } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
import { createDbHarness } from '../helpers/db-node.mjs';
|
||||
import { fieldClass } from '../../server/ai/policy.js';
|
||||
import { createTranslator } from '../../server/ai/translate.js';
|
||||
|
||||
const TEST_GEHEIM = 'test-geheim-voor-de-suite-0123456789abcdef';
|
||||
|
||||
const harness = createDbHarness({ seedPreferences: true });
|
||||
mock.module('../../server/db.js', { namedExports: harness.exports });
|
||||
|
||||
const modules = {
|
||||
accounts: await import('../../server/data/accounts.js'),
|
||||
assets: await import('../../server/data/assets.js'),
|
||||
'api-metrics': await import('../../server/data/api-metrics.js'),
|
||||
connections: await import('../../server/data/connections.js'),
|
||||
counts: await import('../../server/data/counts.js'),
|
||||
dashboard: await import('../../server/data/dashboard.js'),
|
||||
events: await import('../../server/data/events.js'),
|
||||
'interest-credits': await import('../../server/data/interest-credits.js'),
|
||||
'interest-schedules': await import('../../server/data/interest-schedules.js'),
|
||||
labels: await import('../../server/data/labels.js'),
|
||||
metals: await import('../../server/data/metals.js'),
|
||||
notifications: await import('../../server/data/notifications.js'),
|
||||
'price-history': await import('../../server/data/price-history.js'),
|
||||
'price-source': await import('../../server/data/price-source.js'),
|
||||
proposals: await import('../../server/data/proposals.js'),
|
||||
providers: await import('../../server/data/providers.js'),
|
||||
'scan-logs': await import('../../server/data/scan-logs.js'),
|
||||
'tx-links': await import('../../server/data/tx-links.js'),
|
||||
valuations: await import('../../server/data/valuations.js'),
|
||||
'wallet-addresses': await import('../../server/data/wallet-addresses.js'),
|
||||
'wallet-sources': await import('../../server/data/wallet-sources.js'),
|
||||
'wallet-txs': await import('../../server/data/wallet-txs.js'),
|
||||
};
|
||||
|
||||
const LOK = Object.freeze({
|
||||
xpub: 'xpubLOKVOGEL66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666',
|
||||
adres: 'bc1qlokvogel99999999999999999999999999zzzz',
|
||||
txid: 'lokvogel4444444444444444444444444444444444444444444444444444beef',
|
||||
extern: 'bc1qlokvogelextern9999999999999999999zzzzz',
|
||||
notitie: 'LOKVOGELNOTITIE',
|
||||
rekening: 'LOKVOGELREKENING',
|
||||
});
|
||||
const LOKWAARDEN = Object.values(LOK);
|
||||
|
||||
const MUTEERT = /^(create|update|delete|upsert|set|purge|merge|assert|emit|forget|take|sync|book|restore|import|save|apply|resolve|dismiss|link|unlink|reset|seed|ensure|add|remove|move|rename|record|log|mark|clear|prune|revert)/;
|
||||
|
||||
let ids = {};
|
||||
let resultaten = [];
|
||||
let overgeslagen = [];
|
||||
|
||||
before(async () => {
|
||||
harness.recreate();
|
||||
|
||||
const asset = await modules.assets.createAsset(
|
||||
{ symbol: 'BTC', name: 'Bitcoin', kind: 'crypto', unit: 'BTC', subunit: 'sat', decimals: 8, displayUnit: 'unit' });
|
||||
const account = await modules.accounts.createAccount(
|
||||
{ name: LOK.rekening, kind: 'wallet', isOwnCustody: 1, scanEnabled: 1 });
|
||||
ids = { asset: idVan(asset), account: idVan(account) };
|
||||
|
||||
const bron = await modules['wallet-sources'].createWalletSource(
|
||||
{ accountId: ids.account, kind: 'xpub', value: LOK.xpub, name: LOK.rekening, scriptType: 'p2wpkh' });
|
||||
ids.bron = idVan(bron);
|
||||
|
||||
await modules['wallet-addresses'].upsertWalletAddresses([{
|
||||
accountId: ids.account, sourceId: ids.bron, address: LOK.adres,
|
||||
chainIndex: 0, derivationIndex: 3, balanceSats: 123456789, transactionCount: 2,
|
||||
}]);
|
||||
await modules['wallet-txs'].upsertWalletTxs([{
|
||||
accountId: ids.account, sourceId: ids.bron, txid: LOK.txid,
|
||||
direction: 'in', valueSats: 123456789, feeSats: 250, blockHeight: 800000,
|
||||
blockTime: '2026-01-02T03:04:05Z', address: LOK.adres,
|
||||
}]);
|
||||
await modules.events.createEvent({
|
||||
assetId: ids.asset, type: 'buy', occurredAt: '2026-01-02T03:04:05Z', amount: 123456789,
|
||||
fiatPrice: 54321.5, toAccountId: ids.account, source: 'manual',
|
||||
note: LOK.notitie, externalAddress: LOK.extern,
|
||||
});
|
||||
|
||||
for (const [mod, exports] of Object.entries(modules)) {
|
||||
for (const [naam, fn] of Object.entries(exports)) {
|
||||
if (typeof fn !== 'function' || MUTEERT.test(naam)) { overgeslagen.push(`${mod}.${naam}`); continue; }
|
||||
let ruw, gelukt = false;
|
||||
for (const args of [[], [ids.account], [ids.bron], [ids.asset]]) {
|
||||
try { ruw = await fn(...args); gelukt = true; break; } catch { }
|
||||
}
|
||||
if (gelukt && ruw !== undefined) resultaten.push({ naam: `${mod}.${naam}`, ruw });
|
||||
else overgeslagen.push(`${mod}.${naam}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function idVan(r) { return typeof r === 'object' && r !== null ? (r.id ?? r) : r; }
|
||||
|
||||
function bevat(structuur, naald) {
|
||||
return JSON.stringify(structuur ?? null).includes(naald);
|
||||
}
|
||||
|
||||
describe('AI-sweep, richting 1: geen lokvogel overleeft de vertaalslag', () => {
|
||||
it('roept genoeg leesfuncties aan om iets te bewijzen', () => {
|
||||
assert.ok(resultaten.length >= 30,
|
||||
`te weinig aangeroepen om iets te bewijzen: ${resultaten.length} gelukt, ${overgeslagen.length} overgeslagen`);
|
||||
});
|
||||
|
||||
it('ziet de lokvogels in de ONvertaalde uitvoer (anders bewijst de rest niets)', () => {
|
||||
const gezien = LOKWAARDEN.filter(w => resultaten.some(r => bevat(r.ruw, w)));
|
||||
assert.deepEqual(gezien.sort(), [...LOKWAARDEN].sort(),
|
||||
'niet elke lokvogel kwam in de ruwe uitvoer voor; de sweep raakt die paden dus niet');
|
||||
});
|
||||
|
||||
it('laat geen enkele lokvogel door de vertaalslag', () => {
|
||||
const t = createTranslator({ secret: TEST_GEHEIM });
|
||||
const lekken = [];
|
||||
for (const { naam, ruw } of resultaten) {
|
||||
const uit = t.toAi(ruw);
|
||||
for (const w of LOKWAARDEN) if (bevat(uit, w)) lekken.push(`${naam} lekt ${w.slice(0, 16)}…`);
|
||||
}
|
||||
assert.deepEqual(lekken, []);
|
||||
});
|
||||
});
|
||||
|
||||
describe('AI-sweep, richting 2: elk veld in de uitvoer is gedeclareerd', () => {
|
||||
it('kent voor elk veld in de vertaalde uitvoer een klasse', () => {
|
||||
const t = createTranslator({ secret: TEST_GEHEIM });
|
||||
const onbekend = new Set();
|
||||
const loop = (v) => {
|
||||
if (Array.isArray(v)) { v.forEach(loop); return; }
|
||||
if (v === null || typeof v !== 'object') return;
|
||||
for (const [k, w] of Object.entries(v)) {
|
||||
if (fieldClass(k) === null) onbekend.add(k);
|
||||
loop(w);
|
||||
}
|
||||
};
|
||||
for (const { ruw } of resultaten) loop(t.toAi(ruw));
|
||||
assert.deepEqual([...onbekend].sort(), []);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user