Hamcrest

发布人:仓颉技术交流平台官方
分类:工具库 / 通用工具

该仓库是 OpenHarmony 生态中的一个 Hamcrest 风格匹配器库,主要用于在测试或逻辑判断中提供灵活、可组合的条件匹配功能。它支持字符串、数值、数组、对象等多种类型的断言匹配(如包含、相等、为空、正则匹配等),适用于 OpenHarmony 应用开发中的单元测试和验证场景,基于 TypeScript/ArkTS 编写

等待接取
21

悬赏内容

招募内容

项目背景与战略目标

Hamcrest 是全球公认的测试断言标准,其“可组合匹配器(Composable Matchers)”理念极大地提升了单元测试的可读性与维护性。然而,OpenHarmony 生态中现有的 Hamcrest 实现基于 TypeScript/ArkTS,存在以下后端场景下的局限性:

  1. 类型安全缺失:动态类型系统导致匹配器在编译期无法校验类型兼容性,常出现“运行时才报错”的低级错误,且缺乏智能提示。

  2. 性能开销:JS 引擎的动态分发与对象创建开销较大,在大规模数据验证或高频断言场景下(如 fuzzing 测试),会显著拖慢测试执行速度。

  3. 组合能力受限:缺乏强大的泛型与高阶函数支持,自定义复杂匹配器(如嵌套对象结构验证)时代码冗长且易错。

  4. 内存管理:频繁创建临时匹配器对象可能增加 GC 压力,影响长运行测试任务的稳定性。

本项目旨在利用 仓颉编程语言(Cangjie Language)1.0.0+ 重构 Hamcrest,打造一款编译期类型安全、零运行时开销、高度可组合的通用匹配器库。它将包含:

  • 强类型泛型系统:利用仓颉泛型约束,确保 Matcher<T> 只能接受类型 T 的数据,编译期拦截类型不匹配错误。

  • 零开销抽象:利用内联函数(Inline Functions)与值类型优化,消除虚函数调用与临时对象分配,提升断言执行速度 5-10 倍。

  • 代数数据类型组合:利用 enum 和模式匹配构建复杂的逻辑组合(And/Or/Not),代码简洁且逻辑严密。

  • 原生错误报告:生成结构化的差异报告(Diff),精准定位失败原因,无缝集成仓颉测试框架。

这将为企业提供一个工业级、高可靠的测试基础设施,不仅适用于单元测试,还可广泛应用于运行时的数据校验、规则引擎条件判断等后端核心场景。

核心功能需求与技术规格

2.1 功能模块分解

模块类别

核心职责

关键技术要求 (仓颉特性)

验收依据

核心匹配接口

定义 Matcher<T> 泛型接口 (matches, describe)

利用 泛型约束 确保类型安全;接口默认方法提供便捷实现

编译期类型检查通过率 100%,无强制类型转换

基础匹配器库

相等、为空、实例类型、数值范围、字符串包含/正则

使用 内联函数 优化常用匹配器;正则表达式预编译缓存

基础断言执行耗时 < 100ns,内存分配为零

组合逻辑引擎

And, Or, Not, AnyOf, AllOf 逻辑组合

利用 代数数据类型 表达组合树;短路求值优化性能

复杂组合逻辑执行效率优于 JS 实现 5 倍以上

集合与映射匹配

数组/列表包含、顺序无关匹配、Map 键值对验证

泛型集合处理;高效迭代器模式;自定义元素匹配器传递

万级元素集合验证耗时 < 10ms,内存平稳

对象属性匹配

基于反射或宏的对象字段提取与验证

利用 宏系统 生成字段访问代码;避免运行时反射开销

支持嵌套对象路径验证,编译期检查字段存在性

差异报告生成

生成人类可读的错误描述与 Diff 对比

结构化错误信息构建;敏感数据脱敏处理

错误信息清晰准确,包含期望值与实际值对比

2.2 非功能性需求规范

  • 性能指标:单次断言平均耗时 < 200ns;大规模集合(10k 元素)验证吞吐量 > 1M ops/s;内存占用比 TS 版降低 80%。

  • 安全要求:杜绝正则表达式 ReDoS 攻击风险;错误信息中自动脱敏敏感字段;无运行时代码执行风险。

  • 可靠性:匹配逻辑确定性执行,无侧副作用;异常输入(如 null)有明确的布尔返回或错误提示。

  • 可维护性:API 设计符合仓颉惯用风格,支持链式调用,文档覆盖率 100%。

2.3 核心接口设计示例 (伪代码)

// 1. 核心匹配器接口 (泛型)
interface Matcher<T> {
    func matches(item: T): Bool
    func describeMismatch(item: T, description: Description): Unit
    func toDescription(): String
}

// 2. 描述器 (用于生成错误信息)
class Description {
    private var text: StringBuilder
    
