from pathlib import Path
from semantic_kernel import index_project
from sir import EdgeKind, NodeKind
from ui_semantics import form_semantics
def test_index_project_extracts_xml_ui_semantics(tmp_path: Path):
xml = tmp_path / "form.xml"
xml.write_text(
"""
""",
encoding="utf-8",
)
snapshot = index_project(tmp_path, project_id="demo")
assert any(node.kind == NodeKind.FORM for node in snapshot.nodes)
assert any(edge.kind == EdgeKind.HAS_COMMAND for edge in snapshot.edges)
assert form_semantics(snapshot)[0].commands[0].name == "Провести"
def test_index_project_extracts_1c_metadata_objects(tmp_path: Path):
xml = tmp_path / "metadata.xml"
xml.write_text(
"""
ОбменСКассовымУзломРегламентноеЗадание.ОбменСКассовымУзлом
""",
encoding="utf-8",
)
snapshot = index_project(tmp_path, project_id="metadata")
assert any(node.kind == NodeKind.CATALOG and node.name == "Номенклатура" for node in snapshot.nodes)
assert any(node.kind == NodeKind.DOCUMENT and node.name == "ЗаказПокупателя" for node in snapshot.nodes)
assert any(node.kind == NodeKind.TABULAR_SECTION and node.name == "Товары" for node in snapshot.nodes)
assert any(node.kind == NodeKind.ROLE and node.name == "Менеджер" for node in snapshot.nodes)
assert any(node.kind == NodeKind.SCHEDULED_JOB for node in snapshot.nodes)
assert any(edge.kind == EdgeKind.HAS_ATTRIBUTE for edge in snapshot.edges)
assert any(edge.kind == EdgeKind.HAS_TABULAR_SECTION for edge in snapshot.edges)
tabular_section = next(node for node in snapshot.nodes if node.kind == NodeKind.TABULAR_SECTION)
column = next(node for node in snapshot.nodes if node.kind == NodeKind.ATTRIBUTE and node.name == "Номенклатура")
assert any(
edge.kind == EdgeKind.HAS_ATTRIBUTE
and edge.source_lineage == tabular_section.lineage_id
and edge.target_lineage == column.lineage_id
for edge in snapshot.edges
)
assert any(edge.kind == EdgeKind.HAS_FORM for edge in snapshot.edges)
assert any(edge.kind == EdgeKind.HAS_COMMAND for edge in snapshot.edges)
def test_index_project_keeps_extended_1c_metadata_objects(tmp_path: Path):
xml = tmp_path / "metadata.xml"
xml.write_text(
"""
""",
encoding="utf-8",
)
snapshot = index_project(tmp_path, project_id="extended-metadata")
by_kind = {node.kind for node in snapshot.nodes}
assert {
NodeKind.SUBSYSTEM,
NodeKind.ROLE,
NodeKind.SEQUENCE,
NodeKind.DOCUMENT_NUMERATOR,
NodeKind.COMMON_FORM,
NodeKind.FUNCTIONAL_OPTION,
NodeKind.WEB_SERVICE,
NodeKind.WS_REFERENCE,
NodeKind.WEBSOCKET_CLIENT,
NodeKind.INTEGRATION_SERVICE,
}.issubset(by_kind)
def test_index_project_remaps_edges_from_duplicate_metadata_nodes(tmp_path: Path):
first = tmp_path / "first.xml"
first.write_text(
"""
СвойстваОбъектовПланВидовХарактеристик.СвойстваОбъектов
""",
encoding="utf-8",
)
second = tmp_path / "second.xml"
second.write_text(
"""
СвойстваОбъектовПланВидовХарактеристик.СвойстваОбъектов
""",
encoding="utf-8",
)
snapshot = index_project(tmp_path, project_id="metadata-duplicates")
chart = next(node for node in snapshot.nodes if node.kind == NodeKind.CHART_OF_CHARACTERISTIC_TYPES)
attribute = next(node for node in snapshot.nodes if node.kind == NodeKind.ATTRIBUTE)
assert any(
edge.kind == EdgeKind.HAS_ATTRIBUTE
and edge.source_lineage == chart.lineage_id
and edge.target_lineage == attribute.lineage_id
for edge in snapshot.edges
)
def test_index_project_links_document_metadata_to_object_module(tmp_path: Path):
xml = tmp_path / "metadata.xml"
xml.write_text(
"""
""",
encoding="utf-8",
)
module = tmp_path / "Documents" / "ЗаказПокупателя" / "Ext" / "ObjectModule.bsl"
module.parent.mkdir(parents=True)
module.write_text(
"""
Процедура Проведение()
КонецПроцедуры
""",
encoding="utf-8",
)
snapshot = index_project(tmp_path, project_id="metadata-links")
document = next(node for node in snapshot.nodes if node.kind == NodeKind.DOCUMENT)
module_node = next(node for node in snapshot.nodes if node.kind == NodeKind.MODULE)
link = next(
edge
for edge in snapshot.edges
if edge.kind == EdgeKind.CONTAINS
and edge.source_lineage == document.lineage_id
and edge.target_lineage == module_node.lineage_id
)
assert link.attributes["module_role"] == "OBJECT_MODULE"
def test_index_project_links_common_module_metadata_to_bsl_module(tmp_path: Path):
xml = tmp_path / "metadata.xml"
xml.write_text(
"""
""",
encoding="utf-8",
)
module = tmp_path / "CommonModules" / "ИнтеграцияСКассой" / "Module.bsl"
module.parent.mkdir(parents=True)
module.write_text(
"""
Процедура ОтправитьЧек()
КонецПроцедуры
""",
encoding="utf-8",
)
snapshot = index_project(tmp_path, project_id="common-module-links")
common_module = next(node for node in snapshot.nodes if node.kind == NodeKind.COMMON_MODULE)
bsl_module = next(node for node in snapshot.nodes if node.kind == NodeKind.MODULE)
assert any(
edge.kind == EdgeKind.CONTAINS
and edge.source_lineage == common_module.lineage_id
and edge.target_lineage == bsl_module.lineage_id
for edge in snapshot.edges
)
def test_index_project_reads_edt_mdo_metadata(tmp_path: Path):
catalog_dir = tmp_path / "src" / "Catalogs" / "Товары"
catalog_dir.mkdir(parents=True)
(catalog_dir / "Товары.mdo").write_text(
"""
ТоварыАртикулФормаЭлемента
""",
encoding="utf-8",
)
report_dir = tmp_path / "src" / "Reports" / "АнализПродаж"
report_dir.mkdir(parents=True)
(report_dir / "АнализПродаж.mdo").write_text(
"""
АнализПродаж
""",
encoding="utf-8",
)
snapshot = index_project(tmp_path, project_id="edt-mdo")
catalog = next(node for node in snapshot.nodes if node.kind == NodeKind.CATALOG)
attribute = next(node for node in snapshot.nodes if node.kind == NodeKind.ATTRIBUTE and node.name == "Артикул")
form = next(node for node in snapshot.nodes if node.kind == NodeKind.FORM)
report = next(node for node in snapshot.nodes if node.kind == NodeKind.REPORT)
assert catalog.qualified_name == "Справочник.Товары"
assert attribute.qualified_name == "Справочник.Товары.Артикул"
assert form.qualified_name == "Справочник.Товары.ФормаЭлемента"
assert report.qualified_name == "Отчет.АнализПродаж"
assert any(edge.kind == EdgeKind.HAS_ATTRIBUTE and edge.source_lineage == catalog.lineage_id for edge in snapshot.edges)
assert any(edge.kind == EdgeKind.HAS_FORM and edge.source_lineage == catalog.lineage_id for edge in snapshot.edges)
def test_index_project_preserves_register_dimension_and_resource_roles(tmp_path: Path):
register_dir = tmp_path / "src" / "AccumulationRegisters" / "ОстаткиТоваров"
register_dir.mkdir(parents=True)
(register_dir / "ОстаткиТоваров.mdo").write_text(
"""
ОстаткиТоваровНоменклатураКоличество
""",
encoding="utf-8",
)
snapshot = index_project(tmp_path, project_id="register-fields")
register = next(node for node in snapshot.nodes if node.kind == NodeKind.REGISTER)
dimension = next(node for node in snapshot.nodes if node.kind == NodeKind.ATTRIBUTE and node.name == "Номенклатура")
resource = next(node for node in snapshot.nodes if node.kind == NodeKind.ATTRIBUTE and node.name == "Количество")
assert dimension.attributes["attribute_role"] == "DIMENSION"
assert resource.attributes["attribute_role"] == "RESOURCE"
assert any(
edge.kind == EdgeKind.HAS_ATTRIBUTE
and edge.source_lineage == register.lineage_id
and edge.target_lineage == dimension.lineage_id
for edge in snapshot.edges
)
assert any(
edge.kind == EdgeKind.HAS_ATTRIBUTE
and edge.source_lineage == register.lineage_id
and edge.target_lineage == resource.lineage_id
for edge in snapshot.edges
)
def test_index_project_links_role_rights_to_metadata_objects(tmp_path: Path):
xml = tmp_path / "roles.xml"
xml.write_text(
"""
""",
encoding="utf-8",
)
snapshot = index_project(tmp_path, project_id="role-rights")
role = next(node for node in snapshot.nodes if node.kind == NodeKind.ROLE)
document = next(node for node in snapshot.nodes if node.kind == NodeKind.DOCUMENT)
right = next(edge for edge in snapshot.edges if edge.kind == EdgeKind.GRANTS_ACCESS)
assert right.source_lineage == role.lineage_id
assert right.target_lineage == document.lineage_id
assert right.attributes["post"] == "true"
def test_index_project_links_child_element_command_action_and_role_right(tmp_path: Path):
xml = tmp_path / "metadata.xml"
xml.write_text(
"""
ЗаказПокупателяДокумент.ЗаказПокупателяМенеджер
""",
encoding="utf-8",
)
module = tmp_path / "form_module.bsl"
module.write_text("Процедура ПровестиКоманда()\nКонецПроцедуры\n", encoding="utf-8")
snapshot = index_project(tmp_path, project_id="child-element-metadata")
document = next(node for node in snapshot.nodes if node.kind == NodeKind.DOCUMENT)
role = next(node for node in snapshot.nodes if node.kind == NodeKind.ROLE)
command = next(node for node in snapshot.nodes if node.kind == NodeKind.COMMAND)
assert any(
edge.kind == EdgeKind.GRANTS_ACCESS
and edge.source_lineage == role.lineage_id
and edge.target_lineage == document.lineage_id
for edge in snapshot.edges
)
assert any(
edge.kind == EdgeKind.HANDLES
and edge.source_lineage == command.lineage_id
and edge.attributes["handler_name"] == "ПровестиКоманда"
for edge in snapshot.edges
)
def test_index_project_links_form_command_to_handler(tmp_path: Path):
xml = tmp_path / "form.xml"
xml.write_text(
"""
""",
encoding="utf-8",
)
module = tmp_path / "form_module.bsl"
module.write_text("Процедура ПровестиКоманда()\nКонецПроцедуры\n", encoding="utf-8")
snapshot = index_project(tmp_path, project_id="ui-handlers")
assert any(edge.kind == EdgeKind.HANDLES for edge in snapshot.edges)
def test_index_project_extracts_managed_form_items_without_layouts(tmp_path: Path):
xml = tmp_path / "form.xml"
xml.write_text(
"""
""",
encoding="utf-8",
)
snapshot = index_project(tmp_path, project_id="ui-form-items")
form = form_semantics(snapshot)[0]
assert [element.name for element in form.elements] == ["Основное", "Номер"]
assert all(element.kind == NodeKind.FORM_ELEMENT for element in form.elements)
assert form.elements[1].attributes["dataPath"] == "Объект.Номер"
assert not any(element.name == "ПечатнаяФорма" for element in form.elements)
def test_index_project_extracts_edt_form_items_from_form_file_path(tmp_path: Path):
form_dir = tmp_path / "src" / "Catalogs" / "ВидыЗаказовПокупателей" / "Forms" / "ФормаСписка"
form_dir.mkdir(parents=True)
(form_dir / "Form.form").write_text(
"""
СписокСписокНаименованиеСписок.Description
""",
encoding="utf-8",
)
snapshot = index_project(tmp_path, project_id="edt-form-items")
form = next(item for item in form_semantics(snapshot) if item.form.name == "ФормаСписка")
assert form.form.qualified_name == "Справочник.ВидыЗаказовПокупателей.ФормаСписка"
assert [element.name for element in form.elements] == ["Список", "Наименование"]
assert form.elements[0].attributes["control_kind"] == "Table"
assert form.elements[1].attributes["dataPath"] == "Список.Description"
def test_index_project_links_form_events_to_handlers(tmp_path: Path):
xml = tmp_path / "form.xml"
xml.write_text(
"""
""",
encoding="utf-8",
)
module = tmp_path / "form_module.bsl"
module.write_text(
"""
Процедура ПриСозданииНаСервере()
КонецПроцедуры
Процедура ПередЗаписью()
КонецПроцедуры
""",
encoding="utf-8",
)
snapshot = index_project(tmp_path, project_id="ui-form-events")
form = next(node for node in snapshot.nodes if node.kind == NodeKind.FORM)
handlers = {
edge.attributes["handler_name"]: edge
for edge in snapshot.edges
if edge.kind == EdgeKind.HANDLES and edge.source_lineage == form.lineage_id
}
assert set(handlers) == {"ПриСозданииНаСервере", "ПередЗаписью"}
assert {edge.attributes["link_type"] for edge in handlers.values()} == {"FORM_EVENT"}