iOS Build 22
This commit is contained in:
@@ -326,4 +326,203 @@ final class OpenClimbTests: XCTestCase {
|
||||
XCTAssertTrue(hasActiveSession, "Combined sessions should contain active session")
|
||||
XCTAssertTrue(hasCompletedSession, "Combined sessions should contain completed session")
|
||||
}
|
||||
|
||||
// MARK: - Orphaned Data Cleanup Tests
|
||||
|
||||
func testOrphanedAttemptDetection() throws {
|
||||
// Test that we can detect orphaned attempts (attempts referencing non-existent sessions)
|
||||
|
||||
let validSessionId = UUID()
|
||||
let deletedSessionId = UUID()
|
||||
let validProblemId = UUID()
|
||||
|
||||
// Simulate a list of valid sessions
|
||||
let validSessions = [validSessionId]
|
||||
|
||||
// Simulate attempts - one valid, one orphaned
|
||||
let validAttempt: [String: Any] = [
|
||||
"id": UUID().uuidString,
|
||||
"sessionId": validSessionId.uuidString,
|
||||
"problemId": validProblemId.uuidString,
|
||||
"result": "completed",
|
||||
]
|
||||
|
||||
let orphanedAttempt: [String: Any] = [
|
||||
"id": UUID().uuidString,
|
||||
"sessionId": deletedSessionId.uuidString,
|
||||
"problemId": validProblemId.uuidString,
|
||||
"result": "completed",
|
||||
]
|
||||
|
||||
let allAttempts = [validAttempt, orphanedAttempt]
|
||||
|
||||
// Filter to find orphaned attempts
|
||||
let orphaned = allAttempts.filter { attempt in
|
||||
guard let sessionIdString = attempt["sessionId"] as? String,
|
||||
let sessionId = UUID(uuidString: sessionIdString)
|
||||
else {
|
||||
return false
|
||||
}
|
||||
return !validSessions.contains(sessionId)
|
||||
}
|
||||
|
||||
XCTAssertEqual(orphaned.count, 1, "Should detect exactly one orphaned attempt")
|
||||
XCTAssertEqual(orphaned[0]["sessionId"] as? String, deletedSessionId.uuidString)
|
||||
}
|
||||
|
||||
func testOrphanedAttemptRemoval() throws {
|
||||
// Test that orphaned attempts can be properly removed from a list
|
||||
|
||||
let validSessionId = UUID()
|
||||
let deletedSessionId = UUID()
|
||||
let problemId = UUID()
|
||||
|
||||
let validSessions = Set([validSessionId])
|
||||
|
||||
// Create test attempts
|
||||
var attempts: [[String: Any]] = [
|
||||
[
|
||||
"id": UUID().uuidString,
|
||||
"sessionId": validSessionId.uuidString,
|
||||
"problemId": problemId.uuidString,
|
||||
"result": "completed",
|
||||
],
|
||||
[
|
||||
"id": UUID().uuidString,
|
||||
"sessionId": deletedSessionId.uuidString,
|
||||
"problemId": problemId.uuidString,
|
||||
"result": "failed",
|
||||
],
|
||||
[
|
||||
"id": UUID().uuidString,
|
||||
"sessionId": validSessionId.uuidString,
|
||||
"problemId": problemId.uuidString,
|
||||
"result": "flash",
|
||||
],
|
||||
]
|
||||
|
||||
XCTAssertEqual(attempts.count, 3, "Should start with 3 attempts")
|
||||
|
||||
// Remove orphaned attempts
|
||||
attempts.removeAll { attempt in
|
||||
guard let sessionIdString = attempt["sessionId"] as? String,
|
||||
let sessionId = UUID(uuidString: sessionIdString)
|
||||
else {
|
||||
return true
|
||||
}
|
||||
return !validSessions.contains(sessionId)
|
||||
}
|
||||
|
||||
XCTAssertEqual(attempts.count, 2, "Should have 2 attempts after cleanup")
|
||||
|
||||
// Verify remaining attempts are all valid
|
||||
for attempt in attempts {
|
||||
if let sessionIdString = attempt["sessionId"] as? String,
|
||||
let sessionId = UUID(uuidString: sessionIdString)
|
||||
{
|
||||
XCTAssertTrue(
|
||||
validSessions.contains(sessionId),
|
||||
"All remaining attempts should reference valid sessions")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testCascadeDeleteSessionWithAttempts() throws {
|
||||
// Test that deleting a session properly tracks all its attempts as deleted
|
||||
|
||||
let sessionId = UUID()
|
||||
let problemId = UUID()
|
||||
|
||||
// Create attempts for this session
|
||||
let sessionAttempts: [[String: Any]] = [
|
||||
[
|
||||
"id": UUID().uuidString, "sessionId": sessionId.uuidString,
|
||||
"problemId": problemId.uuidString,
|
||||
],
|
||||
[
|
||||
"id": UUID().uuidString, "sessionId": sessionId.uuidString,
|
||||
"problemId": problemId.uuidString,
|
||||
],
|
||||
[
|
||||
"id": UUID().uuidString, "sessionId": sessionId.uuidString,
|
||||
"problemId": problemId.uuidString,
|
||||
],
|
||||
]
|
||||
|
||||
XCTAssertEqual(sessionAttempts.count, 3, "Session should have 3 attempts")
|
||||
|
||||
// Simulate tracking deletions
|
||||
var deletedItems: [String] = []
|
||||
|
||||
// Add session to deleted items
|
||||
deletedItems.append(sessionId.uuidString)
|
||||
|
||||
// Add all attempts to deleted items
|
||||
for attempt in sessionAttempts {
|
||||
if let attemptId = attempt["id"] as? String {
|
||||
deletedItems.append(attemptId)
|
||||
}
|
||||
}
|
||||
|
||||
XCTAssertEqual(deletedItems.count, 4, "Should track 1 session + 3 attempts as deleted")
|
||||
XCTAssertTrue(deletedItems.contains(sessionId.uuidString), "Should track session deletion")
|
||||
|
||||
// Verify all attempt IDs are tracked
|
||||
let attemptIds = sessionAttempts.compactMap { $0["id"] as? String }
|
||||
for attemptId in attemptIds {
|
||||
XCTAssertTrue(
|
||||
deletedItems.contains(attemptId), "Should track attempt \(attemptId) deletion")
|
||||
}
|
||||
}
|
||||
|
||||
func testDataIntegrityValidation() throws {
|
||||
// Test data integrity validation logic
|
||||
|
||||
let gymId = UUID()
|
||||
let sessionId = UUID()
|
||||
let problemId = UUID()
|
||||
|
||||
// Valid data setup
|
||||
let gyms = [gymId]
|
||||
let sessions = [(id: sessionId, gymId: gymId)]
|
||||
let problems = [(id: problemId, gymId: gymId)]
|
||||
let attempts = [
|
||||
(id: UUID(), sessionId: sessionId, problemId: problemId),
|
||||
(id: UUID(), sessionId: sessionId, problemId: problemId),
|
||||
]
|
||||
|
||||
// Validate that all relationships are correct
|
||||
let validGyms = Set(gyms)
|
||||
let validSessions = Set(sessions.map { $0.id })
|
||||
let validProblems = Set(problems.map { $0.id })
|
||||
|
||||
// Check sessions reference valid gyms
|
||||
for session in sessions {
|
||||
XCTAssertTrue(validGyms.contains(session.gymId), "Session should reference valid gym")
|
||||
}
|
||||
|
||||
// Check problems reference valid gyms
|
||||
for problem in problems {
|
||||
XCTAssertTrue(validGyms.contains(problem.gymId), "Problem should reference valid gym")
|
||||
}
|
||||
|
||||
// Check attempts reference valid sessions and problems
|
||||
for attempt in attempts {
|
||||
XCTAssertTrue(
|
||||
validSessions.contains(attempt.sessionId), "Attempt should reference valid session")
|
||||
XCTAssertTrue(
|
||||
validProblems.contains(attempt.problemId), "Attempt should reference valid problem")
|
||||
}
|
||||
|
||||
// Test integrity check passes
|
||||
let hasOrphanedSessions = sessions.contains { !validGyms.contains($0.gymId) }
|
||||
let hasOrphanedProblems = problems.contains { !validGyms.contains($0.gymId) }
|
||||
let hasOrphanedAttempts = attempts.contains {
|
||||
!validSessions.contains($0.sessionId) || !validProblems.contains($0.problemId)
|
||||
}
|
||||
|
||||
XCTAssertFalse(hasOrphanedSessions, "Should not have orphaned sessions")
|
||||
XCTAssertFalse(hasOrphanedProblems, "Should not have orphaned problems")
|
||||
XCTAssertFalse(hasOrphanedAttempts, "Should not have orphaned attempts")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user