Handle duplicate Java collection snapshots
This commit is contained in:
parent
9ec6b905bc
commit
f5dfec00a3
@ -152,7 +152,7 @@ nonisolated struct CollectionSnapshot: Identifiable, Hashable, Sendable, Codable
|
|||||||
let childDirectoryCount: Int
|
let childDirectoryCount: Int
|
||||||
let fingerprint: String
|
let fingerprint: String
|
||||||
|
|
||||||
var id: String { folderName }
|
var id: String { "\(folderName)::\(fingerprint)" }
|
||||||
}
|
}
|
||||||
|
|
||||||
nonisolated struct SourceSnapshot: Hashable, Sendable, Codable {
|
nonisolated struct SourceSnapshot: Hashable, Sendable, Codable {
|
||||||
|
|||||||
@ -214,20 +214,18 @@ enum SourceRestoration {
|
|||||||
_ currentCollections: [CollectionSnapshot],
|
_ currentCollections: [CollectionSnapshot],
|
||||||
persistedCollections: [CollectionSnapshot]
|
persistedCollections: [CollectionSnapshot]
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
let currentCollectionsByName = Dictionary(
|
let currentCollectionsByName = Dictionary(grouping: currentCollections, by: \.folderName)
|
||||||
uniqueKeysWithValues: currentCollections.map { ($0.folderName, $0) }
|
.mapValues { $0.map(\.fingerprint).sorted() }
|
||||||
)
|
let persistedCollectionsByName = Dictionary(grouping: persistedCollections, by: \.folderName)
|
||||||
let persistedCollectionsByName = Dictionary(
|
.mapValues { $0.map(\.fingerprint).sorted() }
|
||||||
uniqueKeysWithValues: persistedCollections.map { ($0.folderName, $0) }
|
|
||||||
)
|
|
||||||
|
|
||||||
if currentCollectionsByName.count != persistedCollectionsByName.count {
|
if currentCollectionsByName.count != persistedCollectionsByName.count {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
for (folderName, persistedCollection) in persistedCollectionsByName {
|
for (folderName, persistedFingerprints) in persistedCollectionsByName {
|
||||||
guard let currentCollection = currentCollectionsByName[folderName],
|
guard let currentFingerprints = currentCollectionsByName[folderName],
|
||||||
currentCollection.fingerprint == persistedCollection.fingerprint else {
|
currentFingerprints == persistedFingerprints else {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -443,6 +443,60 @@ struct World_Manager_for_MinecraftTests {
|
|||||||
#expect(snapshots.map(\.folderName).contains("a/e/f/resourcepacks"))
|
#expect(snapshots.map(\.folderName).contains("a/e/f/resourcepacks"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test func sourceRestorationComparesDuplicateCollectionNamesWithoutCrashing() async throws {
|
||||||
|
let fileManager = FileManager.default
|
||||||
|
let workingURL = fileManager.temporaryDirectory.appendingPathComponent(UUID().uuidString, isDirectory: true)
|
||||||
|
defer { try? fileManager.removeItem(at: workingURL) }
|
||||||
|
try fileManager.createDirectory(at: workingURL, withIntermediateDirectories: true)
|
||||||
|
|
||||||
|
let collectionSnapshots = [
|
||||||
|
CollectionSnapshot(
|
||||||
|
folderName: "mods",
|
||||||
|
modifiedDate: Date(timeIntervalSince1970: 100),
|
||||||
|
childDirectoryCount: 1,
|
||||||
|
fingerprint: "a/b/c/mods::1::100"
|
||||||
|
),
|
||||||
|
CollectionSnapshot(
|
||||||
|
folderName: "mods",
|
||||||
|
modifiedDate: Date(timeIntervalSince1970: 200),
|
||||||
|
childDirectoryCount: 2,
|
||||||
|
fingerprint: "x/y/z/mods::2::200"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
var source = MinecraftSource(
|
||||||
|
folderURL: workingURL,
|
||||||
|
origin: .javaLocalFolder(bookmarkData: nil),
|
||||||
|
accessDescriptor: SourceAccessDescriptor(
|
||||||
|
accessorIdentifier: JavaLocalFolderSourceAccess().accessorIdentifier,
|
||||||
|
kind: .localFolder,
|
||||||
|
refreshStrategy: .eagerFullScan
|
||||||
|
),
|
||||||
|
availability: .available
|
||||||
|
)
|
||||||
|
source.edition = .java
|
||||||
|
source.snapshot = SourceSnapshot(
|
||||||
|
sourceID: workingURL,
|
||||||
|
rootModifiedDate: nil,
|
||||||
|
collectionSnapshots: collectionSnapshots,
|
||||||
|
itemSnapshots: []
|
||||||
|
)
|
||||||
|
|
||||||
|
#expect(SourceRestoration.needsReconcile(source) { _, _ in collectionSnapshots } == false)
|
||||||
|
#expect(
|
||||||
|
SourceRestoration.needsReconcile(source) { _, _ in
|
||||||
|
[
|
||||||
|
collectionSnapshots[0],
|
||||||
|
CollectionSnapshot(
|
||||||
|
folderName: "mods",
|
||||||
|
modifiedDate: Date(timeIntervalSince1970: 300),
|
||||||
|
childDirectoryCount: 3,
|
||||||
|
fingerprint: "x/y/z/mods::3::300"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
} == true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Test func sourceLibraryAddSourceCandidatePreservesJavaAggregateProvider() async throws {
|
@Test func sourceLibraryAddSourceCandidatePreservesJavaAggregateProvider() async throws {
|
||||||
let fileManager = FileManager.default
|
let fileManager = FileManager.default
|
||||||
let workingURL = fileManager.temporaryDirectory.appendingPathComponent(UUID().uuidString, isDirectory: true)
|
let workingURL = fileManager.temporaryDirectory.appendingPathComponent(UUID().uuidString, isDirectory: true)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user