99 lines
3.6 KiB
JavaScript
99 lines
3.6 KiB
JavaScript
|
|
'use strict';
|
||
|
|
|
||
|
|
const test = require('node:test');
|
||
|
|
const assert = require('node:assert/strict');
|
||
|
|
const fs = require('fs');
|
||
|
|
const os = require('os');
|
||
|
|
const path = require('path');
|
||
|
|
|
||
|
|
const FileBackend = require('../../src/registry/backends/FileBackend');
|
||
|
|
|
||
|
|
function tmpdir(prefix) {
|
||
|
|
return fs.mkdtempSync(path.join(os.tmpdir(), `evolv-fb-${prefix}-`));
|
||
|
|
}
|
||
|
|
|
||
|
|
test('per-id layout: one file per id, lowercased keys', () => {
|
||
|
|
const dir = tmpdir('perid');
|
||
|
|
fs.writeFileSync(path.join(dir, 'AlphaModel.json'), JSON.stringify({ kind: 'pump' }));
|
||
|
|
fs.writeFileSync(path.join(dir, 'beta.json'), JSON.stringify({ kind: 'valve' }));
|
||
|
|
const b = new FileBackend({ baseDir: dir, layout: 'per-id' });
|
||
|
|
const m = b.loadAll();
|
||
|
|
assert.equal(m.get('alphamodel').kind, 'pump');
|
||
|
|
assert.equal(m.get('beta').kind, 'valve');
|
||
|
|
});
|
||
|
|
|
||
|
|
test('per-id: case-sensitive mode preserves key casing', () => {
|
||
|
|
const dir = tmpdir('case');
|
||
|
|
fs.writeFileSync(path.join(dir, 'Mixed.json'), JSON.stringify({ ok: true }));
|
||
|
|
const b = new FileBackend({ baseDir: dir, layout: 'per-id', caseInsensitive: false });
|
||
|
|
const m = b.loadAll();
|
||
|
|
assert.ok(m.has('Mixed'));
|
||
|
|
assert.ok(!m.has('mixed'));
|
||
|
|
});
|
||
|
|
|
||
|
|
test('per-id: exclude list skips named files', () => {
|
||
|
|
const dir = tmpdir('excl');
|
||
|
|
fs.writeFileSync(path.join(dir, 'good.json'), '{}');
|
||
|
|
fs.writeFileSync(path.join(dir, 'bad.json'), '{}');
|
||
|
|
const b = new FileBackend({ baseDir: dir, layout: 'per-id', exclude: ['bad'] });
|
||
|
|
const m = b.loadAll();
|
||
|
|
assert.ok(m.has('good'));
|
||
|
|
assert.ok(!m.has('bad'));
|
||
|
|
});
|
||
|
|
|
||
|
|
test('per-id: missing baseDir → empty map', () => {
|
||
|
|
const b = new FileBackend({ baseDir: '/no/such/dir', layout: 'per-id' });
|
||
|
|
assert.equal(b.loadAll().size, 0);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('single-file: indexes array by named field', () => {
|
||
|
|
const dir = tmpdir('single');
|
||
|
|
const file = 'data.json';
|
||
|
|
fs.writeFileSync(path.join(dir, file), JSON.stringify({
|
||
|
|
samples: [
|
||
|
|
{ code: '001', desc: 'one' },
|
||
|
|
{ code: '002', desc: 'two' },
|
||
|
|
],
|
||
|
|
}));
|
||
|
|
const b = new FileBackend({
|
||
|
|
baseDir: dir, layout: 'single-file', filePath: file,
|
||
|
|
arrayKey: 'samples', indexField: 'code',
|
||
|
|
});
|
||
|
|
const m = b.loadAll();
|
||
|
|
assert.equal(m.get('001').desc, 'one');
|
||
|
|
assert.equal(m.get('002').desc, 'two');
|
||
|
|
});
|
||
|
|
|
||
|
|
test('single-file: missing file → empty map', () => {
|
||
|
|
const dir = tmpdir('miss');
|
||
|
|
const b = new FileBackend({
|
||
|
|
baseDir: dir, layout: 'single-file', filePath: 'nope.json',
|
||
|
|
arrayKey: 'samples', indexField: 'code',
|
||
|
|
});
|
||
|
|
assert.equal(b.loadAll().size, 0);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('single-file: bad shape throws', () => {
|
||
|
|
const dir = tmpdir('bad');
|
||
|
|
fs.writeFileSync(path.join(dir, 'data.json'), JSON.stringify({ samples: 'not-array' }));
|
||
|
|
const b = new FileBackend({
|
||
|
|
baseDir: dir, layout: 'single-file', filePath: 'data.json',
|
||
|
|
arrayKey: 'samples', indexField: 'code',
|
||
|
|
});
|
||
|
|
assert.throws(() => b.loadAll(), /expected array/i);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('refresh() returns same result as loadAll() for file backend', async () => {
|
||
|
|
const dir = tmpdir('refresh');
|
||
|
|
fs.writeFileSync(path.join(dir, 'a.json'), JSON.stringify({ v: 1 }));
|
||
|
|
const b = new FileBackend({ baseDir: dir, layout: 'per-id' });
|
||
|
|
const r = await b.refresh();
|
||
|
|
assert.equal(r.get('a').v, 1);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('constructor validates layout + filePath combinations', () => {
|
||
|
|
assert.throws(() => new FileBackend({}), /baseDir/);
|
||
|
|
assert.throws(() => new FileBackend({ baseDir: '/tmp', layout: 'weird' }), /layout/);
|
||
|
|
assert.throws(() => new FileBackend({ baseDir: '/tmp', layout: 'single-file' }), /filePath/);
|
||
|
|
});
|