feat(parser): Unicode-Brueche + Mengen-Plausibilitaet
ingredient.ts: - UNICODE_FRACTION_MAP fuer ½ ¼ ¾ ⅓ ⅔ ⅕ ⅖ ⅗ ⅘ ⅙ ⅚ ⅛ ⅜ ⅝ ⅞ - clampQuantity() weist 0, negative, > 10000 als null ab - splitUnitAndName() helper, vorher 2x dupliziert (Unicode + ASCII Pfad) Tests: - 13 neue Tests fuer Unicode-Brueche (mit/ohne Unit) und Bounds - bestaetigt dass deutsches Kommadezimal (0,25 l) bereits funktioniert Hintergrund: Apple Food App liefert haeufig ½ und ⅓ in JSON-LD Quantity-Feldern. Vor diesem Fix wurden die Felder als unparsable behandelt (quantity null, name = '½ TL Salz'), was den Portionen-Slider fuer importierte Rezepte unbrauchbar machte. Findings aus REVIEW-2026-04-18.md (Refactor D) und structure.md
This commit is contained in:
@@ -39,4 +39,66 @@ describe('parseIngredient', () => {
|
||||
expect(p.quantity).toBe(2);
|
||||
expect(p.name).toBe('Tomaten');
|
||||
});
|
||||
|
||||
describe('Unicode-Bruchzeichen', () => {
|
||||
it.each([
|
||||
['½ TL Salz', 0.5, 'TL', 'Salz'],
|
||||
['¼ kg Zucker', 0.25, 'kg', 'Zucker'],
|
||||
['¾ l Milch', 0.75, 'l', 'Milch'],
|
||||
['⅓ Tasse Mehl', 1 / 3, 'Tasse', 'Mehl'],
|
||||
['⅔ TL Pfeffer', 2 / 3, 'TL', 'Pfeffer'],
|
||||
['⅛ TL Muskat', 0.125, 'TL', 'Muskat']
|
||||
] as const)('%s', (input, qty, unit, name) => {
|
||||
const p = parseIngredient(input);
|
||||
expect(p.quantity).toBeCloseTo(qty, 5);
|
||||
expect(p.unit).toBe(unit);
|
||||
expect(p.name).toBe(name);
|
||||
});
|
||||
|
||||
it('Unicode-Bruch ohne Unit', () => {
|
||||
const p = parseIngredient('½ Zitrone');
|
||||
expect(p.quantity).toBeCloseTo(0.5, 5);
|
||||
expect(p.unit).toBe(null);
|
||||
expect(p.name).toBe('Zitrone');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Mengen-Plausibilitaet (Bounds)', () => {
|
||||
it('weist 0 als Menge ab → quantity null', () => {
|
||||
const p = parseIngredient('0 g Mehl');
|
||||
expect(p.quantity).toBe(null);
|
||||
// name bleibt das was nach der "0" kommt — Importer muss das nicht
|
||||
// perfekt rekonstruieren, der raw_text bleibt erhalten.
|
||||
expect(p.raw_text).toBe('0 g Mehl');
|
||||
});
|
||||
|
||||
it('weist negative Menge ab', () => {
|
||||
// "-1 EL Öl" — Minus führt regex direkt ins Fallback (kein \d am Start),
|
||||
// also bleibt name = full text.
|
||||
const p = parseIngredient('-1 EL Öl');
|
||||
expect(p.quantity).toBe(null);
|
||||
});
|
||||
|
||||
it('weist Menge > 10000 ab', () => {
|
||||
const p = parseIngredient('99999 g Hokuspokus');
|
||||
expect(p.quantity).toBe(null);
|
||||
});
|
||||
|
||||
it('akzeptiert die Obergrenze 10000 selbst', () => {
|
||||
const p = parseIngredient('10000 g Mehl');
|
||||
expect(p.quantity).toBe(10000);
|
||||
});
|
||||
|
||||
it('akzeptiert führende Null bei Dezimalbrüchen', () => {
|
||||
const p = parseIngredient('0.5 kg Salz');
|
||||
expect(p.quantity).toBe(0.5);
|
||||
expect(p.unit).toBe('kg');
|
||||
});
|
||||
|
||||
it('akzeptiert deutsche führende Null', () => {
|
||||
const p = parseIngredient('0,25 l Wasser');
|
||||
expect(p.quantity).toBe(0.25);
|
||||
expect(p.unit).toBe('l');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user