"""Tests for reactive attributes that update when signals change.""" import pytest from ritz.parser import parse_component from ritz.llvm_codegen_signals import generate_llvm_ir def test_parse_reactive_attribute(): """Test parsing attribute with signal dependency.""" source = """ from ritz.syntax import * @component def Toggle(): active = signal(1) with Button(class_='active' if active else 'inactive'): yield "Click" """ ir = parse_component(source) # Should have ternary expression in class attribute with_stmt = [s for s in ir["body"] if s["type"] == "with"][0] class_prop = with_stmt["element"]["props"]["class_"] assert class_prop["type"] == "ifexp" assert class_prop["test"]["id"] == "active" def test_reactive_attribute_infrastructure(): """Test that reactive attribute tracking is generated.""" source = """ from ritz.syntax import * @component def Toggle(): active = signal(1) def toggle(): active = 0 if active else 1 with Button(class_='btn-active' if active else 'btn-inactive', onclick=toggle): yield "Toggle" """ ir = parse_component(source) llvm_ir = generate_llvm_ir(ir) # Should have storage for the button element assert "@reactive_attr_" in llvm_ir or "@elem_" in llvm_ir # Should update attribute when signal changes in toggle() # The toggle function should re-evaluate the class expression and update assert "js_set_attribute" in llvm_ir def test_multiple_reactive_attributes(): """Test multiple elements with reactive attributes.""" source = """ from ritz.syntax import * @component def Tabs(): tab = signal(0) def set_tab(value): tab = value with Ul(): with Li(class_='active' if tab == 0 else ''): yield "Tab 0" with Li(class_='active' if tab == 1 else ''): yield "Tab 1" """ ir = parse_component(source) llvm_ir = generate_llvm_ir(ir) # Both Li elements should have reactive attributes # When tab signal changes, both should update assert llvm_ir.count("js_set_attribute") >= 2 def test_reactive_attribute_with_comparison(): """Test reactive attribute with comparison in ternary.""" source = """ from ritz.syntax import * @component def Counter(): count = signal(5) with Div(class_='high' if count > 10 else 'low'): yield "Value" """ ir = parse_component(source) llvm_ir = generate_llvm_ir(ir) # Should emit comparison when evaluating class assert "icmp" in llvm_ir assert "select" in llvm_ir