# MathML AAM Reference: https://w3c.github.io/mathml-aam/#mathml-element-mappings import pytest TEST_DATA_ATTRIBUTES = { "a": { "html": """Link""", }, "annotation": { "html": "2\\text{two}", }, "annotation-xml": { "html": "2two", }, "maction": { "html": "12", }, "math": { "html": "1", }, "merror": { "html": "Divide by zero", }, "mfrac": { "html": "12", "axapi": {"AXMathFractionNumerator": "num", "AXMathFractionDenominator": "den"} }, "mi": { "html": "x", }, # mmultiscripts object reference tested in mathml-aam/aamtests/attribute/mmultiscripts.py "mmultiscripts": { "html": "X1234", }, "mn": { "html": "2", }, "mo": { "html": "+", }, "mover": { "html": "a˙", "axapi": {"AXMathBase": "base", "AXMathOver": "over"} }, "mpadded": { "html": "1", }, "mphantom": { "html": "1", }, "mprescripts": { "html": "X1234" }, "mroot": { "html": "x3", "axapi": {"AXMathRootRadicand": "rad", "AXMathRootIndex": "idx"} }, "mrow": { "html": "1+1", }, "ms": { "html": """"string"""", }, "mspace": { "html": "" }, "msqrt": { "html": "x", "axapi": {"AXMathRootRadicand": "rad1"} }, "mstyle": { "html": "1", }, "msub": { "html": "x1", "axapi": {"AXMathBase": "base", "AXMathSubscript": "sub"} }, "msubsup": { "html": "x12", "axapi": {"AXMathBase": "base", "AXMathSubscript": "sub", "AXMathSuperscript": "sup"} }, "msup": { "html": "x2", "axapi": {"AXMathBase": "base", "AXMathSuperscript": "sup"} }, "mtable": { "html": "1", "atspi": {"interface": "AtkTable"} }, "mtd": { "html": "1", "atspi": {"interface": "AtkTableCell"} }, "mtext": { "html": "hello", }, "mtr": { "html": "1", }, "munder": { "html": "x_", "axapi": {"AXMathBase": "base", "AXMathUnder": "under"} }, "munderover": { "html": "x_˙", "axapi": {"AXMathBase": "base", "AXMathUnder": "under", "AXMathOver": "over"} }, "none": { "html": "X1" }, "semantics": { "html": "55", } } @pytest.mark.parametrize("element_name", TEST_DATA_ATTRIBUTES.keys()) def test_atspi(atspi, session, inline, element_name): data = TEST_DATA_ATTRIBUTES[element_name] session.url = inline(data["html"]) node = atspi.find_node("test", session.url) obj_attrs = atspi.Accessible.get_attributes(node) assert "tag" in obj_attrs, f"<{element_name}> object attributes missing 'tag' key. Found: {obj_attrs}" assert obj_attrs["tag"] == element_name, f"Expected tag '{element_name}', got '{obj_attrs['tag']}'" atspi_config = data.get("atspi", {}) interface_name = atspi_config.get("interface") if interface_name: obj = atspi.get_interface(node, interface_name) assert obj is not None, f"{element_name} node must implement {interface_name} interface" AX_ATTR_CASES = [name for name, d in TEST_DATA_ATTRIBUTES.items() if "axapi" in d] @pytest.mark.parametrize("element_name", AX_ATTR_CASES) def test_axapi(axapi, session, inline, element_name): data = TEST_DATA_ATTRIBUTES[element_name] session.url = inline(data["html"]) node = axapi.find_node("test", session.url) expected_relationships = data["axapi"] for ax_attr_key, expected_dom_id in expected_relationships.items(): attr_res = axapi.AXUIElementCopyAttributeValue(node, ax_attr_key, None) target_node = attr_res[1] if (attr_res and len(attr_res) > 1) else None assert target_node is not None, f"Relationship attribute '{ax_attr_key}' on <{element_name}> returned None." actual_dom_id = axapi.AXUIElementCopyAttributeValue(target_node, "AXDOMIdentifier", None)[1] assert actual_dom_id == expected_dom_id, f"Pointer '{ax_attr_key}' expected to target id '{expected_dom_id}', but got '{actual_dom_id}'"