native macOS codings agent orchestrator
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

Keep repository icon tests out of production config

onevcat 0bf6122b 3d19de23

+67 -48
+11 -7
supacode/Clients/Repositories/RepositoryIconAssetStore.swift
··· 41 41 42 42 nonisolated extension RepositoryIconAssetStore { 43 43 static var liveValue: RepositoryIconAssetStore { 44 + fileSystemValue(repositoryIconsDirectory: SupacodePaths.repositoryIconsDirectory(for:)) 45 + } 46 + 47 + static func fileSystemValue( 48 + repositoryIconsDirectory: @escaping @Sendable (_ repositoryRootURL: URL) -> URL 49 + ) -> RepositoryIconAssetStore { 44 50 RepositoryIconAssetStore( 45 51 importImage: { sourceURL, rootURL in 46 52 // No extension whitelist — the file picker filters down to ··· 54 60 sourceURL.pathExtension.lowercased().isEmpty 55 61 ? "img" 56 62 : sourceURL.pathExtension.lowercased() 57 - let directory = SupacodePaths.repositoryIconsDirectory(for: rootURL) 63 + let directory = repositoryIconsDirectory(rootURL) 58 64 try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true) 59 65 let filename = "\(UUID().uuidString.lowercased()).\(normalizedExt)" 60 66 let destination = directory.appending(path: filename, directoryHint: .notDirectory) ··· 63 69 return filename 64 70 }, 65 71 remove: { filename, rootURL in 66 - let url = SupacodePaths.repositoryIconFileURL( 67 - filename: filename, repositoryRootURL: rootURL 68 - ) 72 + let url = repositoryIconsDirectory(rootURL) 73 + .appending(path: filename, directoryHint: .notDirectory) 69 74 if FileManager.default.fileExists(atPath: url.path(percentEncoded: false)) { 70 75 try FileManager.default.removeItem(at: url) 71 76 } 72 77 }, 73 78 exists: { filename, rootURL in 74 - let url = SupacodePaths.repositoryIconFileURL( 75 - filename: filename, repositoryRootURL: rootURL 76 - ) 79 + let url = repositoryIconsDirectory(rootURL) 80 + .appending(path: filename, directoryHint: .notDirectory) 77 81 return FileManager.default.fileExists(atPath: url.path(percentEncoded: false)) 78 82 } 79 83 )
+56 -41
supacodeTests/RepositoryIconAssetStoreTests.swift
··· 24 24 struct RepositoryIconAssetStoreTests { 25 25 // MARK: - Helpers 26 26 27 + private struct StoreFixture { 28 + let store: RepositoryIconAssetStore 29 + let repoRoot: ScratchDirectory 30 + let iconStoreRoot: ScratchDirectory 31 + 32 + func iconsDirectory() -> URL { 33 + iconStoreRoot.url 34 + .appending(path: repoRoot.url.lastPathComponent, directoryHint: .isDirectory) 35 + .appending(path: "icons", directoryHint: .isDirectory) 36 + } 37 + } 38 + 27 39 private func makeRepoRootScratch() -> ScratchDirectory { 28 40 ScratchDirectory(prefix: "prowl-icon-store") 29 41 } 30 42 43 + private func makeStoreFixture() -> StoreFixture { 44 + let repoRoot = makeRepoRootScratch() 45 + let iconStoreRoot = ScratchDirectory(prefix: "prowl-icon-store-home") 46 + let store = RepositoryIconAssetStore.fileSystemValue { rootURL in 47 + iconStoreRoot.url 48 + .appending(path: rootURL.lastPathComponent, directoryHint: .isDirectory) 49 + .appending(path: "icons", directoryHint: .isDirectory) 50 + } 51 + return StoreFixture(store: store, repoRoot: repoRoot, iconStoreRoot: iconStoreRoot) 52 + } 53 + 31 54 private func writeSourceFile( 32 55 in scratch: ScratchDirectory, 33 56 extension ext: String, ··· 41 64 // MARK: - importImage 42 65 43 66 @Test func importImageCopiesFileWithUUIDName() throws { 44 - let store = RepositoryIconAssetStore.liveValue 45 - let repoRoot = makeRepoRootScratch() 67 + let fixture = makeStoreFixture() 46 68 let source = ScratchDirectory(prefix: "prowl-icon-source") 47 69 let sourceFile = try writeSourceFile( 48 70 in: source, extension: "png", contents: Data([0x01, 0x02, 0x03]) 49 71 ) 50 72 51 - let filename = try store.importImage(sourceFile, repoRoot.url) 73 + let filename = try fixture.store.importImage(sourceFile, fixture.repoRoot.url) 52 74 53 75 #expect(filename.hasSuffix(".png")) 54 76 #expect(UUID(uuidString: String(filename.dropLast(4))) != nil) 55 77 56 - let resolved = SupacodePaths.repositoryIconFileURL( 57 - filename: filename, repositoryRootURL: repoRoot.url 58 - ) 78 + let resolved = fixture.iconsDirectory().appending(path: filename, directoryHint: .notDirectory) 59 79 let copied = try Data(contentsOf: resolved) 60 80 #expect(copied == Data([0x01, 0x02, 0x03])) 81 + 82 + let productionURL = SupacodePaths.repositoryIconFileURL( 83 + filename: filename, repositoryRootURL: fixture.repoRoot.url 84 + ) 85 + #expect(!FileManager.default.fileExists(atPath: productionURL.path(percentEncoded: false))) 61 86 } 62 87 63 88 @Test func importImageNormalizesUppercaseExtension() throws { 64 - let store = RepositoryIconAssetStore.liveValue 65 - let repoRoot = makeRepoRootScratch() 89 + let fixture = makeStoreFixture() 66 90 let source = ScratchDirectory(prefix: "prowl-icon-source") 67 91 let sourceFile = try writeSourceFile(in: source, extension: "PNG") 68 92 69 - let filename = try store.importImage(sourceFile, repoRoot.url) 93 + let filename = try fixture.store.importImage(sourceFile, fixture.repoRoot.url) 70 94 #expect(filename.hasSuffix(".png")) 71 95 } 72 96 73 97 @Test func importImageAcceptsSVG() throws { 74 - let store = RepositoryIconAssetStore.liveValue 75 - let repoRoot = makeRepoRootScratch() 98 + let fixture = makeStoreFixture() 76 99 let source = ScratchDirectory(prefix: "prowl-icon-source") 77 100 let sourceFile = try writeSourceFile(in: source, extension: "svg") 78 101 79 - let filename = try store.importImage(sourceFile, repoRoot.url) 102 + let filename = try fixture.store.importImage(sourceFile, fixture.repoRoot.url) 80 103 #expect(filename.hasSuffix(".svg")) 81 104 } 82 105 ··· 87 110 // render time. JPG / WebP / HEIC / GIF / TIFF / etc. all flow 88 111 // through the same byte-copy path and round-trip through 89 112 // `repositoryIconFileURL` like PNG does. 90 - let store = RepositoryIconAssetStore.liveValue 91 - let repoRoot = makeRepoRootScratch() 113 + let fixture = makeStoreFixture() 92 114 93 115 for ext in ["jpg", "jpeg", "webp", "heic", "gif", "tiff", "bmp"] { 94 116 let source = ScratchDirectory(prefix: "prowl-icon-source") 95 117 let sourceFile = try writeSourceFile(in: source, extension: ext) 96 - let filename = try store.importImage(sourceFile, repoRoot.url) 118 + let filename = try fixture.store.importImage(sourceFile, fixture.repoRoot.url) 97 119 #expect(filename.hasSuffix(".\(ext)")) 98 120 } 99 121 } ··· 102 124 // Defensive: a dragged-in file without an extension shouldn't 103 125 // crash the importer. The destination filename gets a generic 104 126 // fallback so the round-trip still works. 105 - let store = RepositoryIconAssetStore.liveValue 106 - let repoRoot = makeRepoRootScratch() 127 + let fixture = makeStoreFixture() 107 128 let source = ScratchDirectory(prefix: "prowl-icon-source") 108 129 let sourceFile = source.url.appending(path: "icon", directoryHint: .notDirectory) 109 130 try Data([0xDE, 0xAD]).write(to: sourceFile) 110 131 111 - let filename = try store.importImage(sourceFile, repoRoot.url) 132 + let filename = try fixture.store.importImage(sourceFile, fixture.repoRoot.url) 112 133 #expect(!filename.isEmpty) 113 134 } 114 135 115 136 @Test func importImageCreatesIconsDirectoryWhenMissing() throws { 116 - let store = RepositoryIconAssetStore.liveValue 117 - let repoRoot = makeRepoRootScratch() 137 + let fixture = makeStoreFixture() 118 138 // Don't pre-create the icons directory — importImage should make 119 139 // it itself, otherwise first-time imports would fail. 120 140 let source = ScratchDirectory(prefix: "prowl-icon-source") 121 141 let sourceFile = try writeSourceFile(in: source, extension: "png") 122 142 123 - _ = try store.importImage(sourceFile, repoRoot.url) 143 + _ = try fixture.store.importImage(sourceFile, fixture.repoRoot.url) 124 144 125 - let iconsDir = SupacodePaths.repositoryIconsDirectory(for: repoRoot.url) 145 + let iconsDir = fixture.iconsDirectory() 126 146 var isDirectory: ObjCBool = false 127 147 let exists = FileManager.default.fileExists( 128 148 atPath: iconsDir.path(percentEncoded: false), isDirectory: &isDirectory ··· 132 152 } 133 153 134 154 @Test func importImageGeneratesUniqueFilenamePerCall() throws { 135 - let store = RepositoryIconAssetStore.liveValue 136 - let repoRoot = makeRepoRootScratch() 155 + let fixture = makeStoreFixture() 137 156 let source = ScratchDirectory(prefix: "prowl-icon-source") 138 157 let sourceFile = try writeSourceFile(in: source, extension: "png") 139 158 140 - let first = try store.importImage(sourceFile, repoRoot.url) 141 - let second = try store.importImage(sourceFile, repoRoot.url) 159 + let first = try fixture.store.importImage(sourceFile, fixture.repoRoot.url) 160 + let second = try fixture.store.importImage(sourceFile, fixture.repoRoot.url) 142 161 #expect(first != second) 143 162 } 144 163 145 164 // MARK: - exists 146 165 147 166 @Test func existsReportsFalseWhenMissing() { 148 - let store = RepositoryIconAssetStore.liveValue 149 - let repoRoot = makeRepoRootScratch() 150 - #expect(!store.exists("nonexistent.png", repoRoot.url)) 167 + let fixture = makeStoreFixture() 168 + #expect(!fixture.store.exists("nonexistent.png", fixture.repoRoot.url)) 151 169 } 152 170 153 171 @Test func existsReportsTrueAfterImport() throws { 154 - let store = RepositoryIconAssetStore.liveValue 155 - let repoRoot = makeRepoRootScratch() 172 + let fixture = makeStoreFixture() 156 173 let source = ScratchDirectory(prefix: "prowl-icon-source") 157 174 let sourceFile = try writeSourceFile(in: source, extension: "png") 158 - let filename = try store.importImage(sourceFile, repoRoot.url) 159 - #expect(store.exists(filename, repoRoot.url)) 175 + let filename = try fixture.store.importImage(sourceFile, fixture.repoRoot.url) 176 + #expect(fixture.store.exists(filename, fixture.repoRoot.url)) 160 177 } 161 178 162 179 // MARK: - remove 163 180 164 181 @Test func removeDeletesImportedFile() throws { 165 - let store = RepositoryIconAssetStore.liveValue 166 - let repoRoot = makeRepoRootScratch() 182 + let fixture = makeStoreFixture() 167 183 let source = ScratchDirectory(prefix: "prowl-icon-source") 168 184 let sourceFile = try writeSourceFile(in: source, extension: "png") 169 - let filename = try store.importImage(sourceFile, repoRoot.url) 185 + let filename = try fixture.store.importImage(sourceFile, fixture.repoRoot.url) 170 186 171 - try store.remove(filename, repoRoot.url) 172 - #expect(!store.exists(filename, repoRoot.url)) 187 + try fixture.store.remove(filename, fixture.repoRoot.url) 188 + #expect(!fixture.store.exists(filename, fixture.repoRoot.url)) 173 189 } 174 190 175 191 @Test func removeIsIdempotent() throws { 176 192 // Reset / replace flows can call remove repeatedly; missing files 177 193 // shouldn't throw or the reducer would have to track existence. 178 - let store = RepositoryIconAssetStore.liveValue 179 - let repoRoot = makeRepoRootScratch() 180 - try store.remove("never-existed.png", repoRoot.url) 194 + let fixture = makeStoreFixture() 195 + try fixture.store.remove("never-existed.png", fixture.repoRoot.url) 181 196 } 182 197 }