- Add Apple Sign-In backend (JWKS verification, account linking, session management) - Implement push notification deep linking with NotificationDeepLinkRouter - Add jailbreak detection, runtime integrity monitoring, secure enclave service - Implement OAuth social login, token refresh, and secure logout flows - Add image caching (memory/disk), optimizer, upload queue, async semaphore - Implement notification analytics, type preferences, and category setup - Expand UI test suite with UITestBase, accessibility, auth flow, performance tests - Add CI pipeline for iOS UI tests (3 device sizes) and performance benchmarks - Restructure Xcode project to manual groups with KordantWidgets target - Add SwiftLint, Swift Collections/Algorithms/GoogleSignIn dependencies - Update project.yml for XcodeGen with new targets and configurations
230 lines
8.2 KiB
Swift
230 lines
8.2 KiB
Swift
import XCTest
|
|
@testable import Kordant
|
|
|
|
final class WidgetDataTests: XCTestCase {
|
|
// MARK: - Encoding / Decoding
|
|
|
|
func testWidgetDataEncodingDecoding() throws {
|
|
let original = WidgetData(
|
|
threatScore: 0.42,
|
|
recentAlerts: [
|
|
WidgetAlert(
|
|
id: "test-1",
|
|
title: "Test Alert",
|
|
message: "Test message",
|
|
severity: "high",
|
|
type: "breach",
|
|
createdAt: Date()
|
|
)
|
|
],
|
|
alertCount: 1,
|
|
unreadCount: 1,
|
|
criticalCount: 0,
|
|
exposureCount: 2,
|
|
lastUpdated: Date()
|
|
)
|
|
|
|
let encoded = try JSONEncoder().encode(original)
|
|
let decoded = try JSONDecoder().decode(WidgetData.self, from: encoded)
|
|
|
|
XCTAssertEqual(original, decoded)
|
|
XCTAssertEqual(decoded.threatScore, 0.42)
|
|
XCTAssertEqual(decoded.alertCount, 1)
|
|
XCTAssertEqual(decoded.unreadCount, 1)
|
|
XCTAssertEqual(decoded.criticalCount, 0)
|
|
XCTAssertEqual(decoded.exposureCount, 2)
|
|
XCTAssertEqual(decoded.recentAlerts.count, 1)
|
|
XCTAssertEqual(decoded.recentAlerts[0].id, "test-1")
|
|
XCTAssertEqual(decoded.recentAlerts[0].title, "Test Alert")
|
|
XCTAssertEqual(decoded.recentAlerts[0].severity, "high")
|
|
}
|
|
|
|
// MARK: - Threat Level
|
|
|
|
func testThreatLevelLow() {
|
|
let data = WidgetData(
|
|
threatScore: 0.15,
|
|
recentAlerts: [],
|
|
alertCount: 0,
|
|
unreadCount: 0,
|
|
criticalCount: 0,
|
|
exposureCount: 0,
|
|
lastUpdated: Date()
|
|
)
|
|
XCTAssertEqual(data.threatLevel, .low)
|
|
}
|
|
|
|
func testThreatLevelMedium() {
|
|
let data = WidgetData(
|
|
threatScore: 0.25,
|
|
recentAlerts: [],
|
|
alertCount: 0,
|
|
unreadCount: 0,
|
|
criticalCount: 0,
|
|
exposureCount: 0,
|
|
lastUpdated: Date()
|
|
)
|
|
XCTAssertEqual(data.threatLevel, .medium)
|
|
}
|
|
|
|
func testThreatLevelHigh() {
|
|
let data = WidgetData(
|
|
threatScore: 0.45,
|
|
recentAlerts: [],
|
|
alertCount: 0,
|
|
unreadCount: 0,
|
|
criticalCount: 0,
|
|
exposureCount: 0,
|
|
lastUpdated: Date()
|
|
)
|
|
XCTAssertEqual(data.threatLevel, .high)
|
|
}
|
|
|
|
func testThreatLevelCritical() {
|
|
let data = WidgetData(
|
|
threatScore: 0.72,
|
|
recentAlerts: [],
|
|
alertCount: 0,
|
|
unreadCount: 0,
|
|
criticalCount: 0,
|
|
exposureCount: 0,
|
|
lastUpdated: Date()
|
|
)
|
|
XCTAssertEqual(data.threatLevel, .critical)
|
|
}
|
|
|
|
func testThreatLevelBoundaries() {
|
|
// Exactly 0.2 is medium
|
|
let mediumLow = WidgetData(threatScore: 0.2, recentAlerts: [], alertCount: 0, unreadCount: 0, criticalCount: 0, exposureCount: 0, lastUpdated: Date())
|
|
XCTAssertEqual(mediumLow.threatLevel, .medium)
|
|
|
|
// Exactly 0.4 is high
|
|
let highLow = WidgetData(threatScore: 0.4, recentAlerts: [], alertCount: 0, unreadCount: 0, criticalCount: 0, exposureCount: 0, lastUpdated: Date())
|
|
XCTAssertEqual(highLow.threatLevel, .high)
|
|
|
|
// Exactly 0.7 is critical
|
|
let criticalLow = WidgetData(threatScore: 0.7, recentAlerts: [], alertCount: 0, unreadCount: 0, criticalCount: 0, exposureCount: 0, lastUpdated: Date())
|
|
XCTAssertEqual(criticalLow.threatLevel, .critical)
|
|
}
|
|
|
|
// MARK: - Threat Percentage
|
|
|
|
func testThreatPercentage() {
|
|
let data = WidgetData(threatScore: 0.35, recentAlerts: [], alertCount: 0, unreadCount: 0, criticalCount: 0, exposureCount: 0, lastUpdated: Date())
|
|
XCTAssertEqual(data.threatPercentage, 35)
|
|
|
|
let data2 = WidgetData(threatScore: 1.0, recentAlerts: [], alertCount: 0, unreadCount: 0, criticalCount: 0, exposureCount: 0, lastUpdated: Date())
|
|
XCTAssertEqual(data2.threatPercentage, 100)
|
|
|
|
let data3 = WidgetData(threatScore: 0.0, recentAlerts: [], alertCount: 0, unreadCount: 0, criticalCount: 0, exposureCount: 0, lastUpdated: Date())
|
|
XCTAssertEqual(data3.threatPercentage, 0)
|
|
}
|
|
|
|
// MARK: - WidgetAlert
|
|
|
|
func testWidgetAlertSeverityEnum() {
|
|
let critical = WidgetAlert(id: "1", title: "Test", message: "Msg", severity: "critical", type: "breach", createdAt: nil)
|
|
XCTAssertEqual(critical.severityEnum, .critical)
|
|
|
|
let high = WidgetAlert(id: "2", title: "Test", message: "Msg", severity: "high", type: "exposure", createdAt: nil)
|
|
XCTAssertEqual(high.severityEnum, .high)
|
|
|
|
let medium = WidgetAlert(id: "3", title: "Test", message: "Msg", severity: "medium", type: "voiceMatch", createdAt: nil)
|
|
XCTAssertEqual(medium.severityEnum, .medium)
|
|
|
|
let low = WidgetAlert(id: "4", title: "Test", message: "Msg", severity: "low", type: "removal", createdAt: nil)
|
|
XCTAssertEqual(low.severityEnum, .low)
|
|
|
|
// Unknown severity defaults to low
|
|
let unknown = WidgetAlert(id: "5", title: "Test", message: "Msg", severity: "unknown", type: "login", createdAt: nil)
|
|
XCTAssertEqual(unknown.severityEnum, .low)
|
|
}
|
|
|
|
func testWidgetAlertTypeEnum() {
|
|
let breach = WidgetAlert(id: "1", title: "Test", message: "Msg", severity: "low", type: "breach", createdAt: nil)
|
|
XCTAssertEqual(breach.typeEnum, .breach)
|
|
|
|
let exposure = WidgetAlert(id: "2", title: "Test", message: "Msg", severity: "low", type: "exposure", createdAt: nil)
|
|
XCTAssertEqual(exposure.typeEnum, .exposure)
|
|
}
|
|
|
|
func testWidgetAlertDeepLink() {
|
|
let alert = WidgetAlert(id: "abc-123", title: "Test", message: "Msg", severity: "high", type: "breach", createdAt: nil)
|
|
let url = alert.deepLink
|
|
XCTAssertEqual(url.absoluteString, "kordant://alerts/abc-123")
|
|
}
|
|
|
|
// MARK: - Placeholder & Unavailable
|
|
|
|
func testPlaceholderData() {
|
|
let placeholder = WidgetData.placeholder
|
|
XCTAssertEqual(placeholder.threatScore, 0.25)
|
|
XCTAssertEqual(placeholder.alertCount, 5)
|
|
XCTAssertEqual(placeholder.recentAlerts.count, 3)
|
|
}
|
|
|
|
func testUnavailableData() {
|
|
let unavailable = WidgetData.unavailable
|
|
XCTAssertEqual(unavailable.threatScore, 0)
|
|
XCTAssertEqual(unavailable.alertCount, 0)
|
|
XCTAssertEqual(unavailable.recentAlerts.count, 0)
|
|
}
|
|
|
|
func testPlaceholderAlerts() {
|
|
let alerts = WidgetAlert.placeholders
|
|
XCTAssertEqual(alerts.count, 3)
|
|
XCTAssertEqual(alerts[0].title, "Data Breach Detected")
|
|
XCTAssertEqual(alerts[0].severity, "critical")
|
|
XCTAssertEqual(alerts[1].severity, "high")
|
|
XCTAssertEqual(alerts[2].severity, "medium")
|
|
}
|
|
|
|
// MARK: - Severity Filter
|
|
|
|
func testSeverityFilterAll() {
|
|
let filter = AlertSeverityFilter.all
|
|
XCTAssertTrue(filter.matches(severity: "low"))
|
|
XCTAssertTrue(filter.matches(severity: "medium"))
|
|
XCTAssertTrue(filter.matches(severity: "high"))
|
|
XCTAssertTrue(filter.matches(severity: "critical"))
|
|
}
|
|
|
|
func testSeverityFilterCritical() {
|
|
let filter = AlertSeverityFilter.critical
|
|
XCTAssertFalse(filter.matches(severity: "low"))
|
|
XCTAssertFalse(filter.matches(severity: "medium"))
|
|
XCTAssertFalse(filter.matches(severity: "high"))
|
|
XCTAssertTrue(filter.matches(severity: "critical"))
|
|
}
|
|
|
|
func testSeverityFilterHigh() {
|
|
let filter = AlertSeverityFilter.high
|
|
XCTAssertFalse(filter.matches(severity: "low"))
|
|
XCTAssertFalse(filter.matches(severity: "medium"))
|
|
XCTAssertTrue(filter.matches(severity: "high"))
|
|
XCTAssertTrue(filter.matches(severity: "critical"))
|
|
}
|
|
|
|
// MARK: - Data Manager (integration)
|
|
|
|
func testWidgetDataManagerSaveAndLoad() {
|
|
let manager = WidgetDataManager.shared
|
|
let original = WidgetData.placeholder
|
|
|
|
// Clear any existing data
|
|
manager.clear()
|
|
XCTAssertNil(manager.load())
|
|
|
|
// Save and reload
|
|
manager.save(original)
|
|
let loaded = manager.load()
|
|
XCTAssertNotNil(loaded)
|
|
XCTAssertEqual(loaded, original)
|
|
XCTAssertEqual(loaded?.threatScore, 0.25)
|
|
|
|
// Clean up
|
|
manager.clear()
|
|
XCTAssertNil(manager.load())
|
|
}
|
|
}
|