@@ -1328,6 +1328,121 @@ def test_format_invalid_class_raises(self):
13281328 f"{ TrafficLightMachine :invalid} "
13291329
13301330
1331+ class TestFormatter :
1332+ """Tests for the Formatter facade (render, register_format, supported_formats)."""
1333+
1334+ def test_render_mermaid (self ):
1335+ from statemachine .contrib .diagram import formatter
1336+
1337+ from tests .examples .traffic_light_machine import TrafficLightMachine
1338+
1339+ result = formatter .render (TrafficLightMachine , "mermaid" )
1340+ assert "stateDiagram-v2" in result
1341+
1342+ def test_render_dot (self ):
1343+ from statemachine .contrib .diagram import formatter
1344+
1345+ from tests .examples .traffic_light_machine import TrafficLightMachine
1346+
1347+ result = formatter .render (TrafficLightMachine , "dot" )
1348+ assert result .startswith ("digraph TrafficLightMachine {" )
1349+
1350+ def test_render_md (self ):
1351+ from statemachine .contrib .diagram import formatter
1352+
1353+ from tests .examples .traffic_light_machine import TrafficLightMachine
1354+
1355+ result = formatter .render (TrafficLightMachine , "md" )
1356+ assert "| State" in result
1357+
1358+ def test_render_markdown_alias (self ):
1359+ from statemachine .contrib .diagram import formatter
1360+
1361+ from tests .examples .traffic_light_machine import TrafficLightMachine
1362+
1363+ assert formatter .render (TrafficLightMachine , "markdown" ) == formatter .render (
1364+ TrafficLightMachine , "md"
1365+ )
1366+
1367+ def test_render_rst (self ):
1368+ from statemachine .contrib .diagram import formatter
1369+
1370+ from tests .examples .traffic_light_machine import TrafficLightMachine
1371+
1372+ result = formatter .render (TrafficLightMachine , "rst" )
1373+ assert "+---" in result
1374+
1375+ def test_render_empty_repr_instance (self ):
1376+ from statemachine .contrib .diagram import formatter
1377+
1378+ from tests .examples .traffic_light_machine import TrafficLightMachine
1379+
1380+ sm = TrafficLightMachine ()
1381+ assert formatter .render (sm , "" ) == repr (sm )
1382+
1383+ def test_render_empty_repr_class (self ):
1384+ from statemachine .contrib .diagram import formatter
1385+
1386+ from tests .examples .traffic_light_machine import TrafficLightMachine
1387+
1388+ assert formatter .render (TrafficLightMachine , "" ) == repr (TrafficLightMachine )
1389+
1390+ def test_render_invalid_raises (self ):
1391+ from statemachine .contrib .diagram import formatter
1392+
1393+ with pytest .raises (ValueError , match = "Unsupported format" ):
1394+ formatter .render (object (), "invalid" )
1395+
1396+ def test_supported_formats (self ):
1397+ from statemachine .contrib .diagram import formatter
1398+
1399+ fmts = formatter .supported_formats ()
1400+ assert "dot" in fmts
1401+ assert "mermaid" in fmts
1402+ assert "md" in fmts
1403+ assert "markdown" in fmts
1404+ assert "rst" in fmts
1405+
1406+ def test_register_custom_format (self ):
1407+ from statemachine .contrib .diagram import formatter
1408+
1409+ @formatter .register_format ("_test_custom" )
1410+ def _render_custom (machine_or_class ):
1411+ return "custom output"
1412+
1413+ try :
1414+ assert formatter .render (object (), "_test_custom" ) == "custom output"
1415+ finally :
1416+ formatter ._formats .pop ("_test_custom" , None )
1417+
1418+ def test_register_format_with_aliases (self ):
1419+ from statemachine .contrib .diagram import formatter
1420+
1421+ @formatter .register_format ("_test_alias" , "_test_alias2" )
1422+ def _render_alias_test (machine_or_class ):
1423+ return "alias output"
1424+
1425+ try :
1426+ assert formatter .render (object (), "_test_alias" ) == "alias output"
1427+ assert formatter .render (object (), "_test_alias2" ) == "alias output"
1428+ finally :
1429+ formatter ._formats .pop ("_test_alias" , None )
1430+ formatter ._formats .pop ("_test_alias2" , None )
1431+
1432+ def test_error_message_lists_primary_formats (self ):
1433+ from statemachine .contrib .diagram import formatter
1434+
1435+ with pytest .raises (ValueError , match = "'dot'" ) as exc_info :
1436+ formatter .render (object (), "nonexistent" )
1437+ msg = str (exc_info .value )
1438+ # Should list primary names, not aliases
1439+ assert "'mermaid'" in msg
1440+ assert "'md'" in msg
1441+ assert "'rst'" in msg
1442+ # "markdown" is an alias, should not appear in error message
1443+ assert "'markdown'" not in msg
1444+
1445+
13311446class TestDirectiveMermaidFormat :
13321447 """Tests for the :format: mermaid Sphinx directive option."""
13331448
0 commit comments