diff --git a/app.py b/app.py index 7dcfc9f..4d08384 100644 --- a/app.py +++ b/app.py @@ -219,6 +219,11 @@ def solve_diagram(data: DiagramData): return {"status": "error", "message": f"Input node '{data.input_node}' not found."} if data.output_node not in real_nodes: return {"status": "error", "message": f"Output node '{data.output_node}' not found."} + if not nx.has_path(G, data.input_node, data.output_node): + return { + "status": "error", + "message": f"No forward path from '{data.input_node}' to '{data.output_node}'.", + } raw_loops = list(nx.simple_cycles(G)) loops_data = [] diff --git a/tests/test_solver.py b/tests/test_solver.py index 26ef199..fa9725f 100644 --- a/tests/test_solver.py +++ b/tests/test_solver.py @@ -95,6 +95,26 @@ def test_validate_rejects_missing_output_node(self): self.assertEqual(result["status"], "error") self.assertIn("missing_output_node", {e["type"] for e in result["errors"]}) + def test_solve_rejects_disconnected_output(self): + data = diagram( + [("S", "A", "G")], + nodes=["S", "A", "T"], + ) + validated = validate_diagram(data) + solved = solve_diagram(data) + self.assertEqual(validated["status"], "error") + self.assertIn("no_path", {error["type"] for error in validated["errors"]}) + self.assertEqual(solved["status"], "error") + self.assertIn("No forward path", solved["message"]) + self.assertNotIn("transfer_function_expr", solved) + + def test_solve_rejects_reverse_only_connection(self): + data = diagram([("T", "S", "H")]) + self.assertEqual(validate_diagram(data)["status"], "error") + solved = solve_diagram(data) + self.assertEqual(solved["status"], "error") + self.assertIn("No forward path", solved["message"]) + def test_validate_reports_off_path_and_isolated_nodes(self): result = validate_diagram( diagram([("S", "T", "G")], nodes=["S", "T", "Z"])