Hamcrest
该仓库是 OpenHarmony 生态中的一个 Hamcrest 风格匹配器库,主要用于在测试或逻辑判断中提供灵活、可组合的条件匹配功能。它支持字符串、数值、数组、对象等多种类型的断言匹配(如包含、相等、为空、正则匹配等),适用于 OpenHarmony 应用开发中的单元测试和验证场景,基于 TypeScript/ArkTS 编写
悬赏内容
招募内容
项目背景与战略目标
Hamcrest 是全球公认的测试断言标准,其“可组合匹配器(Composable Matchers)”理念极大地提升了单元测试的可读性与维护性。然而,OpenHarmony 生态中现有的 Hamcrest 实现基于 TypeScript/ArkTS,存在以下后端场景下的局限性:
类型安全缺失:动态类型系统导致匹配器在编译期无法校验类型兼容性,常出现“运行时才报错”的低级错误,且缺乏智能提示。
性能开销:JS 引擎的动态分发与对象创建开销较大,在大规模数据验证或高频断言场景下(如 fuzzing 测试),会显著拖慢测试执行速度。
组合能力受限:缺乏强大的泛型与高阶函数支持,自定义复杂匹配器(如嵌套对象结构验证)时代码冗长且易错。
内存管理:频繁创建临时匹配器对象可能增加 GC 压力,影响长运行测试任务的稳定性。
本项目旨在利用 仓颉编程语言(Cangjie Language)1.0.0+ 重构 Hamcrest,打造一款编译期类型安全、零运行时开销、高度可组合的通用匹配器库。它将包含:
强类型泛型系统:利用仓颉泛型约束,确保
Matcher<T>只能接受类型T的数据,编译期拦截类型不匹配错误。零开销抽象:利用内联函数(Inline Functions)与值类型优化,消除虚函数调用与临时对象分配,提升断言执行速度 5-10 倍。
代数数据类型组合:利用
enum和模式匹配构建复杂的逻辑组合(And/Or/Not),代码简洁且逻辑严密。原生错误报告:生成结构化的差异报告(Diff),精准定位失败原因,无缝集成仓颉测试框架。
这将为企业提供一个工业级、高可靠的测试基础设施,不仅适用于单元测试,还可广泛应用于运行时的数据校验、规则引擎条件判断等后端核心场景。
核心功能需求与技术规格
2.1 功能模块分解
模块类别 | 核心职责 | 关键技术要求 (仓颉特性) | 验收依据 |
|---|---|---|---|
核心匹配接口 | 定义 | 利用 泛型约束 确保类型安全;接口默认方法提供便捷实现 | 编译期类型检查通过率 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.功能
三方库必须有明确的功能;
如果参考对标库移值开发,功能与参考三方库保持一致。
2.资料
Readme:包含简介,软件架构,目录结构,下载安装(编译构建),接口说明,使用示例,约束限制,开源协议,参与贡献等内容;
Changelog,三方库版本需包含基本的修改说明。
3.标准遵从性(可选),三方库实现需满足对应协议或行业标准,举例
appquth:支持对OAuth 的PKCE扩展;
icu4j:支持unicode标准库,通用字符集ISO/IEC 10646。
4.性能目标
性能敏感三方库接口运行性能持平对标三方库
5.开源协议遵从,必须包含License文件
放置合适的开源License协议,建议Apache License Version 2.0;
引用或参考开源三方库,需遵从开源协议。
6.网络安全要求
满足基础的网络安全红线及隐私要求,符合安全编码规范。
过程质量要求
指标分类 | 指标名称 | 指标要求 | 度量工具 | 牵引 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 |