    func appendText(text: String): Description {
        this.text.append(text)
        return this
    }
    
    func appendValue(value: Any): Description {
        this.text.append(ValueFormatter.format(value))
        return this
    }
    
    func toString(): String {
        return this.text.toString()
    }
}

// 3. 基础匹配器实现示例 (相等)
class IsEqual<T>: Matcher<T> {
    private var expected: T
    
    init(expected: T) {
        self.expected = expected
    }
    
    func matches(item: T): Bool {
        return item == this.expected // 利用仓颉 Equatable 协议
    }
    
    func describeMismatch(item: T, description: Description): Unit {
        description.appendText("was ").appendValue(item)
    }
    
    static func equalTo<T>(value: T): Matcher<T> {
        return IsEqual(value)
    }
}

// 4. 组合匹配器 (And)
class AllOf<T>: Matcher<T> {
    private var matchers: List<Matcher<T>>
    
    init(matchers: List<Matcher<T>>) {
        self.matchers = matchers
    }
    
    func matches(item: T): Bool {
        // 短路求值
        for m in this.matchers {
            if (!m.matches(item)) {
                return false
            }
        }
        return true
    }
    
    func describeMismatch(item: T, description: Description): Unit {
        description.appendText("all of ")
        for i in 0..<this.matchers.size() {
            if (!this.matchers[i].matches(item)) {
                this.matchers[i].describeMismatch(item, description)
                break
            }
        }
    }
    
    static func allOf<T>(matchers: List<Matcher<T>>): Matcher<T> {
        return AllOf(matchers)
    }
}

// 5. 集合匹配器 (包含元素)
class ContainsElement<T>: Matcher<List<T>> {
    private var matcher: Matcher<T>
    
    init(matcher: Matcher<T>) {
        self.matcher = matcher
    }
    
    func matches(item: List<T>): Bool {
        for elem in item {
            if (this.matcher.matches(elem)) {
                return true
            }
        }
        return false
    }
    
    func describeMismatch(item: List<T>, description: Description): Unit {
        description.appendText("did not contain an item matching ").appendText(this.matcher.toDescription())
    }
    
    static func hasItem<T>(matcher: Matcher<T>): Matcher<List<T>> {
        return ContainsElement(matcher)
    }
}

// 6. 业务场景示例:用户订单测试
struct Order {
    let id: String
    let status: String
    let items: List<OrderItem>
    let totalAmount: Double
}

func testOrderValidation() {
    let order = Order(id: "1001", status: "PAID", items: [...], totalAmount: 99.9)
    
    // 链式组合断言,编译期类型安全
    let orderMatcher: Matcher<Order> = AllOf.allOf([
        // 检查 ID
        IsEqual.equalTo("1001"), 
        // 检查状态
        IsEqual.equalTo("PAID"), 
        // 检查总金额 (自定义数值范围匹配器)
        NumberMatchers.closeTo(99.9, 0.01),
        // 检查包含特定商品 (嵌套匹配)
        CollectionMatchers.hasItem(
            ItemMatchers.hasProperty("name", IsEqual.equalTo("Laptop"))
        )
    ])
    
    // 执行断言
    if (!orderMatcher.matches(order)) {
        let desc = Description()
        orderMatcher.describeMismatch(order, desc)
        print("Assertion Failed: \(desc.toString())")
    }
}

项目交付物与实施路线图

3.1 阶段性交付物清单

  • 第一阶段:核心 Matcher 接口、基础匹配器(相等、空、类型、数值、字符串)、组合逻辑(And/Or/Not)、单元测试。

  • 第二阶段:集合与映射匹配器、对象属性匹配器(宏支持)、差异报告优化、集成测试。

  • 第三阶段:性能调优报告、自定义匹配器开发指南、cjpm 发布包及完整文档。

3.2 项目实施路线图

阶段

核心任务

交付成果

周期预估

里程碑

基础构建

核心接口与基础匹配器

可编译库、基础断言功能、单测集

4-6 周

覆盖 80% 常用断言场景,编译期类型检查通过

核心攻坚

组合逻辑与集合匹配

复杂组合支持、集合高效验证、压测报告

6-8 周

万级数据验证性能达标,内存零泄漏

生态集成

文档与发布

用户手册、宏示例、cjpm 包

3-4 周

上架仓颉社区,提供测试框架集成插件

技术实现规范与质量认证体系

4.1 仓颉语言专项质量规范

  • 零开销抽象:常用匹配器方法必须标记为 inline,避免虚函数调用与装箱开销。

  • 类型安全第一:严禁使用 Any 进行模糊匹配,充分利用泛型约束确保编译器能推导具体类型。

  • 不可变性:所有匹配器实例创建后应为不可变(Immutable),确保线程安全与并发读取无锁。

  • 错误显式化:匹配失败不抛异常,而是返回 false 并填充 Description,由测试框架统一处理。

