// Runde-7-Tests: selektives Löschen (Korridor-Keep, manuelles Gebiet weg, Komplett-Wipe) const fs = require('fs'); const stores = { tiles: new Map(), meta: new Map() }; function mkReq(result) { return { result }; } global.indexedDB = { open() { const req = {}; setTimeout(() => { const db = { objectStoreNames: { contains: n => !!stores[n] }, transaction(name) { const os = { get: k => mkReq(stores[name].get(k)), put: (v, k) => { stores[name].set(k, v); return mkReq(undefined); }, delete: k => { stores[name].delete(k); return mkReq(undefined); }, clear: () => { stores[name].clear(); return mkReq(undefined); }, count: () => mkReq(stores[name].size), getAllKeys: () => mkReq([...stores[name].keys()]), }; const tx = { objectStore: () => os }; setTimeout(() => tx.oncomplete && tx.oncomplete()); return tx; }, close() {}, }; req.result = db; req.onsuccess && req.onsuccess(); }); return req; } }; global.window = {}; Object.defineProperty(globalThis, 'navigator', { value: { onLine: true, storage: { persist: () => Promise.resolve(true) } }, configurable: true }); global.pmtiles = { PMTiles: class { getZxy() { return Promise.resolve({ data: new Uint8Array(100).buffer }); } } }; global.MapGLStyle = { tilesUrl: () => 'http://t/d.pmtiles' }; global.fetch = () => Promise.resolve({ ok: true, arrayBuffer: () => Promise.resolve(new Uint8Array(50).buffer), json: () => Promise.resolve([{ id: 1, lat: 48.2, lon: 12.1 }]) }); eval(fs.readFileSync(process.argv[2], 'utf8')); const MO = global.window.MapOffline; (async () => { // Setup: manuelles Gebiet weit weg (lon 8) + Routen-Korridor (lon 12.1) await MO.downloadAround(50.0, 8.0, { budgetMB: 0.005 }); const track = [{ lat: 48.20, lon: 12.10 }, { lat: 48.21, lon: 12.12 }, { lat: 48.22, lon: 12.14 }]; await MO.downloadCorridor(track, { bufferKm: 1, name: 'R' }); const before = stores.tiles.size; const poisBefore = [...stores.tiles.keys()].filter(k => k.startsWith('p/')).length; // 1. Selektiv: Korridor bleibt, manuelles Gebiet verschwindet, Marker bleiben await MO.clear({ keepTracks: [track] }); const gj = await MO.coverage(); const lons = gj.features.map(f => f.geometry.coordinates[0][0][0]); console.log('Selektiv: tiles', before, '→', stores.tiles.size, '— Coverage-Features:', gj.features.length); if (!gj.features.length) throw new Error('Korridor überlebte nicht'); if (lons.some(l => l < 11.5)) throw new Error('Manuelles Gebiet (lon 8) überlebte'); const poisAfter = [...stores.tiles.keys()].filter(k => k.startsWith('p/')).length; if (poisAfter !== poisBefore) throw new Error('Marker-Stores überlebten nicht'); const regs = stores.meta.get('regions') || []; if (!regs.length || regs.some(r => r.type === 'gebiet')) throw new Error('Regions-Meta falsch gefiltert'); // 2. Komplett-Wipe ohne Keep-Kandidaten: alles weg (auch p/ + f/), Zonen bleiben await MO.markDeadZone(48.2, 12.1); await MO.clear(); console.log('Komplett-Wipe: tiles =', stores.tiles.size, '— Zonen:', (stores.meta.get('deadzones') || []).length); // Korridor-Region hat keinen Track in der Meta → kein Keep-Set → echter Wipe if (stores.tiles.size !== 0) throw new Error('Komplett-Wipe unvollständig'); if ((stores.meta.get('deadzones') || []).length !== 1) throw new Error('Zonen weg'); console.log('\nALLE RUNDE-7-TESTS BESTANDEN'); })().catch(e => { console.error('FEHLER:', e.message); process.exit(1); });