Initial scaffold: context-aware notes app for iOS + macOS
XcodeGen project (Notes / NotesMac / NotesTests), Swift 6 strict concurrency, iCloud-document storage via IndieSync with a SwiftData cache, automatic capture context (location, place, time zone, device) on every note, context-based relevance ranking with a 'Right here, right now' shelf, tags, search, and the square.and.pencil-on-red app icon.
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
import Foundation
|
||||
import SwiftData
|
||||
import Testing
|
||||
@testable import Notes
|
||||
|
||||
@MainActor
|
||||
struct NoteMapperTests {
|
||||
/// Returns the container too — `mainContext` does not keep its container
|
||||
/// alive, and letting it deallocate mid-test crashes the process.
|
||||
private func makeStore() throws -> (container: ModelContainer, context: ModelContext) {
|
||||
let config = ModelConfiguration(isStoredInMemoryOnly: true, cloudKitDatabase: .none)
|
||||
let container = try ModelContainer(for: NoteEntity.self, configurations: config)
|
||||
return (container, container.mainContext)
|
||||
}
|
||||
|
||||
private func makeNote(text: String = "Barista's name is Sam") -> Note {
|
||||
var context = CaptureContext.empty
|
||||
context.latitude = 37.8044
|
||||
context.longitude = -122.2712
|
||||
context.placeName = "Blue Bottle Coffee"
|
||||
context.timeZoneID = "America/Los_Angeles"
|
||||
return Note.create(text: text, tags: ["coffee"], context: context)
|
||||
}
|
||||
|
||||
@Test func upsertInsertsThenUpdates() throws {
|
||||
let (container, context) = try makeStore()
|
||||
defer { withExtendedLifetime(container) {} }
|
||||
let note = makeNote()
|
||||
|
||||
NoteMapper.upsert(note, relativePath: note.relativePath, into: context)
|
||||
let inserted = NoteMapper.fetch(id: note.meta.id.stringValue, in: context)
|
||||
#expect(inserted?.text == "Barista's name is Sam")
|
||||
#expect(inserted?.placeName == "Blue Bottle Coffee")
|
||||
|
||||
var edited = note
|
||||
edited.payload.text = "Barista's name is Sam — likes cortados"
|
||||
edited.payload.tags = ["coffee", "people"]
|
||||
NoteMapper.upsert(edited, relativePath: note.relativePath, into: context)
|
||||
|
||||
let all = try context.fetch(FetchDescriptor<NoteEntity>())
|
||||
#expect(all.count == 1)
|
||||
#expect(all.first?.text == "Barista's name is Sam — likes cortados")
|
||||
#expect(all.first?.tags == ["coffee", "people"])
|
||||
}
|
||||
|
||||
@Test func entityRoundTripsBackToNote() throws {
|
||||
let (container, context) = try makeStore()
|
||||
defer { withExtendedLifetime(container) {} }
|
||||
let note = makeNote()
|
||||
NoteMapper.upsert(note, relativePath: note.relativePath, into: context)
|
||||
|
||||
let entity = try #require(NoteMapper.fetch(id: note.meta.id.stringValue, in: context))
|
||||
let restored = try #require(NoteMapper.note(from: entity))
|
||||
#expect(restored.payload == note.payload)
|
||||
#expect(restored.meta.id == note.meta.id)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user