test: fix race condition in tests

This commit is contained in:
Stefan Hausotte 2026-05-07 18:21:09 +02:00
parent 3d3de81f2b
commit ea9c9825e0
2 changed files with 122 additions and 119 deletions

View file

@ -2,51 +2,135 @@ import Foundation
import Testing
@testable import Forji
struct DiskCacheTests {
// Both nested suites touch the shared `DiskCache` directory. Running them inside a
// `.serialized` parent suite prevents parallel tests from racing on the global cache
// (e.g. one test's `removeAll()` wiping another test's freshly-written file).
@Suite(.serialized)
struct DiskCacheRootTests {
@Test func saveAndLoadRoundTrip() {
DiskCache.save(["a", "b", "c"], as: "test-roundtrip")
let items: [String]? = DiskCache.load(as: "test-roundtrip")
#expect(items == ["a", "b", "c"])
struct CoreTests {
@Test func saveAndLoadRoundTrip() {
DiskCache.save(["a", "b", "c"], as: "test-roundtrip")
let items: [String]? = DiskCache.load(as: "test-roundtrip")
#expect(items == ["a", "b", "c"])
}
@Test func loadMissingReturnsNil() {
let items: [String]? = DiskCache.load(as: "nonexistent-\(UUID().uuidString)")
#expect(items == nil)
}
@Test func overwriteExistingFile() {
DiskCache.save(["old"], as: "test-overwrite")
DiskCache.save(["new"], as: "test-overwrite")
let items: [String]? = DiskCache.load(as: "test-overwrite")
#expect(items == ["new"])
}
@Test func differentNamesAreIsolated() {
DiskCache.save([1, 2], as: "test-alpha")
DiskCache.save([3, 4], as: "test-beta")
let alpha: [Int]? = DiskCache.load(as: "test-alpha")
let beta: [Int]? = DiskCache.load(as: "test-beta")
#expect(alpha == [1, 2])
#expect(beta == [3, 4])
}
@Test func removeAllClearsEverything() {
DiskCache.save(["x"], as: "test-remove")
DiskCache.removeAll()
let items: [String]? = DiskCache.load(as: "test-remove")
#expect(items == nil)
}
@Test func emptyArrayReturnsNil() {
DiskCache.save([String](), as: "test-empty")
let items: [String]? = DiskCache.load(as: "test-empty")
#expect(items == nil)
}
@Test func typeMismatchReturnsNil() {
DiskCache.save(["text"], as: "test-mismatch")
let wrong: [Int]? = DiskCache.load(as: "test-mismatch")
#expect(wrong == nil)
}
}
@Test func loadMissingReturnsNil() {
let items: [String]? = DiskCache.load(as: "nonexistent-\(UUID().uuidString)")
#expect(items == nil)
}
struct PaginationCacheTests {
@Test func overwriteExistingFile() {
DiskCache.save(["old"], as: "test-overwrite")
DiskCache.save(["new"], as: "test-overwrite")
let items: [String]? = DiskCache.load(as: "test-overwrite")
#expect(items == ["new"])
}
init() {
DiskCache.removeAll()
}
@Test func differentNamesAreIsolated() {
DiskCache.save([1, 2], as: "test-alpha")
DiskCache.save([3, 4], as: "test-beta")
let alpha: [Int]? = DiskCache.load(as: "test-alpha")
let beta: [Int]? = DiskCache.load(as: "test-beta")
#expect(alpha == [1, 2])
#expect(beta == [3, 4])
}
@Test @MainActor func reloadAndCachePersistsItems() async {
let pagination = PaginationState<String>(pageSize: 20)
pagination.cacheName = "test-persist"
@Test func removeAllClearsEverything() {
DiskCache.save(["x"], as: "test-remove")
DiskCache.removeAll()
let items: [String]? = DiskCache.load(as: "test-remove")
#expect(items == nil)
}
await pagination.reloadAndCache { _, _ in ["a", "b", "c"] }.value
@Test func emptyArrayReturnsNil() {
DiskCache.save([String](), as: "test-empty")
let items: [String]? = DiskCache.load(as: "test-empty")
#expect(items == nil)
}
let cached: [String]? = DiskCache.load(as: "test-persist")
#expect(cached == ["a", "b", "c"])
}
@Test func typeMismatchReturnsNil() {
DiskCache.save(["text"], as: "test-mismatch")
let wrong: [Int]? = DiskCache.load(as: "test-mismatch")
#expect(wrong == nil)
@Test @MainActor func loadFromCacheRestoresItems() {
DiskCache.save(["x", "y"], as: "test-restore")
let pagination = PaginationState<String>(pageSize: 20)
pagination.cacheName = "test-restore"
pagination.loadFromCache()
#expect(pagination.items == ["x", "y"])
#expect(!pagination.hasLoaded)
}
@Test @MainActor func loadFromCacheSkipsWhenAlreadyLoaded() async {
DiskCache.save(["cached"], as: "test-skip")
let pagination = PaginationState<String>(pageSize: 20)
pagination.cacheName = "test-skip"
await pagination.reloadAndCache { _, _ in ["fresh"] }.value
#expect(pagination.hasLoaded)
pagination.loadFromCache()
#expect(pagination.items == ["fresh"])
}
@Test @MainActor func noCacheNameSkipsPersistence() async {
let pagination = PaginationState<String>(pageSize: 20)
await pagination.reloadAndCache { _, _ in ["no-name"] }.value
pagination.loadFromCache()
#expect(pagination.items == ["no-name"])
}
@Test @MainActor func loadMoreAndCacheSaves() async {
let pagination = PaginationState<String>(pageSize: 2)
pagination.cacheName = "test-loadmore"
await pagination.reloadAndCache { _, _ in ["a", "b"] }.value
#expect(pagination.hasMore)
await pagination.loadMoreAndCache { _, _ in ["c"] }
let cached: [String]? = DiskCache.load(as: "test-loadmore")
#expect(cached == ["a", "b", "c"])
}
@Test @MainActor func failedReloadDoesNotOverwriteCache() async {
let pagination = PaginationState<String>(pageSize: 20)
pagination.cacheName = "test-fail"
await pagination.reloadAndCache { _, _ in ["good"] }.value
await pagination.reloadAndCache(clearItems: true) { _, _ in
throw URLError(.badServerResponse)
}.value
let cached: [String]? = DiskCache.load(as: "test-fail")
#expect(cached == ["good"])
}
}
}

View file

@ -1,81 +0,0 @@
import Foundation
import Testing
@testable import Forji
@Suite(.serialized)
struct PaginationStateCacheTests {
init() {
DiskCache.removeAll()
}
@Test @MainActor func reloadAndCachePersistsItems() async {
let pagination = PaginationState<String>(pageSize: 20)
pagination.cacheName = "test-persist"
await pagination.reloadAndCache { _, _ in ["a", "b", "c"] }.value
let cached: [String]? = DiskCache.load(as: "test-persist")
#expect(cached == ["a", "b", "c"])
}
@Test @MainActor func loadFromCacheRestoresItems() {
DiskCache.save(["x", "y"], as: "test-restore")
let pagination = PaginationState<String>(pageSize: 20)
pagination.cacheName = "test-restore"
pagination.loadFromCache()
#expect(pagination.items == ["x", "y"])
#expect(!pagination.hasLoaded)
}
@Test @MainActor func loadFromCacheSkipsWhenAlreadyLoaded() async {
DiskCache.save(["cached"], as: "test-skip")
let pagination = PaginationState<String>(pageSize: 20)
pagination.cacheName = "test-skip"
await pagination.reloadAndCache { _, _ in ["fresh"] }.value
#expect(pagination.hasLoaded)
pagination.loadFromCache()
#expect(pagination.items == ["fresh"])
}
@Test @MainActor func noCacheNameSkipsPersistence() async {
let pagination = PaginationState<String>(pageSize: 20)
await pagination.reloadAndCache { _, _ in ["no-name"] }.value
pagination.loadFromCache()
#expect(pagination.items == ["no-name"])
}
@Test @MainActor func loadMoreAndCacheSaves() async {
let pagination = PaginationState<String>(pageSize: 2)
pagination.cacheName = "test-loadmore"
await pagination.reloadAndCache { _, _ in ["a", "b"] }.value
#expect(pagination.hasMore)
await pagination.loadMoreAndCache { _, _ in ["c"] }
let cached: [String]? = DiskCache.load(as: "test-loadmore")
#expect(cached == ["a", "b", "c"])
}
@Test @MainActor func failedReloadDoesNotOverwriteCache() async {
let pagination = PaginationState<String>(pageSize: 20)
pagination.cacheName = "test-fail"
await pagination.reloadAndCache { _, _ in ["good"] }.value
await pagination.reloadAndCache(clearItems: true) { _, _ in
throw URLError(.badServerResponse)
}.value
let cached: [String]? = DiskCache.load(as: "test-fail")
#expect(cached == ["good"])
}
}