347 lines
12 KiB
Swift
347 lines
12 KiB
Swift
import Foundation
|
|
import Testing
|
|
import SwiftData
|
|
@testable import BusinessCard
|
|
|
|
@MainActor
|
|
struct BusinessCardTests {
|
|
|
|
private func makeTestContainer() throws -> ModelContainer {
|
|
let config = ModelConfiguration(isStoredInMemoryOnly: true)
|
|
return try ModelContainer(for: BusinessCard.self, Contact.self, configurations: config)
|
|
}
|
|
|
|
@Test func vCardPayloadIncludesFields() async throws {
|
|
let container = try makeTestContainer()
|
|
let context = container.mainContext
|
|
|
|
let card = BusinessCard(
|
|
displayName: "Test User",
|
|
role: "Developer",
|
|
company: "Test Corp",
|
|
email: "test@example.com",
|
|
phone: "+1 555 123 4567",
|
|
website: "example.com",
|
|
location: "San Francisco, CA",
|
|
bio: "A passionate developer"
|
|
)
|
|
context.insert(card)
|
|
|
|
#expect(card.vCardPayload.contains("BEGIN:VCARD"))
|
|
#expect(card.vCardPayload.contains("FN:Test User"))
|
|
#expect(card.vCardPayload.contains("ORG:Test Corp"))
|
|
#expect(card.vCardPayload.contains("EMAIL;TYPE=WORK:test@example.com"))
|
|
#expect(card.vCardPayload.contains("TEL;TYPE=CELL:+1 555 123 4567"))
|
|
#expect(card.vCardPayload.contains("A passionate developer"))
|
|
#expect(card.vCardPayload.contains("END:VCARD"))
|
|
}
|
|
|
|
@Test func vCardPayloadIncludesStructuredName() async throws {
|
|
let container = try makeTestContainer()
|
|
let context = container.mainContext
|
|
|
|
let card = BusinessCard(
|
|
prefix: "Dr.",
|
|
firstName: "John",
|
|
middleName: "Michael",
|
|
lastName: "Smith",
|
|
suffix: "Jr."
|
|
)
|
|
context.insert(card)
|
|
|
|
// N: LastName;FirstName;MiddleName;Prefix;Suffix
|
|
#expect(card.vCardPayload.contains("N:Smith;John;Michael;Dr.;Jr."))
|
|
#expect(card.vCardPayload.contains("FN:Dr. John Michael Smith Jr."))
|
|
}
|
|
|
|
@Test func vCardPayloadIncludesAllContactInfo() async throws {
|
|
let container = try makeTestContainer()
|
|
let context = container.mainContext
|
|
|
|
let card = BusinessCard(
|
|
role: "CEO",
|
|
company: "Acme Inc",
|
|
prefix: "",
|
|
firstName: "Jane",
|
|
lastName: "Doe",
|
|
pronouns: "she/her",
|
|
department: "Executive",
|
|
headline: "Building the future",
|
|
bio: "Passionate leader",
|
|
accreditations: "MBA, CPA"
|
|
)
|
|
context.insert(card)
|
|
|
|
// Verify structured name
|
|
#expect(card.vCardPayload.contains("N:Doe;Jane;;;"))
|
|
#expect(card.vCardPayload.contains("FN:Jane Doe"))
|
|
|
|
// Verify org with department
|
|
#expect(card.vCardPayload.contains("ORG:Acme Inc;Executive"))
|
|
|
|
// Verify title
|
|
#expect(card.vCardPayload.contains("TITLE:CEO"))
|
|
|
|
// Verify note contains all info
|
|
#expect(card.vCardPayload.contains("Building the future"))
|
|
#expect(card.vCardPayload.contains("Passionate leader"))
|
|
#expect(card.vCardPayload.contains("Credentials: MBA\\, CPA"))
|
|
#expect(card.vCardPayload.contains("Pronouns: she/her"))
|
|
}
|
|
|
|
@Test func defaultCardSelectionUpdatesCards() async throws {
|
|
let container = try makeTestContainer()
|
|
let context = container.mainContext
|
|
|
|
// Insert cards directly instead of using samples (which might trigger other logic)
|
|
let card1 = BusinessCard(displayName: "Card One", role: "Role", company: "Company", isDefault: true)
|
|
let card2 = BusinessCard(displayName: "Card Two", role: "Role", company: "Company", isDefault: false)
|
|
context.insert(card1)
|
|
context.insert(card2)
|
|
try context.save()
|
|
|
|
let store = CardStore(modelContext: context)
|
|
|
|
#expect(store.cards.count >= 2)
|
|
|
|
store.setDefaultCard(card2)
|
|
|
|
#expect(store.selectedCardID == card2.id)
|
|
#expect(store.cards.filter { $0.isDefault }.count == 1)
|
|
#expect(store.cards.first { $0.isDefault }?.id == card2.id)
|
|
}
|
|
|
|
@Test func contactsSearchFiltersByNameOrCompany() async throws {
|
|
let container = try makeTestContainer()
|
|
let context = container.mainContext
|
|
|
|
// Insert contacts directly
|
|
let contact1 = Contact(name: "John Doe", role: "Developer", company: "Global Bank")
|
|
let contact2 = Contact(name: "Jane Smith", role: "Designer", company: "Tech Corp")
|
|
context.insert(contact1)
|
|
context.insert(contact2)
|
|
try context.save()
|
|
|
|
// Create store without triggering sample creation - just use the context
|
|
let descriptor = FetchDescriptor<Contact>()
|
|
let contacts = try context.fetch(descriptor)
|
|
|
|
// Filter manually to test the logic
|
|
let query = "Global"
|
|
let filtered = contacts.filter { $0.company.localizedStandardContains(query) }
|
|
|
|
#expect(filtered.count == 1)
|
|
#expect(filtered.first?.company == "Global Bank")
|
|
}
|
|
|
|
@Test func addCardIncreasesCardCount() async throws {
|
|
let container = try makeTestContainer()
|
|
let context = container.mainContext
|
|
|
|
let store = CardStore(modelContext: context)
|
|
let initialCount = store.cards.count
|
|
|
|
let newCard = BusinessCard(
|
|
displayName: "New User",
|
|
role: "Manager",
|
|
company: "New Corp"
|
|
)
|
|
store.addCard(newCard)
|
|
|
|
#expect(store.cards.count == initialCount + 1)
|
|
}
|
|
|
|
@Test func deleteCardRemovesFromStore() async throws {
|
|
let container = try makeTestContainer()
|
|
let context = container.mainContext
|
|
|
|
let card1 = BusinessCard(displayName: "Card One", role: "Role", company: "Company")
|
|
let card2 = BusinessCard(displayName: "Card Two", role: "Role", company: "Company")
|
|
context.insert(card1)
|
|
context.insert(card2)
|
|
try context.save()
|
|
|
|
let store = CardStore(modelContext: context)
|
|
let initialCount = store.cards.count
|
|
|
|
store.deleteCard(card2)
|
|
|
|
#expect(store.cards.count == initialCount - 1)
|
|
#expect(!store.cards.contains(where: { $0.id == card2.id }))
|
|
}
|
|
|
|
@Test func updateCardChangesProperties() async throws {
|
|
let container = try makeTestContainer()
|
|
let context = container.mainContext
|
|
|
|
let card = BusinessCard(
|
|
displayName: "Original Name",
|
|
role: "Original Role",
|
|
company: "Original Company"
|
|
)
|
|
context.insert(card)
|
|
try context.save()
|
|
|
|
let store = CardStore(modelContext: context)
|
|
|
|
card.displayName = "Updated Name"
|
|
card.role = "Updated Role"
|
|
store.updateCard(card)
|
|
|
|
let updatedCard = store.cards.first(where: { $0.id == card.id })
|
|
#expect(updatedCard?.displayName == "Updated Name")
|
|
#expect(updatedCard?.role == "Updated Role")
|
|
}
|
|
|
|
@Test func recordShareCreatesContact() async throws {
|
|
let container = try makeTestContainer()
|
|
let context = container.mainContext
|
|
|
|
// Manually insert a contact and test recordShare logic
|
|
let newContact = Contact(
|
|
name: "New Contact",
|
|
role: "CEO",
|
|
company: "Partner Inc",
|
|
cardLabel: "Work"
|
|
)
|
|
context.insert(newContact)
|
|
try context.save()
|
|
|
|
let descriptor = FetchDescriptor<Contact>()
|
|
let contacts = try context.fetch(descriptor)
|
|
|
|
#expect(contacts.count >= 1)
|
|
#expect(contacts.first(where: { $0.name == "New Contact" }) != nil)
|
|
}
|
|
|
|
@Test func recordShareUpdatesExistingContact() async throws {
|
|
let container = try makeTestContainer()
|
|
let context = container.mainContext
|
|
|
|
let existingContact = Contact(
|
|
name: "Existing Contact",
|
|
role: "Manager",
|
|
company: "Partner Inc",
|
|
cardLabel: "Personal"
|
|
)
|
|
context.insert(existingContact)
|
|
try context.save()
|
|
|
|
// Update the contact
|
|
existingContact.cardLabel = "Work"
|
|
existingContact.lastSharedDate = .now
|
|
try context.save()
|
|
|
|
let descriptor = FetchDescriptor<Contact>()
|
|
let contacts = try context.fetch(descriptor)
|
|
|
|
let updated = contacts.first(where: { $0.name == "Existing Contact" })
|
|
#expect(updated?.cardLabel == "Work")
|
|
}
|
|
|
|
@Test func themeAssignmentWorks() async throws {
|
|
let card = BusinessCard()
|
|
|
|
card.theme = .midnight
|
|
#expect(card.themeName == "Midnight")
|
|
#expect(card.theme == .midnight)
|
|
|
|
card.theme = .ocean
|
|
#expect(card.themeName == "Ocean")
|
|
}
|
|
|
|
@Test func layoutStyleAssignmentWorks() async throws {
|
|
let card = BusinessCard()
|
|
|
|
card.layoutStyle = .split
|
|
#expect(card.layoutStyleRawValue == "split")
|
|
#expect(card.layoutStyle == .split)
|
|
|
|
card.layoutStyle = .photo
|
|
#expect(card.layoutStyleRawValue == "photo")
|
|
}
|
|
|
|
// Tests for high priority features
|
|
|
|
@Test func cardSocialLinksDetection() async throws {
|
|
let card = BusinessCard(displayName: "Test")
|
|
#expect(!card.hasSocialLinks)
|
|
|
|
card.linkedIn = "linkedin.com/in/test"
|
|
#expect(card.hasSocialLinks)
|
|
}
|
|
|
|
@Test func contactNotesAndTags() async throws {
|
|
let contact = Contact(
|
|
name: "Test Contact",
|
|
notes: "Met at conference",
|
|
tags: "VIP, client, tech"
|
|
)
|
|
|
|
#expect(contact.tagList.count == 3)
|
|
#expect(contact.tagList.contains("VIP"))
|
|
#expect(contact.tagList.contains("client"))
|
|
#expect(contact.tagList.contains("tech"))
|
|
}
|
|
|
|
@Test func contactFollowUpStatus() async throws {
|
|
let contact = Contact(name: "Test")
|
|
#expect(!contact.hasFollowUp)
|
|
#expect(!contact.isFollowUpOverdue)
|
|
|
|
contact.followUpDate = .now.addingTimeInterval(86400) // Tomorrow
|
|
#expect(contact.hasFollowUp)
|
|
#expect(!contact.isFollowUpOverdue)
|
|
|
|
contact.followUpDate = .now.addingTimeInterval(-86400) // Yesterday
|
|
#expect(contact.isFollowUpOverdue)
|
|
}
|
|
|
|
@Test func contactFromVCardParsing() async throws {
|
|
let vCardData = """
|
|
BEGIN:VCARD
|
|
VERSION:3.0
|
|
FN:John Smith
|
|
ORG:Acme Corp
|
|
TITLE:CEO
|
|
EMAIL;TYPE=work:john@acme.com
|
|
TEL;TYPE=work:+1 555 123 4567
|
|
END:VCARD
|
|
"""
|
|
|
|
let contact = Contact.fromVCard(vCardData)
|
|
|
|
#expect(contact.name == "John Smith")
|
|
#expect(contact.company == "Acme Corp")
|
|
#expect(contact.role == "CEO")
|
|
#expect(contact.email == "john@acme.com")
|
|
#expect(contact.phone == "+1 555 123 4567")
|
|
#expect(contact.isReceivedCard)
|
|
#expect(contact.cardLabel == "Received")
|
|
}
|
|
|
|
@Test func addReceivedCardFromVCard() async throws {
|
|
let container = try makeTestContainer()
|
|
let context = container.mainContext
|
|
|
|
let vCardData = """
|
|
BEGIN:VCARD
|
|
VERSION:3.0
|
|
FN:Jane Doe
|
|
ORG:Test Inc
|
|
END:VCARD
|
|
"""
|
|
|
|
let contact = Contact.fromVCard(vCardData)
|
|
context.insert(contact)
|
|
try context.save()
|
|
|
|
let descriptor = FetchDescriptor<Contact>()
|
|
let contacts = try context.fetch(descriptor)
|
|
|
|
let received = contacts.first(where: { $0.name == "Jane Doe" })
|
|
#expect(received != nil)
|
|
#expect(received?.isReceivedCard == true)
|
|
}
|
|
}
|