99 lines
4.0 KiB
Swift
99 lines
4.0 KiB
Swift
import Foundation
|
|
import Testing
|
|
import SstCore
|
|
@testable import SstData
|
|
|
|
struct CorrectionEngineTests {
|
|
let knowledge = FakeKnowledge()
|
|
|
|
func engine(_ entries: [DictionaryEntry]) -> CorrectionEngine {
|
|
CorrectionEngine(entries: entries, knowledge: knowledge)
|
|
}
|
|
|
|
@Test func replacesAPairAndReportsIt() {
|
|
let result = engine([pair("cloud code", "Claude Code")]).correct("ik gebruik cloud code vandaag")
|
|
#expect(result.text == "ik gebruik Claude Code vandaag")
|
|
#expect(result.corrections.count == 1)
|
|
let c = result.corrections[0]
|
|
#expect(c.heard == "cloud code" && c.wrote == "Claude Code" && c.rule == "cloud code")
|
|
#expect((result.text as NSString).substring(with: NSRange(location: c.start, length: c.length)) == "Claude Code")
|
|
}
|
|
|
|
@Test func findsGluedHyphenatedAndSpacedVariants() {
|
|
let e = engine([pair("cloud code", "Claude Code")])
|
|
for variant in ["CloudCode", "Cloud-Code", "CLOUD CODE", "cloud\u{2011}code", "cloud code"] {
|
|
#expect(e.correct(variant).text == "Claude Code", "variant \(variant)")
|
|
}
|
|
}
|
|
|
|
@Test func neverTouchesRealWordsThatMerelyStartTheSame() {
|
|
let e = engine([pair("cloud code", "Claude Code")])
|
|
#expect(e.correct("Cloudflare is handig").text == "Cloudflare is handig")
|
|
#expect(e.correct("cloud codex").text == "cloud codex")
|
|
#expect(e.correct("de cloud en de code").text == "de cloud en de code")
|
|
#expect(e.correct("the cloud").corrections.isEmpty)
|
|
}
|
|
|
|
@Test func respectsPunctuationBoundaries() {
|
|
let e = engine([pair("cloud code", "Claude Code")])
|
|
#expect(e.correct("(cloud code)").text == "(Claude Code)")
|
|
#expect(e.correct("cloud code.").text == "Claude Code.")
|
|
#expect(e.correct("Cloud Code, Cloud Code").text == "Claude Code, Claude Code")
|
|
}
|
|
|
|
@Test func longestMatchWins() {
|
|
let e = engine([pair("cloud code", "Claude Code"), pair("cloud code review", "Claude Code Review")])
|
|
#expect(e.correct("cloud code review nu").text == "Claude Code Review nu")
|
|
#expect(e.correct("cloud-code-review").text == "Claude Code Review")
|
|
}
|
|
|
|
@Test func replacedTextIsNeverRescanned() {
|
|
let e = engine([pair("a", "b"), pair("b", "c")])
|
|
#expect(e.correct("a b").text == "b c")
|
|
}
|
|
|
|
@Test func termsFixCasingAndSpacing() {
|
|
let e = engine([term("Anthropic"), term("Claude Code")])
|
|
#expect(e.correct("anthropic ANTHROPIC").text == "Anthropic Anthropic")
|
|
#expect(e.correct("claudecode en claude-code").text == "Claude Code en Claude Code")
|
|
}
|
|
|
|
@Test func termAlreadyRightIsNotReportedAsACorrection() {
|
|
let result = engine([term("Anthropic")]).correct("Anthropic bouwt Claude")
|
|
#expect(result.text == "Anthropic bouwt Claude")
|
|
#expect(result.corrections.isEmpty)
|
|
}
|
|
|
|
@Test func singleWordTermThatIsARealWordGetsNoCasingRule() {
|
|
let e = engine([term("Reef"), term("Slack")])
|
|
#expect(e.correct("het reef en slack").text == "het reef en slack")
|
|
}
|
|
|
|
@Test func firstEntryWinsOnDuplicateSources() {
|
|
let e = engine([pair("cloud code", "Claude Code"), pair("Cloud-Code", "Other")])
|
|
#expect(e.correct("cloudcode").text == "Claude Code")
|
|
}
|
|
|
|
@Test func replacementIsLiteral() {
|
|
let e = engine([pair("price", "US$1 \\0 $1")])
|
|
#expect(e.correct("the price").text == "the US$1 \\0 $1")
|
|
}
|
|
|
|
@Test func handlesDiacritics() {
|
|
let e = engine([term("Café")])
|
|
#expect(e.correct("een CAFÉ om de hoek").text == "een Café om de hoek")
|
|
}
|
|
|
|
@Test func offsetsAreRelativeToTheCorrectedText() {
|
|
let result = engine([pair("a", "xxx"), pair("b", "y")]).correct("a b a")
|
|
#expect(result.text == "xxx y xxx")
|
|
#expect(result.corrections.map(\.start) == [0, 4, 6])
|
|
#expect(result.corrections.map(\.length) == [3, 1, 3])
|
|
}
|
|
|
|
@Test func emptyDictionaryAndEmptyTextAreNoOps() {
|
|
#expect(engine([]).correct("hallo").text == "hallo")
|
|
#expect(engine([pair("a", "b")]).correct("").text == "")
|
|
}
|
|
}
|