performance updates now qwith progress on import

This commit is contained in:
Mark Gregory
2026-11-06 09:17:40 +00:00
parent 8d33198d21
commit 48d8ffe804
6 changed files with 253 additions and 13 deletions
+84
View File
@@ -2540,3 +2540,87 @@ extension KJamsCloneTests {
XCTAssertLessThan(inside.redComponent*inside.blueComponent,0.99,"Spectrum must still paint inside its bounds")
}
}
extension KJamsCloneTests {
func testImportSkipsRenamedLegacyContentAndLogsEachResultWithoutMatchingTitles() throws {
let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
defer { try? FileManager.default.removeItem(at:root) }
try FileManager.default.createDirectory(at:root,withIntermediateDirectories:true)
let fixtures = try XCTUnwrap(Bundle(for:Self.self).resourceURL?.appendingPathComponent("Fixtures"))
let original = root.appendingPathComponent("Original.mp3"),renamed = root.appendingPathComponent("Renamed.mp3"),different = root.appendingPathComponent("Different.mp3")
try FileManager.default.copyItem(at:fixtures.appendingPathComponent("Demo.mp3"),to:original)
try FileManager.default.copyItem(at:original,to:renamed)
try FileManager.default.copyItem(at:fixtures.appendingPathComponent("TestTrack.mp3"),to:different)
let db = try Library(url:root.appendingPathComponent("db.sqlite")),legacy = try db.add(title:"My saved title",audio:original.path,cdg:nil)
try db.rate(legacy,4)
var result = ImportProgress()
let importer = Importer(media:root.appendingPathComponent("Media"))
let ids = try importer.run([renamed,different],library:db,progress:{ result = $0 })
XCTAssertEqual(ids.count,2);XCTAssertEqual(try db.songs().count,2)
XCTAssertEqual(result.skipped,1);XCTAssertEqual(result.completed,2)
XCTAssertTrue(result.logLines.contains{$0.hasPrefix("[SKIPPED]") && $0.contains("Renamed.mp3")})
XCTAssertTrue(result.logLines.contains{$0.hasPrefix("[IMPORTED]") && $0.contains("Different.mp3")})
XCTAssertEqual(try db.song(legacy)?.title,"My saved title");XCTAssertEqual(try db.song(legacy)?.rating,4)
XCTAssertEqual(try db.song(legacy)?.fingerprint.count,64)
_ = try importer.run([renamed,different],library:db,progress:{ result = $0 })
XCTAssertEqual(result.skipped,2);XCTAssertEqual(result.logLines.count,2)
XCTAssertTrue(result.logLines.allSatisfy{$0.hasPrefix("[SKIPPED]")})
}
func testReimportFromAnotherFolderSkipsExistingMediaAndReturnsItsID() throws {
let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
defer { try? FileManager.default.removeItem(at:root) }
try FileManager.default.createDirectory(at:root,withIntermediateDirectories:true)
let fixture = try XCTUnwrap(Bundle(for:Self.self).resourceURL?.appendingPathComponent("Fixtures/Demo.mp3"))
let first = root.appendingPathComponent("First.mp3"),second = root.appendingPathComponent("Second.mp3")
try FileManager.default.copyItem(at:fixture,to:first);try FileManager.default.copyItem(at:fixture,to:second)
let db = try Library(url:root.appendingPathComponent("db.sqlite"))
let ids = try Importer(media:root.appendingPathComponent("MediaA")).run([first],library:db)
var report = ImportProgress()
let repeated = try Importer(media:root.appendingPathComponent("MediaB")).run([second],library:db,progress:{report = $0})
XCTAssertEqual(repeated,ids);XCTAssertEqual(try db.songs().count,1);XCTAssertEqual(report.skipped,1)
XCTAssertTrue(try FileManager.default.contentsOfDirectory(atPath:root.appendingPathComponent("MediaB").path).isEmpty)
XCTAssertTrue(report.logText.contains("0 imported, 1 skipped"));XCTAssertTrue(report.logText.contains(second.path))
}
@MainActor func testImportReportIncludesSavedTracksAndFailureAfterPartialImport() async throws {
let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
defer { try? FileManager.default.removeItem(at:root) }
try FileManager.default.createDirectory(at:root,withIntermediateDirectories:true)
let fixture = try XCTUnwrap(Bundle(for:Self.self).resourceURL?.appendingPathComponent("Fixtures/Demo.mp3"))
let good = root.appendingPathComponent("A Good.mp3"),bad = root.appendingPathComponent("Z Empty.mp3")
try FileManager.default.copyItem(at:fixture,to:good);try Data().write(to:bad)
let model = AppModel(storageURL:root.appendingPathComponent("App"))
model.importFiles([good,bad])
for _ in 0..<200 where model.isImporting { try await Task.sleep(nanoseconds:20_000_000) }
let report = try XCTUnwrap(model.importProgress)
XCTAssertTrue(report.finished);XCTAssertNotNil(report.failure);XCTAssertEqual(report.completed,1)
XCTAssertTrue(report.reportLines.contains{$0.hasPrefix("[IMPORTED]") && $0.contains("A Good.mp3")})
XCTAssertTrue(report.reportLines.contains{$0.hasPrefix("[FAILED]") && $0.contains("Z Empty.mp3")})
}
}
extension KJamsCloneTests {
@MainActor func testDJImportShowsLiveModalAndBackgroundChoiceSurvivesCompletion() async throws {
let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
defer { try? FileManager.default.removeItem(at:root) }
let input = root.appendingPathComponent("Input")
try FileManager.default.createDirectory(at:input,withIntermediateDirectories:true)
let fixture = try XCTUnwrap(Bundle(for:Self.self).resourceURL?.appendingPathComponent("Fixtures/Demo.mp3"))
for i in 0..<48 { try FileManager.default.copyItem(at:fixture,to:input.appendingPathComponent("Track \(i).mp3")) }
let system = DJSystem(storageURL:root.appendingPathComponent("DJ"))
system.importFiles([input])
XCTAssertTrue(system.importing);XCTAssertTrue(system.importLogVisible)
XCTAssertNotNil(system.importProgress)
// Main-actor controls remain available while the worker scans/copies.
system.importLogVisible = false
system.crossfader = 0.7
XCTAssertEqual(system.crossfader,0.7)
for _ in 0..<300 where system.importing { try await Task.sleep(nanoseconds:20_000_000) }
XCTAssertFalse(system.importing);XCTAssertFalse(system.importLogVisible,"Run in Background must not force the modal open again at completion")
let report = try XCTUnwrap(system.lastImportReport)
XCTAssertTrue(report.finished);XCTAssertNil(report.failure)
XCTAssertEqual(report.completed,48);XCTAssertEqual(report.skipped,47)
XCTAssertEqual(report.reportLines.count,48);XCTAssertEqual(system.songs.count,1)
}
}