IF-Funktion als Formel: echte Kurzschluss-Auswertung
Neue eingebaute Funktion IF(Bedingung; Dann; Sonst?), nutzbar in jeder
gewöhnlichen Zellformel (nicht nur in "Mit Schleife"-Funktionskörpern).
- functions.ts: IF als Platzhalter-Eintrag registriert, nur damit
hasFunction('IF') greift (Namensreservierung -- ein Benutzer kann
keine gleichnamige eigene Funktion mehr anlegen) und als defensiver
Fallback. Trägt einen Kommentar, der auf die echte Implementierung
verweist.
- evaluator.ts: die echte, kurzschließende Auswertung sitzt in
evalScalar()s case 'func', VOR dem generischen eager-args-Pfad.
evalIf() wertet nur die Bedingung immer aus, danach ausschließlich
den genommenen Zweig -- der andere Zweig wird nie evaluiert, ein
Fehler darin (z. B. =IF(B1=0; 0; A1/B1)) schlägt also nie durch.
Gleiche Wahrheits-Konvention wie überall sonst im Engine (Zahl != 0
bzw. nicht-leerer Text = wahr).
- collectRefs() bleibt unverändert: sein generischer case 'func' läuft
bereits konservativ durch alle Argumente, unabhängig vom zur
Laufzeit genommenen Zweig -- exakt wie Excels IF().
Tests: 8 neue (evaluator.spec.ts: beide Zweige, 2-/3-Argument-Form,
Kurzschluss-Beweis, Fehler in der Bedingung, Arity-Fehler, Vergleiche
als Bedingung; document.spec.ts: Namenskollision mit eingebautem IF).
257 -> 265 Tests, alle grün. vue-tsc/eslint/build sauber. Live per
Playwright verifiziert (inkl. Kurzschluss- und Neuberechnungsverhalten).
READMEs aktualisiert (Funktionen-Liste, Auswertungsmodell, Testzahl).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -87,6 +87,44 @@ describe('evaluator functions', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('evaluator IF', () => {
|
||||
const host = makeHost({ S1: { A1: 8, B1: 0 } });
|
||||
|
||||
it('picks the then-branch when the condition is truthy', () => {
|
||||
expect(ev('=IF(1;2;3)', host)).toBe(2);
|
||||
expect(ev('=IF(A1>5;"groß";"klein")', host)).toBe('groß');
|
||||
});
|
||||
|
||||
it('picks the else-branch when the condition is falsy', () => {
|
||||
expect(ev('=IF(0;2;3)', host)).toBe(3);
|
||||
expect(ev('=IF(A1<5;"groß";"klein")', host)).toBe('klein');
|
||||
});
|
||||
|
||||
it('returns 0 for a falsy condition with no else-branch', () => {
|
||||
expect(ev('=IF(0;2)', host)).toBe(0);
|
||||
});
|
||||
|
||||
it('never evaluates the untaken branch (short-circuit)', () => {
|
||||
expect(ev('=IF(1;2;1/0)', host)).toBe(2);
|
||||
expect(ev('=IF(B1=0;0;A1/B1)', host)).toBe(0);
|
||||
});
|
||||
|
||||
it('propagates an error from the condition itself', () => {
|
||||
const r = ev('=IF(1/0;2;3)', host);
|
||||
expect(isError(r) && r.code).toBe('#DIV/0!');
|
||||
});
|
||||
|
||||
it('wrong number of arguments -> #ERR', () => {
|
||||
expect(isError(ev('=IF(1)', host))).toBe(true);
|
||||
expect(isError(ev('=IF(1;2;3;4)', host))).toBe(true);
|
||||
});
|
||||
|
||||
it('works with comparison operators as the condition', () => {
|
||||
expect(ev('=IF(A1>=8;1;0)', host)).toBe(1);
|
||||
expect(ev('=IF(A1<>8;1;0)', host)).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('evaluator cross-sheet & errors', () => {
|
||||
const host = makeHost({
|
||||
S1: { A1: 3 },
|
||||
|
||||
Reference in New Issue
Block a user