From 4d896702d1d4287b692b74b7751758a8ba540592 Mon Sep 17 00:00:00 2001 From: vchuser Date: Tue, 28 Jul 2026 15:57:28 +0200 Subject: [PATCH] feat: Absturzschutz fuer die laufende Sitzung Co-Authored-By: Claude Opus 5 (1M context) --- src/storage.js | 36 +++++++++++++++++++++++++++++ test/storage.test.js | 54 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 src/storage.js create mode 100644 test/storage.test.js diff --git a/src/storage.js b/src/storage.js new file mode 100644 index 0000000..4cf3f7a --- /dev/null +++ b/src/storage.js @@ -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 + } +} diff --git a/test/storage.test.js b/test/storage.test.js new file mode 100644 index 0000000..522c225 --- /dev/null +++ b/test/storage.test.js @@ -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)); +});