R022: errcode值(.code)值断言使用"==="非"=="

SkillDev tools

A skill for dev tools by openharmonyinsight.

Available today. Use it from your connected AI after setup.

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的字段:

字段
ruleR022
typeerrcode值断言使用==而非===
severityCritical
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 vs 401 number)
  • 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