v0.2.90
This commit is contained in:
1 parent
0abc8e871d
commit
4da41a1404
10 files changed
+458
-49
No files matched your search
@@ -0,0 +1,74 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { performance } from 'node:perf_hooks';
|
||||
|
||||
const source = readFileSync('static/js/authorship.js', 'utf8');
|
||||
const { lineAuthors, parseAuthorship } = await import('data:text/javascript;base64,' + Buffer.from(source).toString('base64'));
|
||||
|
||||
// Reference implementation from 0.2.89; include it to detect attribution,
|
||||
// color and tie-breaking regressions independently of the optimized code.
|
||||
function referenceLineAuthors(content, model) {
|
||||
const starts = [0];
|
||||
for (let i = 0; i < content.length; i++) if (content.charCodeAt(i) === 10) starts.push(i + 1);
|
||||
return starts.map((start, index) => {
|
||||
const end = index + 1 < starts.length ? starts[index + 1] : content.length;
|
||||
const totals = new Map();
|
||||
const representatives = new Map();
|
||||
for (const span of model?.spans || []) {
|
||||
const overlap = Math.max(0, Math.min(end, span.end) - Math.max(start, span.start));
|
||||
if (!overlap) continue;
|
||||
const identity = String(span.owner || '').split('\u001f', 1)[0];
|
||||
totals.set(identity, (totals.get(identity) || 0) + overlap);
|
||||
representatives.set(identity, span.owner);
|
||||
}
|
||||
return [...totals.entries()]
|
||||
.sort((a, b) => b[1] - a[1])
|
||||
.map(([identity]) => representatives.get(identity));
|
||||
});
|
||||
}
|
||||
|
||||
let seed = 42;
|
||||
function random(n) { seed = (seed * 1664525 + 1013904223) >>> 0; return seed % n; }
|
||||
const owners = ['A\u001f#ff0000', 'B', 'A\u001f#00ff00', 'C', 'D', ''];
|
||||
for (let sample = 0; sample < 400; sample++) {
|
||||
const content = Array.from({ length: 1 + random(65) }, (_, i) => {
|
||||
const base = ['text', '', '🙂 éół', ' x', '......'][random(5)];
|
||||
return base + (i ? '\n' : '');
|
||||
}).join('');
|
||||
const spans = [];
|
||||
for (let i = 0; i < 4 + random(100); i++) {
|
||||
const start = random(content.length + 1);
|
||||
spans.push({ start, end: start + random(content.length + 4), owner: owners[random(owners.length)] });
|
||||
}
|
||||
const canonical = parseAuthorship(content, { version: 2, spans });
|
||||
assert.deepEqual(lineAuthors(content, canonical), referenceLineAuthors(content, canonical), `canonical parity sample ${sample}`);
|
||||
assert.deepEqual(lineAuthors(content, { spans }), referenceLineAuthors(content, { spans }), `noncanonical parity sample ${sample}`);
|
||||
}
|
||||
for (const content of ['', 'a', '\n', '🙂\n\nB\n', 'line1\nline2\n']) {
|
||||
for (const model of [{ spans: [] }, { spans: [{ start: 0, end: 999, owner: 'one' }] }]) {
|
||||
assert.deepEqual(lineAuthors(content, model), referenceLineAuthors(content, model));
|
||||
}
|
||||
}
|
||||
|
||||
const n = 6000;
|
||||
const lines = [], spans = [];
|
||||
let offset = 0;
|
||||
for (let i = 0; i < n; i++) {
|
||||
const line = `row ${String(i).padStart(5, '0')} lorem ipsum\n`;
|
||||
lines.push(line);
|
||||
spans.push({ start: offset, end: offset + line.length, owner: `user${i % 37}` });
|
||||
offset += line.length;
|
||||
}
|
||||
const text = lines.join('');
|
||||
const model = { version: 2, spans };
|
||||
assert.deepEqual(lineAuthors(text, model), referenceLineAuthors(text, model));
|
||||
function medianDuration(fn) {
|
||||
const ms = [];
|
||||
for (let i = 0; i < 7; i++) { const start = performance.now(); fn(); ms.push(performance.now() - start); }
|
||||
ms.sort((a, b) => a - b);
|
||||
return ms[3];
|
||||
}
|
||||
medianDuration(() => lineAuthors(text, model));
|
||||
const oldMs = medianDuration(() => referenceLineAuthors(text, model));
|
||||
const newMs = medianDuration(() => lineAuthors(text, model));
|
||||
console.log(`PASS: 400 randomized canonical + noncanonical parity cases; 6000 lines, 6000 spans: reference ${oldMs.toFixed(2)} ms; optimized ${newMs.toFixed(2)} ms; ${(oldMs / newMs).toFixed(1)}x`);
|
||||
Reference in new issue
Block a user