"""Tests for reactive conditional rendering with signal updates.""" import pytest from ritz.parser import parse_component from ritz.llvm_codegen_signals import generate_llvm_ir def test_reactive_conditional_infrastructure(): """Test that reactive conditional infrastructure is generated.""" source = """ from ritz.syntax import * @component def Toggle(): visible = signal(1) if visible: with P(): yield "Visible" else: with P(): yield "Hidden" """ ir = parse_component(source) llvm_ir = generate_llvm_ir(ir) # Should have marker global assert "@cond_0_marker = global i32 0" in llvm_ir # Should have current state global assert "@cond_0_current = global i32 0" in llvm_ir # Should have root globals for both branches assert "@cond_0_then_root = global i32 0" in llvm_ir assert "@cond_0_else_root = global i32 0" in llvm_ir # Should have init function assert "define void @_init_conditional_0()" in llvm_ir # Should have reevaluate function (for signal updates) assert "define void @reevaluate_conditional_0()" in llvm_ir # Should have branch render functions assert "define i32 @_render_cond_0_then()" in llvm_ir assert "define i32 @_render_cond_0_else()" in llvm_ir def test_reactive_conditional_init_logic(): """Test that init function pre-renders both branches.""" source = """ from ritz.syntax import * @component def Toggle(): visible = signal(1) if visible: with P(): yield "Shown" else: with P(): yield "Hidden" """ ir = parse_component(source) llvm_ir = generate_llvm_ir(ir) # Init should call both render functions assert "call i32 @_render_cond_0_then()" in llvm_ir assert "call i32 @_render_cond_0_else()" in llvm_ir # Init should store both roots assert "store i32" in llvm_ir and "@cond_0_then_root" in llvm_ir assert "store i32" in llvm_ir and "@cond_0_else_root" in llvm_ir # Init should insert active branch at marker assert "call void @js_replace_at_marker" in llvm_ir def test_reactive_conditional_swap_logic(): """Test that reevaluate function swaps branches when condition changes.""" source = """ from ritz.syntax import * @component def Toggle(): visible = signal(0) if visible: with P(): yield "On" else: with P(): yield "Off" """ ir = parse_component(source) llvm_ir = generate_llvm_ir(ir) # Reevaluate should re-evaluate the condition assert "reevaluate_conditional_0" in llvm_ir # Should check if condition changed assert "icmp ne" in llvm_ir # Should have swap logic assert "swap:" in llvm_ir or "swap_to_then:" in llvm_ir assert "swap_to_then:" in llvm_ir assert "swap_to_else:" in llvm_ir def test_multiple_reactive_conditionals(): """Test multiple if statements in same component get unique IDs.""" source = """ from ritz.syntax import * @component def MultiToggle(): flag1 = signal(1) flag2 = signal(0) if flag1: with P(): yield "First on" if flag2: with P(): yield "Second on" """ ir = parse_component(source) llvm_ir = generate_llvm_ir(ir) # Should have two separate conditionals assert "@cond_0_marker" in llvm_ir assert "@cond_1_marker" in llvm_ir # Should have init functions for both assert "define void @_init_conditional_0()" in llvm_ir assert "define void @_init_conditional_1()" in llvm_ir # Should have reevaluate functions for both assert "define void @reevaluate_conditional_0()" in llvm_ir assert "define void @reevaluate_conditional_1()" in llvm_ir def test_reactive_conditional_with_comparison(): """Test reactive conditional with comparison operator.""" source = """ from ritz.syntax import * @component def Counter(): count = signal(0) if count > 5: with P(): yield "High" else: with P(): yield "Low" """ ir = parse_component(source) llvm_ir = generate_llvm_ir(ir) # Should generate icmp for comparison assert "icmp" in llvm_ir assert "sgt" in llvm_ir # signed greater than # Should still have reactive infrastructure assert "@_init_conditional_0()" in llvm_ir assert "@reevaluate_conditional_0()" in llvm_ir