| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- //
- // SavedJobsPersistenceTests.swift
- // indeed_ai_job_searchTests
- //
- import XCTest
- @testable import indeed_ai_job_search
- @MainActor
- final class SwiftDataSavedJobsStoreTests: XCTestCase {
- private var controller: PersistenceController!
- private var store: SwiftDataSavedJobsStore!
- override func setUp() {
- super.setUp()
- controller = PersistenceController.makeInMemory()
- store = SwiftDataSavedJobsStore(controller: controller)
- }
- override func tearDown() {
- store = nil
- controller = nil
- super.tearDown()
- }
- func testSaveUnsaveSurvivesReload() {
- let listing = makeListing(key: "abc123def4567890", title: "iOS Developer")
- store.toggleSave(listing)
- XCTAssertTrue(store.isSaved(listing))
- XCTAssertEqual(store.savedJobs.count, 1)
- let reloaded = SwiftDataSavedJobsStore(controller: controller)
- XCTAssertTrue(reloaded.isSaved(listing))
- XCTAssertEqual(reloaded.savedJobs.first?.listing.title, "iOS Developer")
- reloaded.toggleSave(listing)
- XCTAssertFalse(reloaded.isSaved(listing))
- XCTAssertTrue(reloaded.savedJobs.isEmpty)
- }
- func testDedupeOnSaveKeepsSingleRow() {
- let first = makeListing(key: "samekey000000001", title: "Old Title")
- var second = makeListing(key: "samekey000000001", title: "New Title")
- second.company = "Acme"
- store.toggleSave(first)
- let savedAt = store.savedJobs.first?.savedAt
- store.save(second)
- XCTAssertEqual(store.savedJobs.count, 1)
- XCTAssertEqual(store.savedJobs.first?.listing.title, "New Title")
- XCTAssertEqual(store.savedJobs.first?.listing.company, "Acme")
- XCTAssertEqual(store.savedJobs.first?.savedAt, savedAt)
- }
- func testUpdateListingPersistsAvailability() {
- var listing = makeListing(key: "verifykey0000001", title: "Swift Engineer")
- store.toggleSave(listing)
- listing.availability = .unavailable
- let verifiedAt = Date(timeIntervalSince1970: 1_700_000_000)
- store.updateListing(listing, lastVerifiedAt: verifiedAt)
- XCTAssertEqual(store.savedJobs.first?.availability, .unavailable)
- XCTAssertEqual(store.savedJobs.first?.lastVerifiedAt, verifiedAt)
- XCTAssertFalse(store.savedJobs.isEmpty)
- }
- func testClearAllRemovesPersistedJobs() {
- store.toggleSave(makeListing(key: "clear00000000001", title: "A"))
- store.toggleSave(makeListing(key: "clear00000000002", title: "B"))
- XCTAssertEqual(store.savedJobs.count, 2)
- store.clearAll()
- XCTAssertTrue(store.savedJobs.isEmpty)
- let reloaded = SwiftDataSavedJobsStore(controller: controller)
- XCTAssertTrue(reloaded.savedJobs.isEmpty)
- }
- func testExportJSONContainsKeys() throws {
- store.toggleSave(makeListing(key: "exportkey0000001", title: "Export Me"))
- let data = try store.exportJSON()
- let text = String(data: data, encoding: .utf8) ?? ""
- XCTAssertTrue(text.contains("exportkey0000001"))
- XCTAssertTrue(text.contains("Export Me"))
- }
- }
- @MainActor
- final class SavedJobsRevalidatorTests: XCTestCase {
- func testRevalidatesOnlyStaleJobs() async {
- let store = MockSavedJobsStore()
- var fresh = makeListing(key: "fresh00000000001", title: "Fresh")
- fresh.availability = .open
- var stale = makeListing(key: "stale00000000001", title: "Stale")
- stale.availability = .open
- store.toggleSave(fresh)
- store.toggleSave(stale)
- store.updateListing(fresh, lastVerifiedAt: Date())
- store.updateListing(stale, lastVerifiedAt: Date().addingTimeInterval(-86_400 * 2))
- let validation = StubValidationService(result: .unavailable)
- let revalidator = SavedJobsRevalidator(
- store: store,
- validationService: validation,
- staleInterval: 86_400
- )
- let checked = await revalidator.runPass()
- XCTAssertEqual(checked, 1)
- XCTAssertEqual(
- store.savedJobs.first(where: { $0.listing.indeedJobKey == "stale00000000001" })?.availability,
- .unavailable
- )
- XCTAssertEqual(
- store.savedJobs.first(where: { $0.listing.indeedJobKey == "fresh00000000001" })?.availability,
- .open
- )
- }
- func testNeverVerifiedJobsAreChecked() async {
- let store = MockSavedJobsStore()
- store.toggleSave(makeListing(key: "never00000000001", title: "Never"))
- let validation = StubValidationService(result: .unknown)
- let revalidator = SavedJobsRevalidator(
- store: store,
- validationService: validation,
- staleInterval: 86_400
- )
- let checked = await revalidator.runPass()
- XCTAssertEqual(checked, 1)
- XCTAssertNotNil(store.savedJobs.first?.lastVerifiedAt)
- XCTAssertEqual(store.savedJobs.first?.availability, .unknown)
- }
- }
- private struct StubValidationService: JobValidationService {
- let result: JobAvailability
- func validate(listing: JobListing) async -> JobAvailability {
- result
- }
- }
- private func makeListing(
- key: String,
- title: String,
- company: String = "Test Co",
- postedAt: Date = Date()
- ) -> JobListing {
- JobListing(
- indeedJobKey: key,
- title: title,
- company: company,
- location: "Remote",
- remoteType: .remote,
- postedAt: postedAt,
- snippet: "Test snippet",
- indeedURL: URL(string: "https://www.indeed.com/viewjob?jk=\(key)")!
- )
- }
|