skills/check-test-code-quality/rules/R014/SKILL.md
# R014: 测试HAP命名不规范 ## 规则信息 | 属性 | 值 | |------|-----| | 规则编号 | R014 | | 问题类型 | 测试HAP命名不规范 | | 严重级别 | Critical | | 规则复杂度 | simple | | 扫描范围 | BUILD.gn文件中的ohos_js_app_suite、ohos_js_app_static_suite、ohos_moduletest_suite模板 | | testcase字段 | `-`(BUILD.gn为非测试文件,无对应it()块) | ## 问题描述 测试HAP命名不符合规范要求。hap包命名采用大驼峰方式。 ## 命名规范 | 模板类型 | 检测目标 | 命名规范 | 正确示例 | |---------|---------|---------|---------| | `ohos_js_app_suite` | `hap_name` | 以`Acts`开头(A大写),以`Test`结尾(T大写) | `ActsAbilityTest` | | `ohos_js_app_static
npx skillsauth add openharmonyinsight/openharmony-skills skills/check-test-code-quality/rules/R014Install this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
| 属性 | 值 |
|------|-----|
| 规则编号 | R014 |
| 问题类型 | 测试HAP命名不规范 |
| 严重级别 | Critical |
| 规则复杂度 | simple |
| 扫描范围 | BUILD.gn文件中的ohos_js_app_suite、ohos_js_app_static_suite、ohos_moduletest_suite模板 |
| testcase字段 | -(BUILD.gn为非测试文件,无对应it()块) |
测试HAP命名不符合规范要求。hap包命名采用大驼峰方式。
| 模板类型 | 检测目标 | 命名规范 | 正确示例 |
|---------|---------|---------|---------|
| ohos_js_app_suite | hap_name | 以Acts开头(A大写),以Test结尾(T大写) | ActsAbilityTest |
| ohos_js_app_static_suite | hap_name | 以Acts开头(A大写),以StaticTest结尾(S、T大写) | ActsAbilityStaticTest |
| ohos_moduletest_suite | 模板名称XXXX | 以Acts开头(A大写),以Test结尾(T大写) | ActsModuleTest |
只修改hap_name,不修改target名称。 target名称与上层BUILD.gn中deps字段的引用保持一致,与hap_name无直接关系。
必须修改target名称。 ohos_moduletest_suite没有hap_name字段,target名称就是输出文件名。
名称中包含validator的不视为问题(如ActsValidatorTest是合法的)。
使用状态机方法解析BUILD.gn文件,识别三种模板类型并提取对应的检测目标。
import re
import os
TEMPLATE_TYPES = {
'ohos_js_app_suite': {
'pattern': re.compile(r'ohos_js_app_suite\s*\(\s*["\']([^"\']+)["\']'),
'check_field': 'hap_name',
'must_start': 'Acts',
'must_end': 'Test',
},
'ohos_js_app_static_suite': {
'pattern': re.compile(r'ohos_js_app_static_suite\s*\(\s*["\']([^"\']+)["\']'),
'check_field': 'hap_name',
'must_start': 'Acts',
'must_end': 'StaticTest',
},
'ohos_moduletest_suite': {
'pattern': re.compile(r'ohos_moduletest_suite\s*\(\s*["\']([^"\']+)["\']'),
'check_field': 'target_name',
'must_start': 'Acts',
'must_end': 'Test',
},
}
HAP_NAME_PATTERN = re.compile(r'hap_name\s*=\s*["\']([^"\']+)["\']')
对BUILD.gn文件进行逐行扫描,使用状态机跟踪当前所在的模板块。
def parse_build_gn_templates(content):
templates = []
lines = content.split('\n')
state = 'IDLE'
current_template = None
brace_depth = 0
template_start_line = 0
for line_num, line in enumerate(lines, 1):
stripped = line.strip()
if state == 'IDLE':
for tname, tinfo in TEMPLATE_TYPES.items():
match = tinfo['pattern'].search(line)
if match:
target_name = match.group(1)
current_template = {
'type': tname,
'target_name': target_name,
'target_line': line_num,
'hap_name': None,
'hap_name_line': 0,
}
state = 'IN_TEMPLATE'
template_start_line = line_num
brace_depth = line.count('{') - line.count('}')
break
elif state == 'IN_TEMPLATE':
brace_depth += line.count('{') - line.count('}')
hap_match = HAP_NAME_PATTERN.search(line)
if hap_match:
current_template['hap_name'] = hap_match.group(1)
current_template['hap_name_line'] = line_num
if brace_depth <= 0:
templates.append(current_template)
current_template = None
state = 'IDLE'
return templates
def validate_naming(template):
tname = template['type']
tinfo = TEMPLATE_TYPES[tname]
if tinfo['check_field'] == 'hap_name':
name = template['hap_name']
report_line = template['hap_name_line']
else:
name = template['target_name']
report_line = template['target_line']
if not name:
return None
if 'validator' in name.lower():
return None
must_start = tinfo['must_start']
must_end = tinfo['must_end']
starts_ok = name.startswith(must_start)
ends_ok = name.endswith(must_end)
if starts_ok and ends_ok:
return None
errors = []
if not starts_ok:
errors.append(f'不以"{must_start}"开头')
if not ends_ok:
errors.append(f'不以"{must_end}"结尾')
return {
'name': name,
'line': report_line,
'errors': errors,
'template_type': tname,
'check_field': tinfo['check_field'],
}
def generate_fix_suggestion(template, validation):
name = validation['name']
tname = validation['template_type']
check_field = validation['check_field']
tinfo = TEMPLATE_TYPES[tname]
errors = validation['errors']
must_start = tinfo['must_start']
must_end = tinfo['must_end']
fixed_name = name
if not fixed_name.startswith(must_start):
fixed_name = must_start + fixed_name[0].upper() + fixed_name[1:]
if not fixed_name.endswith(must_end):
fixed_name = fixed_name + 'Adapt001' + must_end
if check_field == 'hap_name':
target_info = f"target名称 \"{template['target_name']}\" 保持不变,只修改hap_name"
else:
target_info = f"target名称 \"{template['target_name']}\" 需要修改为 \"{fixed_name}\""
return (
f"{check_field} \"{name}\" 不符合规范:{', '.join(errors)}。"
f"修复: {check_field}改为 \"{fixed_name}\"。{target_info}。"
)
def scan_r014(scan_root, base_dir):
issues = []
for dirpath, dirnames, filenames in os.walk(scan_root):
if 'BUILD.gn' not in filenames:
continue
build_gn_path = os.path.join(dirpath, 'BUILD.gn')
with open(build_gn_path, 'r', encoding='utf-8') as f:
content = f.read()
templates = parse_build_gn_templates(content)
for template in templates:
validation = validate_naming(template)
if validation is None:
continue
rel_path = os.path.relpath(build_gn_path, base_dir)
suggestion = generate_fix_suggestion(template, validation)
if validation['check_field'] == 'hap_name':
snippet = f'hap_name = "{validation["name"]}"'
else:
snippet = f'{template["type"]}("{validation["name"]}")'
issues.append({
'rule': 'R014',
'type': '测试HAP命名不规范',
'severity': 'Critical',
'file': rel_path,
'line': validation['line'],
'testcase': '-',
'snippet': snippet,
'suggestion': suggestion,
})
return issues
ohos_js_app_suite("mytest") { # target名称,保持不变
testonly = true
part_name = "ace_engine"
subsystem_name = "arkui"
hap_name = "actsability" # ✗ 错误:不以Acts开头,不以Test结尾
}
ohos_js_app_static_suite("statictest") { # target名称,保持不变
testonly = true
part_name = "ace_engine"
subsystem_name = "arkui"
hap_name = "ActsTestSuite" # ✗ 错误:不以StaticTest结尾
}
# ohos_moduletest_suite没有hap_name字段,target名称就是输出文件名
ohos_moduletest_suite("mymoduletest") { # ✗ 错误:不以Acts开头,不以Test结尾
testonly = true
part_name = "ace_engine"
subsystem_name = "arkui"
}
ohos_js_app_suite("test2") {
hap_name = "actsTest" # ✗ 错误:A应该大写
}
ohos_js_app_static_suite("test3") {
hap_name = "Actsstatictest" # ✗ 错误:S、T应该大写
}
# target名称与hap_name可以不同,修复时只修改hap_name
ohos_js_app_suite("mytest") { # target名称,保持不变
testonly = true
part_name = "ace_engine"
subsystem_name = "arkui"
hap_name = "ActsAbilityAdapt001Test" # ✓ 正确:以Acts开头,以Test结尾
}
ohos_js_app_static_suite("statictest") { # target名称,保持不变
testonly = true
part_name = "ace_engine"
subsystem_name = "arkui"
hap_name = "ActsAbilityAdapt001StaticTest" # ✓ 正确:以Acts开头,以StaticTest结尾
}
# ohos_moduletest_suite没有hap_name字段,target名称需要符合规范
ohos_moduletest_suite("ActsMyModuleAdapt001Test") { # ✓ 正确
testonly = true
part_name = "ace_engine"
subsystem_name = "arkui"
}
ohos_js_app_suite("valtest") {
hap_name = "ActsValidatorTest" # ✓ 不是问题:包含validator
}
修复前:
# BUILD.gn
ohos_js_app_suite("mytest") { # target名称,保持不变
testonly = true
part_name = "ace_engine"
subsystem_name = "arkui"
hap_name = "actsability" # ✗ 不符合规范
}
# Test.json
{
"test-file-name": ["actsability.hap"]
}
修复后:
# BUILD.gn
ohos_js_app_suite("mytest") { # target名称,保持不变
testonly = true
part_name = "ace_engine"
subsystem_name = "arkui"
hap_name = "ActsAbilityAdapt001Test" # ✓ 只修改hap_name
}
# Test.json
{
"test-file-name": ["ActsAbilityAdapt001Test.hap"]
}
修复前:
# BUILD.gn
ohos_moduletest_suite("mymoduletest") { # ✗ 不符合规范
testonly = true
part_name = "ace_engine"
subsystem_name = "arkui"
}
# Test.json
{
"kits": [{
"push": ["mymoduletest->/data/local/tmp/mymoduletest"]
}],
"driver": {
"module-name": "mymoduletest"
}
}
修复后:
# BUILD.gn
ohos_moduletest_suite("ActsMyModuleAdapt001Test") { # ✓ 修改target名称
testonly = true
part_name = "ace_engine"
subsystem_name = "arkui"
}
# Test.json
{
"kits": [{
"push": ["ActsMyModuleAdapt001Test->/data/local/tmp/ActsMyModuleAdapt001Test"]
}],
"driver": {
"module-name": "ActsMyModuleAdapt001Test"
}
}
test-file-name、push路径、module-name等)validator的hap名称不视为问题每条issue的字段:
| 字段 | 值 |
|------|-----|
| rule | R014 |
| type | 测试HAP命名不规范 |
| severity | Critical |
| file | 相对路径(如xxx/BUILD.gn) |
| line | hap_name或target名称所在行号 |
| testcase | - |
| snippet | hap_name = "xxx" 或 ohos_moduletest_suite("xxx") |
| suggestion | hap_name "xxx" 不符合规范:不以"Acts"开头, 不以"Test"结尾。修复: hap_name改为 "ActsXxxAdapt001Test"。target名称 "yyy" 保持不变,只修改hap_name。 |
ohos_js_app_suite("test1") { # target名称,保持不变
testonly = true
part_name = "ace_engine"
subsystem_name = "arkui"
hap_name = "MyTest" # ✗ 错误:不以Acts开头
}
ohos_js_app_suite模板 - 正确格式:
ActsAbilityTest - 以Acts开头,Test结尾ActsWindowManagerTest - 以Acts开头,Test结尾ohos_js_app_static_suite模板 - 正确格式:
ActsAbilityStaticTest - 以Acts开头,StaticTest结尾ActsNotificationThirdPartyWatchPermissionStaticTest - 以Acts开头,StaticTest结尾ohos_moduletest_suite模板 - 正确格式:
ActsModuleTest - 以Acts开头,Test结尾ActsAbilityTest - 以Acts开头,Test结尾错误格式:
actsStartSelfUIAbilityStaticTest - 首字母小写(错误)ActsAbility - 缺少Test/StaticTest结尾(错误)AbilityTest - 缺少Acts开头(错误)ActsStatictest - T未大写(错误)development
Run local code quality checks covering a subset of OpenHarmony gate CI (copyright, CodeArts C/C++) plus additional local checks (pylint/flake8, shellcheck/bashate, gn format). Use before committing to reduce gate failures. Triggers on: /oh-precommit-codecheck, "门禁检查", "门禁预检", "检查代码", "run codecheck", "check code quality", "lint my code", "代码检查", or after completing code implementation. WHEN to use: before git commit, before creating PR, after modifying C/C++/Python/Shell/GN files, when gate CI fails with codecheck defects, or when you want to preview what gate will flag.
development
OpenHarmony PR full lifecycle workflow. Five modes: - Commit: standardized commit with DCO sign-off and Issue linking - Create PR: commit + push to fork + create Issue + create PR on upstream - Fix Codecheck: fetch gate CI codecheck defects from a PR and auto-fix them - Review PR: fetch a PR's changes to local for code review - Fix Review: fetch unresolved review comments from a PR and auto-fix them Triggers on: /oh-pr-workflow, "提交代码", "创建PR", "提个PR", "commit", "修复告警", "修复门禁", "修复codecheck", "fix codecheck", "review pr", "review这个pr", "看下这个pr", "检视pr", "修复review", "修复检视意见", "fix review", or a GitCode PR URL with fix/review intent.
testing
分析 HM Desktop PRD 文档,提取需求信息、验证完整性、检查章节顺序(需求来源→需求背景→需求价值分析→竞品分析→需求描述)、检查 KEP 定义、检测需求冲突并生成结构化分析报告。适用于用户请求:(1) 分析或审查 PRD 文档, (2) 从需求中提取 KEP 列表, (3) 检查 PRD 完整性或一致性, (4) 将需求映射到模块架构, (5) 验证 PRD 格式合规性, (6) 验证竞品分析章节完整性。关键词:PRD分析, requirement extraction, KEP验证, completeness check, chapter order validation, 竞品分析检查, analyze PRD, 需求提取, 完整性检查, 章节顺序验证
development
基于 PRD 文档自动生成鸿蒙系统设计文档,包括架构设计文档和功能设计文档。生成前会分析 OpenHarmony 存量代码结构,确保与现有架构兼容。架构设计文档第2章必须为竞品方案分析,位于需求背景之后。适用于用户请求:(1) 生成架构设计文档, (2) 生成功能设计文档, (3) 从 PRD 生成设计文档, (4) 创建系统架构设计, (5) 编写功能规格说明, (6) 分析 OH 代码结构。关键词:architecture design, functional design, design doc, 竞品方案分析, OpenHarmony code analysis, 架构设计, 功能设计, 设计文档生成, OH代码分析, analyze codebase, competitor analysis