Skip to content

Commit 7a11780

Browse files
Added tests for validating multiple persistences don't overwrite each other
1 parent 4b34d8d commit 7a11780

File tree

1 file changed

+108
-0
lines changed

1 file changed

+108
-0
lines changed
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
//
2+
// MultiplePersistenceTests.swift
3+
// CodableDatastore
4+
//
5+
// Created by Dimitri Bouniol on 2025-12-26.
6+
// Copyright © 2023-25 Mochi Development, Inc. All rights reserved.
7+
//
8+
9+
#if !canImport(Darwin)
10+
@preconcurrency import Foundation
11+
#endif
12+
import XCTest
13+
@testable import CodableDatastore
14+
15+
final class MultiplePersistenceTests: XCTestCase, @unchecked Sendable {
16+
var temporaryStoreURLOuter: URL = FileManager.default.temporaryDirectory
17+
var temporaryStoreURLInner: URL = FileManager.default.temporaryDirectory
18+
19+
override func setUp() async throws {
20+
temporaryStoreURLOuter = FileManager.default.temporaryDirectory.appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString + "-Outer", isDirectory: true);
21+
temporaryStoreURLInner = FileManager.default.temporaryDirectory.appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString + "-Inner", isDirectory: true);
22+
}
23+
24+
override func tearDown() async throws {
25+
try? FileManager.default.removeItem(at: temporaryStoreURLOuter)
26+
try? FileManager.default.removeItem(at: temporaryStoreURLInner)
27+
}
28+
29+
func testCanWorkWithMultiplePersistences() async throws {
30+
let outerPersistence = try DiskPersistence(readWriteURL: temporaryStoreURLOuter)
31+
let innerPersistence = try DiskPersistence(readWriteURL: temporaryStoreURLInner)
32+
33+
struct TestFormat: DatastoreFormat {
34+
enum Version: Int, CaseIterable {
35+
case zero
36+
}
37+
38+
struct Instance: Codable, Identifiable {
39+
var id: String
40+
var value: String
41+
}
42+
43+
static let defaultKey: DatastoreKey = "test"
44+
static let currentVersion = Version.zero
45+
}
46+
47+
let outerDatastore = Datastore.JSONStore(
48+
persistence: outerPersistence,
49+
format: TestFormat.self,
50+
migrations: [
51+
.zero: { data, decoder in
52+
try decoder.decode(TestFormat.Instance.self, from: data)
53+
}
54+
]
55+
)
56+
57+
let innerDatastore = Datastore.JSONStore(
58+
persistence: innerPersistence,
59+
format: TestFormat.self,
60+
migrations: [
61+
.zero: { data, decoder in
62+
try decoder.decode(TestFormat.Instance.self, from: data)
63+
}
64+
]
65+
)
66+
67+
/// Set some default starting values
68+
try await outerDatastore.persist(.init(id: "A", value: "OuterA"))
69+
try await outerDatastore.persist(.init(id: "B", value: "OuterB"))
70+
try await innerDatastore.persist(.init(id: "A", value: "InnerA"))
71+
try await innerDatastore.persist(.init(id: "B", value: "InnerB"))
72+
73+
/// Start a transaction in the outer persistence, and modify a record.
74+
try await outerPersistence.perform {
75+
try await outerDatastore.persist(.init(id: "A", value: "OuterA-New"))
76+
try await innerPersistence.perform(options: .readOnly) {
77+
/// Access the inner persistence within a read-only transaction.
78+
let innerValueA = try await innerDatastore.load(id: "A")
79+
XCTAssertEqual(innerValueA?.value, "InnerA")
80+
81+
try await Task.detached {
82+
/// Attempt to modify the inner persistence in a detached task, which should succeed without issue.
83+
try await innerDatastore.persist(.init(id: "B", value: "InnerB-New"))
84+
let innerValueB = try await innerDatastore.load(id: "B")
85+
XCTAssertEqual(innerValueB?.value, "InnerB-New")
86+
}.value
87+
88+
/// Check for the old value since we are locked to a transaction where reads already started.
89+
let innerValueB = try await innerDatastore.load(id: "B")
90+
XCTAssertEqual(innerValueB?.value, "InnerB")
91+
}
92+
93+
/// Check to see that the inner persistence value is unchanged.
94+
let innerValue = try await innerDatastore.load(id: "A")
95+
XCTAssertEqual(innerValue?.value, "InnerA")
96+
}
97+
98+
/// Make sure final values all agree.
99+
let outerValueA = try await outerDatastore.load(id: "A")
100+
let outerValueB = try await outerDatastore.load(id: "B")
101+
let innerValueA = try await innerDatastore.load(id: "A")
102+
let innerValueB = try await innerDatastore.load(id: "B")
103+
XCTAssertEqual(outerValueA?.value, "OuterA-New")
104+
XCTAssertEqual(outerValueB?.value, "OuterB")
105+
XCTAssertEqual(innerValueA?.value, "InnerA")
106+
XCTAssertEqual(innerValueB?.value, "InnerB-New")
107+
}
108+
}

0 commit comments

Comments
 (0)