// // VoteLogicsTests.swift // ReflectTests // // Tests for ShowBasedOnVoteLogics vote status and timing. // import XCTest import SwiftData @testable import Reflect @MainActor final class VoteLogicsTests: XCTestCase { // MARK: - Phase 7: passedTodaysVotingUnlock Tests func test_passedVotingUnlock_beforeTime() { // Voting unlock set to 6:00 PM, current time is 2:00 PM let voteDate = makeDateWithTime(hour: 18, minute: 0) let now = makeDateWithTime(hour: 14, minute: 0) let result = ShowBasedOnVoteLogics.passedTodaysVotingUnlock(voteDate: voteDate, now: now) XCTAssertFalse(result, "Should not have passed unlock when current time is before vote time") } func test_passedVotingUnlock_afterTime() { // Voting unlock set to 6:00 PM, current time is 8:00 PM let voteDate = makeDateWithTime(hour: 18, minute: 0) let now = makeDateWithTime(hour: 20, minute: 0) let result = ShowBasedOnVoteLogics.passedTodaysVotingUnlock(voteDate: voteDate, now: now) XCTAssertTrue(result, "Should have passed unlock when current time is after vote time") } func test_passedVotingUnlock_exactTime() { // Voting unlock set to 6:00 PM, current time is exactly 6:00 PM let voteDate = makeDateWithTime(hour: 18, minute: 0) let now = makeDateWithTime(hour: 18, minute: 0) let result = ShowBasedOnVoteLogics.passedTodaysVotingUnlock(voteDate: voteDate, now: now) XCTAssertTrue(result, "Should have passed unlock at exact vote time (uses >=)") } // MARK: - Phase 7: getCurrentVotingDate Tests func test_votingDate_today_beforeTime() { let onboarding = OnboardingData() onboarding.inputDay = .Today onboarding.date = makeDateWithTime(hour: 18, minute: 0) let now = makeDateWithTime(hour: 14, minute: 0) // before 6pm let result = ShowBasedOnVoteLogics.getCurrentVotingDate(onboardingData: onboarding, now: now) let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: now)! XCTAssertTrue(Calendar.current.isDate(result, inSameDayAs: yesterday), "Today mode, before unlock: should return yesterday") } func test_votingDate_today_afterTime() { let onboarding = OnboardingData() onboarding.inputDay = .Today onboarding.date = makeDateWithTime(hour: 18, minute: 0) let now = makeDateWithTime(hour: 20, minute: 0) // after 6pm let result = ShowBasedOnVoteLogics.getCurrentVotingDate(onboardingData: onboarding, now: now) XCTAssertTrue(Calendar.current.isDate(result, inSameDayAs: now), "Today mode, after unlock: should return today") } func test_votingDate_previous_beforeTime() { let onboarding = OnboardingData() onboarding.inputDay = .Previous onboarding.date = makeDateWithTime(hour: 18, minute: 0) let now = makeDateWithTime(hour: 14, minute: 0) // before 6pm let result = ShowBasedOnVoteLogics.getCurrentVotingDate(onboardingData: onboarding, now: now) let twoDaysAgo = Calendar.current.date(byAdding: .day, value: -2, to: now)! XCTAssertTrue(Calendar.current.isDate(result, inSameDayAs: twoDaysAgo), "Previous mode, before unlock: should return 2 days ago") } func test_votingDate_previous_afterTime() { let onboarding = OnboardingData() onboarding.inputDay = .Previous onboarding.date = makeDateWithTime(hour: 18, minute: 0) let now = makeDateWithTime(hour: 20, minute: 0) // after 6pm let result = ShowBasedOnVoteLogics.getCurrentVotingDate(onboardingData: onboarding, now: now) let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: now)! XCTAssertTrue(Calendar.current.isDate(result, inSameDayAs: yesterday), "Previous mode, after unlock: should return yesterday") } // MARK: - Phase 7: Vote Needed Tests (exercising the same logic as isMissingCurrentVote) // Note: isMissingCurrentVote uses DataController.shared (singleton) internally, // so we test the equivalent logic using a testable DataController instance. func test_voteNeeded_noEntry() { let sut = makeTestDataController() let onboarding = OnboardingData() onboarding.inputDay = .Today onboarding.date = makeDateWithTime(hour: 0, minute: 1) let votingDate = ShowBasedOnVoteLogics.getCurrentVotingDate(onboardingData: onboarding) let entry = sut.getEntry(byDate: votingDate.startOfDay) let isMissing = entry == nil || entry?.mood == .missing XCTAssertTrue(isMissing, "Should need a vote when no entry exists") } func test_voteNeeded_validEntry() { let sut = makeTestDataController() let onboarding = OnboardingData() onboarding.inputDay = .Today onboarding.date = makeDateWithTime(hour: 0, minute: 1) let votingDate = ShowBasedOnVoteLogics.getCurrentVotingDate(onboardingData: onboarding) sut.add(mood: .great, forDate: votingDate, entryType: .listView) let entry = sut.getEntry(byDate: votingDate.startOfDay) let isMissing = entry == nil || entry?.mood == .missing XCTAssertFalse(isMissing, "Should not need a vote when valid entry exists") } func test_voteNeeded_missingEntry() { let sut = makeTestDataController() let onboarding = OnboardingData() onboarding.inputDay = .Today onboarding.date = makeDateWithTime(hour: 0, minute: 1) let votingDate = ShowBasedOnVoteLogics.getCurrentVotingDate(onboardingData: onboarding) sut.add(mood: .missing, forDate: votingDate, entryType: .filledInMissing) let entry = sut.getEntry(byDate: votingDate.startOfDay) let isMissing = entry == nil || entry?.mood == .missing XCTAssertTrue(isMissing, "Should need a vote when entry is .missing") } // MARK: - Helpers private func makeTestDataController() -> DataController { let schema = Schema([MoodEntryModel.self]) let config = ModelConfiguration(schema: schema, isStoredInMemoryOnly: true) return DataController(container: try! ModelContainer(for: schema, configurations: [config])) } private func makeDateWithTime(hour: Int, minute: Int) -> Date { let calendar = Calendar.current var components = calendar.dateComponents([.year, .month, .day], from: Date()) components.hour = hour components.minute = minute components.second = 0 return calendar.date(from: components)! } }