4.2 测试与验证标准

  • 单元测试:核心逻辑覆盖率≥95%,包含边界值、空值、复杂嵌套结构测试。

  • 性能基准:建立 Benchmark 套件,对比 TS/JS 版本,确保性能提升显著(目标 5-10 倍)。

  • 类型测试:编写负向测试用例,确保类型不匹配时代码无法编译通过。

  • 内存分析:长时间运行测试,验证无内存泄漏与 GC 压力。

4.3 文档与可维护性

  • API 文档:每个匹配器均需包含详细的 Doc Comments,说明适用场景与参数含义。

  • 示例工程:提供丰富的单元测试示例,展示如何组合匹配器验证复杂业务对象。

  • 扩展指南:指导开发者如何编写自定义匹配器,融入现有生态。

4.4 持续集成质量门禁

# PR 自动化流水线
cjpm fmt --check
cjpm build --release
cjpm lint --deny-warnings
cjpm test --coverage --min-coverage 95
cjpm bench --threshold 10% # 确保性能不回退

技术栈与开发环境

  • 核心语言:仓颉编程语言(Cangjie Language)1.0.0+。

  • 构建工具:CJPM (Cangjie Package Manager)。

  • 测试框架:仓颉原生测试框架。

  • 环境要求:仓颉 1.0.0+ SDK,CI 使用官方认证 Docker 镜像。

相关附件

暂无附件

质量认证要求

交付件

NO

交付件描述

备注

1

三方库源代码

源代码

2

三方库测试方案和用例

测试用例和文档

3

用户手册,API文档,设计文档,license文档

 资料和文档

验收标准

1.功能

  1. 三方库必须有明确的功能;

  2. 如果参考对标库移值开发,功能与参考三方库保持一致。

2.资料

  1. Readme:包含简介,软件架构,目录结构,下载安装(编译构建),接口说明,使用示例,约束限制,开源协议,参与贡献等内容;

  2. Changelog,三方库版本需包含基本的修改说明。

3.标准遵从性(可选),三方库实现需满足对应协议或行业标准,举例

  1. appquth:支持对OAuth 的PKCE扩展;

  2. icu4j:支持unicode标准库,通用字符集ISO/IEC 10646。

4.性能目标

  1. 性能敏感三方库接口运行性能持平对标三方库

5.开源协议遵从,必须包含License文件

  1. 放置合适的开源License协议,建议Apache License Version 2.0;

  2. 引用或参考开源三方库,需遵从开源协议。

6.网络安全要求

  1. 满足基础的网络安全红线及隐私要求,符合安全编码规范。

过程质量要求

指标分类

指标名称

指标要求

度量工具

牵引 OR Must

代码度量

平均文件代码行

≤300 LOC

CMetricsPlus,CJMetric

Must

总文件重复率

C/C++≤4%;相比开源不劣化

CMetricsPlus,CJMetric

Must

源文件重复率

C/C++≤4%;相比开源不劣化

CMetricsPlus,CJMetric

Must

平均函数或方法代码行*

≤30  LOC

CMetricsPlus,CJMetric

Must

总代码重复率

C/C++≤10%;相比开源不劣化

CMetricsPlus,CJMetric

Must

源文件代码重复率

C/C++≤10%;相比开源不劣化

CMetricsPlus,CJMetric

Must

平均圈复杂度

≤5;相比开源不劣化

CMetricsPlus,CJMetric

Must

冗余代码

“0” 【2】;

CMetricsPlus,CJMetric

Must

不安全函数

NA

CMetricsPlus,CJMetric

Must

静态检查

编译告警

“0” 【2】

Compile工具

牵引

通用静态告警

“0” 【2】

Pclint plus,CJLINT

Must

开发者测试

DT用例密度(个/KLOC)

> 40

手工

牵引 

DT代码语句覆盖率

>=85%

Gcov,cjcov

牵引

DT代码分支覆盖率

>=50%

Gcov,cjcov

牵引

未做DT文件数

0

手工

牵引

问题解决率

遗留问题DI

整体<10

Issue

牵引 

遗留致命缺陷数(0)

0

Issue

Must

累计缺陷解决率

85%

Issue

牵引 

软件开发

每日构建成功率

100%

CI

牵引

测试评估

测试缺陷密度(/KLOC)

5-9

人工

牵引

测试用例密度(个/KLOC)

20-40

人工

牵引

初验用例自动化率

100%

CIDA

牵引 

HLT自动化用例比率

【85%,95%】

CIDA

牵引 

开源第三方(含构建工具)

开源片段引用

0(除例外备案类)

FOSSBOT+人工

Must

可信构建

二进制一致性

0(含可澄清)

人工

Mus