import Foundation import Testing @testable import Workouts /// Locks `RoutineOrdering.changedOrders` — the pure `.onMove` → renumbered-order math /// shared by any list backed by a `SyncEngine` document write. Results are compared as /// `"id:order"` strings since tuple arrays aren't `Equatable`. struct RoutineOrderingTests { private func describe(_ changes: [(id: String, order: Int)]) -> [String] { changes.map { "\($0.id):\($0.order)" } } @Test func moveProducesMinimalChangedSet() { // A, B, C, D at orders 0...3; drag C (index 2) to the front. B and A shift by // one; D — already last — keeps its order and must NOT appear in the result. let changes = RoutineOrdering.changedOrders( ids: ["A", "B", "C", "D"], currentOrders: ["A": 0, "B": 1, "C": 2, "D": 3], from: IndexSet(integer: 2), to: 0 ) #expect(Set(describe(changes)) == Set(["C:0", "A:1", "B:2"])) } @Test func noOpMoveYieldsEmptyChangeSet() { // Dropping a row back where it started (or an app-level tap that fires the // same source/destination) must produce zero document churn. let changes = RoutineOrdering.changedOrders( ids: ["A", "B", "C", "D"], currentOrders: ["A": 0, "B": 1, "C": 2, "D": 3], from: IndexSet(integer: 0), to: 0 ) #expect(changes.isEmpty) } @Test func legacyDuplicateOrdersNormalizeOnFirstDrag() { // Legacy data where every row collided at order 0. Even a no-op array move // (A stays first) must renumber every row that isn't already at its correct // 0...n-1 position — the whole point of comparing against the stored value // rather than only the dragged row. let changes = RoutineOrdering.changedOrders( ids: ["A", "B", "C", "D"], currentOrders: ["A": 0, "B": 0, "C": 0, "D": 0], from: IndexSet(integer: 0), to: 0 ) #expect(Set(describe(changes)) == Set(["B:1", "C:2", "D:3"])) } @Test func idMissingFromCurrentOrdersIsAlwaysIncluded() { // A newly-added row with no prior stored order can't be assumed unchanged. let changes = RoutineOrdering.changedOrders( ids: ["A", "B"], currentOrders: ["A": 0], from: IndexSet(integer: 0), to: 0 ) #expect(Set(describe(changes)) == Set(["B:1"])) } @Test func moveToEndRenumbersOnlyDisplacedRows() { let changes = RoutineOrdering.changedOrders( ids: ["A", "B", "C", "D"], currentOrders: ["A": 0, "B": 1, "C": 2, "D": 3], from: IndexSet(integer: 0), to: 4 ) // A moves to the end; B, C, D each shift down one; nothing keeps its old order. #expect(Set(describe(changes)) == Set(["B:0", "C:1", "D:2", "A:3"])) } }