feat: Notitie editor in the app, dictation routed to system or editor
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,26 +2,44 @@ import Foundation
|
||||
import Testing
|
||||
@testable import SstCore
|
||||
|
||||
struct GatedInserterTests {
|
||||
@Test func insertsWhenAllowed() async throws {
|
||||
let inner = FakeInserter()
|
||||
try await GatedInserter(inner: inner, shouldInsert: { true }).insert("hallo")
|
||||
#expect(inner.inserted == ["hallo"])
|
||||
struct RoutingInserterTests {
|
||||
@Test func sendsToTheSystemRoute() async throws {
|
||||
let system = FakeInserter(), editor = FakeInserter()
|
||||
try await RoutingInserter(system: system, editor: editor, route: { .system }).insert("hallo")
|
||||
#expect(system.inserted == ["hallo"])
|
||||
#expect(editor.inserted.isEmpty)
|
||||
}
|
||||
|
||||
@Test func staysSilentWhenNotAllowed() async throws {
|
||||
let inner = FakeInserter()
|
||||
try await GatedInserter(inner: inner, shouldInsert: { false }).insert("hallo")
|
||||
#expect(inner.inserted.isEmpty)
|
||||
@Test func sendsToTheEditorRoute() async throws {
|
||||
let system = FakeInserter(), editor = FakeInserter()
|
||||
try await RoutingInserter(system: system, editor: editor, route: { .editor }).insert("hallo")
|
||||
#expect(editor.inserted == ["hallo"])
|
||||
#expect(system.inserted.isEmpty)
|
||||
}
|
||||
|
||||
@Test func dropsTheTextOnNone() async throws {
|
||||
let system = FakeInserter(), editor = FakeInserter()
|
||||
try await RoutingInserter(system: system, editor: editor, route: { .none }).insert("hallo")
|
||||
#expect(system.inserted.isEmpty)
|
||||
#expect(editor.inserted.isEmpty)
|
||||
}
|
||||
|
||||
@Test func askedAtInsertionTimeNotAtCreation() async throws {
|
||||
let inner = FakeInserter()
|
||||
var allowed = false
|
||||
let gated = GatedInserter(inner: inner, shouldInsert: { allowed })
|
||||
allowed = true
|
||||
try await gated.insert("nu wel")
|
||||
#expect(inner.inserted == ["nu wel"])
|
||||
let system = FakeInserter(), editor = FakeInserter()
|
||||
var current = InsertionRoute.none
|
||||
let router = RoutingInserter(system: system, editor: editor, route: { current })
|
||||
current = .editor
|
||||
try await router.insert("nu wel")
|
||||
#expect(editor.inserted == ["nu wel"])
|
||||
}
|
||||
|
||||
@Test func propagatesInserterErrors() async {
|
||||
struct Boom: Error {}
|
||||
let system = FakeInserter()
|
||||
system.error = Boom()
|
||||
await #expect(throws: Boom.self) {
|
||||
try await RoutingInserter(system: system, editor: FakeInserter(), route: { .system }).insert("x")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import SstData
|
||||
|
||||
@MainActor
|
||||
struct NoteStoreTests {
|
||||
private func temp() -> URL {
|
||||
FileManager.default.temporaryDirectory.appending(path: "note-\(UUID().uuidString)/note.txt")
|
||||
}
|
||||
|
||||
@Test func missingFileLoadsEmpty() {
|
||||
let store = NoteStore(fileURL: temp())
|
||||
store.load()
|
||||
#expect(store.text == "")
|
||||
#expect(!store.isReadOnly)
|
||||
}
|
||||
|
||||
@Test func flushWritesAndAnotherStoreReadsIt() {
|
||||
let url = temp()
|
||||
let store = NoteStore(fileURL: url)
|
||||
store.text = "eerste regel\nté"
|
||||
store.flush()
|
||||
let other = NoteStore(fileURL: url)
|
||||
other.load()
|
||||
#expect(other.text == "eerste regel\nté")
|
||||
}
|
||||
|
||||
@Test func editsAreSavedAfterTheDebounce() async throws {
|
||||
let url = temp()
|
||||
let store = NoteStore(fileURL: url)
|
||||
store.text = "bewaard"
|
||||
#expect(!FileManager.default.fileExists(atPath: url.path))
|
||||
try await Task.sleep(for: .milliseconds(900))
|
||||
#expect(try String(contentsOf: url, encoding: .utf8) == "bewaard")
|
||||
}
|
||||
|
||||
@Test func loadingDoesNotTriggerASave() async throws {
|
||||
let url = temp()
|
||||
try FileManager.default.createDirectory(at: url.deletingLastPathComponent(), withIntermediateDirectories: true)
|
||||
try "oud".write(to: url, atomically: true, encoding: .utf8)
|
||||
let store = NoteStore(fileURL: url)
|
||||
store.load()
|
||||
#expect(store.text == "oud")
|
||||
try FileManager.default.removeItem(at: url)
|
||||
try await Task.sleep(for: .milliseconds(900))
|
||||
#expect(!FileManager.default.fileExists(atPath: url.path))
|
||||
}
|
||||
|
||||
@Test func unreadableFileIsNeverOverwritten() throws {
|
||||
let url = temp()
|
||||
try FileManager.default.createDirectory(at: url.deletingLastPathComponent(), withIntermediateDirectories: true)
|
||||
try Data([0xFF, 0xFE, 0xFD]).write(to: url)
|
||||
let store = NoteStore(fileURL: url)
|
||||
store.load()
|
||||
#expect(store.isReadOnly)
|
||||
store.text = "nieuw"
|
||||
store.flush()
|
||||
#expect(try Data(contentsOf: url) == Data([0xFF, 0xFE, 0xFD]))
|
||||
}
|
||||
}
|
||||
|
||||
struct DictationSpacingTests {
|
||||
@Test func noSpaceAtTheStartOrAfterWhitespace() {
|
||||
#expect(DictationSpacing.prepared("hallo", characterBefore: nil) == "hallo")
|
||||
#expect(DictationSpacing.prepared("hallo", characterBefore: " ") == "hallo")
|
||||
#expect(DictationSpacing.prepared("hallo", characterBefore: "\n") == "hallo")
|
||||
}
|
||||
|
||||
@Test func spaceAfterAWordOrSentenceEnd() {
|
||||
#expect(DictationSpacing.prepared("hallo", characterBefore: "k") == " hallo")
|
||||
#expect(DictationSpacing.prepared("Nog een.", characterBefore: ".") == " Nog een.")
|
||||
}
|
||||
|
||||
@Test func noSpaceBeforeClosingPunctuationOrLeadingWhitespace() {
|
||||
#expect(DictationSpacing.prepared(", dus", characterBefore: "k") == ", dus")
|
||||
#expect(DictationSpacing.prepared(" dus", characterBefore: "k") == " dus")
|
||||
}
|
||||
|
||||
@Test func emptyTextStaysEmpty() {
|
||||
#expect(DictationSpacing.prepared("", characterBefore: "k") == "")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user