feat: bgRFC/FM 支撑能力 + ADT 后缀剥离与 CLAS 激活修复(B1 配套)
新增能力: - remote-enable 子命令:设置函数模块处理类型为远程启用(bgRFC/RFC 执行体必需)。 实现要点均按实机验证:PUT fmodule:processingType="rfc"(枚举值仅小写 rfc 有效, remoteEnabled/remote/RFC 等均 400);lockHandle 走 query 参数(放 header 报 ParameterNotFound);PUT 后 GET 复核回显;DDIC 结构参数才可远程启用(类本地类型 报"针对 RFC 不允许使用类或接口的类型")。 - create --type functiongroup 透传 --package / --corr_nr(此前 package 被静默写成 $TMP, 导致函数组无法归目标包)。 修复: - activate 请求体补重复引用:ADT CLAS 激活端点对 objectReferences 只有 1 个引用时 返回 HTTP 200 + 空 body 且不执行激活;引用数 ≥2 才真正激活(同对象重复亦可)。 - scanner 剥离 ADT 文件后缀(xxx.clas.abap 解析错误)。 守卫测试: - tests/unit/test_bgrfc_support.py(17 例):函数组 package 透传、processingType 助手、 remote-enable 命令(含 lockHandle 走 query/小写 rfc/错误透传/复核失配判失败)、 函数 URI 组装不得用组名冒充模块名。 - test_activate.py 增加激活请求体引用数守卫;test_repo_guards.py 增加后缀剥离守卫。 测试:tests/unit 676 + tests/test_sapcli.py 69 = 745 全绿 (PYTHONPATH=assets python -m unittest discover -s tests/unit -t tests)
This commit is contained in:
@@ -442,6 +442,55 @@ class TestScanProject(unittest.TestCase):
|
||||
self.assertEqual(file_map["ZGROUP/ZFUNC1"], "functions/zgroup/zfunc1.abap")
|
||||
self.assertEqual(file_map["ZDOM_TEST"], "domains/zdom_test.abap")
|
||||
|
||||
def _make_adt_project(self, tmp: str) -> None:
|
||||
"""创建 ADT/abapGit 风格项目(`<name>.<suffix>.abap`,项目仓命名规范形态)。"""
|
||||
os.makedirs(os.path.join(tmp, "src", "ZINT.package", "class"))
|
||||
cls_dir = os.path.join(tmp, "src", "ZINT.package", "class")
|
||||
# ADT 式:zcl_demo.clas.abap
|
||||
with open(os.path.join(cls_dir, "zcl_demo.clas.abap"), "w") as f:
|
||||
f.write("CLASS zcl_demo DEFINITION.\n")
|
||||
# 无后缀式(历史写法,仍须兼容):zcl_plain.abap
|
||||
with open(os.path.join(cls_dir, "zcl_plain.abap"), "w") as f:
|
||||
f.write("CLASS zcl_plain DEFINITION.\n")
|
||||
# 后缀与目录类型不匹配:不得被剥(否则对象名会被错改)
|
||||
with open(os.path.join(cls_dir, "zcl_weird.prog.abap"), "w") as f:
|
||||
f.write("CLASS zcl_weird DEFINITION.\n")
|
||||
|
||||
def test_scan_adt_style_filenames(self):
|
||||
"""ADT 风格 `<name>.clas.abap` 必须解析为对象名 ZCL_DEMO(不带 .CLAS)。"""
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
self._make_adt_project(tmp)
|
||||
results = scan_project(tmp)
|
||||
names = {r.name for r in results}
|
||||
|
||||
self.assertIn("ZCL_DEMO", names)
|
||||
self.assertNotIn("ZCL_DEMO.CLAS", names)
|
||||
# 无后缀式兼容
|
||||
self.assertIn("ZCL_PLAIN", names)
|
||||
# 目录类型不匹配的后缀不剥
|
||||
self.assertIn("ZCL_WEIRD.PROG", names)
|
||||
|
||||
def test_scan_adt_style_file_paths(self):
|
||||
"""ADT 风格项目下 file 字段仍为仓内相对路径。"""
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
self._make_adt_project(tmp)
|
||||
file_map = {r.name: r.file for r in scan_project(tmp)}
|
||||
self.assertEqual(
|
||||
file_map["ZCL_DEMO"],
|
||||
"src/ZINT.package/class/zcl_demo.clas.abap",
|
||||
)
|
||||
|
||||
def test_strip_adt_suffix_unit(self):
|
||||
"""后缀剥离函数单测:只剥匹配目录类型的那一个后缀。"""
|
||||
from sapcli.scanner import _strip_adt_suffix
|
||||
self.assertEqual(_strip_adt_suffix("zcl_demo.clas", "class"), "zcl_demo")
|
||||
self.assertEqual(_strip_adt_suffix("zcl_demo", "class"), "zcl_demo")
|
||||
self.assertEqual(_strip_adt_suffix("zcl_demo.prog", "class"), "zcl_demo.prog")
|
||||
self.assertEqual(_strip_adt_suffix("zrpt1.prog", "report"), "zrpt1")
|
||||
self.assertEqual(_strip_adt_suffix("zdom.doma", "domain"), "zdom")
|
||||
# 后缀即全部文件名时不得剥成空串
|
||||
self.assertEqual(_strip_adt_suffix("clas", "class"), "clas")
|
||||
|
||||
def test_scan_empty_directory(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
results = scan_project(tmp)
|
||||
|
||||
Reference in New Issue
Block a user