"""Entropyk — End-to-End Solver Tests. Tests for System construction, finalization, and solving from Python. """ import pytest import entropyk class TestSystemConstruction: """Tests for System graph building.""" def test_empty_system(self): system = entropyk.System() assert system.node_count == 0 assert system.edge_count == 0 def test_add_component(self): system = entropyk.System() idx = system.add_component(entropyk.Condenser(ua=5000.0)) assert idx == 0 assert system.node_count == 1 def test_add_multiple_components(self): system = entropyk.System() i0 = system.add_component(entropyk.Compressor()) i1 = system.add_component(entropyk.Condenser()) i2 = system.add_component(entropyk.ExpansionValve()) i3 = system.add_component(entropyk.Evaporator()) assert system.node_count == 4 assert i0 != i1 != i2 != i3 def test_add_edge(self): system = entropyk.System() i0 = system.add_component(entropyk.Compressor()) i1 = system.add_component(entropyk.Condenser()) edge_idx = system.add_edge(i0, i1) assert edge_idx == 0 assert system.edge_count == 1 def test_repr(self): system = entropyk.System() system.add_component(entropyk.Compressor()) system.add_component(entropyk.Condenser()) system.add_edge(0, 1) r = repr(system) assert "System" in r assert "nodes=2" in r assert "edges=1" in r class TestSystemFinalize: """Tests for system finalization.""" def test_simple_cycle_finalize(self): """Build and finalize a simple 4-component cycle.""" system = entropyk.System() comp = system.add_component(entropyk.Compressor()) cond = system.add_component(entropyk.Condenser()) exv = system.add_component(entropyk.ExpansionValve()) evap = system.add_component(entropyk.Evaporator()) system.add_edge(comp, cond) system.add_edge(cond, exv) system.add_edge(exv, evap) system.add_edge(evap, comp) system.finalize() assert system.state_vector_len > 0 class TestSolverConfigs: """Tests for solver configuration objects.""" def test_newton_default(self): config = entropyk.NewtonConfig() assert "NewtonConfig" in repr(config) assert "100" in repr(config) def test_newton_custom(self): config = entropyk.NewtonConfig( max_iterations=200, tolerance=1e-8, line_search=True, timeout_ms=5000, ) assert "200" in repr(config) def test_picard_default(self): config = entropyk.PicardConfig() assert "PicardConfig" in repr(config) def test_picard_custom(self): config = entropyk.PicardConfig( max_iterations=300, tolerance=1e-5, relaxation=0.7, ) assert "300" in repr(config) def test_picard_invalid_relaxation_raises(self): with pytest.raises(ValueError, match="between"): entropyk.PicardConfig(relaxation=1.5) def test_fallback_default(self): config = entropyk.FallbackConfig() assert "FallbackConfig" in repr(config) def test_fallback_custom(self): newton = entropyk.NewtonConfig(max_iterations=50) picard = entropyk.PicardConfig(max_iterations=200) config = entropyk.FallbackConfig(newton=newton, picard=picard) assert "50" in repr(config) class TestConvergedState: """Tests for ConvergedState and ConvergenceStatus types.""" def test_convergence_status_repr(self): # We can't easily create a ConvergedState without solving, # so we just verify the classes exist assert hasattr(entropyk, "ConvergedState") assert hasattr(entropyk, "ConvergenceStatus") class TestAllComponentsInSystem: """Test that all component types can be added to a System.""" @pytest.mark.parametrize("component_factory", [ lambda: entropyk.Compressor(), lambda: entropyk.Condenser(), lambda: entropyk.Evaporator(), lambda: entropyk.Economizer(), lambda: entropyk.ExpansionValve(), lambda: entropyk.Pipe(), lambda: entropyk.Pump(), lambda: entropyk.Fan(), lambda: entropyk.FlowSplitter(), lambda: entropyk.FlowMerger(), lambda: entropyk.FlowSource(), lambda: entropyk.FlowSink(), ]) def test_add_component(self, component_factory): system = entropyk.System() idx = system.add_component(component_factory()) assert idx >= 0 assert system.node_count == 1