Skip to content

Commit 915ef59

Browse files
committed
test(short-circuit): add comprehensive nested control flow tests
Add tests for deeply nested structures including: - Nested and chained ternary expressions - Chained logical operators (||, &&, ??) - Mixed operator combinations - Nullish coalescing with logical operators
1 parent 1a836ad commit 915ef59

1 file changed

Lines changed: 225 additions & 0 deletions

File tree

src/integration.short-circuit.test.ts

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,231 @@ describe("短路求值测试", () => {
125125
expect(evaluate<boolean>(compiled, { a: false, b: true, c: true, d: true, e: true })).toBe(true);
126126
expect(evaluate<boolean>(compiled, { a: false, b: true, c: true, d: false, e: true })).toBe(false);
127127
});
128+
129+
test("嵌套三元表达式: a ? (b ? c : d) : e", () => {
130+
const a = variable(z.boolean());
131+
const b = variable(z.boolean());
132+
const c = variable(z.number());
133+
const d = variable(z.number());
134+
const e = variable(z.number());
135+
136+
const result = expr({ a, b, c, d, e })("a ? (b ? c : d) : e");
137+
const compiled = compile(result, { a, b, c, d, e }, { shortCircuit: true });
138+
139+
// a=true, b=true: c
140+
expect(evaluate<number>(compiled, { a: true, b: true, c: 1, d: 2, e: 3 })).toBe(1);
141+
// a=true, b=false: d
142+
expect(evaluate<number>(compiled, { a: true, b: false, c: 1, d: 2, e: 3 })).toBe(2);
143+
// a=false: e
144+
expect(evaluate<number>(compiled, { a: false, b: true, c: 1, d: 2, e: 3 })).toBe(3);
145+
expect(evaluate<number>(compiled, { a: false, b: false, c: 1, d: 2, e: 3 })).toBe(3);
146+
});
147+
148+
test("深度嵌套三元表达式: a ? b ? c ? 1 : 2 : 3 : 4", () => {
149+
const a = variable(z.boolean());
150+
const b = variable(z.boolean());
151+
const c = variable(z.boolean());
152+
153+
const result = expr({ a, b, c })("a ? b ? c ? 1 : 2 : 3 : 4");
154+
const compiled = compile(result, { a, b, c }, { shortCircuit: true });
155+
156+
expect(evaluate<number>(compiled, { a: true, b: true, c: true })).toBe(1);
157+
expect(evaluate<number>(compiled, { a: true, b: true, c: false })).toBe(2);
158+
expect(evaluate<number>(compiled, { a: true, b: false, c: true })).toBe(3);
159+
expect(evaluate<number>(compiled, { a: true, b: false, c: false })).toBe(3);
160+
expect(evaluate<number>(compiled, { a: false, b: true, c: true })).toBe(4);
161+
expect(evaluate<number>(compiled, { a: false, b: false, c: false })).toBe(4);
162+
});
163+
164+
test("链式逻辑或: a || b || c || d", () => {
165+
const a = variable(z.number());
166+
const b = variable(z.number());
167+
const c = variable(z.number());
168+
const d = variable(z.number());
169+
170+
const result = expr({ a, b, c, d })("a || b || c || d");
171+
const compiled = compile(result, { a, b, c, d }, { shortCircuit: true });
172+
173+
// 第一个 truthy 值应该被返回
174+
expect(evaluate<number>(compiled, { a: 1, b: 2, c: 3, d: 4 })).toBe(1);
175+
expect(evaluate<number>(compiled, { a: 0, b: 2, c: 3, d: 4 })).toBe(2);
176+
expect(evaluate<number>(compiled, { a: 0, b: 0, c: 3, d: 4 })).toBe(3);
177+
expect(evaluate<number>(compiled, { a: 0, b: 0, c: 0, d: 4 })).toBe(4);
178+
expect(evaluate<number>(compiled, { a: 0, b: 0, c: 0, d: 0 })).toBe(0);
179+
});
180+
181+
test("链式逻辑与: a && b && c && d", () => {
182+
const a = variable(z.number());
183+
const b = variable(z.number());
184+
const c = variable(z.number());
185+
const d = variable(z.number());
186+
187+
const result = expr({ a, b, c, d })("a && b && c && d");
188+
const compiled = compile(result, { a, b, c, d }, { shortCircuit: true });
189+
190+
// 第一个 falsy 值或最后一个值应该被返回
191+
expect(evaluate<number>(compiled, { a: 1, b: 2, c: 3, d: 4 })).toBe(4);
192+
expect(evaluate<number>(compiled, { a: 0, b: 2, c: 3, d: 4 })).toBe(0);
193+
expect(evaluate<number>(compiled, { a: 1, b: 0, c: 3, d: 4 })).toBe(0);
194+
expect(evaluate<number>(compiled, { a: 1, b: 2, c: 0, d: 4 })).toBe(0);
195+
expect(evaluate<number>(compiled, { a: 1, b: 2, c: 3, d: 0 })).toBe(0);
196+
});
197+
198+
test("链式空值合并: a ?? b ?? c ?? d", () => {
199+
const a = variable(z.union([z.number(), z.null()]));
200+
const b = variable(z.union([z.number(), z.null()]));
201+
const c = variable(z.union([z.number(), z.null()]));
202+
const d = variable(z.number());
203+
204+
const result = expr({ a, b, c, d })("a ?? b ?? c ?? d");
205+
const compiled = compile(result, { a, b, c, d }, { shortCircuit: true });
206+
207+
expect(evaluate<number>(compiled, { a: 1, b: 2, c: 3, d: 4 })).toBe(1);
208+
expect(evaluate<number>(compiled, { a: null, b: 2, c: 3, d: 4 })).toBe(2);
209+
expect(evaluate<number>(compiled, { a: null, b: null, c: 3, d: 4 })).toBe(3);
210+
expect(evaluate<number>(compiled, { a: null, b: null, c: null, d: 4 })).toBe(4);
211+
// 0 不是 null,应该返回 0
212+
expect(evaluate<number>(compiled, { a: 0, b: 2, c: 3, d: 4 })).toBe(0);
213+
});
214+
215+
test("混合运算符: (a || b) && (c || d)", () => {
216+
const a = variable(z.boolean());
217+
const b = variable(z.boolean());
218+
const c = variable(z.boolean());
219+
const d = variable(z.boolean());
220+
221+
const result = expr({ a, b, c, d })("(a || b) && (c || d)");
222+
const compiled = compile(result, { a, b, c, d }, { shortCircuit: true });
223+
224+
expect(evaluate<boolean>(compiled, { a: true, b: false, c: true, d: false })).toBe(true);
225+
expect(evaluate<boolean>(compiled, { a: false, b: true, c: false, d: true })).toBe(true);
226+
expect(evaluate<boolean>(compiled, { a: false, b: false, c: true, d: true })).toBe(false);
227+
expect(evaluate<boolean>(compiled, { a: true, b: true, c: false, d: false })).toBe(false);
228+
});
229+
230+
test("混合运算符: a && b || c && d", () => {
231+
const a = variable(z.boolean());
232+
const b = variable(z.boolean());
233+
const c = variable(z.boolean());
234+
const d = variable(z.boolean());
235+
236+
const result = expr({ a, b, c, d })("a && b || c && d");
237+
const compiled = compile(result, { a, b, c, d }, { shortCircuit: true });
238+
239+
// (a && b) || (c && d)
240+
expect(evaluate<boolean>(compiled, { a: true, b: true, c: false, d: false })).toBe(true);
241+
expect(evaluate<boolean>(compiled, { a: false, b: true, c: true, d: true })).toBe(true);
242+
expect(evaluate<boolean>(compiled, { a: false, b: false, c: false, d: false })).toBe(false);
243+
expect(evaluate<boolean>(compiled, { a: true, b: false, c: true, d: false })).toBe(false);
244+
});
245+
246+
test("三元表达式内嵌套逻辑运算: a ? b && c : d || e", () => {
247+
const a = variable(z.boolean());
248+
const b = variable(z.boolean());
249+
const c = variable(z.boolean());
250+
const d = variable(z.boolean());
251+
const e = variable(z.boolean());
252+
253+
const result = expr({ a, b, c, d, e })("a ? b && c : d || e");
254+
const compiled = compile(result, { a, b, c, d, e }, { shortCircuit: true });
255+
256+
// a=true: b && c
257+
expect(evaluate<boolean>(compiled, { a: true, b: true, c: true, d: false, e: false })).toBe(true);
258+
expect(evaluate<boolean>(compiled, { a: true, b: true, c: false, d: true, e: true })).toBe(false);
259+
expect(evaluate<boolean>(compiled, { a: true, b: false, c: true, d: true, e: true })).toBe(false);
260+
261+
// a=false: d || e
262+
expect(evaluate<boolean>(compiled, { a: false, b: true, c: true, d: true, e: false })).toBe(true);
263+
expect(evaluate<boolean>(compiled, { a: false, b: true, c: true, d: false, e: true })).toBe(true);
264+
expect(evaluate<boolean>(compiled, { a: false, b: true, c: true, d: false, e: false })).toBe(false);
265+
});
266+
267+
test("逻辑运算作为三元条件: (a && b) ? c : d", () => {
268+
const a = variable(z.boolean());
269+
const b = variable(z.boolean());
270+
const c = variable(z.number());
271+
const d = variable(z.number());
272+
273+
const result = expr({ a, b, c, d })("(a && b) ? c : d");
274+
const compiled = compile(result, { a, b, c, d }, { shortCircuit: true });
275+
276+
expect(evaluate<number>(compiled, { a: true, b: true, c: 1, d: 2 })).toBe(1);
277+
expect(evaluate<number>(compiled, { a: true, b: false, c: 1, d: 2 })).toBe(2);
278+
expect(evaluate<number>(compiled, { a: false, b: true, c: 1, d: 2 })).toBe(2);
279+
expect(evaluate<number>(compiled, { a: false, b: false, c: 1, d: 2 })).toBe(2);
280+
});
281+
282+
test("复杂嵌套: (a || b) ? (c && d) : (e ?? f)", () => {
283+
const a = variable(z.boolean());
284+
const b = variable(z.boolean());
285+
const c = variable(z.boolean());
286+
const d = variable(z.boolean());
287+
const e = variable(z.union([z.boolean(), z.null()]));
288+
const f = variable(z.boolean());
289+
290+
const result = expr({ a, b, c, d, e, f })("(a || b) ? (c && d) : (e ?? f)");
291+
const compiled = compile(result, { a, b, c, d, e, f }, { shortCircuit: true });
292+
293+
// 条件为 true: c && d
294+
expect(evaluate<boolean>(compiled, { a: true, b: false, c: true, d: true, e: null, f: false })).toBe(true);
295+
expect(evaluate<boolean>(compiled, { a: false, b: true, c: false, d: true, e: null, f: false })).toBe(false);
296+
297+
// 条件为 false: e ?? f
298+
expect(evaluate<boolean>(compiled, { a: false, b: false, c: true, d: true, e: true, f: false })).toBe(true);
299+
expect(evaluate<boolean>(compiled, { a: false, b: false, c: true, d: true, e: null, f: true })).toBe(true);
300+
expect(evaluate<boolean>(compiled, { a: false, b: false, c: true, d: true, e: null, f: false })).toBe(false);
301+
});
302+
303+
test("多层嵌套三元: a ? (b ? (c ? 1 : 2) : (d ? 3 : 4)) : (e ? 5 : 6)", () => {
304+
const a = variable(z.boolean());
305+
const b = variable(z.boolean());
306+
const c = variable(z.boolean());
307+
const d = variable(z.boolean());
308+
const e = variable(z.boolean());
309+
310+
const result = expr({ a, b, c, d, e })("a ? (b ? (c ? 1 : 2) : (d ? 3 : 4)) : (e ? 5 : 6)");
311+
const compiled = compile(result, { a, b, c, d, e }, { shortCircuit: true });
312+
313+
// a=true, b=true
314+
expect(evaluate<number>(compiled, { a: true, b: true, c: true, d: false, e: false })).toBe(1);
315+
expect(evaluate<number>(compiled, { a: true, b: true, c: false, d: false, e: false })).toBe(2);
316+
317+
// a=true, b=false
318+
expect(evaluate<number>(compiled, { a: true, b: false, c: false, d: true, e: false })).toBe(3);
319+
expect(evaluate<number>(compiled, { a: true, b: false, c: false, d: false, e: false })).toBe(4);
320+
321+
// a=false
322+
expect(evaluate<number>(compiled, { a: false, b: false, c: false, d: false, e: true })).toBe(5);
323+
expect(evaluate<number>(compiled, { a: false, b: false, c: false, d: false, e: false })).toBe(6);
324+
});
325+
326+
test("空值合并与逻辑或混合: (a ?? b) || c", () => {
327+
const a = variable(z.union([z.number(), z.null()]));
328+
const b = variable(z.number());
329+
const c = variable(z.number());
330+
331+
const result = expr({ a, b, c })("(a ?? b) || c");
332+
const compiled = compile(result, { a, b, c }, { shortCircuit: true });
333+
334+
expect(evaluate<number>(compiled, { a: 5, b: 10, c: 20 })).toBe(5);
335+
expect(evaluate<number>(compiled, { a: null, b: 10, c: 20 })).toBe(10);
336+
expect(evaluate<number>(compiled, { a: null, b: 0, c: 20 })).toBe(20);
337+
expect(evaluate<number>(compiled, { a: 0, b: 10, c: 20 })).toBe(20); // 0 非 null 但 falsy
338+
});
339+
340+
test("空值合并与逻辑与混合: (a ?? b) && c", () => {
341+
const a = variable(z.union([z.number(), z.null()]));
342+
const b = variable(z.number());
343+
const c = variable(z.number());
344+
345+
const result = expr({ a, b, c })("(a ?? b) && c");
346+
const compiled = compile(result, { a, b, c }, { shortCircuit: true });
347+
348+
expect(evaluate<number>(compiled, { a: 5, b: 10, c: 20 })).toBe(20);
349+
expect(evaluate<number>(compiled, { a: null, b: 10, c: 20 })).toBe(20);
350+
expect(evaluate<number>(compiled, { a: null, b: 0, c: 20 })).toBe(0);
351+
expect(evaluate<number>(compiled, { a: 0, b: 10, c: 20 })).toBe(0); // 0 非 null 但 falsy
352+
});
128353
});
129354

130355
describe("与非短路模式对比", () => {

0 commit comments

Comments
 (0)