feat: Absturzschutz fuer die laufende Sitzung
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,36 @@
|
|||||||
|
// Reines Modul: kein window, kein document, kein localStorage.
|
||||||
|
|
||||||
|
const KEY = 'ram-sortierhilfe:session';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Absturzschutz, keine Bestandsfuehrung: die laufende Sitzung wird
|
||||||
|
* gesichert, damit ein versehentliches Neuladen sie nicht vernichtet.
|
||||||
|
*/
|
||||||
|
export function saveSession(session, store) {
|
||||||
|
try {
|
||||||
|
store.setItem(KEY, JSON.stringify(session));
|
||||||
|
} catch {
|
||||||
|
// Voller oder gesperrter Speicher darf das Sortieren nicht unterbrechen.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns {object|null} */
|
||||||
|
export function loadSession(store) {
|
||||||
|
try {
|
||||||
|
const raw = store.getItem(KEY);
|
||||||
|
if (!raw) return null;
|
||||||
|
const parsed = JSON.parse(raw);
|
||||||
|
if (!Array.isArray(parsed.stacks) || !Array.isArray(parsed.entries)) return null;
|
||||||
|
return parsed;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearSession(store) {
|
||||||
|
try {
|
||||||
|
store.removeItem(KEY);
|
||||||
|
} catch {
|
||||||
|
// siehe oben
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { test } from 'node:test';
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import { saveSession, loadSession, clearSession } from '../src/storage.js';
|
||||||
|
import { createSession, commitAssignment } from '../src/session.js';
|
||||||
|
import { emptySpec } from '../src/spec.js';
|
||||||
|
|
||||||
|
function fakeStore() {
|
||||||
|
const data = new Map();
|
||||||
|
return {
|
||||||
|
data,
|
||||||
|
getItem: (key) => (data.has(key) ? data.get(key) : null),
|
||||||
|
setItem: (key, value) => data.set(key, value),
|
||||||
|
removeItem: (key) => data.delete(key),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
test('leerer Speicher liefert null', () => {
|
||||||
|
assert.equal(loadSession(fakeStore()), null);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Sitzung ueberlebt Sichern und Laden', () => {
|
||||||
|
const store = fakeStore();
|
||||||
|
const session = createSession();
|
||||||
|
commitAssignment(session, { ...emptySpec(), capacityGb: 64 }, 'barcode', 'A');
|
||||||
|
saveSession(session, store);
|
||||||
|
|
||||||
|
const wieder = loadSession(store);
|
||||||
|
assert.equal(wieder.stacks.length, 1);
|
||||||
|
assert.equal(wieder.stacks[0].count, 1);
|
||||||
|
assert.equal(wieder.entries[0].spec.capacityGb, 64);
|
||||||
|
assert.equal(wieder.nextEntryId, 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('clearSession raeumt auf', () => {
|
||||||
|
const store = fakeStore();
|
||||||
|
saveSession(createSession(), store);
|
||||||
|
clearSession(store);
|
||||||
|
assert.equal(loadSession(store), null);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('kaputter Inhalt liefert null statt einer Ausnahme', () => {
|
||||||
|
const store = fakeStore();
|
||||||
|
store.setItem('ram-sortierhilfe:session', '{kein json');
|
||||||
|
assert.equal(loadSession(store), null);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Sichern ohne funktionierenden Speicher wirft nicht', () => {
|
||||||
|
const kaputt = {
|
||||||
|
getItem: () => null,
|
||||||
|
setItem: () => { throw new Error('quota exceeded'); },
|
||||||
|
removeItem: () => {},
|
||||||
|
};
|
||||||
|
assert.doesNotThrow(() => saveSession(createSession(), kaputt));
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user