R022: errcode值(.code)值断言使用"==="非"=="
SkillDev toolsA skill for dev tools by openharmonyinsight.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the R022: errcode值(.code)值断言使用"==="非"==" skill
What this skill tells your AI
The instructions your AI receives, as published by openharmonyinsight/openharmony-skills in skills/check-test-code-quality/rules/R022/SKILL.md and read by ahel’s review.
规则信息
| 属性 | 值 |
|---|---|
| 规则编号 | R022 |
| 问题类型 | errcode值断言使用==而非=== |
| 严重级别 | Critical |
| 规则复杂度 | simple |
| 扫描范围 | 所有源代码文件(.ets, .ts, .js) |
| testcase字段 | 需解析it()块范围 |
问题描述
测试用例中对.code(errcode)进行值断言时,必须使用严格相等运算符===,不允许使用宽松相等运算符==。
修复建议
将==替换为===。例如:expect(err.code == 401) 改为 expect(err.code === 401)。
修复建议格式
路径: {文件路径}, 行号: {行号}, 问题描述: errcode值断言使用了宽松相等运算符'==',应使用严格相等运算符'==='。
扫描逻辑
Step 1: 收集源代码文件
def get_all_source_files(directory):
source_extensions = ('.ets', '.ts', '.js')
result = []
for root, dirs, files in os.walk(directory):
for fn in files:
if fn.endswith(source_extensions):
result.append(os.path.join(root, fn))
return result
Step 2: 提取it()块范围
使用状态机解析,追踪字符串字面量内的大括号(含反引号追踪),提取每个it()块的行号范围。用于将问题行号关联到所属testcase。
def extract_it_blocks(content):
blocks = []
it_pattern = re.compile(r'\bit\s*\(\s*(["\'])(.+?)\1\s*,', re.MULTILINE)
for match in it_pattern.finditer(content):
start_line = content[:match.start()].count('\n') + 1
name = match.group(2)
brace_start = content.index('{', match.end())
open_count, close_count = 0, 0
i = brace_start
in_single = in_double = in_backtick = False
while i < len(content):
c = content[i]
if c == '\\' and (in_single or in_double or in_backtick):
i += 2; continue
if c == '`' and not in_single and not in_double:
in_backtick = not in_backtick
elif c == "'" and not in_double and not in_backtick:
in_single = not in_single
elif c == '"' and not in_single and not in_backtick:
in_double = not in_double
elif not in_single and not in_double and not in_backtick:
if c == '{': open_count += 1
elif c == '}':
close_count += 1
if open_count == close_count:
end_line = content[:i].count('\n') + 1
blocks.append({'name': name, 'start': start_line, 'end': end_line})
break
i += 1
return blocks
Step 3: 检测.code ==模式
在源代码文件中,查找.code后跟==(非===)的模式。
import re
CODE_EQ_PATTERN = re.compile(r'\.code\s*==(?!=)')
def scan_r022(file_path, base_dir):
issues = []
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
lines = content.split('\n')
it_blocks = extract_it_blocks(content)
for line_idx, line in enumerate(lines):
if not CODE_EQ_PATTERN.search(line):
continue
# 跳过注释行
stripped = line.strip()
if stripped.startswith('//'):
continue
code_part = stripped
if '//' in stripped:
code_part = stripped[:stripped.index('//')].strip()
if not CODE_EQ_PATTERN.search(code_part):
continue
line_num = line_idx + 1
testcase = '-'
for block in it_blocks:
if block['start'] <= line_num <= block['end']:
testcase = block['name']
break
rel_path = os.path.relpath(file_path, base_dir)
issues.append({
'rule': 'R022',
'type': 'errcode值断言使用==而非===',
'severity': 'Critical',
'file': rel_path,
'line': line_num,
'testcase': testcase,
'snippet': stripped.strip(),
'suggestion': (
f"路径: {rel_path}, 行号: {line_num}, "
f"问题描述: errcode值断言使用了宽松相等运算符'==',应使用严格相等运算符'==='。"
),
})
return issues
错误示例
expect(err.code == 0).assertTrue(); // ✗ 错误:使用 ==
expect(err.code == 29360216).assertTrue(); // ✗ 错误:使用 ==
expect((error as BusinessError)?.code == 401).assertTrue(); // ✗ 错误:使用 ==
if (e.code == 801) { // ✗ 错误:使用 ==
正确示例
expect(err.code === 0).assertTrue(); // ✓ 正确:使用 ===
expect(err.code === 29360216).assertTrue(); // ✓ 正确:使用 ===
expect((error as BusinessError)?.code === 401).assertTrue(); // ✓ 正确:使用 ===
if (e.code === 801) { // ✓ 正确:使用 ===
陷阱与注意事项
陷阱1: 必须区分==和===
正则\.code\s*==(?!=)使用负向前瞻(?!=)确保只匹配==而非===。
\.code == 401→ 匹配(问题)\.code === 401→ 不匹配(合规)
陷阱2: 跳过注释行
// 注释中的 .code == 不应被检测。需要先去除注释部分再进行匹配。
// expect(err.code == 401).assertTrue(); // ← 被注释掉,不检查
陷阱3: 多个.code ==在同一行
一行代码中可能包含多个.code ==(如||组合断言),每个都应报告:
expect((err.code == 13900012 || err.code == 13900006)).assertTrue();
// ↑ 两个.code ==都应报告
陷阱4: 非断言场景中的.code ==
.code ==不仅出现在expect()断言中,也可能出现在if条件判断等场景中。R022对所有.code ==统一报告,不区分是否在断言内。因为无论是断言还是条件判断,对errcode都应使用===严格比较。
输出格式
每条issue的字段:
| 字段 | 值 |
|---|---|
| rule | R022 |
| type | errcode值断言使用==而非=== |
| severity | Critical |
| file | 相对路径 |
| line | .code ==所在行号 |
| testcase | 所属it()块名称或- |
| snippet | 当前行内容 |
| suggestion | 路径: {文件路径}, 行号: {行号}, 问题描述: errcode值断言使用了宽松相等运算符'==',应使用严格相等运算符'==='。 |
排除规则
//注释行中的.code ==不检查.code ===(严格相等)不报告
技术规范
检测范围补充说明
检查:
- 源代码文件(
.ets,.ts,.js)中所有.code ==(非.code ===) - 包括
expect()断言、if条件判断等所有场景
不检查:
- 注释中的
.code == .code ===(已使用严格相等)
实际案例
全仓扫描结果(预估):
- 问题数: ~8800+ 行包含 .code ==(非===)
- 涉及子系统: 全部子系统
- 典型场景:
- expect(err.code == 0).assertTrue();
- expect((error as BusinessError)?.code == 401).assertTrue();
- if (e.code == 801) { ... }
- expect((err.code == 13900012 || err.code == 13900006)).assertTrue();
与R002的关系
- R002: 检查errcode断言中错误码是否为number类型(
"401"string vs401number) - R022: 检查errcode断言中是否使用严格相等
===(==vs===) - 两个规则互补,可同时触发:
expect(err.code == "401")会同时触发R002和R022
Signals
- GitHub stars
- 34
- Forks
- 7
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
r022- Source
- github.com/openharmonyinsight/openharmony-skills