Files
2026-10-01 09:30:58 +00:00

111 lines
4.4 KiB
JavaScript

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { mkdtempSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { loadGeo } from '../src/geo.js';
const CSV = [
'1.0.0.0,1.0.0.255,AU',
'5.9.0.0,5.9.255.255,DE',
'5.10.0.0,5.10.0.9,ZZ',
'8.8.8.0,8.8.8.255,US',
'255.255.255.0,255.255.255.255,FR',
'2001:db8::,2001:db8:ffff:ffff:ffff:ffff:ffff:ffff,AT',
'2a01:4f8::,2a01:4f8:ffff:ffff:ffff:ffff:ffff:ffff,DE',
'2a02:1::1,2a02:1::ff,CH',
'',
].join('\n');
function fixture(content) {
const dir = mkdtempSync(join(tmpdir(), 'geo-'));
const f = join(dir, 'geo.csv');
writeFileSync(f, content);
return f;
}
test('IPv4: Treffer und Grenzen', () => {
const g = loadGeo(fixture(CSV));
assert.equal(g.size, 8);
assert.equal(g.lookup('5.9.0.0'), 'DE');
assert.equal(g.lookup('5.9.123.4'), 'DE');
assert.equal(g.lookup('5.9.255.255'), 'DE');
assert.equal(g.lookup('5.8.255.255'), '');
assert.equal(g.lookup('5.10.0.0'), '');
assert.equal(g.lookup('1.0.0.255'), 'AU');
assert.equal(g.lookup('1.0.1.0'), '');
assert.equal(g.lookup('0.0.0.1'), '');
assert.equal(g.lookup('255.255.255.255'), 'FR');
assert.equal(g.lookup('8.8.8.8'), 'US');
});
test('IPv6: Treffer, Grenzen, Kurzschreibweise', () => {
const g = loadGeo(fixture(CSV));
assert.equal(g.lookup('2a01:4f8::'), 'DE');
assert.equal(g.lookup('2a01:4f8:1:2:3:4:5:6'), 'DE');
assert.equal(g.lookup('2A01:04F8:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF'), 'DE');
assert.equal(g.lookup('2a01:4f9::'), '');
assert.equal(g.lookup('2a01:4f7:ffff:ffff:ffff:ffff:ffff:ffff'), '');
assert.equal(g.lookup('2001:db8::1'), 'AT');
assert.equal(g.lookup('2a02:1::1'), 'CH');
assert.equal(g.lookup('2a02:1::ff'), 'CH');
assert.equal(g.lookup('2a02:1::100'), '');
assert.equal(g.lookup('2a02:1::'), '');
assert.equal(g.lookup('::1'), '');
});
test('IPv4-gemappte IPv6-Adressen zählen als IPv4', () => {
const g = loadGeo(fixture(CSV));
assert.equal(g.lookup('::ffff:5.9.1.1'), 'DE');
assert.equal(g.lookup('::FFFF:8.8.8.8'), 'US');
assert.equal(g.lookup('::ffff:808:808'), 'US');
assert.equal(g.lookup('::ffff:9.9.9.9'), '');
});
test('ZZ, ungültige Eingaben, unsortierte Datei', () => {
const g = loadGeo(fixture(CSV));
assert.equal(g.lookup('5.10.0.5'), '');
for (const bad of ['', 'abc', '1.2.3', '256.1.1.1', '1.2.3.4.5', '2001:db8::zz', ':::', '1::2::3', null, undefined, 42]) {
assert.equal(g.lookup(bad), '', String(bad));
}
const u = loadGeo(fixture('8.8.8.0,8.8.8.255,US\n1.0.0.0,1.0.0.255,AU\n2a01:4f8::,2a01:4f8::ff,DE\n2001:db8::,2001:db8::ff,AT\n'));
assert.equal(u.lookup('1.0.0.7'), 'AU');
assert.equal(u.lookup('8.8.8.8'), 'US');
assert.equal(u.lookup('2001:db8::7'), 'AT');
assert.equal(u.lookup('2a01:4f8::7'), 'DE');
});
test('fehlende Datei: alles leer, eine Warnung, kein Absturz', () => {
const warns = [];
const orig = console.warn;
console.warn = (...a) => warns.push(a.join(' '));
try {
const g = loadGeo('/nicht/vorhanden/geo.csv');
assert.equal(g.lookup('5.9.1.1'), '');
assert.equal(g.lookup('2a01:4f8::1'), '');
assert.equal(g.size, 0);
} finally { console.warn = orig; }
assert.equal(warns.length, 1);
assert.match(warns[0], /nicht lesbar/);
});
test('600k Zeilen: lädt zügig, Heap bleibt klein', () => {
const lines = [];
for (let i = 0; i < 400000; i++) lines.push(`${(i * 4096) >>> 24}.${((i * 4096) >>> 16) & 255}.${((i * 4096) >>> 8) & 255}.0,${(i * 4096) >>> 24}.${((i * 4096) >>> 16) & 255}.${((i * 4096 + 255) >>> 8) & 255}.255,${i % 7 ? 'DE' : 'AT'}`);
for (let i = 0; i < 200000; i++) lines.push(`2a00:${(i >> 8).toString(16)}:${(i & 255).toString(16)}::,2a00:${(i >> 8).toString(16)}:${(i & 255).toString(16)}:ffff:ffff:ffff:ffff:ffff,${i % 5 ? 'DE' : 'FR'}`);
const f = fixture(lines.join('\n'));
lines.length = 0;
globalThis.gc?.();
const before = process.memoryUsage().heapUsed; const rss0 = process.memoryUsage().rss;
const t0 = Date.now();
const g = loadGeo(f);
const ms = Date.now() - t0;
globalThis.gc?.();
const grow = (process.memoryUsage().heapUsed - before) / 1048576;
console.log(`# geo 600k: ${ms} ms, Heap +${grow.toFixed(1)} MB, RSS +${((process.memoryUsage().rss - rss0) / 1048576).toFixed(0)} MB, Zeilen ${g.size}`);
assert.equal(g.size, 600000);
assert.equal(g.lookup('0.0.16.5'), 'DE');
assert.equal(g.lookup('2a00:0:1::5'), 'DE');
assert.ok(grow < 100, `Heap +${grow} MB`);
});