Revert "hogar compartido: colaboracion entre cuentas sobre Firestore"

El hogar compartido cambia donde viven los datos, asi que se va a la 3.0 y la
2.x queda para correcciones. El trabajo sigue vivo en la rama 3.0.0 (163fd60).

Importante para esta rama: esto tambien retira el entitlement
com.apple.developer.applesignin, que sin la capability marcada en el App ID
habria roto la firma al subir la 2.1.1 a TestFlight.

This reverts commit 163fd60.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013su1ttRiMeMYxkZJ1Y3246
This commit is contained in:
alexandrev-tibco
2026-09-12 13:08:27 +02:00
parent 163fd6026a
commit d8345a5b20
22 changed files with 8 additions and 2261 deletions
-241
View File
@@ -1,241 +0,0 @@
import XCTest
import SwiftData
@testable import MealMood
/// The pure half of the household sync: document ids, fingerprints and the
/// model Firestore mapping. Anything touching the network stays out.
final class HouseholdDocumentsTests: XCTestCase {
/// Held for the duration of the test: releasing the container tears the
/// store off the coordinator and the next SwiftData call traps.
private var container: ModelContainer!
private var context: ModelContext!
override func setUpWithError() throws {
try super.setUpWithError()
container = try ModelContainer(
for: AppSettings.self, Dish.self, Tag.self, WeekPlan.self, MealSlot.self, ShoppingItem.self,
configurations: ModelConfiguration(isStoredInMemoryOnly: true)
)
context = ModelContext(container)
}
override func tearDown() {
context = nil
container = nil
super.tearDown()
}
// MARK: - Document ids
func testWeekKeyIsTheMondayDate() {
let monday = Calendar(identifier: .gregorian)
.date(from: DateComponents(year: 2026, month: 9, day: 14))!
XCTAssertEqual(HouseholdDocuments.weekKey(for: monday), "2026-09-14")
}
func testWeekKeyIsStableAcrossLocales() {
let monday = Calendar(identifier: .gregorian)
.date(from: DateComponents(year: 2026, month: 1, day: 5))!
// Two members with different phone languages must write the same
// document, not one each.
XCTAssertEqual(HouseholdDocuments.weekKey(for: monday), "2026-01-05")
}
func testSlotIdIsDerivedFromContent() {
XCTAssertEqual(HouseholdDocuments.slotId(dayOfWeek: 5, mealType: "dinner"), "5-dinner")
XCTAssertEqual(HouseholdDocuments.slotId(dayOfWeek: 0, mealType: "breakfast"), "0-breakfast")
}
// MARK: - Fingerprints
func testFingerprintIgnoresKeyOrder() {
let a: [String: Any] = ["name": "Tortilla", "isPriority": true, "sortOrder": 3]
let b: [String: Any] = ["sortOrder": 3, "name": "Tortilla", "isPriority": true]
XCTAssertEqual(HouseholdDocuments.fingerprint(a), HouseholdDocuments.fingerprint(b))
}
func testFingerprintChangesWithContent() {
let dish = Dish(name: "Tortilla")
context.insert(dish)
let before = HouseholdDocuments.fingerprint(HouseholdDocuments.fields(for: dish))
dish.name = "Tortilla de patatas"
let after = HouseholdDocuments.fingerprint(HouseholdDocuments.fields(for: dish))
XCTAssertNotEqual(before, after, "an edited dish must be detected as a local change")
}
func testFingerprintDistinguishesBoolFromInt() {
let asBool: [String: Any] = ["value": true]
let asInt: [String: Any] = ["value": 1]
XCTAssertNotEqual(HouseholdDocuments.fingerprint(asBool), HouseholdDocuments.fingerprint(asInt))
}
// MARK: - Round trips
func testDishSurvivesARoundTrip() {
let tagId = UUID()
let original = Dish(
name: "Salmón al horno",
descriptionText: "con limón",
tagIds: [tagId],
isPriority: true,
ingredients: ["salmón", "limón"],
fixedDayOfWeek: 4,
fixedMealType: "dinner"
)
context.insert(original)
let copy = Dish(id: original.id, name: "")
context.insert(copy)
HouseholdDocuments.apply(HouseholdDocuments.fields(for: original), to: copy)
XCTAssertEqual(copy.name, "Salmón al horno")
XCTAssertEqual(copy.descriptionText, "con limón")
XCTAssertEqual(copy.tagIds, [tagId])
XCTAssertEqual(copy.ingredients, ["salmón", "limón"])
XCTAssertTrue(copy.isPriority)
XCTAssertEqual(copy.fixedDayOfWeek, 4)
XCTAssertEqual(copy.fixedMealType, "dinner")
XCTAssertEqual(
HouseholdDocuments.fingerprint(HouseholdDocuments.fields(for: original)),
HouseholdDocuments.fingerprint(HouseholdDocuments.fields(for: copy)),
"a round trip must not look like a change to push"
)
}
func testTagRulesSurviveARoundTrip() {
let original = Tag(
name: "Pescado", nameEN: "Fish", color: "#4FC3F7",
maxPerWeek: 2, noConsecutive: true, noDuplicateInDay: true,
mealTypeRestriction: "dinner", dayRestriction: "weekdays",
isDefault: false, sortOrder: 7
)
context.insert(original)
let copy = Tag(id: original.id, name: "", color: "")
context.insert(copy)
HouseholdDocuments.apply(HouseholdDocuments.fields(for: original), to: copy)
XCTAssertEqual(copy.nameEN, "Fish")
XCTAssertEqual(copy.maxPerWeek, 2)
XCTAssertTrue(copy.noConsecutive)
XCTAssertEqual(copy.mealTypeRestriction, "dinner")
XCTAssertEqual(copy.dayRestriction, "weekdays", "day rules must travel or they'd silently reset")
XCTAssertEqual(copy.sortOrder, 7)
}
func testSlotSurvivesARoundTripWithoutTheCalendarEventId() {
let original = MealSlot(dayOfWeek: 2, mealType: "lunch")
original.dishId = UUID()
original.secondaryDishId = UUID()
original.isSkipped = true
original.calendarEventId = "local-eventkit-id"
context.insert(original)
let copy = MealSlot(dayOfWeek: 2, mealType: "lunch")
context.insert(copy)
HouseholdDocuments.apply(HouseholdDocuments.fields(for: original), to: copy)
XCTAssertEqual(copy.dishId, original.dishId)
XCTAssertEqual(copy.secondaryDishId, original.secondaryDishId)
XCTAssertTrue(copy.isSkipped)
// The EventKit id only means something on the device that created it.
XCTAssertNil(copy.calendarEventId)
XCTAssertNil(HouseholdDocuments.fields(for: original)["calendarEventId"])
}
func testWeekPlanCarriesItsScheduleOverride() {
let plan = WeekPlan(weekStartDate: Date().startOfWeek())
plan.includeWeekendsOverride = true
plan.mealTypesOverrideRaw = "breakfast,dinner"
plan.userRating = 1
context.insert(plan)
let copy = WeekPlan(weekStartDate: plan.weekStartDate)
context.insert(copy)
HouseholdDocuments.apply(HouseholdDocuments.fields(for: plan), to: copy)
XCTAssertEqual(copy.includeWeekendsOverride, true)
XCTAssertEqual(copy.mealTypesOverrideRaw, "breakfast,dinner")
XCTAssertEqual(copy.userRating, 1)
}
func testShoppingItemSurvivesARoundTrip() {
let item = ShoppingItem(weekStartDate: Date().startOfWeek(), title: "Leche", isChecked: true, sortOrder: 4)
context.insert(item)
let copy = ShoppingItem(id: item.id, weekStartDate: item.weekStartDate, title: "")
context.insert(copy)
HouseholdDocuments.apply(HouseholdDocuments.fields(for: item), to: copy)
XCTAssertEqual(copy.title, "Leche")
XCTAssertTrue(copy.isChecked)
XCTAssertEqual(copy.sortOrder, 4)
}
// MARK: - Invite codes
func testInviteCodesUseAnUnambiguousAlphabet() {
for _ in 0..<200 {
let code = HouseholdService.makeInviteCode()
XCTAssertEqual(code.count, 6)
// No 0/O/1/I and no vowels: codes get read out loud and retyped.
XCTAssertFalse(code.contains(where: { "01IOAEU".contains($0) }), "ambiguous character in \(code)")
}
}
func testCodeNormalizationAcceptsHowPeopleTypeIt() {
let code = HouseholdService.makeInviteCode()
let messy = code.lowercased().split(separator: "").joined()
let spaced = code.map(String.init).joined(separator: " ")
let dashed = code.prefix(3) + "-" + code.suffix(3)
XCTAssertEqual(HouseholdService.normalize(messy), code)
XCTAssertEqual(HouseholdService.normalize(spaced), code)
XCTAssertEqual(HouseholdService.normalize(String(dashed)), code)
XCTAssertTrue(HouseholdService.isPlausibleCode(spaced))
}
func testShortOrEmptyCodesAreRejectedBeforeHittingTheNetwork() {
XCTAssertFalse(HouseholdService.isPlausibleCode(""))
XCTAssertFalse(HouseholdService.isPlausibleCode("BCD"))
XCTAssertFalse(HouseholdService.isPlausibleCode("AEIOU"), "vowels aren't part of the alphabet")
}
// MARK: - Shadow
func testShadowTracksWhatWasSynced() {
var shadow = SyncShadow()
shadow.set(path: "dishes/abc", fingerprint: "1234")
XCTAssertEqual(shadow.fingerprint(for: "dishes/abc"), "1234")
XCTAssertNil(shadow.fingerprint(for: "dishes/other"))
shadow.remove(path: "dishes/abc")
XCTAssertNil(shadow.fingerprint(for: "dishes/abc"))
shadow.set(path: "tags/x", fingerprint: "ffff")
shadow.reset()
XCTAssertTrue(shadow.paths.isEmpty)
}
func testShadowSurvivesARelaunch() {
let householdId = "test-\(UUID().uuidString)"
var shadow = SyncShadow()
shadow.set(path: "dishes/abc", fingerprint: "1234")
shadow.save(householdId: householdId)
var restored = SyncShadow()
restored.load(householdId: householdId)
XCTAssertEqual(restored.fingerprint(for: "dishes/abc"), "1234",
"without this the whole store would re-upload on every launch")
UserDefaults.standard.removeObject(forKey: "household_shadow_\(householdId)")
}
}