// // TankCatalogTests.swift // GasTankARTests // // Created by Dennis Nemec on 14.09.26. // import Testing import Foundation @testable import GasTankAR /// Prüft das Laden/Decodieren des Tank-Katalogs aus JSON sowie die abgeleiteten /// Abfragen (verfügbare Größen/Farben, Auflösung & Normalisierung der Auswahl). struct TankCatalogTests { // Kleiner, in sich konsistenter Beispielkatalog für Query-Tests. private static let sampleJSON = """ { "sizeDisplayNames": { "t1_2": "1,2 t", "t2_9": "2,9 t" }, "colorDisplayNames": { "white": "Weiß", "green": "Hellgrün", "olive": "Olivgrün" }, "tanks": [ { "size": "t1_2", "color": "white", "placement": "aboveGround", "modelPath": "DG-2700_wh.usdz" }, { "size": "t1_2", "color": "green", "placement": "aboveGround", "modelPath": "DG-2700_mi.usdz" }, { "size": "t1_2", "color": "olive", "placement": "belowGround", "modelPath": "DG-2700_ol.usdz" }, { "size": "t2_9", "color": "white", "placement": "aboveGround", "modelPath": "DG-6400_wh.usdz" }, { "size": "t2_9", "color": "olive", "placement": "belowGround", "modelPath": "DG-6400_ol.usdz" } ] } """ private static func sampleCatalog() throws -> TankCatalog { let loader = DataTankCatalogLoader(data: Data(sampleJSON.utf8)) return TankCatalog(file: try loader.load()) } // MARK: - Decoding @Test func decodesAllFieldsFromJSON() throws { let catalog = try Self.sampleCatalog() let def = try #require(catalog.definitions.first) #expect(def.size == .t1_2) #expect(def.color == .white) #expect(def.placement == .aboveGround) #expect(def.modelPath == "DG-2700_wh.usdz") #expect(def.modelResourceName == "DG-2700_wh") #expect(def.modelFileExtension == "usdz") } @Test func decodesDisplayNameMappings() throws { let catalog = try Self.sampleCatalog() #expect(catalog.sizeDisplayNames["t1_2"] == "1,2 t") #expect(catalog.colorDisplayNames["olive"] == "Olivgrün") } @Test func displayNameFallsBackToRawValueWhenMissing() { // Katalog ohne Mappings → Anzeigename ist der rawValue. let catalog = TankCatalog(definitions: []) #expect(catalog.displayName(for: TankSize.t2_1) == "t2_1") #expect(catalog.displayName(for: TankColor.green) == "green") } @Test func missingResourceThrows() { let loader = BundleTankCatalogLoader( bundle: .main, resourceName: "Datei-die-nicht-existiert", resourceExtension: "json" ) #expect(throws: TankCatalogLoaderError.self) { _ = try loader.load() } } @Test func emptyCatalogWhenLoaderFails() { let loader = BundleTankCatalogLoader(resourceName: "gibt-es-nicht") let catalog = TankCatalog(loader: loader) #expect(catalog.definitions.isEmpty) } // MARK: - Abgeleitete Abfragen @Test func availableColorsDependOnPlacement() throws { let catalog = try Self.sampleCatalog() #expect(catalog.colors(for: .t1_2, placement: .aboveGround) == [.white, .green]) #expect(catalog.colors(for: .t1_2, placement: .belowGround) == [.olive]) } @Test func availableSizesPerPlacement() throws { let catalog = try Self.sampleCatalog() #expect(catalog.sizes(for: .aboveGround) == [.t1_2, .t2_9]) #expect(catalog.sizes(for: .belowGround) == [.t1_2, .t2_9]) } @Test func placementsPreserveOrder() throws { let catalog = try Self.sampleCatalog() #expect(catalog.placements == [.aboveGround, .belowGround]) } @Test func displayNamesResolveFromCatalog() throws { let catalog = try Self.sampleCatalog() #expect(catalog.displayName(for: TankSize.t2_9) == "2,9 t") #expect(catalog.displayName(for: TankColor.olive) == "Olivgrün") } // MARK: - Auflösung & Normalisierung @Test func definitionMatchesExactSelection() throws { let catalog = try Self.sampleCatalog() let tank = Tank(size: .t2_9, color: .olive, placement: .belowGround) #expect(catalog.definition(for: tank)?.modelPath == "DG-6400_ol.usdz") } @Test func normalizesInconsistentColorForPlacement() throws { let catalog = try Self.sampleCatalog() // Weiß gibt es unterirdisch nicht → sollte auf Olivgrün korrigiert werden. let tank = Tank(size: .t2_9, color: .white, placement: .belowGround) let normalized = catalog.normalized(tank) #expect(normalized.color == .olive) #expect(catalog.definition(for: normalized) != nil) } @Test func resolvedDefinitionHealsLegacySelection() throws { let catalog = try Self.sampleCatalog() // Altdaten: unterirdisch + weiß → muss trotzdem das Olivgrün-Modell liefern. let legacy = Tank(size: .t2_9, color: .white, placement: .belowGround) #expect(catalog.resolvedDefinition(for: legacy)?.modelPath == "DG-6400_ol.usdz") } @Test func validSelectionStaysUnchanged() throws { let catalog = try Self.sampleCatalog() let tank = Tank(size: .t1_2, color: .green, placement: .aboveGround) #expect(catalog.normalized(tank) == tank) } }