Ruined
This commit is contained in:
+47
-10
@@ -8,6 +8,17 @@ import { LIMITS, USER_AGENT, parseCatalogue, apiURL, allowedURL, fetchBatch,
|
||||
|
||||
const catalogue = parseCatalogue(await readFile(new URL('../mods/hearth/botany.lua', import.meta.url), 'utf8'));
|
||||
const cached = parseBundle(await readFile(new URL('../mods/hearth/wiki_articles.lua', import.meta.url), 'utf8'));
|
||||
const additions = [
|
||||
['crab_apple', 'Malus sylvestris'], ['wild_cherry', 'Prunus avium'], ['field_maple', 'Acer campestre'],
|
||||
['honeysuckle', 'Lonicera periclymenum'], ['ivy', 'Hedera helix'], ['gorse', 'Ulex europaeus'],
|
||||
['broom', 'Cytisus scoparius'], ['dandelion', 'Taraxacum officinale'], ['daisy', 'Bellis perennis'],
|
||||
['red_clover', 'Trifolium pratense'], ['birdsfoot_trefoil', 'Lotus corniculatus'],
|
||||
['ribwort_plantain', 'Plantago lanceolata'], ['selfheal', 'Prunella vulgaris'],
|
||||
['knapweed', 'Centaurea nigra'], ['oxeye_daisy', 'Leucanthemum vulgare'],
|
||||
['field_scabious', 'Knautia arvensis'], ['teasel', 'Dipsacus fullonum'],
|
||||
['cow_parsley', 'Anthriscus sylvestris'], ['garlic_mustard', 'Alliaria petiolata'],
|
||||
['holly_fern', 'Polystichum setiferum'],
|
||||
].map(([id, latin]) => ({ id, latin }));
|
||||
const retrieved = '2026-11-03T08:00:00.000Z';
|
||||
const record = catalogue[0];
|
||||
const intro = 'Quercus robur is a species of flowering plant. This fixture is original test text, not a cached Wikipedia quotation.';
|
||||
@@ -25,10 +36,13 @@ function jsonResponse(data, headers = {}) {
|
||||
}
|
||||
function mock(fn) { return async (...args) => { mockedRequests++; return fn(...args); }; }
|
||||
|
||||
test('bounded non-executing Lua parser finds the actual 80 Latin names and IDs', async () => {
|
||||
assert.equal(catalogue.length, 80);
|
||||
assert.equal(new Set(catalogue.map(r => r.id)).size, 80);
|
||||
test('bounded non-executing Lua parser finds the actual 100 Latin names and multi-underscore IDs', async () => {
|
||||
assert.equal(LIMITS.species, 100);
|
||||
assert.equal(catalogue.length, 100);
|
||||
assert.equal(new Set(catalogue.map(r => r.id)).size, 100);
|
||||
assert.deepEqual(catalogue.find(r => r.id === 'wood_blewit'), { id: 'wood_blewit', latin: 'Collybia nuda' });
|
||||
assert.deepEqual(catalogue.find(r => r.id === 'sweet_vernal_grass'), { id: 'sweet_vernal_grass', latin: 'Anthoxanthum odoratum' });
|
||||
assert.deepEqual(catalogue.filter(r => additions.some(a => a.id === r.id)), additions);
|
||||
const source = await readFile(new URL('../mods/hearth/botany.lua', import.meta.url), 'utf8');
|
||||
for (const bad of [source.replace('Quercus robur', 'https://127.0.0.1/'),
|
||||
source.replace('Quercus robur', 'Quercus robur|User:Private'),
|
||||
@@ -37,8 +51,9 @@ test('bounded non-executing Lua parser finds the actual 80 Latin names and IDs',
|
||||
source.replace('add("birch"', 'add("oak"'),
|
||||
source.replace('"Betula pendula"', '"Quercus robur"'),
|
||||
source.replace('add("oak",', 'add(variable,'), source + '\nadd("extra","Extra","Abies alba",',
|
||||
source.replace(/^\s*add\("holly_fern"[^\r\n]*/m, ''),
|
||||
source.repeat(10), 'os.execute("not executed")']) assert.throws(() => parseCatalogue(bad));
|
||||
assert.equal(parseCatalogue(source + '\nos.execute("never evaluated")').length, 80);
|
||||
assert.equal(parseCatalogue(source + '\nos.execute("never evaluated")').length, 100);
|
||||
});
|
||||
|
||||
test('URL construction rejects URL/query/title injection before any request', async () => {
|
||||
@@ -230,7 +245,7 @@ test('untrusted Wikipedia text is exclusively UTF-8 byte literals, never executa
|
||||
assert.throws(() => serializeBundle([{ ...entry, revision: '12345' }]));
|
||||
});
|
||||
|
||||
test('80 titles use exactly eight mocked batches at concurrency <=2 and stable catalogue order', async () => {
|
||||
test('100 titles use exactly ten mocked batches at concurrency <=2 and stable catalogue order', async () => {
|
||||
let active = 0, peak = 0, calls = 0;
|
||||
const seen = [];
|
||||
const entries = await fetchEntries(catalogue, { now: () => new Date(retrieved), fetchImpl: mock(async url => {
|
||||
@@ -239,13 +254,18 @@ test('80 titles use exactly eight mocked batches at concurrency <=2 and stable c
|
||||
assert.ok(names.length <= 10); await setImmediate(); active--;
|
||||
return jsonResponse(payload(names.map(name => page(name))));
|
||||
}) });
|
||||
assert.equal(calls, 8); assert.equal(peak, 2);
|
||||
assert.equal(calls, 10); assert.equal(peak, 2);
|
||||
assert.deepEqual(seen, catalogue.map(r => r.latin));
|
||||
assert.deepEqual(entries.map(r => r.id), catalogue.map(r => r.id));
|
||||
assert.equal(entries.length, 80);
|
||||
assert.equal(entries.length, 100);
|
||||
assert.deepEqual(parseBundle(serializeBundle(entries)), entries);
|
||||
for (const records of [[], [...catalogue, { id: 'extra', latin: 'Abies alba' }]]) {
|
||||
await assert.rejects(fetchEntries(records, { fetchImpl: () => { throw new Error('must not fetch'); } }), /scope/);
|
||||
assert.throws(() => serializeBundle(records), /scope/);
|
||||
}
|
||||
const extra = { ...entries[0], id: 'extra', latin: 'Abies alba' };
|
||||
const oversized = serializeBundle(entries).replace(/}\n$/, serializeBundle([extra]).split('return {\n')[1]);
|
||||
assert.throws(() => parseBundle(oversized), /scope/);
|
||||
});
|
||||
|
||||
test('batch failure aborts other workers and never launches the remaining catalogue', async () => {
|
||||
@@ -258,10 +278,20 @@ test('batch failure aborts other workers and never launches the remaining catalo
|
||||
assert.equal(calls, 2); assert.equal(otherSignal.aborted, true);
|
||||
});
|
||||
|
||||
test('shipped bundle contains 78 real intros and two honest missing-page notes for all 80 species', () => {
|
||||
assert.equal(cached.length, 80);
|
||||
test('shipped bundle retains 78 old intros and two notes plus 20 real new intros for all 100 species', () => {
|
||||
assert.equal(cached.length, 100);
|
||||
assert.deepEqual(cached.map(({ id, latin }) => ({ id, latin })), catalogue);
|
||||
assert.equal(cached.filter(e => e.kind === 'wikipedia_intro').length, 78);
|
||||
assert.equal(cached.filter(e => e.kind === 'wikipedia_intro').length, 98);
|
||||
const old = cached.filter(e => !additions.some(a => a.id === e.id));
|
||||
assert.equal(old.length, 80);
|
||||
assert.equal(old.filter(e => e.kind === 'wikipedia_intro').length, 78);
|
||||
for (const addition of additions) {
|
||||
const e = cached.find(e => e.id === addition.id);
|
||||
assert.equal(e.latin, addition.latin);
|
||||
assert.equal(e.kind, 'wikipedia_intro');
|
||||
assert.equal(e.excerpt, true);
|
||||
assert.ok(e.text.length > 30);
|
||||
}
|
||||
assert.deepEqual(cached.filter(e => e.kind === 'original_notes').map(e => e.latin), ['Usnea subfloridana', 'Cladonia chlorophaea']);
|
||||
for (const e of cached) {
|
||||
assert.ok(Array.from(e.text).length <= 8000);
|
||||
@@ -273,6 +303,13 @@ test('shipped bundle contains 78 real intros and two honest missing-page notes f
|
||||
assert.ok(e.history_url.endsWith('&action=history'));
|
||||
assert.ok(e.revision_url.endsWith('?oldid=' + e.revision));
|
||||
assert.match(e.attribution, /^Wikipedia contributors/);
|
||||
assert.equal(e.license_url, 'https://creativecommons.org/licenses/by-sa/4.0/');
|
||||
assert.ok(Date.parse(e.revision_timestamp) <= Date.parse(e.retrieved));
|
||||
} else {
|
||||
assert.equal(e.kind, 'original_notes');
|
||||
assert.equal(e.license, 'CC0 1.0');
|
||||
assert.equal(e.excerpt, false);
|
||||
for (const field of ['pageid', 'revision', 'revision_url', 'revision_timestamp']) assert.equal(e[field], undefined);
|
||||
}
|
||||
}
|
||||
assert.equal(cached.find(e => e.id === 'meadow_fescue').title, 'Lolium pratense');
|
||||
|
||||
Reference in New Issue
Block a user