Initial SQL-only 1C adapter baseline
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT))
|
||||
sys.path.insert(0, str(ROOT / "plugins" / "1c"))
|
||||
sys.path.insert(0, str(ROOT / "plugins" / "1c" / "connector"))
|
||||
|
||||
import adapter_1c_server as adapter_server # noqa: E402
|
||||
|
||||
|
||||
def require(condition: bool, message: str, failures: list[str]) -> None:
|
||||
if not condition:
|
||||
failures.append(message)
|
||||
|
||||
|
||||
def patch_adapter_for_symbol_checks() -> None:
|
||||
def fake_definition_find(payload: dict[str, Any]) -> dict[str, Any]:
|
||||
query = str(payload.get("query") or "")
|
||||
if query == "Артикул":
|
||||
return {
|
||||
"schema": "onec_definition_find.v1",
|
||||
"status": "ok",
|
||||
"matches": [
|
||||
{
|
||||
"canonical_path": "Справочник.Номенклатура.Артикул",
|
||||
"kind": "Catalog",
|
||||
"name": "Номенклатура",
|
||||
}
|
||||
],
|
||||
}
|
||||
if query == "Номенклатура":
|
||||
return {
|
||||
"schema": "onec_definition_find.v1",
|
||||
"status": "ok",
|
||||
"matches": [
|
||||
{
|
||||
"canonical_path": "Справочник.Номенклатура",
|
||||
"kind": "Catalog",
|
||||
"name": "Номенклатура",
|
||||
}
|
||||
],
|
||||
}
|
||||
return {"schema": "onec_definition_find.v1", "status": "ok", "matches": []}
|
||||
|
||||
def fake_read_module(payload: dict[str, Any]) -> dict[str, Any]:
|
||||
return {
|
||||
"schema": "onec_module_read.v1",
|
||||
"status": "ok",
|
||||
"text": "Процедура ПередЗаписью(Отказ) Экспорт\n Отказ = Истина;\nКонецПроцедуры",
|
||||
"owner": {"kind": "Catalog", "name": "Номенклатура"},
|
||||
"module": {"name": "Модуль объекта"},
|
||||
}
|
||||
|
||||
def fake_attributes(payload: dict[str, Any]) -> dict[str, Any]:
|
||||
return {"schema": "onec_metadata_object_attributes.v1", "status": "ok", "attributes": []}
|
||||
|
||||
adapter_server.metadata_definition_find = fake_definition_find
|
||||
adapter_server.read_module = fake_read_module
|
||||
adapter_server.metadata_object_attributes = fake_attributes
|
||||
|
||||
|
||||
def check_full_path(failures: list[str]) -> None:
|
||||
result = adapter_server.call_method(
|
||||
"code.symbol.resolve",
|
||||
{
|
||||
"base_id": "upo_test",
|
||||
"expression": "Справочник.Номенклатура.Артикул",
|
||||
"module_ref": "ConfigSave:file:0",
|
||||
},
|
||||
)
|
||||
require(result.get("schema") == "onec_bsl_symbol_resolution.v1", "full path must return BSL symbol schema", failures)
|
||||
require(result.get("status") == "resolved", "full path must resolve", failures)
|
||||
require(result.get("resolution_kind") == "metadata_path", "full path must be classified as metadata_path", failures)
|
||||
require(result.get("canonical_path") == "Справочник.Номенклатура.Артикул", "full path must expose canonical_path publicly", failures)
|
||||
require(result.get("safe_as_metadata_path") is True, "full path must expose safe_as_metadata_path=true", failures)
|
||||
|
||||
|
||||
def check_parameter(failures: list[str]) -> None:
|
||||
result = adapter_server.call_method(
|
||||
"code.symbol.resolve",
|
||||
{
|
||||
"base_id": "upo_test",
|
||||
"expression": "Отказ.Код",
|
||||
"routine_name": "ПередЗаписью",
|
||||
"module_ref": "ConfigSave:file:0",
|
||||
},
|
||||
)
|
||||
require(result.get("status") == "resolved", "routine parameter must resolve", failures)
|
||||
require(result.get("resolution_kind") == "parameter", "routine parameter must not be metadata", failures)
|
||||
require(result.get("context_path") == "Отказ.Код", "routine parameter must expose context_path publicly", failures)
|
||||
require(result.get("safe_as_metadata_path") is False, "routine parameter must expose safe_as_metadata_path=false", failures)
|
||||
|
||||
|
||||
def check_short_name(failures: list[str]) -> None:
|
||||
result = adapter_server.call_method(
|
||||
"code.symbol.resolve",
|
||||
{
|
||||
"base_id": "upo_test",
|
||||
"expression": "Номенклатура.ЕдИзмерение.Код",
|
||||
"routine_name": "ПередЗаписью",
|
||||
"module_ref": "ConfigSave:file:0",
|
||||
},
|
||||
)
|
||||
candidates = result.get("candidates") if isinstance(result.get("candidates"), list) else []
|
||||
require(result.get("status") == "unresolved", "short object name must stay unresolved", failures)
|
||||
require(result.get("safe_as_metadata_path") is False, "short object name must expose safe_as_metadata_path=false", failures)
|
||||
require(bool(candidates), "short object name must return ambiguity candidates", failures)
|
||||
if candidates:
|
||||
require(candidates[0].get("canonical_path") == "Справочник.Номенклатура", "candidate canonical_path must stay public", failures)
|
||||
require(candidates[0].get("reason") == "short_object_name_requires_kind", "candidate must explain short name risk", failures)
|
||||
|
||||
|
||||
def run_checks() -> dict[str, Any]:
|
||||
patch_adapter_for_symbol_checks()
|
||||
failures: list[str] = []
|
||||
check_full_path(failures)
|
||||
check_parameter(failures)
|
||||
check_short_name(failures)
|
||||
return {
|
||||
"schema": "onec_code_symbol_contract_check.v1",
|
||||
"status": "ok" if not failures else "failed",
|
||||
"failures": failures,
|
||||
"checks": {
|
||||
"full_path_metadata": "full path must resolve as metadata_path",
|
||||
"parameter_not_metadata": "routine parameter must not be metadata",
|
||||
"short_name_unsafe": "short object name must remain unsafe",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Check adapter-level code.symbol.resolve contract invariants.")
|
||||
parser.add_argument("--print", action="store_true")
|
||||
args = parser.parse_args()
|
||||
report = run_checks()
|
||||
if args.print or report["status"] != "ok":
|
||||
print(json.dumps(report, ensure_ascii=False, indent=2))
|
||||
else:
|
||||
print("1C code symbol contract status: ok")
|
||||
return 0 if report["status"] == "ok" else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user