配合 filter-repo 重写历史(51 个 commit 全过一遍): - 删除 scripts/probes/(agentx 训练追问清单)。那两个文件描述了一个 未发布商业产品的架构、训练策略、内部通道拆解和内部素材路径 —— 不是密钥泄露,是路线图泄露。已从全部历史移除。 - 真实项目名换成中性名:内容和 commit message 一起替换, 实战细节全部保留(NOTES.md 里每条坑的现场是这个仓库最有价值的部分)。 - 蓝湖 skill 的真实项目 UUID 换成 YOUR_* 占位符,并说明去哪儿取。 - /Users/dev → /Users/dev。 - 补 LICENSE(MIT,README 早就写了 MIT 但没有文件)。 - README 的 clone 地址指向新的公开仓库。 ProjectSearchTests 的 fixture 跟着改了:`demo-ios` 有 n 和两个 u, `demo-ios` 没有,原来的断言字符在新名字上不成立。断言的性质没变 (子序列必须按顺序、字符不能复用),只换了在新 fixture 上等价的字符。 保留 bundle id dev.hengjun.claude-hub —— 改它会让已授予的 TCC 权限 (控制 iTerm 的 Automation、通知)全部失效,而 app 标识本来就是公开信息。 518 个测试全过。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
42 lines
1.5 KiB
Swift
42 lines
1.5 KiB
Swift
import XCTest
|
||
@testable import HubUI
|
||
|
||
/// 验收页项目选择器的模糊匹配。
|
||
///
|
||
/// 这块单独测是因为它有个容易写错的边界:子序列匹配**必须按顺序**。
|
||
/// 写成"每个字符都出现过"的话 `sod` 也能匹配到 `demo-ios`,
|
||
/// 搜索结果会变成噪音,而这种错在肉眼看列表时很难发现。
|
||
final class ProjectSearchTests: XCTestCase {
|
||
|
||
private func matches(_ needle: String, _ haystack: String) -> Bool {
|
||
AcceptancePane.isSubsequence(needle, of: haystack)
|
||
}
|
||
|
||
func testMatchesAnAbbreviation() {
|
||
XCTAssertTrue(matches("dios", "demo-ios"))
|
||
XCTAssertTrue(matches("dand", "demo-android"))
|
||
XCTAssertTrue(matches("chub", "claude-hub"))
|
||
}
|
||
|
||
/// **顺序必须算数。** 这条是这个函数唯一真正的约束。
|
||
func testRespectsOrder() {
|
||
XCTAssertFalse(matches("sod", "demo-ios"), "字符齐了但顺序不对,不该匹配")
|
||
XCTAssertFalse(matches("bahc", "claude-hub"))
|
||
}
|
||
|
||
func testRejectsMissingCharacters() {
|
||
XCTAssertFalse(matches("diosx", "demo-ios"))
|
||
XCTAssertFalse(matches("z", "claude-hub"))
|
||
}
|
||
|
||
func testEmptyNeedleMatchesEverything() {
|
||
XCTAssertTrue(matches("", "claude-hub"))
|
||
}
|
||
|
||
/// 每个字符只能消费一次 —— 否则 `iii` 会匹配上只有一个 i 的名字。
|
||
func testDoesNotReuseTheSameCharacter() {
|
||
XCTAssertFalse(matches("ii", "demo-ios"))
|
||
XCTAssertTrue(matches("oo", "demo-ios"))
|
||
}
|
||
}
|