feat: add EntryWarnings and VocabularyBuilder

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-01 15:11:48 +02:00
co-authored by Claude Sonnet 5.5
parent 93bf59e090
commit fe24292279
4 changed files with 165 additions and 0 deletions
@@ -0,0 +1,60 @@
import Testing
@testable import SstData
struct EntryWarningsTests {
let knowledge = FakeKnowledge()
func check(_ kind: DictionaryEntry.Kind, others: [DictionaryEntry] = []) -> [EntryWarning] {
EntryWarnings.check(kind, among: others, knowledge: knowledge)
}
@Test func singleCommonWordIsAWarning() {
let w = check(.correction(heard: "cloud", wrote: "Claude"))
#expect(w.contains { $0.level == .warning && $0.message.contains("cloud") })
}
@Test func veryShortSourceIsAWarning() {
#expect(check(.correction(heard: "ab", wrote: "AB")).contains { $0.level == .warning })
}
@Test func functionWordInsideAPhraseIsAWarning() {
#expect(check(.correction(heard: "in de", wrote: "indeed")).contains { $0.level == .warning })
}
@Test func gluedFormThatIsARealWordIsAWarning() {
let w = check(.correction(heard: "some thing", wrote: "Something"))
#expect(w.contains { $0.level == .warning && $0.message.contains("something") })
}
@Test func phraseOfCommonWordsOnlyGetsANote() {
let w = check(.correction(heard: "cloud code", wrote: "Claude Code"))
#expect(w.count == 1)
#expect(w[0].level == .note)
}
@Test func distinctiveEntriesGetNoWarnings() {
#expect(check(.correction(heard: "versel", wrote: "Vercel")).isEmpty)
#expect(check(.term("Supabase")).isEmpty)
}
@Test func duplicateSourceIsAnErrorEvenWithDifferentSpelling() {
let others = [pair("cloud code", "Claude Code")]
let w = check(.correction(heard: "Cloud-Code", wrote: "X"), others: others)
#expect(w.first?.level == .error)
}
@Test func termThatIsARealWordGetsANoteAboutBiasOnly() {
let w = check(.term("Reef"))
#expect(w.count == 1)
#expect(w[0].level == .note)
}
@Test func emptySourceIsAnError() {
#expect(check(.term(" ")).first?.level == .error)
}
@Test func warningsAreSortedMostSevereFirst() {
let w = check(.correction(heard: "cloud", wrote: "Claude"), others: [pair("cloud", "x")])
#expect(w.map(\.level) == w.map(\.level).sorted(by: >))
}
}
@@ -0,0 +1,19 @@
import Testing
@testable import SstData
struct VocabularyBuilderTests {
@Test func termsComeFirstThenCorrectionTargetsWithoutDuplicates() {
let entries = [pair("cloud code", "Claude Code"), term("Anthropic"), term("anthropic"), pair("versel", "Vercel"), term("Supabase")]
#expect(VocabularyBuilder.build(from: entries) == ["Anthropic", "Supabase", "Claude Code", "Vercel"])
}
@Test func listIsCapped() {
let entries = (1...40).map { term("Woord\($0)") }
#expect(VocabularyBuilder.build(from: entries).count == 24)
#expect(VocabularyBuilder.build(from: entries, maxTerms: 5).count == 5)
}
@Test func emptyDictionaryGivesNoVocabulary() {
#expect(VocabularyBuilder.build(from: []).isEmpty)
}
}