Files
Reflect/ReflectTests/VoteLogicsTests.swift
Trey t 0442eab1f8 Rebrand entire project from Feels to Reflect
Complete rename across all bundle IDs, App Groups, CloudKit containers,
StoreKit product IDs, data store filenames, URL schemes, logger subsystems,
Swift identifiers, user-facing strings (7 languages), file names, directory
names, Xcode project, schemes, assets, and documentation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 11:47:16 -06:00

158 lines
6.5 KiB
Swift

//
// 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)!
}
}