Skip to content

Commit 6a2715c

Browse files
committed
Add CycleOne tests and ignore coverage.json
Add two new test suites (CoverageIncreaseTests and ViewBranchTests) that exercise UI hosting, CycleManager rebuild/fullSync paths, ExportService CSV generation, and CycleComparisonView cases (empty, positive/zero/negative diffs). Also update .gitignore to exclude coverage.json. These tests increase coverage and exercise background threads, Core Data entities, and CSV export behavior.
1 parent c1bcc71 commit 6a2715c

3 files changed

Lines changed: 141 additions & 0 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,6 @@ TestResults-run*
5858

5959
## Logs
6060
*.log
61+
62+
## Coverage
63+
coverage.json
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import CoreData
2+
@testable import CycleOne
3+
import SwiftUI
4+
import XCTest
5+
6+
final class CoverageIncreaseTests: XCTestCase {
7+
func testHostRunsOnBackgroundThread() {
8+
let exp = expectation(description: "host background")
9+
DispatchQueue.global().async {
10+
let view = EmptyStateView(icon: "xmark.circle", title: "No Data", message: "Please add data")
11+
host(view)
12+
exp.fulfill()
13+
}
14+
waitForExpectations(timeout: 5)
15+
}
16+
17+
func testRebuildAllCycles_withDifferentFlowValueTypes_andFullSyncBackground() throws {
18+
let context = TestPersistenceController.empty().container.viewContext
19+
let calendar = Calendar(identifier: .gregorian)
20+
let date1 = try XCTUnwrap(calendar.date(from: DateComponents(year: 2024, month: 1, day: 1))?.startOfDay)
21+
let date2 = try XCTUnwrap(calendar.date(from: DateComponents(year: 2024, month: 2, day: 1))?.startOfDay)
22+
let date3 = try XCTUnwrap(calendar.date(from: DateComponents(year: 2024, month: 3, day: 3))?.startOfDay)
23+
24+
let log1 = NSEntityDescription.insertNewObject(forEntityName: "DayLog", into: context)
25+
log1.setValue(UUID(), forKey: "id")
26+
log1.setValue(date1, forKey: "date")
27+
log1.setValue(NSNumber(value: 1), forKey: "flowLevel")
28+
29+
let log2 = NSEntityDescription.insertNewObject(forEntityName: "DayLog", into: context)
30+
log2.setValue(UUID(), forKey: "id")
31+
log2.setValue(date2, forKey: "date")
32+
log2.setValue(Int(2), forKey: "flowLevel")
33+
34+
let log3 = NSEntityDescription.insertNewObject(forEntityName: "DayLog", into: context)
35+
log3.setValue(UUID(), forKey: "id")
36+
log3.setValue(date3, forKey: "date")
37+
log3.setValue(Int16(3), forKey: "flowLevel")
38+
39+
try context.save()
40+
41+
// Should create three cycles since dates are separated
42+
CycleManager.shared.rebuildAllCycles(in: context)
43+
44+
let req: NSFetchRequest<Cycle> = Cycle.fetchRequest()
45+
let cycles = try context.fetch(req)
46+
XCTAssertEqual(cycles.count, 3)
47+
48+
// Exercise fullSync's background path
49+
let exp = expectation(description: "fullSync background")
50+
DispatchQueue.global().async {
51+
CycleManager.shared.fullSync(in: context)
52+
exp.fulfill()
53+
}
54+
waitForExpectations(timeout: 5)
55+
}
56+
57+
func testExportService_replacesCommasAndNewlinesInNotesAndJoinsSymptoms() throws {
58+
let context = TestPersistenceController.empty().container.viewContext
59+
60+
let log = DayLog(context: context)
61+
log.id = UUID()
62+
log.date = Date().startOfDay
63+
log.flowLevel = FlowLevel.light.rawValue
64+
log.notes = "Line1\nLine2, with comma"
65+
let symptom = Symptom(context: context)
66+
symptom.id = UUID().uuidString
67+
symptom.name = "Cramps"
68+
symptom.category = "Other"
69+
log.addToSymptoms(symptom)
70+
71+
try context.save()
72+
73+
let path = ExportService.shared.generateCSV(context: context)
74+
XCTAssertNotNil(path)
75+
if let path {
76+
let csv = try String(contentsOf: path)
77+
XCTAssertTrue(csv.contains("Cramps"))
78+
XCTAssertTrue(csv.contains("Line1 Line2"))
79+
}
80+
}
81+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import CoreData
2+
@testable import CycleOne
3+
import SwiftUI
4+
import XCTest
5+
6+
final class ViewBranchTests: XCTestCase {
7+
func testCycleComparisonView_showsEmptyStateWhenNotEnoughCycles() {
8+
host(CycleComparisonView(cycles: []))
9+
}
10+
11+
func testCycleComparisonView_diffPositiveAndZero() {
12+
let context = TestPersistenceController.empty().container.viewContext
13+
14+
let c1 = Cycle(context: context)
15+
c1.startDate = Date().startOfDay
16+
c1.cycleLength = 30
17+
c1.periodLength = 5
18+
19+
let c2 = Cycle(context: context)
20+
c2.startDate = Calendar.current.date(byAdding: .day, value: -30, to: Date().startOfDay)
21+
c2.cycleLength = 28
22+
c2.periodLength = 4
23+
24+
// current (30) vs previous (28) -> positive diff
25+
host(CycleComparisonView(cycles: [c1, c2]), context: context)
26+
27+
// zero diff case
28+
let c3 = Cycle(context: context)
29+
c3.startDate = Date().startOfDay
30+
c3.cycleLength = 28
31+
c3.periodLength = 5
32+
33+
let c4 = Cycle(context: context)
34+
c4.startDate = Calendar.current.date(byAdding: .day, value: -28, to: Date().startOfDay)
35+
c4.cycleLength = 28
36+
c4.periodLength = 5
37+
38+
host(CycleComparisonView(cycles: [c3, c4]), context: context)
39+
}
40+
41+
func testCycleComparisonView_diffNegative() {
42+
let context = TestPersistenceController.empty().container.viewContext
43+
44+
let c1 = Cycle(context: context)
45+
c1.startDate = Date().startOfDay
46+
c1.cycleLength = 26
47+
c1.periodLength = 4
48+
49+
let c2 = Cycle(context: context)
50+
c2.startDate = Calendar.current.date(byAdding: .day, value: -26, to: Date().startOfDay)
51+
c2.cycleLength = 30
52+
c2.periodLength = 6
53+
54+
// current (26) vs previous (30) -> negative diff
55+
host(CycleComparisonView(cycles: [c1, c2]), context: context)
56+
}
57+
}

0 commit comments

Comments
 (0)